LCOV - code coverage report
Current view: top level - bias - MaxEnt.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 215 224 96.0 %
Date: 2020-11-18 11:20:57 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-2019 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "Bias.h"
      23             : #include "core/PlumedMain.h"
      24             : #include "core/Atoms.h"
      25             : #include <string>
      26             : #include <cstring>
      27             : //#include "ActionRegister.h"
      28             : #include "core/ActionRegister.h"
      29             : #include "core/ActionWithValue.h"
      30             : #include "tools/Communicator.h"
      31             : #include "tools/File.h"
      32             : #include <iostream>
      33             : 
      34             : //#include "Analysis.h"
      35             : //#include "core/PlumedMain.h"
      36             : //#include "core/ActionRegister.h"
      37             : //#include "tools/Grid.h"
      38             : //#include "tools/KernelFunctions.h"
      39             : //#include "tools/IFile.h"
      40             : //#include "tools/OFile.h"
      41             : 
      42             : // The original implementation of this method was contributed
      43             : // by Andrea Cesari (andreacesari90@gmail.com).
      44             : // Copyright has been then transferred to PLUMED developers
      45             : // (see https://github.com/plumed/plumed2/blob/master/.github/CONTRIBUTING.md)
      46             : 
      47             : using namespace std;
      48             : 
      49             : 
      50             : namespace PLMD {
      51             : namespace bias {
      52             : 
      53             : //+PLUMEDOC BIAS MAXENT
      54             : /*
      55             : Add a linear biasing potential on one or more variables \f$f_{i}\left(\boldsymbol{x}\right)\f$ satisfying the maximum entropy principle as proposed in Ref. \cite cesari2016maxent .
      56             : 
      57             : \warning
      58             :     Notice that syntax is still under revision and might change
      59             : 
      60             : The resulting biasing potential is given by:
      61             : \f[
      62             :   V_{BIAS}(\boldsymbol{x},t)=K_{B}T\sum_{i=1}^{\#arguments}f_{i}(\boldsymbol{x},t)\lambda_{i}(t)
      63             : \f]
      64             : Lagrangian multipliers \f$ \lambda_{i}\f$ are updated, every PACE steps, according to the following update rule:
      65             : \f[
      66             : \lambda_{i}=\lambda_{i}+\frac{k_{i}}{1+\frac{t}{\tau_{i}}}\left(f_{exp,i}+\xi_{i}\lambda_{i}-f_{i}(\boldsymbol{x})\right)
      67             : \f]
      68             : \f$k\f$ set the initial value of the learning rate and its units are \f$[observable]^{-2}ps^{-1}\f$. This can be set with the keyword KAPPA.
      69             : The number of components for any KAPPA vector must be equal to the number of arguments of the action.
      70             : 
      71             : Variable \f$ \xi_{i}(\lambda) \f$ is related to the choosen prior to model experimental errors. If a GAUSSIAN prior is used then:
      72             : \f[
      73             : \xi_{i}(\lambda)=-\lambda_{i}\sigma^{2}
      74             : \f]
      75             : where \f$ \sigma \f$ is the typical expected error on the observable \f$ f_i\f$.
      76             : For a LAPLACE prior:
      77             : \f[
      78             : \xi_{i}(\lambda)=-\frac{\lambda_{i}\sigma^{2}}{1-\frac{\lambda^{2}\sigma^{2}}{2}}
      79             : 
      80             : \f]
      81             : The value of \f$ \xi(\lambda,t)\f$ is written in output as a component named: argument name followed by the string _error.
      82             : Setting \f$ \sigma =0\f$ is equivalent to enforce a pure Maximum Entropy restraint without any noise modelling.
      83             : This method can be also used to enforce inequality restraint as shown in following examples.
      84             : 
      85             : Notice that a similar method is available as \ref EDS, although with different features and using a different optimization algorithm.
      86             : 
      87             : \par Examples
      88             : 
      89             : The following input tells plumed to restrain the distance between atoms 7 and 15
      90             : and the distance between atoms 2 and 19, at different equilibrium
      91             : values, and to print the energy of the restraint.
      92             : Lagrangian multiplier will be printed on a file called restraint.LAGMULT with a stride set by the variable PACE to 200ps.
      93             : Moreover plumed will compute the average of each lagrangian multiplier in the window [TSTART,TEND] and use that to continue the simulations with fixed Lagrangian multipliers.
      94             : \plumedfile
      95             : DISTANCE ATOMS=7,15 LABEL=d1
      96             : DISTANCE ATOMS=2,19 LABEL=d2
      97             : MAXENT ...
      98             : ARG=d1,d2
      99             : TYPE=EQUAL
     100             : AT=0.2,0.5
     101             : KAPPA=35000.0,35000.0
     102             : TAU=0.02,0.02
     103             : PACE=200
     104             : TSTART=100
     105             : TEND=500
     106             : LABEL=restraint
     107             : PRINT ARG=restraint.bias
     108             : ... MAXENT
     109             : \endplumedfile
     110             : Lagrangian multipliers will be printed on a file called restraint.bias
     111             : The following input tells plumed to restrain the distance between atoms 7 and 15
     112             : to be greater than 0.2 and to print the energy of the restraint
     113             : \plumedfile
     114             : DISTANCE ATOMS=7,15 LABEL=d
     115             : MAXENT ARG=d TYPE=INEQUAL> AT=0.02 KAPPA=35000.0 TAU= LABEL=restraint
     116             : PRINT ARG=restraint.bias
     117             : \endplumedfile
     118             : 
     119             : (See also \ref DISTANCE and \ref PRINT).
     120             : 
     121             : */
     122             : //+ENDPLUMEDOC
     123             : 
     124             : class MaxEnt : public Bias {
     125             :   std::vector<double> at;
     126             :   std::vector<double> kappa;
     127             :   std::vector<double> lambda;
     128             :   std::vector<double> avgx;
     129             :   std::vector<double> work;
     130             :   std::vector<double> oldlambda;
     131             :   std::vector<double> tau;
     132             :   std::vector<double> avglambda;
     133             :   std::vector<double> avglambda_restart;
     134             :   std::vector<double> expected_eps;
     135             :   std::vector<double> apply_weights;
     136             :   double sigma;
     137             :   double tstart;
     138             :   double tend;
     139             :   double avgstep; //current number of samples over which to compute the average. Check if could be replaced bu getStep()
     140             :   long int pace_;
     141             :   long int stride_;
     142             :   double totalWork;
     143             :   double BetaReweightBias;
     144             :   double simtemp;
     145             :   double reweight_bias2;
     146             :   vector<ActionWithValue*> biases;
     147             :   std::string type;
     148             :   std::string error_type;
     149             :   double alpha;
     150             :   double avg_counter;
     151             :   int learn_replica;
     152             :   Value* valueForce2;
     153             :   Value* valueWork;
     154             :   OFile lagmultOfile_;
     155             :   IFile ifile;
     156             :   string lagmultfname;
     157             :   string ifilesnames;
     158             :   string fmt;
     159             :   bool isFirstStep;
     160             :   bool reweight;
     161             :   bool no_broadcast;
     162             :   bool printFirstStep;
     163             :   std::vector<bool> done_average;
     164             :   int myrep,nrep;
     165             : public:
     166             :   explicit MaxEnt(const ActionOptions&);
     167             :   ~MaxEnt();
     168             :   void calculate();
     169             :   void update();
     170             :   void update_lambda();
     171             :   static void registerKeywords(Keywords& keys);
     172             :   void ReadLagrangians(IFile &ifile);
     173             :   void WriteLagrangians(vector<double> &lagmult,OFile &file);
     174             :   double compute_error(string &err_type,double &l);
     175             :   double convert_lambda(string &type,double lold);
     176             :   void check_lambda_boundaries(string &err_type,double &l);
     177             : };
     178        6502 : PLUMED_REGISTER_ACTION(MaxEnt,"MAXENT")
     179             : 
     180          51 : void MaxEnt::registerKeywords(Keywords& keys) {
     181          51 :   Bias::registerKeywords(keys);
     182          51 :   componentsAreNotOptional(keys);
     183         102 :   keys.use("ARG");
     184         255 :   keys.add("compulsory","KAPPA","0.0","specifies the initial value for the learning rate");
     185         204 :   keys.add("compulsory","TAU","Specify the dumping time for the learning rate.");
     186         204 :   keys.add("compulsory","TYPE","specify the restraint type. "
     187             :            "EQAUL to restrain the variable at a given equilibrium value"
     188             :            "INEQUAL< to restrain the variable to be smaller than a given value"
     189             :            "INEQUAL> to restrain the variable to be greater than a given value");
     190         204 :   keys.add("optional","ERROR_TYPE","specify the prior on the error to use."
     191             :            "GAUSSIAN: use a Gaussian prior"
     192             :            "LAPLACE: use a Laplace prior");
     193         204 :   keys.add("optional","TSTART","time in ps from where to start averaging the Lagrangian multiplier. By default no average is computed, hence lambda is updated every PACE steps");
     194         204 :   keys.add("optional","TEND","time in ps where to stop to compute the average of Lagrangian multiplier. From this time until the end of the simulation Lagrangian multipliers are kept fix to the average computed between TSTART and TEND;");
     195         204 :   keys.add("optional","ALPHA","default=1.0; To be used with LAPLACE KEYWORD, allows to choose a prior function proportional to a Gaussian times an exponential function. ALPHA=1 correspond to the LAPLACE prior.");
     196         204 :   keys.add("compulsory","AT","the position of the restraint");
     197         204 :   keys.add("optional","SIGMA","The typical erros expected on observable");
     198         204 :   keys.add("optional","FILE","Lagrangian multipliers output file. The default name is: label name followed by the string .LAGMULT ");
     199         204 :   keys.add("optional","LEARN_REPLICA","In a multiple replica environment specify which is the reference replica. By default replica 0 will be used.");
     200         204 :   keys.add("optional","APPLY_WEIGHTS","Vector of weights containing 1 in correspondece of each replica that will receive the lagrangian multiplier from the current one.");
     201         204 :   keys.add("optional","PACE","the frequency for Lagrangian multipliers update");
     202         204 :   keys.add("optional","PRINT_STRIDE","stride of Lagrangian multipliers output file. If no STRIDE is passed they are written every time they are updated (PACE).");
     203         204 :   keys.add("optional","FMT","specify format for Lagrangian multipliers files (usefulf to decrease the number of digits in regtests)");
     204         153 :   keys.addFlag("REWEIGHT",false,"to be used with plumed driver in order to reweight a trajectory a posteriori");
     205         153 :   keys.addFlag("NO_BROADCAST",false,"If active will avoid Lagrangian multipliers to be comunicated to other replicas.");
     206         204 :   keys.add("optional","TEMP","the system temperature.  This is required if you are reweighting.");
     207         204 :   keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential");
     208         204 :   keys.addOutputComponent("work","default","the instantaneous value of the work done by the biasing force");
     209         204 :   keys.addOutputComponent("_work","default","the instantaneous value of the work done by the biasing force for each argument. "
     210             :                           "These quantities will named with the arguments of the bias followed by "
     211             :                           "the character string _work.");
     212         204 :   keys.addOutputComponent("_error","default","Instantaneous values of the discrepancy between the observable and the restraint center");
     213         204 :   keys.addOutputComponent("_coupling","default","Instantaneous values of Lagrangian multipliers. They are also written by default in a separate output file.");
     214         102 :   keys.use("RESTART");
     215          51 : }
     216         200 : MaxEnt::~MaxEnt() {
     217          50 :   lagmultOfile_.close();
     218         100 : }
     219          50 : MaxEnt::MaxEnt(const ActionOptions&ao):
     220             :   PLUMED_BIAS_INIT(ao),
     221             :   at(getNumberOfArguments()),
     222             :   kappa(getNumberOfArguments(),0.0),
     223             :   lambda(getNumberOfArguments(),0.0),
     224             :   avgx(getNumberOfArguments(),0.0),
     225             :   oldlambda(getNumberOfArguments(),0.0),
     226         100 :   tau(getNumberOfArguments(),getTimeStep()),
     227             :   avglambda(getNumberOfArguments(),0.0),
     228             :   avglambda_restart(getNumberOfArguments(),0.0),
     229             :   expected_eps(getNumberOfArguments(),0.0),
     230             :   sigma(0.0),
     231             :   pace_(100),
     232             :   stride_(100),
     233             :   alpha(1.0),
     234             :   avg_counter(0.0),
     235             :   isFirstStep(true),
     236             :   reweight(false),
     237             :   no_broadcast(false),
     238             :   printFirstStep(true),
     239         950 :   done_average(getNumberOfArguments(),false)
     240             : {
     241          50 :   if(comm.Get_rank()==0) nrep=multi_sim_comm.Get_size();
     242          50 :   if(comm.Get_rank()==0) myrep=multi_sim_comm.Get_rank();
     243          50 :   comm.Bcast(nrep,0);
     244          50 :   comm.Bcast(myrep,0);
     245         100 :   parseFlag("NO_BROADCAST",no_broadcast);
     246             :   //if(no_broadcast){
     247             :   //for(int irep=0;irep<nrep;irep++){
     248             :   //  if(irep!=myrep)
     249             :   //    apply_weights[irep]=0.0;}
     250             :   //}
     251          50 :   avgstep=1.0;
     252          50 :   tstart=-1.0;
     253          50 :   tend=-1.0;
     254          50 :   totalWork=0.0;
     255          50 :   learn_replica=0;
     256             : 
     257         100 :   parse("LEARN_REPLICA",learn_replica);
     258         100 :   parseVector("APPLY_WEIGHTS",apply_weights);
     259          50 :   if(apply_weights.size()==0) apply_weights.resize(nrep,1.0);
     260         100 :   parseVector("KAPPA",kappa);
     261         100 :   parseVector("AT",at);
     262         100 :   parseVector("TAU",tau);
     263         100 :   parse("TYPE",type);
     264             :   error_type="GAUSSIAN";
     265         100 :   parse("ERROR_TYPE",error_type);
     266         100 :   parse("ALPHA",alpha);
     267         100 :   parse("SIGMA",sigma);
     268         100 :   parse("TSTART",tstart);
     269          50 :   if(tstart <0 && tstart != -1.0) error("TSTART should be a positive number");
     270         100 :   parse("TEND",tend);
     271          50 :   if(tend<0 && tend != -1.0) error("TSTART should be a positive number");
     272          50 :   if(tend<tstart) error("TEND should be >= TSTART");
     273         100 :   lagmultfname=getLabel()+".LAGMULT";
     274         100 :   parse("FILE",lagmultfname);
     275         100 :   parse("FMT",fmt);
     276         100 :   parse("PACE",pace_);
     277          50 :   if(pace_<=0 ) error("frequency for lagrangian multipliers update (PACE) is nonsensical");
     278          50 :   stride_=pace_;  //if no STRIDE is passed, then Lagrangian multipliers willbe printed at each update
     279         100 :   parse("PRINT_STRIDE",stride_);
     280          50 :   if(stride_<=0 ) error("frequency for Lagrangian multipliers printing (STRIDE) is nonsensical");
     281          50 :   simtemp=0.;
     282         100 :   parse("TEMP",simtemp);
     283         100 :   if(simtemp>0) simtemp*=plumed.getAtoms().getKBoltzmann();
     284           0 :   else simtemp=plumed.getAtoms().getKbT();
     285         100 :   parseFlag("REWEIGHT",reweight);
     286          50 :   if(simtemp<=0 && reweight) error("Set the temperature (TEMP) if you want to do reweighting.");
     287             : 
     288          50 :   checkRead();
     289             : 
     290          50 :   log.printf("  at");
     291        1546 :   for(unsigned i=0; i<at.size(); i++) log.printf(" %f",at[i]);
     292          50 :   log.printf("\n");
     293          50 :   log.printf("  with initial learning rate for optimization of");
     294        1546 :   for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]);
     295          50 :   log.printf("\n");
     296          50 :   log.printf("Dumping times for the learning rates are (ps): ");
     297        1546 :   for(unsigned i=0; i<tau.size(); i++) log.printf(" %f",tau[i]);
     298          50 :   log.printf("\n");
     299          50 :   log.printf("Lagrangian multipliers are updated every %ld steps (PACE)\n",pace_);
     300         100 :   log.printf("Lagrangian multipliers output file %s\n",lagmultfname.c_str());
     301          50 :   log.printf("Lagrangian multipliers are written every %ld steps (PRINT_STRIDE)\n",stride_);
     302          50 :   if(fmt.length()>0)
     303         100 :     log.printf("The format for real number in Lagrangian multipliers file is %s\n",fmt.c_str());
     304          50 :   if(tstart >-1.0 && tend>-1.0)
     305          14 :     log.printf("Lagrangian multipliers are averaged from %lf ps to %lf ps\n",tstart,tend);
     306          50 :   if(no_broadcast)
     307           0 :     log.printf("Using NO_BROADCAST options. Lagrangian multipliers will not be comunicated to other replicas.\n");
     308             :   //for(int irep=0;irep<nrep;irep++){
     309             :   //  if(apply_weights[irep]!=0)
     310             :   //    log.printf("%d",irep);
     311             :   //  }
     312         150 :   addComponent("force2"); componentIsNotPeriodic("force2");
     313         150 :   addComponent("work"); componentIsNotPeriodic("work");
     314         100 :   valueForce2=getPntrToComponent("force2");
     315         100 :   valueWork=getPntrToComponent("work");
     316             : 
     317             :   std::string comp;
     318        1014 :   for(unsigned i=0; i< getNumberOfArguments() ; i++) {
     319         964 :     comp=getPntrToArgument(i)->getName()+"_coupling";
     320         482 :     addComponent(comp); componentIsNotPeriodic(comp);
     321         964 :     comp=getPntrToArgument(i)->getName()+"_work";
     322         482 :     addComponent(comp); componentIsNotPeriodic(comp);
     323         964 :     work.push_back(0.); // initialize the work value
     324         964 :     comp=getPntrToArgument(i)->getName()+"_error";
     325         482 :     addComponent(comp); componentIsNotPeriodic(comp);
     326             :   }
     327             :   string fname;
     328             :   fname=lagmultfname;
     329          50 :   ifile.link(*this);
     330          50 :   if(ifile.FileExist(fname)) {
     331          37 :     ifile.open(fname);
     332          37 :     if(getRestart()) {
     333          74 :       log.printf("  Restarting from: %s\n",fname.c_str());
     334          37 :       ReadLagrangians(ifile);
     335          37 :       printFirstStep=false;
     336             :     }
     337          37 :     ifile.reset(false);
     338          37 :     ifile.close();
     339             :   }
     340             : 
     341          50 :   lagmultOfile_.link(*this);
     342          50 :   lagmultOfile_.open(fname);
     343         100 :   if(fmt.length()>0) {fmt=" "+fmt; lagmultOfile_.fmtField(fmt);}
     344          50 : }
     345             : ////MEMBER FUNCTIONS
     346          37 : void MaxEnt::ReadLagrangians(IFile &ifile)
     347             : {
     348             :   double dummy;
     349         888 :   while(ifile.scanField("time",dummy)) {
     350        9009 :     for(unsigned j=0; j<getNumberOfArguments(); ++j) {
     351       12903 :       ifile.scanField(getPntrToArgument(j)->getName()+"_coupling",lambda[j]);
     352        4301 :       if(dummy>=tstart && dummy <=tend)
     353          84 :         avglambda[j]+=lambda[j];
     354        4301 :       if(dummy>=tend) {
     355        4231 :         avglambda[j]=lambda[j];
     356             :         done_average[j]=true;
     357             :       }
     358             :     }
     359         407 :     if(dummy>=tstart && dummy <=tend)
     360           6 :       avg_counter++;
     361         407 :     ifile.scanField();
     362             :   }
     363          37 : }
     364         550 : void MaxEnt::WriteLagrangians(vector<double> &lagmult,OFile &file) {
     365         550 :   if(printFirstStep) {
     366         143 :     unsigned ncv=getNumberOfArguments();
     367         286 :     file.printField("time",getTimeStep()*getStep());
     368        2145 :     for(unsigned i=0; i<ncv; ++i)
     369        4004 :       file.printField(getPntrToArgument(i)->getName()+"_coupling",lagmult[i]);
     370         143 :     file.printField();
     371             :   } else {
     372         407 :     if(!isFirstStep) {
     373         370 :       unsigned ncv=getNumberOfArguments();
     374         740 :       file.printField("time",getTimeStep()*getStep());
     375        8190 :       for(unsigned i=0; i<ncv; ++i)
     376       15640 :         file.printField(getPntrToArgument(i)->getName()+"_coupling",lagmult[i]);
     377         370 :       file.printField();
     378             :     }
     379             :   }
     380         550 : }
     381        5302 : double MaxEnt::compute_error(string &err_type,double &l) {
     382        5302 :   double sigma2=pow(sigma,2.0);
     383        5302 :   double l2=convert_lambda(type,l);
     384             :   double return_error=0;
     385        5302 :   if(err_type=="GAUSSIAN" && sigma!=0.0)
     386           0 :     return_error=-l2*sigma2;
     387             :   else {
     388        5302 :     if(err_type=="LAPLACE" && sigma!=0) {
     389        5302 :       return_error=-l2*sigma2/(1.0-l2*l2*sigma2/(alpha+1));
     390             :     }
     391             :   }
     392        5302 :   return return_error;
     393             : }
     394      119118 : double MaxEnt::convert_lambda(string &type,double lold) {
     395             :   double return_lambda=0;
     396      119118 :   if(type=="EQUAL")
     397             :     return_lambda=lold;
     398             :   else {
     399        5302 :     if(type=="INEQUAL>") {
     400           0 :       if(lold>0.0)
     401             :         return_lambda=0.0;
     402             :       else
     403             :         return_lambda=lold;
     404             :     }
     405             :     else {
     406        5302 :       if(type=="INEQUAL<") {
     407           0 :         if(lold<0.0)
     408             :           return_lambda=0.0;
     409             :         else
     410             :           return_lambda=lold;
     411             :       }
     412             :     }
     413             :   }
     414      119118 :   return return_lambda;
     415             : }
     416        5302 : void MaxEnt::check_lambda_boundaries(string &err_type,double &l) {
     417        5302 :   if(err_type=="LAPLACE" && sigma !=0 ) {
     418        5302 :     double l2=convert_lambda(err_type,l);
     419        5302 :     if(l2 <-(sqrt(alpha+1)/sigma-0.01)) {
     420           0 :       l=-(sqrt(alpha+1)/sigma-0.01);
     421           0 :       log.printf("Lambda exceeded the allowed range\n");
     422             :     }
     423        5302 :     if(l2>(sqrt(alpha+1)/sigma-0.01)) {
     424           0 :       l=sqrt(alpha+1)/sigma-0.01;
     425           0 :       log.printf("Lambda exceeded the allowed range\n");
     426             :     }
     427             :   }
     428        5302 : }
     429             : 
     430         550 : void MaxEnt::update_lambda() {
     431             : 
     432             :   double totalWork_=0.0;
     433         550 :   const double time=getTime();
     434         550 :   const double step=getStep();
     435         550 :   double KbT=simtemp;
     436             :   double learning_rate;
     437         550 :   if(reweight)
     438         396 :     BetaReweightBias=plumed.getBias()/KbT;
     439             :   else
     440         154 :     BetaReweightBias=0.0;
     441             : 
     442       11154 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     443       10604 :     const double k=kappa[i];
     444       10604 :     double cv=(getArgument(i)+compute_error(error_type,lambda[i])-at[i]);
     445        5302 :     if(reweight)
     446        4224 :       learning_rate=1.0*k/(1+step/tau[i]);
     447             :     else
     448        1078 :       learning_rate=1.0*k/(1+time/tau[i]);
     449       10604 :     lambda[i]+=learning_rate*cv*exp(-BetaReweightBias); //update Lagrangian multipliers and reweight them if REWEIGHT is set
     450        5302 :     check_lambda_boundaries(error_type,lambda[i]);      //check that Lagrangians multipliers not exceed the allowed range
     451        5890 :     if(time>=tstart && time <=tend && !done_average[i]) {
     452        1092 :       avglambda[i]+=convert_lambda(type,lambda[i]); //compute the average of Lagrangian multipliers over the required time window
     453             :     }
     454        5302 :     if(time>=tend && tend >=0) { //setting tend<0 will disable this feature
     455          98 :       if(!done_average[i]) {
     456          91 :         avglambda[i]=avglambda[i]/avg_counter;
     457             :         done_average[i]=true;
     458          91 :         lambda[i]=avglambda[i];
     459             :       }
     460             :       else
     461           7 :         lambda[i]=avglambda[i]; //keep Lagrangian multipliers fixed to the previously computed average.
     462             :     }
     463       21208 :     work[i]+=(convert_lambda(type,lambda[i])-oldlambda[i])*getArgument(i); //compute the work performed in updating lambda
     464        5302 :     totalWork_+=work[i];
     465        5302 :     totalWork=totalWork_;
     466       10604 :     oldlambda[i]=convert_lambda(type,lambda[i]);
     467             :   };
     468         550 :   if(time>=tstart && time <=tend)
     469          84 :     avg_counter++;
     470         550 : }
     471             : 
     472        5050 : void MaxEnt::calculate() {
     473             :   double totf2=0.0;
     474             :   double ene=0.0;
     475        5050 :   double KbT=simtemp;
     476      102414 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     477      194728 :     getPntrToComponent(getPntrToArgument(i)->getName()+"_error")->set(expected_eps[i]);
     478      146046 :     getPntrToComponent(getPntrToArgument(i)->getName()+"_work")->set(work[i]);
     479       48682 :     valueWork->set(totalWork);
     480      146046 :     getPntrToComponent(getPntrToArgument(i)->getName()+"_coupling")->set(lambda[i]);
     481      146046 :     const double f=-KbT*convert_lambda(type,lambda[i])*apply_weights[myrep];
     482       48682 :     totf2+=f*f;
     483      146046 :     ene+=KbT*convert_lambda(type,lambda[i])*getArgument(i)*apply_weights[myrep];
     484       48682 :     setOutputForce(i,f);
     485             :   }
     486             :   setBias(ene);
     487        5050 :   valueForce2->set(totf2);
     488        5050 : }
     489             : 
     490        5050 : void MaxEnt::update() {
     491             : 
     492        5050 :   if(getStep()%stride_ == 0)
     493         550 :     WriteLagrangians(lambda,lagmultOfile_);
     494        5050 :   if(getStep()%pace_ == 0) {
     495         550 :     update_lambda();
     496         550 :     if(!no_broadcast) {
     497         550 :       if(comm.Get_rank()==0) //Comunicate Lagrangian multipliers from reference replica to higher ones
     498         462 :         multi_sim_comm.Bcast(lambda,learn_replica);
     499             :     }
     500         550 :     comm.Bcast(lambda,0);
     501             :   }
     502        5050 :   isFirstStep=false;
     503        5050 : }
     504             : 
     505             : }
     506             : 
     507        4839 : }

Generated by: LCOV version 1.13