LCOV - code coverage report
Current view: top level - ves - Optimizer.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 700 786 89.1 %
Date: 2025-03-25 09:33:27 Functions: 27 32 84.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-2021 The VES code team
       3             :    (see the PEOPLE-VES file at the root of this folder for a list of names)
       4             : 
       5             :    See http://www.ves-code.org for more information.
       6             : 
       7             :    This file is part of VES code module.
       8             : 
       9             :    The VES code module 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             :    The VES code module 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 the VES code module.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : 
      23             : #include "Optimizer.h"
      24             : #include "CoeffsVector.h"
      25             : #include "CoeffsMatrix.h"
      26             : #include "VesBias.h"
      27             : #include "VesTools.h"
      28             : 
      29             : #include "tools/Exception.h"
      30             : #include "core/PlumedMain.h"
      31             : #include "core/ActionSet.h"
      32             : #include "tools/Communicator.h"
      33             : #include "tools/File.h"
      34             : #include "tools/FileBase.h"
      35             : 
      36             : namespace PLMD {
      37             : namespace ves {
      38             : 
      39          79 : Optimizer::Optimizer(const ActionOptions&ao):
      40             :   Action(ao),
      41             :   ActionPilot(ao),
      42             :   ActionWithValue(ao),
      43         158 :   description_("Undefined"),
      44          79 :   type_("Undefined"),
      45          79 :   stepsizes_(0),
      46          79 :   current_stepsizes(0),
      47          79 :   fixed_stepsize_(true),
      48          79 :   iter_counter(0),
      49          79 :   use_hessian_(false),
      50          79 :   diagonal_hessian_(true),
      51          79 :   monitor_instantaneous_gradient_(false),
      52          79 :   use_mwalkers_mpi_(false),
      53          79 :   mwalkers_mpi_single_files_(true),
      54          79 :   dynamic_targetdists_(0),
      55          79 :   ustride_targetdist_(0),
      56          79 :   ustride_reweightfactor_(0),
      57          79 :   coeffssetid_prefix_(""),
      58          79 :   coeffs_wstride_(100),
      59          79 :   coeffs_output_fmt_(""),
      60          79 :   gradient_wstride_(100),
      61          79 :   gradient_output_fmt_(""),
      62          79 :   hessian_wstride_(100),
      63          79 :   hessianOFiles_(0),
      64          79 :   hessian_output_fmt_(""),
      65          79 :   targetdist_averages_wstride_(0),
      66          79 :   targetdist_averages_output_fmt_(""),
      67          79 :   nbiases_(0),
      68          79 :   bias_pntrs_(0),
      69          79 :   ncoeffssets_(0),
      70          79 :   coeffs_pntrs_(0),
      71          79 :   gradient_pntrs_(0),
      72          79 :   hessian_pntrs_(0),
      73          79 :   targetdist_averages_pntrs_(0),
      74          79 :   identical_coeffs_shape_(true),
      75          79 :   bias_output_active_(false),
      76          79 :   bias_output_stride_(0),
      77          79 :   fes_output_active_(false),
      78          79 :   fes_output_stride_(0),
      79          79 :   fesproj_output_active_(false),
      80          79 :   fesproj_output_stride_(0),
      81          79 :   targetdist_output_active_(false),
      82          79 :   targetdist_output_stride_(0),
      83          79 :   targetdist_proj_output_active_(false),
      84          79 :   targetdist_proj_output_stride_(0),
      85         316 :   isFirstStep(true) {
      86          79 :   std::vector<std::string> bias_labels(0);
      87         158 :   parseVector("BIAS",bias_labels);
      88          79 :   plumed_massert(bias_labels.size()>0,"problem with BIAS keyword");
      89          79 :   nbiases_ = bias_labels.size();
      90             :   //
      91          79 :   std::string error_msg = "";
      92         158 :   bias_pntrs_ = VesTools::getPointersFromLabels<VesBias*>(bias_labels,plumed.getActionSet(),error_msg);
      93          79 :   if(error_msg.size()>0) {
      94           0 :     plumed_merror("Error in keyword BIAS of "+getName()+": "+error_msg);
      95             :   }
      96             : 
      97         164 :   for(unsigned int i=0; i<bias_pntrs_.size(); i++) {
      98          85 :     bias_pntrs_[i]->linkOptimizer(this);
      99             :     //
     100          85 :     std::vector<CoeffsVector*> pntrs_coeffs = bias_pntrs_[i]->getCoeffsPntrs();
     101          85 :     std::vector<CoeffsVector*> pntrs_gradient = bias_pntrs_[i]->getGradientPntrs();
     102          85 :     std::vector<CoeffsVector*> pntrs_targetdist_averages = bias_pntrs_[i]->getTargetDistAveragesPntrs();
     103          85 :     plumed_massert(pntrs_coeffs.size()==pntrs_gradient.size(),"something wrong in the coefficients and gradient passed from VES bias");
     104          85 :     plumed_massert(pntrs_coeffs.size()==pntrs_targetdist_averages.size(),"something wrong in the coefficients and target distribution averages passed from VES bias");
     105         170 :     for(unsigned int k=0; k<pntrs_coeffs.size(); k++) {
     106          85 :       plumed_massert(pntrs_coeffs[k] != NULL,"some coefficient is not linked correctly");
     107          85 :       plumed_massert(pntrs_gradient[k] != NULL,"some gradient is not linked correctly");
     108          85 :       plumed_massert(pntrs_targetdist_averages[k] != NULL,"some target distribution average is not linked correctly");
     109             :       pntrs_coeffs[k]->turnOnIterationCounter();
     110          85 :       coeffs_pntrs_.push_back(pntrs_coeffs[k]);
     111          85 :       pntrs_gradient[k]->turnOnIterationCounter();
     112          85 :       gradient_pntrs_.push_back(pntrs_gradient[k]);
     113          85 :       pntrs_targetdist_averages[k]->turnOnIterationCounter();
     114          85 :       targetdist_averages_pntrs_.push_back(pntrs_targetdist_averages[k]);
     115             :       //
     116          85 :       auto aux_coeffs_tmp = Tools::make_unique<CoeffsVector>(*pntrs_coeffs[k]);
     117          85 :       std::string aux_label = pntrs_coeffs[k]->getLabel();
     118          85 :       if(aux_label.find("coeffs")!=std::string::npos) {
     119         170 :         aux_label.replace(aux_label.find("coeffs"), std::string("coeffs").length(), "aux_coeffs");
     120             :       } else {
     121             :         aux_label += "_aux";
     122             :       }
     123          85 :       aux_coeffs_tmp->setLabels(aux_label);
     124          85 :       aux_coeffs_pntrs_.emplace_back(std::move(aux_coeffs_tmp));
     125          85 :       AuxCoeffs(i).setValues( Coeffs(i) );
     126          85 :     }
     127             :   }
     128          79 :   ncoeffssets_ = coeffs_pntrs_.size();
     129          79 :   plumed_massert(aux_coeffs_pntrs_.size()==ncoeffssets_,"problems in linking aux coefficients");
     130          79 :   plumed_massert(gradient_pntrs_.size()==ncoeffssets_,"problems in linking gradients");
     131          79 :   setAllCoeffsSetIterationCounters();
     132             : 
     133             : 
     134             :   //
     135          79 :   identical_coeffs_shape_ = true;
     136          85 :   for(unsigned int i=1; i<ncoeffssets_; i++) {
     137           6 :     if(!coeffs_pntrs_[0]->sameShape(*coeffs_pntrs_[i])) {
     138           0 :       identical_coeffs_shape_ = false;
     139           0 :       break;
     140             :     }
     141             :   }
     142             :   //
     143          79 :   if(keywords.exists("STEPSIZE")) {
     144          77 :     plumed_assert(!keywords.exists("INITIAL_STEPSIZE"));
     145          77 :     fixed_stepsize_=true;
     146          77 :     parseMultipleValues("STEPSIZE",stepsizes_);
     147          77 :     setCurrentStepSizes(stepsizes_);
     148             :   }
     149          79 :   if(keywords.exists("INITIAL_STEPSIZE")) {
     150           1 :     plumed_assert(!keywords.exists("STEPSIZE"));
     151           1 :     fixed_stepsize_=false;
     152           1 :     parseMultipleValues("INITIAL_STEPSIZE",stepsizes_);
     153           1 :     setCurrentStepSizes(stepsizes_);
     154             :   }
     155             :   //
     156          79 :   if(ncoeffssets_==1) {
     157          76 :     log.printf("  optimizing VES bias %s with label %s: \n",bias_pntrs_[0]->getName().c_str(),bias_pntrs_[0]->getLabel().c_str());
     158          76 :     log.printf("   KbT: %f\n",bias_pntrs_[0]->getKbT());
     159          76 :     log.printf("  number of coefficients: %zu\n",coeffs_pntrs_[0]->numberOfCoeffs());
     160          76 :     if(stepsizes_.size()>0) {
     161          75 :       if(fixed_stepsize_) {
     162          74 :         log.printf("  using a constant step size of %f\n",stepsizes_[0]);
     163             :       } else {
     164           1 :         log.printf("  using an initial step size of %f\n",stepsizes_[0]);
     165             :       }
     166             :     }
     167             :   } else {
     168           3 :     log.printf("  optimizing %u coefficient sets from following %u VES biases:\n",ncoeffssets_,nbiases_);
     169          12 :     for(unsigned int i=0; i<nbiases_; i++) {
     170           9 :       log.printf("   %s of type %s (KbT: %f) \n",bias_pntrs_[i]->getLabel().c_str(),bias_pntrs_[i]->getName().c_str(),bias_pntrs_[i]->getKbT());
     171             :     }
     172             :     size_t tot_ncoeffs = 0;
     173          12 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
     174           9 :       log.printf("  coefficient set %u: \n",i);
     175           9 :       log.printf("   used in bias %s (type %s)\n",coeffs_pntrs_[i]->getPntrToAction()->getLabel().c_str(),coeffs_pntrs_[i]->getPntrToAction()->getName().c_str());
     176           9 :       log.printf("   number of coefficients: %zu\n",coeffs_pntrs_[i]->numberOfCoeffs());
     177           9 :       if(stepsizes_.size()>0) {
     178           9 :         if(fixed_stepsize_) {
     179           9 :           log.printf("   using a constant step size of %f\n",stepsizes_[i]);
     180             :         } else {
     181           0 :           log.printf("   using an initial step size of %f\n",stepsizes_[i]);
     182             :         }
     183             :       }
     184           9 :       tot_ncoeffs += coeffs_pntrs_[i]->numberOfCoeffs();
     185             :     }
     186           3 :     log.printf("  total number of coefficients: %zu\n",tot_ncoeffs);
     187           3 :     if(identical_coeffs_shape_) {
     188           3 :       log.printf("  the indices shape is identical for all coefficient sets\n");
     189             :     } else {
     190           0 :       log.printf("  the indices shape differs between coefficient sets\n");
     191             :     }
     192             :   }
     193             : 
     194             :   //
     195          79 :   if(keywords.exists("FULL_HESSIAN")) {
     196           0 :     bool full_hessian=false;
     197           0 :     parseFlag("FULL_HESSIAN",full_hessian);
     198           0 :     diagonal_hessian_ = !full_hessian;
     199             :   }
     200             :   //
     201             :   bool mw_single_files = false;
     202          79 :   if(keywords.exists("MULTIPLE_WALKERS")) {
     203          79 :     parseFlag("MULTIPLE_WALKERS",use_mwalkers_mpi_);
     204          79 :     if(use_mwalkers_mpi_) {
     205             :       mw_single_files=true;
     206             :     }
     207             :   }
     208             : 
     209          79 :   int numwalkers=1;
     210          79 :   int walker_rank=0;
     211          79 :   if(comm.Get_rank()==0) {
     212          70 :     numwalkers = multi_sim_comm.Get_size();
     213          70 :     walker_rank = multi_sim_comm.Get_rank();
     214             :   }
     215          79 :   comm.Bcast(numwalkers,0);
     216          79 :   comm.Bcast(walker_rank,0);
     217          79 :   if(use_mwalkers_mpi_ && numwalkers==1) {
     218           0 :     plumed_merror("using the MULTIPLE_WALKERS keyword does not make sense if running the MD code with a single replica");
     219             :   }
     220          79 :   if(use_mwalkers_mpi_) {
     221          12 :     log.printf("  optimization performed using multiple walkers connected via MPI:\n");
     222          12 :     log.printf("   number of walkers: %d\n",numwalkers);
     223          12 :     log.printf("   walker number: %d\n",walker_rank);
     224          12 :     log.printf("   please see and cite ");
     225          24 :     log << plumed.cite("Raiteri, Laio, Gervasio, Micheletti, and Parrinello, J. Phys. Chem. B 110, 3533 (2006)");
     226          12 :     log.printf("\n");
     227             :   }
     228             : 
     229          79 :   dynamic_targetdists_.resize(nbiases_,false);
     230          79 :   if(keywords.exists("TARGETDIST_STRIDE")) {
     231             :     bool need_stride = false;
     232         162 :     for(unsigned int i=0; i<nbiases_; i++) {
     233          84 :       dynamic_targetdists_[i] = bias_pntrs_[i]->dynamicTargetDistribution();
     234          84 :       if(dynamic_targetdists_[i]) {
     235             :         need_stride = true;
     236             :       }
     237             :     }
     238          78 :     parse("TARGETDIST_STRIDE",ustride_targetdist_);
     239          78 :     if(need_stride && ustride_targetdist_==0) {
     240           0 :       plumed_merror("one of the biases has a dynamic target distribution so you need to give stride for updating it by using the TARGETDIST_STRIDE keyword");
     241             :     }
     242          78 :     if(!need_stride && ustride_targetdist_!=0) {
     243           0 :       plumed_merror("using the TARGETDIST_STRIDE keyword doesn't make sense as there is no dynamic target distribution to update");
     244             :     }
     245          78 :     if(ustride_targetdist_>0) {
     246          38 :       if(nbiases_==1) {
     247          38 :         log.printf("  the target distribution will be updated very %u coefficient iterations\n",ustride_targetdist_);
     248             :       } else {
     249           0 :         log.printf("  the target distribution will be updated very %u coefficient iterations for the following biases\n   ",ustride_targetdist_);
     250           0 :         for(unsigned int i=0; i<nbiases_; i++) {
     251           0 :           log.printf("%s ",bias_pntrs_[i]->getLabel().c_str());
     252             :         }
     253           0 :         log.printf("\n");
     254             :       }
     255          38 :       log.printf("  See and cite ");
     256          76 :       log << plumed.cite("Valsson and Parrinello, J. Chem. Theory Comput. 11, 1996-2002 (2015)");
     257          38 :       log.printf("\n");
     258             :     }
     259             :   }
     260             : 
     261          79 :   if(keywords.exists("REWEIGHT_FACTOR_STRIDE")) {
     262             :     bool reweightfactor_calculated = false;
     263           0 :     for(unsigned int i=0; i<nbiases_; i++) {
     264           0 :       reweightfactor_calculated = bias_pntrs_[i]->isReweightFactorCalculated();
     265             :     }
     266           0 :     parse("REWEIGHT_FACTOR_STRIDE",ustride_reweightfactor_);
     267           0 :     if(ustride_reweightfactor_==0 && reweightfactor_calculated) {
     268           0 :       plumed_merror("the calculation of the reweight factor is enabled, You need to use the REWEIGHT_FACTOR_STRIDE keyword to specfiy how often it should be updated.");
     269             :     }
     270           0 :     if(ustride_reweightfactor_>0) {
     271           0 :       if(!reweightfactor_calculated) {
     272           0 :         plumed_merror("In order to use the REWEIGHT_FACTOR_STRIDE keyword you need to enable the calculation of the reweight factor in the VES bias by using the CALC_REWEIGHT_FACTOR flag.");
     273             :       }
     274           0 :       log.printf("  the reweight factor c(t) will be updated very %u coefficient iterations\n",ustride_reweightfactor_);
     275             :     }
     276             :   }
     277             : 
     278          79 :   if(keywords.exists("MONITOR_INSTANTANEOUS_GRADIENT")) {
     279         158 :     parseFlag("MONITOR_INSTANTANEOUS_GRADIENT",monitor_instantaneous_gradient_);
     280             :   }
     281             : 
     282          79 :   if(keywords.exists("MONITOR_AVERAGE_GRADIENT")) {
     283          76 :     bool monitor_aver_gradient = false;
     284          76 :     parseFlag("MONITOR_AVERAGE_GRADIENT",monitor_aver_gradient);
     285          76 :     if(monitor_aver_gradient) {
     286           2 :       unsigned int averaging_exp_decay=0;
     287           4 :       parse("MONITOR_AVERAGES_GRADIENT_EXP_DECAY",averaging_exp_decay);
     288             :       aver_gradient_pntrs_.clear();
     289           4 :       for(unsigned int i=0; i<ncoeffssets_; i++) {
     290           2 :         auto aver_gradient_tmp = Tools::make_unique<CoeffsVector>(*gradient_pntrs_[i]);
     291           2 :         aver_gradient_tmp->clear();
     292             :         std::string aver_grad_label = aver_gradient_tmp->getLabel();
     293           2 :         if(aver_grad_label.find("gradient")!=std::string::npos) {
     294           4 :           aver_grad_label.replace(aver_grad_label.find("gradient"), std::string("gradient").length(), "aver_gradient");
     295             :         } else {
     296             :           aver_grad_label += "_aver";
     297             :         }
     298           2 :         aver_gradient_tmp->setLabels(aver_grad_label);
     299           2 :         if(averaging_exp_decay>0) {
     300             :           aver_gradient_tmp->setupExponentiallyDecayingAveraging(averaging_exp_decay);
     301             :         }
     302           2 :         aver_gradient_pntrs_.emplace_back(std::move(aver_gradient_tmp));
     303           2 :       }
     304             :     }
     305             :   }
     306             : 
     307             : 
     308          79 :   if(ncoeffssets_>1) {
     309             :     coeffssetid_prefix_="c-";
     310           3 :     if(keywords.exists("COEFFS_SET_ID_PREFIX")) {
     311           6 :       parse("COEFFS_SET_ID_PREFIX",coeffssetid_prefix_);
     312             :     }
     313             :   } else {
     314             :     coeffssetid_prefix_="";
     315          76 :     if(keywords.exists("COEFFS_SET_ID_PREFIX")) {
     316         152 :       parse("COEFFS_SET_ID_PREFIX",coeffssetid_prefix_);
     317             :     }
     318          76 :     if(coeffssetid_prefix_.size()>0) {
     319           0 :       plumed_merror("COEFFS_SET_ID_PREFIX should only be given if optimizing multiple coefficient sets");
     320             :     }
     321             :   }
     322             : 
     323          79 :   if(keywords.exists("INITIAL_COEFFS")) {
     324             :     std::vector<std::string> initial_coeffs_fnames;
     325         158 :     parseFilenames("INITIAL_COEFFS",initial_coeffs_fnames);
     326          79 :     if(initial_coeffs_fnames.size()>0) {
     327           1 :       readCoeffsFromFiles(initial_coeffs_fnames,false);
     328           1 :       comm.Barrier();
     329           1 :       if(comm.Get_rank()==0 && use_mwalkers_mpi_) {
     330           0 :         multi_sim_comm.Barrier();
     331             :       }
     332           1 :       setAllCoeffsSetIterationCounters();
     333             :     }
     334          79 :   }
     335             :   //
     336             : 
     337             :   std::vector<std::string> coeffs_fnames;
     338          79 :   if(keywords.exists("COEFFS_FILE")) {
     339         158 :     parseFilenames("COEFFS_FILE",coeffs_fnames,"coeffs.data");
     340          79 :     bool start_opt_afresh=false;
     341          79 :     if(keywords.exists("START_OPTIMIZATION_AFRESH")) {
     342          76 :       parseFlag("START_OPTIMIZATION_AFRESH",start_opt_afresh);
     343          76 :       if(start_opt_afresh && !getRestart()) {
     344           0 :         plumed_merror("the START_OPTIMIZATION_AFRESH keyword should only be used when a restart has been triggered by the RESTART keyword or the MD code");
     345             :       }
     346             :     }
     347          79 :     if(getRestart()) {
     348          28 :       for(unsigned int i=0; i<coeffs_fnames.size(); i++) {
     349          15 :         IFile ifile;
     350          15 :         ifile.link(*this);
     351          15 :         if(use_mwalkers_mpi_) {
     352           8 :           ifile.enforceSuffix("");
     353             :         }
     354          15 :         bool file_exist = ifile.FileExist(coeffs_fnames[i]);
     355          15 :         if(!file_exist) {
     356           0 :           std::string fname = FileBase::appendSuffix(coeffs_fnames[i],ifile.getSuffix());
     357           0 :           plumed_merror("Cannot find coefficient file " + fname + " when trying to restart an optimzation. If you don't want to restart the optimzation please remove the RESTART keyword or use the RESTART=NO within the "+getName()+" action to locally disable the restart.");
     358             :         }
     359          15 :       }
     360          13 :       readCoeffsFromFiles(coeffs_fnames,true);
     361          13 :       comm.Barrier();
     362          13 :       if(comm.Get_rank()==0 && use_mwalkers_mpi_) {
     363           4 :         multi_sim_comm.Barrier();
     364             :       }
     365          13 :       unsigned int iter_opt_tmp = coeffs_pntrs_[0]->getIterationCounter();
     366          15 :       for(unsigned int i=1; i<ncoeffssets_; i++) {
     367           2 :         plumed_massert(coeffs_pntrs_[i]->getIterationCounter()==iter_opt_tmp,"the iteraton counter should be the same for all files when restarting from previous coefficient files\n");
     368             :       }
     369          13 :       if(start_opt_afresh) {
     370             :         setIterationCounter(0);
     371           1 :         log.printf("  Optimization started afresh at iteration %u\n",getIterationCounter());
     372           2 :         for(unsigned int i=0; i<ncoeffssets_; i++) {
     373           1 :           AuxCoeffs(i).setValues( Coeffs(i) );
     374             :         }
     375             :       } else {
     376             :         setIterationCounter(coeffs_pntrs_[0]->getIterationCounter());
     377          12 :         log.printf("  Optimization restarted at iteration %u\n",getIterationCounter());
     378             :       }
     379          13 :       setAllCoeffsSetIterationCounters();
     380             :     }
     381             : 
     382          79 :     std::string coeffs_wstride_tmpstr="";
     383         158 :     parse("COEFFS_OUTPUT",coeffs_wstride_tmpstr);
     384          79 :     if(coeffs_wstride_tmpstr!="OFF" && coeffs_wstride_tmpstr.size()>0) {
     385          79 :       Tools::convert(coeffs_wstride_tmpstr,coeffs_wstride_);
     386             :     }
     387          79 :     if(coeffs_wstride_tmpstr=="OFF") {
     388             :       coeffs_fnames.clear();
     389             :     }
     390          79 :     setupOFiles(coeffs_fnames,coeffsOFiles_,mw_single_files);
     391         158 :     parse("COEFFS_FMT",coeffs_output_fmt_);
     392          79 :     if(coeffs_output_fmt_.size()>0) {
     393         162 :       for(unsigned int i=0; i<ncoeffssets_; i++) {
     394          84 :         coeffs_pntrs_[i]->setOutputFmt(coeffs_output_fmt_);
     395             :       }
     396             :     }
     397          79 :     if(!getRestart()) {
     398         136 :       for(unsigned int i=0; i<coeffsOFiles_.size(); i++) {
     399          70 :         coeffs_pntrs_[i]->writeToFile(*coeffsOFiles_[i],aux_coeffs_pntrs_[i].get(),false);
     400             :       }
     401             :     }
     402          79 :     if(coeffs_fnames.size()>0) {
     403          79 :       if(ncoeffssets_==1) {
     404         152 :         log.printf("  Coefficients will be written out to file %s every %u iterations\n",coeffsOFiles_[0]->getPath().c_str(),coeffs_wstride_);
     405             :       } else {
     406           3 :         log.printf("  Coefficients will be written out to the following files every %u iterations:\n",coeffs_wstride_);
     407          12 :         for(unsigned int i=0; i<coeffs_fnames.size(); i++) {
     408          18 :           log.printf("   coefficient set %u: %s\n",i,coeffsOFiles_[i]->getPath().c_str());
     409             :         }
     410             :       }
     411             :     } else {
     412           0 :       log.printf("  Output of coefficients to file has been disabled\n");
     413             :     }
     414             :   }
     415             : 
     416             :   std::vector<std::string> gradient_fnames;
     417          79 :   if(keywords.exists("GRADIENT_FILE")) {
     418          79 :     parseFilenames("GRADIENT_FILE",gradient_fnames);
     419         158 :     parse("GRADIENT_OUTPUT",gradient_wstride_);
     420             : 
     421          79 :     if(coeffs_fnames.size()>0) {
     422         151 :       for(unsigned int i=0; i<gradient_fnames.size(); i++) {
     423          72 :         plumed_massert(gradient_fnames[i]!=coeffs_fnames[i],"COEFFS_FILE and GRADIENT_FILE cannot be the same");
     424             :       }
     425             :     }
     426          79 :     setupOFiles(gradient_fnames,gradientOFiles_,mw_single_files);
     427         158 :     parse("GRADIENT_FMT",gradient_output_fmt_);
     428          79 :     if(gradient_output_fmt_.size()>0) {
     429         138 :       for(unsigned int i=0; i<ncoeffssets_; i++) {
     430          72 :         gradient_pntrs_[i]->setOutputFmt(gradient_output_fmt_);
     431             :       }
     432             :     }
     433             : 
     434          79 :     if(gradient_fnames.size()>0) {
     435          66 :       if(ncoeffssets_==1) {
     436         126 :         log.printf("  Gradient will be written out to file %s every %u iterations\n",gradientOFiles_[0]->getPath().c_str(),gradient_wstride_);
     437             :       } else {
     438           3 :         log.printf("  Gradient will be written out to the following files every %u iterations:\n",gradient_wstride_);
     439          12 :         for(unsigned int i=0; i<gradient_fnames.size(); i++) {
     440          18 :           log.printf("   coefficient set %u: %s\n",i,gradientOFiles_[i]->getPath().c_str());
     441             :         }
     442             :       }
     443             :     }
     444             :   }
     445             : 
     446             :   std::vector<std::string> hessian_fnames;
     447          79 :   if(keywords.exists("HESSIAN_FILE")) {
     448          76 :     parseFilenames("HESSIAN_FILE",hessian_fnames);
     449         152 :     parse("HESSIAN_OUTPUT",hessian_wstride_);
     450             : 
     451          76 :     if(coeffs_fnames.size()>0) {
     452         142 :       for(unsigned int i=0; i<hessian_fnames.size(); i++) {
     453          66 :         plumed_massert(hessian_fnames[i]!=coeffs_fnames[i],"COEFFS_FILE and HESSIAN_FILE cannot be the same");
     454             :       }
     455             :     }
     456          76 :     if(gradient_fnames.size()>0) {
     457         131 :       for(unsigned int i=0; i<hessian_fnames.size(); i++) {
     458          66 :         plumed_massert(hessian_fnames[i]!=gradient_fnames[i],"GRADIENT_FILE and HESSIAN_FILE cannot be the same");
     459             :       }
     460             :     }
     461          76 :     setupOFiles(hessian_fnames,hessianOFiles_,mw_single_files);
     462         152 :     parse("HESSIAN_FMT",hessian_output_fmt_);
     463             : 
     464          76 :     if(hessian_fnames.size()>0) {
     465          62 :       if(ncoeffssets_==1) {
     466         120 :         log.printf("  Hessian will be written out to file %s every %u iterations\n",hessianOFiles_[0]->getPath().c_str(),hessian_wstride_);
     467             :       } else {
     468           2 :         log.printf("  Hessian will be written out to the following files every %u iterations:\n",hessian_wstride_);
     469           8 :         for(unsigned int i=0; i<hessian_fnames.size(); i++) {
     470          12 :           log.printf("   coefficient set %u: %s\n",i,hessianOFiles_[i]->getPath().c_str());
     471             :         }
     472             :       }
     473             :     }
     474             :   }
     475             : 
     476             : 
     477             :   //
     478          79 :   if(keywords.exists("MASK_FILE")) {
     479             :     std::vector<std::string> mask_fnames_in;
     480         156 :     parseVector("MASK_FILE",mask_fnames_in);
     481          78 :     if(mask_fnames_in.size()==1 && ncoeffssets_>1) {
     482           0 :       if(identical_coeffs_shape_) {
     483           0 :         mask_fnames_in.resize(ncoeffssets_,mask_fnames_in[0]);
     484             :       } else {
     485           0 :         plumed_merror("the coefficients indices shape differs between biases so you need to give a separate file for each coefficient set\n");
     486             :       }
     487             :     }
     488          78 :     if(mask_fnames_in.size()>0 && mask_fnames_in.size()!=ncoeffssets_) {
     489           0 :       plumed_merror("Error in MASK_FILE keyword: either give one value for all biases or a separate value for each coefficient set");
     490             :     }
     491             : 
     492          78 :     coeffs_mask_pntrs_.resize(ncoeffssets_);
     493         162 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
     494         168 :       coeffs_mask_pntrs_[i] = Tools::make_unique<CoeffsVector>(*coeffs_pntrs_[i]);
     495         168 :       coeffs_mask_pntrs_[i]->setLabels("mask");
     496          84 :       coeffs_mask_pntrs_[i]->setValues(1.0);
     497         168 :       coeffs_mask_pntrs_[i]->setOutputFmt("%f");
     498             :     }
     499             : 
     500          78 :     if(mask_fnames_in.size()>0) {
     501           1 :       if(ncoeffssets_==1) {
     502           1 :         size_t nread = coeffs_mask_pntrs_[0]->readFromFile(mask_fnames_in[0],true,true);
     503           1 :         log.printf("  read %zu values from mask file %s\n",nread,mask_fnames_in[0].c_str());
     504           1 :         size_t ndeactived = coeffs_mask_pntrs_[0]->countValues(0.0);
     505           1 :         log.printf("  deactived optimization of %zu coefficients\n",ndeactived);
     506             :       } else {
     507           0 :         for(unsigned int i=0; i<ncoeffssets_; i++) {
     508           0 :           size_t nread = coeffs_mask_pntrs_[i]->readFromFile(mask_fnames_in[i],true,true);
     509           0 :           log.printf("  mask for coefficient set %u:\n",i);
     510           0 :           log.printf("   read %zu values from file %s\n",nread,mask_fnames_in[i].c_str());
     511           0 :           size_t ndeactived = coeffs_mask_pntrs_[0]->countValues(0.0);
     512           0 :           log.printf("   deactived optimization of %zu coefficients\n",ndeactived);
     513             :         }
     514             :       }
     515             :     }
     516             : 
     517             :     std::vector<std::string> mask_fnames_out;
     518          78 :     parseFilenames("OUTPUT_MASK_FILE",mask_fnames_out);
     519             : 
     520          79 :     for(unsigned int i=0; i<mask_fnames_out.size(); i++) {
     521           1 :       if(mask_fnames_in.size()>0) {
     522           1 :         plumed_massert(mask_fnames_out[i]!=mask_fnames_in[i],"MASK_FILE and OUTPUT_MASK_FILE cannot be the same");
     523             :       }
     524           1 :       OFile maskOFile;
     525           1 :       maskOFile.link(*this);
     526           1 :       maskOFile.enforceBackup();
     527           1 :       if(use_mwalkers_mpi_ && mwalkers_mpi_single_files_) {
     528           0 :         unsigned int r=0;
     529           0 :         if(comm.Get_rank()==0) {
     530           0 :           r=multi_sim_comm.Get_rank();
     531             :         }
     532           0 :         comm.Bcast(r,0);
     533           0 :         if(r>0) {
     534             :           mask_fnames_out[i]="/dev/null";
     535             :         }
     536           0 :         maskOFile.enforceSuffix("");
     537             :       }
     538           1 :       maskOFile.open(mask_fnames_out[i]);
     539           1 :       coeffs_mask_pntrs_[i]->writeToFile(maskOFile,true);
     540           1 :       maskOFile.close();
     541           1 :     }
     542          78 :   }
     543             : 
     544          79 :   if(getRestart() && ustride_targetdist_>0) {
     545          16 :     for(unsigned int i=0; i<nbiases_; i++) {
     546           8 :       if(dynamic_targetdists_[i]) {
     547           8 :         bias_pntrs_[i]->restartTargetDistributions();
     548             :       }
     549             :     }
     550             :   }
     551             : 
     552             : 
     553             :   std::vector<std::string> targetdist_averages_fnames;
     554          79 :   if(keywords.exists("TARGETDIST_AVERAGES_FILE")) {
     555         158 :     parseFilenames("TARGETDIST_AVERAGES_FILE",targetdist_averages_fnames,"targetdist-averages.data");
     556         158 :     parse("TARGETDIST_AVERAGES_OUTPUT",targetdist_averages_wstride_);
     557             : 
     558          79 :     if(coeffs_fnames.size()>0) {
     559         164 :       for(unsigned int i=0; i<targetdist_averages_fnames.size(); i++) {
     560          85 :         plumed_massert(targetdist_averages_fnames[i]!=coeffs_fnames[i],"COEFFS_FILE and TARGETDIST_AVERAGES_FILE cannot be the same");
     561             :       }
     562             :     }
     563          79 :     if(gradient_fnames.size()>0) {
     564         138 :       for(unsigned int i=0; i<targetdist_averages_fnames.size(); i++) {
     565          72 :         plumed_massert(targetdist_averages_fnames[i]!=gradient_fnames[i],"GRADIENT_FILE and TARGETDIST_AVERAGES_FILE cannot be the same");
     566             :       }
     567             :     }
     568          79 :     if(hessian_fnames.size()>0) {
     569         128 :       for(unsigned int i=0; i<targetdist_averages_fnames.size(); i++) {
     570          66 :         plumed_massert(targetdist_averages_fnames[i]!=hessian_fnames[i],"HESSIAN_FILE and TARGETDIST_AVERAGES_FILE cannot be the same");
     571             :       }
     572             :     }
     573          79 :     setupOFiles(targetdist_averages_fnames,targetdist_averagesOFiles_,mw_single_files);
     574         158 :     parse("TARGETDIST_AVERAGES_FMT",targetdist_averages_output_fmt_);
     575          79 :     if(targetdist_averages_output_fmt_.size()>0) {
     576         156 :       for(unsigned int i=0; i<ncoeffssets_; i++) {
     577          81 :         targetdist_averages_pntrs_[i]->setOutputFmt(targetdist_averages_output_fmt_);
     578             :       }
     579             :     }
     580             : 
     581         164 :     for(unsigned int i=0; i<targetdist_averagesOFiles_.size(); i++) {
     582          85 :       targetdist_averages_pntrs_[i]->writeToFile(*targetdist_averagesOFiles_[i]);
     583             :     }
     584             : 
     585          79 :     if(targetdist_averages_wstride_==0) {
     586             :       targetdist_averagesOFiles_.clear();
     587             :     }
     588             : 
     589          79 :     if(targetdist_averages_fnames.size()>0 && targetdist_averages_wstride_ > 0) {
     590          34 :       if(ncoeffssets_==1) {
     591          68 :         log.printf("  Target distribution averages will be written out to file %s every %u iterations\n",targetdist_averagesOFiles_[0]->getPath().c_str(),targetdist_averages_wstride_);
     592             :       } else {
     593           0 :         log.printf("  Target distribution averages will be written out to the following files every %u iterations:\n",targetdist_averages_wstride_);
     594           0 :         for(unsigned int i=0; i<targetdist_averages_fnames.size(); i++) {
     595           0 :           log.printf("   coefficient set %u: %s\n",i,targetdist_averagesOFiles_[i]->getPath().c_str());
     596             :         }
     597             :       }
     598             :     }
     599             :   }
     600             : 
     601             : 
     602          79 :   if(keywords.exists("BIAS_OUTPUT")) {
     603          79 :     parse("BIAS_OUTPUT",bias_output_stride_);
     604          79 :     if(bias_output_stride_>0) {
     605          74 :       bias_output_active_=true;
     606         154 :       for(unsigned int i=0; i<nbiases_; i++) {
     607          80 :         bias_pntrs_[i]->enableBiasFileOutput();
     608          80 :         bias_pntrs_[i]->setupBiasFileOutput();
     609          80 :         bias_pntrs_[i]->writeBiasToFile();
     610             :       }
     611             :     } else {
     612           5 :       bias_output_active_=false;
     613           5 :       bias_output_stride_=1000;
     614             :     }
     615             :   }
     616             : 
     617          79 :   if(keywords.exists("FES_OUTPUT")) {
     618          79 :     parse("FES_OUTPUT",fes_output_stride_);
     619          79 :     if(fes_output_stride_>0) {
     620          74 :       fes_output_active_=true;
     621         154 :       for(unsigned int i=0; i<nbiases_; i++) {
     622          80 :         bias_pntrs_[i]->enableFesFileOutput();
     623          80 :         bias_pntrs_[i]->setupFesFileOutput();
     624          80 :         bias_pntrs_[i]->writeFesToFile();
     625             :       }
     626             :     } else {
     627           5 :       fes_output_active_=false;
     628           5 :       fes_output_stride_=1000;
     629             :     }
     630             :   }
     631             : 
     632          79 :   if(keywords.exists("FES_PROJ_OUTPUT")) {
     633          79 :     parse("FES_PROJ_OUTPUT",fesproj_output_stride_);
     634          79 :     if(fesproj_output_stride_>0) {
     635          16 :       fesproj_output_active_=true;
     636          32 :       for(unsigned int i=0; i<nbiases_; i++) {
     637          16 :         bias_pntrs_[i]->enableFesProjFileOutput();
     638          16 :         bias_pntrs_[i]->setupFesProjFileOutput();
     639          16 :         bias_pntrs_[i]->writeFesProjToFile();
     640             :       }
     641             :     } else {
     642          63 :       fesproj_output_active_=false;
     643          63 :       fesproj_output_stride_=1000;
     644             :     }
     645             :   }
     646             : 
     647         164 :   for(unsigned int i=0; i<nbiases_; i++) {
     648          85 :     if(!dynamic_targetdists_[i] && bias_pntrs_[i]->isStaticTargetDistFileOutputActive()) {
     649           4 :       bias_pntrs_[i]->setupTargetDistFileOutput();
     650           4 :       bias_pntrs_[i]->writeTargetDistToFile();
     651           4 :       bias_pntrs_[i]->setupTargetDistProjFileOutput();
     652           4 :       bias_pntrs_[i]->writeTargetDistProjToFile();
     653             :     }
     654             :   }
     655             : 
     656          79 :   if(keywords.exists("TARGETDIST_OUTPUT")) {
     657          78 :     parse("TARGETDIST_OUTPUT",targetdist_output_stride_);
     658          78 :     if(targetdist_output_stride_>0) {
     659          37 :       if(ustride_targetdist_==0) {
     660           0 :         plumed_merror("it doesn't make sense to use the TARGETDIST_OUTPUT keyword if you don't have a target distribution that needs to be updated");
     661             :       }
     662          37 :       if(targetdist_output_stride_%ustride_targetdist_!=0) {
     663           0 :         plumed_merror("the value given in TARGETDIST_OUTPUT doesn't make sense, it should be multiple of TARGETDIST_STRIDE");
     664             :       }
     665          37 :       if(targetdist_output_stride_%coeffs_wstride_!=0) {
     666           0 :         plumed_merror("the value given in TARGETDIST_OUTPUT doesn't make sense, it should be multiple of COEFFS_OUTPUT");
     667             :       }
     668             : 
     669          37 :       targetdist_output_active_=true;
     670          74 :       for(unsigned int i=0; i<nbiases_; i++) {
     671          37 :         if(dynamic_targetdists_[i]) {
     672          37 :           bias_pntrs_[i]->enableDynamicTargetDistFileOutput();
     673          37 :           bias_pntrs_[i]->setupTargetDistFileOutput();
     674          37 :           bias_pntrs_[i]->writeTargetDistToFile();
     675             :         }
     676             :       }
     677             :     } else {
     678          41 :       targetdist_output_active_=false;
     679          41 :       targetdist_output_stride_=1000;
     680             :     }
     681             :   }
     682             : 
     683          79 :   if(keywords.exists("TARGETDIST_PROJ_OUTPUT")) {
     684          78 :     parse("TARGETDIST_PROJ_OUTPUT",targetdist_proj_output_stride_);
     685          78 :     if(targetdist_proj_output_stride_>0) {
     686           3 :       if(ustride_targetdist_==0) {
     687           0 :         plumed_merror("it doesn't make sense to use the TARGETDIST_PROJ_OUTPUT keyword if you don't have a target distribution that needs to be updated");
     688             :       }
     689           3 :       if(targetdist_proj_output_stride_%ustride_targetdist_!=0) {
     690           0 :         plumed_merror("the value given in TARGETDIST_PROJ_OUTPUT doesn't make sense, it should be multiple of TARGETDIST_STRIDE");
     691             :       }
     692             : 
     693           3 :       targetdist_proj_output_active_=true;
     694           6 :       for(unsigned int i=0; i<nbiases_; i++) {
     695           3 :         if(dynamic_targetdists_[i]) {
     696           3 :           bias_pntrs_[i]->enableDynamicTargetDistFileOutput();
     697           3 :           bias_pntrs_[i]->setupTargetDistProjFileOutput();
     698           3 :           bias_pntrs_[i]->writeTargetDistProjToFile();
     699             :         }
     700             :       }
     701             :     } else {
     702          75 :       targetdist_proj_output_active_=false;
     703          75 :       targetdist_proj_output_stride_=1000;
     704             :     }
     705             :   }
     706             : 
     707          79 :   if(ncoeffssets_==1) {
     708          76 :     log.printf("  Output Components:\n");
     709          76 :     log.printf(" ");
     710          76 :     if(monitor_instantaneous_gradient_) {
     711           6 :       addComponent("gradrms");
     712           3 :       componentIsNotPeriodic("gradrms");
     713           3 :       log.printf(" ");
     714           6 :       addComponent("gradmax");
     715           6 :       componentIsNotPeriodic("gradmax");
     716             :     }
     717          76 :     if(aver_gradient_pntrs_.size()>0) {
     718           2 :       log.printf(" ");
     719           4 :       addComponent("avergradrms");
     720           2 :       componentIsNotPeriodic("avergradrms");
     721           2 :       log.printf(" ");
     722           4 :       addComponent("avergradmax");
     723           4 :       componentIsNotPeriodic("avergradmax");
     724             :     }
     725          76 :     if(!fixed_stepsize_) {
     726           1 :       log.printf(" ");
     727           2 :       addComponent("stepsize");
     728           1 :       componentIsNotPeriodic("stepsize");
     729           2 :       getPntrToComponent("stepsize")->set( getCurrentStepSize(0) );
     730             :     }
     731             :   } else {
     732          12 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
     733           9 :       log.printf("  Output Components for coefficient set %u:\n",i);
     734           9 :       std::string is="";
     735           9 :       Tools::convert(i,is);
     736          18 :       is = "-" + coeffssetid_prefix_ + is;
     737           9 :       log.printf(" ");
     738           9 :       if(monitor_instantaneous_gradient_) {
     739           6 :         addComponent("gradrms"+is);
     740           3 :         componentIsNotPeriodic("gradrms"+is);
     741           3 :         log.printf(" ");
     742           6 :         addComponent("gradmax"+is);
     743           6 :         componentIsNotPeriodic("gradmax"+is);
     744             :       }
     745           9 :       if(aver_gradient_pntrs_.size()>0) {
     746           0 :         log.printf(" ");
     747           0 :         addComponent("avergradrms"+is);
     748           0 :         componentIsNotPeriodic("avergradrms"+is);
     749           0 :         log.printf(" ");
     750           0 :         addComponent("avergradmax"+is);
     751           0 :         componentIsNotPeriodic("avergradmax"+is);
     752             :       }
     753           9 :       if(!fixed_stepsize_) {
     754           0 :         log.printf(" ");
     755           0 :         addComponent("stepsize"+is);
     756           0 :         componentIsNotPeriodic("stepsize"+is);
     757           0 :         getPntrToComponent("stepsize"+is)->set( getCurrentStepSize(i) );
     758             :       }
     759             :     }
     760             :   }
     761             : 
     762         158 : }
     763             : 
     764             : 
     765          79 : Optimizer::~Optimizer() {
     766             :   //
     767         164 :   for(unsigned int i=0; i<ncoeffssets_; i++) {
     768          85 :     if(coeffsOFiles_.size()>0 && getIterationCounter()%coeffs_wstride_!=0) {
     769           2 :       coeffs_pntrs_[i]->writeToFile(*coeffsOFiles_[i],aux_coeffs_pntrs_[i].get(),false);
     770             :     }
     771          85 :     if(targetdist_averagesOFiles_.size()>0 && iter_counter%targetdist_averages_wstride_!=0) {
     772           1 :       targetdist_averages_pntrs_[i]->writeToFile(*targetdist_averagesOFiles_[i]);
     773             :     }
     774             :   }
     775             :   //
     776          79 :   if(!isTargetDistOutputActive()) {
     777          90 :     for(unsigned int i=0; i<nbiases_; i++) {
     778          48 :       if(dynamic_targetdists_[i]) {
     779           1 :         bias_pntrs_[i]->enableDynamicTargetDistFileOutput();
     780           1 :         bias_pntrs_[i]->setupTargetDistFileOutput();
     781           1 :         bias_pntrs_[i]->writeTargetDistToFile();
     782             :       }
     783             :     }
     784             :   }
     785             :   //
     786          79 :   if(isBiasOutputActive() && getIterationCounter()%getBiasOutputStride()!=0) {
     787           1 :     writeBiasOutputFiles();
     788             :   }
     789          79 :   if(isFesOutputActive() && getIterationCounter()%getFesOutputStride()!=0) {
     790           1 :     writeFesOutputFiles();
     791             :   }
     792          79 :   if(isFesProjOutputActive() && getIterationCounter()%getFesProjOutputStride()!=0) {
     793           1 :     writeFesProjOutputFiles();
     794             :   }
     795          79 :   if(isTargetDistOutputActive() && getIterationCounter()%getTargetDistOutputStride()!=0) {
     796           2 :     writeTargetDistOutputFiles();
     797             :   }
     798          79 :   if(isTargetDistProjOutputActive() && getIterationCounter()%getTargetDistProjOutputStride()!=0) {
     799           1 :     writeTargetDistProjOutputFiles();
     800             :   }
     801         395 : }
     802             : 
     803             : 
     804          87 : void Optimizer::registerKeywords( Keywords& keys ) {
     805          87 :   Action::registerKeywords(keys);
     806          87 :   ActionPilot::registerKeywords(keys);
     807          87 :   ActionWithValue::registerKeywords(keys);
     808             :   //
     809         174 :   keys.remove("NUMERICAL_DERIVATIVES");
     810             :   // Default always active keywords
     811          87 :   keys.add("compulsory","BIAS","the label of the VES bias to be optimized");
     812          87 :   keys.add("compulsory","STRIDE","the frequency of updating the coefficients given in the number of MD steps.");
     813          87 :   keys.add("compulsory","COEFFS_FILE","coeffs.data","the name of output file for the coefficients");
     814          87 :   keys.add("compulsory","COEFFS_OUTPUT","100","how often the coefficients should be written to file. This parameter is given as the number of iterations.");
     815          87 :   keys.add("optional","COEFFS_FMT","specify format for coefficient file(s) (useful for decrease the number of digits in regtests)");
     816          87 :   keys.add("optional","COEFFS_SET_ID_PREFIX","suffix to add to the filename given in FILE to identify the bias, should only be given if a single filename is given in FILE when optimizing multiple biases.");
     817             :   //
     818          87 :   keys.add("optional","INITIAL_COEFFS","the name(s) of file(s) with the initial coefficients");
     819             :   // Hidden keywords to output the gradient to a file.
     820          87 :   keys.add("hidden","GRADIENT_FILE","the name of output file for the gradient");
     821          87 :   keys.add("hidden","GRADIENT_OUTPUT","how often the gradient should be written to file. This parameter is given as the number of bias iterations. It is by default 100 if GRADIENT_FILE is specficed");
     822          87 :   keys.add("hidden","GRADIENT_FMT","specify format for gradient file(s) (useful for decrease the number of digits in regtests)");
     823             :   // Either use a fixed stepsize (useFixedStepSizeKeywords) or changing stepsize (useDynamicsStepSizeKeywords)
     824          87 :   keys.reserve("compulsory","STEPSIZE","the step size used for the optimization");
     825          87 :   keys.reserve("compulsory","INITIAL_STEPSIZE","the initial step size used for the optimization");
     826             :   // Keywords related to the Hessian, actived with the useHessianKeywords function
     827         174 :   keys.reserveFlag("FULL_HESSIAN",false,"if the full Hessian matrix should be used for the optimization, otherwise only the diagonal part of the Hessian is used");
     828          87 :   keys.reserve("hidden","HESSIAN_FILE","the name of output file for the Hessian");
     829          87 :   keys.reserve("hidden","HESSIAN_OUTPUT","how often the Hessian should be written to file. This parameter is given as the number of bias iterations. It is by default 100 if HESSIAN_FILE is specficed");
     830          87 :   keys.reserve("hidden","HESSIAN_FMT","specify format for hessian file(s) (useful for decrease the number of digits in regtests)");
     831             :   // Keywords related to the multiple walkers, actived with the useMultipleWalkersKeywords function
     832         174 :   keys.reserveFlag("MULTIPLE_WALKERS",false,"if optimization is to be performed using multiple walkers connected via MPI");
     833             :   // Keywords related to the mask file, actived with the useMaskKeywords function
     834          87 :   keys.reserve("optional","MASK_FILE","read in a mask file which allows one to employ different step sizes for different coefficients and/or deactivate the optimization of certain coefficients (by putting values of 0.0). One can write out the resulting mask by using the OUTPUT_MASK_FILE keyword.");
     835          87 :   keys.reserve("optional","OUTPUT_MASK_FILE","Name of the file to write out the mask resulting from using the MASK_FILE keyword. Can also be used to generate a template mask file.");
     836             :   //
     837         174 :   keys.reserveFlag("START_OPTIMIZATION_AFRESH",false,"if the iterations should be started afresh when a restart has been triggered by the RESTART keyword or the MD code.");
     838             :   //
     839          87 :   keys.addFlag("MONITOR_INSTANTANEOUS_GRADIENT",false,"if quantities related to the instantaneous gradient should be outputted.");
     840             :   //
     841         174 :   keys.reserveFlag("MONITOR_AVERAGE_GRADIENT",false,"if the averaged gradient should be monitored and quantities related to it should be outputted.");
     842          87 :   keys.reserve("optional","MONITOR_AVERAGES_GRADIENT_EXP_DECAY","use an exponentially decaying averaging with a given time constant when monitoring the averaged gradient");
     843             :   //
     844          87 :   keys.reserve("optional","TARGETDIST_STRIDE","stride for updating a target distribution that is iteratively updated during the optimization. Note that the value is given in terms of coefficient iterations.");
     845          87 :   keys.reserve("optional","TARGETDIST_OUTPUT","how often the dynamic target distribution(s) should be written out to file. Note that the value is given in terms of coefficient iterations.");
     846          87 :   keys.reserve("optional","TARGETDIST_PROJ_OUTPUT","how often the projections of the dynamic target distribution(s) should be written out to file. Note that the value is given in terms of coefficient iterations.");
     847             :   //
     848          87 :   keys.add("optional","TARGETDIST_AVERAGES_FILE","the name of output file for the target distribution averages. By default it is targetdist-averages.data.");
     849          87 :   keys.add("optional","TARGETDIST_AVERAGES_OUTPUT","how often the target distribution averages should be written out to file. Note that the value is given in terms of coefficient iterations. If no value is given are the averages only written at the beginning of the optimization");
     850          87 :   keys.add("hidden","TARGETDIST_AVERAGES_FMT","specify format for target distribution averages file(s) (useful for decrease the number of digits in regtests)");
     851             :   //
     852          87 :   keys.add("optional","BIAS_OUTPUT","how often the bias(es) should be written out to file. Note that the value is given in terms of coefficient iterations.");
     853          87 :   keys.add("optional","FES_OUTPUT","how often the FES(s) should be written out to file. Note that the value is given in terms of coefficient iterations.");
     854          87 :   keys.add("optional","FES_PROJ_OUTPUT","how often the projections of the FES(s) should be written out to file. Note that the value is given in terms of coefficient iterations.");
     855             :   //
     856          87 :   keys.reserve("optional","REWEIGHT_FACTOR_STRIDE","stride for updating the reweighting factor c(t). Note that the value is given in terms of coefficient iterations.");
     857             :   //
     858          87 :   keys.use("RESTART");
     859             :   //
     860          87 :   keys.use("UPDATE_FROM");
     861          87 :   keys.use("UPDATE_UNTIL");
     862             :   // Components that are always active
     863         174 :   keys.addOutputComponent("gradrms","MONITOR_INSTANTANEOUS_GRADIENT","scalar","the root mean square value of the coefficient gradient. For multiple biases this component is labeled using the number of the bias as gradrms-#.");
     864         174 :   keys.addOutputComponent("gradmax","MONITOR_INSTANTANEOUS_GRADIENT","scalar","the largest absolute value of the coefficient gradient. For multiple biases this component is labeled using the number of the bias as gradmax-#.");
     865             :   // keys.addOutputComponent("gradmaxidx","default","the index of the maximum absolute value of the gradient");
     866         174 :   keys.setValueDescription("scalar","a scalar");
     867          87 : }
     868             : 
     869             : 
     870          80 : void Optimizer::useHessianKeywords(Keywords& keys) {
     871             :   // keys.use("FULL_HESSIAN");
     872          80 :   keys.use("HESSIAN_FILE");
     873          80 :   keys.use("HESSIAN_OUTPUT");
     874          80 :   keys.use("HESSIAN_FMT");
     875          80 : }
     876             : 
     877             : 
     878          87 : void Optimizer::useMultipleWalkersKeywords(Keywords& keys) {
     879          87 :   keys.use("MULTIPLE_WALKERS");
     880          87 : }
     881             : 
     882             : 
     883          81 : void Optimizer::useFixedStepSizeKeywords(Keywords& keys) {
     884          81 :   keys.use("STEPSIZE");
     885          81 : }
     886             : 
     887             : 
     888           3 : void Optimizer::useDynamicStepSizeKeywords(Keywords& keys) {
     889           3 :   keys.use("INITIAL_STEPSIZE");
     890           6 :   keys.addOutputComponent("stepsize","default","scalar","the current value of step size used to update the coefficients. For multiple biases this component is labeled using the number of the bias as stepsize-#.");
     891           3 : }
     892             : 
     893             : 
     894          84 : void Optimizer::useMaskKeywords(Keywords& keys) {
     895          84 :   keys.use("MASK_FILE");
     896          84 :   keys.use("OUTPUT_MASK_FILE");
     897          84 : }
     898             : 
     899             : 
     900          80 : void Optimizer::useRestartKeywords(Keywords& keys) {
     901          80 :   keys.use("START_OPTIMIZATION_AFRESH");
     902          80 : }
     903             : 
     904             : 
     905          80 : void Optimizer::useMonitorAverageGradientKeywords(Keywords& keys) {
     906          80 :   keys.use("MONITOR_AVERAGE_GRADIENT");
     907          80 :   keys.use("MONITOR_AVERAGES_GRADIENT_EXP_DECAY");
     908         160 :   keys.addOutputComponent("avergradrms","MONITOR_AVERAGE_GRADIENT","scalar","the root mean square value of the averaged coefficient gradient. For multiple biases this component is labeled using the number of the bias as gradrms-#.");
     909         160 :   keys.addOutputComponent("avergradmax","MONITOR_AVERAGE_GRADIENT","scalar","the largest absolute value of the averaged coefficient gradient. For multiple biases this component is labeled using the number of the bias as gradmax-#.");
     910          80 : }
     911             : 
     912             : 
     913          84 : void Optimizer::useDynamicTargetDistributionKeywords(Keywords& keys) {
     914          84 :   keys.use("TARGETDIST_STRIDE");
     915          84 :   keys.use("TARGETDIST_OUTPUT");
     916          84 :   keys.use("TARGETDIST_PROJ_OUTPUT");
     917          84 : }
     918             : 
     919             : 
     920           0 : void Optimizer::useReweightFactorKeywords(Keywords& keys) {
     921           0 :   keys.use("REWEIGHT_FACTOR_STRIDE");
     922           0 : }
     923             : 
     924             : 
     925          76 : void Optimizer::turnOnHessian() {
     926          76 :   plumed_massert(hessian_pntrs_.size()==0,"turnOnHessian() should only be run during initialization");
     927          76 :   use_hessian_=true;
     928          76 :   hessian_pntrs_.clear();
     929         158 :   for(unsigned int i=0; i<nbiases_; i++) {
     930          82 :     std::vector<CoeffsMatrix*> pntrs_hessian = enableHessian(bias_pntrs_[i],diagonal_hessian_);
     931         164 :     for(unsigned int k=0; k<pntrs_hessian.size(); k++) {
     932          82 :       pntrs_hessian[k]->turnOnIterationCounter();
     933          82 :       pntrs_hessian[k]->setIterationCounterAndTime(getIterationCounter(),getTime());
     934          82 :       hessian_pntrs_.push_back(pntrs_hessian[k]);
     935             :     }
     936             :   }
     937          76 :   plumed_massert(hessian_pntrs_.size()==ncoeffssets_,"problems in linking Hessians");
     938          76 :   if(diagonal_hessian_) {
     939          76 :     log.printf("  Optimization performed using diagonal Hessian matrix\n");
     940             :   } else {
     941           0 :     log.printf("  Optimization performed using full Hessian matrix\n");
     942             :   }
     943             :   //
     944          76 :   if(hessian_output_fmt_.size()>0) {
     945         128 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
     946          66 :       hessian_pntrs_[i]->setOutputFmt(hessian_output_fmt_);
     947             :     }
     948             :   }
     949             : 
     950          76 : }
     951             : 
     952             : 
     953           0 : void Optimizer::turnOffHessian() {
     954           0 :   use_hessian_=false;
     955           0 :   for(unsigned int i=0; i<nbiases_; i++) {
     956           0 :     bias_pntrs_[i]->disableHessian();
     957             :   }
     958             :   hessian_pntrs_.clear();
     959           0 :   hessianOFiles_.clear();
     960           0 : }
     961             : 
     962             : 
     963          82 : std::vector<CoeffsMatrix*> Optimizer::enableHessian(VesBias* bias_pntr_in, const bool diagonal_hessian) {
     964          82 :   plumed_massert(use_hessian_,"the Hessian should not be used");
     965          82 :   bias_pntr_in->enableHessian(diagonal_hessian);
     966             :   std::vector<CoeffsMatrix*> hessian_pntrs_out = bias_pntr_in->getHessianPntrs();
     967         164 :   for(unsigned int k=0; k<hessian_pntrs_out.size(); k++) {
     968          82 :     plumed_massert(hessian_pntrs_out[k] != NULL,"Hessian is needed but not linked correctly");
     969             :   }
     970          82 :   return hessian_pntrs_out;
     971             : }
     972             : 
     973             : 
     974             : // CoeffsMatrix* Optimizer::switchToDiagonalHessian(VesBias* bias_pntr_in) {
     975             : //   plumed_massert(use_hessian_,"it does not make sense to switch to diagonal Hessian if it Hessian is not used");
     976             : //   diagonal_hessian_=true;
     977             : //   bias_pntr_in->enableHessian(diagonal_hessian_);
     978             : //   CoeffsMatrix* hessian_pntr_out = bias_pntr_in->getHessianPntr();
     979             : //   plumed_massert(hessian_pntr_out != NULL,"Hessian is needed but not linked correctly");
     980             : //   //
     981             : //   log.printf("  %s (with label %s): switching to a diagonal Hessian for VES bias %s (with label %s) at time  %f\n",getName().c_str(),getLabel().c_str(),bias_pntr_in->getName().c_str(),bias_pntr_in->getLabel().c_str(),getTime());
     982             : //   return hessian_pntr_out;
     983             : // }
     984             : 
     985             : 
     986             : // CoeffsMatrix* Optimizer::switchToFullHessian(VesBias* bias_pntr_in) {
     987             : //   plumed_massert(use_hessian_,"it does not make sense to switch to diagonal Hessian if it Hessian is not used");
     988             : //   diagonal_hessian_=false;
     989             : //   bias_pntr_in->enableHessian(diagonal_hessian_);
     990             : //   CoeffsMatrix* hessian_pntr_out = bias_pntr_in->getHessianPntr();
     991             : //   plumed_massert(hessian_pntr_out != NULL,"Hessian is needed but not linked correctly");
     992             : //   //
     993             : //   log.printf("  %s (with label %s): switching to a diagonal Hessian for VES bias %s (with label %s) at time  %f\n",getName().c_str(),getLabel().c_str(),bias_pntr_in->getName().c_str(),bias_pntr_in->getLabel().c_str(),getTime());
     994             : //   return hessian_pntr_out;
     995             : // }
     996             : 
     997             : 
     998       22879 : void Optimizer::update() {
     999       22879 :   if(onStep() && !isFirstStep) {
    1000       45560 :     for(unsigned int i=0; i<nbiases_; i++) {
    1001       22810 :       bias_pntrs_[i]->updateGradientAndHessian(use_mwalkers_mpi_);
    1002             :     }
    1003       45560 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
    1004       22810 :       if(gradient_pntrs_[i]->isActive()) {
    1005       22715 :         coeffsUpdate(i);
    1006             :       } else {
    1007         190 :         std::string msg = "iteration " + getIterationCounterStr(+1) +
    1008         285 :                           " for " + bias_pntrs_[i]->getLabel() +
    1009          95 :                           " - the coefficients are not updated as CV values are outside the bias intervals";
    1010          95 :         warning(msg);
    1011             :       }
    1012             : 
    1013             :       // +1 as this is done before increaseIterationCounter() is used
    1014       22810 :       unsigned int curr_iter = getIterationCounter()+1;
    1015       22810 :       double curr_time = getTime();
    1016       22810 :       coeffs_pntrs_[i]->setIterationCounterAndTime(curr_iter,curr_time);
    1017             :       aux_coeffs_pntrs_[i]->setIterationCounterAndTime(curr_iter,curr_time);
    1018       22810 :       gradient_pntrs_[i]->setIterationCounterAndTime(curr_iter,curr_time);
    1019       22810 :       targetdist_averages_pntrs_[i]->setIterationCounterAndTime(curr_iter,curr_time);
    1020       22810 :       if(use_hessian_) {
    1021       22780 :         hessian_pntrs_[i]->setIterationCounterAndTime(curr_iter,curr_time);
    1022             :       }
    1023       22810 :       if(aver_gradient_pntrs_.size()>0) {
    1024             :         aver_gradient_pntrs_[i]->setIterationCounterAndTime(curr_iter,curr_time);
    1025          20 :         aver_gradient_pntrs_[i]->addToAverage(*gradient_pntrs_[i]);
    1026             :       }
    1027             :     }
    1028             :     increaseIterationCounter();
    1029             : 
    1030       22750 :     if(ustride_targetdist_>0 && getIterationCounter()%ustride_targetdist_==0) {
    1031         708 :       for(unsigned int i=0; i<nbiases_; i++) {
    1032         354 :         if(dynamic_targetdists_[i]) {
    1033         354 :           bias_pntrs_[i]->updateTargetDistributions();
    1034             :         }
    1035             :       }
    1036             :     }
    1037       22750 :     if(ustride_reweightfactor_>0 && getIterationCounter()%ustride_reweightfactor_==0) {
    1038           0 :       for(unsigned int i=0; i<nbiases_; i++) {
    1039           0 :         bias_pntrs_[i]->updateReweightFactor();
    1040             :       }
    1041             :     }
    1042             : 
    1043       22750 :     updateOutputComponents();
    1044       45560 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
    1045       22810 :       writeOutputFiles(i);
    1046             :     }
    1047             :     //
    1048       22750 :     if(isBiasOutputActive() && getIterationCounter()%getBiasOutputStride()==0) {
    1049          74 :       writeBiasOutputFiles();
    1050             :     }
    1051       22750 :     if(isFesOutputActive() && getIterationCounter()%getFesOutputStride()==0) {
    1052          74 :       writeFesOutputFiles();
    1053             :     }
    1054       22750 :     if(isFesProjOutputActive() && getIterationCounter()%getFesProjOutputStride()==0) {
    1055          16 :       writeFesProjOutputFiles();
    1056             :     }
    1057       22750 :     if(isTargetDistOutputActive() && getIterationCounter()%getTargetDistOutputStride()==0) {
    1058          36 :       writeTargetDistOutputFiles();
    1059             :     }
    1060       22750 :     if(isTargetDistProjOutputActive() && getIterationCounter()%getTargetDistProjOutputStride()==0) {
    1061           3 :       writeTargetDistProjOutputFiles();
    1062             :     }
    1063             :   } else {
    1064         129 :     isFirstStep=false;
    1065             :   }
    1066       22879 : }
    1067             : 
    1068             : 
    1069       22750 : void Optimizer::updateOutputComponents() {
    1070       22750 :   if(ncoeffssets_==1) {
    1071       22720 :     if(!fixed_stepsize_) {
    1072          20 :       getPntrToComponent("stepsize")->set( getCurrentStepSize(0) );
    1073             :     }
    1074       22720 :     if(monitor_instantaneous_gradient_) {
    1075          30 :       getPntrToComponent("gradrms")->set( gradient_pntrs_[0]->getRMS() );
    1076          30 :       size_t gradient_maxabs_idx=0;
    1077          60 :       getPntrToComponent("gradmax")->set( gradient_pntrs_[0]->getMaxAbsValue(gradient_maxabs_idx) );
    1078             :     }
    1079       22720 :     if(aver_gradient_pntrs_.size()>0) {
    1080          20 :       getPntrToComponent("avergradrms")->set( aver_gradient_pntrs_[0]->getRMS() );
    1081          20 :       size_t avergradient_maxabs_idx=0;
    1082          40 :       getPntrToComponent("avergradmax")->set( aver_gradient_pntrs_[0]->getMaxAbsValue(avergradient_maxabs_idx) );
    1083             :     }
    1084             :   } else {
    1085         120 :     for(unsigned int i=0; i<ncoeffssets_; i++) {
    1086          90 :       std::string is="";
    1087          90 :       Tools::convert(i,is);
    1088         180 :       is = "-" + coeffssetid_prefix_ + is;
    1089          90 :       if(!fixed_stepsize_) {
    1090           0 :         getPntrToComponent("stepsize"+is)->set( getCurrentStepSize(i) );
    1091             :       }
    1092          90 :       if(monitor_instantaneous_gradient_) {
    1093          30 :         getPntrToComponent("gradrms"+is)->set( gradient_pntrs_[i]->getRMS() );
    1094          30 :         size_t gradient_maxabs_idx=0;
    1095          60 :         getPntrToComponent("gradmax"+is)->set( gradient_pntrs_[i]->getMaxAbsValue(gradient_maxabs_idx) );
    1096             :       }
    1097          90 :       if(aver_gradient_pntrs_.size()>0) {
    1098           0 :         getPntrToComponent("avergradrms"+is)->set( aver_gradient_pntrs_[0]->getRMS() );
    1099           0 :         size_t avergradient_maxabs_idx=0;
    1100           0 :         getPntrToComponent("avergradmax"+is)->set( aver_gradient_pntrs_[0]->getMaxAbsValue(avergradient_maxabs_idx) );
    1101             :       }
    1102             :     }
    1103             :   }
    1104       22750 : }
    1105             : 
    1106             : 
    1107           1 : void Optimizer::turnOffCoeffsOutputFiles() {
    1108           1 :   coeffsOFiles_.clear();
    1109           1 : }
    1110             : 
    1111             : 
    1112       22810 : void Optimizer::writeOutputFiles(const unsigned int coeffs_id) {
    1113       22810 :   if(coeffsOFiles_.size()>0 && iter_counter%coeffs_wstride_==0) {
    1114         789 :     coeffs_pntrs_[coeffs_id]->writeToFile(*coeffsOFiles_[coeffs_id],aux_coeffs_pntrs_[coeffs_id].get(),false);
    1115             :   }
    1116       22810 :   if(gradientOFiles_.size()>0 && iter_counter%gradient_wstride_==0) {
    1117         720 :     if(aver_gradient_pntrs_.size()==0) {
    1118         700 :       gradient_pntrs_[coeffs_id]->writeToFile(*gradientOFiles_[coeffs_id],false);
    1119             :     } else {
    1120          20 :       gradient_pntrs_[coeffs_id]->writeToFile(*gradientOFiles_[coeffs_id],aver_gradient_pntrs_[coeffs_id].get(),false);
    1121             :     }
    1122             :   }
    1123       22810 :   if(hessianOFiles_.size()>0 && iter_counter%hessian_wstride_==0) {
    1124         660 :     hessian_pntrs_[coeffs_id]->writeToFile(*hessianOFiles_[coeffs_id]);
    1125             :   }
    1126       22810 :   if(targetdist_averagesOFiles_.size()>0 && iter_counter%targetdist_averages_wstride_==0) {
    1127         333 :     targetdist_averages_pntrs_[coeffs_id]->writeToFile(*targetdist_averagesOFiles_[coeffs_id]);
    1128             :   }
    1129       22810 : }
    1130             : 
    1131             : 
    1132         388 : void Optimizer::setupOFiles(std::vector<std::string>& fnames, std::vector<std::unique_ptr<OFile>>& OFiles, const bool multi_sim_single_files) {
    1133         388 :   plumed_assert(ncoeffssets_>0);
    1134         388 :   OFiles.resize(fnames.size());
    1135         702 :   for(unsigned int i=0; i<fnames.size(); i++) {
    1136         314 :     OFiles[i] = Tools::make_unique<OFile>();
    1137         314 :     OFiles[i]->link(*this);
    1138         314 :     if(multi_sim_single_files) {
    1139          48 :       unsigned int r=0;
    1140          48 :       if(comm.Get_rank()==0) {
    1141          48 :         r=multi_sim_comm.Get_rank();
    1142             :       }
    1143          48 :       comm.Bcast(r,0);
    1144          48 :       if(r>0) {
    1145             :         fnames[i]="/dev/null";
    1146             :       }
    1147          96 :       OFiles[i]->enforceSuffix("");
    1148             :     }
    1149         314 :     OFiles[i]->open(fnames[i]);
    1150         314 :     OFiles[i]->setHeavyFlush();
    1151             :   }
    1152         388 : }
    1153             : 
    1154             : 
    1155          14 : void Optimizer::readCoeffsFromFiles(const std::vector<std::string>& fnames, const bool read_aux_coeffs) {
    1156          14 :   plumed_assert(ncoeffssets_>0);
    1157          14 :   plumed_assert(fnames.size()==ncoeffssets_);
    1158          14 :   if(ncoeffssets_==1) {
    1159          13 :     log.printf("  Read in coefficients from file ");
    1160             :   } else {
    1161           1 :     log.printf("  Read in coefficients from files:\n");
    1162             :   }
    1163          30 :   for(unsigned int i=0; i<ncoeffssets_; i++) {
    1164          16 :     IFile ifile;
    1165          16 :     ifile.link(*this);
    1166          16 :     if(use_mwalkers_mpi_ && mwalkers_mpi_single_files_) {
    1167           8 :       ifile.enforceSuffix("");
    1168             :     }
    1169          16 :     ifile.open(fnames[i]);
    1170          32 :     if(!ifile.FieldExist(coeffs_pntrs_[i]->getDataLabel())) {
    1171           0 :       std::string error_msg = "Problem with reading coefficients from file " + ifile.getPath() + ": no field with name " + coeffs_pntrs_[i]->getDataLabel() + "\n";
    1172           0 :       plumed_merror(error_msg);
    1173             :     }
    1174          16 :     size_t ncoeffs_read = coeffs_pntrs_[i]->readFromFile(ifile,false,false);
    1175          16 :     if(ncoeffssets_==1) {
    1176          26 :       log.printf("%s (read %zu of %zu values)\n", ifile.getPath().c_str(),ncoeffs_read,coeffs_pntrs_[i]->numberOfCoeffs());
    1177             :     } else {
    1178           6 :       log.printf("   coefficient set %u: %s (read %zu of %zu values)\n",i,ifile.getPath().c_str(),ncoeffs_read,coeffs_pntrs_[i]->numberOfCoeffs());
    1179             :     }
    1180          16 :     ifile.close();
    1181          16 :     if(read_aux_coeffs) {
    1182          15 :       ifile.open(fnames[i]);
    1183          30 :       if(!ifile.FieldExist(aux_coeffs_pntrs_[i]->getDataLabel())) {
    1184           0 :         std::string error_msg = "Problem with reading coefficients from file " + ifile.getPath() + ": no field with name " + aux_coeffs_pntrs_[i]->getDataLabel() + "\n";
    1185           0 :         plumed_merror(error_msg);
    1186             :       }
    1187          15 :       aux_coeffs_pntrs_[i]->readFromFile(ifile,false,false);
    1188          15 :       ifile.close();
    1189             :     } else {
    1190           1 :       AuxCoeffs(i).setValues( Coeffs(i) );
    1191             :     }
    1192          16 :   }
    1193          14 : }
    1194             : 
    1195             : 
    1196          85 : void Optimizer::addCoeffsSetIDsToFilenames(std::vector<std::string>& fnames, std::string& coeffssetid_prefix) {
    1197          85 :   if(ncoeffssets_==1) {
    1198             :     return;
    1199             :   }
    1200             :   //
    1201           9 :   if(fnames.size()==1) {
    1202           0 :     fnames.resize(ncoeffssets_,fnames[0]);
    1203             :   }
    1204           9 :   plumed_assert(fnames.size()==ncoeffssets_);
    1205             :   //
    1206          36 :   for(unsigned int i=0; i<ncoeffssets_; i++) {
    1207          27 :     std::string is="";
    1208          27 :     Tools::convert(i,is);
    1209          54 :     fnames[i] = FileBase::appendSuffix(fnames[i],"."+coeffssetid_prefix_+is);
    1210             :   }
    1211             : }
    1212             : 
    1213             : 
    1214          93 : void Optimizer::setAllCoeffsSetIterationCounters() {
    1215         194 :   for(unsigned int i=0; i<ncoeffssets_; i++) {
    1216         101 :     coeffs_pntrs_[i]->setIterationCounterAndTime(getIterationCounter(),getTime());
    1217         101 :     aux_coeffs_pntrs_[i]->setIterationCounterAndTime(getIterationCounter(),getTime());
    1218         101 :     gradient_pntrs_[i]->setIterationCounterAndTime(getIterationCounter(),getTime());
    1219         101 :     targetdist_averages_pntrs_[i]->setIterationCounterAndTime(getIterationCounter(),getTime());
    1220         101 :     if(use_hessian_) {
    1221           0 :       hessian_pntrs_[i]->setIterationCounterAndTime(getIterationCounter(),getTime());
    1222             :     }
    1223             :   }
    1224          93 : }
    1225             : 
    1226             : 
    1227          95 : std::string Optimizer::getIterationCounterStr(const int offset) const {
    1228             :   std::string s;
    1229          95 :   Tools::convert(getIterationCounter()+offset,s);
    1230          95 :   return s;
    1231             : }
    1232             : 
    1233             : 
    1234          75 : void Optimizer::writeBiasOutputFiles() const {
    1235         156 :   for(unsigned int i=0; i<nbiases_; i++) {
    1236          81 :     bias_pntrs_[i]->writeBiasToFile();
    1237             :   }
    1238          75 : }
    1239             : 
    1240             : 
    1241          75 : void Optimizer::writeFesOutputFiles() const {
    1242         156 :   for(unsigned int i=0; i<nbiases_; i++) {
    1243          81 :     bias_pntrs_[i]->writeFesToFile();
    1244             :   }
    1245          75 : }
    1246             : 
    1247             : 
    1248          17 : void Optimizer::writeFesProjOutputFiles() const {
    1249          34 :   for(unsigned int i=0; i<nbiases_; i++) {
    1250          17 :     bias_pntrs_[i]->writeFesProjToFile();
    1251             :   }
    1252          17 : }
    1253             : 
    1254             : 
    1255          38 : void Optimizer::writeTargetDistOutputFiles() const {
    1256          76 :   for(unsigned int i=0; i<nbiases_; i++) {
    1257          38 :     if(dynamic_targetdists_[i]) {
    1258          38 :       bias_pntrs_[i]->writeTargetDistToFile();
    1259             :     }
    1260             :   }
    1261          38 : }
    1262             : 
    1263             : 
    1264           4 : void Optimizer::writeTargetDistProjOutputFiles() const {
    1265           8 :   for(unsigned int i=0; i<nbiases_; i++) {
    1266           4 :     if(dynamic_targetdists_[i]) {
    1267           4 :       bias_pntrs_[i]->writeTargetDistProjToFile();
    1268             :     }
    1269             :   }
    1270           4 : }
    1271             : 
    1272             : 
    1273             : 
    1274             : }
    1275             : }

Generated by: LCOV version 1.16