24 #include "mxx/bcast.hpp"
25 #include "CVs/CVManager.h"
26 #include "Drivers/DriverException.h"
27 #include "Validator/ObjectRequirement.h"
43 auto cvs = cvmanager.
GetCVs(cvmask_);
50 wdotp1_.setZero(dim_);
51 wdotp2_.setZero(dim_);
53 int ndim = hgrid_->GetDimension();
54 kbt_ = snapshot->
GetKb()*temp_;
57 Eigen::VectorXd vec = Eigen::VectorXd::Zero(ndim);
58 std::fill(hgrid_->begin(), hgrid_->end(), 0);
59 std::fill(ugrid_->begin(), ugrid_->end(), 1.0);
60 std::fill(fgrid_->begin(), fgrid_->end(), vec);
63 Eigen::Map<Eigen::Array<unsigned int, Eigen::Dynamic, 1>> hist(hgrid_->data(), hgrid_->size());
64 Nworld_ = hist.cast<
int>();
67 bias_.array() = abs(bias_.array())*kbt_*0.5;
84 auto cvs = cvmanager.
GetCVs(cvmask_);
91 using NAtoms = decltype(n);
100 if(IsMasterRank(world_))
105 Eigen::RowVectorXd vec(dim_);
106 std::vector<double> val(dim_);
107 bool inbounds =
true;
108 for(
int i = 0; i < dim_; ++i)
110 val[i] = cvs[i]->GetValue();
111 vec[i] = cvs[i]->GetValue();
112 if(val[i] < hgrid_->GetLower(i) || val[i] > hgrid_->GetUpper(i))
117 Eigen::MatrixXd J(dim_, 3*n);
120 for(
int i = 0; i < dim_; ++i)
122 auto& grad = cvs[i]->GetGradient();
123 for(NAtoms j = 0; j < n; ++j)
124 J.block<1, 3>(i,3*j) = grad[j];
129 Eigen::MatrixXd Jmass = J.transpose();
131 Eigen::MatrixXd Minv = J*Jmass;
132 MPI_Allreduce(MPI_IN_PLACE, Minv.data(), Minv.size(), MPI_DOUBLE, MPI_SUM, comm_);
133 Eigen::MatrixXd Wt = Minv.inverse()*Jmass.transpose();
136 Eigen::VectorXd momenta(3*n);
137 for(NAtoms i = 0; i < n; ++i)
138 momenta.segment<3>(3*i) = mass[i]*vels[i];
141 Eigen::VectorXd wdotp = Wt*momenta;
144 MPI_Allreduce(MPI_IN_PLACE, wdotp.data(), wdotp.size(), MPI_DOUBLE, MPI_SUM, comm_);
148 Eigen::VectorXd dwdotpdt = unitconv_*(1.5*wdotp - 2.0*wdotp1_ + 0.5*wdotp2_)/timestep_ + Fold_;
149 Eigen::VectorXd derivatives = Eigen::VectorXd::Zero(dim_);
154 if(IsMasterRank(comm_))
156 for(
int i=0; i<dim_; ++i)
157 F_[i]->at(val) += dwdotpdt[i];
159 hgrid_->at(val) += 1;
167 for(
int i = 0; i < dim_; ++i)
168 derivatives[i] = (F_[i]->at(val)/std::max((
double(hgrid_->at(val))),
double(min_)));
172 net_.forward_pass(vec);
173 net2_.forward_pass(vec);
174 derivatives = net_.get_gradient(0)*ratio_ + net2_.get_gradient(0)*(1.0-ratio_);
182 if(IsMasterRank(comm_))
184 std::cerr <<
"CFF (" << snapshot->
GetIteration() <<
"): out of bounds ( ";
186 std::cerr << v <<
" ";
187 std::cerr <<
")" << std::endl;
191 for(
int i = 0; i < dim_; ++i)
193 auto cval = cvs[i]->GetValue();
194 if(cval < lowerb_[i])
195 derivatives[i] += lowerk_[i]*cvs[i]->GetDifference(cval - lowerb_[i]);
196 else if(cval > upperb_[i])
197 derivatives[i] += upperk_[i]*cvs[i]->GetDifference(cval - upperb_[i]);
202 for(
int i = 0; i < dim_; ++i)
204 auto& grad = cvs[i]->GetGradient();
205 auto& boxgrad = cvs[i]->GetBoxGradient();
209 for (NAtoms j = 0; j < n; ++j)
210 forces[j] -= derivatives[i]*grad[j];
213 virial += derivatives[i]*boxgrad;
232 void CFF::TrainNetwork()
235 std::clock_t start = std::clock();
241 mxx::allreduce(hgrid_->data(), hgrid_->size(), std::plus<unsigned int>(), world_);
245 Eigen::Map<Eigen::Array<unsigned int, Eigen::Dynamic, 1>> hist(hgrid_->data(), hgrid_->size());
246 Nworld_ += hist.cast<
int>();
250 Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, 1>> uhist(ugrid_->data(), ugrid_->size());
253 std::vector<Eigen::MatrixXd> Ftrain;
254 for(
int i=0; i<dim_; ++i)
256 MPI_Allreduce(F_[i]->data(), Fworld_[i]->data(), (F_[i]->size()), MPI_DOUBLE, MPI_SUM, world_);
257 Fworld_[i]->syncGrid();
260 Eigen::ArrayXd Nmin = Eigen::ArrayXd::Ones(Fworld_[0]->size())*min_;
261 Ftrain.push_back(Eigen::Map<Eigen::Array<double, Eigen::Dynamic, 1>> (Fworld_[i]->data(),Fworld_[i]->size()) /
262 ( (Nworld_.cast<
double>()).max(Nmin) ) );
266 uhist.array() = pweight_*uhist.array() + hist.cast<
double>()*(bias_/kbt_).array().exp()*weight_;
275 force_to_val_ratio_ = Eigen::MatrixXd::Zero(hist_.rows(),1);
278 bias_.array() = kbt_*uhist.array().log();
279 bias_.array() -= bias_.minCoeff();
283 net2_.init_weights();
287 net_.autoscale(hist_, bias_);
288 net2_.autoscale_w_grad(hist_, bias_, Ftrain);
289 if(IsMasterRank(world_))
293 gamma1 = net_.train(hist_, bias_,
true);
295 double gamma2 = net2_.train_w_grad(hist_, bias_,Ftrain, force_to_val_ratio_,
true);
296 std::cout <<
"gamma1 " << gamma1 <<
" " << gamma2 << std::endl;
297 ratio_ = gamma1/(gamma1+gamma2);
299 std::cout << std::endl <<
"Ratio: " << ratio_ << std::endl;
302 std::ofstream gammaout;
303 gammaout.open(outfile_ +
"_gamma", std::ios_base::app);
304 gammaout.precision(16);
305 gammaout << sweep_ <<
" " << gamma1 <<
" " << gamma2 <<
" " << ratio_ << std::endl;
310 nnet::vector_t wb = net_.get_wb();
311 mxx::bcast(wb.data(), wb.size(), 0, world_);
314 nnet::vector_t wb2 = net2_.get_wb();
315 mxx::bcast(wb2.data(), wb2.size(), 0, world_);
318 mxx::bcast(&ratio_, 1, 0, world_);
321 net_.forward_pass(hist_);
322 net2_.forward_pass(hist_);
323 bias_.array() = net_.get_activation().col(0).array() * ratio_ + net2_.get_activation().col(0).array() * (1.0-ratio_);
324 bias_.array() -= bias_.minCoeff();
327 if(IsMasterRank(world_))
330 for(
int i = 0 ; i < dim_; ++i)
331 gridPoints = gridPoints * hgrid_->GetNumPoints(i);
333 std::string filename;
334 filename = overwrite_ ?
"F_out" :
"F_out_"+std::to_string(sweep_);
335 std::ofstream file(filename);
337 file <<
"Sweep: " << sweep_ << std::endl;
338 file <<
"Printing out the current Biasing Vector Field from CFF." << std::endl;
339 file <<
"First (Nr of CVs) columns are the coordinates, the next (Nr of CVs) columns are components of the Generalized Force vector at that point." << std::endl;
340 file <<
"The columns are " << gridPoints <<
" long, mapping out a surface of ";
341 for (
int i = 0 ; i < dim_-1; ++i)
342 file << (hgrid_->GetNumPoints())[i] <<
" by " ;
343 file << (hgrid_->GetNumPoints(dim_-1)) <<
" points in " << dim_ <<
" dimensions." << std::endl;
346 for(
int j=0; j < (Ftrain[0].array()).size();++j)
348 file << std::setw(14) << std::setprecision(8) << std::fixed << hist_.row(j);
349 for(
int i = 0 ; i < dim_; ++i){
350 nnet::matrix_t x = Ftrain[i].array();
351 file << std::setw(14) << std::setprecision(8) << std::fixed << x(j) <<
" ";
361 double duration = ( std::clock() - start ) / (
double) CLOCKS_PER_SEC;
362 std::ofstream file1(
"traintime.out",std::ofstream::app);
363 file1 << duration << std::endl;
369 void CFF::WriteBias()
372 std::string filename;
373 filename = overwrite_ ?
"netstate.dat" :
"netstate_"+std::to_string(sweep_)+
".dat";
374 net_.write(filename.c_str());
375 filename = overwrite_ ?
"netstate2.dat" :
"netstate2_"+std::to_string(sweep_)+
".dat";
376 net2_.write(filename.c_str());
380 filename = overwrite_ ? outfile_ : outfile_ + std::to_string(sweep_);
381 std::ofstream file(filename);
383 net_.forward_pass(hist_);
384 net2_.forward_pass(hist_);
385 nnet::matrix_t x = net_.get_activation().array();
386 nnet::matrix_t y = net2_.get_activation().array();
387 nnet::matrix_t q = bias_;
388 nnet::matrix_t m = -q;
389 m.array() -= m.minCoeff();
392 file <<
"Sweep: " << sweep_ << std::endl;
393 file <<
"Printing out the current Combined Force Frequency data." << std::endl;
394 file <<
"First (Nr of CVs) columns are the coordinates." << std::endl;
395 file <<
"Next columns (left to right) are: hist bias(freq_NN) bias(force_NN) bias(both_NN) free_energy" << std::endl;
397 for(
int i = 0; i < y.rows(); ++i)
399 for(
int j = 0; j < hist_.cols(); ++j)
400 file << std::fixed << hist_(i,j) <<
" ";
401 file << std::fixed<< Nworld_[i] <<
" " << x(i)<<
" " << std::fixed << y(i)<<
" " << std::fixed << q(i) <<
" " << std::fixed << m(i) <<
"\n";
408 const Json::Value& json,
409 const MPI_Comm& world,
410 const MPI_Comm& comm,
411 const std::string& path)
415 CharReaderBuilder rbuilder;
416 CharReader* reader = rbuilder.newCharReader();
418 JsonSchema::CFFMethod.c_str(),
419 JsonSchema::CFFMethod.c_str() + JsonSchema::CFFMethod.size(),
423 validator.
Parse(schema, path);
431 auto jsongrid = json.get(
"grid", Json::Value());
435 std::vector<Grid<double>*> F(json[
"grid"][
"upper"].size());
438 std::vector<Grid<double>*> Fworld(json[
"grid"][
"upper"].size());
439 for(
auto& grid : Fworld)
443 auto nlayers = json[
"topology"].size() + 2;
444 Eigen::VectorXi topol(nlayers);
445 topol[0] = fgrid->GetDimension();
446 topol[nlayers-1] = 1;
447 for(decltype(nlayers) i = 0; i < json[
"topology"].size(); ++i)
448 topol[i+1] = json[
"topology"][i].asInt();
451 auto weight = json.get(
"weight", 1.).asDouble();
452 auto temp = json[
"temperature"].asDouble();
453 auto nsweep = json[
"nsweep"].asUInt();
454 auto unitconv = json.get(
"unit_conversion", 1).asDouble();
455 auto timestep = json.get(
"timestep", 0.002).asDouble();
456 auto min = json.get(
"minimum_count", 200).asInt();
459 std::vector<double> lowerb, upperb, lowerk, upperk;
460 auto lbr_size = json[
"lower_bound_restraints"].size();
461 for(decltype(lbr_size) i = 0; i < lbr_size; ++i)
463 lowerk.push_back(json[
"lower_bound_restraints"][i].asDouble());
464 upperk.push_back(json[
"upper_bound_restraints"][i].asDouble());
465 lowerb.push_back(json[
"lower_bounds"][i].asDouble());
466 upperb.push_back(json[
"upper_bounds"][i].asDouble());
469 auto* m =
new CFF(world, comm, topol, fgrid, hgrid, ugrid, F, Fworld, lowerb, upperb, lowerk, upperk, temp, unitconv, timestep, weight, nsweep, min);
472 m->SetPrevWeight(json.get(
"prev_weight", 1).asDouble());
473 m->SetOutput(json.get(
"output_file",
"CFF.out").asString());
474 m->SetOutputOverwrite( json.get(
"overwrite_output",
true).asBool());
475 m->SetConvergeIters(json.get(
"converge_iters", 0).asUInt());
476 m->SetMaxIters(json.get(
"max_iters", 1000).asUInt());
477 m->SetMinLoss(json.get(
"min_loss", 0).asDouble());
478 m->SetRatio(json.get(
"ratio", 0.0).asDouble());
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.
Exception to be thrown when building the Driver fails.
Combined Force Frequency (CFF) Algorithm.
Collective variable manager.
CVList GetCVs(const std::vector< unsigned int > &mask=std::vector< unsigned int >()) const
Get CV iterator.
Class containing a snapshot of the current simulation in time.
double GetKb() const
Get system Kb.
const Matrix3 & GetVirial() const
Get box virial.
unsigned GetNumAtoms() const
Get number of atoms in this snapshot.
const std::vector< Vector3 > & GetForces() const
Access the per-particle forces.
size_t GetIteration() const
Get the current iteration.
const std::vector< double > & GetMasses() const
Const access to the particle masses.
const std::vector< Vector3 > & GetVelocities() const
Access the particle velocities.