MADNESS 0.10.1
RestartPlan.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32/// \file RestartPlan.h
33/// \brief decide once, per geometry, where the initial orbitals come from
34
35#ifndef MADNESS_CHEM_RESTARTPLAN_H__INCLUDED
36#define MADNESS_CHEM_RESTARTPLAN_H__INCLUDED
37
38#include <cstdio>
41
42#include <optional>
43#include <string>
44#include <vector>
45
46namespace madness {
47
48/// what the user asked for with the `restart` keyval
49///
50/// `automatic` is spelled "auto" in input files -- `auto` is a C++ keyword.
51enum class RestartMode {
52 automatic, ///< look at what is on disk and choose (the default)
53 none, ///< ignore everything on disk, start from the initial guess
54 iterate, ///< read restartdata and keep iterating
55 read_only, ///< read restartdata and do not iterate, whatever its precision;
56 ///< requires the archive to be for the requested geometry
57 ao, ///< read the AO projections (restartaodata) and iterate
58 nwchem, ///< read an NWChem movecs file and iterate
59};
60
61/// the six spellings accepted by the `restart` keyval, for allowed_values
62inline std::vector<std::string> restart_mode_names() {
63 return {"auto", "none", "iterate", "read_only", "ao", "nwchem"};
64}
65
66inline std::string to_string(const RestartMode m) {
67 switch (m) {
68 case RestartMode::automatic: return "auto";
69 case RestartMode::none: return "none";
70 case RestartMode::iterate: return "iterate";
71 case RestartMode::read_only: return "read_only";
72 case RestartMode::ao: return "ao";
73 case RestartMode::nwchem: return "nwchem";
74 }
75 return "auto";
76}
77
78/// parse the `restart` keyval
79///
80/// Throws on an unknown spelling. The keyval carries allowed_values, so
81/// QCParameter normally rejects a bad string before this is ever reached; this
82/// check is the backstop for values set programmatically.
83inline RestartMode restart_mode_from_string(const std::string& s) {
84 if (s == "auto") return RestartMode::automatic;
85 if (s == "none") return RestartMode::none;
86 if (s == "iterate") return RestartMode::iterate;
87 if (s == "read_only") return RestartMode::read_only;
88 if (s == "ao") return RestartMode::ao;
89 if (s == "nwchem") return RestartMode::nwchem;
90 MADNESS_EXCEPTION("unknown restart mode", 1);
91}
92
93/// where the initial orbitals will come from
94enum class RestartSource : int {
95 initial_guess = 0, ///< atomic guess, i.e. no restart at all
96 restartdata = 1, ///< <prefix>.restartdata, MRA orbitals
97 restartao = 2, ///< <prefix>.restartaodata, AO expansion coefficients
98 nwchem = 3, ///< an NWChem movecs file
99};
100
101inline std::string to_string(const RestartSource s) {
102 switch (s) {
103 case RestartSource::restartdata: return "restartdata";
104 case RestartSource::restartao: return "restartaodata";
105 case RestartSource::nwchem: return "nwchem";
106 default: return "initial_guess";
107 }
108}
109
110/// what a look at the disk found -- pure disk facts, no engine opinion in here
111///
112/// Separated from the decision so that plan_restart() stays a pure function of
113/// its arguments and the whole decision table can be tested without touching a
114/// filesystem or constructing an MRA function.
116
117 /// <prefix>.restartdata.00000 exists
119
120 /// its header parsed. Set only when restartdata_present; a present file with
121 /// no metadata is a corrupt or future-version archive, which is worth saying
122 /// out loud rather than quietly recomputing.
123 std::optional<RestartMetadata> meta;
124
125 /// alpha orbitals in the archive, 0 when unknown
126 std::size_t nmo_alpha = 0;
127
128 /// <prefix>.restartaodata exists
129 bool restartao_present = false;
130
131 /// an NWChem file was named in the input
132 bool nwfile_named = false;
133};
134
135/// which restart sources the asking engine can actually read
136///
137/// Not every engine can read every source, and pretending otherwise turns a
138/// clear "not implemented" into a confusing "file not found". moldft can read
139/// all of them; nemo can read neither the AO projections (`SCF::restart_aos` is
140/// reachable only from `SCF::get_initial_orbitals`, which nemo never calls, and
141/// the file holds <AO|psi> where nemo needs <AO|F>) nor NWChem movecs.
143 bool ao = false; ///< can read <prefix>.restartaodata
144 bool nwchem = false; ///< can read an NWChem movecs file
145
146 static RestartCapabilities all() { return {true, true}; }
147 static RestartCapabilities restartdata_only() { return {false, false}; }
148};
149
150/// how the requested geometry relates to the one in an archive
151enum class GeometryMatch {
152 same, ///< same atoms at the same places
153 displaced, ///< same atoms, moved -- e.g. a geometry optimization step
154 different_composition, ///< different atoms altogether
155};
156
157/// compare two molecules, atom by atom and in order
158///
159/// Order matters: the orbitals in an archive are expanded about the atoms in
160/// the order the archive's molecule lists them, so a permuted molecule is not
161/// the same molecule as far as restart is concerned.
162// Tolerance: 1e-6 bohr. MRA orbitals at thresh 1e-6 do not resolve smaller
163// displacements, and the same geometry reaches an archive through different
164// parsers at slightly different precision (madqc Params vs moldft's own read
165// differed by 4e-8 bohr on 2026-09-10 and a DALTON-seeded restartdata was
166// rejected as "geometry moved"). A real optimization step moves atoms by
167// >= 1e-4 bohr.
168inline GeometryMatch compare_geometry(const Molecule& archive, const Molecule& requested,
169 const double tol = 1.e-6) {
170 if (archive.natom() != requested.natom()) return GeometryMatch::different_composition;
171 for (std::size_t i = 0; i < requested.natom(); ++i) {
172 if (archive.get_atomic_number(i) != requested.get_atomic_number(i))
174 }
175 for (std::size_t i = 0; i < requested.natom(); ++i) {
176 const Atom a = archive.get_atom(i);
177 const Atom b = requested.get_atom(i);
178 if (std::abs(a.x - b.x) > tol or std::abs(a.y - b.y) > tol or
179 std::abs(a.z - b.z) > tol)
181 }
182 return GeometryMatch::same;
183}
184
185/// the decision: one source, one starting rung, one reason
187
188 RestartMode mode = RestartMode::automatic; ///< what was asked for
190
191 /// false means "return what is on disk without solving anything"
192 bool iterate = true;
193
194 /// rung of `protocol()` to start at; rungs below it are already covered
195 std::size_t protocol_start = 0;
196
197 /// energy from the archive, meaningful only when iterate==false
198 double stale_energy = 1.e10;
199
200 /// true if this decision should be logged as a WARNING rather than as info
201 ///
202 /// Two cases: a file was there but could not be used (silently recomputing
203 /// would hide a disk fault or a wrong prefix), and read_only handing back an
204 /// energy that does not meet the requested precision.
205 bool warn = false;
206
207 /// one line, for the log and for the results json
208 std::string why;
209
210 /// alpha orbitals the archive holds when source is restartdata, 0 when unknown.
211 /// Fewer than requested means the missing virtuals start from the atomic guess.
212 std::size_t archive_nmo_alpha = 0;
213
214 /// when source is restartdata: the header records a convergence at some
215 /// rung, and its eprec, xc and nuclear correlation factor agree with this run's
216 bool archive_converged = false;
218
219 /// true if orbitals have to be read from disk before anything else happens
221
222 std::string print_to_string() const {
223 return "restart " + madness::to_string(mode) + ": from " +
224 madness::to_string(source) + ", " +
225 (iterate ? "starting at protocol rung " + std::to_string(protocol_start)
226 : std::string("no iterations")) +
227 " -- " + why;
228 }
229
230 /// serialization, so the plan can be decided on one rank and broadcast
231 template <typename Archive>
232 void serialize(Archive& ar) {
233 int m = static_cast<int>(mode);
234 int s = static_cast<int>(source);
237 mode = static_cast<RestartMode>(m);
238 source = static_cast<RestartSource>(s);
239 }
240};
241
242/// format a threshold compactly for a log line ("1e-06", not "0.000001")
243inline std::string format_thresh(const double t) {
244 std::stringstream ss;
245 ss << std::scientific << std::setprecision(0) << t;
246 return ss.str();
247}
248
249/// index of the first protocol rung that is tighter than an achieved precision
250///
251/// nullopt means the ladder holds nothing tighter, i.e. the archive already
252/// covers every rung. The 0.999 slack absorbs the round trip of a threshold
253/// through an archive; without it a run converged to 1e-6 can fail to recognize
254/// the 1e-6 rung as covered.
255inline std::optional<std::size_t>
256first_rung_tighter_than(const std::vector<double>& protocol, const double achieved) {
257 for (std::size_t i = 0; i < protocol.size(); ++i)
258 if (protocol[i] < achieved * 0.999) return i;
259 return std::nullopt;
260}
261
262/// decide where the initial orbitals come from -- the whole decision table
263///
264/// Pure: no filesystem, no MPI, no MRA. That is the point of the split, and it
265/// is what makes the table testable line by line (test_restart.cc).
266///
267/// @param[in] mode the user's `restart` keyval
268/// @param[in] disk what survey_restart_sources() found
269/// @param[in] can which sources the asking engine can read
270/// @param[in] protocol the precision ladder, `CalculationParameters::protocol()`
271/// @param[in] user_dconv the user's `dconv`
272/// @param[in] requested the geometry this calculation is for
273/// @param[in] wanted the representation the asking engine stores (mo/nemo/znemo)
274/// @param[in] eprec the requested molecular smoothing parameter; 0 skips the
275/// check, which is what a caller that does not know it passes
276/// @param[in] xc the requested exchange-correlation functional; an empty
277/// string skips the check
278/// @param[in] ncf the requested nuclear correlation factor, e.g. "slater:2.0";
279/// empty for an engine that has none, and skips the check
280inline RestartPlan plan_restart(const RestartMode mode, const RestartSources& disk,
281 const RestartCapabilities& can,
282 const std::vector<double>& protocol,
283 const double user_dconv, const Molecule& requested,
284 const Representation wanted,
285 const double eprec = 0.0,
286 const std::string& xc = "",
287 const std::string& ncf = "",
288 const std::size_t nmo_alpha = 0) {
289
290 MADNESS_CHECK_THROW(not protocol.empty(), "empty protocol in plan_restart");
291 const std::size_t last = protocol.size() - 1;
292
293 const bool ao_available = disk.restartao_present and can.ao;
294 const bool nwchem_available = disk.nwfile_named and can.nwchem;
295
296 // the precision this run has to reach. dconv cannot be demanded tighter
297 // than the final rung represents, which is what SCFProtocol also does.
298 const double target_thresh = protocol.back();
299 const double target_dconv = std::max(target_thresh, user_dconv);
300
301 RestartPlan plan;
302 plan.mode = mode;
303 plan.archive_nmo_alpha = disk.nmo_alpha;
304
305 // an archive with fewer orbitals than requested (virtuals added on restart)
306 // is a guess for the missing ones, whatever its convergence claim says
307 const bool pads_virtuals = nmo_alpha > 0 and disk.nmo_alpha > 0 and disk.nmo_alpha < nmo_alpha;
308
309 // does the archive solve the same Hamiltonian this run is asking about?
310 //
311 // eprec, xc and the nuclear correlation factor all change the operator, not
312 // just its representation: orbitals from a different one are a perfectly good
313 // guess, but their convergence claim is about another problem, and -- unlike a
314 // k or thresh mismatch -- that cannot be repaired by reprojecting. An unset
315 // value on either side (0.0 / "") means "not recorded" -- v4 archives, the
316 // seeding tools, and engines that have no ncf -- which is not evidence of a
317 // mismatch. Returns an empty string when the Hamiltonians agree, otherwise the
318 // phrase that goes into `why`.
319 auto hamiltonian_mismatch = [&](const RestartMetadata& meta) {
320 if (meta.eprec != 0.0 and eprec != 0.0 and
321 std::abs(meta.eprec / eprec - 1.0) > 1.e-10)
322 return "archive was written at eprec " + format_thresh(meta.eprec) +
323 ", this run uses " + format_thresh(eprec);
324 if (not meta.xc.empty() and not xc.empty() and meta.xc != xc)
325 return "archive was written with xc '" + meta.xc + "', this run uses '" +
326 xc + "'";
327 if (not meta.ncf.empty() and not ncf.empty() and meta.ncf != ncf)
328 return "archive was written with the nuclear correlation factor '" +
329 meta.ncf + "', this run uses '" + ncf + "'";
330 return std::string();
331 };
332
333 // ---- fall back to the initial guess, recording why ---------------------
334 auto give_up = [&](const std::string& why) {
336 plan.iterate = true;
337 plan.protocol_start = 0;
338 plan.why = why;
339 return plan;
340 };
341
342 // ---- use restartdata, iterating from wherever it left off --------------
343 // what the archive's header says about the orbitals it holds
344 auto describe_archive = [&](const RestartMetadata& meta) {
345 plan.archive_converged = meta.converged_for_thresh < 1.0;
346 plan.archive_same_hamiltonian = hamiltonian_mismatch(meta).empty();
347 };
348
349 auto continue_from_archive = [&](const RestartMetadata& meta, const std::string& why) {
351 plan.stale_energy = meta.current_energy;
352 describe_archive(meta);
353 const auto rung = first_rung_tighter_than(protocol, meta.converged_for_thresh);
354 plan.iterate = true;
355 plan.protocol_start = rung.value_or(last);
356 plan.why = why;
357 return plan;
358 };
359
360 if (mode == RestartMode::none) {
361 // Contradictory input, and worth saying so here: with `nwfile` set, the AO
362 // basis itself is read from the NWChem file (SCF's ctor), so there is no
363 // atomic guess left to fall back to and SCF::initial_guess asserts with a
364 // message that explains nothing.
365 MADNESS_CHECK_THROW(not nwchem_available,
366 "restart none together with `nwfile`: the AO basis is read from the "
367 "nwchem file, so there is no atomic guess to fall back to. Use "
368 "restart=nwchem, or drop the `nwfile` keyval.");
369 return give_up("restart none: ignoring anything on disk");
370 }
371
372 // ---- explicitly requested sources: never fall back silently ------------
373 //
374 // A silent fallback here burns hours: the user asked to resume a long run
375 // and would get a fresh one instead, indistinguishable from the outside
376 // until the wall clock says so.
377 if (mode == RestartMode::nwchem) {
379 "restart nwchem: this calculation cannot read NWChem orbitals");
381 "restart nwchem: no nwchem file given -- set the `nwfile` keyval");
383 plan.iterate = true;
384 plan.protocol_start = 0;
385 plan.why = "restart nwchem: as requested";
386 return plan;
387 }
388
389 if (mode == RestartMode::ao) {
391 "restart ao: this calculation cannot read AO projections");
393 "restart ao: no restartaodata file found");
395 plan.iterate = true;
396 plan.protocol_start = 0;
397 plan.why = "restart ao: as requested";
398 return plan;
399 }
400
401 if (mode == RestartMode::iterate or mode == RestartMode::read_only) {
403 "restart iterate/read_only: no restartdata archive found");
404 MADNESS_CHECK_THROW(disk.meta.has_value(),
405 "restart iterate/read_only: the restartdata archive could not be read");
406 const RestartMetadata& meta = disk.meta.value();
408 "restart iterate/read_only: the restartdata archive holds a different "
409 "kind of orbital than this calculation uses");
410
411 if (mode == RestartMode::read_only) {
412 // Precision is the user's call to make; the geometry is not. read_only
413 // hands back meta.current_energy without solving anything, so at a
414 // displaced geometry it would report an energy for a molecule nobody
415 // asked about -- and unlike a loose threshold, that cannot be what the
416 // user meant. `iterate` needs no such check: there the orbitals are
417 // only a starting guess and the SCF runs at the requested geometry.
420 "restart read_only: archive geometry does not match the requested geometry");
421 MADNESS_CHECK_THROW(not pads_virtuals,
422 "restart read_only: the archive holds fewer orbitals than requested");
423 // The user asserted these orbitals are the answer. Respect that even
424 // when they are not converged to the requested precision -- warn and
425 // hand back the stale energy rather than second-guessing.
427 plan.iterate = false;
428 plan.protocol_start = last;
429 plan.stale_energy = meta.current_energy;
430 describe_archive(meta);
431 const std::string other = hamiltonian_mismatch(meta);
432 if (not other.empty()) {
433 // Not overridden -- the user asked for these orbitals and gets
434 // them -- but handing back an energy for a different Hamiltonian
435 // without saying so is how a wrong number ends up in a table.
436 plan.warn = true;
437 plan.why = "restart read_only: " + other +
438 " -- returning the archive's energy for a DIFFERENT "
439 "Hamiltonian, as requested";
440 return plan;
441 }
442 const bool good = meta.is_converged_to(target_thresh, target_dconv);
443 plan.warn = not good;
444 plan.why = good
445 ? "restart read_only: archive is converged to the requested precision"
446 : "restart read_only: archive is converged only to thresh " +
447 format_thresh(meta.converged_for_thresh) + " dconv " +
448 format_thresh(meta.converged_for_dconv) + ", NOT to the requested " +
449 format_thresh(target_thresh) + "/" + format_thresh(target_dconv) +
450 " -- returning its energy anyway, as requested";
451 return plan;
452 }
453 // iterate: honour the request even if the archive already looks converged,
454 // and in that case re-verify at the final rung rather than doing nothing.
455 return continue_from_archive(meta, "restart iterate: as requested");
456 }
457
458 // ---- automatic ---------------------------------------------------------
460
461 if (not disk.restartdata_present) {
462 // nwchem before the AO projections, which reverses the order the old
463 // precedence ladder used (SCF::get_initial_orbitals: restartdata, ao,
464 // NWChem, guess). Naming a file in the input is a statement of intent; a
465 // leftover restartaodata is not. In practice the two rarely coexist --
466 // save_mos deliberately writes no restartaodata when nwfile is set,
467 // because the AO basis then comes from the nwchem file.
468 if (nwchem_available) {
470 plan.why = "restart auto: no restartdata, but an nwchem file was given";
471 return plan;
472 }
473 if (ao_available) {
475 plan.why = "restart auto: no restartdata, using the AO projections";
476 return plan;
477 }
478 return give_up("restart auto: nothing on disk");
479 }
480
481 // a file is there. Anything below this point that rejects it is a surprise
482 // and must be reported, not swallowed.
483 auto reject_archive = [&](const std::string& why) {
484 plan.warn = true;
485 if (ao_available) {
487 plan.iterate = true;
488 plan.protocol_start = 0;
489 plan.why = why + "; using the AO projections instead";
490 return plan;
491 }
492 return give_up(why + "; starting from the initial guess instead");
493 };
494
495 if (not disk.meta.has_value())
496 return reject_archive("restart auto: restartdata exists but its header could "
497 "not be read (truncated, or written by a newer MADNESS)");
498
499 const RestartMetadata& meta = disk.meta.value();
500
501 if (not meta.representation_matches(wanted))
502 return reject_archive("restart auto: restartdata holds '" +
504 "' orbitals, this calculation wants '" +
505 madness::to_string(wanted) + "'");
506
507 const GeometryMatch geom = compare_geometry(meta.molecule, requested);
509 // Not a fault: a different molecule in the same directory. The AO file
510 // is indexed by the same atoms, so it is no better.
511 plan.warn = false;
512 return give_up("restart auto: restartdata is for a different molecule");
513 }
514 if (geom == GeometryMatch::displaced) {
515 // A geometry optimization step. MRA orbitals at the old geometry are
516 // wrong where it matters most -- at the nuclei -- so go through the AO
517 // expansion, which is re-centred on the new positions.
518 if (ao_available) {
520 plan.iterate = true;
521 plan.protocol_start = 0;
522 plan.why = "restart auto: geometry moved, using the AO projections";
523 return plan;
524 }
525 {
526 // say by how much: a sub-1e-8 mismatch (10-digit coordinates from
527 // another program) reads very differently from a real optimization step
528 double dmax = 0.0; std::size_t imax = 0;
529 for (std::size_t i = 0; i < requested.natom(); ++i) {
530 const Atom a = meta.molecule.get_atom(i), b = requested.get_atom(i);
531 const double d = std::max({std::abs(a.x - b.x), std::abs(a.y - b.y), std::abs(a.z - b.z)});
532 if (d > dmax) { dmax = d; imax = i; }
533 }
534 char buf[160];
535 std::snprintf(buf, sizeof buf, " (max |dR| = %.3e bohr at atom %zu; tolerance 1e-6)", dmax, imax);
536 return give_up(std::string("restart auto: geometry moved and no AO projections available") + buf);
537 }
538 }
539
540 // A different eprec, functional or nuclear correlation factor is a different
541 // Hamiltonian: keep the orbitals as a guess, but throw away the archive's
542 // convergence claim, which is about another problem. Without this an
543 // `xc=lda` run in a directory holding a converged `xc=hf` archive skips the
544 // SCF entirely and reports the HF energy.
545 const std::string other = hamiltonian_mismatch(meta);
546 if (not other.empty())
547 return continue_from_archive(meta, "restart auto: " + other +
548 " -- a different Hamiltonian, so re-converging");
549
550 if (pads_virtuals)
551 return continue_from_archive(meta, "restart auto: archive holds " + std::to_string(disk.nmo_alpha) +
552 " alpha orbitals, " + std::to_string(nmo_alpha) +
553 " requested; the missing virtuals start from the atomic guess");
554
555 if (meta.is_converged_to(target_thresh, target_dconv)) {
557 plan.iterate = false;
558 plan.protocol_start = last;
559 plan.stale_energy = meta.current_energy;
560 describe_archive(meta);
561 plan.why = "restart auto: archive is converged to thresh " +
562 format_thresh(target_thresh) + " and dconv " +
563 format_thresh(target_dconv);
564 return plan;
565 }
566
567 return continue_from_archive(meta, "restart auto: archive converged only to thresh " +
569 " dconv " + format_thresh(meta.converged_for_dconv) +
570 ", continuing");
571}
572
573/// look at the disk: what restart data is there?
574///
575/// The existence tests run on rank 0 and are broadcast, so ranks cannot diverge
576/// on them. peek_restartdata() is collective by construction (the parallel
577/// archive broadcasts what it reads), so every rank passes through it together
578/// or none does.
579inline RestartSources survey_restart_sources(World& world, const std::string& prefix,
580 const bool nwfile_named) {
581 RestartSources disk;
582 disk.nwfile_named = nwfile_named;
583
584 int flags[2] = {0, 0};
585 if (world.rank() == 0) {
586 flags[0] = restartdata_exists(prefix + ".restartdata") ? 1 : 0;
587 flags[1] = std::filesystem::exists(prefix + ".restartaodata") ? 1 : 0;
588 }
589 world.gop.broadcast(flags, 2, 0);
590 disk.restartdata_present = (flags[0] == 1);
591 disk.restartao_present = (flags[1] == 1);
592
593 if (disk.restartdata_present) {
594 disk.meta = peek_restartdata(world, prefix + ".restartdata");
595 if (const auto summary = peek_restartdata_summary(world, prefix + ".restartdata"))
596 disk.nmo_alpha = summary->nmo_alpha;
597 }
598 return disk;
599}
600
601/// survey the disk and decide, identically on every rank
602///
603/// Agreement between ranks is the point. Ranks that disagree about where the
604/// orbitals come from diverge on collective Function construction and hang -- a
605/// hang is a far worse failure than a wrong answer, because it leaves nothing to
606/// debug. Two things secure it:
607///
608/// * every input to plan_restart() is already rank-invariant -- the existence
609/// tests are broadcast by survey_restart_sources(), the header is broadcast by
610/// the parallel archive, and the parameters and molecule are replicated -- so
611/// all ranks run the decision and any throw from an explicitly requested but
612/// missing source is collective rather than a rank-0 abort into a hang;
613/// * the result is then broadcast anyway, so the "identical inputs, identical
614/// output" argument does not have to stay true for correctness.
615///
616/// @param[in] can which sources the asking engine can read; see RestartCapabilities
617/// @param[in] ncf the nuclear correlation factor this run uses (SCF::restart_ncf);
618/// empty for an engine that has none
621 const Molecule& requested,
622 const Representation wanted,
623 const RestartCapabilities& can,
624 const std::string& ncf = "") {
625
626 const RestartSources disk =
627 survey_restart_sources(world, param.prefix(), param.nwfile() != "none");
628
629 RestartPlan plan = plan_restart(mode, disk, can, param.protocol(), param.dconv(),
630 requested, wanted, requested.parameters.eprec(),
631 param.xc(), ncf, std::size_t(param.nmo_alpha()));
632 world.gop.broadcast_serializable(plan, 0);
633
634 if (world.rank() == 0 and param.print_level() > 1) {
635 if (plan.warn) print("WARNING:", plan.why);
636 else print(plan.print_to_string());
637 if (disk.meta.has_value() and param.print_level() > 2)
638 print(" archive:", disk.meta.value().print_to_string());
639 }
640 return plan;
641}
642
643} // namespace madness
644
645#endif // MADNESS_CHEM_RESTARTPLAN_H__INCLUDED
the header of a restartdata archive, in one place
Definition molecule.h:60
Definition molecule.h:129
const Atom & get_atom(unsigned int i) const
Definition molecule.cc:502
size_t natom() const
Definition molecule.h:463
unsigned int get_atomic_number(unsigned int i) const
Definition molecule.cc:430
GeometryParameters parameters
Definition molecule.h:334
void broadcast_serializable(objT &obj, ProcessID root)
Broadcast a serializable object.
Definition worldgop.h:774
void broadcast(void *buf, size_t nbyte, ProcessID root, bool dowork=true, Tag bcast_tag=-1)
Broadcasts bytes from process root while still processing AM & tasks.
Definition worldgop.cc:189
A parallel world class.
Definition world.h:134
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
WorldGopInterface & gop
Global operations.
Definition world.h:216
static const double eprec
Definition hatom_sf_dirac.cc:18
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_CHECK_THROW(condition, msg)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:207
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
std::string to_string(const Representation r)
Definition Restart.h:64
std::optional< std::size_t > first_rung_tighter_than(const std::vector< double > &protocol, const double achieved)
Definition RestartPlan.h:256
RestartPlan plan_restart(const RestartMode mode, const RestartSources &disk, const RestartCapabilities &can, const std::vector< double > &protocol, const double user_dconv, const Molecule &requested, const Representation wanted, const double eprec=0.0, const std::string &xc="", const std::string &ncf="", const std::size_t nmo_alpha=0)
Definition RestartPlan.h:280
std::string format_thresh(const double t)
format a threshold compactly for a log line ("1e-06", not "0.000001")
Definition RestartPlan.h:243
bool restartdata_exists(const std::string &filename)
Definition Restart.h:298
std::optional< RestartSummary > peek_restartdata_summary(World &world, const std::string &filename)
Definition Restart.h:260
RestartMode
Definition RestartPlan.h:51
@ automatic
look at what is on disk and choose (the default)
@ none
ignore everything on disk, start from the initial guess
@ iterate
read restartdata and keep iterating
@ ao
read the AO projections (restartaodata) and iterate
@ nwchem
read an NWChem movecs file and iterate
RestartMode restart_mode_from_string(const std::string &s)
Definition RestartPlan.h:83
RestartPlan make_restart_plan(World &world, const RestartMode mode, const CalculationParameters &param, const Molecule &requested, const Representation wanted, const RestartCapabilities &can, const std::string &ncf="")
Definition RestartPlan.h:619
RestartSources survey_restart_sources(World &world, const std::string &prefix, const bool nwfile_named)
Definition RestartPlan.h:579
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:227
std::optional< RestartMetadata > peek_restartdata(World &world, const std::string &filename)
Definition Restart.h:223
RestartSource
where the initial orbitals will come from
Definition RestartPlan.h:94
@ initial_guess
atomic guess, i.e. no restart at all
@ restartdata
<prefix>.restartdata, MRA orbitals
@ restartao
<prefix>.restartaodata, AO expansion coefficients
@ nwchem
an NWChem movecs file
GeometryMatch compare_geometry(const Molecule &archive, const Molecule &requested, const double tol=1.e-6)
Definition RestartPlan.h:168
GeometryMatch
how the requested geometry relates to the one in an archive
Definition RestartPlan.h:151
@ different_composition
different atoms altogether
@ same
same atoms at the same places
@ displaced
same atoms, moved – e.g. a geometry optimization step
Representation
Definition Restart.h:57
std::vector< std::string > restart_mode_names()
the six spellings accepted by the restart keyval, for allowed_values
Definition RestartPlan.h:62
static long abs(long a)
Definition tensor.h:219
XCfunctional xc
Definition newsolver_lda.cc:53
static const double b
Definition nonlinschro.cc:119
static const double d
Definition nonlinschro.cc:121
static const double a
Definition nonlinschro.cc:118
static const double m
Definition relops.cc:9
std::string prefix
Definition tdse.cc:71
Definition CalculationParameters.h:51
double eprec() const
Definition molecule.h:306
Definition RestartPlan.h:142
static RestartCapabilities restartdata_only()
Definition RestartPlan.h:147
bool nwchem
can read an NWChem movecs file
Definition RestartPlan.h:144
static RestartCapabilities all()
Definition RestartPlan.h:146
bool ao
can read <prefix>.restartaodata
Definition RestartPlan.h:143
Definition Restart.h:105
bool is_converged_to(const double thresh, const double dconv) const
true if these orbitals are at least as converged as the request
Definition Restart.h:186
double converged_for_dconv
Definition Restart.h:127
bool representation_matches(const Representation wanted) const
Definition Restart.h:195
Molecule molecule
Definition Restart.h:117
double converged_for_thresh
Definition Restart.h:120
Representation representation
what the stored functions are; see Representation
Definition Restart.h:130
double current_energy
Definition Restart.h:113
the decision: one source, one starting rung, one reason
Definition RestartPlan.h:186
RestartSource source
Definition RestartPlan.h:189
bool warn
Definition RestartPlan.h:205
bool needs_load() const
true if orbitals have to be read from disk before anything else happens
Definition RestartPlan.h:220
std::size_t protocol_start
rung of protocol() to start at; rungs below it are already covered
Definition RestartPlan.h:195
bool iterate
false means "return what is on disk without solving anything"
Definition RestartPlan.h:192
std::size_t archive_nmo_alpha
Definition RestartPlan.h:212
bool archive_same_hamiltonian
Definition RestartPlan.h:217
double stale_energy
energy from the archive, meaningful only when iterate==false
Definition RestartPlan.h:198
std::string why
one line, for the log and for the results json
Definition RestartPlan.h:208
RestartMode mode
what was asked for
Definition RestartPlan.h:188
std::string print_to_string() const
Definition RestartPlan.h:222
bool archive_converged
Definition RestartPlan.h:216
void serialize(Archive &ar)
serialization, so the plan can be decided on one rank and broadcast
Definition RestartPlan.h:232
Definition RestartPlan.h:115
bool restartao_present
<prefix>.restartaodata exists
Definition RestartPlan.h:129
bool restartdata_present
<prefix>.restartdata.00000 exists
Definition RestartPlan.h:118
bool nwfile_named
an NWChem file was named in the input
Definition RestartPlan.h:132
std::size_t nmo_alpha
alpha orbitals in the archive, 0 when unknown
Definition RestartPlan.h:126
std::optional< RestartMetadata > meta
Definition RestartPlan.h:123
Definition dirac-hatom.cc:112
ncf(double gamma, double a, double Z)
Definition dirac-hatom.cc:116
InputParameters param
Definition tdse.cc:203