Skip to content

Commit

Permalink
Merge branch 'master' into pr-fix-cc2
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/madness/world/cloud.h
  • Loading branch information
fbischoff committed Aug 16, 2024
2 parents 6af7837 + 21f1e5a commit becdef2
Show file tree
Hide file tree
Showing 10 changed files with 833 additions and 21 deletions.
403 changes: 403 additions & 0 deletions src/examples/periodic/test.cc

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/madness/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# src/madness/misc

set(MADMISC_HEADERS misc.h ran.h phandler.h interpolation_1d.h cfft.h info.h)
set(MADMISC_HEADERS misc.h ran.h phandler.h interpolation_1d.h cfft.h info.h gnuplot.h)
set(MADMISC_SOURCES
checksum_file.cc position_stream.cc gprofexit.cc ran.cc cfft.cc info.cc unique_filename.cc)
checksum_file.cc position_stream.cc gprofexit.cc ran.cc cfft.cc info.cc)
# retrieve git metadata
include(GetGitMetadata)
vgkit_cmake_git_metadata()
Expand All @@ -20,8 +20,8 @@ add_mad_library(misc MADMISC_SOURCES MADMISC_HEADERS "world" "madness/misc/")
if(BUILD_TESTING)

# The list of unit test source files
set(MISC_TEST_SOURCES interp3.cc)
set(MISC_TEST_SOURCES interp3.cc test_gnuplot.cc)

add_unittests(misc "${MISC_TEST_SOURCES}" "MADmisc;MADgtest" "unittests;short")

endif()
endif()
198 changes: 198 additions & 0 deletions src/madness/misc/gnuplot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#ifndef MADNESS_GNUPLOT_H__INCUDED
#define MADNESS_GNUPLOT_H__INCUDED

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

#include <iostream>
#include <string>
#include <vector>

