From eb7eed2a1c656d69bbd0de405ff56d428072b648 Mon Sep 17 00:00:00 2001 From: Gareth Tribello <gareth.tribello@gmail.com> Date: Thu, 31 Dec 2015 12:04:54 +0000 Subject: [PATCH] Added find contour action to replace WillardChandler surface action --- regtest/adjmat/rt-dfg-wcsurf/plumed.dat | 4 +- .../crystallization/rt-wcsurface/plumed.dat | 3 +- src/gridtools/ActionWithInputGrid.cpp | 1 + src/gridtools/FindContour.cpp | 169 +++++++++++ src/gridtools/GridVessel.cpp | 111 ++++--- src/gridtools/GridVessel.h | 15 +- src/multicolvar/WillardChandlerSurface.cpp | 272 ------------------ src/tools/Minimise1DBrent.h | 6 +- 8 files changed, 251 insertions(+), 330 deletions(-) create mode 100644 src/gridtools/FindContour.cpp delete mode 100644 src/multicolvar/WillardChandlerSurface.cpp diff --git a/regtest/adjmat/rt-dfg-wcsurf/plumed.dat b/regtest/adjmat/rt-dfg-wcsurf/plumed.dat index 8a89ab0b3..08f843273 100644 --- a/regtest/adjmat/rt-dfg-wcsurf/plumed.dat +++ b/regtest/adjmat/rt-dfg-wcsurf/plumed.dat @@ -6,4 +6,6 @@ clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 # DUMPMULTICOLVAR DATA=clust1 ORIGIN=1 UNITS=A FILE=atoms.xyz # MULTICOLVARDENS DATA=clust1 ORIGIN=1 DIR=xyz NBINS=30,30,30 BANDWIDTH=1.0,1.0,1.0 RUN=1 OFILE=dens.cube -WCSURFACE DATA=clust1 ORIGIN=1 FILE=surface.xyz NBINS=30,30,30 BANDWIDTH=1.0,1.0,1.0 UNITS=A CONTOUR=250.0 PRECISION=4 +dens: MULTICOLVARDENS DATA=clust1 ORIGIN=1 DIR=xyz NBINS=30,30,30 BANDWIDTH=1.0,1.0,1.0 +FIND_CONTOUR GRID=dens CONTOUR=250.0 FILE=surface.xyz PRECISION=4 UNITS=A +# WCSURFACE DATA=clust1 ORIGIN=1 FILE=surface.xyz NBINS=30,30,30 BANDWIDTH=1.0,1.0,1.0 UNITS=A CONTOUR=250.0 PRECISION=4 diff --git a/regtest/crystallization/rt-wcsurface/plumed.dat b/regtest/crystallization/rt-wcsurface/plumed.dat index 3f4be0507..452ac0e42 100644 --- a/regtest/crystallization/rt-wcsurface/plumed.dat +++ b/regtest/crystallization/rt-wcsurface/plumed.dat @@ -6,5 +6,4 @@ DUMPMULTICOLVAR DATA=fcc ORIGIN=1 FILE=atoms.xyz PRECISION=4 dens: MULTICOLVARDENS DATA=fcc ORIGIN=1 DIR=xyz NBINS=14,14,28 BANDWIDTH=1.0,1.0,1.0 PRINT_CUBE GRID=dens STRIDE=1 FILE=dens.cube - -WCSURFACE DATA=fcc ORIGIN=1 NBINS=14,14,28 BANDWIDTH=1.0,1.0,1.0 CONTOUR=0.42 FILE=surface.xyz PRECISION=4 +FIND_CONTOUR GRID=dens STRIDE=1 CONTOUR=0.42 FILE=surface.xyz PRECISION=4 diff --git a/src/gridtools/ActionWithInputGrid.cpp b/src/gridtools/ActionWithInputGrid.cpp index 7ee8323ba..7596d020b 100644 --- a/src/gridtools/ActionWithInputGrid.cpp +++ b/src/gridtools/ActionWithInputGrid.cpp @@ -82,6 +82,7 @@ void ActionWithInputGrid::update(){ } void ActionWithInputGrid::runFinalJobs(){ + if( !single_run ) return ; if( unormalised ) norm = 1.0; else norm=1.0/mygrid->getNorm(); performOperationsWithGrid( false ); diff --git a/src/gridtools/FindContour.cpp b/src/gridtools/FindContour.cpp new file mode 100644 index 000000000..001ec6ce9 --- /dev/null +++ b/src/gridtools/FindContour.cpp @@ -0,0 +1,169 @@ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 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 "tools/OFile.h" +#include "tools/RootFindingBase.h" + +namespace PLMD { +namespace gridtools { + +class FindContour : public ActionWithInputGrid { +private: + OFile of; + double lenunit; + std::string fmt_xyz; + unsigned mycomp; + double contour; +public: + static void registerKeywords( Keywords& keys ); + explicit FindContour(const ActionOptions&ao); + void performOperationsWithGrid( const bool& from_update ); + double getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ); + unsigned getNumberOfDerivatives(){ return 0; } + void performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const {} + bool isPeriodic(){ return false; } +}; + +PLUMED_REGISTER_ACTION(FindContour,"FIND_CONTOUR") + +void FindContour::registerKeywords( Keywords& keys ){ + ActionWithInputGrid::registerKeywords( keys ); + keys.add("compulsory","CONTOUR","the value we would like to draw the contour at in the space"); +// We want a better way of doing this bit + keys.add("compulsory", "FILE", "file on which to output coordinates"); + keys.add("compulsory", "UNITS","PLUMED","the units in which to print out the coordinates. PLUMED means internal PLUMED units"); + keys.add("optional","COMPONENT","if your input is a vector field use this to specifiy the component of the input vector field for which you wish to find the contour"); + keys.add("optional", "PRECISION","The number of digits in trajectory file"); +} + +FindContour::FindContour(const ActionOptions&ao): +Action(ao), +ActionWithInputGrid(ao) +{ + if( mygrid->getNumberOfComponents()==1 ){ + mycomp=0; + } else { + int tcomp=-1; parse("COMPONENT",tcomp); + if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); + mycomp=tcomp; + } + if( mygrid->noDerivatives() ) error("cannot find contours if input grid has no derivatives"); + + parse("CONTOUR",contour); + log.printf(" calculating dividing surface along which function equals %f \n", contour); + + // START OF BIT TO IMPROVE + std::string file; parse("FILE",file); + if(file.length()==0) error("name out output file was not specified"); + std::string type=Tools::extension(file); + log<<" file name "<<file<<"\n"; + if(type!="xyz") error("can only print xyz file type with DUMPMULTICOLVAR"); + + fmt_xyz="%f"; + std::string precision; parse("PRECISION",precision); + if(precision.length()>0){ + int p; Tools::convert(precision,p); + log<<" with precision "<<p<<"\n"; + std::string a,b; + Tools::convert(p+5,a); + Tools::convert(p,b); + fmt_xyz="%"+a+"."+b+"f"; + } + + std::string unitname; parse("UNITS",unitname); + if(unitname!="PLUMED"){ + Units myunit; myunit.setLength(unitname); + lenunit=plumed.getAtoms().getUnits().getLength()/myunit.getLength(); + } + else lenunit=1.0; + // END OF BIT TO IMPROVE + + of.link(*this); + of.open(file); + checkRead(); +} + +double FindContour::getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ){ + return mygrid->getValueAndDerivatives( x, mycomp, der ) - contour; +} + +void FindContour::performOperationsWithGrid( const bool& from_update ){ + std::vector< std::vector<double> > contour_points( mygrid->getDimension()*mygrid->getNumberOfPoints() ); + + // Two points for search + std::vector<unsigned> ind( mygrid->getDimension() ); + std::vector<double> dx( mygrid->getGridSpacing() ); + std::vector<double> direction( mygrid->getDimension(), 0 ); + // Retrieve nbin from grid (remember this returns nbin for restart) + std::vector<unsigned> nbin( mygrid->getNbin() ); + for(unsigned i=0;i<nbin.size();++i){ + if( !mygrid->isPeriodic(i) ) nbin[i]+=1; + } + + // Run over whole grid + unsigned npoints=0; RootFindingBase<FindContour> mymin( this ); + for(unsigned i=0;i<mygrid->getNumberOfPoints();++i){ + // Get the index of the current grid point + mygrid->getIndices( i, ind ); + + // Get the value of a point on the grid + double val1=getGridElement( i, mycomp*(mygrid->getDimension()+1) ) - contour; + + bool edge=false; + for(unsigned j=0;j<mygrid->getDimension();++j){ + // Make sure we don't search at the edge of the grid + if( !mygrid->isPeriodic(j) && (ind[j]+1)==nbin[j] ) continue; + else if( (ind[j]+1)==nbin[j] ){ edge=true; ind[j]=0; } + else ind[j]+=1; + double val2=getGridElement(ind,mycomp*(mygrid->getDimension()+1)) - contour; + if( val1*val2<0 ){ + // Use initial point location as first guess for search + contour_points[npoints].resize( mygrid->getDimension() ); + mygrid->getGridPointCoordinates( i, contour_points[npoints] ); + // Setup direction vector + direction[j]=0.9999*dx[j]; + // And do proper search for contour point + mymin.linesearch( direction, contour_points[npoints], &FindContour::getDifferenceFromContour ); + direction[j]=0.0; npoints++; + } + if( mygrid->isPeriodic(j) && edge ){ edge=false; ind[j]=nbin[j]-1; } + else ind[j]-=1; + } + + } + + of.printf("%u\n",npoints); + of.printf("Points found on isocontour\n"); + const char* nn="X"; Vector cpos; + for(unsigned i=0;i<npoints;++i){ + for(unsigned j=0;j<3;++j) cpos[j]=contour_points[i][j]; + // cpos=mycolv->getPbc().scaledToReal(fpos); + of.printf(("%s "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz).c_str(),nn,lenunit*cpos[0], lenunit*cpos[1], lenunit*cpos[2] ); + of.printf("\n"); + } +} + +} +} diff --git a/src/gridtools/GridVessel.cpp b/src/gridtools/GridVessel.cpp index e0496faac..9039b94d0 100644 --- a/src/gridtools/GridVessel.cpp +++ b/src/gridtools/GridVessel.cpp @@ -38,7 +38,6 @@ GridVessel::GridVessel( const vesselbase::VesselOptions& da ): Vessel(da), noderiv(false), bounds_set(false), -bold(0), cube_units(1.0) { std::vector<std::string> compnames; parseVector("COMPONENTS",compnames); @@ -48,9 +47,6 @@ cube_units(1.0) str_min.resize( dimension); str_max.resize( dimension ); parseFlag("NOMEMORY",nomemory); - tmp_indices.resize( str_min.size() ); - current_neigh.resize( static_cast<unsigned>(pow(2.,dimension)) ); - unsigned n=0; nper=compnames.size()*( 1 + coordnames.size() ); arg_names.resize( coordnames.size() + compnames.size()*( 1 + coordnames.size() ) ); for(unsigned i=0;i<coordnames.size();++i){ arg_names[n] = coordnames[i]; n++; } @@ -136,13 +132,17 @@ 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); +void GridVessel::getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const { + plumed_dbg_assert( bounds_set && point.size()==dimension && indices.size()==dimension ); for(unsigned i=0;i<dimension;++i){ - indices[i]=std::floor( (point[i] - min[i])/dx[i] ); + indices[i]=std::floor( (point[i] - min[i])/dx[i] ); if( pbc[i] ) indices[i]=indices[i]%nbin[i]; } +} + +unsigned GridVessel::getIndex( const std::vector<double>& point ) const { + plumed_dbg_assert( bounds_set && point.size()==dimension ); + std::vector<unsigned> indices(dimension); getIndices( point, indices ); return getIndex( indices ); } @@ -169,42 +169,22 @@ void GridVessel::getGridPointCoordinates( const unsigned& ipoint , std::vector<d for(unsigned i=0;i<dimension;++i) x[i] = min[i] + dx[i]*tindices[i]; } -unsigned GridVessel::getLocationOnGrid( const std::vector<double>& x, std::vector<double>& dd ){ - plumed_dbg_assert( bounds_set && x.size()==dimension && dd.size()==dimension ); - getIndices( bold, tmp_indices ); bool changebox=false; - for(unsigned i=0;i<dimension;++i){ - double bb = x[i] - min[i]; - if ( bb<0.0 || bb>dx[i]*nbin[i] ){ - getAction()->error("Extrapolation of function is not allowed"); - } else if( bb<tmp_indices[i]*dx[i] || bb>(tmp_indices[i]+1)*dx[i] ){ - tmp_indices[i]=static_cast<unsigned>( std::floor(bb/dx[i]) ); - changebox=true; +void GridVessel::getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ) const { + mysneigh.resize( static_cast<unsigned>(pow(2.,dimension)) ); + + std::vector<unsigned> tmp_indices( dimension ); + std::vector<unsigned> my_indices( dimension ); + getIndices( mybox, my_indices ); + for(unsigned i=0;i<mysneigh.size();++i){ + unsigned tmp=i; + for(unsigned j=0;j<dimension;++j){ + unsigned i0=tmp%2+my_indices[j]; tmp/=2; + if(!pbc[j] && i0==nbin[j]) getAction()->error("Extrapolating function on grid"); + if( pbc[j] && i0==nbin[j]) i0=0; + tmp_indices[j]=i0; } - dd[i] = bb/dx[i] - static_cast<double>(tmp_indices[i]); + mysneigh[i]=getIndex( tmp_indices ); } - if(changebox) bold = getIndex( tmp_indices ); - return bold; -} - -void GridVessel::getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ){ - if( mysneigh.size()!=current_neigh.size() ) mysneigh.resize( current_neigh.size() ); - - if( bold!=mybox ){ - std::vector<unsigned> my_indices( dimension ); - getIndices( mybox, my_indices ); - for(unsigned i=0;i<current_neigh.size();++i){ - unsigned tmp=i; - for(unsigned j=0;j<dimension;++j){ - unsigned i0=tmp%2+my_indices[j]; tmp/=2; - if(!pbc[j] && i0==nbin[j]) getAction()->error("Extrapolating function on grid"); - if( pbc[j] && i0==nbin[j]) i0=0; - tmp_indices[j]=i0; - } - current_neigh[i]=getIndex( tmp_indices ); - } - bold=mybox; - } - for(unsigned i=0;i<current_neigh.size();++i) mysneigh[i]=current_neigh[i]; } double GridVessel::getGridElement( const unsigned& ipoint, const unsigned& jelement ) const { @@ -311,6 +291,53 @@ std::string GridVessel::getInputString() const { return mstring; } +double GridVessel::getValueAndDerivatives( const std::vector<double>& x, const unsigned& ind, std::vector<double>& der ) const { + plumed_dbg_assert( der.size()==dimension && !noderiv && ind<getNumberOfComponents() ); + + double X,X2,X3,value=0; der.assign(der.size(),0.0); + std::vector<double> fd(dimension); + std::vector<double> C(dimension); + std::vector<double> D(dimension); + std::vector<double> dder(dimension); + + std::vector<unsigned> nindices(dimension); + std::vector<unsigned> indices(dimension); getIndices( x, indices ); + std::vector<unsigned> neigh; getSplineNeighbors( getIndex(indices), neigh ); + std::vector<double> xfloor(dimension); getGridPointCoordinates( getIndex(x), xfloor ); + +// loop over neighbors + for(unsigned int ipoint=0;ipoint<neigh.size();++ipoint){ + double grid=getGridElement(neigh[ipoint], ind*(1+dimension) ); + for(unsigned j=0;j<dimension;++j) dder[j] = getGridElement( neigh[ipoint], ind*(1+dimension) + 1 + j ); + + getIndices( neigh[ipoint], nindices ); + double ff=1.0; + + for(unsigned j=0;j<dimension;++j){ + int x0=1; + if(nindices[j]==indices[j]) x0=0; + double ddx=dx[j]; + X=fabs((x[j]-xfloor[j])/ddx-(double)x0); + X2=X*X; + X3=X2*X; + double yy; + if(fabs(grid)<0.0000001) yy=0.0; + else yy=-dder[j]/grid; + C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*ddx; + D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*ddx; + D[j]*=(x0?-1.0:1.0)/ddx; + ff*=C[j]; + } + for(unsigned j=0;j<dimension;++j){ + fd[j]=D[j]; + for(unsigned i=0;i<dimension;++i) if(i!=j) fd[j]*=C[i]; + } + value+=grid*ff; + for(unsigned j=0;j<dimension;++j) der[j]+=grid*fd[j]; + } + return value; +} + } } diff --git a/src/gridtools/GridVessel.h b/src/gridtools/GridVessel.h index 84684c3f2..cf303df71 100644 --- a/src/gridtools/GridVessel.h +++ b/src/gridtools/GridVessel.h @@ -36,15 +36,10 @@ private: bool noderiv; /// Have the minimum and maximum for the grid been set bool bounds_set; -/// These two variables are used to -/// remember the box we were in on the previous call - unsigned bold; /// The number of points in the grid unsigned npoints; /// Units for Gaussian Cube file double cube_units; -/// Remember the neighbors that were used last time - std::vector<unsigned> current_neigh; /// The names of the various columns in the grid file std::vector<std::string> arg_names; /// The minimum and maximum of the grid stored as doubles @@ -53,8 +48,6 @@ private: std::vector<unsigned> stride; /// The number of bins in each grid direction std::vector<unsigned> nbin; -/// A tempory array that can be used to store indices for a point - std::vector<unsigned> tmp_indices; /// Flatten the grid and get the grid index for a point unsigned getIndex( const std::vector<unsigned>& indices ) const ; /// The grid point that was requested last by getGridPointCoordinates @@ -78,6 +71,8 @@ protected: /// Get the set of points neighouring a particular location in space void getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, unsigned& num_neighbours, std::vector<unsigned>& neighbors ) const ; +/// Get the indices of a particular point + void getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const ; /// Convert a point in space the the correspoinding grid point unsigned getIndex( const std::vector<double>& p ) const ; public: @@ -130,10 +125,8 @@ public: double getCellVolume() const ; /// Get the value of the ith grid element double getGridElement( const unsigned&, const unsigned& ) const ; -/// Get the numerical index for the box that contains a particular point - unsigned getLocationOnGrid( const std::vector<double>& x, std::vector<double>& dd ); /// Get the points neighboring a particular spline point - void getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ); + void getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ) const ; /// Get the spacing between grid points const std::vector<double>& getGridSpacing() const ; /// Get the extent of the grid in one of the axis @@ -151,6 +144,8 @@ public: std::string getInputString() const ; /// Does this have derivatives bool noDerivatives() const ; +/// Get the value and derivatives at a particular location using spline interpolation + double getValueAndDerivatives( const std::vector<double>& x, const unsigned& ind, std::vector<double>& der ) const ; }; inline diff --git a/src/multicolvar/WillardChandlerSurface.cpp b/src/multicolvar/WillardChandlerSurface.cpp deleted file mode 100644 index f9dc0fd25..000000000 --- a/src/multicolvar/WillardChandlerSurface.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Copyright (c) 2015,2016 The plumed team - (see the PEOPLE file at the root of the distribution for a list of names) - - See http://www.plumed.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/ActionAtomistic.h" -#include "core/ActionPilot.h" -#include "core/ActionRegister.h" -#include "tools/Pbc.h" -#include "tools/File.h" -#include "core/PlumedMain.h" -#include "core/Atoms.h" -#include "tools/Units.h" -#include <cstdio> -#include "core/SetupMolInfo.h" -#include "core/ActionSet.h" -#include "MultiColvarBase.h" -#include "tools/Grid.h" -#include "tools/OFile.h" -#include "tools/KernelFunctions.h" -#include "vesselbase/ActionWithInputVessel.h" -#include "vesselbase/StoreDataVessel.h" - -using namespace std; - -namespace PLMD { -namespace multicolvar { - -//+PLUMEDOC ANALYSIS WCSURFACE -/* -Calculate the Willard Chanlder dividing surface - -\par Examples - - -*/ -//+ENDPLUMEDOC - -class WillardChandlerSurface : - public ActionPilot, - public ActionAtomistic, - public vesselbase::ActionWithInputVessel -{ - std::string kerneltype; - unsigned rstride; - std::string filename; - unsigned dir; - double contour; - OFile of; - double lenunit; - std::string fmt_xyz; - MultiColvarBase* mycolv; - std::vector<unsigned> nbins; - std::vector<double> bw; - std::vector<bool> nosearch_dirs, confined; - std::vector<double> cmin, cmax; -public: - explicit WillardChandlerSurface(const ActionOptions&); - static void registerKeywords( Keywords& keys ); - void calculate(){} - void calculateNumericalDerivatives( ActionWithValue* a=NULL ){ plumed_error(); } - void apply(){} - void update(); -}; - -PLUMED_REGISTER_ACTION(WillardChandlerSurface,"WCSURFACE") - -void WillardChandlerSurface::registerKeywords( Keywords& keys ){ - Action::registerKeywords( keys ); - ActionPilot::registerKeywords( keys ); - ActionAtomistic::registerKeywords( keys ); - ActionWithInputVessel::registerKeywords( keys ); - keys.add("compulsory","STRIDE","1","the frequency with which the data should be collected and added to the grid"); - keys.add("atoms","ORIGIN","we will use the position of this atom as the origin"); - keys.add("compulsory","NBINS","the number of bins to use to represent the density profile"); - keys.add("compulsory","BANDWIDTH","the bandwidths for kernel density esimtation"); - keys.add("compulsory","KERNEL","gaussian","the kernel function you are using. More details on the kernels available " - "in plumed plumed can be found in \\ref kernelfunctions."); - keys.add("compulsory","CONTOUR","the value we would like to draw the contour at in the space"); -// We want a better way of doing this bit - keys.add("compulsory", "FILE", "file on which to output coordinates"); - keys.add("compulsory", "UNITS","PLUMED","the units in which to print out the coordinates. PLUMED means internal PLUMED units"); - keys.add("optional", "PRECISION","The number of digits in trajectory file"); - keys.addFlag("NO_X_SEARCH",false,""); - keys.addFlag("XREDUCED",false,""); - keys.add("optional","XLOWER",""); - keys.add("optional","XUPPER",""); - keys.addFlag("NO_Y_SEARCH",false,""); - keys.addFlag("YREDUCED",false,""); - keys.add("optional","YLOWER",""); - keys.add("optional","YUPPER",""); - keys.addFlag("NO_Z_SEARCH",false,""); - keys.addFlag("ZREDUCED",false,""); - keys.add("optional","ZLOWER",""); - keys.add("optional","ZUPPER",""); -// Better way for this bit -} - -WillardChandlerSurface::WillardChandlerSurface(const ActionOptions&ao): - Action(ao), - ActionPilot(ao), - ActionAtomistic(ao), - ActionWithInputVessel(ao), - nosearch_dirs(3,false), - confined(3,false), - cmin(3), - cmax(3) -{ - std::vector<AtomNumber> atom; parseAtomList("ORIGIN",atom); - if( atom.size()!=1 ) error("should only be one atom specified"); - log.printf(" origin is at position of atom : %d\n",atom[0].serial() ); - - readArgument("store"); - mycolv = dynamic_cast<MultiColvarBase*>( getDependencies()[0] ); - plumed_assert( getDependencies().size()==1 ); - if(!mycolv) error("action labeled " + mycolv->getLabel() + " is not a multicolvar"); - - parse("KERNEL",kerneltype); parseVector("BANDWIDTH",bw); parseVector("NBINS",nbins); parse("CONTOUR",contour); - if( bw.size()!=3 || nbins.size()!=3 ) error("wrong size found for bandwidth vector or number of bins"); - log.printf(" calculating dividing surface where average equals %f along ", contour); - log.printf(" for colvars calculated by action %s \n",mycolv->getLabel().c_str() ); - - // Read in confinement stuff - bool tflag; - parseFlag("XREDUCED",tflag); confined[0]=tflag; - parseFlag("NO_X_SEARCH",tflag); nosearch_dirs[0]=tflag; - if( confined[0] ){ - cmin[0]=cmax[0]=0.0; - parse("XLOWER",cmin[0]); parse("XUPPER",cmax[0]); - if( fabs(cmin[0]-cmax[0])<epsilon ) error("range set for x axis search makes no sense"); - log.printf(" confining search in x direction to between %f and %f \n",cmin[0],cmax[0]); - } - parseFlag("YREDUCED",tflag); confined[1]=tflag; - parseFlag("NO_Y_SEARCH",tflag); nosearch_dirs[1]=tflag; - if( confined[1] ){ - cmin[1]=cmax[1]=0.0; - parse("YLOWER",cmin[1]); parse("YUPPER",cmax[1]); - if( fabs(cmin[1]-cmax[1])<epsilon ) error("range set for y axis search makes no sense"); - log.printf(" confining search in y direction to between %f and %f \n",cmin[1],cmax[1]); - } - parseFlag("ZREDUCED",tflag); confined[2]=tflag; - parseFlag("NO_Z_SEARCH",tflag); nosearch_dirs[2]=tflag; - if( confined[2] ){ - cmin[2]=cmax[2]=0.0; - parse("ZLOWER",cmin[2]); parse("ZUPPER",cmax[2]); - if( fabs(cmin[2]-cmax[2])<epsilon ) error("range set for z axis search makes no sense"); - log.printf(" confining search in z direction to between %f and %f \n",cmin[2],cmax[2]); - } - - // START OF BIT TO IMPROVE - std::string file; parse("FILE",file); - if(file.length()==0) error("name out output file was not specified"); - std::string type=Tools::extension(file); - log<<" file name "<<file<<"\n"; - if(type!="xyz") error("can only print xyz file type with DUMPMULTICOLVAR"); - - fmt_xyz="%f"; - std::string precision; parse("PRECISION",precision); - if(precision.length()>0){ - int p; Tools::convert(precision,p); - log<<" with precision "<<p<<"\n"; - string a,b; - Tools::convert(p+5,a); - Tools::convert(p,b); - fmt_xyz="%"+a+"."+b+"f"; - } - - std::string unitname; parse("UNITS",unitname); - if(unitname!="PLUMED"){ - Units myunit; myunit.setLength(unitname); - lenunit=plumed.getAtoms().getUnits().getLength()/myunit.getLength(); - } - else lenunit=1.0; - // END OF BIT TO IMPROVE - - of.link(*this); - of.open(file); - - checkRead(); requestAtoms(atom); - // Stupid dependencies cleared by requestAtoms - why GBussi why? That's got me so many times - addDependency( mycolv ); -} - -void WillardChandlerSurface::update(){ - std::vector<bool> pbc(nbins.size()); std::vector<double> min(nbins.size()), max(nbins.size()); - std::vector<std::string> args(nbins.size()), gmin(nbins.size()), gmax(nbins.size());; - args[0]="x"; args[1]="y"; args[2]="z"; - for(unsigned i=0;i<3;++i){ min[i]=-0.5; max[i]=0.5; pbc[i]=!confined[i]; } - - if( !mycolv->getPbc().isOrthorombic() ){ - error("I think that Willard-Chandler surfaces with non-orthorhombic cells don't work. If you want it have a look and see if you can work it out"); - } - - // Get the box (this is going to give us the extent of the grid) - for(unsigned i=0;i<3;++i){ - if( !confined[i] ){ - min[i]*=mycolv->getBox()(i,i); max[i]*=mycolv->getBox()(i,i); - } else { - min[i]=cmin[i]; max[i]=cmax[i]; - } - } - - // This will be the only thing we keep eventually - for(unsigned i=0;i<3;++i){ Tools::convert(min[i],gmin[i]); Tools::convert(max[i],gmax[i]); } - - // Setup the grid - std::string funcl=mycolv->getLabel() + ".dens"; - Grid gg(funcl,args,gmin,gmax,nbins,true,true,true,pbc,gmin,gmax); - - vesselbase::StoreDataVessel* stash=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToArgument() ); - plumed_dbg_assert( stash ); std::vector<double> cvals( mycolv->getNumberOfQuantities() ); - Vector origin = getPosition(0); std::vector<double> pp( 3 ); Vector fpos; - - unsigned rank=comm.Get_rank(), size=comm.Get_size(); - - for(unsigned i=rank;i<mycolv->getFullNumberOfTasks();i+=size){ - // Skip if task was not active on last run through - if( !mycolv->taskIsCurrentlyActive(i) ) continue ; - - stash->retrieveValue( i, false, cvals ); - Vector apos = pbcDistance( mycolv->getCentralAtomPos( mycolv->getTaskCode(i) ), origin ); - - // fpos = getPbc().realToScaled( apos ); Ideally want to do with scaled coordinates eventually GAT - for(unsigned j=0;j<3;++j) pp[j]=apos[j]; - - KernelFunctions kernel( pp, bw, kerneltype, false, cvals[0]*cvals[1], true ); - gg.addKernel( kernel ); - } - gg.mpiSumValuesAndDerivatives( comm ); - - unsigned npoints=0; std::vector<std::vector<double> > contour_points; - gg.findSetOfPointsOnContour( contour, nosearch_dirs, npoints, contour_points ); - if(npoints==0 ) warning("found no points on Willard-Chandler surface try changing the CONTOUR parameter"); - - of.printf("%u\n",npoints); - const Tensor & t(mycolv->getPbc().getBox()); - if(mycolv->getPbc().isOrthorombic()){ - of.printf((" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(),lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); - }else{ - of.printf((" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(), - lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), - lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), - lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) - ); - } - const char* nn="X"; Vector cpos; - for(unsigned i=0;i<npoints;++i){ - for(unsigned j=0;j<3;++j) cpos[j]=contour_points[i][j]; - // cpos=mycolv->getPbc().scaledToReal(fpos); - of.printf(("%s "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz).c_str(),nn,lenunit*cpos[0], lenunit*cpos[1], lenunit*cpos[2] ); - of.printf("\n"); - } -} - -} -} diff --git a/src/tools/Minimise1DBrent.h b/src/tools/Minimise1DBrent.h index ee6761e32..b0f67c84c 100644 --- a/src/tools/Minimise1DBrent.h +++ b/src/tools/Minimise1DBrent.h @@ -45,7 +45,7 @@ private: /// Use to prevent any possible division by zero const double TINY; /// Maximum number of interactions in line minimiser - const int ITMAX; + const unsigned ITMAX; /// The value of the golden ratio const double CGOLD; /// A small number that protects against trying to achieve fractional @@ -78,10 +78,10 @@ TINY(1.0E-20), ITMAX(100), CGOLD(0.3819660), ZEPS(epsilon*1.0E-3), -myclass_func(pf), ax(0),bx(0),cx(0), fa(0),fb(0),fc(0), -fmin(0) +fmin(0), +myclass_func(pf) { } -- GitLab