Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2016-2023 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #include "core/ActionWithArguments.h"
23 : #include "core/ActionPilot.h"
24 : #include "core/ActionRegister.h"
25 : #include "core/PlumedMain.h"
26 : #include "ActionWithGrid.h"
27 : #include "tools/OFile.h"
28 :
29 : namespace PLMD {
30 : namespace gridtools {
31 :
32 : //+PLUMEDOC GRIDANALYSIS DUMPCUBE
33 : /*
34 : Output a three dimensional grid using the Gaussian cube file format.
35 :
36 : Suppose you have calculated the value of a function on a three dimensional grid.
37 : This function might be a [HISTOGRAM](HISTOGRAM.md), [KDE](KDE.md) or it might be a free energy energy surface
38 : that was calculated from this histogram by using [CONVERT_TO_FES](CONVERT_TO_FES.md). Alternatively,
39 : your function might be a phase-field that was calculated using [MULTICOLVARDENS](MULTICOLVARDENS.md) or a series of [CUSTOM](CUSTOM.md) functions
40 : that had been applied on the input grid.
41 : Whatever the function is, however, you obviously cannot show it using a typical contour
42 : plotting program such as gnuplot as you have three input variables.
43 :
44 : Tools like VMD have nice features for plotting these types of three dimensional functions
45 : but typically you are required to use a Gaussian cube file format to input the data. This
46 : action thus allows you to output a function evaluated on a grid to a Gaussian cube file format.
47 :
48 : ## Examples
49 :
50 : The input below can be used to post process a trajectory. A histogram as a function of the distance
51 : between atoms 1 and 2, the distance between atom 1 and 3 and the angle between the vector connecting atoms 1 and
52 : 2 and 1 and 3 is computed using kernel density estimation. Once all the data contained in the trajectory has been read in and
53 : all the kernels have been added the resulting histogram is output to a file called histoA1.cube. This file has the
54 : Gaussian cube file format. The histogram can thus be visualized using tools such as VMD.
55 :
56 : ```plumed
57 : x1: DISTANCE ATOMS=1,2
58 : x2: DISTANCE ATOMS=1,3
59 : x3: ANGLE ATOMS=1,2,3
60 :
61 : hA1: HISTOGRAM ARG=x1,x2,x3 GRID_MIN=0.0,0.0,0.0 GRID_MAX=3.0,3.0,3.0 GRID_BIN=10,10,10 BANDWIDTH=1.0,1.0,1.0
62 : DUMPCUBE ARG=hA1 FILE=histoA1.cube
63 : ```
64 :
65 : In the input above the cube file is output at the end of the simulation or when the full trajectory has been read.
66 : If you want to output the cube file every 1000 steps you would use an input like the one shown below:
67 :
68 : ```plumed
69 : x1: DISTANCE ATOMS=1,2
70 : x2: DISTANCE ATOMS=1,3
71 : x3: ANGLE ATOMS=1,2,3
72 :
73 : hA1: HISTOGRAM ARG=x1,x2,x3 GRID_MIN=0.0,0.0,0.0 GRID_MAX=3.0,3.0,3.0 GRID_BIN=10,10,10 BANDWIDTH=1.0,1.0,1.0
74 : DUMPCUBE ARG=hA1 FILE=histoA1.cube STRIDE=1000
75 : ```
76 :
77 : The default option is used here and thus multiple cube files are output. The cube file that is obtained from the
78 : first 1000 steps of the trajectory will be named `analysis.0.histoA1.cube`, the one from the second 1000 steps of
79 : trajectory is named `analysis.1.histoA1.cube` and so on until the final histogram output, which will called
80 : `histoA1.cube`. If you would like to output the data from all these cube files in a single file you use the
81 : `PRINT_ONE_FILE` flag as shown below:
82 :
83 : ```plumed
84 : x1: DISTANCE ATOMS=1,2
85 : x2: DISTANCE ATOMS=1,3
86 : x3: ANGLE ATOMS=1,2,3
87 :
88 : hA1: HISTOGRAM ARG=x1,x2,x3 GRID_MIN=0.0,0.0,0.0 GRID_MAX=3.0,3.0,3.0 GRID_BIN=10,10,10 BANDWIDTH=1.0,1.0,1.0
89 : DUMPCUBE ARG=hA1 FILE=histoA1.cube STRIDE=1000 FMT=%10.6f PRINT_ONE_FILE
90 : ```
91 :
92 : Notice that we have also used the `FMT` keyword here to control the format of the numbers in our output cube file.
93 :
94 : */
95 : //+ENDPLUMEDOC
96 :
97 : //+PLUMEDOC GRIDANALYSIS DUMPGRID
98 : /*
99 : Output the function on the grid to a file with the PLUMED grid format.
100 :
101 : PLUMED provides a number of actions that calculate the values of functions on grids.
102 : For instance, whenever you calculate a free energy as a function of a collective variable using
103 : [KDE](KDE.md), [HISTOGRAM](HISTOGRAM.md) and [CONVERT_TO_FES](CONVERT_TO_FES.md) you will generally want to output the value of the free energy at a number of points on a
104 : discrete grid that covers the CV space uniformly. Alternatively you may want to calculate
105 : what value some symmetry function takes at different points inside your simulation cell using [MULTICOLVARDENS](MULTICOLVARDENS.md) or some suitable combination of [CUSTOM](CUSTOM.md) actions.
106 :
107 : This action allows you to output these functions calculated on a grid using a format that can be read in using gnuplot
108 : and other such plotting programs. The file output using this action will have a header that contains some essential
109 : information about the function plotted and that looks something like this:
110 :
111 : ````
112 : #! FIELDS x y hA1 dhA1_x dhA1_x
113 : #! SET normalisation 2.0000
114 : #! SET min_x 0.0
115 : #! SET max_x 3.0
116 : #! SET nbins_x 100
117 : #! SET periodic_x false
118 : #! SET min_y 0.0
119 : #! SET max_y 3.0
120 : #! SET nbins_y 100
121 : #! SET periodic_y false
122 : ````
123 :
124 : The header shown here tells us that we have grid showing the values that a function with two arguments x and y
125 : takes at various points in our cell. The lines beneath the first line then tell us a little bit about these two
126 : input arguments.
127 :
128 : The remaining lines of the file give us information on the positions of our grid points and the value the function and
129 : its partial derivatives with respect to x and y. If the header is as above a list of values of the function that have
130 : x=0 and 100 values of y between 0.0 and 3.0 will be provided. This block of data will be followed with a blank line.
131 : There will then be a second block of values which will all have been evaluated the same value of x and all possible values
132 : for y. This block is then followed by a blank line again and this pattern continues until all points of the grid have been covered.
133 :
134 : ## Examples
135 :
136 : The following input monitors two torsional angles during a simulation
137 : and outputs a continuous histogram as a function of them at the end of the simulation.
138 :
139 : ```plumed
140 : r1: TORSION ATOMS=1,2,3,4
141 : r2: TORSION ATOMS=2,3,4,5
142 : hh: HISTOGRAM ...
143 : ARG=r1,r2
144 : GRID_MIN=-3.14,-3.14
145 : GRID_MAX=3.14,3.14
146 : GRID_BIN=200,200
147 : BANDWIDTH=0.05,0.05
148 : ...
149 :
150 : DUMPGRID ARG=hh FILE=histo
151 : ```
152 :
153 : The following input monitors two torsional angles during a simulation
154 : and outputs a discrete histogram as a function of them at the end of the simulation.
155 : In this input we have also used the FMT keyword to control the appearance of the numbers
156 : in the output file.
157 :
158 : ```plumed
159 : r1: TORSION ATOMS=1,2,3,4
160 : r2: TORSION ATOMS=2,3,4,5
161 : hh: HISTOGRAM ...
162 : ARG=r1,r2
163 : KERNEL=DISCRETE
164 : GRID_MIN=-3.14,-3.14
165 : GRID_MAX=3.14,3.14
166 : GRID_BIN=200,200
167 : ...
168 :
169 : DUMPGRID ARG=hh FILE=histo FMT=%10.6f
170 : ```
171 :
172 : The following input monitors two torsional angles during a simulation
173 : and outputs the histogram accumulated thus far every 100000 steps.
174 :
175 : ```plumed
176 : r1: TORSION ATOMS=1,2,3,4
177 : r2: TORSION ATOMS=2,3,4,5
178 : hh: HISTOGRAM ...
179 : ARG=r1,r2
180 : GRID_MIN=-3.14,-3.14
181 : GRID_MAX=3.14,3.14
182 : GRID_BIN=200,200
183 : BANDWIDTH=0.05,0.05
184 : ...
185 :
186 : DUMPGRID ARG=hh FILE=histo STRIDE=100000
187 : ```
188 :
189 : By default each of the histogram estimates are output to separate files. There will thus be one
190 : file called `analysis.0.histo` which contains the histogram that was obtained from the first 100000
191 : steps of the simulation. The file `analysis.1.histo` contains the histogram that was obtained from the first
192 : 200000 steps of the simulation and so on until the final estimate of the histogram is output to a file
193 : called `histo`. If you would like to output all estimates of the histogram to a single file you can use the `PRINT_ONE_FILE`
194 : keyword as shown below:
195 :
196 : ```plumed
197 : r1: TORSION ATOMS=1,2,3,4
198 : r2: TORSION ATOMS=2,3,4,5
199 : hh: HISTOGRAM ...
200 : ARG=r1,r2
201 : GRID_MIN=-3.14,-3.14
202 : GRID_MAX=3.14,3.14
203 : GRID_BIN=200,200
204 : BANDWIDTH=0.05,0.05
205 : ...
206 :
207 : DUMPGRID ARG=hh FILE=histo STRIDE=100000 PRINT_ONE_FILE
208 : ```
209 :
210 : Now all estimates of the histogram are contained in a single file called `histo`.
211 :
212 : The following input monitors two torsional angles during a simulation
213 : and outputs a separate histogram for each 100000 steps worth of trajectory.
214 : Notice how the CLEAR keyword is used here and how it is not used in the
215 : previous two examples.
216 :
217 : ```plumed
218 : r1: TORSION ATOMS=1,2,3,4
219 : r2: TORSION ATOMS=2,3,4,5
220 : hh: HISTOGRAM ...
221 : ARG=r1,r2 CLEAR=100000
222 : GRID_MIN=-3.14,-3.14
223 : GRID_MAX=3.14,3.14
224 : GRID_BIN=200,200
225 : BANDWIDTH=0.05,0.05
226 : ...
227 :
228 : DUMPGRID ARG=hh FILE=histo STRIDE=100000
229 : ```
230 :
231 : ## Working with Fibonacci grids
232 :
233 : If you have accumulated a histogram using the [SPHERICAL_KDE](SPHERICAL_KDE.md) keyword as has been done in the following input, we recommend you use
234 : the `PRINT_XYZ` keyword when using DUMPGRID as shown below:
235 :
236 : ```plumed
237 : d1: DISTANCE ATOMS1=1,2 ATOMS2=1,3 ATOMS3=1,4 ATOMS4=1,5 ATOMS5=2,3 ATOMS6=2,4 ATOMS7=2,5 ATOMS8=3,4 ATOMS9=3,5 ATOMS10=4,5
238 : d1lt: LESS_THAN ARG=d1 SWITCH={RATIONAL D_0=2.0 R_0=0.5 D_MAX=5.0}
239 : d1lts: SUM ARG=d1lt PERIODIC=NO
240 : d1c: DISTANCE ATOMS1=2,1 ATOMS2=3,1 ATOMS3=4,1 ATOMS4=5,1 ATOMS5=3,2 ATOMS6=4,2 ATOMS7=5,2 ATOMS8=4,3 ATOMS9=5,3 ATOMS10=5,4 COMPONENTS
241 : b1_x: CUSTOM ARG=d1c.x,d1 FUNC=x/y PERIODIC=NO
242 : b1_y: CUSTOM ARG=d1c.y,d1 FUNC=x/y PERIODIC=NO
243 : b1_z: CUSTOM ARG=d1c.z,d1 FUNC=x/y PERIODIC=NO
244 : hu: SPHERICAL_KDE HEIGHTS=d1lt ARG=b1_x,b1_y,b1_z CONCENTRATION=100 GRID_BIN=144
245 : h: CUSTOM ARG=hu,d1lts FUNC=x/y PERIODIC=NO
246 : DUMPGRID PRINT_XYZ ARG=h PRINT_ONE_FILE STRIDE=1 FILE=allkde.xyz
247 : ```
248 :
249 : This input outputs an xyz file in which atom represents one of the grid points on your spherical grid. These atoms are shifted in and out radially
250 : based on the value of the function at the grid point.
251 :
252 : */
253 : //+ENDPLUMEDOC
254 :
255 : class DumpGrid :
256 : public ActionWithArguments,
257 : public ActionPilot {
258 : private:
259 : std::string fmt, filename;
260 : bool onefile, xyzfile;
261 : public:
262 : static void registerKeywords( Keywords& keys );
263 : explicit DumpGrid(const ActionOptions&ao);
264 178 : ~DumpGrid() {}
265 123 : void calculate() override {}
266 123 : void apply() override {}
267 : void update() override ;
268 : };
269 :
270 : PLUMED_REGISTER_ACTION(DumpGrid,"DUMPCUBE")
271 : PLUMED_REGISTER_ACTION(DumpGrid,"DUMPGRID")
272 :
273 97 : void DumpGrid::registerKeywords( Keywords& keys ) {
274 97 : Action::registerKeywords( keys );
275 97 : ActionPilot::registerKeywords( keys );
276 97 : ActionWithArguments::registerKeywords( keys );
277 194 : keys.addInputKeyword("compulsory","ARG","grid","the label for the grid that you would like to output");
278 97 : keys.addDeprecatedKeyword("GRID","ARG");
279 97 : keys.add("compulsory","STRIDE","0","the frequency with which the grid should be output to the file. Default of zero means dump at end of calculation");
280 97 : keys.add("compulsory","FILE","density","the file on which to write the grid.");
281 97 : keys.add("optional","FMT","the format that should be used to output real numbers");
282 97 : if( keys.getDisplayName()!="DUMPCUBE" ) {
283 88 : keys.addFlag("PRINT_XYZ",false,"output coordinates on fibonacci grid to xyz file");
284 : }
285 97 : keys.addFlag("PRINT_ONE_FILE",false,"output grids one after the other in a single file");
286 97 : }
287 :
288 89 : DumpGrid::DumpGrid(const ActionOptions&ao):
289 : Action(ao),
290 : ActionWithArguments(ao),
291 : ActionPilot(ao),
292 89 : fmt("%f") {
293 89 : if( getNumberOfArguments()!=1 ) {
294 0 : error("should only be one argument");
295 : }
296 89 : if( getPntrToArgument(0)->getRank()==0 || !getPntrToArgument(0)->hasDerivatives() ) {
297 0 : error("input should be a grid");
298 : }
299 89 : if( getName()=="DUMPCUBE" && getPntrToArgument(0)->getRank()!=3 ) {
300 0 : error("input should be a three dimensional grid");
301 : }
302 178 : parse("FILE",filename);
303 89 : if(filename.length()==0) {
304 0 : error("name out output file was not specified");
305 : }
306 89 : ActionWithGrid* ag = ActionWithGrid::getInputActionWithGrid( getPntrToArgument(0)->getPntrToAction() );
307 89 : if( !ag ) {
308 0 : error( getPntrToArgument(0)->getName() + " is not grid");
309 : }
310 :
311 89 : log.printf(" outputting grid with label %s to file named %s",getPntrToArgument(0)->getName().c_str(), filename.c_str() );
312 89 : parse("FMT",fmt);
313 89 : log.printf(" with format %s \n", fmt.c_str() );
314 89 : if( getName()=="DUMPGRID" ) {
315 168 : fmt = " " + fmt;
316 5 : } else if( getName()=="DUMPCUBE" ) {
317 10 : fmt = fmt + " ";
318 : }
319 89 : parseFlag("PRINT_ONE_FILE", onefile);
320 89 : xyzfile=false;
321 89 : if( getName()!="DUMPCUBE" ) {
322 168 : parseFlag("PRINT_XYZ",xyzfile);
323 : }
324 89 : if( xyzfile ) {
325 4 : if( getName()=="DUMPCUBE" ) {
326 0 : error("PRINT_XYZ flag not compatible with DUMPCUBE");
327 : }
328 4 : if( ag->getGridCoordinatesObject().getGridType()=="flat" ) {
329 0 : error("can only use PRINT_XYZ option for fibonacci grids");
330 : }
331 4 : log.printf(" outputting grid to xyzfile\n");
332 : }
333 89 : if( onefile ) {
334 2 : log.printf(" printing all grids on a single file \n");
335 : } else {
336 87 : log.printf(" printing all grids on separate files \n");
337 : }
338 89 : }
339 :
340 168 : void DumpGrid::update() {
341 168 : OFile ofile;
342 168 : ofile.link(*this);
343 168 : if( onefile ) {
344 10 : ofile.enforceRestart();
345 10 : ofile.open( filename );
346 : } else {
347 158 : ofile.setBackupString("analysis");
348 158 : ofile.open( filename );
349 : }
350 :
351 168 : ActionWithGrid* ag = ActionWithGrid::getInputActionWithGrid( getPntrToArgument(0)->getPntrToAction() );
352 168 : plumed_assert( ag );
353 168 : const GridCoordinatesObject & mygrid = ag->getGridCoordinatesObject();
354 : // A grid that was never calculated has no points, and the loops below read an empty grid (segmentation fault).
355 : // This happens with STRIDE=0 (output at the end of the run) for an instantaneous grid that nothing else uses
356 : // during the run, e.g. RDF with the default CLEAR=1: at the end only the actions that depend on averages are calculated.
357 168 : if( mygrid.getNumberOfPoints()==0 ) {
358 2 : error("the grid " + getPntrToArgument(0)->getName() + " was never calculated. "
359 : "With STRIDE=0 (the default) the grid is written at the end of the run, so it must be accumulated over the trajectory "
360 : "(e.g. HISTOGRAM, or RDF with CLEAR=0) or calculated at every step for another action. Use STRIDE to write an instantaneous grid");
361 : }
362 :
363 167 : if( getName()=="DUMPCUBE" ) {
364 : double lunit=1.0;
365 11 : std::vector<std::string> argnames( ag->getGridCoordinateNames() );
366 :
367 11 : ofile.printf("PLUMED CUBE FILE\n");
368 11 : ofile.printf("OUTER LOOP: X, MIDDLE LOOP: Y, INNER LOOP: Z\n");
369 : // Number of atoms followed by position of origin (origin set so that center of grid is in center of cell)
370 : bool isdists=true;
371 11 : std::vector<double> extent(3);
372 11 : std::vector<std::string> min( mygrid.getMin() ), max( mygrid.getMax() );
373 44 : for(unsigned j=0; j<3; ++j) {
374 33 : if( argnames[j].find(".")!=std::string::npos ) {
375 : std::size_t dot = argnames[j].find(".");
376 3 : std::string name = argnames[j].substr(dot+1);
377 3 : if( name!="x" && name!="y" && name!="z" ) {
378 : isdists=false;
379 : }
380 : } else {
381 : isdists=false;
382 : }
383 :
384 : double mind, maxd;
385 33 : Tools::convert( min[j], mind );
386 33 : Tools::convert( max[j], maxd );
387 33 : if( mygrid.isPeriodic(j) ) {
388 3 : extent[j]=maxd-mind;
389 : } else {
390 30 : extent[j]=maxd-mind+mygrid.getGridSpacing()[j];
391 : }
392 : }
393 11 : if( isdists ) {
394 1 : if( plumed.usingNaturalUnits() ) {
395 : lunit = 1.0/0.5292;
396 : } else {
397 0 : lunit = plumed.getUnits().getLength()/.05929;
398 : }
399 : }
400 22 : std::string ostr = "%d " + fmt + fmt + fmt + "\n";
401 : Value* gval=getPntrToArgument(0);
402 11 : ofile.printf(ostr.c_str(),1,-0.5*lunit*extent[0],-0.5*lunit*extent[1],-0.5*lunit*extent[2]);
403 11 : ofile.printf(ostr.c_str(),mygrid.getNbin(true)[0],lunit*mygrid.getGridSpacing()[0],0.0,0.0); // Number of bins in each direction followed by
404 11 : ofile.printf(ostr.c_str(),mygrid.getNbin(true)[1],0.0,lunit*mygrid.getGridSpacing()[1],0.0); // shape of voxel
405 11 : ofile.printf(ostr.c_str(),mygrid.getNbin(true)[2],0.0,0.0,lunit*mygrid.getGridSpacing()[2]);
406 11 : ofile.printf(ostr.c_str(),1,0.0,0.0,0.0); // Fake atom otherwise VMD doesn't work
407 11 : std::vector<unsigned> pp(3);
408 11 : std::vector<std::size_t> nbin( mygrid.getNbin(true) );
409 135 : for(pp[0]=0; pp[0]<nbin[0]; ++pp[0]) {
410 1530 : for(pp[1]=0; pp[1]<nbin[1]; ++pp[1]) {
411 20204 : for(pp[2]=0; pp[2]<nbin[2]; ++pp[2]) {
412 18798 : unsigned ival=pp[pp.size()-1];
413 56394 : for(unsigned i=pp.size()-1; i>0; --i) {
414 37596 : ival=ival*nbin[i-1]+pp[i-1];
415 : }
416 18798 : ofile.printf(fmt.c_str(), gval->get(ival) );
417 18798 : if(pp[2]%6==5) {
418 1994 : ofile.printf("\n");
419 : }
420 : }
421 1406 : ofile.printf("\n");
422 : }
423 : }
424 178 : } else if( xyzfile ) {
425 13 : std::vector<double> coords(3);
426 : Value* myarg = getPntrToArgument(0);
427 13 : unsigned nvals = myarg->getNumberOfValues();
428 13 : ofile.printf("%d\n\n", nvals);
429 1797 : for(unsigned i=0; i<nvals; ++i) {
430 1784 : double val = myarg->get(i);
431 1784 : mygrid.getGridPointCoordinates( i, coords );
432 1784 : ofile.printf("X");
433 7136 : for(unsigned j=0; j<3; ++j) {
434 10704 : ofile.printf((" " + fmt).c_str(), val*coords[j] );
435 : }
436 1784 : ofile.printf("\n");
437 : }
438 13 : } else {
439 : Value* gval=getPntrToArgument(0);
440 143 : std::vector<double> xx( gval->getRank() );
441 143 : std::vector<unsigned> ind( gval->getRank() );
442 143 : std::vector<std::string> argn( ag->getGridCoordinateNames() );
443 143 : if( mygrid.getGridType()=="fibonacci" ) {
444 16 : ofile.addConstantField("nbins");
445 : } else {
446 135 : plumed_assert( mygrid.getGridType()=="flat" );
447 299 : for(unsigned i=0; i<gval->getRank(); ++i) {
448 328 : ofile.addConstantField("min_" + argn[i] );
449 328 : ofile.addConstantField("max_" + argn[i] );
450 328 : ofile.addConstantField("nbins_" + argn[i] );
451 328 : ofile.addConstantField("periodic_" + argn[i] );
452 : }
453 : }
454 :
455 244483 : for(unsigned i=0; i<gval->getNumberOfValues(); ++i) {
456 : // Retrieve and print the grid coordinates
457 244340 : mygrid.getGridPointCoordinates( i, ind, xx );
458 244340 : if(i>0 && gval->getRank()==2 && ind[gval->getRank()-2]==0) {
459 1005 : ofile.printf("\n");
460 : }
461 244340 : ofile.fmtField(fmt);
462 244340 : if( mygrid.getGridType()=="fibonacci" ) {
463 1776 : ofile.printField("nbins", static_cast<int>(gval->getNumberOfValues()) );
464 : } else {
465 804990 : for(unsigned j=0; j<gval->getRank(); ++j) {
466 1123076 : ofile.printField("min_" + argn[j], mygrid.getMin()[j] );
467 1123076 : ofile.printField("max_" + argn[j], mygrid.getMax()[j] );
468 1123076 : ofile.printField("nbins_" + argn[j], static_cast<int>(mygrid.getNbin(false)[j]) );
469 561538 : if( mygrid.isPeriodic(j) ) {
470 480404 : ofile.printField("periodic_" + argn[j], "true" );
471 : } else {
472 642672 : ofile.printField("periodic_" + argn[j], "false" );
473 : }
474 : }
475 : }
476 : // Print the grid coordinates
477 808542 : for(unsigned j=0; j<gval->getRank(); ++j) {
478 564202 : ofile.fmtField(fmt);
479 564202 : ofile.printField(argn[j],xx[j]);
480 : }
481 : // Print value
482 244340 : ofile.fmtField(fmt);
483 244340 : ofile.printField( gval->getName(), gval->get(i) );
484 : // Print the derivatives
485 808542 : for(unsigned j=0; j<gval->getRank(); ++j) {
486 564202 : ofile.fmtField(fmt);
487 1692606 : ofile.printField( "d" + gval->getName() + "_" + argn[j], gval->getGridDerivative(i,j) );
488 : }
489 244340 : ofile.printField();
490 : }
491 286 : }
492 168 : }
493 :
494 :
495 : }
496 : }
|