namespace madness {
class Gnuplot {
FILE *f; // pipe connection to gnuplot process
pid_t pid; // pid of gnuplot process
FILE *ftee; // filestream for data tee'd from gnuplot process

// base case for unpacking datablock value
template <typename T>
void dbvalue(size_t i, const T& t) {
char buf[256];
snprintf(buf,sizeof(buf),"%16.8e",double(t[i]));
(*this)(buf); // newline
}

// recursion case for unpacking datablock value
template <typename T, typename... Ts>
void dbvalue(size_t i, const T& t, Ts... values) {
char buf[256];
snprintf(buf,sizeof(buf),"%16.8e ",double(t[i])); // space
(*this)(buf,false);
dbvalue(i,values...);
}

// base case for unpacking plot value
template <int n, typename T>
void doplot(const char* name, const T& value0) {
char buf[256];
snprintf(buf, sizeof(buf), "%s using 1:%d", name, n);
(*this)(buf);
}

// recursion case for unpacking plot value
template <int n, typename T, typename... Ts>
void doplot(const char* name, const T& value0, Ts... values) {
char buf[256];
snprintf(buf, sizeof(buf), "%s using 1:%d, ", name, n);
(*this)(buf,false);

doplot<n+1,Ts...>(name, values...);
}

public:
Gnuplot& operator=(Gnuplot&&) = delete;
Gnuplot& operator=(const Gnuplot&) = delete;
Gnuplot(const Gnuplot&) = delete;
Gnuplot(const std::string& cmd = "", const std::string& teefile = "") : f(0), ftee(0) {
int p[2];
if (pipe (p)) {
throw "Pipe failed.";
}
pid = fork ();
if (pid == 0) { // Child process.
close(p[1]);
dup2(p[0],STDIN_FILENO);
close(p[0]);
if (execlp ("gnuplot", "gnuplot", "-persist", NULL) == -1) {
//if (execlp ("cat", "cat", "-", NULL) == -1) {
fprintf(stderr,"Gnuplot: execlp failed for gnuplot ... plotting disabled\n");
exit(1);
}
}
else if (pid < (pid_t) 0) { // Failure
throw "Fork failed.";
}
else { // Parent process
close (p[0]);
f = fdopen (p[1], "w");
}
if (teefile.size() > 0) {
ftee = fopen(teefile.c_str(),"w");
if (!ftee) {
fprintf(stderr,"Gnuplot: fopen failed for tee file %s ... tee of plotting disabled\n",teefile.c_str());
}
}

if (cmd.size() > 0) (*this)(cmd);
}

// outputs string to gnuplot process
void operator()(const char* cmd, bool EOL=true) {

if (f) {
if (!fprintf(f,"%s",cmd)) {
fprintf(stderr,"Gnuplot: failed writing to gnuplot pipe ... plotting disabled\n");
fclose(f);
f = NULL;
}
}
if (ftee) fprintf(ftee,"%s",cmd);

const int n = strlen(cmd);
if (EOL && ((n==0) || (cmd[n-1] != '\n') ) ) {
if (f) {
if (!fprintf(f,"\n")) {
fprintf(stderr,"Gnuplot: failed writing newline to gnuplot pipe ... plotting disabled\n");
fclose(f);
f = NULL;
}
}
if (ftee) fprintf(ftee,"\n");
}
if (f) fflush(f);
}

// outputs string to gnuplot process
void operator()(const std::string& cmd, bool EOL=true) {
(*this)(cmd.c_str(), EOL);
}

// Define a gnuplot data block with given name assuming 1-d indexing via [] with explicit size
template <typename T, typename... Ts>
void db(const std::string& name, size_t size, const T& x, Ts... values) {
(*this)("$",false);
(*this)(name,false);
(*this)(" << EOD");
for (size_t i = 0; i<size; ++i) {
dbvalue(i,x,values...);
}
(*this)("EOD");
}

// Define a gnuplot data block with given name assuming 1-d indexing via [] with size from x (a 1-d container that supports size())
template <typename T, typename... Ts>
void db(const std::string& name, const T& x, Ts... values) {
db(name,(size_t) x.size(),x,values...); // have to force x.size() to be size_t since Tensor<T>::size() returns long
}

// Plots data in 2 or more vectors by generating the following gnuplot commands:
// $data << EOD
// <data values>
// EOD
// plot $data using 1:2, $data using 1:3, ...
template <typename T, typename... Ts>
void plot(const T& x, Ts... values) {
db("data", x, values...);
(*this)("plot ",false);
doplot<2,Ts...>("$data", values...); // note we peeled off the x values
}

~Gnuplot() {
if (f) {
fclose(f);
waitpid(pid,0,0);
}
if (ftee) fclose(ftee);
}

static void test() {
std::vector<double> x = {1.0,2.0,3.0};
std::vector<double> y = {-1.0,-2.0,3.0};
std::vector<double> z = {10.0,11.0,12.0};
{
Gnuplot g("set style data lp; set grid");
g.plot(x,y,z);
}
{
Gnuplot g;
//g("set term png");
//g("set output \"test.png\"");
g.db("xyz",x,y,z);
g("plot $xyz using 1:2 with linespoints");
}
{
// use x11 to work around bug (https://sourceforge.net/p/gnuplot/bugs/2634/) ... wxt temporarily needs GDK_BACKEND=x11
Gnuplot g("set term x11; set xrange [-10:10]; set yrange [0:1]; set grid; set style data l", "test3.gnuplot");
size_t npts = 100;
std::vector<double> x(npts), y(npts);
for (size_t i = 0; i<npts; ++i) x[i] = -10.0 + 20.0 * i / (npts-1);
for (int step=0; step<40; step++) {
double phase = step*0.3;
for (size_t i = 0; i<npts; ++i) y[i] = 0.5 + 0.5 * std::sin(x[i]+phase);
char buf[256];
snprintf(buf,sizeof(buf),"set title \"step %d\"",step);
g(buf);
g.plot(x,y);
usleep(100000);
}
}
}
};
}
#endif
7 changes: 7 additions & 0 deletions src/madness/misc/test_gnuplot.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <madness/misc/gnuplot.h>

