LCOV - code coverage report
Current view: top level - ves - Optimizer.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 650 752 86.4 %
Date: 2020-11-18 11:20:57 Functions: 28 34 82.4 %

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

Generated by: LCOV version 1.13