QMCPACK
QMCFixedSampleLinearOptimizeBatched.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2020 QMCPACK developers.
6 //
7 // File developed by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
9 // Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
10 // Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
11 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
12 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
13 // Mark Dewing, mdewing@anl.gov, Argonne National Laboratory
14 //
15 // File created by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
16 //////////////////////////////////////////////////////////////////////////////////////
17 
18 
20 #include "Particle/HDFWalkerIO.h"
21 #include "OhmmsData/AttributeSet.h"
22 #include "Message/CommOperators.h"
28 #include "Concurrency/Info.hpp"
29 #include "CPU/Blasf.h"
33 #include <cassert>
34 #ifdef HAVE_LMY_ENGINE
35 #include "formic/utils/matrix.h"
36 #include "formic/utils/random.h"
37 #include "formic/utils/lmyengine/var_dependencies.h"
38 #endif
39 #include <iostream>
40 #include <fstream>
41 #include <stdexcept>
42 
43 
44 namespace qmcplusplus
45 {
47 
48 
50  const ProjectData& project_data,
51  QMCDriverInput&& qmcdriver_input,
52  const std::optional<EstimatorManagerInput>& global_emi,
53  VMCDriverInput&& vmcdriver_input,
55  MCPopulation&& population,
56  SampleStack& samples,
58  : QMCDriverNew(
59  project_data,
60  std::move(qmcdriver_input),
61  std::
62  nullopt, // this class is not a real QMCDriverNew as far as I can tell so we don't give it the actual global_emi_
63  wc,
64  std::move(population),
65  "QMCLinearOptimizeBatched::",
66  comm,
67  "QMCLinearOptimizeBatched"),
68  objFuncWrapper_(*this),
69 #ifdef HAVE_LMY_ENGINE
70  vdeps(1, std::vector<double>()),
71 #endif
72  Max_iterations(1),
73  param_tol(1e-4),
74  nstabilizers(3),
75  stabilizerScale(2.0),
76  bigChange(50),
77  exp0(-16),
78  bestShift_i(-1.0),
79  bestShift_s(-1.0),
80  shift_i_input(0.01),
81  shift_s_input(1.00),
82  accept_history(3),
83  shift_s_base(4.0),
84  MinMethod("OneShiftOnly"),
85  do_output_matrices_csv_(false),
86  do_output_matrices_hdf_(false),
87  output_matrices_initialized_(false),
88  freeze_parameters_(false),
89  initialize_timer_(createGlobalTimer("QMCLinearOptimizeBatched::Initialize", timer_level_medium)),
90  generate_samples_timer_(createGlobalTimer("QMCLinearOptimizeBatched::generateSamples", timer_level_medium)),
91  build_olv_ham_timer_(createGlobalTimer("QMCLinearOptimizedBatched::build_ovl_ham_matrix", timer_level_medium)),
92  invert_olvmat_timer_(createGlobalTimer("QMCLinearOptimizedBatched::invert_ovlMat", timer_level_medium)),
93  eigenvalue_timer_(createGlobalTimer("QMCLinearOptimizeBatched::Eigenvalue", timer_level_medium)),
94  line_min_timer_(createGlobalTimer("QMCLinearOptimizeBatched::Line_Minimization", timer_level_medium)),
95  cost_function_timer_(createGlobalTimer("QMCLinearOptimizeBatched::CostFunction", timer_level_medium)),
96  wfNode(NULL),
97  vmcdriver_input_(vmcdriver_input),
98  samples_(samples),
99  global_emi_(global_emi)
100 {
101  //set the optimization flag
103  //read to use vmc output (just in case)
104  m_param.add(MinMethod, "MinMethod");
105  m_param.add(Max_iterations, "max_its");
106  m_param.add(nstabilizers, "nstabilizers");
107  m_param.add(stabilizerScale, "stabilizerscale");
108  m_param.add(bigChange, "bigchange");
109  m_param.add(exp0, "exp0");
110  m_param.add(param_tol, "alloweddifference");
111  m_param.add(shift_i_input, "shift_i");
112  m_param.add(shift_s_input, "shift_s");
113  // options_LMY_
114  m_param.add(options_LMY_.targetExcited, "options_LMY_.targetExcited");
115  m_param.add(options_LMY_.block_lm, "options_LMY_.block_lm");
116  m_param.add(options_LMY_.nblocks, "options_LMY_.nblocks");
117  m_param.add(options_LMY_.nolds, "options_LMY_.nolds");
118  m_param.add(options_LMY_.nkept, "options_LMY_.nkept");
119  m_param.add(options_LMY_.nsamp_comp, "options_LMY_.nsamp_comp");
121  m_param.add(options_LMY_.max_relative_cost_change, "options_LMY_.max_relative_cost_change");
122  m_param.add(options_LMY_.max_param_change, "options_LMY_.max_param_change");
123  m_param.add(options_LMY_.num_shifts, "options_LMY_.num_shifts");
124  m_param.add(options_LMY_.cost_increase_tol, "options_LMY_.cost_increase_tol");
125  m_param.add(options_LMY_.target_shift_i, "options_LMY_.target_shift_i");
126  m_param.add(options_LMY_.filter_param, "filter_param");
127  m_param.add(options_LMY_.ratio_threshold, "deriv_threshold");
128  m_param.add(options_LMY_.store_samples, "store_samples");
129  m_param.add(options_LMY_.filter_info, "filter_info");
130 
131 
132 #ifdef HAVE_LMY_ENGINE
133  //app_log() << "construct QMCFixedSampleLinearOptimizeBatched" << endl;
134  std::vector<double> shift_scales(3, 1.0);
135  EngineObj = new cqmc::engine::LMYEngine<ValueType>(&vdeps,
136  false, // exact sampling
137  true, // ground state?
138  false, // variance correct,
139  true,
140  true, // print matrices,
141  true, // build matrices
142  false, // spam
143  false, // use var deps?
144  true, // chase lowest
145  false, // chase closest
146  false, // eom
147  false,
148  false, // eom related
149  false, // eom related
150  false, // use block?
151  120000, // number of samples
152  0, // number of parameters
153  60, // max krylov iter
154  0, // max spam inner iter
155  1, // spam appro degree
156  0, // eom related
157  0, // eom related
158  0, // eom related
159  0.0, // omega
160  0.0, // var weight
161  1.0e-6, // convergence threshold
162  0.99, // minimum S singular val
163  0.0, 0.0,
164  10.0, // max change allowed
165  1.00, // identity shift
166  1.00, // overlap shift
167  0.3, // max parameter change
168  shift_scales, app_log());
169 #endif
170 }
171 
172 /** Clean up the vector */
174 {
175 #ifdef HAVE_LMY_ENGINE
176  delete EngineObj;
177 #endif
178 }
179 
181 {
182  for (int i = 0; i < optparam.size(); i++)
183  optTarget->Params(i) = optparam[i] + dl * optdir[i];
185  //only allow this to go false if it was true. If false, stay false
186  // if (validFuncVal)
187  objFuncWrapper_.validFuncVal = optTarget->IsValid;
188  return c;
189 }
190 
192 {
193  generateSamples();
194 
195  optTarget->setWaveFunctionNode(wfNode);
196 
197  {
198  app_log() << std::endl
199  << "*****************************" << std::endl
200  << "Compute parameter derivatives" << std::endl
201  << "*****************************" << std::endl
202  << std::endl;
204  Timer t_deriv;
205  optTarget->getConfigurations("");
206  optTarget->setRng(vmcEngine->getRngRefs());
207  NullEngineHandle handle;
208  optTarget->checkConfigurations(handle);
209  app_log() << " Execution time (derivatives) = " << std::setprecision(4) << t_deriv.elapsed() << std::endl;
210  }
211 }
212 
213 #ifdef HAVE_LMY_ENGINE
214 void QMCFixedSampleLinearOptimizeBatched::engine_start(cqmc::engine::LMYEngine<ValueType>* EngineObj,
215  DescentEngine& descentEngineObj,
216  std::string MinMethod)
217 {
218  app_log() << "entering engine_start function" << std::endl;
219 
220  std::unique_ptr<EngineHandle> handle;
221  if (MinMethod == "descent")
222  handle = std::make_unique<DescentEngineHandle>(descentEngineObj);
223  else if (MinMethod == "adaptive")
224  handle = std::make_unique<LMYEngineHandle>(*EngineObj);
225  else
226  handle = std::make_unique<NullEngineHandle>();
227 
228 
229  // generate samples
231  generateSamples();
233 
234  // store active number of walkers
235  app_log() << "<opt stage=\"setup\">" << std::endl;
236  app_log() << " <log>" << std::endl;
237 
238  // reset the root name
239  optTarget->setRootName(get_root_name());
240  optTarget->setWaveFunctionNode(wfNode);
241  app_log() << " Reading configurations from h5FileRoot " << std::endl;
242 
243  // get configuration from the previous run
244  Timer t1;
246  optTarget->getConfigurations("");
247  optTarget->setRng(vmcEngine->getRngRefs());
248  optTarget->checkConfigurations(*handle);
249 
251  app_log() << " Execution time = " << std::setprecision(4) << t1.elapsed() << std::endl;
252  app_log() << " </log>" << std::endl;
253  app_log() << R"(<opt stage="main" walkers=")" << optTarget->getNumSamples() << "\">" << std::endl;
254 }
255 #endif
256 
257 
259 {
260  if (optTarget->reportH5)
261  optTarget->reportParametersH5();
262  optTarget->reportParameters();
263 }
264 
266 {
268  app_log() << std::endl
269  << "******************" << std::endl
270  << "Generating samples" << std::endl
271  << "******************" << std::endl
272  << std::endl;
274 
275  Timer t_gen;
276  vmcEngine->run();
277  app_log() << " Execution time (sampling) = " << std::setprecision(4) << t_gen.elapsed() << std::endl;
278 
279  //reset the rootname
281  optTarget->setRootName(get_root_name());
282 }
283 
285 {
287  {
288  const int numParams = optTarget->getNumParams();
289  const int N = numParams + 1;
293  }
294 
295  if (doGradientTest)
296  {
297  app_log() << "Doing gradient test run" << std::endl;
298  return test_run();
299  }
300 #ifdef HAVE_LMY_ENGINE
302  {
303  app_log() << "Doing hybrid run" << std::endl;
304  return hybrid_run();
305  }
306 
307  // if requested, perform the update via the adaptive three-shift or single-shift method
309  return adaptive_three_shift_run();
310 
312  return descent_run();
313 
314 #endif
315 
317  return one_shift_run();
318 
320 }
321 
323 {
324  // generate samples and compute weights, local energies, and derivative vectors
325  start();
326 
328 
329  finish();
330 
331  return true;
332 }
333 
335 {
336  start();
337  bool Valid(true);
338  int Total_iterations(0);
339  //size of matrix
340  const int numParams = optTarget->getNumParams();
341  const int N = numParams + 1;
342  // where we are and where we are pointing
343  std::vector<RealType> currentParameterDirections(N, 0);
344  std::vector<RealType> currentParameters(numParams, 0);
345  std::vector<RealType> bestParameters(numParams, 0);
346  for (int i = 0; i < numParams; i++)
347  bestParameters[i] = currentParameters[i] = std::real(optTarget->Params(i));
348  // proposed direction and new parameters
349  optdir.resize(numParams, 0);
350  optparam.resize(numParams, 0);
351 
352  while (Total_iterations < Max_iterations)
353  {
354  Total_iterations += 1;
355  app_log() << "Iteration: " << Total_iterations << "/" << Max_iterations << std::endl;
356  if (!ValidCostFunction(Valid))
357  continue;
358  //this is the small amount added to the diagonal to stabilize the eigenvalue equation. 10^stabilityBase
359  RealType stabilityBase(exp0);
360  // reset params if necessary
361  for (int i = 0; i < numParams; i++)
362  optTarget->Params(i) = currentParameters[i];
364  RealType lastCost(optTarget->Cost(true));
366  // if cost function is currently invalid continue
367  Valid = optTarget->IsValid;
368  if (!ValidCostFunction(Valid))
369  continue;
370  RealType newCost(lastCost);
371  RealType startCost(lastCost);
372  Matrix<RealType> Left(N, N);
373  Matrix<RealType> Right(N, N);
374  Matrix<RealType> S(N, N);
375  // stick in wrong matrix to reduce the number of matrices we need by 1.( Left is actually stored in Right, & vice-versa)
376  optTarget->fillOverlapHamiltonianMatrices(Right, Left);
377  S.copy(Left);
378  bool apply_inverse(true);
379  if (apply_inverse)
380  {
381  Matrix<RealType> RightT(Left);
382  invert_matrix(RightT, false);
383  Left = 0;
384  product(RightT, Right, Left);
385  // Now the left matrix is the Hamiltonian with the inverse of the overlap applied ot it.
386  }
387  //Find largest off-diagonal element compared to diagonal element.
388  //This gives us an idea how well conditioned it is, used to stabilize.
389  RealType od_largest(0);
390  for (int i = 0; i < N; i++)
391  for (int j = 0; j < N; j++)
392  od_largest = std::max(std::max(od_largest, std::abs(Left(i, j)) - std::abs(Left(i, i))),
393  std::abs(Left(i, j)) - std::abs(Left(j, j)));
394  app_log() << "od_largest " << od_largest << std::endl;
395  //if(od_largest>0)
396  // od_largest = std::log(od_largest);
397  //else
398  // od_largest = -1e16;
399  //if (od_largest<stabilityBase)
400  // stabilityBase=od_largest;
401  //else
402  // stabilizerScale = std::max( 0.2*(od_largest-stabilityBase)/nstabilizers, stabilizerScale);
403  app_log() << " stabilityBase " << stabilityBase << std::endl;
404  app_log() << " stabilizerScale " << stabilizerScale << std::endl;
405  int failedTries(0);
406  bool acceptedOneMove(false);
407  for (int stability = 0; stability < nstabilizers; stability++)
408  {
409  bool goodStep(true);
410  // store the Hamiltonian matrix in Right
411  for (int i = 0; i < N; i++)
412  for (int j = 0; j < N; j++)
413  Right(i, j) = Left(j, i);
414  RealType XS(stabilityBase + stabilizerScale * (failedTries + stability));
415  for (int i = 1; i < N; i++)
416  Right(i, i) += std::exp(XS);
417  app_log() << " Using XS:" << XS << " " << failedTries << " " << stability << std::endl;
418  {
420  getLowestEigenvector(Right, currentParameterDirections);
421  objFuncWrapper_.Lambda = getNonLinearRescale(currentParameterDirections, S, *optTarget);
422  }
423  // biggest gradient in the parameter direction vector
424  RealType bigVec(0);
425  for (int i = 0; i < numParams; i++)
426  bigVec = std::max(bigVec, std::abs(currentParameterDirections[i + 1]));
427  // this can be overwritten during the line minimization
428  RealType evaluated_cost(startCost);
429  if (MinMethod == "rescale")
430  {
431  if (std::abs(objFuncWrapper_.Lambda * bigVec) > bigChange)
432  {
433  goodStep = false;
434  app_log() << " Failed Step. Magnitude of largest parameter change: "
435  << std::abs(objFuncWrapper_.Lambda * bigVec) << std::endl;
436  if (stability == 0)
437  {
438  failedTries++;
439  stability--;
440  }
441  else
442  stability = nstabilizers;
443  }
444  for (int i = 0; i < numParams; i++)
445  optTarget->Params(i) = currentParameters[i] + objFuncWrapper_.Lambda * currentParameterDirections[i + 1];
446  optTarget->IsValid = true;
447  }
448  else
449  {
450  for (int i = 0; i < numParams; i++)
451  optparam[i] = currentParameters[i];
452  for (int i = 0; i < numParams; i++)
453  optdir[i] = currentParameterDirections[i + 1];
454  objFuncWrapper_.TOL = param_tol / bigVec;
455  objFuncWrapper_.AbsFuncTol = true;
456  objFuncWrapper_.largeQuarticStep = bigChange / bigVec;
457  objFuncWrapper_.LambdaMax = 0.5 * objFuncWrapper_.Lambda;
459  if (MinMethod == "quartic")
460  {
461  int npts(7);
462  objFuncWrapper_.quadstep = objFuncWrapper_.stepsize * objFuncWrapper_.Lambda;
463  objFuncWrapper_.largeQuarticStep = bigChange / bigVec;
464  Valid = objFuncWrapper_.lineoptimization3(npts, evaluated_cost);
465  }
466  else
467  Valid = objFuncWrapper_.lineoptimization2();
469  RealType biggestParameterChange = bigVec * std::abs(objFuncWrapper_.Lambda);
470  if (biggestParameterChange > bigChange)
471  {
472  goodStep = false;
473  failedTries++;
474  app_log() << " Failed Step. Largest LM parameter change:" << biggestParameterChange << std::endl;
475  if (stability == 0)
476  stability--;
477  else
478  stability = nstabilizers;
479  }
480  else
481  {
482  for (int i = 0; i < numParams; i++)
483  optTarget->Params(i) = optparam[i] + objFuncWrapper_.Lambda * optdir[i];
484  app_log() << " Good Step. Largest LM parameter change:" << biggestParameterChange << std::endl;
485  }
486  }
487 
488  if (goodStep)
489  {
490  // this may have been evaluated already
491  // newCost=evaluated_cost;
492  //get cost at new minimum
493  newCost = optTarget->Cost(false);
494  app_log() << " OldCost: " << lastCost << " NewCost: " << newCost << " Delta Cost:" << (newCost - lastCost)
495  << std::endl;
496  optTarget->printEstimates();
497  // quit if newcost is greater than lastcost. E(Xs) looks quadratic (between steepest descent and parabolic)
498  // mmorales
499  Valid = optTarget->IsValid;
500  //if (MinMethod!="rescale" && !ValidCostFunction(Valid))
501  if (!ValidCostFunction(Valid))
502  {
503  goodStep = false;
504  app_log() << " Good Step, but cost function invalid" << std::endl;
505  failedTries++;
506  if (stability > 0)
507  stability = nstabilizers;
508  else
509  stability--;
510  }
511  if (newCost < lastCost && goodStep)
512  {
513  //Move was acceptable
514  for (int i = 0; i < numParams; i++)
515  bestParameters[i] = std::real(optTarget->Params(i));
516  lastCost = newCost;
517  acceptedOneMove = true;
518  if (std::abs(newCost - lastCost) < 1e-4)
519  {
520  failedTries++;
521  stability = nstabilizers;
522  continue;
523  }
524  }
525  else if (stability > 0)
526  {
527  failedTries++;
528  stability = nstabilizers;
529  continue;
530  }
531  }
532  app_log().flush();
533  if (failedTries > 20)
534  break;
535  //APP_ABORT("QMCFixedSampleLinearOptimizeBatched::run TOO MANY FAILURES");
536  }
537 
538  if (acceptedOneMove)
539  {
540  app_log() << "Setting new Parameters" << std::endl;
541  for (int i = 0; i < numParams; i++)
542  optTarget->Params(i) = bestParameters[i];
543  }
544  else
545  {
546  app_log() << "Reverting to old Parameters" << std::endl;
547  for (int i = 0; i < numParams; i++)
548  optTarget->Params(i) = currentParameters[i];
549  }
550  app_log().flush();
551  }
552 
553  finish();
554  return (optTarget->getReportCounter() > 0);
555 }
556 
557 /** Parses the xml input file for parameter definitions for the wavefunction
558 * optimization.
559 * @param q current xmlNode
560 * @return true if successful
561 */
563 {
564  std::string useGPU("yes");
565  std::string vmcMove("pbyp");
566  std::string ReportToH5("no");
567  std::string OutputMatrices("no");
568  std::string OutputMatricesHDF("no");
569  std::string FreezeParameters("no");
570  OhmmsAttributeSet oAttrib;
571  oAttrib.add(useGPU, "gpu");
572  oAttrib.add(vmcMove, "move");
573  oAttrib.add(ReportToH5, "hdf5");
574 
575  m_param.add(OutputMatrices, "output_matrices_csv", {"no", "yes"});
576  m_param.add(OutputMatricesHDF, "output_matrices_hdf", {"no", "yes"});
577  m_param.add(FreezeParameters, "freeze_parameters", {"no", "yes"});
578 
579  m_param.add(eigensolver_, "eigensolver",
580  {
581  "inverse", // Inverse + nonsymmetric eigenvalue solver
582  "general" // General eigenvalue problem solver
583  });
584 
585  oAttrib.put(q);
586  m_param.put(q);
587 
588  do_output_matrices_csv_ = (OutputMatrices == "yes");
589  do_output_matrices_hdf_ = (OutputMatricesHDF == "yes");
590  freeze_parameters_ = (FreezeParameters == "yes");
591 
592  // Use freeze_parameters with output_matrices to generate multiple lines in the output with
593  // the same parameters so statistics can be computed in post-processing.
594 
595  if (freeze_parameters_)
596  {
597  app_log() << std::endl;
598  app_warning() << " The option 'freeze_parameters' is enabled. Variational parameters will not be updated. This "
599  "run will not perform variational parameter optimization!"
600  << std::endl;
601  app_log() << std::endl;
602  }
603 
604 
605  doGradientTest = false;
606  processChildren(q, [&](const std::string& cname, const xmlNodePtr element) {
607  if (cname == "optimize")
608  {
609  const std::string att(getXMLAttributeValue(element, "method"));
610  if (!att.empty() && att == "gradient_test")
611  {
612  GradientTestInput test_grad_input;
613  test_grad_input.readXML(element);
614  if (!testEngineObj)
615  testEngineObj = std::make_unique<GradientTest>(std::move(test_grad_input));
616  doGradientTest = true;
617  MinMethod = "gradient_test";
618  }
619  else
620  {
621  std::stringstream error_msg;
622  app_log() << "Unknown or missing 'method' attribute in optimize tag: " << att << "\n";
623  throw UniformCommunicateError(error_msg.str());
624  }
625  }
626  });
627 
628 
629  options_LMY_.doHybrid = false;
630  if (MinMethod == "hybrid")
631  {
632  options_LMY_.doHybrid = true;
633  if (!hybridEngineObj)
634  hybridEngineObj = std::make_unique<HybridEngine>(myComm, q);
635 
636  hybridEngineObj->incrementStepCounter();
637 
638  processOptXML(hybridEngineObj->getSelectedXML(), vmcMove, ReportToH5 == "yes", useGPU == "yes");
639  }
640  else
641  {
642  processOptXML(q, vmcMove, ReportToH5 == "yes", useGPU == "yes");
643  }
644 }
645 
647  const std::string& vmcMove,
648  bool reportH5,
649  bool useGPU)
650 {
651  m_param.put(opt_xml);
652 
653  auto iter = OptimizerNames.find(MinMethod);
654  if (iter == OptimizerNames.end())
655  throw std::runtime_error("Unknown MinMethod!\n");
658 
660  descentEngineObj = std::make_unique<DescentEngine>(myComm, opt_xml);
661 
662  // sanity check
665  APP_ABORT("options_LMY_.targetExcited = \"yes\" requires that MinMethod = \"adaptive or descent");
666 
667 #ifdef _OPENMP
669  {
670  // throw std::runtime_error("OpenMP threading not enabled with AdaptiveThreeShift optimizer. Use MPI for parallelism instead, and set OMP_NUM_THREADS to 1.");
671  app_log() << "test version of OpenMP threading with AdaptiveThreeShift optimizer" << std::endl;
672  }
673 #endif
674 
675  // check parameter change sanity
676  if (options_LMY_.max_param_change <= 0.0)
677  throw std::runtime_error(
678  "options_LMY_.max_param_change must be positive in QMCFixedSampleLinearOptimizeBatched::put");
679 
680  // check cost change sanity
682  throw std::runtime_error(
683  "options_LMY_.max_relative_cost_change must be positive in QMCFixedSampleLinearOptimizeBatched::put");
684 
685  // check shift sanity
686  if (shift_i_input <= 0.0)
687  throw std::runtime_error("shift_i must be positive in QMCFixedSampleLinearOptimizeBatched::put");
688  if (shift_s_input <= 0.0)
689  throw std::runtime_error("shift_s must be positive in QMCFixedSampleLinearOptimizeBatched::put");
690 
691  // check cost increase tolerance sanity
693  throw std::runtime_error(
694  "options_LMY_.cost_increase_tol must be non-negative in QMCFixedSampleLinearOptimizeBatched::put");
695 
696  // if this is the first time this function has been called, set the initial shifts
701  if (bestShift_s < 0.0)
703 
704  xmlNodePtr qsave = opt_xml;
705  xmlNodePtr cur = qsave->children;
706  int pid = OHMMS::Controller->rank();
707  while (cur != NULL)
708  {
709  std::string cname((const char*)(cur->name));
710  if (cname == "mcwalkerset")
711  {
712  mcwalkerNodePtr.push_back(cur);
713  }
714  cur = cur->next;
715  }
716 
717  // Destroy old object to stop timer to correctly order timer with object lifetime scope
718  vmcEngine.reset(nullptr);
719 
720  // Explicitly copy the driver input objects since they will be used to instantiate the VMCEngine repeatedly.
721  //Overwriting input information is also done here to account for the hybrid method
722  QMCDriverInput qmcdriver_input_copy = qmcdriver_input_;
723  VMCDriverInput vmcdriver_input_copy = vmcdriver_input_;
724 
725  if (MinMethod == "hybrid")
726  {
727  qmcdriver_input_copy.readXML(hybridEngineObj->getSelectedXML());
728  vmcdriver_input_copy.readXML(hybridEngineObj->getSelectedXML());
729  }
730  else
731  {
732  qmcdriver_input_copy.readXML(opt_xml);
733  vmcdriver_input_copy.readXML(opt_xml);
734  }
735 
736 
737  // create VMC engine
738  vmcEngine =
739  std::make_unique<VMCBatched>(project_data_, std::move(qmcdriver_input_copy), global_emi_,
740  std::move(vmcdriver_input_copy), walker_configs_ref_,
743  samples_, myComm);
744 
745  vmcEngine->setUpdateMode(vmcMove[0] == 'p');
746 
747 
748  bool AppendRun = false;
749  vmcEngine->setStatus(get_root_name(), h5_file_root_, AppendRun);
750  vmcEngine->process(qsave);
751 
752  vmcEngine->enable_sample_collection();
753 
754  auto& qmcdriver_input = vmcEngine->getQMCDriverInput();
758 
759 
760  bool success = true;
761  //allways reset optTarget
762  optTarget = std::make_unique<QMCCostFunctionBatched>(population_.get_golden_electrons(), population_.get_golden_twf(),
765  optTarget->setStream(&app_log());
766  if (reportH5)
767  optTarget->reportH5 = true;
768  success = optTarget->put(qsave);
769 
770  return success;
771 }
772 
773 ///////////////////////////////////////////////////////////////////////////////////////////////////
774 /// \brief returns a vector of three shift values centered around the provided shift.
775 ///
776 /// \param[in] central_shift the central shift
777 ///
778 ///////////////////////////////////////////////////////////////////////////////////////////////////
779 std::vector<double> QMCFixedSampleLinearOptimizeBatched::prepare_shifts(const double central_shift) const
780 {
781  std::vector<double> retval(options_LMY_.num_shifts);
782 
783  // check to see whether the number of shifts is odd
784  if (options_LMY_.num_shifts % 2 == 0)
785  throw std::runtime_error("number of shifts must be odd in QMCFixedSampleLinearOptimizeBatched::prepare_shifts");
786 
787  // decide the central shift index
788  int central_index = options_LMY_.num_shifts / 2;
789 
790  for (int i = 0; i < options_LMY_.num_shifts; i++)
791  {
792  if (i < central_index)
793  retval.at(i) = central_shift / (4.0 * (central_index - i));
794  else if (i > central_index)
795  retval.at(i) = central_shift * (4.0 * (i - central_index));
796  else if (i == central_index)
797  retval.at(i) = central_shift;
798  //retval.at(i) = central_shift
799  //retval.at(0) = central_shift * 4.0;
800  //retval.at(1) = central_shift;
801  //retval.at(2) = central_shift / 4.0;
802  }
803  return retval;
804 }
805 
806 ///////////////////////////////////////////////////////////////////////////////////////////////////
807 /// \brief prints a header for the summary of each shift's result
808 ///
809 ///////////////////////////////////////////////////////////////////////////////////////////////////
811 {
812  app_log() << " " << std::right << std::setw(12) << "shift_i";
813  app_log() << " " << std::right << std::setw(12) << "shift_s";
814  app_log() << " " << std::right << std::setw(20) << "max param change";
815  app_log() << " " << std::right << std::setw(20) << "cost function value";
816  app_log() << std::endl;
817  app_log() << " " << std::right << std::setw(12) << "------------";
818  app_log() << " " << std::right << std::setw(12) << "------------";
819  app_log() << " " << std::right << std::setw(20) << "--------------------";
820  app_log() << " " << std::right << std::setw(20) << "--------------------";
821  app_log() << std::endl;
822 }
823 
824 ///////////////////////////////////////////////////////////////////////////////////////////////////
825 /// \brief prints a summary of the computed cost for the given shift
826 ///
827 /// \param[in] si the identity shift
828 /// \param[in] ss the overlap shift
829 /// \param[in] mc the maximum parameter change
830 /// \param[in] cv the cost function value
831 /// \param[in] ind the shift index: -1 (for initial state), 0, 1, or 2
832 /// \param[in] bi index of the best shift
833 /// \param[in] gu flag telling whether it was a good update
834 ///
835 ///////////////////////////////////////////////////////////////////////////////////////////////////
837  const double ss,
838  const RealType mc,
839  const RealType cv,
840  const int ind,
841  const int bi,
842  const bool gu)
843 {
844  if (ind >= 0)
845  {
846  if (gu)
847  {
848  app_log() << " " << std::scientific << std::right << std::setw(12) << std::setprecision(4) << si;
849  app_log() << " " << std::scientific << std::right << std::setw(12) << std::setprecision(4) << ss;
850  app_log() << " " << std::scientific << std::right << std::setw(20) << std::setprecision(4) << mc;
851  app_log() << " " << std::fixed << std::right << std::setw(20) << std::setprecision(12) << cv;
852  //app_log() << " " << std::right << std::setw(12) << ( ind == 0 ? "big shift" : ( ind == 1 ? "medium shift" : "small shift" ) );
853  }
854  else
855  {
856  app_log() << " " << std::right << std::setw(12) << "N/A";
857  app_log() << " " << std::right << std::setw(12) << "N/A";
858  app_log() << " " << std::right << std::setw(20) << "N/A";
859  app_log() << " " << std::right << std::setw(20) << "N/A";
860  app_log() << " " << std::right << std::setw(12) << "bad update";
861  }
862  }
863  else
864  {
865  app_log() << " " << std::right << std::setw(12) << "N/A";
866  app_log() << " " << std::right << std::setw(12) << "N/A";
867  app_log() << " " << std::right << std::setw(20) << "N/A";
868  app_log() << " " << std::fixed << std::right << std::setw(20) << std::setprecision(12) << cv;
869  app_log() << " " << std::right << std::setw(12) << "initial";
870  }
871  if (ind == bi)
872  app_log() << " <--";
873  app_log() << std::endl;
874 }
875 
876 ///////////////////////////////////////////////////////////////////////////////////////////////////
877 /// \brief Returns whether the proposed new cost is the best compared to the others.
878 ///
879 /// \param[in] ii index of the proposed best cost
880 /// \param[in] cv vector of new costs
881 /// \param[in] sh vector of identity shifts (shift_i values)
882 /// \param[in] ic the initial cost
883 ///
884 ///////////////////////////////////////////////////////////////////////////////////////////////////
886  const std::vector<RealType>& cv,
887  const std::vector<double>& sh,
888  const RealType ic) const
889 {
890  //app_log() << "determining best cost with options_LMY_.cost_increase_tol = " << options_LMY_.cost_increase_tol << " and options_LMY_.target_shift_i = " << options_LMY_.target_shift_i << std::endl;
891 
892  // initialize return value
893  bool retval = true;
894 
895  //app_log() << "retval = " << retval << std::endl;
896 
897  // compare to other costs
898  for (int i = 0; i < cv.size(); i++)
899  {
900  // don't compare to yourself
901  if (i == ii)
902  continue;
903 
904  // we only worry about the other value if it is within the maximum relative change threshold and not too high
905  const bool other_is_valid =
906  ((ic == 0.0 ? 0.0 : std::abs((cv.at(i) - ic) / ic)) < options_LMY_.max_relative_cost_change &&
907  cv.at(i) < ic + options_LMY_.cost_increase_tol);
908  if (other_is_valid)
909  {
910  // if we are using a target shift and the cost is not too much higher, then prefer this cost if its shift is closer to the target shift
911  if (options_LMY_.target_shift_i > 0.0)
912  {
913  const bool closer_to_target =
915  const bool cost_is_similar = (std::abs(cv.at(ii) - cv.at(i)) < options_LMY_.cost_increase_tol);
916  const bool cost_is_much_lower = (!cost_is_similar && cv.at(ii) < cv.at(i) - options_LMY_.cost_increase_tol);
917  if (cost_is_much_lower || (closer_to_target && cost_is_similar))
918  retval = (retval && true);
919  else
920  retval = false;
921 
922  // if we are not using a target shift, then prefer this cost if it is lower
923  }
924  else
925  {
926  retval = (retval && cv.at(ii) <= cv.at(i));
927  }
928  }
929 
930  //app_log() << "cv.at(ii) = " << std::fixed << std::right << std::setw(20) << std::setprecision(12) << cv.at(ii) << " <= "
931  // << "cv.at(i) = " << std::fixed << std::right << std::setw(20) << std::setprecision(12) << cv.at(i) << " ?" << std::endl;
932  //app_log() << "retval = " << retval << std::endl;
933  }
934 
935  // new cost can only be the best cost if it is less than (or not too much higher than) the initial cost
936  retval = (retval && cv.at(ii) < ic + options_LMY_.cost_increase_tol);
937  //app_log() << "cv.at(ii) = " << std::fixed << std::right << std::setw(20) << std::setprecision(12) << cv.at(ii) << " <= "
938  // << "ic = " << std::fixed << std::right << std::setw(20) << std::setprecision(12) << ic << " ?" << std::endl;
939  //app_log() << "retval = " << retval << std::endl;
940 
941  // new cost is only best if it's relative change from the initial cost is not too large ( or if the initial cost is exactly zero )
942  retval = (retval && (ic == 0.0 ? 0.0 : std::abs((cv.at(ii) - ic) / ic)) < options_LMY_.max_relative_cost_change);
943  //app_log() << "std::abs( ( cv.at(ii) - ic ) / ic ) = " << std::fixed << std::right << std::setw(20) << std::setprecision(12)
944  // << std::abs( ( cv.at(ii) - ic ) / ic ) << " <= " << this->options_LMY_.max_relative_cost_change << " ? " << std::endl;
945  //app_log() << "retval = " << retval << std::endl;
946  //app_log() << std::endl;
947 
948  // return whether the proposed cost is actually the best
949  return retval;
950 }
951 
952 ///////////////////////////////////////////////////////////////////////////////////////////////////
953 /// \brief For each set of shifts, solves the linear method eigenproblem by building and
954 /// diagonalizing the matrices.
955 ///
956 /// \param[in] shfits_i vector of identity shifts
957 /// \param[in] shfits_s vector of overlap shifts
958 /// \param[out] parameterDirections on exit, the update directions for the different shifts
959 ///
960 ///////////////////////////////////////////////////////////////////////////////////////////////////
962  const std::vector<double>& shifts_i,
963  const std::vector<double>& shifts_s,
964  std::vector<std::vector<RealType>>& parameterDirections)
965 {
966  // get number of shifts to solve
967  const int nshifts = shifts_i.size();
968 
969  // get number of optimizable parameters
970  const int numParams = optTarget->getNumParams();
971 
972  // get dimension of the linear method matrices
973  const int N = numParams + 1;
974 
975  // prepare vectors to hold the parameter updates
976  parameterDirections.resize(nshifts);
977  for (int i = 0; i < parameterDirections.size(); i++)
978  parameterDirections.at(i).assign(N, 0.0);
979 
980  // allocate the matrices we will need
981  Matrix<RealType> ovlMat(N, N);
982  ovlMat = 0.0;
983  Matrix<RealType> hamMat(N, N);
984  hamMat = 0.0;
985  Matrix<RealType> invMat(N, N);
986  invMat = 0.0;
987  Matrix<RealType> sftMat(N, N);
988  sftMat = 0.0;
989  Matrix<RealType> prdMat(N, N);
990  prdMat = 0.0;
991 
992  // build the overlap and hamiltonian matrices
993  optTarget->fillOverlapHamiltonianMatrices(hamMat, ovlMat);
994 
995  //// print the hamiltonian matrix
996  //app_log() << std::endl;
997  //app_log() << "printing H matrix:" << std::endl;
998  //for (int i = 0; i < hamMat.rows(); i++) {
999  // for (int j = 0; j < hamMat.cols(); j++)
1000  // app_log() << " " << std::scientific << std::right << std::setw(14) << std::setprecision(5) << hamMat(i,j);
1001  // app_log() << std::endl;
1002  //}
1003  //app_log() << std::endl;
1004 
1005  //// print the overlap matrix
1006  //app_log() << std::endl;
1007  //app_log() << "printing S matrix:" << std::endl;
1008  //for (int i = 0; i < ovlMat.rows(); i++) {
1009  // for (int j = 0; j < ovlMat.cols(); j++)
1010  // app_log() << " " << std::scientific << std::right << std::setw(14) << std::setprecision(5) << ovlMat(i,j);
1011  // app_log() << std::endl;
1012  //}
1013  //app_log() << std::endl;
1014 
1015  // compute the inverse of the overlap matrix
1016  invMat.copy(ovlMat);
1017  invert_matrix(invMat, false);
1018 
1019  // compute the update for each shift
1020  for (int shift_index = 0; shift_index < nshifts; shift_index++)
1021  {
1022  // prepare to shift the hamiltonain matrix
1023  sftMat.copy(hamMat);
1024 
1025  // apply the identity shift
1026  for (int i = 1; i < N; i++)
1027  sftMat(i, i) += shifts_i.at(shift_index);
1028 
1029  // apply the overlap shift
1030  for (int i = 1; i < N; i++)
1031  for (int j = 1; j < N; j++)
1032  sftMat(i, j) += shifts_s.at(shift_index) * ovlMat(i, j);
1033 
1034  // multiply the shifted hamiltonian matrix by the inverse of the overlap matrix
1035  qmcplusplus::MatrixOperators::product(invMat, sftMat, prdMat);
1036 
1037  // transpose the result (why?)
1038  for (int i = 0; i < N; i++)
1039  for (int j = i + 1; j < N; j++)
1040  std::swap(prdMat(i, j), prdMat(j, i));
1041 
1042  // compute the lowest eigenvalue of the product matrix and the corresponding eigenvector
1043  getLowestEigenvector(prdMat, parameterDirections.at(shift_index));
1044 
1045  // compute the scaling constant to apply to the update
1046  objFuncWrapper_.Lambda = getNonLinearRescale(parameterDirections.at(shift_index), ovlMat, *optTarget);
1047 
1048  // scale the update by the scaling constant
1049  for (int i = 0; i < numParams; i++)
1050  parameterDirections.at(shift_index).at(i + 1) *= objFuncWrapper_.Lambda;
1051  }
1052 }
1053 
1054 ///////////////////////////////////////////////////////////////////////////////////////////////////
1055 /// \brief Performs one iteration of the linear method using an adaptive scheme that tries three
1056 /// different shift magnitudes and picks the best one.
1057 /// The scheme is adaptive in that it saves the best shift to use as a starting point
1058 /// in the next iteration.
1059 /// Note that the best shift is chosen based on a different sample than that used to
1060 /// construct the linear method matrices in order to avoid over-optimizing on a particular
1061 /// sample.
1062 ///
1063 /// \return ???
1064 ///
1065 ///////////////////////////////////////////////////////////////////////////////////////////////////
1066 #ifdef HAVE_LMY_ENGINE
1068 {
1069  EngineObj->setStoringSamples(options_LMY_.store_samples);
1070 
1071  //Set whether LM will only update a filtered set of parameters
1072  EngineObj->setFiltering(options_LMY_.filter_param);
1073  EngineObj->setFilterInfo(options_LMY_.filter_info);
1074 
1076  myComm->barrier_and_abort(" Error: Parameter Filtration requires storing the samples. \n");
1077 
1079  EngineObj->setThreshold(options_LMY_.ratio_threshold);
1080 
1081  // remember what the cost function grads flag was
1082  const bool saved_grads_flag = optTarget->getneedGrads();
1083 
1084  // remember the initial number of samples
1085  const int init_num_samp = optTarget->getNumSamples();
1086 
1087  // the index of central shift
1088  const int central_index = options_LMY_.num_shifts / 2;
1089 
1090  // get number of optimizable parameters
1091  const int numParams = optTarget->getNumParams();
1092 
1093  // prepare the shifts that we will try
1094  const std::vector<double> shifts_i = prepare_shifts(bestShift_i);
1095  const std::vector<double> shifts_s = prepare_shifts(bestShift_s);
1096  std::vector<double> shift_scales(shifts_i.size(), 1.0);
1097  for (int i = 0; i < shift_scales.size(); i++)
1098  shift_scales.at(i) = shifts_i.at(i) / shift_i_input;
1099 
1100  // ensure the cost function is set to compute derivative vectors
1101  optTarget->setneedGrads(true);
1102 
1103  // prepare previous updates
1104  int count = 0;
1105  while (options_LMY_.block_lm && previous_update.size() < options_LMY_.nolds)
1106  {
1107  previous_update.push_back(formic::ColVec<double>(numParams));
1108  for (int i = 0; i < numParams; i++)
1109  previous_update.at(count).at(i) = 2.0 * (formic::random_number<double>() - 0.5);
1110  count++;
1111  }
1112 
1113  if (!EngineObj->full_init())
1114  {
1115  // prepare a variable dependency object with no dependencies
1116  formic::VarDeps real_vdeps(numParams, std::vector<double>());
1117  vdeps = real_vdeps;
1118  EngineObj->get_param(&vdeps,
1119  false, // exact sampling
1121  false, // variable deps use?
1122  false, // eom
1123  false, // ssquare
1124  options_LMY_.block_lm, 12000, numParams, options_LMY_.omega_shift,
1125  options_LMY_.max_relative_cost_change, shifts_i.at(central_index), shifts_s.at(central_index),
1126  options_LMY_.max_param_change, shift_scales);
1127  }
1128 
1129  //Reset parameter number for vdeps to the total number in case filtration happened on a previous iteration
1131  {
1132  formic::VarDeps tmp_vdeps(numParams, std::vector<double>());
1133  vdeps = tmp_vdeps;
1134  EngineObj->var_deps_ptr_update(&vdeps);
1135  }
1136 
1137  // update shift
1138  EngineObj->shift_update(shift_scales);
1139 
1140  // turn on wavefunction update mode
1141  EngineObj->turn_on_update();
1142 
1143  //The initial intialization of the LM engine is handled differently if parameters are being filtered
1145  {
1146  // initialize the engine if we do not use block lm or it's the first part of block lm
1147  EngineObj->initialize(options_LMY_.nblocks, 0, options_LMY_.nkept, previous_update, false);
1148  EngineObj->reset();
1149  }
1150  else
1151  {
1152  app_log() << "Skipping initialization at first" << std::endl;
1153  EngineObj->store_blocked_lm_info(options_LMY_.nblocks, options_LMY_.nkept);
1154  }
1155 
1156 
1157  // reset the engine
1158  EngineObj->reset();
1159 
1160  // generate samples and compute weights, local energies, and derivative vectors
1161  engine_start(EngineObj, *descentEngineObj, MinMethod);
1162 
1163  int new_num = 0;
1164 
1165  //To handle different cases for the LM's mode of operation, first check if samples are being stored
1167  {
1168  //Need to clear lists from previous iter
1169  EngineObj->reset();
1170 
1171  //If samples are being stored, check for the subcase where parameters are also being filtered
1173  {
1174  EngineObj->selectParameters();
1175 
1176  for (int i = 0; i < numParams; i++)
1177  if (EngineObj->getParameterSetting(i))
1178  new_num++;
1179 
1180  formic::VarDeps real_vdeps(new_num, std::vector<double>());
1181  vdeps = real_vdeps;
1182  EngineObj->var_deps_ptr_update(&vdeps);
1183 
1184  //Also need to check if Blocked LM is being used
1185  if (EngineObj->use_blm())
1186  {
1187  //If so, the old update vectors need to be trimmed to remove the filtered out parameters
1188  std::vector<formic::ColVec<double>> trimmed_old_updates(previous_update.size());
1189 
1190  //Check if this Blocked LM step is part of a hybrid optimization
1191  if (EngineObj->getOnHybrid())
1192  {
1193  //If so, get the old update vectors from the descent engine
1194  std::vector<std::vector<ValueType>> hybridBLM_Input = descentEngineObj->retrieveHybridBLM_Input();
1195 
1196 
1197  app_log() << "Blocked LM is part of hybrid run. Need to filter vectors from descent. " << std::endl;
1198 
1199  //This section handles the trimming of the old update vectors from descent
1200  for (int i = 0; i < hybridBLM_Input.size(); i++)
1201  {
1202  std::vector<ValueType> full_vec = hybridBLM_Input[i];
1203  std::vector<ValueType> filtered_vec;
1204 
1205  formic::ColVec<double> reduced_vector(new_num, 0.0);
1206  int count = 0;
1207 
1208  for (int j = 0; j < full_vec.size(); j++)
1209  if (EngineObj->getParameterSetting(j))
1210  {
1211  filtered_vec.push_back(full_vec[j]);
1212  reduced_vector[count] = formic::real(full_vec[j]);
1213  count++;
1214  }
1215 
1216  hybridBLM_Input[i] = filtered_vec;
1217  trimmed_old_updates[i] = reduced_vector;
1218  }
1219 
1220 #if !defined(QMC_COMPLEX)
1221  EngineObj->setHybridBLM_Input(hybridBLM_Input);
1222 #endif
1223 
1224  EngineObj->initialize(options_LMY_.nblocks, 0, options_LMY_.nkept, trimmed_old_updates, false);
1225  EngineObj->reset();
1226  }
1227  //If the Blocked LM is not part of a hybrid run, carry out the trimming of the old updates here
1228  else
1229  {
1230  app_log() << "Regular Blocked LM run. Need to filter old update vectors. " << std::endl;
1231 
1232  for (int i = 0; i < previous_update.size(); i++)
1233  {
1234  formic::ColVec<double> full_vec = previous_update[i];
1235 
1236  formic::ColVec<double> reduced_vector(new_num, 0.0);
1237  int count = 0;
1238 
1239  for (int j = 0; j < full_vec.size(); j++)
1240  if (EngineObj->getParameterSetting(j))
1241  {
1242  reduced_vector[count] = full_vec[j];
1243  count++;
1244  }
1245 
1246  trimmed_old_updates[i] = reduced_vector;
1247  }
1248 
1249  EngineObj->initialize(options_LMY_.nblocks, 0, options_LMY_.nkept, trimmed_old_updates, false);
1250  EngineObj->reset();
1251  }
1252  }
1253  }
1254  //If not filtering parameters and only storing samples, can proceed with the rest of the LM engine initialization
1255  else
1256  {
1257  EngineObj->initialize(options_LMY_.nblocks, 0, options_LMY_.nkept, previous_update, false);
1258  EngineObj->reset();
1259  }
1260 
1261 
1262  //This function call builds the matrices from the stored samples
1263  EngineObj->buildMatricesFromDerivatives();
1264  }
1265 
1266 
1267  // get dimension of the linear method matrices
1268  int N = numParams + 1;
1270  N = new_num + 1;
1271 
1272  // have the cost function prepare derivative vectors
1273  EngineObj->energy_target_compute();
1274  const RealType starting_cost = EngineObj->target_value();
1275  const RealType init_energy = EngineObj->energy_mean();
1276 
1277  // print out the initial energy
1278  app_log() << std::endl
1279  << "*************************************************************************************************"
1280  << std::endl
1281  << "Solving the linear method equations on the initial sample with initial energy" << std::setw(20)
1282  << std::setprecision(12) << init_energy << std::endl
1283  << "*************************************************************************************************"
1284  << std::endl
1285  << std::endl;
1286 
1287  // prepare wavefunction update which does nothing if we do not use block lm
1288  EngineObj->wfn_update_prep();
1289 
1290  if (options_LMY_.block_lm)
1291  {
1293  {
1294  optTarget->setneedGrads(true);
1295 
1296  int numOptParams = optTarget->getNumParams();
1297 
1298  // reset the engine object
1299  EngineObj->reset();
1300 
1301  // finish last sample
1302  finish();
1303 
1304  // take sample
1305  engine_start(EngineObj, *descentEngineObj, MinMethod);
1306  }
1307  else
1308  {
1309  EngineObj->clear_histories();
1310  EngineObj->reset();
1311 
1312  finish();
1313 
1315  {
1316  engine_start(EngineObj, *descentEngineObj, MinMethod);
1317  EngineObj->buildMatricesFromDerivatives();
1318  }
1319  else
1320  {
1321  engine_start(EngineObj, *descentEngineObj, MinMethod);
1322  app_log() << "Should be building matrices from stored samples" << std::endl;
1323  EngineObj->buildMatricesFromDerivatives();
1324  }
1325  }
1326  }
1327 
1328  //Need to wipe the stored samples after they are no longer needed and before the next iteration
1330  {
1331  EngineObj->clear_histories();
1332  }
1333 
1334  // say what we are doing
1335  app_log() << std::endl
1336  << "*********************************************************" << std::endl
1337  << "Solving the linear method equations on the initial sample" << std::endl
1338  << "*********************************************************" << std::endl
1339  << std::endl;
1340 
1341  // for each set of shifts, solve the linear method equations for the parameter update direction
1342  std::vector<std::vector<RealType>> parameterDirections;
1343 #ifdef HAVE_LMY_ENGINE
1344  // call the engine to perform update
1345  EngineObj->wfn_update_compute();
1346 #else
1347  solveShiftsWithoutLMYEngine(shifts_i, shifts_s, parameterDirections);
1348 #endif
1349 
1350  // size update direction vector correctly
1351  parameterDirections.resize(shifts_i.size());
1352  for (int i = 0; i < shifts_i.size(); i++)
1353  {
1354  parameterDirections.at(i).assign(N, 0.0);
1355  if (true)
1356  {
1357  for (int j = 0; j < N; j++)
1358  parameterDirections.at(i).at(j) = std::real(EngineObj->wfn_update().at(i * N + j));
1359  }
1360  else
1361  parameterDirections.at(i).at(0) = 1.0;
1362  }
1363 
1364  //If paramters are being filtered need to expand the LM updates from the engine to the full parameter set.
1365  //There will be updates of 0 for parameters that were filtered out before derivative ratios were used by the engine.
1367  {
1368  std::vector<std::vector<RealType>> tmpParameterDirections;
1369  tmpParameterDirections.resize(shifts_i.size());
1370 
1371  for (int i = 0; i < shifts_i.size(); i++)
1372  {
1373  tmpParameterDirections.at(i).assign(numParams + 1, 0.0);
1374  int lm_update_idx = 0;
1375  for (int j = 0; j < numParams + 1; j++)
1376  {
1377  if (j == 0)
1378  {
1379  tmpParameterDirections.at(i).at(j) = parameterDirections.at(i).at(j);
1380  lm_update_idx++;
1381  }
1382  else if (EngineObj->getParameterSetting(j - 1) == true)
1383  {
1384  tmpParameterDirections.at(i).at(j) = parameterDirections.at(i).at(lm_update_idx);
1385  lm_update_idx++;
1386  }
1387  }
1388  parameterDirections.at(i) = tmpParameterDirections.at(i);
1389  }
1390  }
1391 
1392  //From this point, the comparison of the 3 diffferent shifts' updates should proceed as normal regardless of the sample storage or parameter filtration settings.
1393 
1394  // now that we are done with them, prevent further computation of derivative vectors
1395  optTarget->setneedGrads(false);
1396 
1397  // prepare vectors to hold the initial and current parameters
1398  std::vector<RealType> currParams(numParams, 0.0);
1399 
1400  // initialize the initial and current parameter vectors
1401  for (int i = 0; i < numParams; i++)
1402  currParams.at(i) = optTarget->Params(i);
1403 
1404  // create a vector telling which updates are within our constraints
1405  std::vector<bool> good_update(parameterDirections.size(), true);
1406 
1407  // compute the largest parameter change for each shift, and zero out updates that have too-large changes
1408  std::vector<RealType> max_change(parameterDirections.size(), 0.0);
1409  for (int k = 0; k < parameterDirections.size(); k++)
1410  {
1411  for (int i = 0; i < numParams; i++)
1412  max_change.at(k) =
1413  std::max(max_change.at(k), std::abs(parameterDirections.at(k).at(i + 1) / parameterDirections.at(k).at(0)));
1414  good_update.at(k) = (good_update.at(k) && max_change.at(k) <= options_LMY_.max_param_change);
1415  }
1416 
1417  // prepare to use the middle shift's update as the guiding function for a new sample
1418  for (int i = 0; i < numParams; i++)
1419  optTarget->Params(i) = currParams.at(i) + parameterDirections.at(central_index).at(i + 1);
1420 
1421  // say what we are doing
1422  app_log() << std::endl
1423  << "************************************************************" << std::endl
1424  << "Updating the guiding function with the middle shift's update" << std::endl
1425  << "************************************************************" << std::endl
1426  << std::endl;
1427 
1428  // generate the new sample on which we will compare the different shifts
1429 
1430  finish();
1431  app_log() << std::endl
1432  << "*************************************************************" << std::endl
1433  << "Generating a new sample based on the updated guiding function" << std::endl
1434  << "*************************************************************" << std::endl
1435  << std::endl;
1436 
1437  //Apparently the batched drivers are intended to be run only once, which
1438  //means that the origianl version of adaptive_three_shift will not work as
1439  //calling start or engine_start at this point will lead to vmcEngine being run again.
1440  //This will lead to a slight difference in behavior compared to the
1441  //legacy drivers as those could be run a second time to obtain samples based
1442  //on the wave function from the middle shift.
1443  //It is possible this difference may not make much difference in
1444  //practical optimization performance, but that is unexplored.
1445 
1446 
1447  // say what we are doing
1448  app_log() << std::endl
1449  << "******************************************************************" << std::endl
1450  << "Comparing different shifts' cost function values on updated sample" << std::endl
1451  << "******************************************************************" << std::endl
1452  << std::endl;
1453 
1454  // update the current parameters to those of the new guiding function
1455  for (int i = 0; i < numParams; i++)
1456  currParams.at(i) = optTarget->Params(i);
1457 
1458  // compute cost function for the initial parameters (by subtracting the middle shift's update back off)
1459  for (int i = 0; i < numParams; i++)
1460  optTarget->Params(i) = currParams.at(i) - parameterDirections.at(central_index).at(i + 1);
1461  optTarget->IsValid = true;
1462  const RealType initCost = optTarget->LMYEngineCost(false, EngineObj);
1463 
1464  // compute the update directions for the smaller and larger shifts relative to that of the middle shift
1465  for (int i = 0; i < numParams; i++)
1466  {
1467  for (int j = 0; j < parameterDirections.size(); j++)
1468  {
1469  if (j != central_index)
1470  parameterDirections.at(j).at(i + 1) -= parameterDirections.at(central_index).at(i + 1);
1471  }
1472  }
1473 
1474  // prepare a vector to hold the cost function value for each different shift
1475  std::vector<RealType> costValues(options_LMY_.num_shifts, 0.0);
1476 
1477  // compute the cost function value for each shift and make sure the change is within our constraints
1478  for (int k = 0; k < parameterDirections.size(); k++)
1479  {
1480  for (int i = 0; i < numParams; i++)
1481  optTarget->Params(i) = currParams.at(i) + (k == central_index ? 0.0 : parameterDirections.at(k).at(i + 1));
1482  optTarget->IsValid = true;
1483  costValues.at(k) = optTarget->LMYEngineCost(false, EngineObj);
1484  good_update.at(k) = (good_update.at(k) &&
1485  std::abs((initCost - costValues.at(k)) / initCost) < options_LMY_.max_relative_cost_change);
1486  if (!good_update.at(k))
1487  costValues.at(k) = std::abs(1.5 * initCost) + 1.0;
1488  }
1489 
1490  // find the best shift and the corresponding update direction
1491  const std::vector<RealType>* bestDirection = 0;
1492  int best_shift = -1;
1493  for (int k = 0;
1494  k < costValues.size() && std::abs((initCost - initCost) / initCost) < options_LMY_.max_relative_cost_change; k++)
1495  if (is_best_cost(k, costValues, shifts_i, initCost) && good_update.at(k))
1496  {
1497  best_shift = k;
1498  bestDirection = &parameterDirections.at(k);
1499  }
1500 
1501  // print the results for each shift
1502  app_log() << std::endl;
1504  print_cost_summary(0.0, 0.0, 0.0, initCost, -1, best_shift, true);
1505  for (int k = 0; k < good_update.size(); k++)
1506  print_cost_summary(shifts_i.at(k), shifts_s.at(k), max_change.at(k), costValues.at(k), k, best_shift,
1507  good_update.at(k));
1508 
1509  // if any of the shifts produced a good update, apply the best such update and remember those shifts for next time
1510  if (bestDirection)
1511  {
1512  bestShift_i = shifts_i.at(best_shift);
1513  bestShift_s = shifts_s.at(best_shift);
1514  for (int i = 0; i < numParams; i++)
1515  optTarget->Params(i) = currParams.at(i) + (best_shift == central_index ? 0.0 : bestDirection->at(i + 1));
1516  app_log() << std::endl
1517  << "*****************************************************************************" << std::endl
1518  << "Applying the update for shift_i = " << std::scientific << std::right << std::setw(12)
1519  << std::setprecision(4) << bestShift_i << " and shift_s = " << std::scientific << std::right
1520  << std::setw(12) << std::setprecision(4) << bestShift_s << std::endl
1521  << "*****************************************************************************" << std::endl
1522  << std::endl;
1523 
1524  // otherwise revert to the old parameters and set the next shift to be larger
1525  }
1526  else
1527  {
1528  bestShift_i *= 10.0;
1529  bestShift_s *= 10.0;
1530  for (int i = 0; i < numParams; i++)
1531  optTarget->Params(i) = currParams.at(i) - parameterDirections.at(central_index).at(i + 1);
1532  app_log() << std::endl
1533  << "***********************************************************" << std::endl
1534  << "Reverting to old parameters and increasing shift magnitudes" << std::endl
1535  << "***********************************************************" << std::endl
1536  << std::endl;
1537  }
1538 
1539  // save the update for future linear method iterations
1540  if (options_LMY_.block_lm && bestDirection)
1541  {
1542  // save the difference between the updated and old variables
1543  formic::ColVec<RealType> update_dirs(numParams, 0.0);
1544  for (int i = 0; i < numParams; i++)
1545  // take the real part since blocked LM currently does not support complex parameter optimization
1546  update_dirs.at(i) = std::real(bestDirection->at(i + 1) + parameterDirections.at(central_index).at(i + 1));
1547  previous_update.insert(previous_update.begin(), update_dirs);
1548 
1549  // eliminate the oldest saved update if necessary
1550  while (previous_update.size() > options_LMY_.nolds)
1551  previous_update.pop_back();
1552  }
1553 
1554  // return the cost function grads flag to what it was
1555  optTarget->setneedGrads(saved_grads_flag);
1556 
1557  // perform some finishing touches for this linear method iteration
1558  finish();
1559 
1560  // set the number samples to be initial one
1561  optTarget->setNumSamples(init_num_samp);
1562 
1563  //app_log() << "block first second third end " << options_LMY_.block_first << options_LMY_.block_second << options_LMY_.block_third << endl;
1564  // return whether the cost function's report counter is positive
1565  return (optTarget->getReportCounter() > 0);
1566 }
1567 #endif
1568 
1570 {
1571  // ensure the cost function is set to compute derivative vectors
1572  optTarget->setneedGrads(true);
1573 
1574  // generate samples and compute weights, local energies, and derivative vectors
1575  start();
1576 
1577  // get number of optimizable parameters
1578  const int numParams = optTarget->getNumParams();
1579 
1580  // get dimension of the linear method matrices
1581  const int N = numParams + 1;
1582 
1583  // prepare vectors to hold the initial and current parameters
1584  std::vector<RealType> currentParameters(numParams, 0.0);
1585 
1586  // initialize the initial and current parameter vectors
1587  for (int i = 0; i < numParams; i++)
1588  currentParameters.at(i) = std::real(optTarget->Params(i));
1589 
1590  // prepare vectors to hold the parameter update directions for each shift
1591  std::vector<RealType> parameterDirections;
1592  parameterDirections.assign(N, 0.0);
1593 
1594  // compute the initial cost
1595  const RealType initCost = optTarget->computedCost();
1596 
1597  // allocate the matrices we will need
1598  Matrix<RealType> ovlMat(N, N);
1599  ovlMat = 0.0;
1600  Matrix<RealType> hamMat(N, N);
1601  hamMat = 0.0;
1602  Matrix<RealType> invMat(N, N);
1603  invMat = 0.0;
1604  Matrix<RealType> prdMat(N, N);
1605  prdMat = 0.0;
1606 
1607  // for outputing matrices and eigenvalue/vectors to disk
1608  hdf_archive hout;
1609 
1610  {
1612  Timer t_build_matrices;
1613  // say what we are doing
1614  app_log() << std::endl
1615  << "*****************************************" << std::endl
1616  << "Building overlap and Hamiltonian matrices" << std::endl
1617  << "*****************************************" << std::endl;
1618 
1619  // build the overlap and hamiltonian matrices
1620  optTarget->fillOverlapHamiltonianMatrices(hamMat, ovlMat);
1621 
1623  {
1624  output_overlap_.output(ovlMat);
1625  output_hamiltonian_.output(hamMat);
1626  }
1627 
1629  {
1630  std::string newh5 = get_root_name() + ".linear_matrices.h5";
1631  hout.create(newh5, H5F_ACC_TRUNC);
1632  hout.write(ovlMat, "overlap");
1633  hout.write(hamMat, "Hamiltonian");
1634  hout.write(bestShift_i, "bestShift_i");
1635  hout.write(bestShift_s, "bestShift_s");
1636  }
1637  app_log() << " Execution time (building matrices) = " << std::setprecision(4) << t_build_matrices.elapsed()
1638  << std::endl;
1639  }
1640 
1641  // Solve eigenvalue problem on one rank.
1642  if (is_manager())
1643  {
1645  Timer t_eigen;
1646  app_log() << std::endl
1647  << "**************************" << std::endl
1648  << "Solving eigenvalue problem" << std::endl
1649  << "**************************" << std::endl;
1650 
1651  invMat.copy(ovlMat);
1652  // apply the identity shift
1653  for (int i = 1; i < N; i++)
1654  {
1655  hamMat(i, i) += bestShift_i;
1656  if (invMat(i, i) == 0)
1657  invMat(i, i) = bestShift_i * bestShift_s;
1658  }
1659 
1660  // apply the overlap shift
1661  for (int i = 1; i < N; i++)
1662  for (int j = 1; j < N; j++)
1663  hamMat(i, j) += bestShift_s * ovlMat(i, j);
1664 
1665  RealType lowestEV;
1666  // compute the lowest eigenvalue and the corresponding eigenvector
1667  if (eigensolver_ == "general")
1668  {
1669  app_log() << " Using generalized eigenvalue solver (ggev)" << std::endl;
1670  lowestEV = getLowestEigenvector_Gen(hamMat, invMat, parameterDirections);
1671  }
1672  else if (eigensolver_ == "inverse")
1673  {
1674  app_log() << " Using inverse + regular eigenvalue solver (geev)" << std::endl;
1675  lowestEV = getLowestEigenvector_Inv(hamMat, invMat, parameterDirections);
1676  }
1677  else if (eigensolver_ == "arpack")
1678  {
1679  app_log() << "ARPACK not compiled into this QMCPACK executable" << std::endl;
1680  throw std::runtime_error("ARPACK not present (QMC_USE_ARPACK not set)");
1681  }
1682  else
1683  {
1684  throw std::runtime_error("Unknown eigenvalue solver: " + eigensolver_);
1685  }
1686 
1687  app_log() << " Execution time (eigenvalue) = " << std::setprecision(4) << t_eigen.elapsed() << std::endl;
1688 
1689  // compute the scaling constant to apply to the update
1690  objFuncWrapper_.Lambda = getNonLinearRescale(parameterDirections, ovlMat, *optTarget);
1691 
1693  {
1694  hout.write(lowestEV, "lowest_eigenvalue");
1695  hout.write(parameterDirections, "scaled_eigenvector");
1696  hout.write(objFuncWrapper_.Lambda, "non_linear_rescale");
1697  hout.close();
1698  }
1699 
1700  // scale the update by the scaling constant
1701  for (int i = 0; i < numParams; i++)
1702  parameterDirections.at(i + 1) *= objFuncWrapper_.Lambda;
1703  }
1704  myComm->bcast(parameterDirections);
1705 
1706  // now that we are done building the matrices, prevent further computation of derivative vectors
1707  optTarget->setneedGrads(false);
1708 
1709  // prepare to use the middle shift's update as the guiding function for a new sample
1710  if (!freeze_parameters_)
1711  {
1712  for (int i = 0; i < numParams; i++)
1713  optTarget->Params(i) = currentParameters.at(i) + parameterDirections.at(i + 1);
1714  }
1715 
1716  RealType largestChange(0);
1717  int max_element = 0;
1718  for (int i = 0; i < numParams; i++)
1719  if (std::abs(parameterDirections.at(i + 1)) > largestChange)
1720  {
1721  largestChange = std::abs(parameterDirections.at(i + 1));
1722  max_element = i;
1723  }
1724  app_log() << std::endl
1725  << "Among totally " << numParams << " optimized parameters, "
1726  << "largest LM parameter change : " << largestChange << " at parameter " << max_element << std::endl;
1727 
1728  // compute the new cost
1729  optTarget->IsValid = true;
1730  const RealType newCost = optTarget->Cost(false);
1731 
1732  app_log() << std::endl
1733  << "******************************************************************************" << std::endl
1734  << "Init Cost = " << std::scientific << std::right << std::setw(12) << std::setprecision(4) << initCost
1735  << " New Cost = " << std::scientific << std::right << std::setw(12) << std::setprecision(4) << newCost
1736  << " Delta Cost = " << std::scientific << std::right << std::setw(12) << std::setprecision(4)
1737  << newCost - initCost << std::endl
1738  << "******************************************************************************" << std::endl;
1739 
1740  if (!optTarget->IsValid || qmcplusplus::isnan(newCost))
1741  {
1742  app_log() << std::endl << "The new set of parameters is not valid. Revert to the old set!" << std::endl;
1743  for (int i = 0; i < numParams; i++)
1744  optTarget->Params(i) = currentParameters.at(i);
1746  if (accept_history[0] == true && accept_history[1] == false) // rejected the one before last and accepted the last
1747  {
1749  app_log() << "Update shift_s_base to " << shift_s_base << std::endl;
1750  }
1751  accept_history <<= 1;
1752  }
1753  else
1754  {
1755  if (bestShift_s > 1.0e-2)
1757  // say what we are doing
1758  app_log() << std::endl << "The new set of parameters is valid. Updating the trial wave function!" << std::endl;
1759  accept_history <<= 1;
1760  accept_history.set(0, true);
1761  }
1762 
1763  app_log() << std::endl
1764  << "*****************************************************************************" << std::endl
1765  << "Applying the update for shift_i = " << std::scientific << std::right << std::setw(12)
1766  << std::setprecision(4) << bestShift_i << " and shift_s = " << std::scientific << std::right
1767  << std::setw(12) << std::setprecision(4) << bestShift_s << std::endl
1768  << "*****************************************************************************" << std::endl;
1769 
1770  // perform some finishing touches for this linear method iteration
1771  finish();
1772 
1773  // return whether the cost function's report counter is positive
1774  return (optTarget->getReportCounter() > 0);
1775 }
1776 
1777 #ifdef HAVE_LMY_ENGINE
1778 //Function for optimizing using gradient descent
1780 {
1781  //Compute Lagrangian derivatives needed for parameter updates with engine_checkConfigurations, which is called inside engine_start
1782  engine_start(EngineObj, *descentEngineObj, MinMethod);
1783 
1784  int descent_num = descentEngineObj->getDescentNum();
1785 
1786  if (descent_num == 0)
1787  descentEngineObj->setupUpdate(optTarget->getOptVariables());
1788 
1789  //Store the derivatives and then compute parameter updates
1790  descentEngineObj->storeDerivRecord();
1791 
1792  descentEngineObj->updateParameters();
1793 
1794  std::vector<ValueType> results = descentEngineObj->retrieveNewParams();
1795 
1796 
1797  for (int i = 0; i < results.size(); i++)
1798  {
1799  optTarget->Params(i) = std::real(results[i]);
1800  }
1801 
1802  //If descent is being run as part of a hybrid optimization, need to check if a vector of
1803  //parameter differences should be stored.
1804  if (options_LMY_.doHybrid)
1805  {
1806  int store_num = descentEngineObj->retrieveStoreFrequency();
1807  bool store = hybridEngineObj->queryStore(store_num, OptimizerType::DESCENT);
1808  if (store)
1809  {
1810  descentEngineObj->storeVectors(results);
1811  }
1812  }
1813 
1814  finish();
1815  return (optTarget->getReportCounter() > 0);
1816 }
1817 #endif
1818 
1819 
1820 //Function for controlling the alternation between sections of descent optimization and BLM optimization.
1821 #ifdef HAVE_LMY_ENGINE
1822 bool QMCFixedSampleLinearOptimizeBatched::hybrid_run()
1823 {
1824  app_log() << "This is methodName: " << MinMethod << std::endl;
1825 
1826  //Either the adaptive BLM or descent optimization is run
1827 
1828  //Ensure LM engine knows it is being used as part of a hybrid run
1829  EngineObj->setOnHybrid(true);
1830 
1832  {
1833  //If the optimization just switched to using the BLM, need to transfer a set
1834  //of vectors to the BLM engine.
1836  {
1837  descentEngineObj->resetStorageCount();
1838  std::vector<std::vector<ValueType>> hybridBLM_Input = descentEngineObj->retrieveHybridBLM_Input();
1839 #if !defined(QMC_COMPLEX)
1840  //FIXME once complex is fixed in BLM engine
1841  EngineObj->setHybridBLM_Input(hybridBLM_Input);
1842 #endif
1843  }
1845  }
1846 
1848  descent_run();
1849 
1850  app_log() << "Finished a hybrid step" << std::endl;
1851  return (optTarget->getReportCounter() > 0);
1852 }
1853 #endif
1854 
1855 } // namespace qmcplusplus
OptimizerType previous_optimizer_type
type of the previous optimization method, updated by processOptXML before run
MatrixA::value_type invert_matrix(MatrixA &M, bool getdet=true)
invert a matrix
double elapsed() const
Definition: Timer.h:30
const ParticleSet & get_golden_electrons() const
Definition: MCPopulation.h:176
std::ostream & app_warning()
Definition: OutputManager.h:69
Abstraction of information on executor environments.
void write(T &data, const std::string &aname)
write the data to the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:259
MCPopulation population_
the entire (on node) walker population it serves VMCBatch and DMCBatch right now but will be polymorp...
Definition: QMCDriverNew.h:426
QMCTraits::RealType real
QMCHamiltonian & get_golden_hamiltonian()
Definition: MCPopulation.h:181
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
int rank() const
return the rank
Definition: Communicate.h:116
const std::map< std::string, OptimizerType > OptimizerNames
size_t getActiveWalkers() const
return the number of active walkers
Input representation for VMC driver class runtime parameters.
void resetSampleCount()
Set the sample count to zero but preserve the storage.
Definition: SampleStack.cpp:57
This is a data structure strictly for QMCDriver and its derived classes.
Definition: QMCDriverNew.h:116
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
std::vector< double > prepare_shifts(const double central_shift) const
returns a vector of three shift values centered around the provided shift.
OptimizerType current_optimizer_type
type of the current optimization method, updated by processOptXML before run
QMCDriverNew Base class for Unified Drivers.
Definition: QMCDriverNew.h:75
std::ostream & app_log()
Definition: OutputManager.h:65
class ProjectData
Definition: ProjectData.h:36
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
A set of light weight walkers that are carried between driver sections and restart.
void print_cost_summary_header()
prints a header for the summary of each shift&#39;s result
void close()
close all the open groups and file
Definition: hdf_archive.cpp:38
class to handle hdf file
Definition: hdf_archive.h:51
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
int size() const
return the number of tasks
Definition: Communicate.h:118
void copy(const This_t &rhs)
Definition: OhmmsMatrix.h:143
bool put(std::istream &is) override
read from std::istream
Definition: ParameterSet.h:42
std::unique_ptr< QMCCostFunctionBase > optTarget
target cost function to optimize
std::bitset< QMC_MODE_MAX > qmc_driver_mode_
bits to classify QMCDriver
Definition: QMCDriverNew.h:103
static Real getLowestEigenvector_Inv(Matrix< Real > &A, Matrix< Real > &B, std::vector< Real > &ev)
Solve the generalized eigenvalue problem and return a scaled eigenvector corresponding to the selecte...
Wrapping information on parallelism.
Definition: Communicate.h:68
RealType shift_i_input
current shift_i, shift_s input values
bool one_shift_run()
Performs one iteration of the linear method using an adaptive scheme that tries three different shift...
IndexType get_num_crowds() const
RealType max_param_change
max amount a parameter may change relative to current wave function weight
static Real getLowestEigenvector_Gen(Matrix< Real > &A, Matrix< Real > &B, std::vector< Real > &ev)
Solve the generalized eigenvalue problem and return a scaled eigenvector corresponding to the selecte...
IndexType get_total_walkers() const
const std::string & get_root_name() const override
Definition: QMCDriverNew.h:331
void readXML(xmlNodePtr xml_input)
omp_int_t omp_get_max_threads()
Definition: OpenMP.h:26
bool is_best_cost(const int ii, const std::vector< RealType > &cv, const std::vector< double > &sh, const RealType ic) const
Returns whether the proposed new cost is the best compared to the others.
QMCFixedSampleLinearOptimizeBatched(const ProjectData &project_data, QMCDriverInput &&qmcdriver_input, const std::optional< EstimatorManagerInput > &global_emi, VMCDriverInput &&vmcdriver_input, WalkerConfigurations &wc, MCPopulation &&population, SampleStack &samples, Communicate *comm)
Constructor.
IndexType get_walkers_per_rank() const
WalkerConfigurations & walker_configs_ref_
Definition: QMCDriverNew.h:481
void product(const Matrix< T > &A, const Matrix< T > &B, Matrix< T > &C)
static function to perform C=AB for real matrices
Compilation units that construct QMCDriverInput need visibility to the actual input classes types in ...
RealType omega_shift
the shift to use when targeting an excited state
Real getLowestEigenvector(Matrix< Real > &A, std::vector< Real > &ev) const
Communicate * myComm
pointer to Communicate
Definition: MPIObjectBase.h:62
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
This a subclass for runtime errors that will occur on all ranks.
void print_cost_summary(const double si, const double ss, const RealType mc, const RealType cv, const int ind, const int bi, const bool gu)
prints a summary of the computed cost for the given shift
Definition of QMCDriver which performs VMC and optimization.
RealType cost_increase_tol
the tolerance to cost function increases when choosing the best shift in the adaptive shift method ...
Tests for variational parameter derivatives.
NewTimer & createGlobalTimer(const std::string &myname, timer_levels mylevel)
int nsamp_comp
number of samples to do in correlated sampling part
NRCOptimizationFunctionWrapper< QMCFixedSampleLinearOptimizeBatched > objFuncWrapper_
RealType target_shift_i
the shift_i value that the adaptive shift method should aim for
std::string MinMethod
name of the current optimization method, updated by processOptXML before run
static QMCDriverNew::AdjustedWalkerCounts adjustGlobalWalkerCount(Communicate &comm, const IndexType current_configs, const IndexType requested_total_walkers, const IndexType requested_walkers_per_rank, const RealType reserve_walkers, int num_crowds)
}@
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
MakeReturn< UnaryNode< FnExp, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t exp(const Vector< T1, C1 > &l)
std::string getXMLAttributeValue(const xmlNodePtr cur, const std::string_view name)
get the value string for attribute name if name is unfound in cur you get an empty string back this i...
void solveShiftsWithoutLMYEngine(const std::vector< double > &shifts_i, const std::vector< double > &shiffts_s, std::vector< std::vector< RealType >> &parameterDirections)
For each set of shifts, solves the linear method eigenproblem by building and diagonalizing the matri...
const TrialWaveFunction & get_golden_twf() const
Definition: MCPopulation.h:178
void output(Matrix< RealType > &mat)
Print matrix to text-formatted scalar.dat file.
void add(PDT &aparam, const std::string &aname_in, std::vector< PDT > candidate_values={}, TagStatus status=TagStatus::OPTIONAL)
add a new parameter corresponding to an xmlNode <parameter>
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
QMCTraits::RealType RealType
void readXML(xmlNodePtr xml_input)
bool create(const std::filesystem::path &fname, unsigned flags=H5F_ACC_TRUNC)
create a file
void processChildren(const xmlNodePtr cur, const F &functor)
process through all the children of an XML element F is a lambda or functor void F/[](const std::stri...
Definition: libxmldefs.h:175
void readXML(xmlNodePtr cur)
Reads qmc section xml node parameters.
bool processOptXML(xmlNodePtr cur, const std::string &vmcMove, bool reportH5, bool useGPU)
process xml node value (parameters for both VMC and OPT) for the actual optimization ...
std::vector< xmlNodePtr > mcwalkerNodePtr
a list of mcwalkerset element
Definition: QMCDriverNew.h:456
RealType max_relative_cost_change
the maximum relative change in the cost function for the adaptive three-shift scheme ...
bool is_manager() const
return true if the rank == 0
Definition: MPIObjectBase.h:51
const ProjectData & project_data_
project info for accessing global fileroot and series id
Definition: QMCDriverNew.h:478
void bcast(T &)
QMCTraits::RealType RealType
Definition: QMCDriverNew.h:78
void finish()
common operation to finish optimization, used by the derived classes
int nstabilizers
Number of iterations maximum before generating new configurations.
std::bitset< 2 > accept_history
accept history, remember the last 2 iterations, value 00, 01, 10, 11
int Max_iterations
Number of iterations maximum before generating new configurations.
double ratio_threshold
threshold for filtering parameters for the lm
void barrier_and_abort(const std::string &msg) const
QMCDriverInput qmcdriver_input_
Definition: QMCDriverNew.h:372
const std::optional< EstimatorManagerInput > global_emi_
This is retained in order to construct and reconstruct the vmcEngine.
void init_file(const std::string &root_name, const std::string &name, int N)
Open a text-formatted scalar.dat file and print the header line.
void add(PDT &aparam, const std::string &aname, std::vector< PDT > candidate_values={}, TagStatus status=TagStatus::OPTIONAL)
add a new attribute
Definition: AttributeSet.h:42
void process(xmlNodePtr cur) override
preprocess xml node
Real getNonLinearRescale(std::vector< Real > &dP, Matrix< Real > &S, const QMCCostFunctionBase &optTarget) const
Input representation for Driver base class runtime parameters.
bool isnan(float a)
return true if the value is NaN.
Definition: math.cpp:18