From a0479f21bbb215c1df38f74fbb415eca0385b86c Mon Sep 17 00:00:00 2001 From: Gareth Tribello <gareth.tribello@gmail.com> Date: Thu, 31 Dec 2015 09:46:03 +0000 Subject: [PATCH] Using new grid infrastructure for histogram --- regtest/analysis/rt0/plumed.dat | 47 ++++--- src/analysis/Analysis.cpp | 39 ++++-- src/analysis/Analysis.h | 3 +- src/analysis/Histogram.cpp | 170 ++++++++------------------ src/analysis/Makefile | 2 +- src/core/ActionPilot.cpp | 5 + src/core/ActionPilot.h | 1 + src/gridtools/ActionWithInputGrid.cpp | 19 ++- src/gridtools/ActionWithInputGrid.h | 5 +- src/gridtools/ConvertToFES.cpp | 99 +++++++++++++++ src/gridtools/GridFunction.cpp | 48 ++++++++ src/gridtools/GridFunction.h | 41 +++++++ src/gridtools/GridVessel.cpp | 50 +++++++- src/gridtools/GridVessel.h | 19 ++- src/gridtools/HistogramOnGrid.cpp | 69 +++++++---- src/gridtools/HistogramOnGrid.h | 1 + src/gridtools/PrintCube.cpp | 3 + src/gridtools/PrintGrid.cpp | 8 +- src/vesselbase/ActionWithVessel.h | 2 + 19 files changed, 428 insertions(+), 203 deletions(-) create mode 100644 src/gridtools/ConvertToFES.cpp create mode 100644 src/gridtools/GridFunction.cpp create mode 100644 src/gridtools/GridFunction.h diff --git a/regtest/analysis/rt0/plumed.dat b/regtest/analysis/rt0/plumed.dat index bba4549e6..22ba7aca7 100755 --- a/regtest/analysis/rt0/plumed.dat +++ b/regtest/analysis/rt0/plumed.dat @@ -9,11 +9,11 @@ HISTOGRAM ... GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 - GRID_WFILE=histoA - FMT=%8.4f - RUN=1 + LABEL=hA ... HISTOGRAM +PRINT_GRID GRID=hA FILE=histoA STRIDE=1 FMT=%8.4f + HISTOGRAM ... ARG=x TEMP=300 @@ -21,83 +21,80 @@ HISTOGRAM ... GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 - GRID_WFILE=histoB - FMT=%8.4f REWEIGHT_BIAS - RUN=1 + LABEL=hB ... HISTOGRAM +PRINT_GRID GRID=hB FILE=histoB STRIDE=1 FMT=%8.4f + HISTOGRAM ... ARG=x - USE_ALL_DATA GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 - GRID_WFILE=histoC + LABEL=hC ... HISTOGRAM +PRINT_GRID GRID=hC FILE=histoC USE_ALL_DATA + HISTOGRAM ... ARG=x TEMP=300 - USE_ALL_DATA GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 KERNEL=DISCRETE - FMT=%8.4f REWEIGHT_BIAS - GRID_WFILE=histoD - UNNORMALIZED + LABEL=hD ... HISTOGRAM +PRINT_GRID GRID=hD FILE=histoD FMT=%8.4f UNNORMALIZED USE_ALL_DATA + HISTOGRAM ... ARG=x TEMP=10000 - USE_ALL_DATA GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 KERNEL=DISCRETE - FMT=%8.4f REWEIGHT_BIAS - GRID_WFILE=histoE - FREE-ENERGY - UNNORMALIZED + LABEL=hE ... HISTOGRAM +fE: CONVERT_TO_FES GRID=hE TEMP=10000 UNNORMALIZED +PRINT_GRID GRID=fE FMT=%8.4f USE_ALL_DATA FILE=histoE + HISTOGRAM ... ARG=x TEMP=300 - USE_ALL_DATA GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 KERNEL=DISCRETE - FMT=%8.4f REWEIGHT_BIAS - GRID_WFILE=histoD1 - UNNORMALIZED UPDATE_FROM=0 UPDATE_UNTIL=1 + LABEL=hD1 ... HISTOGRAM +PRINT_GRID GRID=hD1 FILE=histoD1 FMT=%8.4f UNNORMALIZED USE_ALL_DATA + HISTOGRAM ... ARG=x TEMP=300 - USE_ALL_DATA GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 KERNEL=DISCRETE - FMT=%8.4f REWEIGHT_BIAS - GRID_WFILE=histoD2 - UNNORMALIZED UPDATE_FROM=1 UPDATE_UNTIL=2 + LABEL=hD2 ... HISTOGRAM +PRINT_GRID GRID=hD2 FILE=histoD2 FMT=%8.4f UNNORMALIZED USE_ALL_DATA + diff --git a/src/analysis/Analysis.cpp b/src/analysis/Analysis.cpp index 648f3e1e2..6c8e86712 100644 --- a/src/analysis/Analysis.cpp +++ b/src/analysis/Analysis.cpp @@ -94,6 +94,7 @@ nomemory(true), write_chq(false), reusing_data(false), ignore_reweight(false), +freq(0), needeng(false), idata(0), firstAnalysisDone(false), @@ -175,20 +176,16 @@ argument_names(getNumberOfArguments()) if(simtemp==0) error("The MD engine does not pass the temperature to plumed so you have to specify it using TEMP"); } - parseFlag("USE_ALL_DATA",single_run); - if( !single_run ){ - parse("RUN",freq ); - log.printf(" running analysis every %u steps\n",freq); - if( freq%getStride()!= 0 ) error("Frequncy of running is not a multiple of the stride"); - ndata=freq/getStride(); - data.resize( ndata ); - for(unsigned i=0;i<ndata;++i){ - data[i]=metricRegister().create<ReferenceConfiguration>( metricname ); - data[i]->setNamesAndAtomNumbers( atom_numbers, argument_names ); + single_run=true; + if( keywords.exists("USE_ALL_DATA") ){ + parseFlag("USE_ALL_DATA",single_run); + if( !single_run ){ + unsigned astride; parse("RUN",astride); + log.printf(" running analysis every %u steps\n",astride); + setAnalysisStride( false, astride ); + } else { + log.printf(" analyzing all data in trajectory\n"); } - logweights.resize( ndata ); - } else { - log.printf(" analyzing all data in trajectory\n"); } if( keywords.exists("NOMEMORY") ){ nomemory=false; parseFlag("NOMEMORY",nomemory); } if(nomemory) log.printf(" doing a separate analysis for each block of data\n"); @@ -221,6 +218,20 @@ argument_names(getNumberOfArguments()) } } +void Analysis::setAnalysisStride( const bool& use_all, const unsigned& astride ){ + if( freq>0 && astride!=freq ) error("frequency for output does not match frequency for run"); + else if( freq>0 || use_all ) return; + + freq=astride; single_run=false; + if( astride%getStride()!= 0 ) error("Frequncy of running is not a multiple of the stride"); + ndata=freq/getStride(); data.resize( ndata ); + for(unsigned i=0;i<ndata;++i){ + data[i]=metricRegister().create<ReferenceConfiguration>( metricname ); + data[i]->setNamesAndAtomNumbers( getAbsoluteIndexes(), argument_names ); + } + logweights.resize( ndata ); +} + void Analysis::readDataFromFile( const std::string& filename ){ FILE* fp=fopen(filename.c_str(),"r"); double tstep, oldtstep; if(fp!=NULL){ @@ -394,6 +405,8 @@ void Analysis::runAnalysis(){ mydatastash->finalizeWeights( ignore_reweight ); norm=mydatastash->retrieveNorm(); } + // This ensures everything is set up to run the calculation + setAnalysisStride( single_run, freq ); // And run the analysis performAnalysis(); idata=0; // Update total normalization constant diff --git a/src/analysis/Analysis.h b/src/analysis/Analysis.h index de5f69d11..27f7f9fb4 100644 --- a/src/analysis/Analysis.h +++ b/src/analysis/Analysis.h @@ -148,7 +148,8 @@ public: void unlockRequests(); void calculateNumericalDerivatives( ActionWithValue* a=NULL ){ plumed_error(); } bool isPeriodic(){ plumed_error(); return false; } - unsigned getNumberOfDerivatives(){ plumed_error(); return 0; } + unsigned getNumberOfDerivatives(){ return 0; } + virtual void setAnalysisStride( const bool& use_all, const unsigned& astride ); }; inline diff --git a/src/analysis/Histogram.cpp b/src/analysis/Histogram.cpp index 1ae64bf30..d2519e7f9 100644 --- a/src/analysis/Histogram.cpp +++ b/src/analysis/Histogram.cpp @@ -26,6 +26,7 @@ #include "tools/KernelFunctions.h" #include "tools/IFile.h" #include "tools/OFile.h" +#include "gridtools/HistogramOnGrid.h" namespace PLMD{ namespace analysis{ @@ -115,7 +116,7 @@ HISTOGRAM ... class Histogram : public Analysis { private: - std::vector<std::string> gmin, gmax; + gridtools::HistogramOnGrid* mygrid; std::vector<double> point, bw; std::vector<unsigned> gbin; std::string gridfname; @@ -126,7 +127,9 @@ public: static void registerKeywords( Keywords& keys ); explicit Histogram(const ActionOptions&ao); void performAnalysis(); + unsigned getNumberOfQuantities() const ; void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void setAnalysisStride( const bool& use_all, const unsigned& astride ); }; PLUMED_REGISTER_ACTION(Histogram,"HISTOGRAM") @@ -134,6 +137,7 @@ PLUMED_REGISTER_ACTION(Histogram,"HISTOGRAM") void Histogram::registerKeywords( Keywords& keys ){ Analysis::registerKeywords( keys ); keys.reset_style("METRIC","hidden"); keys.remove("ATOMS"); keys.reset_style("ARG","compulsory"); + keys.remove("RUN"); keys.remove("USE_ALL_DATA"); keys.add("compulsory","GRID_MIN","the lower bounds for the grid"); keys.add("compulsory","GRID_MAX","the upper bounds for the grid"); keys.add("optional","GRID_BIN","the number of bins for the grid"); @@ -141,148 +145,70 @@ void Histogram::registerKeywords( Keywords& keys ){ keys.add("compulsory","KERNEL","gaussian","the kernel function you are using. Use discrete/DISCRETE if you want to accumulate a discrete histogram. \ More details on the kernels available in plumed can be found in \\ref kernelfunctions."); keys.add("optional","BANDWIDTH","the bandwdith for kernel density estimation"); - keys.addFlag("FREE-ENERGY",false,"Set to TRUE if you want a FREE ENERGY instead of a probabilty density (you need to set TEMP)."); keys.addFlag("UNNORMALIZED",false,"Set to TRUE if you don't want histogram to be normalized or free energy to be shifted."); - keys.add("compulsory","GRID_WFILE","histogram","the file on which to write the grid"); keys.use("NOMEMORY"); } Histogram::Histogram(const ActionOptions&ao): PLUMED_ANALYSIS_INIT(ao), +mygrid(NULL), point(getNumberOfArguments()), fenergy(false), unnormalized(false) { - // Read stuff for Grid - parseVector("GRID_MIN",gmin); - if(gmin.size()!=getNumberOfArguments()) error("Wrong number of values for GRID_MIN: they should be equal to the number of arguments"); - parseVector("GRID_MAX",gmax); - if(gmax.size()!=getNumberOfArguments()) error("Wrong number of values for GRID_MAX: they should be equal to the number of arguments"); - parseVector("GRID_BIN",gbin); - if(gbin.size()!=getNumberOfArguments() && gbin.size()!=0) error("Wrong number of values for GRID_BIN: they should be equal to the number of arguments"); - std::vector<double> gspacing; - parseVector("GRID_SPACING",gspacing); - if(gspacing.size()!=getNumberOfArguments() && gspacing.size()!=0) - error("Wrong number of for GRID_SPACING: they should be equal to the number of arguments"); - if(gbin.size()==0 && gspacing.size()==0) { error("At least one among GRID_BIN and GRID_SPACING should be used"); - } else if(gspacing.size()!=0 && gbin.size()==0) { - log<<" The number of bins will be estimated from GRID_SPACING\n"; - } else if(gspacing.size()!=0 && gbin.size()!=0) { - log<<" You specified both GRID_BIN and GRID_SPACING\n"; - log<<" The more conservative (highest) number of bins will be used for each variable\n"; + // Read stuff for grid + std::vector<std::string> gmin( getNumberOfArguments() ), gmax( getNumberOfArguments() ); + parseVector("GRID_MIN",gmin); parseVector("GRID_MAX",gmax); + + // Setup input for grid vessel + std::string dmin, dmax, vstring = getKeyword("KERNEL") + " " + getKeyword("BANDWIDTH"); + if( getPeriodicityInformation(0, dmin, dmax) ) vstring+=" PBC=T"; + else vstring+=" PBC=F"; + for(unsigned i=1;i<getNumberOfArguments();++i){ + if( getPeriodicityInformation(i, dmin, dmax) ) vstring+=",T"; + else vstring+=",F"; } - if(gbin.size()==0) gbin.assign(getNumberOfArguments(),1); - if(gspacing.size()!=0) for(unsigned i=0;i<getNumberOfArguments();i++){ - double a,b; - Tools::convert(gmin[i],a); - Tools::convert(gmax[i],b); - unsigned n=((b-a)/gspacing[i])+1; - if(gbin[i]<n) gbin[i]=n; + vstring += " STORE_NORMED COMPONENTS=" + getLabel(); + vstring += " COORDINATES=" + getPntrToArgument(0)->getName(); + for(unsigned i=1;i<getNumberOfArguments();++i) vstring += "," + getPntrToArgument(i)->getName(); + if( !usingMemory() ) vstring += " NOMEMORY"; + std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); + std::vector<double> gspacing; parseVector("GRID_SPACING",gspacing); + if( nbin.size()!=getNumberOfArguments() && gspacing.size()!=getNumberOfArguments() ){ + error("GRID_BIN or GRID_SPACING must be set"); } - parseOutputFile("GRID_WFILE",gridfname); - // Read the type of kernel we are using - parse("KERNEL",kerneltype); - if(kerneltype=="DISCRETE") kerneltype="discrete"; - // Read stuff for window functions - parseVector("BANDWIDTH",bw); - if(bw.size()!=getNumberOfArguments()&&kerneltype!="discrete") - error("Wrong number of values for BANDWIDTH: they should be equal to the number of arguments"); + // Create a grid + vesselbase::VesselOptions da("mygrid","",-1,vstring,this); + Keywords keys; gridtools::HistogramOnGrid::registerKeywords( keys ); + vesselbase::VesselOptions dar( da, keys ); + mygrid = new gridtools::HistogramOnGrid(dar); addVessel( mygrid ); + mygrid->setBounds( gmin, gmax, nbin, gspacing ); + resizeFunctions(); - parseFlag("FREE-ENERGY",fenergy); - if(getTemp()<=0 && fenergy) error("Set the temperature (TEMP) if you want a free energy."); - - parseFlag("UNNORMALIZED",unnormalized); - if(unnormalized){ - if(fenergy) log<<" free energy will not be shifted to set its minimum to zero\n"; - else log<<" histogram will not be normalized\n"; - } else { - if(fenergy) log<<" free energy will be shifted to set its minimum to zero\n"; - else log<<" histogram will be normalized\n"; - } checkRead(); - - log.printf(" Using %s kernel functions\n",kerneltype.c_str() ); - log.printf(" Grid min"); - for(unsigned i=0;i<gmin.size();++i) log.printf(" %s",gmin[i].c_str() ); - log.printf("\n"); - log.printf(" Grid max"); - for(unsigned i=0;i<gmax.size();++i) log.printf(" %s",gmax[i].c_str() ); - log.printf("\n"); - log.printf(" Grid bin"); - for(unsigned i=0;i<gbin.size();++i) log.printf(" %u",gbin[i]); - log.printf("\n"); } -void Histogram::performTask( const unsigned& , const unsigned& , MultiValue& ) const { plumed_error(); } - -void Histogram::performAnalysis(){ - // Back up old histogram files - // std::string oldfname=saveResultsFromPreviousAnalyses( gridfname ); - - // Get pbc stuff for grid - std::vector<bool> pbc; std::string dmin,dmax; std::vector<double> pmin,pmax; - pmin.resize(getNumberOfArguments()); - pmax.resize(getNumberOfArguments()); - for(unsigned i=0;i<getNumberOfArguments();++i){ - pbc.push_back( getPeriodicityInformation(i,dmin,dmax) ); - if(pbc[i]){ - Tools::convert(dmin,gmin[i]); - Tools::convert(dmax,gmax[i]); - Tools::convert(dmin,pmin[i]); - Tools::convert(dmax,pmax[i]); - } - } +void Histogram::setAnalysisStride( const bool& use_all, const unsigned& astride ){ + if( getFullNumberOfTasks()>0 && getFullNumberOfTasks()==getNumberOfDataPoints() ) return; + Analysis::setAnalysisStride( use_all, astride ); plumed_assert( getFullNumberOfTasks()==0 ); + for(unsigned i=0;i<getNumberOfDataPoints();++i) addTaskToList( i ); +} - Grid* gg; IFile oldf; oldf.link(*this); - if( usingMemory() && oldf.FileExist(gridfname) ){ - if(fenergy) error("FREE-ENERGY only works with USE_ALL_DATA"); - if(unnormalized) error("UNNORMALIZED only works with USE_ALL_DATA"); - oldf.open(gridfname); - gg = Grid::create( "probs", getArguments(), oldf, gmin, gmax, gbin, false, false, false ); - oldf.close(); - } else { - gg = new Grid( "probs", getArguments(), gmin, gmax, gbin,false,false); - } - // Set output format for grid - gg->setOutputFmt( getOutputFormat() ); +unsigned Histogram::getNumberOfQuantities() const { + return getNumberOfArguments() + 2; +} - // Now build the histogram +void Histogram::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { double weight; std::vector<double> point( getNumberOfArguments() ); - if(kerneltype!="discrete") { - for(unsigned i=0;i<getNumberOfDataPoints();++i){ - getDataPoint( i, point, weight ); - KernelFunctions kernel( point, bw, kerneltype, false, weight, true); - gg->addKernel( kernel ); - } - } else { - for(unsigned i=0;i<getNumberOfDataPoints();++i){ - getDataPoint( i, point, weight ); - // Without KERNEL the point are assigned with a lower approximation (floor) - // in order to have a correct assigmnet points must be translated of half - // the mesh - std::vector<double> dx_; - dx_ = gg->getDx(); - for(unsigned j=0;j<point.size();j++) { - point[j]+=0.5*dx_[j]; - if(pbc[j]&&point[j]>pmax[j]) point[j] -= (pmax[j]-pmin[j]); - } - gg->addValue(gg->getIndex(point), weight); - } - } - - // Normalize the histogram - if(!unnormalized) gg->scaleAllValuesAndDerivatives( 1.0 / getNormalization() ); - if(fenergy) { - gg->logAllValuesAndDerivatives( -getTemp() ); - if(!unnormalized) gg->setMinToZero(); - } + getDataPoint( current, point, weight ); + myvals.setValue( 0, 1.0 ); + for(unsigned j=0;j<getNumberOfArguments();++j) myvals.setValue( 1+j, point[j] ); + myvals.setValue( 1+getNumberOfArguments(), weight ); +} - // Write the grid to a file - OFile gridfile; gridfile.link(*this); gridfile.setBackupString("analysis"); - gridfile.open( gridfname ); gg->writeToFile( gridfile ); - // Close the file - gridfile.close(); delete gg; +void Histogram::performAnalysis(){ + runAllTasks(); mygrid->setNorm( getNormalization() ); } } diff --git a/src/analysis/Makefile b/src/analysis/Makefile index 5e8a0d81a..bdf98d20a 100644 --- a/src/analysis/Makefile +++ b/src/analysis/Makefile @@ -1,4 +1,4 @@ -USE=core tools reference vesselbase +USE=core tools reference vesselbase gridtools #generic makefile include ../maketools/make.module diff --git a/src/core/ActionPilot.cpp b/src/core/ActionPilot.cpp index 0b17378f4..539e1d7ed 100644 --- a/src/core/ActionPilot.cpp +++ b/src/core/ActionPilot.cpp @@ -42,6 +42,11 @@ bool ActionPilot::onStep()const{ int ActionPilot::getStride()const{ return stride; } + +void ActionPilot::setStride( const unsigned& ss ){ + stride=ss; +} + } diff --git a/src/core/ActionPilot.h b/src/core/ActionPilot.h index 61e7bede2..a4a1d74a0 100644 --- a/src/core/ActionPilot.h +++ b/src/core/ActionPilot.h @@ -42,6 +42,7 @@ class ActionPilot: int stride; // multiple time step protected: int getStride()const; + void setStride( const unsigned& ss ); public: explicit ActionPilot(const ActionOptions&); /// Create the keywords for actionPilot diff --git a/src/gridtools/ActionWithInputGrid.cpp b/src/gridtools/ActionWithInputGrid.cpp index f0dfe559e..7ee8323ba 100644 --- a/src/gridtools/ActionWithInputGrid.cpp +++ b/src/gridtools/ActionWithInputGrid.cpp @@ -29,15 +29,17 @@ namespace gridtools { void ActionWithInputGrid::registerKeywords( Keywords& keys ){ Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); + vesselbase::ActionWithVessel::registerKeywords( keys ); keys.add("compulsory","GRID","the action that creates the input grid you would like to use"); - keys.add("compulsory","STRIDE","the frequency with which to output the grid"); + keys.add("optional","STRIDE","the frequency with which to output the grid"); keys.addFlag("USE_ALL_DATA",false,"use the data from the entire trajectory to perform the analysis"); - keys.addFlag("UNORMALISED",false,"output an unormalised grid"); + keys.addFlag("UNNORMALIZED",false,"output an unormalised grid"); } ActionWithInputGrid::ActionWithInputGrid(const ActionOptions&ao): Action(ao), ActionPilot(ao), +ActionWithVessel(ao), norm(0.0), mygrid(NULL) { @@ -53,7 +55,7 @@ mygrid(NULL) } if( !mygrid ) error("input action does not calculate a grid"); - parseFlag("UNORMALISED",unormalised); + parseFlag("UNNORMALIZED",unormalised); if( unormalised ){ log.printf(" working with unormalised grid \n"); mygrid->switchOffNormalisation(); @@ -61,11 +63,18 @@ mygrid(NULL) if( keywords.exists("USE_ALL_DATA") ){ parseFlag("USE_ALL_DATA",single_run); - if( !single_run ) log.printf(" outputting grid every %u steps \n", getStride() ); - else log.printf(" outputting grid at end of calculation\n"); + if( !single_run ){ + mves->setAnalysisStride( false, getStride() ); + log.printf(" outputting grid every %u steps \n", getStride() ); + } else log.printf(" outputting grid at end of calculation\n"); } } +void ActionWithInputGrid::setAnalysisStride( const bool& use_all, const unsigned& astride ){ + single_run=use_all; + if( !single_run ) setStride( astride ); +} + void ActionWithInputGrid::update(){ if( unormalised ) norm = 1.0; else norm=1.0/mygrid->getNorm(); diff --git a/src/gridtools/ActionWithInputGrid.h b/src/gridtools/ActionWithInputGrid.h index 3016bee2c..9b5251641 100644 --- a/src/gridtools/ActionWithInputGrid.h +++ b/src/gridtools/ActionWithInputGrid.h @@ -29,7 +29,9 @@ namespace PLMD { namespace gridtools { class ActionWithInputGrid : -public ActionPilot { +public ActionPilot, +public vesselbase::ActionWithVessel +{ private: double norm; bool unormalised; @@ -46,6 +48,7 @@ public: void update(); void runFinalJobs(); virtual void performOperationsWithGrid( const bool& from_update )=0; + void setAnalysisStride( const bool& use_all, const unsigned& astride ); }; inline diff --git a/src/gridtools/ConvertToFES.cpp b/src/gridtools/ConvertToFES.cpp new file mode 100644 index 000000000..eef7fd498 --- /dev/null +++ b/src/gridtools/ConvertToFES.cpp @@ -0,0 +1,99 @@ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 2011-2015 The plumed team + (see the PEOPLE file at the root of the distribution for a list of names) + + See http://www.plumed-code.org for more information. + + This file is part of plumed, version 2. + + plumed is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + plumed is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with plumed. If not, see <http://www.gnu.org/licenses/>. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +#include "core/ActionRegister.h" +#include "core/PlumedMain.h" +#include "core/Atoms.h" +#include "ActionWithInputGrid.h" +#include "GridFunction.h" + +namespace PLMD { +namespace gridtools { + +class ConvertToFES : public ActionWithInputGrid { +private: + double simtemp; + GridFunction* outgrid; +public: + static void registerKeywords( Keywords& keys ); + explicit ConvertToFES(const ActionOptions&ao); + void performOperationsWithGrid( const bool& from_update ); + unsigned getNumberOfDerivatives(){ return 0; } + unsigned getNumberOfQuantities() const ; + void performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const ; + bool isPeriodic(){ return false; } +}; + +PLUMED_REGISTER_ACTION(ConvertToFES,"CONVERT_TO_FES") + +void ConvertToFES::registerKeywords( Keywords& keys ){ + ActionWithInputGrid::registerKeywords( keys ); + keys.add("optional","TEMP","the temperature at which you are operating"); + keys.reset_style("STRIDE","hidden"); keys.remove("USE_ALL_DATA"); +} + +ConvertToFES::ConvertToFES(const ActionOptions&ao): +Action(ao), +ActionWithInputGrid(ao) +{ + if( mygrid->getNumberOfComponents()!=1 ) error("input grid is vector field and cannot be converted to FES"); + // Create the input from the old string + std::string vstring = "NOMEMORY COMPONENTS=" + getLabel() + " " + mygrid->getInputString(); + + // Create a grid + vesselbase::VesselOptions da("mygrid","",-1,vstring,this); + Keywords keys; GridFunction::registerKeywords( keys ); + vesselbase::VesselOptions dar( da, keys ); + outgrid = new GridFunction(dar); addVessel( outgrid ); std::vector<double> fspacing; + outgrid->setBounds( mygrid->getMin(), mygrid->getMax(), mygrid->getNbin(), fspacing); + if( mygrid->noDerivatives() ) outgrid->setNoDerivatives(); + resizeFunctions(); + + simtemp=0.; parse("TEMP",simtemp); + if(simtemp>0) simtemp*=plumed.getAtoms().getKBoltzmann(); + else simtemp=plumed.getAtoms().getKbT(); + + // Now create task list + for(unsigned i=0;i<mygrid->getNumberOfPoints();++i) addTaskToList(i); +} + +unsigned ConvertToFES::getNumberOfQuantities() const { + if( mygrid->noDerivatives() ) return 2; + return 2 + mygrid->getDimension(); +} + +void ConvertToFES::performOperationsWithGrid( const bool& from_update ){ + outgrid->clear(); runAllTasks(); +} + +void ConvertToFES::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { + double val=getGridElement(current, 0); + myvals.setValue( 0, 1.0 ); myvals.setValue(1, -simtemp*std::log(val) ); + if( !mygrid->noDerivatives() ){ + for(unsigned i=0;i<mygrid->getDimension();++i) myvals.setValue( 2+i, -(simtemp/val)*getGridElement(current,i+1) ); + } +} + + + + +} +} diff --git a/src/gridtools/GridFunction.cpp b/src/gridtools/GridFunction.cpp new file mode 100644 index 000000000..056775b49 --- /dev/null +++ b/src/gridtools/GridFunction.cpp @@ -0,0 +1,48 @@ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 2012-2015 The plumed team + (see the PEOPLE file at the root of the distribution for a list of names) + + See http://www.plumed-code.org for more information. + + This file is part of plumed, version 2. + + plumed is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + plumed is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with plumed. If not, see <http://www.gnu.org/licenses/>. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +#include "GridFunction.h" + +namespace PLMD { +namespace gridtools { + +void GridFunction::registerKeywords( Keywords& keys ){ + GridVessel::registerKeywords( keys ); +} + +GridFunction::GridFunction( const vesselbase::VesselOptions& da ): +GridVessel(da) +{ +} + +bool GridFunction::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { + plumed_dbg_assert( myvals.getNumberOfValues()==(nper+1) ); + for(unsigned i=0;i<myvals.getNumberOfValues();++i) buffer[bufstart + nper*current + i] += myvals.get(i+1); + return true; +} + + +void GridFunction::finish( const std::vector<double>& buffer ){ + for(unsigned i=0;i<data.size();++i) data[i]+=buffer[bufstart + i]; +} + +} +} diff --git a/src/gridtools/GridFunction.h b/src/gridtools/GridFunction.h new file mode 100644 index 000000000..7f8d7f69b --- /dev/null +++ b/src/gridtools/GridFunction.h @@ -0,0 +1,41 @@ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 2012 The plumed team + (see the PEOPLE file at the root of the distribution for a list of names) + + See http://www.plumed-code.org for more information. + + This file is part of plumed, version 2.0. + + plumed is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + plumed is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with plumed. If not, see <http://www.gnu.org/licenses/>. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +#ifndef __PLUMED_gridtools_HistogramOnGrid_h +#define __PLUMED_gridtools_HistogramOnGrid_h + +#include "GridVessel.h" + +namespace PLMD { +namespace gridtools { + +class GridFunction : public GridVessel { +public: + static void registerKeywords( Keywords& keys ); + explicit GridFunction( const vesselbase::VesselOptions& da ); + bool calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const ; + void finish( const std::vector<double>& ); + bool applyForce( std::vector<double>& forces ){ return false; } +}; + +} +} +#endif diff --git a/src/gridtools/GridVessel.cpp b/src/gridtools/GridVessel.cpp index 9b424a516..e0496faac 100644 --- a/src/gridtools/GridVessel.cpp +++ b/src/gridtools/GridVessel.cpp @@ -31,12 +31,12 @@ void GridVessel::registerKeywords( Keywords& keys ){ keys.add("compulsory","COMPONENTS","the names of the components in the vector"); keys.add("compulsory","COORDINATES","the names of the coordinates of the grid"); keys.add("compulsory","PBC","is the grid periodic in each direction or not"); - keys.add("compulsory","NBINS","number of bins in each direction for the grid"); keys.addFlag("NOMEMORY",false,"should the data in the grid be deleted after print/analysis"); } GridVessel::GridVessel( const vesselbase::VesselOptions& da ): Vessel(da), +noderiv(false), bounds_set(false), bold(0), cube_units(1.0) @@ -67,6 +67,16 @@ cube_units(1.0) } } +void GridVessel::setNoDerivatives(){ + nper = ( nper/(1+dimension) ); noderiv=true; + std::vector<std::string> tnames( dimension ), cnames(nper); + for(unsigned i=0;i<dimension;++i) tnames[i]=arg_names[i]; + unsigned k=dimension; for(unsigned i=0;i<nper;++i){ cnames[i]=arg_names[k]; k+=(1+dimension); } + arg_names.resize( dimension + nper ); + for(unsigned i=0;i<dimension;++i) arg_names[i]=tnames[i]; + for(unsigned i=0;i<nper;++i) arg_names[dimension+i]=cnames[i]; +} + void GridVessel::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, const std::vector<unsigned>& binsin, const std::vector<double>& spacing ){ plumed_dbg_assert( smin.size()==dimension && smax.size()==dimension ); @@ -126,6 +136,16 @@ unsigned GridVessel::getIndex( const std::vector<unsigned>& indices ) const { return index; } +unsigned GridVessel::getIndex( const std::vector<double>& point ) const { + plumed_dbg_assert( bounds_set && point.size()==dimension ); + std::vector<unsigned> indices(dimension); + for(unsigned i=0;i<dimension;++i){ + indices[i]=std::floor( (point[i] - min[i])/dx[i] ); + if( pbc[i] ) indices[i]=indices[i]%nbin[i]; + } + return getIndex( indices ); +} + void GridVessel::convertIndexToIndices( const unsigned& index, const std::vector<unsigned>& nnbin, std::vector<unsigned>& indices ) const { unsigned kk=index; indices[0]=index%nnbin[0]; @@ -232,7 +252,8 @@ std::vector<unsigned> GridVessel::getNbin() const { return ngrid; } -void GridVessel::getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, std::vector<unsigned>& neighbors ) const { +void GridVessel::getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, + unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const { plumed_dbg_assert( bounds_set && nneigh.size()==dimension ); std::vector<unsigned> indices( dimension ); @@ -244,19 +265,23 @@ void GridVessel::getNeighbors( const std::vector<double>& pp, const std::vector< num_neigh *=small_bin[i]; } - neighbors.resize( num_neigh ); + neighbors.resize( num_neigh ); num_neighbors=0; std::vector<unsigned> s_indices(dimension), t_indices(dimension); for(unsigned index=0;index<num_neigh;++index){ + bool found=true; convertIndexToIndices( index, small_bin, s_indices ); for(unsigned i=0;i<dimension;++i){ int i0=s_indices[i]-nneigh[i]+indices[i]; - if(!pbc[i] && i0<0) plumed_merror("grid is not large enough"); - if(!pbc[i] && i0>=nbin[i]) plumed_merror("grid is not large engouh"); + if(!pbc[i] && i0<0) found=false; + if(!pbc[i] && i0>=nbin[i]) found=false; if( pbc[i] && i0<0) i0=nbin[i]-(-i0)%nbin[i]; if( pbc[i] && i0>=nbin[i]) i0%=nbin[i]; t_indices[i]=static_cast<unsigned>(i0); } - neighbors[index]=getIndex( t_indices ); + if( found ){ + neighbors[num_neighbors]=getIndex( t_indices ); + num_neighbors++; + } } } @@ -273,6 +298,19 @@ double GridVessel::getCubeUnits() const { return cube_units; } +std::string GridVessel::getInputString() const { + std::string mstring="COORDINATES="+arg_names[0]; + for(unsigned i=1;i<dimension;++i) mstring+="," + arg_names[i]; + mstring += " PBC="; + if( pbc[0] ) mstring +="T"; + else mstring +="F"; + for(unsigned i=1;i<dimension;++i){ + if( pbc[i] ) mstring +=",T"; + else mstring +=",F"; + } + return mstring; +} + } } diff --git a/src/gridtools/GridVessel.h b/src/gridtools/GridVessel.h index 9dfdd8952..84684c3f2 100644 --- a/src/gridtools/GridVessel.h +++ b/src/gridtools/GridVessel.h @@ -32,6 +32,8 @@ namespace gridtools { class GridVessel : public vesselbase::Vessel { private: +/// Do we have derivatives + bool noderiv; /// Have the minimum and maximum for the grid been set bool bounds_set; /// These two variables are used to @@ -74,12 +76,17 @@ protected: /// The grid with all the data values on it std::vector<double> data; /// Get the set of points neighouring a particular location in space - void getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, std::vector<unsigned>& neighbors ) const ; + void getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, + unsigned& num_neighbours, std::vector<unsigned>& neighbors ) const ; +/// Convert a point in space the the correspoinding grid point + unsigned getIndex( const std::vector<double>& p ) const ; public: /// keywords static void registerKeywords( Keywords& keys ); /// Constructor explicit GridVessel( const vesselbase::VesselOptions& ); +/// Remove the derivatives + void setNoDerivatives(); /// Set the minimum and maximum of the grid virtual void setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, const std::vector<unsigned>& nbins, const std::vector<double>& spacing ); /// Get a description of the grid to output to the log @@ -140,6 +147,10 @@ public: /// This gives the normalisation of histograms virtual double getNorm() const ; virtual void switchOffNormalisation(){} +/// Return a string containing the input to the grid so we can clone it + std::string getInputString() const ; +/// Does this have derivatives + bool noDerivatives() const ; }; inline @@ -180,6 +191,7 @@ std::string GridVessel::getComponentName( const unsigned& i ) const { inline unsigned GridVessel::getNumberOfComponents() const { + if( noderiv ) return nper; return nper / ( dimension + 1 ); } @@ -193,6 +205,11 @@ double GridVessel::getNorm() const { return 1.0; } +inline +bool GridVessel::noDerivatives() const { + return noderiv; +} + } } #endif diff --git a/src/gridtools/HistogramOnGrid.cpp b/src/gridtools/HistogramOnGrid.cpp index 6ca321c07..edb89d003 100644 --- a/src/gridtools/HistogramOnGrid.cpp +++ b/src/gridtools/HistogramOnGrid.cpp @@ -36,9 +36,15 @@ HistogramOnGrid::HistogramOnGrid( const vesselbase::VesselOptions& da ): GridVessel(da), norm(0), store_normed(false), -bandwidths(dimension) +bandwidths(dimension), +discrete(false) { - parseFlag("STORE_NORMED",store_normed); parse("KERNEL",kerneltype); parseVector("BANDWIDTH",bandwidths); + parseFlag("STORE_NORMED",store_normed); parse("KERNEL",kerneltype); + if( kerneltype=="discrete" || kerneltype=="DISCRETE" ){ + discrete=true; setNoDerivatives(); + } else { + parseVector("BANDWIDTH",bandwidths); + } } void HistogramOnGrid::switchOffNormalisation(){ @@ -47,10 +53,12 @@ void HistogramOnGrid::switchOffNormalisation(){ void HistogramOnGrid::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, const std::vector<unsigned>& nbins, const std::vector<double>& spacing ){ - GridVessel::setBounds( smin, smax, nbins, spacing ); - std::vector<double> point(dimension,0); - KernelFunctions kernel( point, bandwidths, kerneltype, false, 1.0, true ); - nneigh=kernel.getSupport( dx ); + GridVessel::setBounds( smin, smax, nbins, spacing ); + if( !discrete ){ + std::vector<double> point(dimension,0); + KernelFunctions kernel( point, bandwidths, kerneltype, false, 1.0, true ); + nneigh=kernel.getSupport( dx ); + } } bool HistogramOnGrid::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { @@ -58,27 +66,34 @@ bool HistogramOnGrid::calculate( const unsigned& current, MultiValue& myvals, st // Create a kernel function at the point of interest std::vector<double> point( dimension ); double weight=myvals.get(0)*myvals.get( 1+dimension ); for(unsigned i=0;i<dimension;++i) point[i]=myvals.get( 1+i ); - KernelFunctions kernel( point, bandwidths, kerneltype, false, weight, true ); - - std::vector<unsigned> neighbors; getNeighbors( kernel.getCenter(), nneigh, neighbors ); - std::vector<double> xx( dimension ); std::vector<Value*> vv; - for(unsigned i=0;i<dimension;++i){ - vv.push_back(new Value()); - if( pbc[i] ) vv[i]->setDomain( str_min[i], str_max[i] ); - else vv[i]->setNotPeriodic(); + + if( discrete ){ + for(unsigned i=0;i<dimension;++i) point[i] += 0.5*dx[i]; + buffer[bufstart + nper*getIndex( point )] += weight; + } else { + KernelFunctions kernel( point, bandwidths, kerneltype, false, weight, true ); + + unsigned num_neigh; std::vector<unsigned> neighbors; + getNeighbors( kernel.getCenter(), nneigh, num_neigh, neighbors ); + std::vector<double> xx( dimension ); std::vector<Value*> vv; + for(unsigned i=0;i<dimension;++i){ + vv.push_back(new Value()); + if( pbc[i] ) vv[i]->setDomain( str_min[i], str_max[i] ); + else vv[i]->setNotPeriodic(); + } + + double newval; std::vector<double> der( dimension ); + for(unsigned i=0;i<num_neigh;++i){ + unsigned ineigh=neighbors[i]; + getGridPointCoordinates( ineigh, xx ); + for(unsigned j=0;j<dimension;++j) vv[j]->set(xx[j]); + newval = kernel.evaluate( vv, der, true ); + buffer[bufstart+nper*ineigh ] += newval; + for(unsigned j=0;j<dimension;++j) buffer[bufstart+nper*ineigh + 1 + j] += der[j]; + } + + for(unsigned i=0;i<dimension;++i) delete vv[i]; } - - double newval; std::vector<double> der( dimension ); - for(unsigned i=0;i<neighbors.size();++i){ - unsigned ineigh=neighbors[i]; - getGridPointCoordinates( ineigh, xx ); - for(unsigned j=0;j<dimension;++j) vv[j]->set(xx[j]); - newval = kernel.evaluate( vv, der, true ); - buffer[ nper*ineigh ] += newval; - for(unsigned j=0;j<dimension;++j) buffer[ nper*ineigh + 1 + j] += der[j]; - } - - for(unsigned i=0;i<dimension;++i) delete vv[i]; return true; } @@ -91,7 +106,7 @@ void HistogramOnGrid::clear(){ if( nomemory ){ norm = 0.; GridVessel::clear(); return; } - if( store_normed ){ + if( norm>0 && store_normed ){ for(unsigned i=0;i<data.size();++i) data[i] /= norm; } } diff --git a/src/gridtools/HistogramOnGrid.h b/src/gridtools/HistogramOnGrid.h index cea0b9c02..55438778d 100644 --- a/src/gridtools/HistogramOnGrid.h +++ b/src/gridtools/HistogramOnGrid.h @@ -33,6 +33,7 @@ private: bool store_normed; std::string kerneltype; std::vector<double> bandwidths; + bool discrete; std::vector<unsigned> nneigh; public: static void registerKeywords( Keywords& keys ); diff --git a/src/gridtools/PrintCube.cpp b/src/gridtools/PrintCube.cpp index 993bad2c3..f4955a9f5 100644 --- a/src/gridtools/PrintCube.cpp +++ b/src/gridtools/PrintCube.cpp @@ -33,6 +33,9 @@ public: static void registerKeywords( Keywords& keys ); explicit PrintCube(const ActionOptions&ao); void performOperationsWithGrid( const bool& from_update ); + unsigned getNumberOfDerivatives(){ return 0; } + void performTask( const unsigned& , const unsigned& , MultiValue& ) const {} + bool isPeriodic(){ return false; } }; PLUMED_REGISTER_ACTION(PrintCube,"PRINT_CUBE") diff --git a/src/gridtools/PrintGrid.cpp b/src/gridtools/PrintGrid.cpp index 8ae5f491c..a1ab19260 100644 --- a/src/gridtools/PrintGrid.cpp +++ b/src/gridtools/PrintGrid.cpp @@ -34,6 +34,9 @@ public: static void registerKeywords( Keywords& keys ); explicit PrintGrid(const ActionOptions&ao); void performOperationsWithGrid( const bool& from_update ); + unsigned getNumberOfDerivatives(){ return 0; } + void performTask( const unsigned& , const unsigned& , MultiValue& ) const {} + bool isPeriodic(){ return false; } }; PLUMED_REGISTER_ACTION(PrintGrid,"PRINT_GRID") @@ -62,6 +65,7 @@ void PrintGrid::performOperationsWithGrid( const bool& from_update ){ if( from_update ) ofile.setBackupString("analysis"); ofile.open( filename ); + ofile.addConstantField("normalisation"); for(unsigned i=0;i<mygrid->getDimension();++i){ ofile.addConstantField("min_" + mygrid->getComponentName(i) ); ofile.addConstantField("max_" + mygrid->getComponentName(i) ); @@ -69,11 +73,13 @@ void PrintGrid::performOperationsWithGrid( const bool& from_update ){ ofile.addConstantField("periodic_" + mygrid->getComponentName(i) ); } + double norm = mygrid->getNorm(); std::vector<double> xx( mygrid->getDimension() ); std::vector<unsigned> ind( mygrid->getDimension() ); for(unsigned i=0;i<mygrid->getNumberOfPoints();++i){ mygrid->getIndices( i, ind ); - if(i>0 && mygrid->getDimension()==2 && ind[mygrid->getDimension()-2]==0) ofile.printf("\n"); + if(i>0 && mygrid->getDimension()>1 && ind[mygrid->getDimension()-2]==0) ofile.printf("\n"); + ofile.fmtField(fmt); ofile.printField("normalisation", norm ); for(unsigned j=0;j<mygrid->getDimension();++j){ ofile.printField("min_" + mygrid->getComponentName(j), mygrid->getMin()[j] ); ofile.printField("max_" + mygrid->getComponentName(j), mygrid->getMax()[j] ); diff --git a/src/vesselbase/ActionWithVessel.h b/src/vesselbase/ActionWithVessel.h index 63d4df645..46dfb26ac 100644 --- a/src/vesselbase/ActionWithVessel.h +++ b/src/vesselbase/ActionWithVessel.h @@ -199,6 +199,8 @@ public: Vessel* getVesselWithName( const std::string& mynam ); /// Does the weight have derivatives bool weightWithDerivatives() const ; +/// This is used to set the stride for the output of histograms + virtual void setAnalysisStride( const bool& use_all, const unsigned& astride ){} }; inline -- GitLab