LCOV - code coverage report
Current view: top level - gridtools - DumpGrid.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 140 148 94.6 %
Date: 2026-11-05 10:19:04 Functions: 7 8 87.5 %

          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             : }

Generated by: LCOV version 1.16