int main (void)
{
madness::Gnuplot::test();
return 0;
}
18 changes: 11 additions & 7 deletions src/madness/world/cloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,14 @@ class Cloud {
void clear_timings() {
reading_time=0l;
writing_time=0l;
writing_time1=0l;
replication_time=0l;
cache_stores=0l;
cache_reads=0l;
}


/// load a single object from the cloud, recordlist is kept unchanged
/// @param[in] world the subworld the objects are loaded to
/// @param[in] recordlist the list of records where the objects are stored
template<typename T>
T load(madness::World &world, const recordlistT recordlist) const {
recordlistT rlist = recordlist;
Expand Down Expand Up @@ -286,6 +287,7 @@ class Cloud {
}
}

/// @param[in] world presumably the universe
template<typename T>
recordlistT store(madness::World &world, const T &source) {
if (is_replicated) {
Expand Down Expand Up @@ -313,6 +315,7 @@ class Cloud {
void replicate(const std::size_t chunk_size=INT_MAX) {

World& world=container.get_world();
world.gop.fence();
cloudtimer t(world,replication_time);
container.reset_pmap_to_local();
is_replicated=true;
Expand Down Expand Up @@ -394,13 +397,14 @@ class Cloud {

struct cloudtimer {
World& world;
double cpu0;
double wall0;
std::atomic<long> &rtime;

cloudtimer(World& world, std::atomic<long> &readtime) : world(world), cpu0(cpu_time()), rtime(readtime) {}
cloudtimer(World& world, std::atomic<long> &readtime) : world(world), wall0(wall_time()), rtime(readtime) {}

~cloudtimer() {
if (world.rank()==0) rtime += long((cpu_time() - cpu0) * 1000l);
long deltatime=long((wall_time() - wall0) * 1000l);
rtime += deltatime;
}
};

Expand Down Expand Up @@ -459,6 +463,7 @@ class Cloud {
if (is_already_present) {
if (world.rank()==0) cache_stores++;
} else {
cloudtimer t(world,writing_time1);
madness::archive::ContainerRecordOutputArchive ar(world, container, record);
madness::archive::ParallelOutputArchive<madness::archive::ContainerRecordOutputArchive> par(world, ar);
par & source;
Expand Down Expand Up @@ -500,7 +505,6 @@ class Cloud {
madness::archive::ContainerRecordInputArchive ar(world, container, record);
madness::archive::ParallelInputArchive<madness::archive::ContainerRecordInputArchive> par(world, ar);
par & target;

cache(world, target, record);
return target;
}
Expand Down Expand Up @@ -538,7 +542,7 @@ class Cloud {
/// @param[inout] world destination world
/// @param[inout] recordlist list of records to load from (reduced by the first few elements)
template<typename T>
T load_tuple(madness::World &world, recordlistT &recordlist) const {
T load_tuple(madness::World &world, recordlistT &recordlist) const {
if (debug) std::cout << "loading tuple of type " << typeid(T).name() << " to world " << world.id() << std::endl;
T target;
std::apply([&](auto &&... args) {
Expand Down
17 changes: 15 additions & 2 deletions src/madness/world/parallel_dc_archive.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ namespace madness {
{
close();
}


VectorOutputArchive& get_archive() {
return ar;
}
template <class T>
inline
typename std::enable_if< madness::is_trivially_serializable<T>::value, void >::type
Expand Down Expand Up @@ -97,7 +100,17 @@ namespace madness {

void close() {}
};



template <class keyT, class valueT>
struct ArchiveStoreImpl< ParallelOutputArchive<ContainerRecordOutputArchive>, WorldContainer<keyT,valueT> > {
static void store(const ParallelOutputArchive<ContainerRecordOutputArchive>& ar, const WorldContainer<keyT,valueT>& t) {
ParallelOutputArchive<VectorOutputArchive> par(*(ar.get_world()), ar.local_archive().get_archive());
par & t;

}
};

}


Expand Down
Loading

0 comments on commit becdef2

Please sign in to comment.