22 #include "CVs/CVManager.h"
23 #include "Drivers/DriverException.h"
24 #include "Validator/ObjectRequirement.h"
43 if(world_.rank() == 0)
45 worldout_.open(filename_);
50 auto cvs = cvmanager.
GetCVs(cvmask_);
63 wdotp1_.setZero(dim_);
64 wdotp2_.setZero(dim_);
82 auto cvs = cvmanager.
GetCVs(cvmask_);
93 Eigen::MatrixXd J(dim_, 3*n);
96 std::vector<double> cvVals(dim_);
99 for(
int i = 0; i < dim_; ++i)
101 auto& grad = cvs[i]->GetGradient();
102 for(
size_t j = 0; j < n; ++j)
103 J.block<1, 3>(i,3*j) = grad[j];
104 cvVals[i] = cvs[i]->GetValue();
108 Eigen::MatrixXd Jmass = J.transpose();
111 for(
size_t i = 0; i < forces.size(); ++i)
112 Jmass.block(3*i, 0, 3, dim_) = Jmass.block(3*i, 0, 3, dim_)/mass[i];
115 Eigen::MatrixXd Minv = J*Jmass;
116 MPI_Allreduce(MPI_IN_PLACE, Minv.data(), Minv.size(), MPI_DOUBLE, MPI_SUM, comm_);
117 Eigen::MatrixXd Wt = Minv.inverse()*Jmass.transpose();
119 Eigen::VectorXd momenta(3*vels.size());
120 for(
size_t i = 0; i < vels.size(); ++i)
121 momenta.segment<3>(3*i) = mass[i]*vels[i];
124 Eigen::VectorXd wdotp = Wt*momenta;
128 MPI_Allreduce(MPI_IN_PLACE, wdotp.data(), wdotp.size(), MPI_DOUBLE, MPI_SUM, comm_);
133 Eigen::VectorXd dwdotpdt = unitconv_*(1.5*wdotp - 2.0*wdotp1_ + 0.5*wdotp2_)/timestep_ + Fold_;
136 if(boundsCheck(cvVals))
138 for(
size_t i=0; i<dim_; ++i)
139 F_[i]->at(cvVals) += dwdotpdt[i];
144 for(
size_t i=0; i<dim_; ++i)
145 MPI_Allreduce(F_[i]->data(), Fworld_[i]->data(), (F_[i]->size()), MPI_DOUBLE, MPI_SUM, world_);
146 MPI_Allreduce(N_->data(), Nworld_->data(), N_->size(), MPI_INT, MPI_SUM, world_);
149 if(boundsCheck(cvVals))
151 for(
size_t i=0; i < dim_; ++i)
152 Fold_[i] = Fworld_[i]->at(cvVals)/std::max(min_, Nworld_->at(cvVals));
160 if(iteration_ % FBackupInterv_ == 0)
165 CalcBiasForce(snapshot, cvs, cvVals);
169 for (
size_t j = 0; j < forces.size(); ++j)
170 forces[j] += biases_[j];
179 void ABF::CalcBiasForce(
const Snapshot* snapshot,
const CVList& cvs,
const std::vector<double> &cvVals)
183 for(
auto& b : biases_)
187 if(boundsCheck(cvVals))
189 for(
int i = 0; i < dim_; ++i)
191 auto& grad = cvs[i]->GetGradient();
192 for(
size_t j = 0; j < biases_.size(); ++j)
193 biases_[j] -= (Fworld_[i]->at(cvVals))*grad[j]/std::max(min_,Nworld_->at(cvVals));
199 for(
int i = 0; i < dim_; ++i)
201 double cvVal = cvs[i]->GetValue();
207 double periodsize = periodicboundaries_[i][1]-periodicboundaries_[i][0];
208 double cvRestrMidpoint = (restraint_[i][1]+restraint_[i][0])/2;
209 while((cvVal-cvRestrMidpoint) > periodsize/2)
211 while((cvVal-cvRestrMidpoint) < -periodsize/2)
215 if(cvVal < restraint_[i][0] && restraint_[i][2] > 0)
217 k = restraint_[i][2];
218 x0 = restraint_[i][0];
220 else if (cvVal > restraint_[i][1] && restraint_[i][2] > 0)
222 k = restraint_[i][2];
223 x0 = restraint_[i][1];
226 auto& grad = cvs[i]->GetGradient();
227 for(
size_t j = 0; j < biases_.size(); ++j)
228 biases_[j] -= (cvVal - x0)*k*grad[j];
235 void ABF::WriteData()
238 if(world_.rank() != 0)
242 Nworld_->WriteToFile(Nworld_filename_);
243 for(
size_t i = 0 ; i < dim_; ++i)
245 Fworld_[i]->WriteToFile(Fworld_filename_+std::to_string(i));
251 for(
size_t i = 0 ; i < dim_; ++i)
252 gridPoints = gridPoints * N_->GetNumPoints(i);
254 worldout_.open(filename_,std::ios::out);
255 worldout_ << std::endl;
256 worldout_ <<
"Iteration: " << iteration_ << std::endl;
257 worldout_ <<
"Printing out the current Adaptive Biasing Vector Field." << std::endl;
258 worldout_ <<
"First (Nr of CVs) columns are the coordinates, the next (Nr of CVs) columns are components of the Adaptive Force vector at that point." << std::endl;
259 worldout_ <<
"The columns are " << gridPoints <<
" long, mapping out a surface of ";
261 for(
size_t i = 0 ; i < dim_-1; ++i)
262 worldout_ << (N_->GetNumPoints())[i] <<
" by " ;
263 worldout_ << (N_->GetNumPoints(dim_-1)) <<
" points in " << dim_ <<
" dimensions." << std::endl;
264 worldout_ << std::endl;
266 std::vector<int> printCoords(dim_);
269 std::vector<double> tempcoord(dim_);
270 for(
size_t i = 0; i < gridPoints; ++i)
272 printCoords[0] = i%(Nworld_->GetNumPoints(0));
274 for(
size_t j = 1; j < dim_; ++j)
276 div = div * Nworld_->GetNumPoints(j);
277 printCoords[j]=i/div;
279 for(
size_t j = 0; j < dim_; ++j)
281 worldout_ << std::setw(10) << (printCoords[j]+0.5)*((Nworld_->GetUpper(j)-Nworld_->GetLower(j))/Nworld_->GetNumPoints(j)) + Nworld_->GetLower(j) <<
" ";
282 tempcoord[j] = ((printCoords[j]+0.5)*((Nworld_->GetUpper(j)-Nworld_->GetLower(j))/Nworld_->GetNumPoints(j)) + Nworld_->GetLower(j));
284 for(
size_t j = 0; j < dim_; ++j)
286 worldout_ << std::setw(10) << (Fworld_[j]->at(tempcoord))/std::max(Nworld_->at(tempcoord),min_)<<
" ";
288 worldout_ << std::endl;
292 worldout_ << std::endl;
293 worldout_ << std::endl;
298 bool ABF::boundsCheck(
const std::vector<double> &CVs)
300 for(
size_t i = 0; i < dim_ ; ++i)
302 if((CVs[i] < N_->GetLower(i)) || (CVs[i] > N_->GetUpper(i)))
311 ABF* ABF::Build(
const Value& json,
312 const MPI_Comm& world,
313 const MPI_Comm& comm,
314 const std::string& path)
320 reader.parse(JsonSchema::ABFMethod, schema);
321 validator.
Parse(schema, path);
328 uint wid = mxx::comm(world).rank()/mxx::comm(comm).size();
333 std::vector<double> minsCV;
334 for(
auto& mins : json[
"CV_lower_bounds"])
337 throw BuildException({
"Separate inputs for multi-walker not fully implemented. Please use global entries for CV ranges"});
343 minsCV.push_back(mins.asDouble());
346 std::vector<double> maxsCV;
347 for(
auto& maxs : json[
"CV_upper_bounds"])
354 maxsCV.push_back(maxs.asDouble());
357 std::vector<int> binsCV;
358 for(
auto& bins : json[
"CV_bins"])
359 binsCV.push_back(bins.asInt());
362 std::vector<double> minsrestCV;
363 for(
auto& mins : json[
"CV_restraint_minimums"])
370 minsrestCV.push_back(mins.asDouble());
373 std::vector<double> maxsrestCV;
374 for(
auto& maxs : json[
"CV_restraint_maximums"])
381 maxsrestCV.push_back(maxs.asDouble());
384 std::vector<double> springkrestCV;
385 for(
auto& bins : json[
"CV_restraint_spring_constants"])
386 springkrestCV.push_back(bins.asDouble());
389 std::vector<bool> isperiodic;
390 for(
auto& isperCV : json[
"CV_isperiodic"])
391 isperiodic.push_back(isperCV.asBool());
394 std::vector<double> minperboundaryCV;
395 for(
auto& minsperCV : json[
"CV_periodic_boundary_lower_bounds"])
396 minperboundaryCV.push_back(minsperCV.asDouble());
399 std::vector<double> maxperboundaryCV;
400 for(
auto& maxsperCV : json[
"CV_periodic_boundary_upper_bounds"])
401 maxperboundaryCV.push_back(maxsperCV.asDouble());
404 if(!(( minsCV.size() == maxsCV.size() &&
405 maxsCV.size() == minsrestCV.size() &&
406 minsrestCV.size() == maxsrestCV.size()) &&
407 (binsCV.size() == springkrestCV.size() &&
408 springkrestCV.size() == isperiodic.size())))
409 throw BuildException({
"CV lower bounds, upper bounds, restrain minimums, restrains maximums must match in size. Bins, spring constants and periodicity info must match in size."});
412 bool anyperiodic=
false;
413 for(
size_t i = 0; i<isperiodic.size(); ++i)
417 if(!(isperiodic.size() == minperboundaryCV.size() &&
418 minperboundaryCV.size() == maxperboundaryCV.size()))
419 throw BuildException({
"If any CV is defined as periodic, please define the full upper and lower bound vectors. They should both have the same number of entries as CV lower bounds, upper bounds... Entries corresponding to non-periodic CVs will not be used."});
422 int dim = binsCV.size();
425 auto FBackupInterv = json.get(
"output_frequency", 1000).asInt();
426 auto unitconv = json.get(
"unit_conversion", 0).asDouble();
427 auto timestep = json.get(
"timestep", 2).asDouble();
428 auto min = json.get(
"minimum_count", 200).asDouble();
429 auto massweigh = json.get(
"mass_weighing",
false).asBool();
431 std::vector<std::vector<double>> histdetails;
432 std::vector<std::vector<double>> restraint;
433 std::vector<std::vector<double>> periodicboundaries;
434 std::vector<double> temp1(3);
435 std::vector<double> temp2(3);
436 std::vector<double> temp3(2);
438 auto freq = json.get(
"frequency", 1).asInt();
439 auto filename = json.get(
"output_file",
"F_out").asString();
440 auto Nworld_filename = json.get(
"Nworld_output_file",
"Nworld").asString();
441 auto Fworld_filename = json.get(
"Fworld_output_file",
"Fworld_cv").asString();
446 std::vector<Grid<double>*> F(dim);
447 std::vector<Grid<double>*> Fworld(dim);
489 N=
new Grid<int>(binsCV, minsCV, maxsCV, isperiodic);
490 Nworld=
new Grid<int>(binsCV, minsCV, maxsCV, isperiodic);
494 grid=
new Grid<double>(binsCV, minsCV, maxsCV, isperiodic);
496 for(
auto& grid : Fworld)
498 grid=
new Grid<double>(binsCV, minsCV, maxsCV, isperiodic);
501 for(
size_t i=0; i<dim; ++i)
503 temp1 = {minsCV[i], maxsCV[i], binsCV[i]};
504 temp2 = {minsrestCV[i], maxsrestCV[i], springkrestCV[i]};
505 histdetails.push_back(temp1);
506 restraint.push_back(temp2);
509 temp3 = {minperboundaryCV[i], maxperboundaryCV[i]};
510 periodicboundaries.push_back(temp3);
516 if(std::ifstream(Nworld_filename) && std::ifstream(Fworld_filename+std::to_string(0)) && wid == 0)
518 std::cout <<
"Attempting to load data from a previous run of ABF." << std::endl;
520 for(
size_t i=0; i<dim; ++i)
521 if(std::ifstream(Fworld_filename+std::to_string(i)))
522 F[i]->LoadFromFile(Fworld_filename+std::to_string(i));
524 throw BuildException({
"Some, but not all Fworld outputs were found. Please check that these are appropriate inputs, or clean the working directory of other Fworld and Nworld inputs."});
528 auto* m =
new ABF(world, comm, N, Nworld, F, Fworld, restraint, isperiodic, periodicboundaries, min, massweigh, filename, Nworld_filename, Fworld_filename, histdetails, FBackupInterv, unitconv, timestep, freq);
531 if(json.isMember(
"iteration"))
532 m->SetIteration(json.get(
"iteration",0).asInt());
bool HasErrors()
Check if errors have occured.
Collective variable manager.
unsigned GetNumAtoms() const
Get number of atoms in this snapshot.
std::vector< CollectiveVariable * > CVList
List of Collective Variables.
Class containing a snapshot of the current simulation in time.
virtual void Parse(Value json, const std::string &path) override
Parse JSON value to generate Requirement(s).
Exception to be thrown when building the Driver fails.
std::vector< std::string > GetErrors()
Get list of error messages.
std::vector< CollectiveVariable * > GetCVs(const std::vector< uint > &mask=std::vector< uint >()) const
Get CV iterator.
const std::vector< double > & GetMasses() const
Const access to the particle masses.
Adaptive Biasing Force Algorithm.
Requirements on an object.
Eigen::Vector3d Vector3
Three-dimensional vector.
const std::vector< Vector3 > & GetVelocities() const
Access the particle velocities.
void LoadFromFile(const std::string &filename)
Builds a grid from file.
const std::vector< Vector3 > & GetForces() const
Access the per-particle forces.
const std::vector< Vector3 > & GetPositions() const
Access the particle positions.
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.