21 #include "BasisFunc.h"
22 #include "Validator/ObjectRequirement.h"
23 #include "Drivers/DriverException.h"
24 #include "CVs/CVManager.h"
38 auto cvs = cvmanager.
GetCVs(cvmask_);
47 if(hist_->GetDimension() != cvs.size())
49 std::cerr<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
50 std::cerr<<
"ERROR: Histogram dimensions doesn't match number of CVS."<<std::endl;
51 std::cerr<<
"Exiting on node ["<<mpiid_<<
"]"<<std::endl;
52 std::cerr<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
53 MPI_Abort(world_, EXIT_FAILURE);
55 else if(cvs.size() != polyords_.size())
57 std::cout<<cvs.size()<<std::endl;
58 std::cout<<polyords_.size()<<std::endl;
59 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
60 std::cout<<
"WARNING: The number of polynomial orders is not the same"<<std::endl;
61 std::cout<<
"as the number of CVs"<<std::endl;
62 std::cout<<
"The simulation will take the first defined input"<<std::endl;
63 std::cout<<
"as the same for all CVs. ["<<polyords_[0]<<
"]"<<std::endl;
64 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
67 polyords_.resize(cvs.size());
69 for(
size_t i = 0; i < cvs.size(); ++i)
71 polyords_[i] = polyords_[0];
78 size_t coeff_size = 1;
80 for(
size_t i = 0; i < cvs.size(); ++i)
82 coeff_size *= polyords_[i]+1;
85 derivatives_.resize(cvs.size());
86 unbias_.resize(hist_->size(),0);
87 coeff_arr_.resize(coeff_size,0);
89 std::vector<int> idx(cvs.size(), 0);
90 std::vector<int> jdx(cvs.size(), 0);
91 Map temp_map(idx,0.0);
94 for (
int &val : *hist_) {
99 for(
size_t i = 0; i < coeff_size; ++i)
101 for(
size_t j = 0; j < jdx.size(); ++j)
103 if(jdx[j] > 0 && jdx[j] % (polyords_[j]+1) == 0)
105 if(j != cvs.size() - 1)
111 temp_map.map[j] = jdx[j];
114 coeff_.push_back(temp_map);
115 coeff_[i].value = coeff_arr_[i];
126 auto cvs = cvmanager.
GetCVs(cvmask_);
127 std::vector<double> x(cvs.size(),0);
133 for(
size_t i = 0; i < cvs.size(); ++i)
135 x[i] = cvs[i]->GetValue();
153 if(temperature_ == 0)
155 std::cout<<std::endl;
156 std::cerr<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
157 std::cerr<<
"ERROR: Input temperature needs to be defined for this simulation"<<std::endl;
158 std::cerr<<
"Exiting on node ["<<mpiid_<<
"]"<<std::endl;
159 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
164 UpdateBias(cvs,beta);
165 std::cout<<
"Node: ["<<mpiid_<<
"]"<<std::setw(10)<<
"\tSweep: "<<iteration_<<std::endl;
174 for(
size_t i = 0; i < cvs.size(); ++i)
176 auto& grad = cvs[i]->GetGradient();
177 auto& boxgrad = cvs[i]->GetBoxGradient();
182 for (
size_t j = 0; j < forces.size(); ++j)
183 forces[j] += derivatives_[i]*grad[j];
185 virial -= derivatives_[i]*boxgrad;
192 std::cout<<
"Run has finished"<<std::endl;
200 for(
size_t k = 0; k < cvs.size(); k++)
202 size_t ncoeff = polyords_[k]+1;
203 int nbins = hist_->GetNumPoints(k);
205 std::vector<double> dervs(nbins*ncoeff,0);
206 std::vector<double> vals(nbins*ncoeff,0);
207 std::vector<double> x(nbins,0);
212 for (
int i = 0; i < nbins; ++i)
214 x[i] = (2.0*i + 1.0)/nbins - 1.0;
219 for (
int i = 0; i < nbins; ++i)
221 vals[i+nbins] = x[i];
222 dervs[i+nbins] = 1.0;
225 for (
size_t j = 2; j < ncoeff; j++)
227 for (
int i = 0; i < nbins; i++)
230 vals[i+j*nbins] = ( ( 2.0*j - 1.0 ) * x[i] * vals[i+(j-1)*nbins]
231 - (j - 1.0) * vals[i+(j-2)*nbins] ) / j;
234 dervs[i+j*nbins] = ( ( 2.0*j - 1.0 ) * ( vals[i+(j-1)*nbins] + x[i] * dervs[i+(j-1)*nbins] )
235 - (j - 1.0) * dervs[i+(j-2)*nbins] ) / j;
239 LUT_.push_back(TempLUT);
244 void Basis::UpdateBias(
const CVList& cvs,
const double beta)
246 std::vector<double> x(cvs.size(), 0);
247 std::vector<double> coeffTemp(coeff_.size(), 0);
256 MPI_Allreduce(histlocal.
data(), hist_->data(), hist_->size(), MPI_INT, MPI_SUM, world_);
262 if (it2.isUnderOverflowBin()) {
268 if (*it2 == 0) { *it2 = 1; }
271 for(
size_t k = 1; k < coeff_.size(); ++k)
273 auto& coeff = coeff_[k];
274 for(
size_t l = 0; l < cvs.size(); ++l)
277 int nbins = hist_->GetNumPoints(l);
278 basis *= LUT_[l].values[it2.index(l) + coeff.map[l]*nbins];
280 bias += coeff.value*basis;
287 unbias_[i] += (*it2) * exp(bias) * weight_ / (double)(cyclefreq_);
293 for(
size_t i = 0; i < coeff_.size(); ++i)
295 coeffTemp[i] = coeff_[i].value;
296 coeff_[i].value = 0.0;
300 for (
int &val : *hist_) {
305 for(
size_t i = 1; i < coeff_.size(); ++i)
307 auto& coeff = coeff_[i];
313 if (it2.isUnderOverflowBin()) {
318 double weight = std::pow(2.0,cvs.size());
321 for(
size_t k = 0; k < cvs.size(); ++k)
323 if( it2.index(k) == 0 ||
324 it2.index(k) == hist_->GetNumPoints(k)-1)
331 for(
size_t l = 0; l < cvs.size(); l++)
333 int nbins = hist_->GetNumPoints(l);
334 basis *= LUT_[l].values[it2.index(l) + coeff.map[l]*nbins] / nbins;
335 basis *= 2.0 * coeff.map[l] + 1.0;
337 coeff.value += basis * log(unbias_[j]) * weight/std::pow(2.0,cvs.size());
340 coeffTemp[i] -= coeff.value;
341 coeff_arr_[i] = coeff.value;
342 sum += coeffTemp[i]*coeffTemp[i];
345 if(world_.rank() == 0)
352 std::cout<<
"System has converged"<<std::endl;
355 std::cout<<
"User has elected to exit. System is now exiting"<<std::endl;
365 void Basis::PrintBias(
const CVList& cvs,
const double beta)
367 std::vector<double> bias(hist_->size(), 0);
368 std::vector<double> x(cvs.size(), 0);
377 if (it.isUnderOverflowBin()) {
382 for(
size_t j = 1; j < coeff_.size(); ++j)
384 for(
size_t k = 0; k < cvs.size(); ++k)
386 int nbins = hist_->GetNumPoints(k);
387 temp *= LUT_[k].values[it.index(k) + coeff_[j].map[k] * nbins];
389 bias[i] += coeff_[j].value*temp;
395 std::string filename1 =
"basis"+bnme_+
".out";
396 std::string filename2 =
"coeff"+cnme_+
".out";
398 basisout_.precision(5);
399 coeffout_.precision(5);
400 basisout_.open(filename1.c_str());
401 coeffout_.open(filename2.c_str());
404 coeffout_ << iteration_ <<std::endl;
405 basisout_ <<
"CV Values" << std::setw(35*cvs.size()) <<
"Basis Set Bias" << std::setw(35) <<
"PMF Estimate" << std::setw(35) <<
"Biased Histogram" << std::endl;
410 if (it.isUnderOverflowBin()) {
415 for(
size_t k = 0; k < cvs.size(); ++k)
418 basisout_ << it.coordinate(k) << std::setw(35);
420 basisout_ << -bias[j] << std::setw(35);
422 basisout_ << -log(unbias_[j]) / beta << std::setw(35);
424 basisout_ <<
"0" << std::setw(35);
425 basisout_ << unbias_[j];
426 basisout_ << std::endl;
429 for(
size_t k = 0; k < coeff_.size(); ++k)
431 coeffout_ <<coeff_[k].value << std::endl;
434 basisout_ << std::endl;
440 void Basis::CalcBiasForce(
const CVList& cvs)
443 std::fill(derivatives_.begin(), derivatives_.end(), 0);
444 std::vector<double> x(cvs.size(),0);
449 for (
size_t j = 0; j < cvs.size(); ++j)
451 x[j] = cvs[j]->GetValue();
452 double min = hist_->GetLower(j);
453 double max = hist_->GetUpper(j);
455 if(!hist_->GetPeriodic(j))
458 if(x[j] > max && bounds_)
460 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
461 std::cout<<
"WARNING: CV is above the maximum boundary."<<std::endl;
462 std::cout<<
"Statistics will not be gathered during this interval"<<std::endl;
463 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
466 else if(x[j] < min && bounds_)
468 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
469 std::cout<<
"WARNING: CV is below the minimum boundary."<<std::endl;
470 std::cout<<
"Statistics will not be gathered during this interval"<<std::endl;
471 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
474 else if(x[j] < max && x[j] > min && !bounds_)
476 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
477 std::cout<<
"CV has returned in between bounds. Run is resuming"<<std::endl;
478 std::cout<<
"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<std::endl;
487 for (
size_t i = 1; i < coeff_.size(); ++i)
489 for (
size_t j = 0; j < cvs.size(); ++j)
492 for (
size_t k = 0; k < cvs.size(); ++k)
494 int nbins = hist_->GetNumPoints(k);
495 temp *= j == k ? LUT_[k].derivs[hist_->GetIndices(x)[k] + coeff_[i].map[k]*nbins] * 2.0 / (hist_->GetUpper(j) - hist_->GetLower(j))
496 : LUT_[k].values[hist_->GetIndices(x)[k] + coeff_[i].map[k]*nbins];
498 derivatives_[j] -= coeff_[i].value * temp;
504 for(
size_t j = 0; j < cvs.size(); ++j)
510 if(!hist_->GetPeriodic(j))
512 if(x[j] > boundUp_[j])
513 derivatives_[j] -= restraint_[j] * (x[j] - boundUp_[j]);
514 else if(x[j] < boundLow_[j])
515 derivatives_[j] -= restraint_[j] * (x[j] - boundLow_[j]);
521 Basis* Basis::Build(
const Json::Value& json,
522 const MPI_Comm& world,
523 const MPI_Comm& comm,
524 const std::string& path)
530 reader.parse(JsonSchema::BFSMethod, schema);
531 validator.
Parse(schema, path);
538 std::vector<unsigned int> coefsCV(0);
539 for(
auto& coefs : json[
"CV_coefficients"])
540 coefsCV.push_back(coefs.asInt());
542 std::vector<double> restrCV(0);
543 for(
auto& restr : json[
"CV_restraint_spring_constants"])
544 restrCV.push_back(restr.asDouble());
546 std::vector<double> boundLow(0);
547 for(
auto& bndl : json[
"CV_restraint_minimums"])
548 boundLow.push_back(bndl.asDouble());
550 std::vector<double> boundUp(0);
551 for(
auto& bndu : json[
"CV_restraint_maximums"])
552 boundUp.push_back(bndu.asDouble());
554 auto cyclefreq = json.get(
"cycle_frequency", 100000).asInt();
555 auto freq = json.get(
"frequency", 1).asInt();
556 auto wght = json.get(
"weight", 1.0).asDouble();
557 auto bnme = json.get(
"basis_filename",
"").asString();
558 auto cnme = json.get(
"coeff_filename",
"").asString();
559 auto temp = json.get(
"temperature", 0.0).asDouble();
560 auto tol = json.get(
"tolerance", 1e-6).asDouble();
561 auto conv = json.get(
"convergence_exit",
false).asBool();
564 json.get(
"grid", Json::Value()) );
566 auto* m =
new Basis(world, comm, hist, coefsCV, restrCV, boundUp, boundLow,
567 cyclefreq, freq, bnme, cnme, temp, tol, wght,
570 if(json.isMember(
"iteration"))
571 m->SetIteration(json.get(
"iteration",0).asInt());
573 if(json.isMember(
"coefficients") && json.isMember(
"bias hist"))
575 std::vector<double> coeff;
576 std::vector<double> unbias;
578 for(
auto& c : json[
"coefficients"])
579 coeff.push_back(c.asDouble());
581 for(
auto& u : json[
"bias hist"])
582 unbias.push_back(u.asDouble());
584 m->SetBasis(coeff, unbias);
unsigned GetWalkerID() const
Get walker ID.
bool HasErrors()
Check if errors have occured.
Collective variable manager.
int GetIteration() const
Get the current iteration.
const Matrix3 & GetVirial() const
Get box virial.
std::vector< CollectiveVariable * > CVList
List of Collective Variables.
Class containing a snapshot of the current simulation in time.
Basis Function Sampling Algorithm.
virtual void Parse(Value json, const std::string &path) override
Parse JSON value to generate Requirement(s).
Map for histogram and coefficients.
Exception to be thrown when building the Driver fails.
std::vector< std::string > GetErrors()
Get list of error messages.
double GetTemperature() const
Get current temperature.
std::vector< CollectiveVariable * > GetCVs(const std::vector< uint > &mask=std::vector< uint >()) const
Get CV iterator.
Look-up table for basis functions.
Requirements on an object.
double GetKb() const
Get system Kb.
iterator begin()
Return iterator at first bin of histogram.
T * data()
Get pointer to the internal data storage vector.
const std::vector< Vector3 > & GetForces() const
Access the per-particle forces.
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.