22 #include "CVs/CVManager.h"
23 #include "Drivers/DriverException.h"
24 #include "Validator/ObjectRequirement.h"
42 if(IsMasterRank(world_))
44 worldout_.open(filename_);
49 auto cvs = cvmanager.
GetCVs(cvmask_);
59 wdotp1_.setZero(dim_);
60 wdotp2_.setZero(dim_);
78 auto cvs = cvmanager.
GetCVs(cvmask_);
89 Eigen::MatrixXd J(dim_, 3*n);
92 std::vector<double> cvVals(dim_);
95 for(
size_t i = 0; i < dim_; ++i)
97 auto& grad = cvs[i]->GetGradient();
98 for(
size_t j = 0; j < n; ++j)
99 J.block<1, 3>(i,3*j) = grad[j];
100 cvVals[i] = cvs[i]->GetValue();
104 Eigen::MatrixXd Jmass = J.transpose();
107 for(
size_t i = 0; i < forces.size(); ++i)
108 Jmass.block(3*i, 0, 3, dim_) = Jmass.block(3*i, 0, 3, dim_)/mass[i];
111 Eigen::MatrixXd Minv = J*Jmass;
112 MPI_Allreduce(MPI_IN_PLACE, Minv.data(), Minv.size(), MPI_DOUBLE, MPI_SUM, comm_);
113 Eigen::MatrixXd Wt = Minv.inverse()*Jmass.transpose();
115 Eigen::VectorXd momenta(3*vels.size());
116 for(
size_t i = 0; i < vels.size(); ++i)
117 momenta.segment<3>(3*i) = mass[i]*vels[i];
120 Eigen::VectorXd wdotp = Wt*momenta;
124 MPI_Allreduce(MPI_IN_PLACE, wdotp.data(), wdotp.size(), MPI_DOUBLE, MPI_SUM, comm_);
129 Eigen::VectorXd dwdotpdt = unitconv_*(1.5*wdotp - 2.0*wdotp1_ + 0.5*wdotp2_)/timestep_ + Fold_;
132 if(boundsCheck(cvVals) && IsMasterRank(comm_))
134 for(
size_t i = 0; i < dim_; ++i)
135 F_[i]->at(cvVals) += dwdotpdt[i];
140 for(
size_t i = 0; i < dim_; ++i)
141 MPI_Allreduce(F_[i]->data(), Fworld_[i]->data(), (F_[i]->size()), MPI_DOUBLE, MPI_SUM, world_);
142 MPI_Allreduce(N_->data(), Nworld_->data(), N_->size(), MPI_INT, MPI_SUM, world_);
145 if(boundsCheck(cvVals))
147 for(
size_t i=0; i < dim_; ++i)
148 Fold_[i] = Fworld_[i]->at(cvVals)/std::max(min_, Nworld_->at(cvVals));
156 if(iteration_ % FBackupInterv_ == 0){
162 CalcBiasForce(snapshot, cvs, cvVals);
166 for (
size_t j = 0; j < forces.size(); ++j)
167 forces[j] += biases_[j];
176 void ABF::CalcBiasForce(
const Snapshot* snapshot,
const CVList& cvs,
const std::vector<double> &cvVals)
180 for(
auto& b : biases_)
184 if(boundsCheck(cvVals))
186 for(
size_t i = 0; i < dim_; ++i)
188 auto& grad = cvs[i]->GetGradient();
189 for(
size_t j = 0; j < biases_.size(); ++j)
190 biases_[j] -= (Fworld_[i]->at(cvVals))*grad[j]/std::max(min_,Nworld_->at(cvVals));
196 for(
size_t i = 0; i < dim_; ++i)
198 double cvVal = cvs[i]->GetValue();
204 double periodsize = periodicboundaries_[i][1]-periodicboundaries_[i][0];
205 double cvRestrMidpoint = (restraint_[i][1]+restraint_[i][0])/2;
206 while((cvVal-cvRestrMidpoint) > periodsize/2)
208 while((cvVal-cvRestrMidpoint) < -periodsize/2)
212 if(cvVal < restraint_[i][0])
214 k = restraint_[i][2];
215 x0 = restraint_[i][0];
217 else if (cvVal > restraint_[i][1])
219 k = restraint_[i][2];
220 x0 = restraint_[i][1];
223 auto& grad = cvs[i]->GetGradient();
224 for(
size_t j = 0; j < biases_.size(); ++j)
225 biases_[j] -= (cvVal - x0)*k*grad[j];
232 void ABF::WriteData()
236 if(!IsMasterRank(world_))
242 Nworld_->WriteToFile(Nworld_filename_);
243 for(
size_t i = 0 ; i < dim_; ++i)
245 Fworld_[i]->syncGrid();
246 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;
267 for(
auto it = Nworld_->begin(); it != Nworld_->end(); ++it)
270 auto coord = it.coordinates();
272 worldout_ << std::setw(14) << std::setprecision(8) << std::fixed << c <<
" ";
273 for(
size_t i = 0 ; i < dim_; ++i)
274 worldout_ << std::setw(14) << std::setprecision(8) << std::fixed << Fworld_[i]->at(coord)/std::max(val,min_) <<
" ";
275 worldout_ << std::endl;
278 worldout_ << std::endl;
279 worldout_ << std::endl;
284 bool ABF::boundsCheck(
const std::vector<double> &CVs)
286 for(
size_t i = 0; i < dim_ ; ++i)
288 if((CVs[i] < N_->GetLower(i)) || (CVs[i] > N_->GetUpper(i)))
297 ABF* ABF::Build(
const Value& json,
298 const MPI_Comm& world,
299 const MPI_Comm& comm,
300 const std::string& path)
304 CharReaderBuilder rbuilder;
305 CharReader* reader = rbuilder.newCharReader();
307 reader->parse(JsonSchema::ABFMethod.c_str(),
308 JsonSchema::ABFMethod.c_str() + JsonSchema::ABFMethod.size(),
310 validator.
Parse(schema, path);
320 std::vector<double> minsCV;
321 for(
auto& mins : json[
"CV_lower_bounds"])
324 throw BuildException({
"Separate inputs for multi-walker not fully implemented. Please use global entries for CV ranges"});
330 minsCV.push_back(mins.asDouble());
333 std::vector<double> maxsCV;
334 for(
auto& maxs : json[
"CV_upper_bounds"])
341 maxsCV.push_back(maxs.asDouble());
344 std::vector<int> binsCV;
345 for(
auto& bins : json[
"CV_bins"])
346 binsCV.push_back(bins.asInt());
349 std::vector<double> minsrestCV;
350 for(
auto& mins : json[
"CV_restraint_minimums"])
357 minsrestCV.push_back(mins.asDouble());
360 std::vector<double> maxsrestCV;
361 for(
auto& maxs : json[
"CV_restraint_maximums"])
368 maxsrestCV.push_back(maxs.asDouble());
371 std::vector<double> springkrestCV;
372 for(
auto& springkrest : json[
"CV_restraint_spring_constants"])
374 if(springkrest.asDouble() < 0)
376 throw BuildException({
"Restraint spring constants must be non-negative."});
378 springkrestCV.push_back(springkrest.asDouble());
382 std::vector<bool> isperiodic;
383 for(
auto& isperCV : json[
"CV_isperiodic"])
384 isperiodic.push_back(isperCV.asBool());
387 std::vector<double> minperboundaryCV;
388 for(
auto& minsperCV : json[
"CV_periodic_boundary_lower_bounds"])
389 minperboundaryCV.push_back(minsperCV.asDouble());
392 std::vector<double> maxperboundaryCV;
393 for(
auto& maxsperCV : json[
"CV_periodic_boundary_upper_bounds"])
394 maxperboundaryCV.push_back(maxsperCV.asDouble());
397 if(!(( minsCV.size() == maxsCV.size() &&
398 maxsCV.size() == minsrestCV.size() &&
399 minsrestCV.size() == maxsrestCV.size()) &&
400 (binsCV.size() == springkrestCV.size() &&
401 springkrestCV.size() == isperiodic.size())))
402 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."});
405 bool anyperiodic=
false;
406 for(
size_t i = 0; i<isperiodic.size(); ++i)
410 if(!(isperiodic.size() == minperboundaryCV.size() &&
411 minperboundaryCV.size() == maxperboundaryCV.size()))
412 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."});
415 size_t dim = binsCV.size();
418 auto FBackupInterv = json.get(
"output_frequency", 1000).asInt();
419 auto unitconv = json.get(
"unit_conversion", 0).asDouble();
420 auto timestep = json.get(
"timestep", 2).asDouble();
421 auto min = json.get(
"minimum_count", 200).asDouble();
422 auto massweigh = json.get(
"mass_weighing",
false).asBool();
424 std::vector<std::vector<double>> histdetails;
425 std::vector<std::vector<double>> restraint;
426 std::vector<std::vector<double>> periodicboundaries;
427 std::vector<double> temp1(3);
428 std::vector<double> temp2(3);
429 std::vector<double> temp3(2);
431 auto freq = json.get(
"frequency", 1).asInt();
432 auto filename = json.get(
"output_file",
"F_out").asString();
433 auto Nworld_filename = json.get(
"Nworld_output_file",
"Nworld").asString();
434 auto Fworld_filename = json.get(
"Fworld_output_file",
"Fworld_cv").asString();
439 std::vector<Grid<double>*> F(dim);
440 std::vector<Grid<double>*> Fworld(dim);
485 N =
new Grid<int>(binsCV, minsCV, maxsCV, isperiodic);
486 Nworld =
new Grid<int>(binsCV, minsCV, maxsCV, isperiodic);
490 grid =
new Grid<double>(binsCV, minsCV, maxsCV, isperiodic);
492 for(
auto& grid : Fworld)
494 grid =
new Grid<double>(binsCV, minsCV, maxsCV, isperiodic);
497 for(
size_t i = 0; i < dim; ++i)
499 temp1 = {minsCV[i], maxsCV[i], double(binsCV[i])};
500 temp2 = {minsrestCV[i], maxsrestCV[i], springkrestCV[i]};
501 histdetails.push_back(temp1);
502 restraint.push_back(temp2);
505 temp3 = {minperboundaryCV[i], maxperboundaryCV[i]};
506 periodicboundaries.push_back(temp3);
512 bool restart = json.get(
"restart",
false).asBool();
515 if(IsMasterRank(world))
519 std::cout <<
"Attempting to load data from a previous run of ABF..." << std::endl;
521 for(
size_t i = 0; i < dim; ++i)
523 F[i]->LoadFromFile(Fworld_filename+std::to_string(i));
528 std::ifstream Nworldbackupsource(Nworld_filename, std::ios::binary);
529 if(Nworldbackupsource)
531 std::cout <<
"Backing up previous copy of Nworld." << std::endl;
532 std::ofstream Nworldbackuptarget(Nworld_filename+
"_backup", std::ios::binary);
533 Nworldbackuptarget << Nworldbackupsource.rdbuf();
535 for(
size_t i = 0; i < dim; ++i)
537 std::ifstream Fworldbackupsource(Fworld_filename+std::to_string(i), std::ios::binary);
538 if(Fworldbackupsource)
540 std::cout <<
"Backing up previous copy of Fworld_cv"+std::to_string(i)+
"." << std::endl;
541 std::ofstream Fworldbackuptarget(Fworld_filename+std::to_string(i)+
"_backup", std::ios::binary);
542 Fworldbackuptarget << Fworldbackupsource.rdbuf();
548 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);
550 if(json.isMember(
"iteration"))
551 m->SetIteration(json.get(
"iteration",0).asInt());
Requirements on an object.
virtual void Parse(Value json, const std::string &path) override
Parse JSON value to generate Requirement(s).
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.
std::vector< std::string > GetErrors()
Get list of error messages.
bool HasErrors()
Check if errors have occured.
Adaptive Biasing Force Algorithm.
Exception to be thrown when building the Driver fails.
Collective variable manager.
CVList GetCVs(const std::vector< unsigned int > &mask=std::vector< unsigned int >()) const
Get CV iterator.
void LoadFromFile(const std::string &filename)
Builds a grid from file.
Class containing a snapshot of the current simulation in time.
unsigned GetNumAtoms() const
Get number of atoms in this snapshot.
const std::vector< Vector3 > & GetForces() const
Access the per-particle forces.
const std::vector< Vector3 > & GetPositions() const
Access the particle positions.
const std::vector< double > & GetMasses() const
Const access to the particle masses.
const std::vector< Vector3 > & GetVelocities() const
Access the particle velocities.
Eigen::Vector3d Vector3
Three-dimensional vector.
std::vector< CollectiveVariable * > CVList
List of Collective Variables.