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

Generated by: LCOV version 1.16