1 /*
2   This file is part of MADNESS.
3 
4   Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20   For more information please contact:
21 
22   Robert J. Harrison
23   Oak Ridge National Laboratory
24   One Bethel Valley Road
25   P.O. Box 2008, MS-6367
26 
27   email: harrisonrj@ornl.gov
28   tel:   865-241-3937
29   fax:   865-572-0680
30 
31 
32   $Id: test.cc 257 2007-06-25 19:09:38Z HartmanBaker $
33 */
34 
35 /// \file mraplot.cc
36 /// \brief Function plotting utility
37 
38 #include <madness/mra/mra.h>
39 #include <unistd.h>
40 #include <cstdio>
41 #include <madness/constants.h>
42 #include <madness/misc/phandler.h>
43 
44 using namespace madness;
45 
46 template <typename T, std::size_t NDIM>
47 struct lbcost {
operator ()lbcost48     double operator()(const Key<NDIM>& key, const FunctionNode<T,NDIM>& node) const {
49         return 1.0;
50     }
51 };
52 
53 std::string help = "\n\
54       Input is read from standard input.\n\
55 \n\
56       Keywords may appear in any order until the plot keyword is  \n\
57       detected, at which point the plot is generated.  Input processing  \n\
58       then resumes with previous input values being remembered. \n\
59  \n\
60       Thus, multiple plots may be generated by one input file. \n\
61       If only one plot is being generated, the plot keyword may \n\
62       be omitted (plot is triggered by hitting EOF). \n\
63  \n\
64       REQUIRED KEYWORDS \n\
65       .   input <string filename> // Input file name ... no default for this! \n\
66  \n\
67       OPTIONAL KEYWORDS \n\
68       .   output <string filename> // Default is 'plot' \n\
69       .   ndim <int ndim>   // No. of dimensions ... default is 3 \n\
70       .   cell <double lo> <double hi> [...] // Compute cell volume ... default is [0,1]^ndim \n\
71       .   ascii             // Text output for volume data [default is binary] \n\
72       .   text              // Text output for volume data [default is binary] \n\
73       .   dx                // Specifies DX format for volume data [default is dx] \n\
74       .   vtk <str function_name> // Specifies VTK format for volume data [default is dx], giving the function name function_name \n\
75       .   real              // Sets data type to real, default is real \n\
76       .   complex           // Sets data type to complex, default is real \n\
77       .   line              // Sets plot type to line, default is volume \n\
78       .   volume            // Sets plot type to volume, default is volume \n\
79       .   plot_cell <double lo> <double hi> [...] // Plot range in each dimension, default is compute cell \n\
80       .   npt               // No. of points in each dimension (default is 101) \n\
81       .   formula           // Also plot analytic expression \n\
82       .   exit              // exits the program gracefully \n\
83       .   quit              // exits the program gracefully \n\
84  \n\
85       EXAMPLE \n\
86       .   For a real function in parallel archive 'psi_step22' it  \n\
87       .   makes a volume plot over the whole domain and then a line \n\
88       .   plot along the z axis between [-10,10] \n\
89       .   \n\
90       .   cell -100 100 -100 100 -100 100 \n\
91       .   input psi_step22 \n\
92       .   output psi22.dx \n\
93       .   plot \n\
94       . \n\
95       .   vtk my_function \n\
96       .   output psi22.vts \n\
97       .   plot \n\
98       . \n\
99       . \n\
100       .   dx \n\
101       .   plot_cell 0 0 0 0 -10 10 \n\
102       .   output psi22.dat \n\
103       .   line \n\
104       .   plot \n\
105  \n\
106       DEBUG TIPS\n\
107       !! If the parallel archive holding the function was generated \n\
108       !! with multiple writers you presently must run mraplot in parallel \n\
109       !! with at least as many MPI processes. \n\
110       \n\
111       input data-00000.00000 may produce the following error\n\
112       MadnessException : msg=BinaryFstreamInputArchive: ... function=open \n\
113       input data-00000 fixes the problem\n\
114       ";
115 
116 class Plotter {
117 
118 public:
119 
120     World& world;
121     Tensor<double> cell;        // Computational cell
122     Tensor<double> plot_cell;   // Plotting volume
123     std::string data_type;           // presently only double or complex
124     std::string plot_type;           // line or volume
125     std::string input_filename;      // filename for function on disk
126     std::string output_filename;     // output file name for plot data
127     std::string output_format;       // output format for volume data (presently only dx)
128     std::string formula;             // analytic function to plot
129     std::string function_name;       // function name for VTK output
130     std::vector<long> npt;           // no. points in each dimension
131     int ndim;                   // no. of dimensions
132     bool binary;                // output format for plot data
133     bool finished;              // true if finishing
134 
135     template <typename Archive>
serialize(Archive & ar)136     void serialize(Archive& ar) {
137         ar & cell & plot_cell & data_type & plot_type
138             & input_filename & output_filename & output_format & function_name
139             & npt & ndim & binary & finished;
140     }
141 
Plotter(World & world)142     Plotter(World& world)
143         : world(world)
144         , cell()
145         , plot_cell()
146         , data_type("double")
147         , plot_type("volume")
148         , input_filename()
149         , output_filename("plot")
150         , output_format("dx")
151         , formula("")
152         , function_name("function")
153         , ndim(3)
154         , binary(true)
155         , finished(true)
156     {}
157 
read_to_end_of_line(std::istream & input)158     std::string read_to_end_of_line(std::istream& input) {
159         std::string buf;
160         while (1) {
161             char c = input.get();
162             if (c == '\n') break;
163             buf.append(1, c);
164         }
165         return buf;
166     }
167 
read_npt(std::istream & input)168     std::vector<long> read_npt(std::istream& input) {
169         std::istringstream s(read_to_end_of_line(input));
170         std::vector<long> npt;
171         int i;
172         while (s >> i) {
173             npt.push_back(i);
174         }
175         return npt;
176     }
177 
178     // Read pairs of floating point values and return appropriately sized tensor
read_cell(std::istream & input)179     Tensor<double> read_cell(std::istream& input) {
180         std::istringstream s(read_to_end_of_line(input));
181         double v[65];
182         int n = 0;
183         while (s >> v[n]) {
184             ++n;
185             MADNESS_ASSERT(n < 65);
186         }
187         // There should be an even number
188         int ndim = n/2;
189         MADNESS_ASSERT(n==ndim*2 && ndim>=1);
190         Tensor<double> cell(ndim,2);
191         for (int i=0; i<ndim; ++i) {
192             cell(i,0) = v[2*i  ];
193             cell(i,1) = v[2*i+1];
194         }
195         return cell;
196     }
197 
read(std::istream & input)198     void read(std::istream& input) {
199         finished = true;
200         std::string token;
201         while (input >> token) {
202             finished = false;
203 
204             if (token == "ndim") {
205                 input >> ndim;
206             }
207             else if (token == "ascii") {
208                 binary = false;
209             }
210             else if (token == "text") {
211                 binary = false;
212             }
213             else if (token == "dx") {
214                 output_format = "dx";
215             }
216             else if (token == "vtk") {
217                 output_format = "vtk";
218 
219                 // get the name of the function
220                 if(!(input >> function_name))
221                     MADNESS_EXCEPTION("VTK format requires a function name", 0);
222             }
223             else if (token == "input") {
224                 input >> input_filename;
225             }
226             else if (token == "real") {
227                 data_type = "real";
228             }
229             else if (token == "complex") {
230                 data_type = "complex";
231             }
232             else if (token == "line") {
233                 plot_type = "line";
234             }
235             else if (token == "volume") {
236                 plot_type = "volume";
237             }
238             else if (token == "cell") {
239                 cell = read_cell(input);
240             }
241             else if (token == "plot_cell") {
242                 plot_cell = read_cell(input);
243             }
244             else if (token == "npt") {
245                 npt = read_npt(input);
246             }
247             else if (token == "plot") {
248                 break;
249             }
250             else if (token == "input") {
251                 input >> input_filename;
252             }
253             else if (token == "output") {
254                 input >> output_filename;
255             }
256             else if (token == "formula") {
257                 input >> formula;
258             }
259             else if (token == "quit" || token == "exit") {
260                 finished = true;
261                 break;
262             }
263             else {
264                 print("unknown keyword =", token);
265                 MADNESS_EXCEPTION("unknown plotter keyword", 0);
266             }
267         }
268 
269         if (finished) return;
270 
271         // Implement runtime defaults
272         if (cell.size() <= 0) {
273             MADNESS_ASSERT(ndim>0 && ndim<=6);
274             cell = Tensor<double>(ndim,2);
275             for (int i=0; i<ndim; ++i) cell(i,1) = 1.0;
276         }
277         if (plot_cell.size() <= 0) plot_cell = copy(cell);
278         while (int(npt.size()) < ndim) npt.push_back(101);
279 
280         // Warm and fuzzy
281         std::string ff[2] = {"text","binary"};
282         print(plot_type,"plot of", data_type, "function in", ndim,"dimensions from file", input_filename, "to", ff[binary], "file", output_filename);
283         print("  compute cell");
284         print(cell);
285         print("  plot cell");
286         print(plot_cell);
287         print("  number of points");
288         print(npt);
289         print("");
290 
291         // Sanity check
292         MADNESS_ASSERT(ndim>0 && ndim<=6);
293         MADNESS_ASSERT(cell.dim(0)==ndim && cell.dim(1)==2);
294         MADNESS_ASSERT(plot_cell.dim(0)==ndim && plot_cell.dim(1)==2);
295     }
296 
297     template <typename T, std::size_t NDIM>
dolineplot(const Function<T,NDIM> & f)298     void dolineplot(const Function<T,NDIM>& f) {
299         Vector<double,NDIM> lo, hi;
300         for (std::size_t i=0; i<NDIM; ++i) {
301             lo[i] = plot_cell(i,0);
302             hi[i] = plot_cell(i,1);
303         }
304 
305         plot_line(output_filename.c_str(), npt[0], lo, hi, f);
306     }
307 
308 
309     template <typename T, std::size_t NDIM>
dovolumeplot(const Function<T,NDIM> & f)310     void dovolumeplot(const Function<T,NDIM>& f) {
311         if(output_format == "dx") {
312             plotdx(f, output_filename.c_str(), plot_cell, npt, binary);
313         }
314         else if(output_format == "vtk") {
315             Vector<double, NDIM> plotlo, plothi;
316             Vector<long, NDIM> numpt;
317             for(std::size_t i = 0; i < NDIM; ++i) {
318                 plotlo[i] = plot_cell(i, 0);
319                 plothi[i] = plot_cell(i, 1);
320                 numpt[i] = npt[i];
321             }
322 
323             plotvtk_begin(world, output_filename.c_str(), plotlo, plothi,
324                 numpt, binary);
325             plotvtk_data(f, function_name.c_str(), world,
326                 output_filename.c_str(), plotlo, plothi, numpt, binary);
327             plotvtk_end<NDIM>(world, output_filename.c_str(), binary);
328         }
329     }
330 
331 
332     template <typename T, std::size_t NDIM>
dolineplot(const Function<T,NDIM> & f,const Function<T,NDIM> & g)333     void dolineplot(const Function<T,NDIM>& f, const Function<T,NDIM>& g) {
334         Vector<double,NDIM> lo, hi;
335         for (std::size_t i=0; i<NDIM; ++i) {
336             lo[i] = plot_cell(i,0);
337             hi[i] = plot_cell(i,1);
338         }
339 
340         plot_line(output_filename.c_str(), npt[0], lo, hi, f, g);
341     }
342 
343 
344     template <typename T, std::size_t NDIM>
dovolumeplot(const Function<T,NDIM> & f,const Function<T,NDIM> & g)345     void dovolumeplot(const Function<T,NDIM>& f, const Function<T,NDIM>& g) {
346         if(output_format == "dx") {
347           MADNESS_EXCEPTION("plot type not supported with user functions!",0);
348         }
349         else if(output_format == "vtk") {
350             Vector<double, NDIM> plotlo, plothi;
351             Vector<long, NDIM> numpt;
352             for(std::size_t i = 0; i < NDIM; ++i) {
353                 plotlo[i] = plot_cell(i, 0);
354                 plothi[i] = plot_cell(i, 1);
355                 numpt[i] = npt[i];
356             }
357 
358             plotvtk_begin(world, output_filename.c_str(), plotlo, plothi,
359                 numpt, binary);
360             plotvtk_data(f, function_name.c_str(), world,
361                 output_filename.c_str(), plotlo, plothi, numpt, binary);
362             plotvtk_data(g, function_name.c_str(), world,
363                 output_filename.c_str(), plotlo, plothi, numpt, binary);
364             plotvtk_end<NDIM>(world, output_filename.c_str(), binary);
365         }
366     }
367 
368 
369     template <typename T, std::size_t NDIM>
doplot1()370     void doplot1() {
371 
372         // Set up environment for this dimension
373         FunctionDefaults<NDIM>::set_cell(cell);
374 
375         // Load the function
376         Function<T,NDIM> f;
377         archive::ParallelInputArchive ar(world, input_filename.c_str());
378         ar & f;
379 
380         // Load the user's function
381         if (formula != "") {
382          typedef FunctionFactory<T,NDIM> factoryT;
383          typedef std::shared_ptr< FunctionFunctorInterface<T, NDIM> > functorT;
384          Function<T,NDIM> pFunc = factoryT(world).functor(functorT(
385                         new ParserHandler<T,NDIM>("exp(-abs(r))")));
386 
387           if      (plot_type == "volume")    dovolumeplot<T,NDIM>(f,pFunc);
388           else if (plot_type == "line")      dolineplot<T,NDIM>(f,pFunc);
389           else    MADNESS_EXCEPTION("unknown plot type",0);
390         } // end if formula present
391         else {
392           if      (plot_type == "volume")    dovolumeplot<T,NDIM>(f);
393           else if (plot_type == "line")      dolineplot<T,NDIM>(f);
394           else    MADNESS_EXCEPTION("unknown plot type",0);
395         }
396     }
397 
398 
399     template <typename T>
doplot()400     void doplot() {
401         // Redirect to right dimension
402         if      (ndim == 1) doplot1<T,1>();
403         else if (ndim == 2) doplot1<T,2>();
404         else if (ndim == 3) doplot1<T,3>();
405 #ifdef FUNCTION_INSTANTIATE_4
406         else if (ndim == 4) doplot1<T,4>();
407 #endif
408 //         else if (ndim == 5) doplot1<T,5>();
409 //         else if (ndim == 6) doplot1<T,6>();
410         else                MADNESS_EXCEPTION("invalid ndim", ndim);
411     }
412 
plot()413     void plot() {
414         // Redirect to right data type
415         if (data_type == "double") {
416             doplot<double>();
417         }
418         else if (data_type == "complex") {
419             doplot< std::complex<double> >();
420         }
421         else {
422             MADNESS_EXCEPTION("uknown data type",0);
423         }
424     }
425 };
426 
main(int argc,char ** argv)427 int main(int argc, char**argv) {
428     initialize(argc, argv);
429 
430     try {
431         World world(SafeMPI::COMM_WORLD);
432         bool done = false;
433         if (world.rank() == 0) {
434             for (int i=0; i<argc; ++i) {
435                 if (!strcmp(argv[i],"--help")) {
436                     print(help);
437                     done = true;
438                 }
439             }
440         }
441         world.gop.broadcast(done);
442         if (!done) {
443             startup(world,argc,argv);
444             if (world.rank() == 0) print(" ");
445 
446             Plotter plotter(world);
447             while (1) {
448                 if (world.rank() == 0) {
449                     plotter.read(std::cin);
450                 }
451                 world.gop.broadcast_serializable(plotter, 0);
452                 if (plotter.finished) break;
453                 plotter.plot();
454             }
455         }
456 
457         world.gop.fence();
458     }
459     catch (const SafeMPI::Exception& e) {
460         print(e);
461         error("caught an MPI exception");
462     }
463     catch (const madness::MadnessException& e) {
464         print(e);
465         error("caught a MADNESS exception");
466     }
467     catch (const madness::TensorException& e) {
468         print(e);
469         error("caught a Tensor exception");
470     }
471     catch (const char* s) {
472         print(s);
473         error("caught a c-string exception");
474     }
475     catch (const std::string& s) {
476         print(s);
477         error("caught a string (class) exception");
478     }
479     catch (const std::exception& e) {
480         print(e.what());
481         error("caught an STL exception");
482     }
483     catch (...) {
484         error("caught unhandled exception");
485     }
486 
487     finalize();
488     return 0;
489 }
490 
491