From 76f170983cce607dcafcb7a9f0e8171e74c78b5f Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 01/12] Read the Gaussian stability verdict and the spin diagnostic out of ESS logs Two ESS-log readers that nothing in ARC could previously perform, plus the real logs that pin them. Neither is wired to a caller here; later commits consume them. THE WAVEFUNCTION STABILITY VERDICT. Gaussian's documentation states that "analytic frequency calculations are only valid if the wavefunction has no internal instabilities". ARC runs a freq job on every TS, so that precondition was assumed and never tested, and for a restricted singlet TS it cannot even be inferred after the fact, because a restricted wavefunction prints no . parse_wavefunction_stability reads a stable=(rext,noopt) log and returns the verdict, the label and eigenvalue of each negative stability-matrix eigenvalue, and whether the analytic frequencies are invalidated. Whether an instability bears on the frequencies depends on the reference: Gaussian's rule is that a restricted wavefunction need only be free of singlet, i.e. internal, instabilities, while for an unrestricted one any instability invalidates the analytic frequencies. The reference is read from the log's own SCF Done: E(RwB97XD) / E(UwB97XD) line rather than predicted from the species, so the verdict and its consequence are derived once, here, from what Gaussian actually did; the scheduler line and output.yml both read that single result instead of recomputing it. A log that ran an analysis but whose verdict could not be read is reported as 'unknown', never as 'stable', so a gap in the recognised phrasings cannot pass for a clean bill of health, and invalidates_analytic_freq is left undecided rather than guessed when the reference cannot be read. A log with no stability analysis at all returns None. A STABLE UNRESTRICTED GAUSSIAN VERDICT REPORTS external_instability AS None RATHER THAN False, WHICH CHANGES WHAT THE GAUSSIAN READER RETURNS for that case. All four Gaussian fixtures, both UB3LYP ones included, hold exactly one singles matrix and no UHF instability, a stable restricted singlet, a stable unrestricted doublet, and a stable spin-contaminated doublet. They establish two things the parser had assumed otherwise. A RExt run emits one analysis with one verdict line, not an internal and an external one. And the eigenvector symmetry label follows the reference: restricted logs label roots by spin (Triplet-A), unrestricted logs label them by the root's own spin expectation value (2.012-A). Reading the reference off the SCF Done line is confirmed on all four. THE S**2 SPIN-CONTAMINATION DIAGNOSTIC, RE-HOMED FROM AN ARCBENCH-BASED BRANCH. parse_s_squared, s_squared_expected_from_multiplicity, the ESSAdapter default and the Gaussian / ORCA / Q-Chem implementations come from feature_s_squared_spin_ diagnostic, with the Gaussian anchoring fix of fix_s_squared_stability_eigenvector folded in rather than applied afterwards, so the pre-fix parser is never present in this history. Left behind deliberately: that branch's arc/tckdb/ payload builder and its attachment to the sp calc, because arc/tckdb/ does not exist on main and bringing the builder would have meant inventing the module around it. The output.yml key it reads, sp_spin_diagnostic, is brought in the same shape and key names, so the arcbench-side emitter binds to it unchanged. WHY parse_s_squared SURVIVED OVER parse_spin_squared. A second, independently written Gaussian reader returning a bare float existed on a third branch. The two were compared line by line before discarding one. They agree on everything that could have made this a semantic merge rather than a deletion: both anchor on a line carrying = and exclude the Initial guess line, so neither reads a Stable job's Eigenvector root spin as the reference's; both take the last such line, so both report the converged SCF rather than an earlier cycle; both take the value BEFORE annihilation of the first spin contaminant; and both return None for a restricted reference, which prints no spin line at all. Two differences were adjudicated: Return shape. The dict is kept. A bare float discards the annihilated value and the ideal S(S+1), both of which output.yml records, and cannot express "read the reference, but the log states no multiplicity". Numeric spelling. Fixed-point is kept over accepting a Fortran D exponent: Gaussian's spin line and its "S**2 before annihilation" line are both fixed-format F fields, and the D tolerance was speculative rather than fixture-driven. Keeping the deployed regex also keeps this file from diverging from the copy running the benchmark. The choice is stated in parse_s_squared's docstring so it is not silently re-litigated. Gaussian multiplicity anchoring takes the FIRST 'Charge = C Multiplicity = M' line: it is the symbolic Z-matrix echo of the job's own molecule specification, while any later one declares the multiplicity of a single fragment of a guess=fragment calculation, which is not the wavefunction's. arc/testing/spin/uhf_fragment_guess_doublet.out pins it. The initial-guess exclusion is pinned by a fixture that can only be read correctly with the guard in place: arc/testing/spin/uhf_died_before_scf_septet.out is a real septet that printed 'Initial guess ... =12.0000' and then died in l502 on an inaccurate quadrature before any SCF Done. Without the guard the parser reports 12.0000, exactly S(S+1) for a septet, as a converged diagnostic of a wavefunction that never existed. With it the file yields None. Extracted, not fabricated. ORCA needs no equivalent anchoring: across all six ORCA fixtures the string 'Expectation value of ' occurs only inside the UHF SPIN CONTAMINATION block following a converged SCF, and MDCI's '(linearized)' does not contain it. 'Last wins' is correct there and is now pinned. What was fixed is that 'Expectation value' and 'Ideal value' were latched independently, so a block missing its Ideal line would have inherited an earlier block's; the expected value is now reset when a new expectation value is read, tying the pair to one block. The vestigial `and 'Mult' in line` is removed: 'Mult' is a substring of 'Multiplicity', so the condition was unconditionally true. Cross-ESS multiplicity rules are assessed and left alone. Gaussian and Q-Chem take the first declaration, ORCA the last; each is right for its own format's dominant multi-declaration case, and all three are fallbacks only. The restricted contract is assessed and left alone. An RHF/RKS determinant is an exact eigenfunction of S**2 with = S(S+1) exactly, and returning None for it conflates that with a parse failure. Returning the exact value would need a new reference-detection sniffer in each of the three adapters purely to undo what the parser just did, and would split the base class's contract under which None means 'no diagnostic available' for Molpro and CFOUR alike. ESSAdapter.parse_s_squared's docstring now states the conflation so a consumer knows to compute the restricted value from the species' multiplicity instead of reading a log. Deferred cleanup: s_squared_expected_from_multiplicity is homed in arc/parser/parser.py but does no parsing; it is pure spin arithmetic and belongs in arc/checks/spin.py. It duplicates nothing (checked). Moving it would touch three more adapters, so it is recorded here rather than done. Verified by mutation, not only by a green run. Making the Gaussian S**2 reader return None unconditionally fails 13 tests; restoring the pre-fix anchoring, which reads the last = line whatever it sits on, fails 5, including the restricted Stable log that then reports a fabricated diagnostic where its contract is None; making the ORCA and Q-Chem readers return None fails 4 and 1; taking the last Gaussian multiplicity fails 1; dropping the initial-guess guard fails 1; deleting the ESS s_squared_expected fallback fails 1. ORCA reads the same verdict out of its own logs. OrcaParser gains parse_wavefunction_stability, returning the schema GaussianParser returns plus two keys for behaviour Gaussian has no equivalent of, and ESSAdapter gains a base declaration returning None so the parser can be dispatched to any ESS, as parse_s_squared already could. THE FIRST ANALYSIS IS THE ONE UNDER TEST. ORCA 6.0.0 aborts in LEANSCF on an unstable wavefunction unless it is told to follow the instability, so ARC always sets STABRestartUHFifUnstable true and an unstable log therefore holds TWO analyses with opposite verdicts: the wavefunction the frequency job built its Hessian from, then the solution ORCA relaxed into. The verdict, the lowest eigenvalue and the negative roots are read from the first; n_analyses and followed_to_stable report the second without overwriting it. The reference is read from the HFTyp line preceding the first analysis, so a restart to an unrestricted solution does not rewrite the reference tested. BOTH CODES TEST THE SAME SPACE, and the flags follow from that. ORCA analyses RHF/RKS in UHF/UKS space and UHF/UKS in UHF/UKS space, both Ms-conserving; all four Gaussian fixtures print 'Stability analysis using singles matrix', which is the same Ms-conserving block, and Gaussian's Ms-changing block appears in none of them. Neither code reaches the GHF sector, so neither verdict is the weaker one. The verdicts agreed on all four measured systems, and at matched functional (ORCA's B3LYP/G is Gaussian's VWN3; plain ORCA B3LYP uses VWN-5) the lowest roots agree to under 0.4% on the three systems where both codes found the same SCF solution. The fourth, a near-dissociated O(3P)...CH3 pair at r(O-C) = 3.78 A, has the two codes converged to DIFFERENT UHF solutions (total energies 0.025 Eh apart, 1.7488 against 1.700055), so its roots compare two wavefunctions rather than two codes and support no cross-code conclusion. An earlier revision of this branch claimed the opposite and is corrected here, in the parser docstring and in the documentation. For an unrestricted reference an instability is spin-conserving, i.e. Gaussian's internal sector, and external_instability stays None since no spin-flip root is computed. For a restricted reference ORCA prints one unlabelled matrix spanning both sectors, so the sector is MEASURED rather than assumed: ARC is forced to run STABRestartUHFifUnstable true, so the log already carries the spin expectation value of the solution ORCA relaxed into. A nominal singlet reaching a stable solution at above a small threshold broke the spin symmetry, which is external; one reaching a stable solution still at of zero moved within the spin-conserving sector, which is internal. A restart that never reached a stable solution measures nothing, and the verdict is then 'unattributed_instability' with both flags None -- never 'stable', and never grounds for changing a reference. Assuming external, as the first revision did, made derived_reference_is_unrestricted fire on an unmeasured guess AND suppressed the analytic-frequency-invalidity warning that a genuine internal instability must raise. s_squared_after_follow reports the measurement, and the restart fixture's test asserts it. invalidates_analytic_freq now applies the same rule the Gaussian reader applies, so one physical situation gets one answer whichever ESS measured it. Two smaller reader fixes. An RO reference is reported as restricted None rather than as restricted True, and gets no 'RHF -> UHF' relaxation: run_stability_job admits 'rohf', and neither flag names a constraint an ROHF instability relaxes. And a root printed as -0.00000000 parses to negative zero, for which '< 0' is False, so an unstable verdict came back with an empty root list and a blank log detail; negative zero now counts as negative. The five fixtures are real ORCA 6.0.0 B3LYP/def2-TZVP logs of the same four geometries the Gaussian fixtures were taken on, plus the log of a job run with the restart key false, which crashes after printing its verdict and is kept to pin that the verdict is still readable out of an errored log. The test that asserted orca['lowest_eigenvalue'] > 100 * gaussian['lowest_eigenvalue'] is gone. It froze an artifact of two codes converging to different UHF solutions under a name asserting a mechanism that does not exist, and would have passed forever. What replaced it asserts what the fixtures support: the two codes agree on every verdict and on every reference, and they agree on invalidates_analytic_freq. The errored-log test keeps its assertions and loses its claim: the parser does read a crashed log, but check_stability_job returns early on a non-done status and a LEANSCF crash classifies as errored/['Unknown'], so ARC never surfaces that verdict -- it is parser robustness, not a product guarantee. THE ORCA SECTOR IS MEASURED OFF ANY SOLUTION THE LOG RELAXED INTO. ORCA re-converges the SCF before each analysis it runs and allows five follow attempts, so the of the solution it stopped on is that of a converged determinant whether or not a further root remains, and a solution carrying a few tenths of broke the spin symmetry either way. s_squared_after_follow is therefore read whenever the log opened on an unstable analysis and holds more than one, rather than only where the last one ended stable, and a restricted instability ORCA followed to a still-unstable solution is recorded as the external instability its shows it to be. An instability ORCA never followed, a log holding a single analysis, has nothing to measure the sector from and stays unattributed. followed_to_stable additionally requires that the FIRST analysis was unstable, so a concatenation of stable analyses is not read as a followed instability and reports no of a wavefunction the log never relaxed into. The eigenvalue line is matched with an unambiguous number pattern, so a line the analysis never writes is rejected in time linear in its length: the digits before an optional decimal point and those after it no longer describe the same characters, which is what made a long malformed line cost time quadratic in its length to reject. --- arc/parser/adapter.py | 49 + arc/parser/adapters/gaussian.py | 203 +- arc/parser/adapters/orca.py | 264 ++- arc/parser/adapters/qchem.py | 50 +- arc/parser/parser.py | 40 + arc/parser/parser_test.py | 687 ++++++- .../spin/uhf_died_before_scf_septet.out | 441 ++++ .../spin/uhf_fragment_guess_doublet.out | 246 +++ ...a_rhf_uhf_instability_no_restart_crash.out | 933 +++++++++ .../orca_rhf_uhf_instability_singlet_ts.out | 1786 +++++++++++++++++ .../orca_stable_restricted_singlet_ts.out | 1164 +++++++++++ ...ca_stable_spin_contaminated_doublet_ts.out | 1484 ++++++++++++++ .../orca_stable_unrestricted_doublet_ts.out | 1461 ++++++++++++++ .../rhf_uhf_instability_singlet_ts.out | 952 +++++++++ .../stable_restricted_singlet_ts.out | 740 +++++++ .../stable_spin_contaminated_doublet_ts.out | 818 ++++++++ .../stable_unrestricted_doublet_ts.out | 944 +++++++++ 17 files changed, 12255 insertions(+), 7 deletions(-) create mode 100644 arc/testing/spin/uhf_died_before_scf_septet.out create mode 100644 arc/testing/spin/uhf_fragment_guess_doublet.out create mode 100644 arc/testing/stability/orca_rhf_uhf_instability_no_restart_crash.out create mode 100644 arc/testing/stability/orca_rhf_uhf_instability_singlet_ts.out create mode 100644 arc/testing/stability/orca_stable_restricted_singlet_ts.out create mode 100644 arc/testing/stability/orca_stable_spin_contaminated_doublet_ts.out create mode 100644 arc/testing/stability/orca_stable_unrestricted_doublet_ts.out create mode 100644 arc/testing/stability/rhf_uhf_instability_singlet_ts.out create mode 100644 arc/testing/stability/stable_restricted_singlet_ts.out create mode 100644 arc/testing/stability/stable_spin_contaminated_doublet_ts.out create mode 100644 arc/testing/stability/stable_unrestricted_doublet_ts.out diff --git a/arc/parser/adapter.py b/arc/parser/adapter.py index f682830ded..903777ce5c 100644 --- a/arc/parser/adapter.py +++ b/arc/parser/adapter.py @@ -217,6 +217,55 @@ def parse_opt_steps(self) -> int | None: """ return None + def parse_s_squared(self) -> dict[str, float | None] | None: + """ + Parse the S**2 spin-contamination diagnostic from an unrestricted-reference ESS output. + + Only meaningful for unrestricted/open-shell calculations (restricted/closed-shell + references do not print an ```` value). Adapters that don't implement this + (or restricted/closed-shell logs) return ``None`` — the caller treats ``None`` as + "no spin diagnostic available for this calc" and omits the block entirely. + + ``None`` therefore covers three situations that this method does not distinguish: + an ESS with no reader here, a log holding no readable value, and a restricted + reference, whose determinant is an exact eigenfunction of S**2 with + `` = S(S+1)`` by construction. A consumer that wants the restricted value + computes it from the species' multiplicity rather than reading it off a log. + + Returns: dict[str, float | None] | None + ``{'s_squared': float, 's_squared_expected': float | None, + 's_squared_annihilated': float | None}`` when an ```` value was parsed, + else ``None``. ``s_squared`` is always present (and finite) when the dict is + returned; the other two are ``None`` when the ESS doesn't report them. + """ + return None + + def parse_wavefunction_stability(self) -> dict | None: + """ + Parse the verdict of a wavefunction stability analysis. + + Only meaningful for an ESS that offers the analysis and for a log that ran it. + Adapters that don't implement this return ``None``, which the caller records as + no stability verdict for that calc, so an ESS with no reader here is + indistinguishable from a log that holds no analysis. + + An adapter that does implement it returns the keys documented on + ``GaussianParser.parse_wavefunction_stability``: ``verdict``, one of + ``'stable'``, ``'internal_instability'``, ``'external_instability'``, + ``'unattributed_instability'`` or ``'unknown'``, the ``internal_instability`` / + ``external_instability`` flags, the ``relaxations`` an external verdict names, the + ``negative_eigenvectors`` of the stability matrix and the ``lowest_eigenvalue`` + among the roots it reported, the ``restricted`` reference tested, and whether the + verdict ``invalidates_analytic_freq``. ``'unattributed_instability'`` reports a + wavefunction the ESS found unstable without saying which sector the instability + lies in; only an adapter whose ESS leaves that open returns it. An adapter may add + keys of its own for behaviour peculiar to its ESS. + + Returns: dict | None + The structured verdict, or ``None``. + """ + return None + def parse_ess_version(self) -> str | None: """ Parse the ESS software version string from the log file header. diff --git a/arc/parser/adapters/gaussian.py b/arc/parser/adapters/gaussian.py index aa2c223826..9d17a3d43e 100644 --- a/arc/parser/adapters/gaussian.py +++ b/arc/parser/adapters/gaussian.py @@ -8,12 +8,12 @@ import pandas as pd import re -from arc.common import SYMBOL_BY_NUMBER, is_same_pivot +from arc.common import SYMBOL_BY_NUMBER, is_same_pivot, is_str_int from arc.constants import E_h_kJmol, bohr_to_angstrom from arc.species.converter import str_to_xyz, xyz_from_data from arc.parser.adapter import ESSAdapter from arc.parser.factory import register_ess_adapter -from arc.parser.parser import _get_lines_from_file +from arc.parser.parser import _get_lines_from_file, s_squared_expected_from_multiplicity class GaussianParser(ESSAdapter, ABC): @@ -195,6 +195,205 @@ def parse_t1(self) -> float | None: # Not implemented for Gaussian. return None + def parse_wavefunction_stability(self) -> dict | None: + """ + Parse the verdict of a Gaussian ``Stable`` wavefunction stability analysis. + + Gaussian reports one verdict line per stability test it ran:: + + The wavefunction is stable under the perturbations considered. + The wavefunction has an internal instability. + The wavefunction has an RHF -> UHF instability. + + A ``Stable=RExt`` run emits one analysis with one verdict line, which names + the perturbation that broke first; the internal and external roots share a + single stability matrix. ``verdict`` is ``'stable'``, + ``'internal_instability'`` or ``'external_instability'``, with an internal + instability taking precedence should a log ever carry both. A log that ran + an analysis but whose verdict line none of these patterns matched yields + ``'unknown'`` rather than ``'stable'``, so an unread verdict cannot pass for + a clean one. + + WHICH SECTOR WAS TESTED. For a restricted reference the single matrix spans + both the spin-conserving (internal, ``Singlet-A``) and the spin-symmetry-breaking + (RHF -> UHF, external, ``Triplet-A``) sectors, so a ``'stable'`` verdict covers + both and ``external_instability`` is ``False``. For an unrestricted reference + Gaussian builds only the ```` singles matrix and no `` UHF'``). ``negative_eigenvectors`` carries the label and + value of each negative stability-matrix eigenvalue. The label identifies + the perturbation the root came from and its format follows the reference: + a restricted log labels roots by spin (``Triplet-A``, ``Singlet-A``) while + an unrestricted one labels them by the root's own spin expectation value + (``2.012-A``). ``lowest_eigenvalue`` is the smallest eigenvalue reported in + the eigenvector block whether or not any is negative, so it also gives the + margin by which a stable wavefunction is stable. + + ``restricted`` is read from the reference the log reports on its + ``SCF Done: E(RwB97XD)`` / ``E(UwB97XD)`` line. ``invalidates_analytic_freq`` + applies Gaussian's rule that a restricted wavefunction need only be free of + internal instabilities, while for an unrestricted one any instability makes + the analytic frequencies invalid; it is ``None`` when the verdict or the + reference could not be read. + + Returns: dict | None + ``{'verdict': str, 'internal_instability': bool | None, + 'external_instability': bool | None, 'relaxations': list[str], + 'negative_eigenvectors': list[dict], 'lowest_eigenvalue': float | None, + 'restricted': bool | None, 'invalidates_analytic_freq': bool | None}``, + or ``None`` when the log holds no stability analysis. + """ + internal_instability, external_instability = None, None + relaxations, negative_eigenvectors = list(), list() + lowest_eigenvalue, analyzed, verdict_read, restricted = None, False, False, None + for line in _get_lines_from_file(self.log_file_path): + if 'SCF Done:' in line: + match = re.search(r'SCF Done:\s*E\((RO|R|U)\S*\)', line) + if match is not None: + restricted = match.group(1) != 'U' + continue + if 'Stability analysis using' in line: + analyzed = True + continue + if 'wavefunction' not in line and 'Eigenvector' not in line: + continue + if 'is stable under the perturbations considered' in line: + analyzed, verdict_read = True, True + if internal_instability is None: + internal_instability = False + if external_instability is None: + external_instability = False + elif 'has an internal instability' in line: + analyzed, verdict_read = True, True + internal_instability = True + else: + match = re.search(r'wavefunction has an?\s+(\S+\s*->\s*\S+)\s+instability', line) + if match is not None: + analyzed, verdict_read = True, True + external_instability = True + relaxation = re.sub(r'\s*->\s*', ' -> ', match.group(1).strip()) + if relaxation not in relaxations: + relaxations.append(relaxation) + continue + match = re.search(r'Eigenvector\s+\d+:\s*(\S+)?\s*Eigenvalue=\s*' + r'([-+]?\d*\.?\d+(?:[DdEe][-+]?\d+)?)', line) + if match is not None: + try: + eigenvalue = float(re.sub(r'[Dd]', 'e', match.group(2))) + except ValueError: + continue + if eigenvalue < 0: + negative_eigenvectors.append({'label': match.group(1), 'eigenvalue': eigenvalue}) + if lowest_eigenvalue is None or eigenvalue < lowest_eigenvalue: + lowest_eigenvalue = eigenvalue + if not analyzed: + return None + if not verdict_read: + verdict = 'unknown' + elif internal_instability: + verdict = 'internal_instability' + elif external_instability: + verdict = 'external_instability' + else: + verdict = 'stable' + if verdict == 'stable' and restricted is not True: + external_instability = None + if verdict == 'internal_instability': + invalidates_analytic_freq = True + elif verdict == 'stable': + invalidates_analytic_freq = False + elif verdict == 'external_instability' and restricted is not None: + invalidates_analytic_freq = not restricted + else: + invalidates_analytic_freq = None + return {'verdict': verdict, + 'internal_instability': internal_instability, + 'external_instability': external_instability, + 'relaxations': relaxations, + 'negative_eigenvectors': negative_eigenvectors, + 'lowest_eigenvalue': lowest_eigenvalue, + 'restricted': restricted, + 'invalidates_analytic_freq': invalidates_analytic_freq, + } + + def parse_s_squared(self) -> dict[str, float | None] | None: + """ + Parse the S**2 spin-contamination diagnostic from a Gaussian UHF/UKS log. + + Gaussian prints the post-SCF spin expectation value on a line such as:: + + = 0.0000 = 0.0000 = 1.0000 = 2.0086 S= 1.0029 + + and, when it annihilates the first spin contaminant, a line such as:: + + S**2 before annihilation 2.0086, after 2.0000 + + The value of record is read only from a line that also carries ``=``, + and the last such line is taken. Two other kinds of line in a Gaussian log + carry the ``=`` substring and are not the wavefunction's expectation + value: the ``Initial guess`` spin line, which precedes the SCF, and the + ``Eigenvector`` lines of a ``Stable`` analysis, which report the spin of + each stability-matrix root:: + + Eigenvector 3: 2.041-A Eigenvalue= 0.0744695 =0.791 + + Restricted (RHF/RKS, closed-shell) logs print no spin line, so this returns + ``None`` for them, including for a restricted ``Stable`` log whose + eigenvector lines are the only ``=`` it holds. A job that died before + completing an SCF cycle likewise returns ``None`` rather than its initial + guess, which is a spin-pure superposition of atomic densities and would be + reported as a converged diagnostic of a wavefunction that never existed. + + The reported ```` is the one before annihilation of the first spin + contaminant, which is the expectation value of the wavefunction the energy + belongs to; the annihilated value is carried separately. Both are read in + fixed-point notation, which is the only spelling Gaussian uses on these lines. + + The ideal ``S(S+1)`` is computed from the multiplicity parsed off the + log's ``Charge = C Multiplicity = M`` line (Gaussian doesn't print an + "expected" value explicitly for UHF/UKS). The *first* such line is taken: + it is the symbolic Z-matrix echo of the job's own molecule specification, + while any later one declares the multiplicity of a single fragment of a + ``guess=fragment`` calculation, which is not the wavefunction's. + + Returns: dict[str, float | None] | None + ``{'s_squared': float, 's_squared_expected': float | None, + 's_squared_annihilated': float | None}`` or ``None``. + """ + s_squared, s_squared_annihilated, multiplicity = None, None, None + for line in _get_lines_from_file(self.log_file_path): + if 'Multiplicity =' in line and multiplicity is None: + match = re.search(r'Multiplicity\s*=\s*(\d+)', line) + if match and is_str_int(match.group(1)): + multiplicity = int(match.group(1)) + elif '=' in line and '=' in line and 'Initial guess' not in line: + match = re.search(r'=\s*([-+]?\d*\.?\d+)', line) + if match: + try: + s_squared = float(match.group(1)) + except ValueError: + continue + elif 'S**2 before annihilation' in line and 'after' in line: + match = re.search(r'after\s+([-+]?\d*\.?\d+)', line) + if match: + try: + s_squared_annihilated = float(match.group(1)) + except ValueError: + continue + if s_squared is None: + return None + expected = s_squared_expected_from_multiplicity(multiplicity) + return { + 's_squared': s_squared, + 's_squared_expected': expected, + 's_squared_annihilated': s_squared_annihilated, + } + def parse_e_elect(self) -> float | None: """ Parse the electronic energy from an sp job output file. diff --git a/arc/parser/adapters/orca.py b/arc/parser/adapters/orca.py index 225d65ddc0..7e910de38a 100644 --- a/arc/parser/adapters/orca.py +++ b/arc/parser/adapters/orca.py @@ -4,16 +4,38 @@ from abc import ABC +import math import numpy as np import pandas as pd import re -from arc.common import SYMBOL_BY_NUMBER +from arc.common import SYMBOL_BY_NUMBER, is_str_int from arc.constants import E_h_kJmol, bohr_to_angstrom from arc.species.converter import str_to_xyz, xyz_from_data from arc.parser.adapter import ESSAdapter from arc.parser.factory import register_ess_adapter -from arc.parser.parser import _get_lines_from_file +from arc.parser.parser import _get_lines_from_file, s_squared_expected_from_multiplicity + + +SPIN_SYMMETRY_BREAKING_S_SQUARED = 0.01 + + +def _root_is_negative(eigenvalue: float) -> bool: + """ + Check whether a stability-matrix root is a negative one. + + Negative zero counts as negative: ORCA prints a marginal root as ``-0.00000000``, + which parses to ``-0.0``, for which the ordinary ``< 0`` comparison is ``False``. + A wavefunction ORCA reports unstable on such a root would otherwise be recorded + with no negative roots at all. + + Args: + eigenvalue (float): The root of the stability matrix. + + Returns: + bool: Whether the root is negative. + """ + return eigenvalue < 0 or (eigenvalue == 0 and math.copysign(1.0, eigenvalue) < 0) class OrcaParser(ESSAdapter, ABC): @@ -179,6 +201,244 @@ def parse_t1(self) -> float | None: continue return None + def parse_wavefunction_stability(self) -> dict | None: + """ + Parse the verdict of an ORCA ``STABPerform`` wavefunction stability analysis. + + ORCA opens each analysis with a ``WAVEFUNCTION STABILITY ANALYSIS`` banner, + lists the lowest roots of the stability matrix as:: + + The eigenvalues of the stability matrix: + E( 0) = -0.06466151 Eh + + and closes with one of:: + + The stability analysis shows that the wavefunction is stable + The stability analysis indicates that the wavefunction is unstable + + Unlike Gaussian, ORCA neither labels a root by the perturbation it came from + nor reports its spin expectation value, so every entry of + ``negative_eigenvectors`` carries ``'label': None``. A root printed as ``-0.00000000`` + parses to negative zero and counts as negative, so a wavefunction reported unstable + on a marginal root is not reported with an empty root list. + + TWO ANALYSES PER LOG. ``STABRestartUHFifUnstable true``, which ARC always sets + because ORCA 6.0.0 aborts in LEANSCF when it is false, rotates the orbitals of + an unstable wavefunction, re-converges the SCF and analyses the result again. + Such a log holds two analyses with opposite verdicts. ``verdict`` is read from + the FIRST one, which is the wavefunction under test, i.e. the one the frequency + job built its Hessian from; ``lowest_eigenvalue`` and ``negative_eigenvectors`` + likewise come from that block. ``n_analyses`` counts the blocks and + ``followed_to_stable`` reports whether an analysis that opened UNSTABLE ended + stable, i.e. whether ORCA reached a stable solution after following the + instability. A log opening on a stable analysis reports ``False`` however many + blocks follow it, so a concatenation of stable analyses is not read as a follow + and no ```` of a wavefunction the log never relaxed into is reported. + ``restricted`` is read from the ``HFTyp`` line preceding the first analysis, so + a restart to an unrestricted solution does not overwrite the reference tested; + an ``RO`` reference is reported as ``None`` rather than as restricted, since its + instabilities relax neither of the two constraints the flags name. + + WHICH SECTORS ARE TESTED, and hence which of the two instability flags a verdict + can set. ORCA analyses an RHF/RKS reference in UHF/UKS space and a UHF/UKS + reference in UHF/UKS space, both of which are Ms-conserving; the spin-flip + (UHF -> GHF) sector is analysed in neither, and Gaussian's ``Stable=RExt`` uses + the same Ms-conserving ```` singles matrix for both references, so + the two codes span the same space and neither reaches the GHF sector. Measured on + four systems the verdicts agreed in every case, and at matched functional (ORCA's + ``B3LYP/G`` is Gaussian's VWN3 parameterisation, while plain ORCA ``B3LYP`` uses + VWN-5) the lowest roots agreed to under 0.4% on the three systems where both codes + converged to the same SCF solution. + + * An unrestricted reference is tested against spin-conserving rotations, which is + Gaussian's internal sector, so an instability is recorded as + ``internal_instability`` with ``relaxations`` empty. ``external_instability`` + stays ``None``, since a spin-flip root would be the evidence for it and no root + of that kind is computed. + * For a restricted reference the single unlabelled matrix spans both the + spin-conserving (internal) and the spin-symmetry-breaking (RHF -> UHF, external) + sectors, and ORCA does not say which root it found. The sector is therefore + MEASURED rather than assumed, from the solution ORCA relaxes into: a nominal + singlet that reaches a stable solution whose ```` exceeds + ``SPIN_SYMMETRY_BREAKING_S_SQUARED`` broke the spin symmetry, which is an + external instability, while one that reaches a stable solution still at + ```` of zero relaxed within the spin-conserving sector, which is an + internal instability. That value is reported as ``s_squared_after_follow``, and + the threshold sits far above the ``1e-5`` a spin-symmetric UHF solution's + numerical noise reaches and far below the few tenths a broken-symmetry singlet + carries, so nothing realistic falls near it. + THE SECTOR IS READ OFF EVERY FOLLOWED SOLUTION, whether or not the last analysis + ended stable. ORCA re-converges the SCF before each analysis it runs, so the + ```` of the solution it relaxed into is that of a converged determinant + whichever try it stopped on, and a solution that reached ```` of a few + tenths broke the spin symmetry whether or not a further root remains. ORCA allows + five follow attempts, so a biradicaloid singlet reaching the last of them is + ordinary, and the question the sector answers is whether a lower solution exists + outside the spin symmetry rather than whether the one ORCA stopped on is itself + the bottom. + An instability ORCA never followed at all, which is a log holding one analysis, + leaves nothing to measure the sector from: the verdict is + ``'unattributed_instability'`` with both flags ``None``. + + A log that ran an analysis but whose verdict line could not be read yields + ``'unknown'``. An instability whose reference could not be read yields + ``'unattributed_instability'``, since the reference decides which of the two flags + an instability sets. The roots of the first block are reported either way. + + ``invalidates_analytic_freq`` follows the same rule the Gaussian reader applies, so + the two ESSs report the same value for the same physical situation: an internal + instability invalidates the analytic frequencies of either reference, an external + one invalidates only an unrestricted reference's, and an instability whose sector or + reference is undetermined leaves the question open as ``None``. + + WHICH WAVEFUNCTION EACH FIELD DESCRIBES. ``verdict``, ``lowest_eigenvalue``, + ``negative_eigenvectors`` and ``restricted`` describe the wavefunction under TEST. + The rest of a restart log, its ``FINAL SINGLE POINT ENERGY`` and its final + ```` among them, describes the FOLLOWED solution ORCA relaxed into, which is a + different wavefunction; ``s_squared_after_follow`` is reported under a name that says + so. A consumer reading a quantity off the log this verdict came from is reading the + followed solution unless it is one of the four fields named here. + + Returns: dict | None + ``{'verdict': str, 'internal_instability': bool | None, + 'external_instability': bool | None, 'relaxations': list[str], + 'negative_eigenvectors': list[dict], 'lowest_eigenvalue': float | None, + 'restricted': bool | None, 'invalidates_analytic_freq': bool | None, + 'n_analyses': int, 'followed_to_stable': bool, + 's_squared_after_follow': float | None}``, + or ``None`` when the log holds no stability analysis. ``verdict`` is one of + ``'stable'``, ``'internal_instability'``, ``'external_instability'``, + ``'unattributed_instability'`` or ``'unknown'``. + """ + blocks, restricted = list(), None + for line in _get_lines_from_file(self.log_file_path): + if 'WAVEFUNCTION STABILITY ANALYSIS' in line: + blocks.append({'eigenvalues': list(), 'verdict': None}) + continue + if not blocks: + if 'HFTyp' in line: + match = re.search(r'HFTyp\s*\.+\s*(\S+)', line) + if match is not None: + hf_type = match.group(1).upper() + restricted = None if hf_type.startswith('RO') else not hf_type.startswith('U') + continue + match = re.match(r'\s*E\(\s*\d+\)\s*=\s*([-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[EeDd][-+]?\d+)?)\s*Eh', line) + if match is not None: + blocks[-1]['eigenvalues'].append(float(re.sub(r'[Dd]', 'e', match.group(1)))) + continue + if 'stability analysis' in line and 'wavefunction is' in line: + if 'wavefunction is unstable' in line: + blocks[-1]['verdict'] = 'unstable' + elif 'wavefunction is stable' in line: + blocks[-1]['verdict'] = 'stable' + if not blocks: + return None + eigenvalues = blocks[0]['eigenvalues'] + negative_eigenvectors = [{'label': None, 'eigenvalue': eigenvalue} + for eigenvalue in eigenvalues if _root_is_negative(eigenvalue)] + lowest_eigenvalue = min(eigenvalues) if eigenvalues else None + followed = len(blocks) > 1 and blocks[0]['verdict'] == 'unstable' + followed_to_stable = followed and blocks[-1]['verdict'] == 'stable' + s_squared_after_follow = None + if followed: + s_squared = self.parse_s_squared() + s_squared_after_follow = s_squared['s_squared'] if s_squared is not None else None + internal_instability, external_instability, relaxations = None, None, list() + if blocks[0]['verdict'] == 'stable': + verdict = 'stable' + internal_instability = False + external_instability = False if restricted else None + elif blocks[0]['verdict'] == 'unstable' and restricted is False: + verdict, internal_instability = 'internal_instability', True + elif blocks[0]['verdict'] == 'unstable' and restricted is True \ + and s_squared_after_follow is not None: + if s_squared_after_follow > SPIN_SYMMETRY_BREAKING_S_SQUARED: + verdict, external_instability = 'external_instability', True + relaxations.append('RHF -> UHF') + else: + verdict, internal_instability = 'internal_instability', True + elif blocks[0]['verdict'] == 'unstable': + verdict = 'unattributed_instability' + else: + verdict = 'unknown' + if verdict == 'internal_instability': + invalidates_analytic_freq = True + elif verdict == 'stable': + invalidates_analytic_freq = False + elif verdict == 'external_instability' and restricted is not None: + invalidates_analytic_freq = not restricted + else: + invalidates_analytic_freq = None + return {'verdict': verdict, + 'internal_instability': internal_instability, + 'external_instability': external_instability, + 'relaxations': relaxations, + 'negative_eigenvectors': negative_eigenvectors, + 'lowest_eigenvalue': lowest_eigenvalue, + 'restricted': restricted, + 'invalidates_analytic_freq': invalidates_analytic_freq, + 'n_analyses': len(blocks), + 'followed_to_stable': followed_to_stable, + 's_squared_after_follow': s_squared_after_follow, + } + + def parse_s_squared(self) -> dict[str, float | None] | None: + """ + Parse the S**2 spin-contamination diagnostic from an ORCA UHF/UKS log. + + ORCA prints, for an unrestricted reference:: + + Expectation value of : 0.754185 + Ideal value S*(S+1) for S=0.5 : 0.750000 + + The value of record is the *last* (converged / final-SCF) pair on the + log; on a multi-image or multi-step log every SCF prints its own block + and the final one is the calculation's. On a wavefunction-stability log + that followed an instability, that is the SCF ORCA relaxed into and not + the one the analysis tested. Unlike Gaussian's ``=``, + this anchor string occurs nowhere in an ORCA log but in that block, so + it needs no further anchoring. Restricted (closed-shell) references + don't print these lines, so this returns ``None`` for them. ORCA has no + spin-contaminant annihilation step, so ``s_squared_annihilated`` is + always ``None``. The ideal value is taken from the + ``Ideal value S*(S+1)`` line of the same block as the expectation value + of record (that is exactly the expected ``S(S+1)``), else from the + parsed ``Multiplicity`` line. + + Returns: dict[str, float | None] | None + ``{'s_squared': float, 's_squared_expected': float | None, + 's_squared_annihilated': None}`` or ``None``. + """ + s_squared, s_squared_expected, multiplicity = None, None, None + for line in _get_lines_from_file(self.log_file_path): + if 'Expectation value of ' in line: + match = re.search(r':\s*([-+]?\d*\.?\d+)', line) + if match: + try: + s_squared, s_squared_expected = float(match.group(1)), None + except ValueError: + continue + elif 'Ideal value S*(S+1)' in line: + match = re.search(r':\s*([-+]?\d*\.?\d+)', line) + if match: + try: + s_squared_expected = float(match.group(1)) + except ValueError: + continue + elif 'Multiplicity' in line: + match = re.search(r'\.\.\.\.\s*(\d+)', line) + if match and is_str_int(match.group(1)): + multiplicity = int(match.group(1)) + if s_squared is None: + return None + if s_squared_expected is None: + s_squared_expected = s_squared_expected_from_multiplicity(multiplicity) + return { + 's_squared': s_squared, + 's_squared_expected': s_squared_expected, + 's_squared_annihilated': None, + } + def parse_e_elect(self) -> float | None: """ Parse the electronic energy from an sp job output file. diff --git a/arc/parser/adapters/qchem.py b/arc/parser/adapters/qchem.py index 22d4e18500..72e169346b 100644 --- a/arc/parser/adapters/qchem.py +++ b/arc/parser/adapters/qchem.py @@ -8,11 +8,12 @@ import re from typing import TYPE_CHECKING +from arc.common import is_str_int from arc.constants import E_h_kJmol, bohr_to_angstrom from arc.species.converter import xyz_from_data from arc.parser.adapter import ESSAdapter from arc.parser.factory import register_ess_adapter -from arc.parser.parser import _get_lines_from_file +from arc.parser.parser import _get_lines_from_file, s_squared_expected_from_multiplicity if TYPE_CHECKING: import pandas as pd @@ -124,6 +125,53 @@ def parse_t1(self) -> float | None: # Not implemented for Q-Chem. return None + def parse_s_squared(self) -> dict[str, float | None] | None: + """ + Parse the S**2 spin-contamination diagnostic from a Q-Chem UHF/UKS log. + + Q-Chem prints, for an unrestricted reference, a line such as:: + + = 0.7572 + + The value of record is the *last* such line on the log (the converged + SCF). Restricted (closed-shell) references don't print ````, so + this returns ``None`` for them. Q-Chem has no spin-contaminant + annihilation step, so ``s_squared_annihilated`` is always ``None``. + The ideal ``S(S+1)`` is computed from the multiplicity read off the + echoed ``$molecule`` block (`` ``). + + Returns: dict[str, float | None] | None + ``{'s_squared': float, 's_squared_expected': float | None, + 's_squared_annihilated': None}`` or ``None``. + """ + lines = _get_lines_from_file(self.log_file_path) + s_squared, multiplicity = None, None + in_molecule = False + for line in lines: + if '' in line: + match = re.search(r'\s*=\s*([-+]?\d*\.?\d+)', line) + if match: + try: + s_squared = float(match.group(1)) + except ValueError: + continue + elif multiplicity is None: + if '$molecule' in line: + in_molecule = True + elif in_molecule and line.strip(): + tokens = line.split() + if len(tokens) >= 2: + if is_str_int(tokens[1]): + multiplicity = int(tokens[1]) + in_molecule = False + if s_squared is None: + return None + return { + 's_squared': s_squared, + 's_squared_expected': s_squared_expected_from_multiplicity(multiplicity), + 's_squared_annihilated': None, + } + def parse_e_elect(self) -> float | None: """ Parse the electronic energy from an sp job output file. diff --git a/arc/parser/parser.py b/arc/parser/parser.py index 118d644b8b..bffc8a65a3 100644 --- a/arc/parser/parser.py +++ b/arc/parser/parser.py @@ -273,6 +273,46 @@ def parser(log_file_path: str, raise_error: bool = False) -> return_type: error_message='Could not parse ESS version from {path}', ) +parse_wavefunction_stability = make_parser( + parse_method='parse_wavefunction_stability', + return_type=dict | None, + error_message='Could not parse a wavefunction stability analysis from {path}', +) + +parse_s_squared = make_parser( + parse_method='parse_s_squared', + return_type=dict | None, + error_message='Could not parse S**2 spin diagnostic from {path}', +) + + +def s_squared_expected_from_multiplicity(multiplicity: int | float | None) -> float | None: + """ + Compute the ideal (spin-pure) expectation value ``S(S+1)`` of the total-spin + operator from a spin multiplicity. + + For a spin state of multiplicity ``m`` the total spin is ``S = (m - 1) / 2`` + and the ideal ```` is ``S * (S + 1)`` (e.g. doublet ``m=2`` → 0.75, + triplet ``m=3`` → 2.0). + + Args: + multiplicity (int | float | None): The spin multiplicity. + + Returns: float | None + The ideal ``S(S+1)`` value, or ``None`` if ``multiplicity`` is missing + or not a positive number. + """ + if multiplicity is None: + return None + try: + m = float(multiplicity) + except (TypeError, ValueError): + return None + if m < 1: + return None + s = (m - 1.0) / 2.0 + return s * (s + 1.0) + def get_normal_mode_displacement(log_file_path: str, label: str = '', diff --git a/arc/parser/parser_test.py b/arc/parser/parser_test.py index 222b45cb76..665594b413 100644 --- a/arc/parser/parser_test.py +++ b/arc/parser/parser_test.py @@ -5,15 +5,21 @@ This module contains unit tests for the parser functions """ +import math import numpy as np import os +import shutil +import tempfile +import time import unittest import arc.parser.parser as parser from ase.data import atomic_masses, atomic_numbers from arc.common import ARC_TESTING_PATH, almost_equal_coords, get_element_mass, read_yaml_file -from arc.parser.adapters.gaussian import parse_ic_info, parse_ic_values +from arc.parser.adapters.gaussian import GaussianParser, parse_ic_info, parse_ic_values +from arc.parser.adapters.orca import OrcaParser, SPIN_SYMMETRY_BREAKING_S_SQUARED +from arc.parser.factory import ess_factory from arc.species import ARCSpecies from arc.species.converter import str_to_xyz, xyz_to_str @@ -818,6 +824,132 @@ def test_parse_t1(self): t1 = parser.parse_t1(path) self.assertEqual(t1, 0.0002) + def test_parse_s_squared_gaussian_doublet(self): + """Test parsing the S**2 diagnostic of a Gaussian open-shell doublet""" + path = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7535) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + self.assertAlmostEqual(sd['s_squared_annihilated'], 0.75) + + def test_parse_s_squared_gaussian_triplet(self): + """Test parsing the S**2 diagnostic of a Gaussian open-shell triplet""" + path = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'TSs', 'TS_freq.out') + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 2.0153) + self.assertAlmostEqual(sd['s_squared_expected'], 2.0) + self.assertAlmostEqual(sd['s_squared_annihilated'], 2.0001) + + def test_parse_s_squared_gaussian_closed_shell(self): + """Test that a restricted Gaussian log, which prints no , yields None""" + path = os.path.join(ARC_TESTING_PATH, 'composite', 'C2H5NO2__C2H5ONO.out') + self.assertIsNone(parser.parse_s_squared(path)) + + def test_parse_s_squared_orca(self): + """Test parsing the S**2 diagnostic of an ORCA open-shell doublet""" + path = os.path.join(ARC_TESTING_PATH, 'neb', 'neb_res.out') + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.762333) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + self.assertIsNone(sd['s_squared_annihilated']) + + def test_parse_s_squared_orca_takes_the_last_scf_block(self): + """Test that a multi-image ORCA log yields the final SCF's pair, not an earlier image's""" + path = os.path.join(ARC_TESTING_PATH, 'neb', 'neb_res.out') + with open(path, 'r') as f: + values = [float(line.split(':')[1]) for line in f.readlines() + if 'Expectation value of ' in line] + self.assertGreater(len(values), 1) + self.assertNotAlmostEqual(values[0], values[-1]) + self.assertAlmostEqual(parser.parse_s_squared(path)['s_squared'], values[-1]) + + def test_parse_s_squared_qchem(self): + """Test parsing the S**2 diagnostic of a Q-Chem open-shell doublet""" + path = os.path.join(ARC_TESTING_PATH, 'freq', 'NO3_freq_QChem_fails_on_cclib.out') + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7572) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + self.assertIsNone(sd['s_squared_annihilated']) + + def test_parse_s_squared_from_a_non_ess_file(self): + """Test that a file holding no yields None rather than raising""" + path = os.path.join(ARC_TESTING_PATH, 'mockter.yml') + self.assertIsNone(parser.parse_s_squared(path)) + + def test_parse_s_squared_from_a_stability_log(self): + """Test that a Stable job's eigenvector spins are not read as the wavefunction's S**2""" + path = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_unrestricted_doublet_ts.out') + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7536) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + self.assertAlmostEqual(sd['s_squared_annihilated'], 0.75) + with open(path, 'r') as f: + eigenvector_spins = [float(line.split('=')[1]) + for line in f.readlines() if 'Eigenvector' in line and '=' in line] + self.assertGreater(len(eigenvector_spins), 1) + self.assertNotIn(round(sd['s_squared'], 3), [round(spin, 3) for spin in eigenvector_spins]) + + def test_parse_s_squared_from_a_restricted_stability_log(self): + """Test that a restricted Stable log, whose only = lines are its roots, yields None""" + path = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_restricted_singlet_ts.out') + self.assertIsNone(parser.parse_s_squared(path)) + path = os.path.join(ARC_TESTING_PATH, 'stability', 'rhf_uhf_instability_singlet_ts.out') + self.assertIsNone(parser.parse_s_squared(path)) + + def test_parse_s_squared_is_the_value_before_annihilation(self): + """Test that the SCF is read, not the value after annihilating the first contaminant""" + path = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_spin_contaminated_doublet_ts.out') + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + with open(path, 'r') as f: + lines = [line for line in f.readlines() if 'S**2 before annihilation' in line] + self.assertEqual(len(lines), 1) + before, after = lines[0].split()[3].rstrip(','), lines[0].split()[-1] + self.assertAlmostEqual(sd['s_squared'], float(before), places=4) + self.assertAlmostEqual(sd['s_squared_annihilated'], float(after), places=4) + self.assertNotAlmostEqual(sd['s_squared'], float(after), places=4) + + def test_parse_s_squared_ignores_the_initial_guess_spin(self): + """Test that a job that died before its first SCF cycle reports no at all""" + path = os.path.join(ARC_TESTING_PATH, 'spin', 'uhf_died_before_scf_septet.out') + with open(path, 'r') as f: + lines = [line for line in f.readlines() if '=' in line] + self.assertEqual(len(lines), 1) + self.assertIn('Initial guess', lines[0]) + self.assertIn('=12.0000', lines[0]) + self.assertIsNone(parser.parse_s_squared(path)) + + def test_parse_s_squared_takes_the_first_multiplicity_line(self): + """Test that a guess=fragment log's ideal value comes from the molecule, not from a fragment""" + path = os.path.join(ARC_TESTING_PATH, 'spin', 'uhf_fragment_guess_doublet.out') + with open(path, 'r') as f: + multiplicities = [int(line.split('Multiplicity =')[1].split()[0]) + for line in f.readlines() if 'Multiplicity =' in line] + self.assertEqual(multiplicities, [2, 2, 1]) + sd = parser.parse_s_squared(path) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7536) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + + def test_parse_s_squared_from_an_ordinary_unrestricted_freq_log(self): + """Test that is read from a log carrying no stability analysis""" + path = os.path.join(ARC_TESTING_PATH, 'freq', 'CH3OO_freq_gaussian.out') + self.assertIsNone(parser.parse_wavefunction_stability(path)) + self.assertAlmostEqual(parser.parse_s_squared(path)['s_squared'], 0.7544, places=4) + + def test_s_squared_expected_from_multiplicity(self): + """Test the ideal S(S+1) helper""" + self.assertEqual(parser.s_squared_expected_from_multiplicity(2), 0.75) + self.assertEqual(parser.s_squared_expected_from_multiplicity(3), 2.0) + self.assertEqual(parser.s_squared_expected_from_multiplicity(1), 0.0) + self.assertIsNone(parser.s_squared_expected_from_multiplicity(None)) + self.assertIsNone(parser.s_squared_expected_from_multiplicity(0)) + def test_parse_e_elect(self): """Test parsing the electronic energy from a single-point job output file""" path = os.path.join(ARC_TESTING_PATH, 'sp', 'mehylamine_CCSD(T).out') @@ -1298,7 +1430,6 @@ def test_parse_ess_version(self): def test_yaml_parser(self): """Test the YAMLParser adapter for all its parse methods.""" - import tempfile from arc.parser.adapters.yaml import YAMLParser from arc.constants import E_h_kJmol, bohr_to_angstrom import yaml @@ -1390,5 +1521,557 @@ def test_yaml_parser(self): os.remove(temp_path) +class TestParseRealStabilityLogs(unittest.TestCase): + """ + Contains unit tests for parsing real Gaussian stable=(rext,noopt) logs of campaign TSs. + """ + + @classmethod + def setUpClass(cls): + """ + A method that is run before all unit tests in this class. + """ + cls.maxDiff = None + cls.path = lambda name: os.path.join(ARC_TESTING_PATH, 'stability', name) + + def _parse(self, name: str) -> dict: + """Parse a stability fixture by file name.""" + result = parser.parse_wavefunction_stability(os.path.join(ARC_TESTING_PATH, 'stability', name)) + self.assertIsNotNone(result, msg=f'no stability verdict parsed from {name}') + return result + + def test_one_analysis_and_one_verdict_per_rext_run(self): + """Test that a RExt run reports a single analysis with a single verdict line""" + for name in ['rhf_uhf_instability_singlet_ts.out', 'stable_unrestricted_doublet_ts.out', + 'stable_restricted_singlet_ts.out', 'stable_spin_contaminated_doublet_ts.out']: + with open(os.path.join(ARC_TESTING_PATH, 'stability', name), 'r') as f: + lines = f.readlines() + headers = [line for line in lines if 'Stability analysis using' in line] + verdicts = [line for line in lines + if 'wavefunction is stable' in line or 'wavefunction has an' in line] + self.assertEqual(len(headers), 1, msg=f'{name} has {len(headers)} stability analyses') + self.assertEqual(len(verdicts), 1, msg=f'{name} has {len(verdicts)} verdict lines') + + def test_restricted_singlet_ts_with_an_rhf_uhf_instability(self): + """Test the verdict of a restricted singlet TS whose wavefunction is RHF -> UHF unstable""" + result = self._parse('rhf_uhf_instability_singlet_ts.out') + self.assertEqual(result['verdict'], 'external_instability') + self.assertTrue(result['restricted']) + self.assertTrue(result['external_instability']) + self.assertEqual(result['relaxations'], ['RHF -> UHF']) + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.0642219, places=6) + self.assertEqual([e['label'] for e in result['negative_eigenvectors']], ['Triplet-A']) + self.assertAlmostEqual(result['negative_eigenvectors'][0]['eigenvalue'], -0.0642219, places=6) + + def test_restricted_external_instability_leaves_the_analytic_hessian_defined(self): + """Test that the sole negative root of the unstable singlet TS is triplet, not singlet""" + result = self._parse('rhf_uhf_instability_singlet_ts.out') + self.assertNotIn('Singlet', [e['label'].split('-')[0] for e in result['negative_eigenvectors']]) + self.assertFalse(result['internal_instability']) + self.assertFalse(result['invalidates_analytic_freq']) + + def test_stable_unrestricted_doublet_ts(self): + """Test that an unrestricted stable verdict leaves the unanalysed spin-flip sector undecided""" + result = self._parse('stable_unrestricted_doublet_ts.out') + self.assertEqual(result['verdict'], 'stable') + self.assertFalse(result['restricted']) + self.assertFalse(result['internal_instability']) + self.assertIsNone(result['external_instability']) + self.assertFalse(result['invalidates_analytic_freq']) + self.assertEqual(result['relaxations'], []) + self.assertEqual(result['negative_eigenvectors'], []) + self.assertAlmostEqual(result['lowest_eigenvalue'], 0.0024619, places=6) + + def test_an_unrestricted_analysis_holds_no_spin_flip_block(self): + """Test that the unrestricted fixtures carry no singles matrix'), 1, msg=name) + self.assertNotIn(' singles matrix: + + Eigenvector 1: 3.026-?Sym Eigenvalue= 0.0219147 =2.039 + Eigenvector 2: 3.026-?Sym Eigenvalue= 0.0451128 =2.041 + + The wavefunction is stable under the perturbations considered. + + Normal termination of Gaussian 16. +""" + cls.internal_block = """ Stability analysis using singles matrix: + + Eigenvector 1: Singlet-?Sym Eigenvalue=-0.0731205 =0.000 + + The wavefunction has an internal instability. + + Normal termination of Gaussian 16. +""" + cls.external_block = """ Stability analysis using singles matrix: + + Eigenvector 1: Triplet-?Sym Eigenvalue=-0.1434007 =2.000 + Eigenvector 3: Singlet-?Sym Eigenvalue= 0.0000259 =0.000 + + The wavefunction has an RHF -> UHF instability. + + Normal termination of Gaussian 16. +""" + + def _parse(self, block: str, scf_done: str = ''): + """Write a Gaussian log holding the given block to a temporary file and parse its verdict.""" + with tempfile.NamedTemporaryFile(suffix='.log', mode='w', delete=False) as f: + f.write(self.header + scf_done + block) + temp_path = f.name + try: + return parser.parse_wavefunction_stability(temp_path) + finally: + if os.path.exists(temp_path): + os.remove(temp_path) + + def test_stable_verdict(self): + """Test parsing a stable wavefunction verdict whose reference the log never states""" + result = self._parse(self.stable_block) + self.assertEqual(result['verdict'], 'stable') + self.assertIsNone(result['restricted']) + self.assertFalse(result['internal_instability']) + self.assertIsNone(result['external_instability']) + self.assertEqual(result['relaxations'], []) + self.assertAlmostEqual(result['lowest_eigenvalue'], 0.0219147, places=6) + + def test_a_restricted_stable_verdict_covers_the_spin_flip_sector(self): + """Test that a stable restricted reference reports the external sector tested and clean""" + result = self._parse(self.stable_block, scf_done=' SCF Done: E(RwB97XD) = -100.0 A.U.\n') + self.assertTrue(result['restricted']) + self.assertFalse(result['internal_instability']) + self.assertFalse(result['external_instability']) + + def test_an_unrestricted_stable_verdict_leaves_the_spin_flip_sector_undecided(self): + """Test that a stable unrestricted reference reports the untested external sector as undecided""" + result = self._parse(self.stable_block, scf_done=' SCF Done: E(UwB97XD) = -100.0 A.U.\n') + self.assertFalse(result['restricted']) + self.assertFalse(result['internal_instability']) + self.assertIsNone(result['external_instability']) + + def test_internal_instability_verdict(self): + """Test parsing an internal instability verdict""" + result = self._parse(self.internal_block) + self.assertEqual(result['verdict'], 'internal_instability') + self.assertTrue(result['internal_instability']) + self.assertEqual(result['relaxations'], []) + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.0731205, places=6) + + def test_external_instability_verdict(self): + """Test parsing an external instability verdict and the relaxed constraint""" + result = self._parse(self.external_block) + self.assertEqual(result['verdict'], 'external_instability') + self.assertTrue(result['external_instability']) + self.assertEqual(result['relaxations'], ['RHF -> UHF']) + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.1434007, places=6) + + def test_internal_takes_precedence_over_external(self): + """Test that an internal instability outranks an external one in the same log""" + result = self._parse(self.internal_block + self.external_block) + self.assertEqual(result['verdict'], 'internal_instability') + self.assertTrue(result['internal_instability']) + self.assertTrue(result['external_instability']) + self.assertEqual(result['relaxations'], ['RHF -> UHF']) + + def test_restricted_external_instability_does_not_invalidate_freq(self): + """Test that an external instability of a restricted reference leaves the freq valid""" + result = self._parse(' SCF Done: E(RwB97XD) = -78.5936 A.U.\n' + self.external_block) + self.assertTrue(result['restricted']) + self.assertEqual(result['verdict'], 'external_instability') + self.assertFalse(result['invalidates_analytic_freq']) + + def test_unrestricted_external_instability_invalidates_freq(self): + """Test that any instability of an unrestricted reference invalidates the freq""" + result = self._parse(' SCF Done: E(UwB97XD) = -78.5936 A.U.\n' + self.external_block) + self.assertFalse(result['restricted']) + self.assertEqual(result['verdict'], 'external_instability') + self.assertTrue(result['invalidates_analytic_freq']) + + def test_internal_instability_invalidates_either_reference(self): + """Test that an internal instability invalidates the freq for both references""" + for reference in ['R', 'U']: + result = self._parse(f' SCF Done: E({reference}wB97XD) = -78.5936 A.U.\n' + self.internal_block) + self.assertTrue(result['invalidates_analytic_freq']) + stable = self._parse(' SCF Done: E(UwB97XD) = -78.5936 A.U.\n' + self.stable_block) + self.assertFalse(stable['invalidates_analytic_freq']) + + def test_unknown_reference_leaves_freq_validity_undecided(self): + """Test that an unreadable reference does not resolve an external verdict either way""" + result = self._parse(self.external_block) + self.assertIsNone(result['restricted']) + self.assertIsNone(result['invalidates_analytic_freq']) + + def test_negative_unrestricted_eigenvector_label_is_read(self): + """Test that a negative root carrying an unrestricted numeric label is recorded""" + result = self._parse(' SCF Done: E(UB3LYP) = -614.0536 A.U.\n' + ' Stability analysis using singles matrix:\n' + '\n' + ' Eigenvectors of the stability matrix:\n' + '\n' + ' Eigenvector 1: 2.012-A Eigenvalue=-0.0311204 =0.762\n' + ' Eigenvector 2: 2.041-A Eigenvalue= 0.0744695 =0.791\n' + '\n' + ' The wavefunction has an internal instability.\n') + self.assertEqual(result['verdict'], 'internal_instability') + self.assertFalse(result['restricted']) + self.assertTrue(result['invalidates_analytic_freq']) + self.assertEqual([e['label'] for e in result['negative_eigenvectors']], ['2.012-A']) + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.0311204, places=6) + + def test_unparsed_verdict_is_not_reported_as_stable(self): + """Test that an analysis whose verdict line was not recognized yields 'unknown'""" + result = self._parse(' Stability analysis using singles matrix:\n' + ' Eigenvector 1: Singlet-?Sym Eigenvalue=-0.0731205 =0.000\n' + ' The wavefunction has some phrasing ARC does not know.\n') + self.assertEqual(result['verdict'], 'unknown') + self.assertIsNone(result['internal_instability']) + self.assertIsNone(result['external_instability']) + + def test_negative_eigenvector_labels_are_kept(self): + """Test that the label of each negative stability-matrix eigenvalue is recorded""" + result = self._parse(self.external_block) + self.assertEqual([e['label'] for e in result['negative_eigenvectors']], ['Triplet-?Sym']) + self.assertEqual(len(result['negative_eigenvectors']), 1) + self.assertEqual(self._parse(self.stable_block)['negative_eigenvectors'], []) + + def test_fortran_double_exponent_eigenvalue(self): + """Test that an eigenvalue in Fortran D notation is not read as its mantissa""" + result = self._parse(' Stability analysis using singles matrix:\n' + ' Eigenvector 1: Singlet-?Sym Eigenvalue=-0.53D-02 =0.000\n' + ' The wavefunction has an internal instability.\n') + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.0053, places=6) + + def test_no_stability_analysis(self): + """Test that a log with no stability analysis yields no verdict""" + self.assertIsNone(self._parse(' SCF Done: E(UB3LYP) = -78.5936 A.U.\n' + ' Normal termination of Gaussian 16.\n')) + freq_path = os.path.join(ARC_TESTING_PATH, 'freq', 'CH3OO_freq_gaussian.out') + self.assertIsNone(parser.parse_wavefunction_stability(freq_path)) + + +class TestParseOrcaStabilityLogs(unittest.TestCase): + """ + Contains unit tests for parsing real ORCA STABPerform logs of campaign TSs. + """ + + @classmethod + def setUpClass(cls): + """ + A method that is run before all unit tests in this class. + """ + cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_orca_stability_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) + + def _parse(self, name: str) -> dict: + """Parse an ORCA stability fixture by file name.""" + result = parser.parse_wavefunction_stability(os.path.join(ARC_TESTING_PATH, 'stability', name)) + self.assertIsNotNone(result, msg=f'no stability verdict parsed from {name}') + return result + + def test_stable_restricted_singlet_ts(self): + """Test the verdict of a stable restricted singlet TS""" + result = self._parse('orca_stable_restricted_singlet_ts.out') + self.assertEqual(result['verdict'], 'stable') + self.assertTrue(result['restricted']) + self.assertFalse(result['internal_instability']) + self.assertFalse(result['external_instability']) + self.assertFalse(result['invalidates_analytic_freq']) + self.assertEqual(result['relaxations'], []) + self.assertEqual(result['negative_eigenvectors'], []) + self.assertAlmostEqual(result['lowest_eigenvalue'], 0.0245450, places=6) + self.assertEqual(result['n_analyses'], 1) + self.assertFalse(result['followed_to_stable']) + + def test_stable_unrestricted_doublet_ts(self): + """Test that an unrestricted stable verdict leaves the unanalysed spin-flip sector undecided""" + result = self._parse('orca_stable_unrestricted_doublet_ts.out') + self.assertEqual(result['verdict'], 'stable') + self.assertFalse(result['restricted']) + self.assertFalse(result['internal_instability']) + self.assertIsNone(result['external_instability']) + self.assertFalse(result['invalidates_analytic_freq']) + self.assertEqual(result['negative_eigenvectors'], []) + self.assertAlmostEqual(result['lowest_eigenvalue'], 0.0024498, places=6) + + def test_spin_contaminated_doublet_ts_is_stable(self): + """Test that a spin-contaminated doublet TS is reported stable by the spin-conserving analysis""" + result = self._parse('orca_stable_spin_contaminated_doublet_ts.out') + self.assertEqual(result['verdict'], 'stable') + self.assertFalse(result['restricted']) + self.assertEqual(result['negative_eigenvectors'], []) + self.assertAlmostEqual(result['lowest_eigenvalue'], 0.0656010, places=6) + + def test_the_two_codes_agree_on_every_verdict(self): + """Test that ORCA and Gaussian report the same verdict on each of the four measured systems""" + for orca_name, gaussian_name in [('orca_stable_restricted_singlet_ts.out', + 'stable_restricted_singlet_ts.out'), + ('orca_stable_unrestricted_doublet_ts.out', + 'stable_unrestricted_doublet_ts.out'), + ('orca_stable_spin_contaminated_doublet_ts.out', + 'stable_spin_contaminated_doublet_ts.out'), + ('orca_rhf_uhf_instability_singlet_ts.out', + 'rhf_uhf_instability_singlet_ts.out')]: + orca = self._parse(orca_name) + gaussian = parser.parse_wavefunction_stability( + os.path.join(ARC_TESTING_PATH, 'stability', gaussian_name)) + self.assertEqual(orca['verdict'], gaussian['verdict'], msg=f'{orca_name} vs {gaussian_name}') + self.assertEqual(orca['restricted'], gaussian['restricted'], msg=f'{orca_name} vs {gaussian_name}') + self.assertEqual(orca['internal_instability'], gaussian['internal_instability'], + msg=f'{orca_name} vs {gaussian_name}') + self.assertEqual(orca['external_instability'], gaussian['external_instability'], + msg=f'{orca_name} vs {gaussian_name}') + + def test_the_same_physical_situation_gets_the_same_analytic_freq_answer(self): + """Test that both readers apply one rule to invalidates_analytic_freq""" + for orca_name, gaussian_name in [('orca_stable_restricted_singlet_ts.out', + 'stable_restricted_singlet_ts.out'), + ('orca_stable_unrestricted_doublet_ts.out', + 'stable_unrestricted_doublet_ts.out'), + ('orca_rhf_uhf_instability_singlet_ts.out', + 'rhf_uhf_instability_singlet_ts.out')]: + orca = self._parse(orca_name) + gaussian = parser.parse_wavefunction_stability( + os.path.join(ARC_TESTING_PATH, 'stability', gaussian_name)) + self.assertEqual(orca['invalidates_analytic_freq'], gaussian['invalidates_analytic_freq'], + msg=f'{orca_name} vs {gaussian_name}') + + def test_restricted_singlet_ts_with_an_rhf_uhf_instability(self): + """Test that the verdict of a restarted log describes the first analysis, the one under test""" + result = self._parse('orca_rhf_uhf_instability_singlet_ts.out') + self.assertEqual(result['verdict'], 'external_instability') + self.assertTrue(result['restricted']) + self.assertTrue(result['external_instability']) + self.assertIsNone(result['internal_instability']) + self.assertFalse(result['invalidates_analytic_freq']) + self.assertEqual(result['relaxations'], ['RHF -> UHF']) + self.assertEqual(result['n_analyses'], 2) + self.assertTrue(result['followed_to_stable']) + self.assertEqual([eigenvector['label'] for eigenvector in result['negative_eigenvectors']], [None]) + self.assertAlmostEqual(result['negative_eigenvectors'][0]['eigenvalue'], -0.0646615, places=6) + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.0646615, places=6) + + def test_the_external_sector_is_measured_and_not_assumed(self): + """Test that the RHF -> UHF label rests on the spin contamination of the followed solution""" + result = self._parse('orca_rhf_uhf_instability_singlet_ts.out') + self.assertAlmostEqual(result['s_squared_after_follow'], 0.864742, places=6) + self.assertGreater(result['s_squared_after_follow'], SPIN_SYMMETRY_BREAKING_S_SQUARED) + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_rhf_uhf_instability_singlet_ts.out'), 'r') as f: + lines = f.readlines() + spin_lines = [line for line in lines if 'Expectation value of ' in line] + self.assertEqual(len(spin_lines), 1, msg='the restart fixture no longer holds one block') + self.assertGreater(lines.index(spin_lines[0]), + max(index for index, line in enumerate(lines) + if 'WAVEFUNCTION STABILITY ANALYSIS' in line), + msg='the of record is no longer the followed solution\'s') + self.assertEqual(result['verdict'], 'external_instability') + + def test_a_follow_that_ended_unstable_still_measures_the_sector(self): + """Test that the sector is read off a followed solution the last analysis still calls unstable""" + path = os.path.join(self.scratch_dir, 'follow_ended_unstable.out') + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_rhf_uhf_instability_singlet_ts.out'), 'r') as f: + content = f.read() + with open(path, 'w') as f: + f.write(content.replace('The stability analysis shows that the wavefunction is stable', + 'The stability analysis indicates that the wavefunction is unstable')) + result = parser.parse_wavefunction_stability(path) + self.assertEqual(result['n_analyses'], 2) + self.assertFalse(result['followed_to_stable']) + self.assertAlmostEqual(result['s_squared_after_follow'], 0.864742, places=5) + self.assertEqual(result['verdict'], 'external_instability') + self.assertTrue(result['external_instability']) + self.assertEqual(result['relaxations'], ['RHF -> UHF']) + self.assertFalse(result['invalidates_analytic_freq']) + + def test_a_follow_that_stayed_spin_symmetric_is_an_internal_instability(self): + """Test that a followed solution still at zero relaxed within the spin-conserving sector""" + path = os.path.join(self.scratch_dir, 'follow_stayed_symmetric.out') + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_rhf_uhf_instability_singlet_ts.out'), 'r') as f: + content = f.read() + with open(path, 'w') as f: + f.write(content.replace('Expectation value of : 0.864742', + 'Expectation value of : 0.000000')) + result = parser.parse_wavefunction_stability(path) + self.assertEqual(result['verdict'], 'internal_instability') + self.assertTrue(result['internal_instability']) + self.assertTrue(result['invalidates_analytic_freq']) + + def test_a_log_opening_on_a_stable_analysis_reports_no_follow(self): + """Test that concatenated stable analyses are not read as a followed instability""" + path = os.path.join(self.scratch_dir, 'two_stable_analyses.out') + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_stable_unrestricted_doublet_ts.out'), 'r') as f: + content = f.read() + with open(path, 'w') as f: + f.write(content + content) + result = parser.parse_wavefunction_stability(path) + self.assertEqual(result['n_analyses'], 2) + self.assertFalse(result['followed_to_stable']) + self.assertIsNone(result['s_squared_after_follow']) + self.assertEqual(result['verdict'], 'stable') + + def test_an_eigenvalue_line_of_any_length_is_read_without_backtracking(self): + """Test that a malformed eigenvalue line is rejected in time linear in its length""" + path = os.path.join(self.scratch_dir, 'long_eigenvalue_line.out') + with open(path, 'w') as f: + f.write(' WAVEFUNCTION STABILITY ANALYSIS\n') + f.write('The eigenvalues of the stability matrix:\n') + f.write(f" E( 0) = {'1' * 160000}\n") + f.write('The stability analysis shows that the wavefunction is stable\n') + start = time.time() + result = OrcaParser(log_file_path=path).parse_wavefunction_stability() + elapsed = time.time() - start + self.assertEqual(result['verdict'], 'stable') + self.assertEqual(result['negative_eigenvectors'], []) + self.assertLess(elapsed, 15.0, msg=f'a 160k-character eigenvalue line took {elapsed} s to reject') + + def test_an_instability_whose_sector_was_not_measured_is_left_unattributed(self): + """Test that a restricted instability the ESS never relaxed is neither internal nor external""" + result = self._parse('orca_rhf_uhf_instability_no_restart_crash.out') + self.assertEqual(result['verdict'], 'unattributed_instability') + self.assertTrue(result['restricted']) + self.assertIsNone(result['internal_instability']) + self.assertIsNone(result['external_instability']) + self.assertIsNone(result['invalidates_analytic_freq']) + self.assertIsNone(result['s_squared_after_follow']) + self.assertEqual(result['relaxations'], []) + self.assertLess(result['lowest_eigenvalue'], 0) + + def test_an_ro_reference_is_neither_restricted_nor_unrestricted(self): + """Test that an ROHF reference is not reported as restricted and gets no RHF -> UHF relaxation""" + path = os.path.join(self.scratch_dir, 'rohf_instability.out') + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_rhf_uhf_instability_singlet_ts.out'), 'r') as f: + content = f.read() + with open(path, 'w') as f: + f.write(content.replace('HFTyp .... RHF', 'HFTyp .... ROHF')) + result = parser.parse_wavefunction_stability(path) + self.assertIsNone(result['restricted']) + self.assertEqual(result['verdict'], 'unattributed_instability') + self.assertEqual(result['relaxations'], []) + self.assertIsNone(result['internal_instability']) + self.assertIsNone(result['external_instability']) + + def test_a_negative_zero_root_counts_as_negative(self): + """Test that a marginal root printed as -0.00000000 is not dropped from the root list""" + path = os.path.join(self.scratch_dir, 'negative_zero_root.out') + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_rhf_uhf_instability_singlet_ts.out'), 'r') as f: + content = f.read() + with open(path, 'w') as f: + f.write(content.replace('-0.06466151', '-0.00000000')) + result = parser.parse_wavefunction_stability(path) + self.assertEqual(len(result['negative_eigenvectors']), 1) + self.assertLess(math.copysign(1.0, result['negative_eigenvectors'][0]['eigenvalue']), 0) + self.assertEqual(result['verdict'], 'external_instability') + + def test_the_relaxed_solution_does_not_overwrite_the_verdict(self): + """Test that the stable second analysis of a restarted log is reported apart from the verdict""" + with open(os.path.join(ARC_TESTING_PATH, 'stability', + 'orca_rhf_uhf_instability_singlet_ts.out'), 'r') as f: + lines = f.readlines() + verdicts = [line for line in lines if 'stability analysis' in line and 'wavefunction is' in line] + self.assertEqual(len(verdicts), 2, msg='the restart fixture no longer holds two verdicts') + self.assertIn('unstable', verdicts[0]) + self.assertNotIn('unstable', verdicts[1]) + result = self._parse('orca_rhf_uhf_instability_singlet_ts.out') + self.assertEqual(result['verdict'], 'external_instability') + self.assertLess(result['lowest_eigenvalue'], 0) + + def test_the_parser_does_not_need_a_normal_termination(self): + """Test parser robustness on a crashed log, which ARC itself never surfaces a verdict from""" + path = os.path.join(ARC_TESTING_PATH, 'stability', 'orca_rhf_uhf_instability_no_restart_crash.out') + with open(path, 'r') as f: + content = f.read() + self.assertIn('error termination in LEANSCF', content) + self.assertNotIn('ORCA TERMINATED NORMALLY', content) + result = self._parse('orca_rhf_uhf_instability_no_restart_crash.out') + self.assertTrue(result['restricted']) + self.assertEqual(result['n_analyses'], 1) + self.assertFalse(result['followed_to_stable']) + self.assertAlmostEqual(result['lowest_eigenvalue'], -0.0646615, places=6) + + def test_the_two_codes_agree_on_a_restricted_reference(self): + """Test that the lowest root of a restricted reference agrees between ORCA and Gaussian""" + for orca_name, gaussian_name in [('orca_rhf_uhf_instability_singlet_ts.out', + 'rhf_uhf_instability_singlet_ts.out'), + ('orca_stable_restricted_singlet_ts.out', + 'stable_restricted_singlet_ts.out')]: + orca = self._parse(orca_name) + gaussian = parser.parse_wavefunction_stability( + os.path.join(ARC_TESTING_PATH, 'stability', gaussian_name)) + self.assertEqual(orca['verdict'], gaussian['verdict']) + self.assertAlmostEqual(orca['lowest_eigenvalue'], gaussian['lowest_eigenvalue'], places=2) + + def test_no_stability_analysis_in_a_plain_orca_log(self): + """Test that an ORCA log holding no analysis yields no verdict""" + self.assertIsNone(parser.parse_wavefunction_stability( + os.path.join(ARC_TESTING_PATH, 'freq', 'orca_example_freq.log'))) + + +class TestBaseParserStability(unittest.TestCase): + """ + Contains unit tests for the base ESS adapter's wavefunction stability declaration. + """ + + def test_an_ess_with_no_reader_returns_none(self): + """Test that an adapter that does not implement the analysis returns None rather than raising""" + for path in [os.path.join(ARC_TESTING_PATH, 'freq', 'CH2O_freq_molpro.out'), + os.path.join(ARC_TESTING_PATH, 'freq', 'C2H6_freq_QChem.out')]: + ess_name = parser.determine_ess(log_file_path=path) + adapter = ess_factory(log_file_path=path, ess_adapter=ess_name) + self.assertIsNone(adapter.parse_wavefunction_stability()) + self.assertIsNone(parser.parse_wavefunction_stability(path)) + + if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/testing/spin/uhf_died_before_scf_septet.out b/arc/testing/spin/uhf_died_before_scf_septet.out new file mode 100644 index 0000000000..7c95e675ac --- /dev/null +++ b/arc/testing/spin/uhf_died_before_scf_septet.out @@ -0,0 +1,441 @@ + Entering Gaussian System, Link 0=g09 + Initial command: + /usr/local/g09/l1.exe "/scratch/g09/job/Gau-2890310.inp" -scrdir="/scratch/g09/job/" + Entering Link 1 = /usr/local/g09/l1.exe PID= 2890311. + + Copyright (c) 1988,1990,1992,1993,1995,1998,2003,2009,2013, + Gaussian, Inc. All Rights Reserved. + + This is part of the Gaussian(R) 09 program. It is based on + the Gaussian(R) 03 system (copyright 2003, Gaussian, Inc.), + the Gaussian(R) 98 system (copyright 1998, Gaussian, Inc.), + the Gaussian(R) 94 system (copyright 1995, Gaussian, Inc.), + the Gaussian 92(TM) system (copyright 1992, Gaussian, Inc.), + the Gaussian 90(TM) system (copyright 1990, Gaussian, Inc.), + the Gaussian 88(TM) system (copyright 1988, Gaussian, Inc.), + the Gaussian 86(TM) system (copyright 1986, Carnegie Mellon + University), and the Gaussian 82(TM) system (copyright 1983, + Carnegie Mellon University). Gaussian is a federally registered + trademark of Gaussian, Inc. + + This software contains proprietary and confidential information, + including trade secrets, belonging to Gaussian, Inc. + + This software is provided under written license and may be + used, copied, transmitted, or stored only in accord with that + written license. + + The following legend is applicable only to US Government + contracts under FAR: + + RESTRICTED RIGHTS LEGEND + + Use, reproduction and disclosure by the US Government is + subject to restrictions as set forth in subparagraphs (a) + and (c) of the Commercial Computer Software - Restricted + Rights clause in FAR 52.227-19. + + Gaussian, Inc. + 340 Quinnipiac St., Bldg. 40, Wallingford CT 06492 + + + --------------------------------------------------------------- + Warning -- This program may not be used in any manner that + competes with the business of Gaussian, Inc. or will provide + assistance to any competitor of Gaussian, Inc. The licensee + of this program is prohibited from giving any competitor of + Gaussian, Inc. access to this program. By using this program, + the user acknowledges that Gaussian, Inc. is engaged in the + business of creating and licensing software in the field of + computational chemistry and represents and warrants to the + licensee that it is not a competitor of Gaussian, Inc. and that + it will not use this program in any manner prohibited above. + --------------------------------------------------------------- + + + Cite this work as: + Gaussian 09, Revision D.01, + M. J. Frisch, G. W. Trucks, H. B. Schlegel, G. E. Scuseria, + M. A. Robb, J. R. Cheeseman, G. Scalmani, V. Barone, B. Mennucci, + G. A. Petersson, H. Nakatsuji, M. Caricato, X. Li, H. P. Hratchian, + A. F. Izmaylov, J. Bloino, G. Zheng, J. L. Sonnenberg, M. Hada, + M. Ehara, K. Toyota, R. Fukuda, J. Hasegawa, M. Ishida, T. Nakajima, + Y. Honda, O. Kitao, H. Nakai, T. Vreven, J. A. Montgomery, Jr., + J. E. Peralta, F. Ogliaro, M. Bearpark, J. J. Heyd, E. Brothers, + K. N. Kudin, V. N. Staroverov, T. Keith, R. Kobayashi, J. Normand, + K. Raghavachari, A. Rendell, J. C. Burant, S. S. Iyengar, J. Tomasi, + M. Cossi, N. Rega, J. M. Millam, M. Klene, J. E. Knox, J. B. Cross, + V. Bakken, C. Adamo, J. Jaramillo, R. Gomperts, R. E. Stratmann, + O. Yazyev, A. J. Austin, R. Cammi, C. Pomelli, J. W. Ochterski, + R. L. Martin, K. Morokuma, V. G. Zakrzewski, G. A. Voth, + P. Salvador, J. J. Dannenberg, S. Dapprich, A. D. Daniels, + O. Farkas, J. B. Foresman, J. V. Ortiz, J. Cioslowski, + and D. J. Fox, Gaussian, Inc., Wallingford CT, 2013. + + ****************************************** + Gaussian 09: EM64L-G09RevD.01 24-Apr-2013 + 10-Aug-2024 + ****************************************** + %chk=check.chk + %mem=32768mb + %NProcShared=16 + Will use up to 16 processors via shared memory. + ---------------------------------------------------------------------- + #P opt=(calcfc) guess=INDO uwb97xd/def2svp IOp(2/9=2000) nosymm scf=(N + Damp=30,NoDIIS,xqc) + ---------------------------------------------------------------------- + 1/10=4,14=-1,18=20,19=15,26=3,38=1/1,3; + 2/9=2000,12=2,15=1,17=6,18=5,40=1/2; + 3/5=43,7=101,11=2,16=1,25=1,30=1,71=2,74=-58,116=2,140=1/1,2,3; + 4/5=4,11=3/1; + 5/5=2,8=3,13=1,18=-1,22=1,38=5,93=30/2,8; + 8/6=4,10=90,11=11/1; + 11/6=1,8=1,9=11,15=111,16=1,31=1/1,2,10; + 10/6=1,13=1,31=1/2; + 6/7=2,8=2,9=2,10=2,28=1/1; + 7/10=1,18=20,25=1,30=1/1,2,3,16; + 1/10=4,14=-1,18=20,19=15,26=3/3(2); + 2/9=2000,15=1/2; + 99//99; + 2/9=2000,15=1/2; + 3/5=43,7=101,11=2,16=1,25=1,30=1,71=1,74=-58,116=2/1,2,3; + 4/5=5,11=3,16=3,69=1/1; + 5/5=2,8=3,13=1,18=-1,22=1,38=5,93=30/2,8; + 7/30=1/1,2,3,16; + 1/14=-1,18=20,19=15,26=3/3(-5); + 2/9=2000,15=1/2; + 6/7=2,8=2,9=2,10=2,19=2,28=1/1; + 99/9=1/99; + Leave Link 1 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 0.5 + (Enter /usr/local/g09/l101.exe) + ------------------------------------ + rxn_1557_SC[C]1[CH][CH][CH][CH][CH]1 + ------------------------------------ + Symbolic Z-matrix: + Charge = 0 Multiplicity = 7 + S -3.09771 0.22702 -0.32636 + C -1.82766 -1.05066 -0.11753 + C -2.1396 -1.91336 1.06268 + C -2.94728 -3.12173 0.90074 + C -3.19313 -3.99489 2.03853 + C -2.65688 -3.65647 3.34684 + C -1.87525 -2.44304 3.52124 + C -1.6261 -1.56595 2.38718 + H -2.55376 0.79953 -1.40907 + H -0.85548 -0.56065 0.00167 + H -1.77694 -1.6461 -1.03532 + H -3.45714 -3.31578 -0.03547 + H -3.86639 -4.83675 1.93453 + H -2.92599 -4.25257 4.20993 + H -1.5729 -2.13614 4.51483 + H -1.15487 -0.60473 2.55479 + + NAtoms= 16 NQM= 16 NQMF= 0 NMMI= 0 NMMIF= 0 + NMic= 0 NMicF= 0. + Isotopes and Nuclear Properties: + (Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) + in nuclear magnetons) + + Atom 1 2 3 4 5 6 7 8 9 10 + IAtWgt= 32 12 12 12 12 12 12 12 1 1 + AtmWgt= 31.9720718 12.0000000 12.0000000 12.0000000 12.0000000 12.0000000 12.0000000 12.0000000 1.0078250 1.0078250 + NucSpn= 0 0 0 0 0 0 0 0 1 1 + AtZEff= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 2.7928460 2.7928460 + AtZNuc= 16.0000000 6.0000000 6.0000000 6.0000000 6.0000000 6.0000000 6.0000000 6.0000000 1.0000000 1.0000000 + + Atom 11 12 13 14 15 16 + IAtWgt= 1 1 1 1 1 1 + AtmWgt= 1.0078250 1.0078250 1.0078250 1.0078250 1.0078250 1.0078250 + NucSpn= 1 1 1 1 1 1 + AtZEff= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 2.7928460 2.7928460 2.7928460 2.7928460 2.7928460 2.7928460 + AtZNuc= 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 + Leave Link 101 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 4.8 + (Enter /usr/local/g09/l103.exe) + + GradGradGradGradGradGradGradGradGradGradGradGradGradGradGradGradGradGrad + Berny optimization. + Initialization pass. + ---------------------------- + ! Initial Parameters ! + ! (Angstroms and Degrees) ! + -------------------------- -------------------------- + ! Name Definition Value Derivative Info. ! + -------------------------------------------------------------------------------- + ! R1 R(1,2) 1.8136 calculate D2E/DX2 analytically ! + ! R2 R(1,9) 1.3401 calculate D2E/DX2 analytically ! + ! R3 R(2,3) 1.4948 calculate D2E/DX2 analytically ! + ! R4 R(2,10) 1.0952 calculate D2E/DX2 analytically ! + ! R5 R(2,11) 1.0952 calculate D2E/DX2 analytically ! + ! R6 R(3,4) 1.4624 calculate D2E/DX2 analytically ! + ! R7 R(3,8) 1.4624 calculate D2E/DX2 analytically ! + ! R8 R(4,5) 1.4551 calculate D2E/DX2 analytically ! + ! R9 R(4,12) 1.0836 calculate D2E/DX2 analytically ! + ! R10 R(5,6) 1.4539 calculate D2E/DX2 analytically ! + ! R11 R(5,13) 1.083 calculate D2E/DX2 analytically ! + ! R12 R(6,7) 1.4539 calculate D2E/DX2 analytically ! + ! R13 R(6,14) 1.0829 calculate D2E/DX2 analytically ! + ! R14 R(7,8) 1.4551 calculate D2E/DX2 analytically ! + ! R15 R(7,15) 1.083 calculate D2E/DX2 analytically ! + ! R16 R(8,16) 1.0836 calculate D2E/DX2 analytically ! + ! A1 A(2,1,9) 96.301 calculate D2E/DX2 analytically ! + ! A2 A(1,2,3) 110.5709 calculate D2E/DX2 analytically ! + ! A3 A(1,2,10) 108.5996 calculate D2E/DX2 analytically ! + ! A4 A(1,2,11) 108.6 calculate D2E/DX2 analytically ! + ! A5 A(3,2,10) 110.9491 calculate D2E/DX2 analytically ! + ! A6 A(3,2,11) 110.9486 calculate D2E/DX2 analytically ! + ! A7 A(10,2,11) 107.059 calculate D2E/DX2 analytically ! + ! A8 A(2,3,4) 120.3109 calculate D2E/DX2 analytically ! + ! A9 A(2,3,8) 120.3112 calculate D2E/DX2 analytically ! + ! A10 A(4,3,8) 119.3735 calculate D2E/DX2 analytically ! + ! A11 A(3,4,5) 120.1678 calculate D2E/DX2 analytically ! + ! A12 A(3,4,12) 120.2338 calculate D2E/DX2 analytically ! + ! A13 A(5,4,12) 119.2494 calculate D2E/DX2 analytically ! + ! A14 A(4,5,6) 120.1081 calculate D2E/DX2 analytically ! + ! A15 A(4,5,13) 119.7621 calculate D2E/DX2 analytically ! + ! A16 A(6,5,13) 119.78 calculate D2E/DX2 analytically ! + ! A17 A(5,6,7) 120.0337 calculate D2E/DX2 analytically ! + ! A18 A(5,6,14) 119.8297 calculate D2E/DX2 analytically ! + ! A19 A(7,6,14) 119.8296 calculate D2E/DX2 analytically ! + ! A20 A(6,7,8) 120.1081 calculate D2E/DX2 analytically ! + ! A21 A(6,7,15) 119.7799 calculate D2E/DX2 analytically ! + ! A22 A(8,7,15) 119.7622 calculate D2E/DX2 analytically ! + ! A23 A(3,8,7) 120.1677 calculate D2E/DX2 analytically ! + ! A24 A(3,8,16) 120.2342 calculate D2E/DX2 analytically ! + ! A25 A(7,8,16) 119.2494 calculate D2E/DX2 analytically ! + ! D1 D(9,1,2,3) -179.9974 calculate D2E/DX2 analytically ! + ! D2 D(9,1,2,10) 58.0492 calculate D2E/DX2 analytically ! + ! D3 D(9,1,2,11) -58.0442 calculate D2E/DX2 analytically ! + ! D4 D(1,2,3,4) 90.3734 calculate D2E/DX2 analytically ! + ! D5 D(1,2,3,8) -90.3892 calculate D2E/DX2 analytically ! + ! D6 D(10,2,3,4) -149.0648 calculate D2E/DX2 analytically ! + ! D7 D(10,2,3,8) 30.1726 calculate D2E/DX2 analytically ! + ! D8 D(11,2,3,4) -30.1886 calculate D2E/DX2 analytically ! + ! D9 D(11,2,3,8) 149.0488 calculate D2E/DX2 analytically ! + ! D10 D(2,3,4,5) 176.9201 calculate D2E/DX2 analytically ! + ! D11 D(2,3,4,12) -9.9126 calculate D2E/DX2 analytically ! + ! D12 D(8,3,4,5) -2.3244 calculate D2E/DX2 analytically ! + ! D13 D(8,3,4,12) 170.8429 calculate D2E/DX2 analytically ! + ! D14 D(2,3,8,7) -176.919 calculate D2E/DX2 analytically ! + ! D15 D(2,3,8,16) 9.9116 calculate D2E/DX2 analytically ! + ! D16 D(4,3,8,7) 2.3255 calculate D2E/DX2 analytically ! + ! D17 D(4,3,8,16) -170.8439 calculate D2E/DX2 analytically ! + ! D18 D(3,4,5,6) 1.1235 calculate D2E/DX2 analytically ! + ! D19 D(3,4,5,13) 174.3182 calculate D2E/DX2 analytically ! + ! D20 D(12,4,5,6) -172.1108 calculate D2E/DX2 analytically ! + ! D21 D(12,4,5,13) 1.0839 calculate D2E/DX2 analytically ! + ! D22 D(4,5,6,7) 0.0978 calculate D2E/DX2 analytically ! + ! D23 D(4,5,6,14) 173.7245 calculate D2E/DX2 analytically ! + ! D24 D(13,5,6,7) -173.0956 calculate D2E/DX2 analytically ! + ! D25 D(13,5,6,14) 0.5311 calculate D2E/DX2 analytically ! + ! D26 D(5,6,7,8) -0.0967 calculate D2E/DX2 analytically ! + ! D27 D(5,6,7,15) 173.0982 calculate D2E/DX2 analytically ! + ! D28 D(14,6,7,8) -173.7234 calculate D2E/DX2 analytically ! + ! D29 D(14,6,7,15) -0.5285 calculate D2E/DX2 analytically ! + ! D30 D(6,7,8,3) -1.1257 calculate D2E/DX2 analytically ! + ! D31 D(6,7,8,16) 172.1107 calculate D2E/DX2 analytically ! + ! D32 D(15,7,8,3) -174.3219 calculate D2E/DX2 analytically ! + ! D33 D(15,7,8,16) -1.0854 calculate D2E/DX2 analytically ! + -------------------------------------------------------------------------------- + Trust Radius=3.00D-01 FncErr=1.00D-07 GrdErr=1.00D-06 + Number of steps in this run= 84 maximum allowed number of steps= 100. + GradGradGradGradGradGradGradGradGradGradGradGradGradGradGradGradGradGrad + + Leave Link 103 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 0.1 + (Enter /usr/local/g09/l202.exe) + Input orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 16 0 -3.097707 0.227023 -0.326361 + 2 6 0 -1.827656 -1.050664 -0.117526 + 3 6 0 -2.139602 -1.913365 1.062678 + 4 6 0 -2.947277 -3.121725 0.900738 + 5 6 0 -3.193127 -3.994893 2.038535 + 6 6 0 -2.656878 -3.656473 3.346845 + 7 6 0 -1.875251 -2.443044 3.521240 + 8 6 0 -1.626100 -1.565953 2.387185 + 9 1 0 -2.553758 0.799527 -1.409069 + 10 1 0 -0.855480 -0.560646 0.001672 + 11 1 0 -1.776939 -1.646101 -1.035315 + 12 1 0 -3.457144 -3.315784 -0.035467 + 13 1 0 -3.866390 -4.836747 1.934528 + 14 1 0 -2.925991 -4.252567 4.209932 + 15 1 0 -1.572900 -2.136139 4.514826 + 16 1 0 -1.154867 -0.604729 2.554792 + --------------------------------------------------------------------- + Distance matrix (angstroms): + 1 2 3 4 5 + 1 S 0.000000 + 2 C 1.813594 0.000000 + 3 C 2.725556 1.494807 0.000000 + 4 C 3.569666 2.565094 1.462429 0.000000 + 5 C 4.840084 3.896357 2.528828 1.455145 0.000000 + 6 C 5.363610 4.413584 2.919489 2.520659 1.453879 + 7 C 4.840216 3.896359 2.528827 2.911508 2.518621 + 8 C 3.569835 2.565097 1.462428 2.524967 2.911509 + 9 H 1.340112 2.370340 3.693351 4.567963 5.939801 + 10 H 2.399085 1.095195 2.145822 3.426815 4.626820 + 11 H 2.399091 1.095196 2.145817 2.701011 4.119584 + 12 H 3.572855 2.791547 2.215540 1.083560 2.198266 + 13 H 5.598594 4.764639 3.505436 2.203359 1.082967 + 14 H 6.377631 5.494126 3.999435 3.497145 2.202890 + 15 H 5.598810 4.764646 3.505439 3.990228 3.494585 + 16 H 3.573162 2.791557 2.215544 3.504839 3.989266 + 6 7 8 9 10 + 6 C 0.000000 + 7 C 1.453880 0.000000 + 8 C 2.520661 1.455145 0.000000 + 9 H 6.518074 5.939915 4.568105 0.000000 + 10 H 4.900956 4.119553 2.700957 2.593146 0.000000 + 11 H 4.900940 4.626768 3.426759 2.593113 1.761431 + 12 H 3.492352 3.989263 3.504835 4.431555 3.789567 + 13 H 2.202408 3.494582 3.990225 6.683579 5.575532 + 14 H 1.082899 2.202891 3.497145 7.565408 5.968815 + 15 H 2.202409 1.082968 2.203362 6.683768 4.833780 + 16 H 3.492353 2.198267 1.083561 4.431820 2.570992 + 11 12 13 14 15 + 11 H 0.000000 + 12 H 2.571114 0.000000 + 13 H 4.833839 2.522239 0.000000 + 14 H 5.968803 4.379851 2.530431 0.000000 + 15 H 5.575467 5.064297 4.383072 2.530432 0.000000 + 16 H 3.789498 4.399970 5.064293 4.379851 2.522242 + 16 + 16 H 0.000000 + Symmetry turned off by external request. + Stoichiometry C7H8S(7) + Framework group C1[X(C7H8S)] + Deg. of freedom 42 + Full point group C1 NOp 1 + Rotational constants (GHZ): 3.9816211 0.9669950 0.8561000 + Leave Link 202 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 0.1 + (Enter /usr/local/g09/l301.exe) + Standard basis: def2SVP (5D, 7F) + Ernie: Thresh= 0.10000D-02 Tol= 0.10000D-05 Strict=F. + 156 basis functions, 268 primitive gaussians, 164 cartesian basis functions + 36 alpha electrons 30 beta electrons + nuclear repulsion energy 385.6752275082 Hartrees. + IExCor= 4639 DFT=T Ex+Corr=wB97XD ExCW=0 ScaHFX= 1.000000 + ScaDFX= 1.000000 1.000000 1.000000 1.000000 ScalE2= 1.000000 1.000000 + IRadAn= 0 IRanWt= -1 IRanGd= 0 ICorTp=0 IEmpDi=121 + HFx wShort= 0.000000 wLong= 0.200000 cFull= 0.222036 cShort= 0.000000 cLong= 0.777964 + DFx wShort= 0.000000 wLong= 0.200000 cFull= 0.000000 cShort= 0.000000 cLong= 1.000000 + NAtoms= 16 NActive= 16 NUniq= 16 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F + Integral buffers will be 131072 words long. + Raffenetti 2 integral format. + Two-electron integral symmetry is turned off. + R6Disp: Grimme-D2 Dispersion energy= -0.0074942444 Hartrees. + Nuclear repulsion after empirical dispersion term = 385.6677332637 Hartrees. + Leave Link 301 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 0.7 + (Enter /usr/local/g09/l302.exe) + NPDir=0 NMtPBC= 1 NCelOv= 1 NCel= 1 NClECP= 1 NCelD= 1 + NCelK= 1 NCelE2= 1 NClLst= 1 CellRange= 0.0. + One-electron integrals computed using PRISM. + 1 Symmetry operations used in ECPInt. + ECPInt: NShTT= 2775 NPrTT= 10291 LenC2= 2731 LenP2D= 8006. + LDataN: DoStor=T MaxTD1= 4 Len= 56 + NBasis= 156 RedAO= T EigKep= 4.62D-04 NBF= 156 + NBsUse= 156 1.00D-06 EigRej= -1.00D+00 NBFU= 156 + Precomputing XC quadrature grid using + IXCGrd= 4 IRadAn= 0 IRanWt= -1 IRanGd= 0 AccXCQ= 0.00D+00. + Generated NRdTot= 0 NPtTot= 0 NUsed= 0 NTot= 32 + NSgBfM= 163 163 163 163 163 MxSgAt= 16 MxSgA2= 16. + Leave Link 302 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 2.1 + (Enter /usr/local/g09/l303.exe) + DipDrv: MaxL=1. + Leave Link 303 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 0.4 + (Enter /usr/local/g09/l401.exe) + Projected New-EHT guess. + Enter ItEHT: IZDO=4 IZDPar=0 Conv= 1.00D-06 N= 40 + It= 1 EEH= -60.8236394838 EQH= 0.000000000000E+00 EH= -60.8236394838 + JPrj=0 DoOrth=T DoCkMO=T. + Initial guess = 0.0000 = 0.0000 = 3.0000 =12.0000 S= 3.0000 + Leave Link 401 at Sat Aug 10 08:46:06 2024, MaxMem= 4294967296 cpu: 1.5 + (Enter /usr/local/g09/l502.exe) + UHF open shell SCF: + Two-electron integral symmetry not used. + Keep R1 and R2 ints in memory in canonical form, NReq=302285489. + IVT= 85985 IEndB= 85985 NGot= 4294967296 MDV= 3994927788 + LenX= 3994927788 LenY= 3994900728 + Requested convergence on RMS density matrix=1.00D-08 within 64 cycles. + Requested convergence on MAX density matrix=1.00D-06. + Requested convergence on energy=1.00D-06. + No special actions if energy rises. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 12246 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Integral accuracy reduced to 1.0D-05 until final iterations. + + Cycle 1 Pass 0 IDiag 1: + E= -665.951315699970 + Gap= -0.187 Goal= None Shift= 0.000 + Gap= 0.088 Goal= None Shift= 0.000 + RMSDP=3.47D-02 MaxDP=2.74D+00 OVMax= 9.51D-01 + + Cycle 2 Pass 0 IDiag 1: + E= -666.378570305519 Delta-E= -0.427254605549 Rises=F Damp=F + Gap= -0.313 Goal= None Shift= 0.000 + Gap= 0.375 Goal= None Shift= 0.000 + RMSDP=7.72D-02 MaxDP=3.43D+00 DE=-4.27D-01 OVMax= 9.93D-01 + + Cycle 3 Pass 0 IDiag 1: + E= -632.379969857807 Delta-E= 33.998600447712 Rises=F Damp=F + Gap= 1.363 Goal= None Shift= 0.000 + Gap= -0.066 Goal= None Shift= 0.000 + RMSDP=1.52D-01 MaxDP=9.38D+00 DE= 3.40D+01 OVMax= 9.98D-01 + + Cycle 4 Pass 0 IDiag 1: + E= -489.238198712169 Delta-E= 143.141771145638 Rises=F Damp=F + Gap= -1.552 Goal= None Shift= 0.000 + Gap= -0.003 Goal= None Shift= 0.000 + RMSDP=1.64D-01 MaxDP=9.57D+00 DE= 1.43D+02 OVMax= 9.65D-01 + + Problem detected with inexpensive integrals. + Switching to full accuracy and repeating last cycle. + Cycle 5 Pass 1 IDiag 1: + E= -489.230721473400 Delta-E= 0.007477238769 Rises=F Damp=F + Gap= -1.552 Goal= None Shift= 0.000 + Gap= -0.003 Goal= None Shift= 0.000 + RMSDP=1.64D-01 MaxDP=9.57D+00 DE= 7.48D-03 OVMax= 9.65D-01 + + Cycle 6 Pass 1 IDiag 1: + E= -301.862897180012 Delta-E= 187.367824293388 Rises=F Damp=F + Gap= 2.883 Goal= None Shift= 0.000 + Gap= -2.719 Goal= None Shift= 0.000 + RMSDP=1.79D-01 MaxDP=9.23D+00 DE= 1.87D+02 OVMax= 9.95D-01 + + Cycle 7 Pass 1 IDiag 1: + E= -292.817631630017 Delta-E= 9.045265549995 Rises=F Damp=F + Gap= -2.078 Goal= None Shift= 0.000 + Gap= -0.195 Goal= None Shift= 0.000 + RMSDP=1.88D-01 MaxDP=9.37D+00 DE= 9.05D+00 OVMax= 9.97D-01 + + Cycle 8 Pass 1 IDiag 1: + E= -215.300577486969 Delta-E= 77.517054143048 Rises=F Damp=F + Gap= -0.700 Goal= None Shift= 0.000 + Gap= -0.883 Goal= None Shift= 0.000 + RMSDP=1.88D-01 MaxDP=1.03D+01 DE= 7.75D+01 OVMax= 9.93D-01 + + Cycle 9 Pass 1 IDiag 1: + E= -297.102500799614 Delta-E= -81.801923312645 Rises=F Damp=F + Gap= -0.891 Goal= None Shift= 0.000 + Gap= -0.552 Goal= None Shift= 0.000 + 3-Point extrapolation. + RMSDP=1.90D-01 MaxDP=1.03D+01 DE=-8.18D+01 OVMax= 9.95D-01 + + Cycle 10 Pass 1 IDiag 1: + Spurious integrated density or basis function: + NE= 66 NElCor= 0 El error=8.92D+00 rel=1.35D-01 Tolerance=1.00D-03 + Shell 19 absolute error=1.35D-04 Tolerance=1.20D-02 + Shell 13 signed error=1.98D-05 Tolerance=1.00D-01 + Inaccurate quadrature in CalDSu. + Error termination via Lnk1e in /usr/local/g09/l502.exe at Sat Aug 10 08:46:11 2024. + Job cpu time: 0 days 0 hours 1 minutes 31.2 seconds. + File lengths (MBytes): RWF= 9 Int= 0 D2E= 0 Chk= 4 Scr= 1 diff --git a/arc/testing/spin/uhf_fragment_guess_doublet.out b/arc/testing/spin/uhf_fragment_guess_doublet.out new file mode 100644 index 0000000000..8f314bd52e --- /dev/null +++ b/arc/testing/spin/uhf_fragment_guess_doublet.out @@ -0,0 +1,246 @@ + Entering Gaussian System, Link 0=g16 + Initial command: + /usr/local/g16-gpu/g16/l1.exe "/scratch/g16/job/Gau-1868571.inp" -scrdir="/scratch/g16/job/" + Entering Link 1 = /usr/local/g16-gpu/g16/l1.exe PID= 1868577. + + Copyright (c) 1988-2021, Gaussian, Inc. All Rights Reserved. + + This is part of the Gaussian(R) 16 program. It is based on + the Gaussian(R) 09 system (copyright 2009, Gaussian, Inc.), + the Gaussian(R) 03 system (copyright 2003, Gaussian, Inc.), + the Gaussian(R) 98 system (copyright 1998, Gaussian, Inc.), + the Gaussian(R) 94 system (copyright 1995, Gaussian, Inc.), + the Gaussian 92(TM) system (copyright 1992, Gaussian, Inc.), + the Gaussian 90(TM) system (copyright 1990, Gaussian, Inc.), + the Gaussian 88(TM) system (copyright 1988, Gaussian, Inc.), + the Gaussian 86(TM) system (copyright 1986, Carnegie Mellon + University), and the Gaussian 82(TM) system (copyright 1983, + Carnegie Mellon University). Gaussian is a federally registered + trademark of Gaussian, Inc. + + This software contains proprietary and confidential information, + including trade secrets, belonging to Gaussian, Inc. + + This software is provided under written license and may be + used, copied, transmitted, or stored only in accord with that + written license. + + The following legend is applicable only to US Government + contracts under FAR: + + RESTRICTED RIGHTS LEGEND + + Use, reproduction and disclosure by the US Government is + subject to restrictions as set forth in subparagraphs (a) + and (c) of the Commercial Computer Software - Restricted + Rights clause in FAR 52.227-19. + + Gaussian, Inc. + 340 Quinnipiac St., Bldg. 40, Wallingford CT 06492 + + + --------------------------------------------------------------- + Warning -- This program may not be used in any manner that + competes with the business of Gaussian, Inc. or will provide + assistance to any competitor of Gaussian, Inc. The licensee + of this program is prohibited from giving any competitor of + Gaussian, Inc. access to this program. By using this program, + the user acknowledges that Gaussian, Inc. is engaged in the + business of creating and licensing software in the field of + computational chemistry and represents and warrants to the + licensee that it is not a competitor of Gaussian, Inc. and that + it will not use this program in any manner prohibited above. + --------------------------------------------------------------- + + + Cite this work as: + Gaussian 16, Revision C.02, + M. J. Frisch, G. W. Trucks, H. B. Schlegel, G. E. Scuseria, + M. A. Robb, J. R. Cheeseman, G. Scalmani, V. Barone, + G. A. Petersson, H. Nakatsuji, X. Li, M. Caricato, A. V. Marenich, + J. Bloino, B. G. Janesko, R. Gomperts, B. Mennucci, H. P. Hratchian, + J. V. Ortiz, A. F. Izmaylov, J. L. Sonnenberg, D. Williams-Young, + F. Ding, F. Lipparini, F. Egidi, J. Goings, B. Peng, A. Petrone, + T. Henderson, D. Ranasinghe, V. G. Zakrzewski, J. Gao, N. Rega, + G. Zheng, W. Liang, M. Hada, M. Ehara, K. Toyota, R. Fukuda, + J. Hasegawa, M. Ishida, T. Nakajima, Y. Honda, O. Kitao, H. Nakai, + T. Vreven, K. Throssell, J. A. Montgomery, Jr., J. E. Peralta, + F. Ogliaro, M. J. Bearpark, J. J. Heyd, E. N. Brothers, K. N. Kudin, + V. N. Staroverov, T. A. Keith, R. Kobayashi, J. Normand, + K. Raghavachari, A. P. Rendell, J. C. Burant, S. S. Iyengar, + J. Tomasi, M. Cossi, J. M. Millam, M. Klene, C. Adamo, R. Cammi, + J. W. Ochterski, R. L. Martin, K. Morokuma, O. Farkas, + J. B. Foresman, and D. J. Fox, Gaussian, Inc., Wallingford CT, 2019. + + ****************************************** + Gaussian 16: ES64L-G16RevC.02 7-Dec-2021 + 13-Aug-2026 + ****************************************** + %mem=16000mb + %NProcShared=8 + Will use up to 8 processors via shared memory. + %chk=check.chk + ---------------------------------------------------------------------- + #P ub3lyp/def2tzvp guess=(fragment=2,mix,always) integral=(grid=ultrafine, Acc2E + =12) scf=(direct,tight) + ---------------------------------------------------------------------- + 1/38=1,172=1/1; + 2/12=2,17=6,18=5,40=1/2; + 3/5=44,7=101,11=2,25=1,27=12,30=1,74=-5,75=-5,116=2/1,2,3; + 4//1; + 5/5=2,32=2,38=5,87=12/2; + 8/6=1,10=90,11=11,87=12/1; + 9/8=-1,42=1,87=12/14; + 6/7=2,8=2,9=2,10=2,28=1,87=12/1; + 99/5=1,9=1/99; + Leave Link 1 at Thu Aug 13 03:09:37 2026, MaxMem= 2097152000 cpu: 0.0 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l101.exe) + -------------------------------------------------- + fragment guess reaction_21_intra_halogen_migration + -------------------------------------------------- + Symbolic Z-matrix: + Charge = 0 Multiplicity = 2 + Charge = 0 Multiplicity = 2 for fragment 1 + Charge = 0 Multiplicity = 1 for fragment 2 + O(Fragment=1) 2.44052 -0.74022 0.00006 + C(Fragment=1) 1.2304 -0.15444 0.00004 + C(Fragment=1) 0.99241 1.16752 0.00007 + Cl(Fragment=2) -2.24715 -0.15396 -0.00008 + H(Fragment=1) 3.13998 -0.0719 0.0001 + H(Fragment=1) 0.42979 -0.88112 -0.00001 + H(Fragment=1) 1.79721 1.89374 0.00012 + H(Fragment=2) -0.02639 1.51989 0.00005 + + ITRead= 0 0 0 0 0 0 0 0 + MicOpt= -1 -1 -1 -1 -1 -1 -1 -1 + NAtoms= 8 NQM= 8 NQMF= 0 NMMI= 0 NMMIF= 0 + NMic= 0 NMicF= 0. + Isotopes and Nuclear Properties: + (Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) + in nuclear magnetons) + + Atom 1 2 3 4 5 6 7 8 + IAtWgt= 16 12 12 35 1 1 1 1 + AtmWgt= 15.9949146 12.0000000 12.0000000 34.9688527 1.0078250 1.0078250 1.0078250 1.0078250 + NucSpn= 0 0 0 3 1 1 1 1 + AtZEff= -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 -8.1650000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 0.0000000 0.0000000 0.0000000 0.8218740 2.7928460 2.7928460 2.7928460 2.7928460 + AtZNuc= 8.0000000 6.0000000 6.0000000 17.0000000 1.0000000 1.0000000 1.0000000 1.0000000 + Leave Link 101 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l202.exe) + Input orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 8 0 2.440519 -0.740222 0.000056 + 2 6 0 1.230401 -0.154439 0.000037 + 3 6 0 0.992406 1.167521 0.000070 + 4 17 0 -2.247152 -0.153960 -0.000079 + 5 1 0 3.139983 -0.071898 0.000098 + 6 1 0 0.429789 -0.881122 -0.000010 + 7 1 0 1.797209 1.893741 0.000117 + 8 1 0 -0.026387 1.519886 0.000049 + --------------------------------------------------------------------- + Distance matrix (angstroms): + 1 2 3 4 5 + 1 O 0.000000 + 2 C 1.344443 0.000000 + 3 C 2.395102 1.343213 0.000000 + 4 Cl 4.724189 3.477553 3.498721 0.000000 + 5 H 0.967423 1.911365 2.479566 5.387760 0.000000 + 6 H 2.015661 1.081225 2.124494 2.773946 2.828426 + 7 H 2.711385 2.125162 1.084022 4.533204 2.380500 + 8 H 3.345701 2.093533 1.078008 2.780927 3.543963 + 6 7 8 + 6 H 0.000000 + 7 H 3.093494 0.000000 + 8 H 2.443959 1.861524 0.000000 + Stoichiometry C2H4ClO(2) + Framework group C1[X(C2H4ClO)] + Deg. of freedom 18 + Full point group C1 NOp 1 + Largest Abelian subgroup C1 NOp 1 + Largest concise Abelian subgroup C1 NOp 1 + Standard orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 8 0 2.440519 -0.740222 0.000056 + 2 6 0 1.230401 -0.154439 0.000037 + 3 6 0 0.992406 1.167521 0.000070 + 4 17 0 -2.247152 -0.153960 -0.000079 + 5 1 0 3.139983 -0.071898 0.000098 + 6 1 0 0.429789 -0.881122 -0.000010 + 7 1 0 1.797209 1.893741 0.000117 + 8 1 0 -0.026387 1.519886 0.000049 + --------------------------------------------------------------------- + Rotational constants (GHZ): 15.3811042 1.6067831 1.4548071 + Leave Link 202 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l301.exe) + Standard basis: def2TZVP (5D, 7F) + Ernie: Thresh= 0.10000D-02 Tol= 0.10000D-05 Strict=F. + There are 174 symmetry adapted cartesian basis functions of A symmetry. + There are 154 symmetry adapted basis functions of A symmetry. + 154 basis functions, 254 primitive gaussians, 174 cartesian basis functions + 21 alpha electrons 20 beta electrons + nuclear repulsion energy 126.7866546617 Hartrees. + IExCor= 402 DFT=T Ex+Corr=B3LYP ExCW=0 ScaHFX= 0.200000 + ScaDFX= 0.800000 0.720000 1.000000 0.810000 ScalE2= 1.000000 1.000000 + IRadAn= 5 IRanWt= -1 IRanGd= 0 ICorTp=0 IEmpDi= 4 + NAtoms= 8 NActive= 8 NUniq= 8 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F + Integral buffers will be 131072 words long. + Raffenetti 2 integral format. + Two-electron integral symmetry is turned on. + Leave Link 301 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l302.exe) + NPDir=0 NMtPBC= 1 NCelOv= 1 NCel= 1 NClECP= 1 NCelD= 1 + NCelK= 1 NCelE2= 1 NClLst= 1 CellRange= 0.0. + One-electron integrals computed using PRISM. + One-electron integral symmetry used in STVInt + 1 Symmetry operations used in ECPInt. + ECPInt: NShTT= 1953 NPrTT= 6330 LenC2= 1888 LenP2D= 4987. + LDataN: DoStor=T MaxTD1= 6 Len= 172 + NBasis= 154 RedAO= T EigKep= 2.05D-04 NBF= 154 + NBsUse= 154 1.00D-06 EigRej= -1.00D+00 NBFU= 154 + Precomputing XC quadrature grid using + IXCGrd= 4 IRadAn= 5 IRanWt= -1 IRanGd= 0 AccXCQ= 1.00D-12. + Generated NRdTot= 0 NPtTot= 0 NUsed= 0 NTot= 32 + NSgBfM= 173 173 173 173 173 MxSgAt= 8 MxSgA2= 8. + Leave Link 302 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.7 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l303.exe) + DipDrv: MaxL=1. + Leave Link 303 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l401.exe) + ExpMin= 9.52D-02 ExpMax= 6.95D+04 ExpMxC= 2.37D+03 IAcc=3 IRadAn= 5 AccDes= 0.00D+00 + Harris functional with IExCor= 402 and IRadAn= 5 diagonalized for initial guess. + HarFok: IExCor= 402 AccDes= 0.00D+00 IRadAn= 5 IDoV= 1 UseB2=F ITyADJ=14 + ICtDFT= 3500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000 + FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0 + NFxFlg= 0 DoJE=T BraDBF=F KetDBF=T FulRan=T + wScrn= 0.000000 ICntrl= 500 IOpCl= 0 I1Cent= 200000004 NGrid= 0 + NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Petite list used in FoFCou. + Harris En= -614.011389393909 + JPrj=0 DoOrth=F DoCkMO=F. + Initial guess = 0.0000 = 0.0000 = 0.5000 = 0.7500 S= 0.5000 + Leave Link 401 at Thu Aug 13 03:09:40 2026, MaxMem= 2097152000 cpu: 2.1 elap: 0.4 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=8.08D-09 MaxDP=2.88D-07 DE=-1.75D-11 OVMax= 1.06D-06 + + SCF Done: E(UB3LYP) = -614.053677338 A.U. after 18 cycles + NFock= 18 Conv=0.81D-08 -V/T= 2.0023 + = 0.0000 = 0.0000 = 0.5000 = 0.7536 S= 0.5018 + = 0.00000000000 + KE= 6.126643386659D+02 PE=-1.708196810389D+03 EE= 3.546921397242D+02 + Annihilation of the first spin contaminant: + S**2 before annihilation 0.7536, after 0.7500 + Leave Link 502 at Thu Aug 13 03:09:49 2026, MaxMem= 2097152000 cpu: 41.7 elap: 8.7 + (Enter /usr/local/g16-gpu/g16/l801.exe) + DoSCS=F DFT=T ScalE2(SS,OS)= 1.000000 1.000000 + Range of M.O.s used for correlation: 1 154 + NBasis= 154 NAE= 21 NBE= 20 NFC= 0 NFV= 0 + NROrb= 154 NOA= 21 NOB= 20 NVA= 133 NVB= 134 + Normal termination of Gaussian 16 at Thu Aug 13 03:10:02 2026. diff --git a/arc/testing/stability/orca_rhf_uhf_instability_no_restart_crash.out b/arc/testing/stability/orca_rhf_uhf_instability_no_restart_crash.out new file mode 100644 index 0000000000..7c0c75c128 --- /dev/null +++ b/arc/testing/stability/orca_rhf_uhf_instability_no_restart_crash.out @@ -0,0 +1,933 @@ + + ***************** + * O R C A * + ***************** + + #, + ### + #### + ##### + ###### + ########, + ,,################,,,,, + ,,#################################,, + ,,##########################################,, + ,#########################################, ''#####, + ,#############################################,, '####, + ,##################################################,,,,####, + ,###########'''' ''''############################### + ,#####'' ,,,,##########,,,, '''####''' '#### + ,##' ,,,,###########################,,, '## + ' ,,###'''' '''############,,, + ,,##'' '''############,,,, ,,,,,,###'' + ,#'' '''#######################''' + ' ''''####'''' + ,#######, #######, ,#######, ## + ,#' '#, ## ## ,#' '#, #''# ,####, ,####, + ## ## ## ,#' ## #' '# #' #' '# + ## ## ####### ## ,######, #####, # # + '#, ,#' ## ## '#, ,#' ,# #, #, # #, ,# + '#######' ## ## '#######' #' '# '####' # '####' + + + + ######################################################### + # -***- # + # Department of theory and spectroscopy # + # # + # Frank Neese # + # # + # Directorship, Architecture, Infrastructure # + # SHARK, DRIVERS # + # Core code/Algorithms in most modules # + # # + # Max Planck Institute fuer Kohlenforschung # + # Kaiser Wilhelm Platz 1 # + # D-45470 Muelheim/Ruhr # + # Germany # + # # + # All rights reserved # + # -***- # + ######################################################### + + + Program Version 6.0.0 - RELEASE - + + + With contributions from (in alphabetic order): + Daniel Aravena : Magnetic Suceptibility + Michael Atanasov : Ab Initio Ligand Field Theory (pilot matlab implementation) + Alexander A. Auer : GIAO ZORA, VPT2 properties, NMR spectrum + Ute Becker : All parallelization in ORCA, NUMFREQ, NUMCALC + Giovanni Bistoni : ED, misc. LED, open-shell LED, HFLD + Martin Brehm : Molecular dynamics + Dmytro Bykov : pre 5.0 version of the SCF Hessian + Marcos Casanova-Páez : Triplet and SCS-CIS(D). UHF-(DLPNO)-IP/EA/STEOM-CCSD. UHF-CVS-IP/STEOM-CCSD + Vijay G. Chilkuri : MRCI spin determinant printing, contributions to CSF-ICE + Pauline Colinet : FMM embedding + Dipayan Datta : RHF DLPNO-CCSD density + Achintya Kumar Dutta : EOM-CC, STEOM-CC + Nicolas Foglia : Exact transition moments, OPA infrastructure, MCD improvements + Dmitry Ganyushin : Spin-Orbit,Spin-Spin,Magnetic field MRCI + Miquel Garcia : C-PCM and meta-GGA Hessian, CCSD/C-PCM, Gaussian charge scheme + Tiago L. C. Gouveia : GS-ROHF, GS-ROCIS + Yang Guo : DLPNO-NEVPT2, F12-NEVPT2, CIM, IAO-localization + Andreas Hansen : Spin unrestricted coupled pair/coupled cluster methods + Ingolf Harden : AUTO-CI MPn and infrastructure + Benjamin Helmich-Paris : MC-RPA, TRAH-(SCF,CASSCF), AVAS, COSX integrals, SCF dyn. polar. + Lee Huntington : MR-EOM, pCC + Robert Izsak : Overlap fitted RIJCOSX, COSX-SCS-MP3, EOM + Riya Kayal : Wick's Theorem for AUTO-CI, AUTO-CI UHF-CCSDT + Emily Kempfer : AUTO-CI, RHF CISDT and CCSDT + Christian Kollmar : KDIIS, OOCD, Brueckner-CCSD(T), CCSD density, CASPT2, CASPT2-K, improved NEVPT2 + Axel Koslowski : Symmetry handling + Simone Kossmann : Meta GGA functionals, TD-DFT gradient, OOMP2, (MP2 Hessian; deprecated post 5.0) + Lucas Lang : DCDCAS + Marvin Lechner : AUTO-CI (C++ implementation), FIC-MRCC + Spencer Leger : CASSCF response + Dagmar Lenk : GEPOL surface, SMD, ORCA-2-JSON + Dimitrios Liakos : Extrapolation schemes; Compound Job, initial MDCI parallelization + Dimitrios Manganas : Further ROCIS development; embedding schemes. LFT, Crystal Embedding + Dimitrios Pantazis : SARC Basis sets + Anastasios Papadopoulos: AUTO-CI, single reference methods and gradients + Taras Petrenko : pre 6.0 DFT Hessian and TD-DFT gradient, (ASA, deprecated), ECA, 1-Electron XAS/XES, NRVS + Peter Pinski : DLPNO-MP2, DLPNO-MP2 Gradient + Christoph Reimann : Effective Core Potentials + Marius Retegan : Local ZFS, SOC + Christoph Riplinger : Optimizer, TS searches, QM/MM, DLPNO-CCSD(T), (RO)-DLPNO pert. Triples + Michael Roemelt : Original ROCIS implementation + Masaaki Saitow : Open-shell DLPNO-CCSD energy and density + Barbara Sandhoefer : DKH picture change effects + Kantharuban Sivalingam : CASSCF convergence/infrastructure, NEVPT2 and variants, FIC-MRCI + Bernardo de Souza : ESD, SOC TD-DFT + Georgi Stoychev : AutoAux, RI-MP2 NMR, DLPNO-MP2 response, X2C + Van Anh Tran : RI-MP2 g-tensors + Willem Van den Heuvel : Paramagnetic NMR + Zikuan Wang : NOTCH, Electric field optimization + Frank Wennmohs : Technical directorship and infrastructure + Hang Xu : AUTO-CI-Response properties + + + We gratefully acknowledge several colleagues who have allowed us to + interface, adapt or use parts of their codes: + Stefan Grimme, W. Hujo, H. Kruse, P. Pracht, : VdW corrections, initial TS optimization, + C. Bannwarth, S. Ehlert, DFT functionals, gCP, sTDA/sTD-DF + L. Wittmann, M. Mueller + Ed Valeev, F. Pavosevic, A. Kumar : LibInt (2-el integral package), F12 methods + Garnet Chan, S. Sharma, J. Yang, R. Olivares : DMRG + Ulf Ekstrom : XCFun DFT Library + Mihaly Kallay : mrcc (arbitrary order and MRCC methods) + Frank Weinhold : gennbo (NPA and NBO analysis) + Simon Mueller : openCOSMO-RS + Christopher J. Cramer and Donald G. Truhlar : smd solvation model + Lars Goerigk : TD-DFT with DH, B97 family of functionals + V. Asgeirsson, H. Jonsson : NEB implementation + FAccTs GmbH : IRC, NEB, NEB-TS, DLPNO-Multilevel, CI-OPT + MM, QMMM, 2- and 3-layer-ONIOM, Crystal-QMMM, + LR-CPCM, SF, NACMEs, symmetry and pop. for TD-DFT, + nearIR, NL-DFT gradient (VV10), updates on ESD, + ML-optimized integration grids, MBIS, APM, + GOAT, DOCKER, SOLVATOR, interface openCOSMO-RS + S Lehtola, MJT Oliveira, MAL Marques : LibXC Library + Liviu Ungur et al : ANISO software + + + Your calculation uses the libint2 library for the computation of 2-el integrals + For citations please refer to: http://libint.valeyev.net + + Your ORCA version has been built with support for libXC version: 6.2.2 + For citations please refer to: https://libxc.gitlab.io + + This ORCA versions uses: + CBLAS interface : Fast vector & matrix operations + LAPACKE interface : Fast linear algebra routines + SCALAPACK package : Parallel linear algebra routines + Shared memory : Shared parallel matrices + BLAS/LAPACK : OpenBLAS 0.3.27 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Cooperlake SINGLE_THREADED + Core in use : Cooperlake + Copyright (c) 2011-2014, The OpenBLAS Project + + +NOTE: MaxCore=3500 MB was set to SCF,MP2,MDCI,CIPSI,MRCI and CIS + => If you want to overwrite this, your respective input block should be placed after the MaxCore statement +Warning: RI is on but no J-basis has been assigned. Assigning Def2/J (nothing to worry about!) +================================================================================ + +----- Orbital basis set information ----- +Your calculation utilizes the basis: def2-TZVP + F. Weigend and R. Ahlrichs, Phys. Chem. Chem. Phys. 7, 3297 (2005). + +----- AuxJ basis set information ----- +Your calculation utilizes the auxiliary basis: def2/J + F. Weigend, Phys. Chem. Chem. Phys. 8, 1057 (2006). + +================================================================================ + WARNINGS + Please study these warnings very carefully! +================================================================================ + + +================================================================================ + INPUT FILE +================================================================================ +NAME = input.in +| 1> !RKS B3LYP def2-TZVP TightSCF defgrid3 +| 2> %maxcore 3500 +| 3> %pal nprocs 8 end +| 4> +| 5> * xyz 0 1 +| 6> C 0.42654 1.47789 -0.00008 +| 7> C 0.49428 0.01192 0.00000 +| 8> C 1.79226 -0.71266 0.00004 +| 9> C -0.76953 -0.70318 0.00004 +| 10> C -2.09552 -0.11756 0.00001 +| 11> H 1.39854 1.97009 -0.00011 +| 12> H -0.16267 1.83052 -0.86690 +| 13> H 2.40601 -0.45645 -0.87511 +| 14> H 2.40600 -0.45637 0.87517 +| 15> H 1.65287 -1.79552 0.00009 +| 16> H -0.70100 -1.41388 0.84851 +| 17> H -0.70101 -1.41397 -0.84837 +| 18> H -2.27706 0.94605 -0.00004 +| 19> H -0.16266 1.83061 0.86672 +| 20> H -2.94717 -0.77952 0.00004 +| 21> * +| 22> +| 23> %scf +| 24> MaxIter 999 +| 25> STABPerform true +| 26> STABRestartUHFifUnstable false +| 27> STABNRoots 6 +| 28> end +| 29> +| 30> ****END OF INPUT**** +================================================================================ + + **************************** + * Single Point Calculation * + **************************** + +--------------------------------- +CARTESIAN COORDINATES (ANGSTROEM) +--------------------------------- + C 0.426540 1.477890 -0.000080 + C 0.494280 0.011920 0.000000 + C 1.792260 -0.712660 0.000040 + C -0.769530 -0.703180 0.000040 + C -2.095520 -0.117560 0.000010 + H 1.398540 1.970090 -0.000110 + H -0.162670 1.830520 -0.866900 + H 2.406010 -0.456450 -0.875110 + H 2.406000 -0.456370 0.875170 + H 1.652870 -1.795520 0.000090 + H -0.701000 -1.413880 0.848510 + H -0.701010 -1.413970 -0.848370 + H -2.277060 0.946050 -0.000040 + H -0.162660 1.830610 0.866720 + H -2.947170 -0.779520 0.000040 + +---------------------------- +CARTESIAN COORDINATES (A.U.) +---------------------------- + NO LB ZA FRAG MASS X Y Z + 0 C 6.0000 0 12.011 0.806044 2.792807 -0.000151 + 1 C 6.0000 0 12.011 0.934054 0.022526 0.000000 + 2 C 6.0000 0 12.011 3.386881 -1.346732 0.000076 + 3 C 6.0000 0 12.011 -1.454201 -1.328818 0.000076 + 4 C 6.0000 0 12.011 -3.959959 -0.222156 0.000019 + 5 H 1.0000 0 1.008 2.642858 3.722931 -0.000208 + 6 H 1.0000 0 1.008 -0.307402 3.459181 -1.638204 + 7 H 1.0000 0 1.008 4.546700 -0.862565 -1.653718 + 8 H 1.0000 0 1.008 4.546681 -0.862414 1.653832 + 9 H 1.0000 0 1.008 3.123472 -3.393041 0.000170 + 10 H 1.0000 0 1.008 -1.324698 -2.671846 1.603452 + 11 H 1.0000 0 1.008 -1.324717 -2.672016 -1.603187 + 12 H 1.0000 0 1.008 -4.303020 1.787775 -0.000076 + 13 H 1.0000 0 1.008 -0.307383 3.459352 1.637863 + 14 H 1.0000 0 1.008 -5.569344 -1.473079 0.000076 + +-------------------------------- +INTERNAL COORDINATES (ANGSTROEM) +-------------------------------- + C 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 1.467534243178 0.00000000 0.00000000 + C 2 1 0 1.486528929554 121.81751498 0.00000000 + C 2 1 3 1.452096321771 116.85676884 179.99993602 + C 4 2 1 1.449551746369 126.66904732 0.00000000 + H 1 2 3 1.089515874552 114.21101881 0.00000000 + H 1 2 3 1.105845040410 110.07045239 123.43469396 + H 3 2 1 1.099190679136 111.95675548 300.85933157 + H 3 2 1 1.099187822258 111.95678016 59.14175764 + H 3 2 1 1.091794556773 111.83685328 180.00051020 + H 4 2 1 1.108914871304 105.17994891 232.44431358 + H 4 2 1 1.108926031167 105.18012877 127.55483417 + H 5 4 2 1.078991661784 123.51459171 0.00000000 + H 1 2 3 1.105852738117 110.07002741 236.56635973 + H 5 4 2 1.078655999381 118.31470748 179.99959841 + +--------------------------- +INTERNAL COORDINATES (A.U.) +--------------------------- + C 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 2.773237811758 0.00000000 0.00000000 + C 2 1 0 2.809132567008 121.81751498 0.00000000 + C 2 1 3 2.744064368221 116.85676884 179.99993602 + C 4 2 1 2.739255817584 126.66904732 0.00000000 + H 1 2 3 2.058886621462 114.21101881 0.00000000 + H 1 2 3 2.089744272930 110.07045239 123.43469396 + H 3 2 1 2.077169352526 111.95675548 300.85933157 + H 3 2 1 2.077163953809 111.95678016 59.14175764 + H 3 2 1 2.063192706808 111.83685328 180.00051020 + H 4 2 1 2.095545412598 105.17994891 232.44431358 + H 4 2 1 2.095566501682 105.18012877 127.55483417 + H 5 4 2 2.038998741557 123.51459171 0.00000000 + H 1 2 3 2.089758819487 110.07002741 236.56635973 + H 5 4 2 2.038364431541 118.31470748 179.99959841 + +--------------------- +BASIS SET INFORMATION +--------------------- +There are 2 groups of distinct atoms + + Group 1 Type C : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 2 Type H : 5s1p contracted to 3s1p pattern {311/1} + +Atom 0C basis set group => 1 +Atom 1C basis set group => 1 +Atom 2C basis set group => 1 +Atom 3C basis set group => 1 +Atom 4C basis set group => 1 +Atom 5H basis set group => 2 +Atom 6H basis set group => 2 +Atom 7H basis set group => 2 +Atom 8H basis set group => 2 +Atom 9H basis set group => 2 +Atom 10H basis set group => 2 +Atom 11H basis set group => 2 +Atom 12H basis set group => 2 +Atom 13H basis set group => 2 +Atom 14H basis set group => 2 +--------------------------------- +AUXILIARY/J BASIS SET INFORMATION +--------------------------------- +There are 2 groups of distinct atoms + + Group 1 Type C : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 2 Type H : 5s2p1d contracted to 3s1p1d pattern {311/2/1} + +Atom 0C basis set group => 1 +Atom 1C basis set group => 1 +Atom 2C basis set group => 1 +Atom 3C basis set group => 1 +Atom 4C basis set group => 1 +Atom 5H basis set group => 2 +Atom 6H basis set group => 2 +Atom 7H basis set group => 2 +Atom 8H basis set group => 2 +Atom 9H basis set group => 2 +Atom 10H basis set group => 2 +Atom 11H basis set group => 2 +Atom 12H basis set group => 2 +Atom 13H basis set group => 2 +Atom 14H basis set group => 2 + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------ + ORCA STARTUP CALCULATIONS + -- RI-GTO INTEGRALS CHOSEN -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + ___ + / \ - P O W E R E D B Y - + / \ + | | | _ _ __ _____ __ __ + | | | | | | | / \ | _ \ | | / | + \ \/ | | | | / \ | | | | | | / / + / \ \ | |__| | / /\ \ | |_| | | |/ / + | | | | __ | / /__\ \ | / | \ + | | | | | | | | __ | | \ | |\ \ + \ / | | | | | | | | | |\ \ | | \ \ + \___/ |_| |_| |__| |__| |_| \__\ |__| \__/ + + - O R C A' S B I G F R I E N D - + & + - I N T E G R A L F E E D E R - + + v1 FN, 2020, v2 2021, v3 2022-2024 +------------------------------------------------------------------------------ + + +---------------------- +SHARK INTEGRAL PACKAGE +---------------------- + +Number of atoms ... 15 +Number of basis functions ... 215 +Number of shells ... 95 +Maximum angular momentum ... 3 +Integral batch strategy ... SHARK/LIBINT Hybrid +RI-J (if used) integral strategy ... SPLIT-RIJ (Revised 2003 algorithm where possible) +Printlevel ... 1 +Contraction scheme used ... SEGMENTED contraction +Prescreening option ... SCHWARTZ + Thresh ... 2.500e-11 + Tcut ... 2.500e-12 + Tpresel ... 2.500e-12 +Coulomb Range Separation ... NOT USED +Exchange Range Separation ... NOT USED +Multipole approximations ... NOT USED +Finite Nucleus Model ... NOT USED +CABS basis ... NOT available +Auxiliary Coulomb fitting basis ... AVAILABLE + # of basis functions in Aux-J ... 355 + # of shells in Aux-J ... 125 + Maximum angular momentum in Aux-J ... 4 +Auxiliary J/K fitting basis ... NOT available +Auxiliary Correlation fitting basis ... NOT available +Auxiliary 'external' fitting basis ... NOT available + +Checking pre-screening integrals ... done ( 0.0 sec) Dimension = 95 +Check shell pair data ... done ( 0.0 sec) +Shell pair information +Shell pair cut-off parameter TPreSel ... 2.5e-12 +Total number of shell pairs ... 4560 +Shell pairs after pre-screening ... 4367 +Total number of primitive shell pairs ... 13020 +Primitive shell pairs kept ... 9947 + la=0 lb=0: 1434 shell pairs + la=1 lb=0: 1323 shell pairs + la=1 lb=1: 315 shell pairs + la=2 lb=0: 537 shell pairs + la=2 lb=1: 246 shell pairs + la=2 lb=2: 55 shell pairs + la=3 lb=0: 267 shell pairs + la=3 lb=1: 125 shell pairs + la=3 lb=2: 50 shell pairs + la=3 lb=3: 15 shell pairs + +Calculating one electron integrals ... done ( 0.0 sec) +Calculating RI/J V-Matrix + Cholesky decomp.... done ( 0.0 sec) +Calculating Nuclear repulsion ... done ( 0.0 sec) ENN= 175.283398255429 Eh + +Diagonalization of the overlap matrix: +Smallest eigenvalue ... 1.549e-04 +Time for diagonalization ... 0.007 sec +Threshold for overlap eigenvalues ... 1.000e-07 +Number of eigenvalues below threshold ... 0 +Time for construction of square roots ... 0.004 sec +Total time needed ... 0.012 sec + +------------------- +DFT GRID GENERATION +------------------- + +General Integration Accuracy IntAcc ... 4.959 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 6 (Lebedev-590) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... off +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 158925 +Total number of batches ... 2492 +Average number of points per batch ... 63 +Average number of grid points per atom ... 10595 + +-------------------- +COSX GRID GENERATION +-------------------- + +GRIDX 1 +------- +General Integration Accuracy IntAcc ... 4.020 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 2 (Lebedev-110) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 16670 +Total number of batches ... 138 +Average number of points per batch ... 120 +Average number of grid points per atom ... 1111 +UseSFitting ... on + +GRIDX 2 +------- +General Integration Accuracy IntAcc ... 4.338 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 3 (Lebedev-194) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 36498 +Total number of batches ... 295 +Average number of points per batch ... 123 +Average number of grid points per atom ... 2433 +UseSFitting ... on + +GRIDX 3 +------- +General Integration Accuracy IntAcc ... 4.871 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 4 (Lebedev-302) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 72764 +Total number of batches ... 576 +Average number of points per batch ... 126 +Average number of grid points per atom ... 4851 +UseSFitting ... on +Initializing property integral containers ... done ( 0.0 sec) + +SHARK setup successfully completed in 4.0 seconds + +Maximum memory used throughout the entire STARTUP-calculation: 35.5 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------- + ORCA GUESS + Start orbitals & Density for SCF / CASSCF +------------------------------------------------------------------------------- + +------------ +SCF SETTINGS +------------ +Hamiltonian: + Density Functional Method .... DFT(GTOs) + Exchange Functional Exchange .... B88 + X-Alpha parameter XAlpha .... 0.666667 + Becke's b parameter XBeta .... 0.004200 + Correlation Functional Correlation .... LYP + LDA part of GGA corr. LDAOpt .... VWN-5 + Gradients option PostSCFGGA .... off + Hybrid DFT is turned on + Fraction HF Exchange ScalHFX .... 0.200000 + Scaling of DF-GGA-X ScalDFX .... 0.720000 + Scaling of DF-GGA-C ScalDFC .... 0.810000 + Scaling of DF-LDA-C ScalLDAC .... 1.000000 + Perturbative correction .... 0.000000 + NL short-range parameter .... 4.800000 + RI-approximation to the Coulomb term is turned on + Number of AuxJ basis functions .... 355 + RIJ-COSX (HFX calculated with COS-X)).... on + + +General Settings: + Integral files IntName .... input + Hartree-Fock type HFTyp .... RHF + Total Charge Charge .... 0 + Multiplicity Mult .... 1 + Number of Electrons NEL .... 40 + Basis Dimension Dim .... 215 + Nuclear Repulsion ENuc .... 175.2833982554 Eh + +Convergence Acceleration: + AO-DIIS CNVDIIS .... on + Start iteration DIISMaxIt .... 12 + Startup error DIISStart .... 0.200000 + # of expansion vecs DIISMaxEq .... 5 + Bias factor DIISBfac .... 1.050 + Max. coefficient DIISMaxC .... 10.000 + MO-DIIS CNVKDIIS .... off + Trust-Rad. Augm. Hess. CNVTRAH .... auto + Auto Start mean grad. ratio tolernc. .... 1.125000 + Auto Start start iteration .... 50 + Auto Start num. interpolation iter. .... 10 + Max. Number of Micro iterations .... 24 + Max. Number of Macro iterations .... Maxiter - #DIIS iter + Number of Davidson start vectors .... 2 + Converg. threshold (grad. norm) .... 1.000e-05 + Grad. Scal. Fac. for Micro threshold .... 0.100 + Minimum threshold for Micro iter. .... 1.000e-02 + NR start threshold (gradient norm) .... 1.000e-04 + Initial trust radius .... 0.400 + Minimum AH scaling param. (alpha) .... 1.000 + Maximum AH scaling param. (alpha) .... 1000.000 + Quad. conv. algorithm .... NR + White noise on init. David. guess .... on + Maximum white noise .... 0.010 + Pseudo random numbers .... off + Inactive MOs .... canonical + Orbital update algorithm .... Taylor + Preconditioner .... Diag + Full preconditioner red. dimension .... 250 + SOSCF CNVSOSCF .... on + Start iteration SOSCFMaxIt .... 150 + Startup grad/error SOSCFStart .... 0.003300 + Hessian update SOSCFHessUp .... L-BFGS + Level Shifting CNVShift .... on + Level shift para. LevelShift .... 0.2500 + Turn off err/grad. ShiftErr .... 0.0010 + Zerner damping CNVZerner .... off + Static damping CNVDamp .... on + Fraction old density DampFac .... 0.7000 + Max. Damping (<1) DampMax .... 0.9800 + Min. Damping (>=0) DampMin .... 0.0000 + Turn off err/grad. DampErr .... 0.1000 + +SCF Procedure: + Maximum # iterations MaxIter .... 999 + SCF integral mode SCFMode .... Direct + Integral package .... SHARK and LIBINT hybrid scheme + Reset frequency DirectResetFreq .... 20 + Integral Threshold Thresh .... 2.500e-11 Eh + Primitive CutOff TCut .... 2.500e-12 Eh + +Convergence Tolerance: + Convergence Check Mode ConvCheckMode .... Total+1el-Energy + Convergence forced ConvForced .... 0 + Energy Change TolE .... 1.000e-08 Eh + 1-El. energy change .... 1.000e-05 Eh + Orbital Gradient TolG .... 1.000e-05 + Orbital Rotation angle TolX .... 1.000e-05 + DIIS Error TolErr .... 5.000e-07 + +------------------------------ +INITIAL GUESS: MODEL POTENTIAL +------------------------------ +Loading Hartree-Fock densities ... done +Calculating cut-offs ... done +Initializing the effective Hamiltonian ... done +Setting up the integral package (SHARK) ... done +Starting the Coulomb interaction ... done ( 0.1 sec) +Making the grid ... done ( 0.1 sec) +Mapping shells ... done +Starting the XC term evaluation ... done ( 0.1 sec) + promolecular density results + # of electrons = 39.996852652 + EX = -28.647031281 + EC = -1.263803968 + EX+EC = -29.910835249 +Transforming the Hamiltonian ... done ( 0.0 sec) +Diagonalizing the Hamiltonian ... done ( 0.0 sec) +Back transforming the eigenvectors ... done ( 0.0 sec) +Now organizing SCF variables ... done + ------------------ + INITIAL GUESS DONE ( 0.3 sec) + ------------------ + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** +Finished Guess after 0.6 sec +Maximum memory used throughout the entire GUESS-calculation: 12.6 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------------------- + ORCA LEAN-SCF + memory conserving SCF solver +------------------------------------------------------------------------------------------- + +----------------------------------------D-I-I-S-------------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP DIISErr Damp Time(sec) +------------------------------------------------------------------------------------------- + *** Starting incremental Fock matrix formation *** + 1 -196.0631216676143254 0.00e+00 2.17e-03 7.83e-02 2.64e-01 0.700 3.8 +Warning: op=0 Small HOMO/LUMO gap ( 0.060) - skipping pre-diagonalization + Will do a full diagonalization + 2 -196.2046327368354355 -1.42e-01 1.84e-03 5.97e-02 1.16e-01 0.700 2.1 + ***Turning on AO-DIIS*** + 3 -196.2519339736680877 -4.73e-02 8.55e-04 2.27e-02 4.87e-02 0.700 2.2 + 4 -196.2783567095005992 -2.64e-02 1.34e-03 2.97e-02 3.11e-02 0.000 2.2 + 5 -196.3417793528537914 -6.34e-02 5.30e-04 1.48e-02 1.66e-02 0.000 2.2 + 6 -196.3440455722681008 -2.27e-03 2.84e-04 7.52e-03 7.59e-03 0.000 2.1 + *** Initializing SOSCF *** +---------------------------------------S-O-S-C-F-------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP MaxGrad Time(sec) +-------------------------------------------------------------------------------------- + 7 -196.3444183600858537 -3.73e-04 1.56e-04 4.06e-03 2.35e-03 2.1 + *** Restarting incremental Fock matrix formation *** + 8 -196.3445203074584242 -1.02e-04 1.74e-04 4.84e-03 9.59e-04 3.7 + 9 -196.3445633162007766 -4.30e-05 8.86e-05 2.63e-03 2.38e-04 3.1 + 10 -196.3445652928795084 -1.98e-06 2.74e-05 1.50e-03 4.22e-04 3.1 + 11 -196.3445654022830809 -1.09e-07 3.32e-05 7.27e-04 6.59e-04 2.9 + 12 -196.3445655813749795 -1.79e-07 1.83e-05 9.82e-04 2.73e-04 2.8 + 13 -196.3445680698875435 -2.49e-06 5.28e-06 2.30e-04 6.96e-05 2.8 + 14 -196.3445681545698562 -8.47e-08 1.94e-06 4.39e-05 2.40e-05 2.7 + 15 -196.3445681718264382 -1.73e-08 8.48e-07 2.17e-05 8.68e-06 2.4 + 16 -196.3445681740595319 -2.23e-09 6.54e-07 1.53e-05 4.92e-06 2.4 + **** Energy Check signals convergence **** + + ***************************************************** + * SUCCESS * + * SCF CONVERGED AFTER 16 CYCLES * + ***************************************************** + +Recomputing exchange energy using gridx3 ... done ( 5.354 sec) +Old exchange energy : -5.867459883 Eh +New exchange energy : -5.867463289 Eh +Exchange energy change after final integration : -0.000003406 Eh +Total energy after final integration : -196.344571580 Eh + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** + +------------------------------------------------------------------------------------------- + WAVEFUNCTION STABILITY ANALYSIS +------------------------------------------------------------------------------------------- + + + ****Iteration 0**** + Lowest Energy : -0.050808103995 + Maximum Energy change : 0.176441058154 (vector 5) + Maximum residual norm : 0.011573406343 + + ****Iteration 1**** + Lowest Energy : -0.064545460780 + Maximum Energy change : 0.013737356786 (vector 0) + Maximum residual norm : 0.000123615590 + + ****Iteration 2**** + Lowest Energy : -0.064661510340 + Maximum Energy change : 0.000359636365 (vector 4) + Maximum residual norm : 0.000017665730 + + *** CONVERGENCE OF RESIDUAL NORM REACHED *** +The eigenvalues of the stability matrix: + E( 0) = -0.06466151 Eh + E( 1) = 0.13214783 Eh + E( 2) = 0.13729508 Eh + E( 3) = 0.16645879 Eh + E( 4) = 0.17203969 Eh + E( 5) = 0.17440600 Eh + +The stability analysis indicates that the wavefunction is unstable + +---------------- +TOTAL SCF ENERGY +---------------- + +Total Energy : -196.34457158019171 Eh -5342.80742 eV + +Components: +Nuclear Repulsion : 175.28339825542940 Eh 4769.70375 eV +Electronic Energy : -371.62796642948894 Eh -10112.51108 eV +One Electron Energy: -609.41658549609213 Eh -16583.06836 eV +Two Electron Energy: 237.78861906660319 Eh 6470.55728 eV + +Virial components: +Potential Energy : -391.70793424638919 Eh -10658.91478 eV +Kinetic Energy : 195.36336266619747 Eh 5316.10736 eV +Virial Ratio : 2.00502248170078 + +DFT components: +N(Alpha) : 20.000000262242 electrons +N(Beta) : 20.000000262242 electrons +N(Total) : 40.000000524484 electrons +E(X) : -23.310385127866 Eh +E(C) : -1.505068409462 Eh +E(XC) : -24.815453537327 Eh + +--------------- +SCF CONVERGENCE +--------------- + + Last Energy change ... 2.2331e-09 Tolerance : 1.0000e-08 + Last MAX-Density change ... 1.5339e-05 Tolerance : 1.0000e-07 + Last RMS-Density change ... 6.5446e-07 Tolerance : 5.0000e-09 + Last DIIS Error ... 2.3468e-03 Tolerance : 5.0000e-07 + Last Orbital Gradient ... 4.9248e-06 Tolerance : 1.0000e-05 + Last Orbital Rotation ... 5.6889e-06 Tolerance : 1.0000e-05 + + +---------------------- +UHF SPIN CONTAMINATION +---------------------- + +Warning: in a DFT calculation there is little theoretical justification to + calculate as in Hartree-Fock theory. We will do it anyways + but you should keep in mind that the values have only limited relevance + +Expectation value of : 0.000000 +Ideal value S*(S+1) for S=0.0 : 0.000000 +Deviation : 0.000000 + +---------------- +ORBITAL ENERGIES +---------------- + SPIN UP ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -10.186338 -277.1844 + 1 1.0000 -10.179246 -276.9914 + 2 1.0000 -10.172950 -276.8201 + 3 1.0000 -10.168649 -276.7030 + 4 1.0000 -10.137486 -275.8550 + 5 1.0000 -0.824948 -22.4480 + 6 1.0000 -0.735039 -20.0014 + 7 1.0000 -0.704737 -19.1769 + 8 1.0000 -0.613183 -16.6856 + 9 1.0000 -0.527818 -14.3627 + 10 1.0000 -0.467064 -12.7094 + 11 1.0000 -0.454105 -12.3568 + 12 1.0000 -0.440257 -11.9800 + 13 1.0000 -0.401353 -10.9214 + 14 1.0000 -0.391448 -10.6518 + 15 1.0000 -0.389516 -10.5993 + 16 1.0000 -0.379348 -10.3226 + 17 1.0000 -0.358968 -9.7680 + 18 1.0000 -0.336793 -9.1646 + 19 1.0000 -0.144940 -3.9440 + 20 0.0000 -0.073085 -1.9888 + 21 0.0000 0.026832 0.7301 + 22 0.0000 0.064730 1.7614 + 23 0.0000 0.069395 1.8883 + 24 0.0000 0.099459 2.7064 + 25 0.0000 0.100818 2.7434 + 26 0.0000 0.107767 2.9325 + 27 0.0000 0.110701 3.0123 + 28 0.0000 0.113847 3.0979 + 29 0.0000 0.126594 3.4448 + 30 0.0000 0.144874 3.9422 + + SPIN DOWN ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -10.186338 -277.1844 + 1 1.0000 -10.179246 -276.9914 + 2 1.0000 -10.172950 -276.8201 + 3 1.0000 -10.168649 -276.7030 + 4 1.0000 -10.137486 -275.8550 + 5 1.0000 -0.824948 -22.4480 + 6 1.0000 -0.735039 -20.0014 + 7 1.0000 -0.704737 -19.1769 + 8 1.0000 -0.613183 -16.6856 + 9 1.0000 -0.527818 -14.3627 + 10 1.0000 -0.467064 -12.7094 + 11 1.0000 -0.454105 -12.3568 + 12 1.0000 -0.440257 -11.9800 + 13 1.0000 -0.401353 -10.9214 + 14 1.0000 -0.391448 -10.6518 + 15 1.0000 -0.389516 -10.5993 + 16 1.0000 -0.379348 -10.3226 + 17 1.0000 -0.358968 -9.7680 + 18 1.0000 -0.336793 -9.1646 + 19 1.0000 -0.144940 -3.9440 + 20 0.0000 -0.073085 -1.9888 + 21 0.0000 0.026832 0.7301 + 22 0.0000 0.064730 1.7614 + 23 0.0000 0.069395 1.8883 + 24 0.0000 0.099459 2.7064 + 25 0.0000 0.100818 2.7434 + 26 0.0000 0.107767 2.9325 + 27 0.0000 0.110701 3.0123 + 28 0.0000 0.113847 3.0979 + 29 0.0000 0.126594 3.4448 + 30 0.0000 0.144874 3.9422 +*Only the first 10 virtual orbitals were printed. +Warning (TDensityContainer): Failed to retrieve input.scfr + + ******************************** + * MULLIKEN POPULATION ANALYSIS * + ******************************** + +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BLAS_Trace: INPUT DIMENSIONS A=0,0 B=215,215 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! FATAL ERROR ENCOUNTERED !!! +!!! ----------------------- !!! +!!! BLAS-ERROR !!! +!!! INCOMPATIBLE MATRICES OR VECTORS FOUND !!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +-------------------------------------------------------------------------- +Primary job terminated normally, but 1 process returned +a non-zero exit code. Per user-direction, the job has been aborted. +-------------------------------------------------------------------------- +-------------------------------------------------------------------------- +mpirun detected that one or more processes exited with non-zero status, thus causing +the job to be terminated. The first process to do so was: + + Process name: [[45377,1],4] + Exit code: 62 +-------------------------------------------------------------------------- + +ORCA finished by error termination in LEANSCF +Calling Command: mpirun -np 8 /usr/local/orca6/orca_leanscf_mpi input.gbw input +[file orca_tools/qcmsg.cpp, line 394]: + .... aborting the run + +[file orca_tools/qcmsg.cpp, line 394]: + .... aborting the run + diff --git a/arc/testing/stability/orca_rhf_uhf_instability_singlet_ts.out b/arc/testing/stability/orca_rhf_uhf_instability_singlet_ts.out new file mode 100644 index 0000000000..cfd2ace2d7 --- /dev/null +++ b/arc/testing/stability/orca_rhf_uhf_instability_singlet_ts.out @@ -0,0 +1,1786 @@ + + ***************** + * O R C A * + ***************** + + #, + ### + #### + ##### + ###### + ########, + ,,################,,,,, + ,,#################################,, + ,,##########################################,, + ,#########################################, ''#####, + ,#############################################,, '####, + ,##################################################,,,,####, + ,###########'''' ''''############################### + ,#####'' ,,,,##########,,,, '''####''' '#### + ,##' ,,,,###########################,,, '## + ' ,,###'''' '''############,,, + ,,##'' '''############,,,, ,,,,,,###'' + ,#'' '''#######################''' + ' ''''####'''' + ,#######, #######, ,#######, ## + ,#' '#, ## ## ,#' '#, #''# ,####, ,####, + ## ## ## ,#' ## #' '# #' #' '# + ## ## ####### ## ,######, #####, # # + '#, ,#' ## ## '#, ,#' ,# #, #, # #, ,# + '#######' ## ## '#######' #' '# '####' # '####' + + + + ######################################################### + # -***- # + # Department of theory and spectroscopy # + # # + # Frank Neese # + # # + # Directorship, Architecture, Infrastructure # + # SHARK, DRIVERS # + # Core code/Algorithms in most modules # + # # + # Max Planck Institute fuer Kohlenforschung # + # Kaiser Wilhelm Platz 1 # + # D-45470 Muelheim/Ruhr # + # Germany # + # # + # All rights reserved # + # -***- # + ######################################################### + + + Program Version 6.0.0 - RELEASE - + + + With contributions from (in alphabetic order): + Daniel Aravena : Magnetic Suceptibility + Michael Atanasov : Ab Initio Ligand Field Theory (pilot matlab implementation) + Alexander A. Auer : GIAO ZORA, VPT2 properties, NMR spectrum + Ute Becker : All parallelization in ORCA, NUMFREQ, NUMCALC + Giovanni Bistoni : ED, misc. LED, open-shell LED, HFLD + Martin Brehm : Molecular dynamics + Dmytro Bykov : pre 5.0 version of the SCF Hessian + Marcos Casanova-Páez : Triplet and SCS-CIS(D). UHF-(DLPNO)-IP/EA/STEOM-CCSD. UHF-CVS-IP/STEOM-CCSD + Vijay G. Chilkuri : MRCI spin determinant printing, contributions to CSF-ICE + Pauline Colinet : FMM embedding + Dipayan Datta : RHF DLPNO-CCSD density + Achintya Kumar Dutta : EOM-CC, STEOM-CC + Nicolas Foglia : Exact transition moments, OPA infrastructure, MCD improvements + Dmitry Ganyushin : Spin-Orbit,Spin-Spin,Magnetic field MRCI + Miquel Garcia : C-PCM and meta-GGA Hessian, CCSD/C-PCM, Gaussian charge scheme + Tiago L. C. Gouveia : GS-ROHF, GS-ROCIS + Yang Guo : DLPNO-NEVPT2, F12-NEVPT2, CIM, IAO-localization + Andreas Hansen : Spin unrestricted coupled pair/coupled cluster methods + Ingolf Harden : AUTO-CI MPn and infrastructure + Benjamin Helmich-Paris : MC-RPA, TRAH-(SCF,CASSCF), AVAS, COSX integrals, SCF dyn. polar. + Lee Huntington : MR-EOM, pCC + Robert Izsak : Overlap fitted RIJCOSX, COSX-SCS-MP3, EOM + Riya Kayal : Wick's Theorem for AUTO-CI, AUTO-CI UHF-CCSDT + Emily Kempfer : AUTO-CI, RHF CISDT and CCSDT + Christian Kollmar : KDIIS, OOCD, Brueckner-CCSD(T), CCSD density, CASPT2, CASPT2-K, improved NEVPT2 + Axel Koslowski : Symmetry handling + Simone Kossmann : Meta GGA functionals, TD-DFT gradient, OOMP2, (MP2 Hessian; deprecated post 5.0) + Lucas Lang : DCDCAS + Marvin Lechner : AUTO-CI (C++ implementation), FIC-MRCC + Spencer Leger : CASSCF response + Dagmar Lenk : GEPOL surface, SMD, ORCA-2-JSON + Dimitrios Liakos : Extrapolation schemes; Compound Job, initial MDCI parallelization + Dimitrios Manganas : Further ROCIS development; embedding schemes. LFT, Crystal Embedding + Dimitrios Pantazis : SARC Basis sets + Anastasios Papadopoulos: AUTO-CI, single reference methods and gradients + Taras Petrenko : pre 6.0 DFT Hessian and TD-DFT gradient, (ASA, deprecated), ECA, 1-Electron XAS/XES, NRVS + Peter Pinski : DLPNO-MP2, DLPNO-MP2 Gradient + Christoph Reimann : Effective Core Potentials + Marius Retegan : Local ZFS, SOC + Christoph Riplinger : Optimizer, TS searches, QM/MM, DLPNO-CCSD(T), (RO)-DLPNO pert. Triples + Michael Roemelt : Original ROCIS implementation + Masaaki Saitow : Open-shell DLPNO-CCSD energy and density + Barbara Sandhoefer : DKH picture change effects + Kantharuban Sivalingam : CASSCF convergence/infrastructure, NEVPT2 and variants, FIC-MRCI + Bernardo de Souza : ESD, SOC TD-DFT + Georgi Stoychev : AutoAux, RI-MP2 NMR, DLPNO-MP2 response, X2C + Van Anh Tran : RI-MP2 g-tensors + Willem Van den Heuvel : Paramagnetic NMR + Zikuan Wang : NOTCH, Electric field optimization + Frank Wennmohs : Technical directorship and infrastructure + Hang Xu : AUTO-CI-Response properties + + + We gratefully acknowledge several colleagues who have allowed us to + interface, adapt or use parts of their codes: + Stefan Grimme, W. Hujo, H. Kruse, P. Pracht, : VdW corrections, initial TS optimization, + C. Bannwarth, S. Ehlert, DFT functionals, gCP, sTDA/sTD-DF + L. Wittmann, M. Mueller + Ed Valeev, F. Pavosevic, A. Kumar : LibInt (2-el integral package), F12 methods + Garnet Chan, S. Sharma, J. Yang, R. Olivares : DMRG + Ulf Ekstrom : XCFun DFT Library + Mihaly Kallay : mrcc (arbitrary order and MRCC methods) + Frank Weinhold : gennbo (NPA and NBO analysis) + Simon Mueller : openCOSMO-RS + Christopher J. Cramer and Donald G. Truhlar : smd solvation model + Lars Goerigk : TD-DFT with DH, B97 family of functionals + V. Asgeirsson, H. Jonsson : NEB implementation + FAccTs GmbH : IRC, NEB, NEB-TS, DLPNO-Multilevel, CI-OPT + MM, QMMM, 2- and 3-layer-ONIOM, Crystal-QMMM, + LR-CPCM, SF, NACMEs, symmetry and pop. for TD-DFT, + nearIR, NL-DFT gradient (VV10), updates on ESD, + ML-optimized integration grids, MBIS, APM, + GOAT, DOCKER, SOLVATOR, interface openCOSMO-RS + S Lehtola, MJT Oliveira, MAL Marques : LibXC Library + Liviu Ungur et al : ANISO software + + + Your calculation uses the libint2 library for the computation of 2-el integrals + For citations please refer to: http://libint.valeyev.net + + Your ORCA version has been built with support for libXC version: 6.2.2 + For citations please refer to: https://libxc.gitlab.io + + This ORCA versions uses: + CBLAS interface : Fast vector & matrix operations + LAPACKE interface : Fast linear algebra routines + SCALAPACK package : Parallel linear algebra routines + Shared memory : Shared parallel matrices + BLAS/LAPACK : OpenBLAS 0.3.27 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Cooperlake SINGLE_THREADED + Core in use : Cooperlake + Copyright (c) 2011-2014, The OpenBLAS Project + + +NOTE: MaxCore=3500 MB was set to SCF,MP2,MDCI,CIPSI,MRCI and CIS + => If you want to overwrite this, your respective input block should be placed after the MaxCore statement +Warning: RI is on but no J-basis has been assigned. Assigning Def2/J (nothing to worry about!) +================================================================================ + +----- Orbital basis set information ----- +Your calculation utilizes the basis: def2-TZVP + F. Weigend and R. Ahlrichs, Phys. Chem. Chem. Phys. 7, 3297 (2005). + +----- AuxJ basis set information ----- +Your calculation utilizes the auxiliary basis: def2/J + F. Weigend, Phys. Chem. Chem. Phys. 8, 1057 (2006). + +================================================================================ + WARNINGS + Please study these warnings very carefully! +================================================================================ + + +================================================================================ + INPUT FILE +================================================================================ +NAME = input.in +| 1> !RKS B3LYP def2-TZVP TightSCF defgrid3 +| 2> %maxcore 3500 +| 3> %pal nprocs 8 end +| 4> +| 5> * xyz 0 1 +| 6> C 0.42654 1.47789 -0.00008 +| 7> C 0.49428 0.01192 0.00000 +| 8> C 1.79226 -0.71266 0.00004 +| 9> C -0.76953 -0.70318 0.00004 +| 10> C -2.09552 -0.11756 0.00001 +| 11> H 1.39854 1.97009 -0.00011 +| 12> H -0.16267 1.83052 -0.86690 +| 13> H 2.40601 -0.45645 -0.87511 +| 14> H 2.40600 -0.45637 0.87517 +| 15> H 1.65287 -1.79552 0.00009 +| 16> H -0.70100 -1.41388 0.84851 +| 17> H -0.70101 -1.41397 -0.84837 +| 18> H -2.27706 0.94605 -0.00004 +| 19> H -0.16266 1.83061 0.86672 +| 20> H -2.94717 -0.77952 0.00004 +| 21> * +| 22> +| 23> %scf +| 24> MaxIter 999 +| 25> STABPerform true +| 26> STABRestartUHFifUnstable true +| 27> STABNRoots 6 +| 28> end +| 29> +| 30> ****END OF INPUT**** +================================================================================ + + **************************** + * Single Point Calculation * + **************************** + +--------------------------------- +CARTESIAN COORDINATES (ANGSTROEM) +--------------------------------- + C 0.426540 1.477890 -0.000080 + C 0.494280 0.011920 0.000000 + C 1.792260 -0.712660 0.000040 + C -0.769530 -0.703180 0.000040 + C -2.095520 -0.117560 0.000010 + H 1.398540 1.970090 -0.000110 + H -0.162670 1.830520 -0.866900 + H 2.406010 -0.456450 -0.875110 + H 2.406000 -0.456370 0.875170 + H 1.652870 -1.795520 0.000090 + H -0.701000 -1.413880 0.848510 + H -0.701010 -1.413970 -0.848370 + H -2.277060 0.946050 -0.000040 + H -0.162660 1.830610 0.866720 + H -2.947170 -0.779520 0.000040 + +---------------------------- +CARTESIAN COORDINATES (A.U.) +---------------------------- + NO LB ZA FRAG MASS X Y Z + 0 C 6.0000 0 12.011 0.806044 2.792807 -0.000151 + 1 C 6.0000 0 12.011 0.934054 0.022526 0.000000 + 2 C 6.0000 0 12.011 3.386881 -1.346732 0.000076 + 3 C 6.0000 0 12.011 -1.454201 -1.328818 0.000076 + 4 C 6.0000 0 12.011 -3.959959 -0.222156 0.000019 + 5 H 1.0000 0 1.008 2.642858 3.722931 -0.000208 + 6 H 1.0000 0 1.008 -0.307402 3.459181 -1.638204 + 7 H 1.0000 0 1.008 4.546700 -0.862565 -1.653718 + 8 H 1.0000 0 1.008 4.546681 -0.862414 1.653832 + 9 H 1.0000 0 1.008 3.123472 -3.393041 0.000170 + 10 H 1.0000 0 1.008 -1.324698 -2.671846 1.603452 + 11 H 1.0000 0 1.008 -1.324717 -2.672016 -1.603187 + 12 H 1.0000 0 1.008 -4.303020 1.787775 -0.000076 + 13 H 1.0000 0 1.008 -0.307383 3.459352 1.637863 + 14 H 1.0000 0 1.008 -5.569344 -1.473079 0.000076 + +-------------------------------- +INTERNAL COORDINATES (ANGSTROEM) +-------------------------------- + C 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 1.467534243178 0.00000000 0.00000000 + C 2 1 0 1.486528929554 121.81751498 0.00000000 + C 2 1 3 1.452096321771 116.85676884 179.99993602 + C 4 2 1 1.449551746369 126.66904732 0.00000000 + H 1 2 3 1.089515874552 114.21101881 0.00000000 + H 1 2 3 1.105845040410 110.07045239 123.43469396 + H 3 2 1 1.099190679136 111.95675548 300.85933157 + H 3 2 1 1.099187822258 111.95678016 59.14175764 + H 3 2 1 1.091794556773 111.83685328 180.00051020 + H 4 2 1 1.108914871304 105.17994891 232.44431358 + H 4 2 1 1.108926031167 105.18012877 127.55483417 + H 5 4 2 1.078991661784 123.51459171 0.00000000 + H 1 2 3 1.105852738117 110.07002741 236.56635973 + H 5 4 2 1.078655999381 118.31470748 179.99959841 + +--------------------------- +INTERNAL COORDINATES (A.U.) +--------------------------- + C 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 2.773237811758 0.00000000 0.00000000 + C 2 1 0 2.809132567008 121.81751498 0.00000000 + C 2 1 3 2.744064368221 116.85676884 179.99993602 + C 4 2 1 2.739255817584 126.66904732 0.00000000 + H 1 2 3 2.058886621462 114.21101881 0.00000000 + H 1 2 3 2.089744272930 110.07045239 123.43469396 + H 3 2 1 2.077169352526 111.95675548 300.85933157 + H 3 2 1 2.077163953809 111.95678016 59.14175764 + H 3 2 1 2.063192706808 111.83685328 180.00051020 + H 4 2 1 2.095545412598 105.17994891 232.44431358 + H 4 2 1 2.095566501682 105.18012877 127.55483417 + H 5 4 2 2.038998741557 123.51459171 0.00000000 + H 1 2 3 2.089758819487 110.07002741 236.56635973 + H 5 4 2 2.038364431541 118.31470748 179.99959841 + +--------------------- +BASIS SET INFORMATION +--------------------- +There are 2 groups of distinct atoms + + Group 1 Type C : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 2 Type H : 5s1p contracted to 3s1p pattern {311/1} + +Atom 0C basis set group => 1 +Atom 1C basis set group => 1 +Atom 2C basis set group => 1 +Atom 3C basis set group => 1 +Atom 4C basis set group => 1 +Atom 5H basis set group => 2 +Atom 6H basis set group => 2 +Atom 7H basis set group => 2 +Atom 8H basis set group => 2 +Atom 9H basis set group => 2 +Atom 10H basis set group => 2 +Atom 11H basis set group => 2 +Atom 12H basis set group => 2 +Atom 13H basis set group => 2 +Atom 14H basis set group => 2 +--------------------------------- +AUXILIARY/J BASIS SET INFORMATION +--------------------------------- +There are 2 groups of distinct atoms + + Group 1 Type C : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 2 Type H : 5s2p1d contracted to 3s1p1d pattern {311/2/1} + +Atom 0C basis set group => 1 +Atom 1C basis set group => 1 +Atom 2C basis set group => 1 +Atom 3C basis set group => 1 +Atom 4C basis set group => 1 +Atom 5H basis set group => 2 +Atom 6H basis set group => 2 +Atom 7H basis set group => 2 +Atom 8H basis set group => 2 +Atom 9H basis set group => 2 +Atom 10H basis set group => 2 +Atom 11H basis set group => 2 +Atom 12H basis set group => 2 +Atom 13H basis set group => 2 +Atom 14H basis set group => 2 + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------ + ORCA STARTUP CALCULATIONS + -- RI-GTO INTEGRALS CHOSEN -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + ___ + / \ - P O W E R E D B Y - + / \ + | | | _ _ __ _____ __ __ + | | | | | | | / \ | _ \ | | / | + \ \/ | | | | / \ | | | | | | / / + / \ \ | |__| | / /\ \ | |_| | | |/ / + | | | | __ | / /__\ \ | / | \ + | | | | | | | | __ | | \ | |\ \ + \ / | | | | | | | | | |\ \ | | \ \ + \___/ |_| |_| |__| |__| |_| \__\ |__| \__/ + + - O R C A' S B I G F R I E N D - + & + - I N T E G R A L F E E D E R - + + v1 FN, 2020, v2 2021, v3 2022-2024 +------------------------------------------------------------------------------ + + +---------------------- +SHARK INTEGRAL PACKAGE +---------------------- + +Number of atoms ... 15 +Number of basis functions ... 215 +Number of shells ... 95 +Maximum angular momentum ... 3 +Integral batch strategy ... SHARK/LIBINT Hybrid +RI-J (if used) integral strategy ... SPLIT-RIJ (Revised 2003 algorithm where possible) +Printlevel ... 1 +Contraction scheme used ... SEGMENTED contraction +Prescreening option ... SCHWARTZ + Thresh ... 2.500e-11 + Tcut ... 2.500e-12 + Tpresel ... 2.500e-12 +Coulomb Range Separation ... NOT USED +Exchange Range Separation ... NOT USED +Multipole approximations ... NOT USED +Finite Nucleus Model ... NOT USED +CABS basis ... NOT available +Auxiliary Coulomb fitting basis ... AVAILABLE + # of basis functions in Aux-J ... 355 + # of shells in Aux-J ... 125 + Maximum angular momentum in Aux-J ... 4 +Auxiliary J/K fitting basis ... NOT available +Auxiliary Correlation fitting basis ... NOT available +Auxiliary 'external' fitting basis ... NOT available + +Checking pre-screening integrals ... done ( 0.0 sec) Dimension = 95 +Check shell pair data ... done ( 0.0 sec) +Shell pair information +Shell pair cut-off parameter TPreSel ... 2.5e-12 +Total number of shell pairs ... 4560 +Shell pairs after pre-screening ... 4367 +Total number of primitive shell pairs ... 13020 +Primitive shell pairs kept ... 9947 + la=0 lb=0: 1434 shell pairs + la=1 lb=0: 1323 shell pairs + la=1 lb=1: 315 shell pairs + la=2 lb=0: 537 shell pairs + la=2 lb=1: 246 shell pairs + la=2 lb=2: 55 shell pairs + la=3 lb=0: 267 shell pairs + la=3 lb=1: 125 shell pairs + la=3 lb=2: 50 shell pairs + la=3 lb=3: 15 shell pairs + +Calculating one electron integrals ... done ( 0.0 sec) +Calculating RI/J V-Matrix + Cholesky decomp.... done ( 0.0 sec) +Calculating Nuclear repulsion ... done ( 0.0 sec) ENN= 175.283398255429 Eh + +Diagonalization of the overlap matrix: +Smallest eigenvalue ... 1.549e-04 +Time for diagonalization ... 0.009 sec +Threshold for overlap eigenvalues ... 1.000e-07 +Number of eigenvalues below threshold ... 0 +Time for construction of square roots ... 0.004 sec +Total time needed ... 0.015 sec + +------------------- +DFT GRID GENERATION +------------------- + +General Integration Accuracy IntAcc ... 4.959 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 6 (Lebedev-590) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... off +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 158925 +Total number of batches ... 2492 +Average number of points per batch ... 63 +Average number of grid points per atom ... 10595 + +-------------------- +COSX GRID GENERATION +-------------------- + +GRIDX 1 +------- +General Integration Accuracy IntAcc ... 4.020 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 2 (Lebedev-110) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 16670 +Total number of batches ... 138 +Average number of points per batch ... 120 +Average number of grid points per atom ... 1111 +UseSFitting ... on + +GRIDX 2 +------- +General Integration Accuracy IntAcc ... 4.338 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 3 (Lebedev-194) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 36498 +Total number of batches ... 295 +Average number of points per batch ... 123 +Average number of grid points per atom ... 2433 +UseSFitting ... on + +GRIDX 3 +------- +General Integration Accuracy IntAcc ... 4.871 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 4 (Lebedev-302) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 72764 +Total number of batches ... 576 +Average number of points per batch ... 126 +Average number of grid points per atom ... 4851 +UseSFitting ... on +Initializing property integral containers ... done ( 0.0 sec) + +SHARK setup successfully completed in 4.3 seconds + +Maximum memory used throughout the entire STARTUP-calculation: 35.5 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------- + ORCA GUESS + Start orbitals & Density for SCF / CASSCF +------------------------------------------------------------------------------- + +------------ +SCF SETTINGS +------------ +Hamiltonian: + Density Functional Method .... DFT(GTOs) + Exchange Functional Exchange .... B88 + X-Alpha parameter XAlpha .... 0.666667 + Becke's b parameter XBeta .... 0.004200 + Correlation Functional Correlation .... LYP + LDA part of GGA corr. LDAOpt .... VWN-5 + Gradients option PostSCFGGA .... off + Hybrid DFT is turned on + Fraction HF Exchange ScalHFX .... 0.200000 + Scaling of DF-GGA-X ScalDFX .... 0.720000 + Scaling of DF-GGA-C ScalDFC .... 0.810000 + Scaling of DF-LDA-C ScalLDAC .... 1.000000 + Perturbative correction .... 0.000000 + NL short-range parameter .... 4.800000 + RI-approximation to the Coulomb term is turned on + Number of AuxJ basis functions .... 355 + RIJ-COSX (HFX calculated with COS-X)).... on + + +General Settings: + Integral files IntName .... input + Hartree-Fock type HFTyp .... RHF + Total Charge Charge .... 0 + Multiplicity Mult .... 1 + Number of Electrons NEL .... 40 + Basis Dimension Dim .... 215 + Nuclear Repulsion ENuc .... 175.2833982554 Eh + +Convergence Acceleration: + AO-DIIS CNVDIIS .... on + Start iteration DIISMaxIt .... 12 + Startup error DIISStart .... 0.200000 + # of expansion vecs DIISMaxEq .... 5 + Bias factor DIISBfac .... 1.050 + Max. coefficient DIISMaxC .... 10.000 + MO-DIIS CNVKDIIS .... off + Trust-Rad. Augm. Hess. CNVTRAH .... auto + Auto Start mean grad. ratio tolernc. .... 1.125000 + Auto Start start iteration .... 50 + Auto Start num. interpolation iter. .... 10 + Max. Number of Micro iterations .... 24 + Max. Number of Macro iterations .... Maxiter - #DIIS iter + Number of Davidson start vectors .... 2 + Converg. threshold (grad. norm) .... 1.000e-05 + Grad. Scal. Fac. for Micro threshold .... 0.100 + Minimum threshold for Micro iter. .... 1.000e-02 + NR start threshold (gradient norm) .... 1.000e-04 + Initial trust radius .... 0.400 + Minimum AH scaling param. (alpha) .... 1.000 + Maximum AH scaling param. (alpha) .... 1000.000 + Quad. conv. algorithm .... NR + White noise on init. David. guess .... on + Maximum white noise .... 0.010 + Pseudo random numbers .... off + Inactive MOs .... canonical + Orbital update algorithm .... Taylor + Preconditioner .... Diag + Full preconditioner red. dimension .... 250 + SOSCF CNVSOSCF .... on + Start iteration SOSCFMaxIt .... 150 + Startup grad/error SOSCFStart .... 0.003300 + Hessian update SOSCFHessUp .... L-BFGS + Level Shifting CNVShift .... on + Level shift para. LevelShift .... 0.2500 + Turn off err/grad. ShiftErr .... 0.0010 + Zerner damping CNVZerner .... off + Static damping CNVDamp .... on + Fraction old density DampFac .... 0.7000 + Max. Damping (<1) DampMax .... 0.9800 + Min. Damping (>=0) DampMin .... 0.0000 + Turn off err/grad. DampErr .... 0.1000 + +SCF Procedure: + Maximum # iterations MaxIter .... 999 + SCF integral mode SCFMode .... Direct + Integral package .... SHARK and LIBINT hybrid scheme + Reset frequency DirectResetFreq .... 20 + Integral Threshold Thresh .... 2.500e-11 Eh + Primitive CutOff TCut .... 2.500e-12 Eh + +Convergence Tolerance: + Convergence Check Mode ConvCheckMode .... Total+1el-Energy + Convergence forced ConvForced .... 0 + Energy Change TolE .... 1.000e-08 Eh + 1-El. energy change .... 1.000e-05 Eh + Orbital Gradient TolG .... 1.000e-05 + Orbital Rotation angle TolX .... 1.000e-05 + DIIS Error TolErr .... 5.000e-07 + +------------------------------ +INITIAL GUESS: MODEL POTENTIAL +------------------------------ +Loading Hartree-Fock densities ... done +Calculating cut-offs ... done +Initializing the effective Hamiltonian ... done +Setting up the integral package (SHARK) ... done +Starting the Coulomb interaction ... done ( 0.1 sec) +Making the grid ... done ( 0.1 sec) +Mapping shells ... done +Starting the XC term evaluation ... done ( 0.1 sec) + promolecular density results + # of electrons = 39.996852652 + EX = -28.647031281 + EC = -1.263803968 + EX+EC = -29.910835249 +Transforming the Hamiltonian ... done ( 0.0 sec) +Diagonalizing the Hamiltonian ... done ( 0.0 sec) +Back transforming the eigenvectors ... done ( 0.0 sec) +Now organizing SCF variables ... done + ------------------ + INITIAL GUESS DONE ( 0.3 sec) + ------------------ + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** +Finished Guess after 0.9 sec +Maximum memory used throughout the entire GUESS-calculation: 12.6 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------------------- + ORCA LEAN-SCF + memory conserving SCF solver +------------------------------------------------------------------------------------------- + +----------------------------------------D-I-I-S-------------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP DIISErr Damp Time(sec) +------------------------------------------------------------------------------------------- + *** Starting incremental Fock matrix formation *** + 1 -196.0631216676143254 0.00e+00 2.17e-03 7.83e-02 2.64e-01 0.700 4.0 +Warning: op=0 Small HOMO/LUMO gap ( 0.060) - skipping pre-diagonalization + Will do a full diagonalization + 2 -196.2046327368354355 -1.42e-01 1.84e-03 5.97e-02 1.16e-01 0.700 2.2 + ***Turning on AO-DIIS*** + 3 -196.2519339736680877 -4.73e-02 8.55e-04 2.27e-02 4.87e-02 0.700 2.3 + 4 -196.2783567095005992 -2.64e-02 1.34e-03 2.97e-02 3.11e-02 0.000 2.1 + 5 -196.3417793528537914 -6.34e-02 5.30e-04 1.48e-02 1.66e-02 0.000 2.0 + 6 -196.3440455722681008 -2.27e-03 2.84e-04 7.52e-03 7.59e-03 0.000 1.9 + *** Initializing SOSCF *** +---------------------------------------S-O-S-C-F-------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP MaxGrad Time(sec) +-------------------------------------------------------------------------------------- + 7 -196.3444183600858537 -3.73e-04 1.56e-04 4.06e-03 2.35e-03 2.1 + *** Restarting incremental Fock matrix formation *** + 8 -196.3445203074584242 -1.02e-04 1.74e-04 4.84e-03 9.59e-04 3.5 + 9 -196.3445633162007766 -4.30e-05 8.86e-05 2.63e-03 2.38e-04 3.1 + 10 -196.3445652928795084 -1.98e-06 2.74e-05 1.50e-03 4.22e-04 2.9 + 11 -196.3445654022830809 -1.09e-07 3.32e-05 7.27e-04 6.59e-04 2.9 + 12 -196.3445655813749795 -1.79e-07 1.83e-05 9.82e-04 2.73e-04 2.9 + 13 -196.3445680698875435 -2.49e-06 5.28e-06 2.30e-04 6.96e-05 2.6 + 14 -196.3445681545698562 -8.47e-08 1.94e-06 4.39e-05 2.40e-05 2.9 + 15 -196.3445681718264382 -1.73e-08 8.48e-07 2.17e-05 8.68e-06 2.6 + 16 -196.3445681740595319 -2.23e-09 6.54e-07 1.53e-05 4.92e-06 2.2 + **** Energy Check signals convergence **** + + ***************************************************** + * SUCCESS * + * SCF CONVERGED AFTER 16 CYCLES * + ***************************************************** + +Recomputing exchange energy using gridx3 ... done ( 6.002 sec) +Old exchange energy : -5.867459883 Eh +New exchange energy : -5.867463289 Eh +Exchange energy change after final integration : -0.000003406 Eh +Total energy after final integration : -196.344571580 Eh + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** + +------------------------------------------------------------------------------------------- + WAVEFUNCTION STABILITY ANALYSIS +------------------------------------------------------------------------------------------- + + + ****Iteration 0**** + Lowest Energy : -0.050808103995 + Maximum Energy change : 0.176441058154 (vector 5) + Maximum residual norm : 0.011573406343 + + ****Iteration 1**** + Lowest Energy : -0.064545460780 + Maximum Energy change : 0.013737356786 (vector 0) + Maximum residual norm : 0.000123615590 + + ****Iteration 2**** + Lowest Energy : -0.064661510340 + Maximum Energy change : 0.000359636365 (vector 4) + Maximum residual norm : 0.000017665730 + + *** CONVERGENCE OF RESIDUAL NORM REACHED *** +The eigenvalues of the stability matrix: + E( 0) = -0.06466151 Eh + E( 1) = 0.13214783 Eh + E( 2) = 0.13729508 Eh + E( 3) = 0.16645879 Eh + E( 4) = 0.17203969 Eh + E( 5) = 0.17440600 Eh + +The stability analysis indicates that the wavefunction is unstable +Restart requested: Orbitals will be transformed and reconvergence attempted +Orbitals have been transformed and reconvergence is now attempted + + ************************************************** + * The wavefunction in try 1/ 5 is unstable. * + * Trying to re-converging now * + ************************************************** + +----------------------------------------D-I-I-S-------------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP DIISErr Damp Time(sec) +------------------------------------------------------------------------------------------- + *** Starting incremental Fock matrix formation *** + 1 -196.3542352637812201 0.00e+00 1.70e-04 8.26e-03 9.65e-03 0.700 5.5 +Warning: op=0 Small HOMO/LUMO gap ( 0.092) - skipping pre-diagonalization + Will do a full diagonalization + 2 -196.3554482760627593 -1.21e-03 1.97e-04 9.53e-03 8.45e-03 0.700 2.9 + ***Turning on AO-DIIS*** + 3 -196.3567845628464852 -1.34e-03 1.90e-04 8.49e-03 8.13e-03 0.700 2.4 + 4 -196.3581094764049340 -1.32e-03 5.39e-04 2.28e-02 7.48e-03 0.000 2.6 + 5 -196.3634370375382332 -5.33e-03 2.90e-04 9.91e-03 4.09e-03 0.000 3.3 + 6 -196.3645834758605702 -1.15e-03 1.63e-04 6.57e-03 1.90e-03 0.000 2.6 + 7 -196.3647813878012016 -1.98e-04 2.99e-05 1.22e-03 6.14e-04 0.000 2.5 + *** Restarting incremental Fock matrix formation *** + ****Resetting DIIS**** + 8 -196.3647838835393031 -2.50e-06 1.33e-05 5.49e-04 3.71e-04 0.000 5.8 + 9 -196.3647827984090100 1.09e-06 8.30e-06 3.14e-04 4.37e-04 0.000 3.7 + 10 -196.3647860997995167 -3.30e-06 2.43e-06 8.51e-05 4.26e-05 0.000 3.4 + 11 -196.3647861786868702 -7.89e-08 7.39e-07 3.61e-05 3.32e-05 0.000 3.5 + 12 -196.3647861895166784 -1.08e-08 4.27e-07 1.31e-05 8.95e-06 0.000 3.1 + 13 -196.3647861881471499 1.37e-09 3.45e-07 1.28e-05 2.52e-06 0.000 2.8 + **** Energy Check signals convergence **** + + ***************************************************** + * SUCCESS * + * SCF CONVERGED AFTER 13 CYCLES * + ***************************************************** + +Recomputing exchange energy using gridx3 ... done ( 5.699 sec) +Old exchange energy : -5.897362869 Eh +New exchange energy : -5.897366042 Eh +Exchange energy change after final integration : -0.000003174 Eh +Total energy after final integration : -196.364789362 Eh + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** + +------------------------------------------------------------------------------------------- + WAVEFUNCTION STABILITY ANALYSIS +------------------------------------------------------------------------------------------- + + + ****Iteration 0**** + Lowest Energy : 0.093462454623 + Maximum Energy change : 0.196792905599 (vector 5) + Maximum residual norm : 0.038596660123 + + ****Iteration 1**** + Lowest Energy : 0.077571925938 + Maximum Energy change : 0.019778696431 (vector 1) + Maximum residual norm : 0.001577510541 + + ****Iteration 2**** + Lowest Energy : 0.076055960106 + Maximum Energy change : 0.001515965832 (vector 0) + Maximum residual norm : 0.000240952858 + + ****Iteration 3**** + Lowest Energy : 0.075908422298 + Maximum Energy change : 0.000284282518 (vector 1) + Maximum residual norm : 0.000069359681 + + *** CONVERGENCE OF RESIDUAL NORM REACHED *** +The eigenvalues of the stability matrix: + E( 0) = 0.07590842 Eh + E( 1) = 0.13152110 Eh + E( 2) = 0.15085752 Eh + E( 3) = 0.18581092 Eh + E( 4) = 0.18979830 Eh + E( 5) = 0.19386855 Eh + +The stability analysis shows that the wavefunction is stable + +---------------- +TOTAL SCF ENERGY +---------------- + +Total Energy : -196.36478936172279 Eh -5343.35757 eV + +Components: +Nuclear Repulsion : 175.28339825542940 Eh 4769.70375 eV +Electronic Energy : -371.64818444357655 Eh -10113.06124 eV +One Electron Energy: -609.57145596524470 Eh -16587.28260 eV +Two Electron Energy: 237.92327152166814 Eh 6474.22136 eV + +Virial components: +Potential Energy : -391.89565610306306 Eh -10664.02295 eV +Kinetic Energy : 195.53086674134025 Eh 5320.66538 eV +Virial Ratio : 2.00426491548000 + +DFT components: +N(Alpha) : 19.999999831128 electrons +N(Beta) : 20.000000482955 electrons +N(Total) : 40.000000314083 electrons +E(X) : -23.369933215171 Eh +E(C) : -1.495983296543 Eh +E(XC) : -24.865916511714 Eh + +--------------- +SCF CONVERGENCE +--------------- + + Last Energy change ... -1.3695e-09 Tolerance : 1.0000e-08 + Last MAX-Density change ... 1.2833e-05 Tolerance : 1.0000e-07 + Last RMS-Density change ... 3.4458e-07 Tolerance : 5.0000e-09 + Last DIIS Error ... 2.5182e-06 Tolerance : 5.0000e-07 + + +---------------------- +UHF SPIN CONTAMINATION +---------------------- + +Warning: in a DFT calculation there is little theoretical justification to + calculate as in Hartree-Fock theory. We will do it anyways + but you should keep in mind that the values have only limited relevance + +Expectation value of : 0.864742 +Ideal value S*(S+1) for S=0.0 : 0.000000 +Deviation : 0.864742 + +---------------- +ORBITAL ENERGIES +---------------- + SPIN UP ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -10.170057 -276.7413 + 1 1.0000 -10.167934 -276.6836 + 2 1.0000 -10.162980 -276.5488 + 3 1.0000 -10.158293 -276.4212 + 4 1.0000 -10.149302 -276.1765 + 5 1.0000 -0.821051 -22.3419 + 6 1.0000 -0.728460 -19.8224 + 7 1.0000 -0.695964 -18.9382 + 8 1.0000 -0.609312 -16.5802 + 9 1.0000 -0.524083 -14.2610 + 10 1.0000 -0.462541 -12.5864 + 11 1.0000 -0.451530 -12.2867 + 12 1.0000 -0.437781 -11.9126 + 13 1.0000 -0.392675 -10.6852 + 14 1.0000 -0.392332 -10.6759 + 15 1.0000 -0.385414 -10.4877 + 16 1.0000 -0.374242 -10.1836 + 17 1.0000 -0.354113 -9.6359 + 18 1.0000 -0.332097 -9.0368 + 19 1.0000 -0.161000 -4.3810 + 20 0.0000 -0.049737 -1.3534 + 21 0.0000 0.031197 0.8489 + 22 0.0000 0.066263 1.8031 + 23 0.0000 0.071548 1.9469 + 24 0.0000 0.104028 2.8308 + 25 0.0000 0.105141 2.8610 + 26 0.0000 0.111024 3.0211 + 27 0.0000 0.114352 3.1117 + 28 0.0000 0.114952 3.1280 + 29 0.0000 0.130020 3.5380 + 30 0.0000 0.145081 3.9479 + + SPIN DOWN ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -10.170060 -276.7414 + 1 1.0000 -10.163835 -276.5720 + 2 1.0000 -10.161919 -276.5199 + 3 1.0000 -10.159203 -276.4460 + 4 1.0000 -10.154841 -276.3273 + 5 1.0000 -0.810918 -22.0662 + 6 1.0000 -0.735098 -20.0030 + 7 1.0000 -0.693853 -18.8807 + 8 1.0000 -0.623518 -16.9668 + 9 1.0000 -0.515641 -14.0313 + 10 1.0000 -0.461028 -12.5452 + 11 1.0000 -0.439341 -11.9551 + 12 1.0000 -0.437883 -11.9154 + 13 1.0000 -0.396672 -10.7940 + 14 1.0000 -0.393221 -10.7001 + 15 1.0000 -0.379977 -10.3397 + 16 1.0000 -0.375834 -10.2270 + 17 1.0000 -0.350980 -9.5507 + 18 1.0000 -0.330138 -8.9835 + 19 1.0000 -0.192936 -5.2501 + 20 0.0000 -0.026987 -0.7344 + 21 0.0000 0.031954 0.8695 + 22 0.0000 0.065837 1.7915 + 23 0.0000 0.070935 1.9302 + 24 0.0000 0.103482 2.8159 + 25 0.0000 0.104611 2.8466 + 26 0.0000 0.109876 2.9899 + 27 0.0000 0.114367 3.1121 + 28 0.0000 0.116110 3.1595 + 29 0.0000 0.130446 3.5496 + 30 0.0000 0.146962 3.9990 +*Only the first 10 virtual orbitals were printed. + + ******************************** + * MULLIKEN POPULATION ANALYSIS * + ******************************** + +-------------------------------------------- +MULLIKEN ATOMIC CHARGES AND SPIN POPULATIONS +-------------------------------------------- + 0 C : -0.365607 -0.054800 + 1 C : 0.095248 0.818773 + 2 C : -0.367489 -0.058347 + 3 C : -0.165539 0.049376 + 4 C : -0.347089 -0.971156 + 5 H : 0.109536 0.000546 + 6 H : 0.114063 0.047172 + 7 H : 0.113575 0.041047 + 8 H : 0.113576 0.041047 + 9 H : 0.109829 0.000458 + 10 H : 0.118240 -0.016958 + 11 H : 0.118238 -0.016957 + 12 H : 0.123475 0.036544 + 13 H : 0.114062 0.047174 + 14 H : 0.115882 0.036080 +Sum of atomic charges : 0.0000000 +Sum of atomic spin populations: -0.0000000 + +----------------------------------------------------- +MULLIKEN REDUCED ORBITAL CHARGES AND SPIN POPULATIONS +----------------------------------------------------- +CHARGE + 0 C s : 3.305154 s : 3.305154 + pz : 1.032410 p : 3.002076 + px : 1.062447 + py : 0.907218 + dz2 : 0.003318 d : 0.054416 + dxz : 0.005859 + dyz : 0.022537 + dx2y2 : 0.005479 + dxy : 0.017223 + f0 : 0.000368 f : 0.003961 + f+1 : 0.000839 + f-1 : 0.000274 + f+2 : 0.000769 + f-2 : -0.000026 + f+3 : 0.000790 + f-3 : 0.000947 + + 1 C s : 3.224556 s : 3.224556 + pz : 0.945648 p : 2.538338 + px : 0.822627 + py : 0.770064 + dz2 : 0.004439 d : 0.132214 + dxz : 0.022974 + dyz : 0.022642 + dx2y2 : 0.040763 + dxy : 0.041396 + f0 : 0.001353 f : 0.009644 + f+1 : 0.000764 + f-1 : 0.000684 + f+2 : 0.000954 + f-2 : 0.001033 + f+3 : 0.003295 + f-3 : 0.001559 + + 2 C s : 3.301023 s : 3.301023 + pz : 1.045705 p : 3.009870 + px : 0.950675 + py : 1.013489 + dz2 : 0.002568 d : 0.052781 + dxz : 0.026693 + dyz : 0.002725 + dx2y2 : 0.014407 + dxy : 0.006388 + f0 : 0.000378 f : 0.003815 + f+1 : 0.000976 + f-1 : 0.000180 + f+2 : 0.000062 + f-2 : 0.000590 + f+3 : 0.000780 + f-3 : 0.000849 + + 3 C s : 3.166291 s : 3.166291 + pz : 0.969599 p : 2.882890 + px : 0.917355 + py : 0.995936 + dz2 : 0.004123 d : 0.110323 + dxz : 0.041714 + dyz : 0.017204 + dx2y2 : 0.031187 + dxy : 0.016096 + f0 : 0.000558 f : 0.006034 + f+1 : 0.000119 + f-1 : 0.001009 + f+2 : 0.000438 + f-2 : 0.001052 + f+3 : 0.001707 + f-3 : 0.001151 + + 4 C s : 3.315161 s : 3.315161 + pz : 1.068243 p : 2.985358 + px : 0.913487 + py : 1.003627 + dz2 : 0.004684 d : 0.041844 + dxz : 0.009049 + dyz : 0.004444 + dx2y2 : 0.011495 + dxy : 0.012173 + f0 : 0.000605 f : 0.004727 + f+1 : 0.000598 + f-1 : 0.000561 + f+2 : 0.000164 + f-2 : 0.000453 + f+3 : 0.001101 + f-3 : 0.001245 + + 5 H s : 0.868969 s : 0.868969 + pz : 0.004331 p : 0.021495 + px : 0.010638 + py : 0.006525 + + 6 H s : 0.864707 s : 0.864707 + pz : 0.009298 p : 0.021230 + px : 0.006512 + py : 0.005420 + + 7 H s : 0.865128 s : 0.865128 + pz : 0.009467 p : 0.021297 + px : 0.007226 + py : 0.004604 + + 8 H s : 0.865127 s : 0.865127 + pz : 0.009467 p : 0.021297 + px : 0.007226 + py : 0.004604 + + 9 H s : 0.868633 s : 0.868633 + pz : 0.004455 p : 0.021538 + px : 0.004386 + py : 0.012696 + + 10 H s : 0.859569 s : 0.859569 + pz : 0.009269 p : 0.022192 + px : 0.004575 + py : 0.008348 + + 11 H s : 0.859571 s : 0.859571 + pz : 0.009268 p : 0.022192 + px : 0.004574 + py : 0.008349 + + 12 H s : 0.853173 s : 0.853173 + pz : 0.006578 p : 0.023351 + px : 0.003929 + py : 0.012844 + + 13 H s : 0.864709 s : 0.864709 + pz : 0.009298 p : 0.021229 + px : 0.006512 + py : 0.005420 + + 14 H s : 0.860876 s : 0.860876 + pz : 0.006444 p : 0.023243 + px : 0.009943 + py : 0.006856 + + +SPIN + 0 C s : -0.014745 s : -0.014745 + pz : -0.027867 p : -0.061443 + px : -0.007428 + py : -0.026149 + dz2 : -0.000016 d : 0.020264 + dxz : 0.001409 + dyz : 0.018918 + dx2y2 : -0.000073 + dxy : 0.000026 + f0 : 0.000298 f : 0.001125 + f+1 : 0.000026 + f-1 : 0.000023 + f+2 : 0.000708 + f-2 : 0.000027 + f+3 : 0.000021 + f-3 : 0.000020 + + 1 C s : 0.046557 s : 0.046557 + pz : 0.713719 p : 0.766965 + px : 0.025158 + py : 0.028088 + dz2 : -0.002606 d : 0.006618 + dxz : 0.002538 + dyz : 0.002049 + dx2y2 : 0.002152 + dxy : 0.002484 + f0 : -0.000358 f : -0.001367 + f+1 : -0.000576 + f-1 : -0.000558 + f+2 : 0.000053 + f-2 : 0.000050 + f+3 : 0.000048 + f-3 : -0.000028 + + 2 C s : -0.016275 s : -0.016275 + pz : -0.026154 p : -0.062740 + px : -0.025553 + py : -0.011034 + dz2 : -0.000025 d : 0.019652 + dxz : 0.018266 + dyz : 0.001457 + dx2y2 : 0.000120 + dxy : -0.000167 + f0 : 0.000297 f : 0.001017 + f+1 : 0.000041 + f-1 : 0.000006 + f+2 : 0.000050 + f-2 : 0.000584 + f+3 : 0.000021 + f-3 : 0.000018 + + 3 C s : 0.024630 s : 0.024630 + pz : 0.014369 p : 0.026842 + px : 0.009516 + py : 0.002957 + dz2 : -0.000356 d : -0.002068 + dxz : -0.000203 + dyz : -0.001142 + dx2y2 : -0.000502 + dxy : 0.000135 + f0 : -0.000076 f : -0.000028 + f+1 : -0.000008 + f-1 : -0.000022 + f+2 : -0.000166 + f-2 : 0.000274 + f+3 : -0.000027 + f-3 : -0.000005 + + 4 C s : -0.072680 s : -0.072680 + pz : -0.825285 p : -0.896594 + px : -0.031682 + py : -0.039627 + dz2 : 0.003631 d : -0.003179 + dxz : -0.002242 + dyz : -0.000547 + dx2y2 : -0.001769 + dxy : -0.002250 + f0 : 0.000208 f : 0.001297 + f+1 : 0.000563 + f-1 : 0.000590 + f+2 : -0.000024 + f-2 : -0.000060 + f+3 : -0.000007 + f-3 : 0.000028 + + 5 H s : 0.000759 s : 0.000759 + pz : -0.000078 p : -0.000213 + px : -0.000073 + py : -0.000061 + + 6 H s : 0.047300 s : 0.047300 + pz : -0.000079 p : -0.000128 + px : -0.000057 + py : 0.000008 + + 7 H s : 0.041109 s : 0.041109 + pz : -0.000069 p : -0.000063 + px : -0.000121 + py : 0.000126 + + 8 H s : 0.041110 s : 0.041110 + pz : -0.000069 p : -0.000063 + px : -0.000121 + py : 0.000126 + + 9 H s : 0.000654 s : 0.000654 + pz : -0.000060 p : -0.000196 + px : -0.000125 + py : -0.000011 + + 10 H s : -0.017036 s : -0.017036 + pz : 0.000028 p : 0.000078 + px : 0.000114 + py : -0.000064 + + 11 H s : -0.017035 s : -0.017035 + pz : 0.000028 p : 0.000078 + px : 0.000114 + py : -0.000064 + + 12 H s : 0.042091 s : 0.042091 + pz : -0.005239 p : -0.005547 + px : -0.000033 + py : -0.000275 + + 13 H s : 0.047302 s : 0.047302 + pz : -0.000079 p : -0.000128 + px : -0.000057 + py : 0.000008 + + 14 H s : 0.041429 s : 0.041429 + pz : -0.004994 p : -0.005349 + px : -0.000190 + py : -0.000165 + + + + ******************************* + * LOEWDIN POPULATION ANALYSIS * + ******************************* + +------------------------------------------- +LOEWDIN ATOMIC CHARGES AND SPIN POPULATIONS +------------------------------------------- + 0 C : -0.287800 0.056332 + 1 C : -0.212054 0.587437 + 2 C : -0.288853 0.053025 + 3 C : -0.317383 -0.012530 + 4 C : -0.221358 -0.761600 + 5 H : 0.122290 0.000103 + 6 H : 0.131885 0.029014 + 7 H : 0.125595 0.025626 + 8 H : 0.125595 0.025626 + 9 H : 0.124553 0.000177 + 10 H : 0.175552 -0.013474 + 11 H : 0.175554 -0.013474 + 12 H : 0.106527 -0.002715 + 13 H : 0.131886 0.029015 + 14 H : 0.108011 -0.002563 + +---------------------------------------------------- +LOEWDIN REDUCED ORBITAL CHARGES AND SPIN POPULATIONS +---------------------------------------------------- +CHARGE + 0 C s : 2.816854 s : 2.816854 + pz : 1.053953 p : 3.154123 + px : 1.049609 + py : 1.050562 + dz2 : 0.032520 d : 0.288119 + dxz : 0.037990 + dyz : 0.082763 + dx2y2 : 0.048861 + dxy : 0.085985 + f0 : 0.002313 f : 0.028704 + f+1 : 0.003518 + f-1 : 0.003597 + f+2 : 0.005759 + f-2 : 0.002511 + f+3 : 0.005799 + f-3 : 0.005207 + + 1 C s : 2.746701 s : 2.746701 + pz : 0.863243 p : 2.901032 + px : 1.010950 + py : 1.026839 + dz2 : 0.030399 d : 0.508490 + dxz : 0.071697 + dyz : 0.075428 + dx2y2 : 0.164938 + dxy : 0.166028 + f0 : 0.007353 f : 0.055831 + f+1 : 0.004035 + f-1 : 0.003992 + f+2 : 0.006077 + f-2 : 0.006332 + f+3 : 0.020036 + f-3 : 0.008004 + + 2 C s : 2.820651 s : 2.820651 + pz : 1.063216 p : 3.160535 + px : 1.042880 + py : 1.054439 + dz2 : 0.032961 d : 0.280414 + dxz : 0.109719 + dyz : 0.012603 + dx2y2 : 0.082012 + dxy : 0.043118 + f0 : 0.002381 f : 0.027253 + f+1 : 0.004207 + f-1 : 0.002859 + f+2 : 0.001878 + f-2 : 0.005546 + f+3 : 0.005576 + f-3 : 0.004807 + + 3 C s : 2.751383 s : 2.751383 + pz : 0.978994 p : 3.045963 + px : 1.058740 + py : 1.008229 + dz2 : 0.039150 d : 0.475178 + dxz : 0.120001 + dyz : 0.086679 + dx2y2 : 0.131891 + dxy : 0.097457 + f0 : 0.003515 f : 0.044858 + f+1 : 0.004300 + f-1 : 0.005268 + f+2 : 0.007113 + f-2 : 0.006838 + f+3 : 0.011249 + f-3 : 0.006575 + + 4 C s : 2.881368 s : 2.881368 + pz : 0.983222 p : 3.090676 + px : 1.050676 + py : 1.056778 + dz2 : 0.013962 d : 0.225077 + dxz : 0.036950 + dyz : 0.012480 + dx2y2 : 0.077715 + dxy : 0.083969 + f0 : 0.002797 f : 0.024236 + f+1 : 0.003466 + f-1 : 0.002885 + f+2 : 0.001502 + f-2 : 0.002725 + f+3 : 0.005801 + f-3 : 0.005059 + + 5 H s : 0.817884 s : 0.817884 + pz : 0.013032 p : 0.059826 + px : 0.030463 + py : 0.016330 + + 6 H s : 0.809249 s : 0.809249 + pz : 0.026254 p : 0.058866 + px : 0.018559 + py : 0.014053 + + 7 H s : 0.814806 s : 0.814806 + pz : 0.026889 p : 0.059598 + px : 0.018819 + py : 0.013890 + + 8 H s : 0.814806 s : 0.814806 + pz : 0.026889 p : 0.059599 + px : 0.018819 + py : 0.013891 + + 9 H s : 0.815706 s : 0.815706 + pz : 0.013234 p : 0.059741 + px : 0.012666 + py : 0.033842 + + 10 H s : 0.767642 s : 0.767642 + pz : 0.024226 p : 0.056806 + px : 0.012331 + py : 0.020249 + + 11 H s : 0.767642 s : 0.767642 + pz : 0.024223 p : 0.056804 + px : 0.012331 + py : 0.020250 + + 12 H s : 0.824767 s : 0.824767 + pz : 0.019508 p : 0.068706 + px : 0.012163 + py : 0.037035 + + 13 H s : 0.809248 s : 0.809248 + pz : 0.026253 p : 0.058865 + px : 0.018559 + py : 0.014054 + + 14 H s : 0.824605 s : 0.824605 + pz : 0.019035 p : 0.067384 + px : 0.026564 + py : 0.021784 + + +SPIN + 0 C s : -0.003304 s : -0.003304 + pz : -0.010052 p : -0.025601 + px : -0.003172 + py : -0.012378 + dz2 : 0.000722 d : 0.077726 + dxz : 0.007921 + dyz : 0.065708 + dx2y2 : 0.002408 + dxy : 0.000966 + f0 : 0.002010 f : 0.007511 + f+1 : 0.000110 + f-1 : 0.000086 + f+2 : 0.004651 + f-2 : 0.000278 + f+3 : 0.000131 + f-3 : 0.000246 + + 1 C s : 0.017127 s : 0.017127 + pz : 0.554903 p : 0.576485 + px : 0.010606 + py : 0.010976 + dz2 : -0.002581 d : -0.005713 + dxz : 0.000165 + dyz : -0.001146 + dx2y2 : -0.000843 + dxy : -0.001308 + f0 : 0.001486 f : -0.000461 + f+1 : -0.000603 + f-1 : -0.000591 + f+2 : -0.000086 + f-2 : -0.000253 + f+3 : 0.000028 + f-3 : -0.000443 + + 2 C s : -0.003357 s : -0.003357 + pz : -0.008286 p : -0.024566 + px : -0.011636 + py : -0.004645 + dz2 : 0.000696 d : 0.074183 + dxz : 0.064081 + dyz : 0.006023 + dx2y2 : 0.001430 + dxy : 0.001953 + f0 : 0.001980 f : 0.006766 + f+1 : 0.000166 + f-1 : 0.000019 + f+2 : 0.000387 + f-2 : 0.003838 + f+3 : 0.000121 + f-3 : 0.000255 + + 3 C s : 0.000518 s : 0.000518 + pz : -0.001501 p : -0.000554 + px : 0.000578 + py : 0.000369 + dz2 : -0.000294 d : -0.011552 + dxz : -0.003685 + dyz : -0.007200 + dx2y2 : -0.000498 + dxy : 0.000124 + f0 : -0.000634 f : -0.000941 + f+1 : -0.000029 + f-1 : -0.000084 + f+2 : -0.001979 + f-2 : 0.001788 + f+3 : -0.000014 + f-3 : 0.000011 + + 4 C s : -0.020270 s : -0.020270 + pz : -0.715150 p : -0.738226 + px : -0.011641 + py : -0.011435 + dz2 : 0.003102 d : -0.004070 + dxz : -0.006913 + dyz : -0.001908 + dx2y2 : 0.000435 + dxy : 0.001214 + f0 : -0.000342 f : 0.000966 + f+1 : 0.000617 + f-1 : 0.000628 + f+2 : -0.000102 + f-2 : -0.000153 + f+3 : 0.000004 + f-3 : 0.000315 + + 5 H s : 0.000713 s : 0.000713 + pz : -0.000155 p : -0.000610 + px : -0.000129 + py : -0.000326 + + 6 H s : 0.029859 s : 0.029859 + pz : -0.000354 p : -0.000845 + px : -0.000374 + py : -0.000118 + + 7 H s : 0.026356 s : 0.026356 + pz : -0.000353 p : -0.000730 + px : -0.000395 + py : 0.000018 + + 8 H s : 0.026357 s : 0.026357 + pz : -0.000353 p : -0.000730 + px : -0.000395 + py : 0.000018 + + 9 H s : 0.000702 s : 0.000702 + pz : -0.000070 p : -0.000525 + px : -0.000330 + py : -0.000125 + + 10 H s : -0.013943 s : -0.013943 + pz : 0.000094 p : 0.000469 + px : 0.000238 + py : 0.000137 + + 11 H s : -0.013943 s : -0.013943 + pz : 0.000094 p : 0.000469 + px : 0.000238 + py : 0.000137 + + 12 H s : 0.016025 s : 0.016025 + pz : -0.016038 p : -0.018740 + px : -0.000224 + py : -0.002478 + + 13 H s : 0.029860 s : 0.029860 + pz : -0.000354 p : -0.000845 + px : -0.000374 + py : -0.000118 + + 14 H s : 0.015378 s : 0.015378 + pz : -0.015330 p : -0.017940 + px : -0.001537 + py : -0.001074 + + + + ***************************** + * MAYER POPULATION ANALYSIS * + ***************************** + + NA - Mulliken gross atomic population + ZA - Total nuclear charge + QA - Mulliken gross atomic charge + VA - Mayer's total valence + BVA - Mayer's bonded valence + FA - Mayer's free valence + + ATOM NA ZA QA VA BVA FA + 0 C 6.3656 6.0000 -0.3656 3.9203 3.9172 0.0031 + 1 C 5.9048 6.0000 0.0952 3.4924 2.9553 0.5372 + 2 C 6.3675 6.0000 -0.3675 3.9451 3.9421 0.0031 + 3 C 6.1655 6.0000 -0.1655 3.9386 3.9320 0.0066 + 4 C 6.3471 6.0000 -0.3471 3.8904 3.1898 0.7006 + 5 H 0.8905 1.0000 0.1095 0.9750 0.9750 0.0000 + 6 H 0.8859 1.0000 0.1141 0.9587 0.9562 0.0025 + 7 H 0.8864 1.0000 0.1136 0.9534 0.9516 0.0018 + 8 H 0.8864 1.0000 0.1136 0.9534 0.9516 0.0018 + 9 H 0.8902 1.0000 0.1098 0.9737 0.9737 0.0000 + 10 H 0.8818 1.0000 0.1182 0.9519 0.9514 0.0005 + 11 H 0.8818 1.0000 0.1182 0.9519 0.9514 0.0005 + 12 H 0.8765 1.0000 0.1235 0.9757 0.9739 0.0018 + 13 H 0.8859 1.0000 0.1141 0.9587 0.9562 0.0025 + 14 H 0.8841 1.0000 0.1159 0.9789 0.9771 0.0018 + + Mayer bond orders larger than 0.100000 +B( 0-C , 1-C ) : 0.9797 B( 0-C , 5-H ) : 0.9836 B( 0-C , 6-H ) : 0.9585 +B( 0-C , 13-H ) : 0.9585 B( 1-C , 2-C ) : 0.9716 B( 1-C , 3-C ) : 1.0266 +B( 2-C , 7-H ) : 0.9582 B( 2-C , 8-H ) : 0.9582 B( 2-C , 9-H ) : 0.9896 +B( 3-C , 4-C ) : 1.0562 B( 3-C , 10-H ) : 0.9153 B( 3-C , 11-H ) : 0.9153 +B( 4-C , 12-H ) : 0.9700 B( 4-C , 14-H ) : 0.9773 + +------- +TIMINGS +------- + +Total SCF time: 0 days 0 hours 0 min 49 sec + +Total time .... 49.879 sec +Sum of individual times .... 68.267 sec (136.9%) + +Fock matrix formation .... 48.676 sec ( 97.6%) + Startup .... 0.047 sec ( 0.1% of F) + Split-RI-J .... 2.016 sec ( 4.1% of F) + Chain of spheres X .... 31.611 sec ( 64.9% of F) + XC integration .... 14.821 sec ( 30.4% of F) + XC Preparation .... 0.000 sec ( 0.0% of XC) + Basis function eval. .... 1.329 sec ( 9.0% of XC) + Density eval. .... 1.776 sec ( 12.0% of XC) + XC-Functional eval. .... 0.422 sec ( 2.9% of XC) + XC-Potential eval. .... 2.837 sec ( 19.1% of XC) +Diagonalization .... 0.000 sec ( 0.0%) +Density matrix formation .... 0.123 sec ( 0.2%) +Total Energy calculation .... 0.071 sec ( 0.1%) +Population analysis .... 0.056 sec ( 0.1%) +Orbital Transformation .... 0.103 sec ( 0.2%) +Orbital Orthonormalization .... 0.000 sec ( 0.0%) +DIIS solution .... 0.831 sec ( 1.7%) +SCF Stability Analysis .... 18.407 sec ( 36.9%) +Finished LeanSCF after 135.4 sec + +Maximum memory used throughout the entire LEANSCF-calculation: 65.2 MB + +------------------------- -------------------- +FINAL SINGLE POINT ENERGY -196.364789361723 +------------------------- -------------------- + + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------ + ORCA PROPERTY CALCULATIONS +------------------------------------------------------------------------------ + +GBWName ... input.gbw +Number of atoms ... 15 +Number of basis functions ... 215 +Max core memory ... 3500 MB + +Electric properties: +Dipole moment ... YES +Quadrupole moment ... NO +Static polarizability (Dipole/Dipole) ... NO +Static polarizability (Dipole/Quad.) ... NO +Static polarizability (Quad./Quad.) ... NO +Static polarizability (Velocity) ... NO + +Atomic electric properties: +Dipole moment ... NO +Quadrupole moment ... NO +Static polarizability ... NO + +Choice of electric origin ... Center of mass +Position of electric origin ... -0.024416 -0.007003 0.000003 + +General magnetic properties: +Magnetizability ... NO + +EPR properties: +g-Tensor (aka g-matrix) ... NO +Zero-Field splitting spin-orbit ... NO +Zero-field splitting spin-spin ... NO +Hyperfine couplings ... NO ( 0 nuclei) +Quadrupole couplings ... NO ( 0 nuclei) +Contact density ... NO ( 0 nuclei) + +NMR properties: +Chemical shifts ... NO ( 0 nuclei) +Spin-rotation constants ... NO ( 0 nuclei) +Spin-spin couplings ... NO ( 0 nuclei, 0 pairs) + +Choice of magnetic origin ... GIAO +Position of magnetic origin ... 0.000000 0.000000 0.000000 + +Properties with geometric perturbations: +SCF Hessian ... NO +IR spectrum ... NO +VCD spectrum ... NO +X-ray spectroscopy properties: +SCF XES/XAS/RIXS spectra ... NO + + +------------- +DIPOLE MOMENT +------------- + +Method : SCF +Type of density : Electron Density +Multiplicity : 1 +Irrep : 0 +Energy : -196.3647893617227851 Eh +Relativity type : +Basis : AO + X Y Z +Electronic contribution: -0.734950469 -0.408864827 0.000023100 +Nuclear contribution : 0.976691591 0.280156462 -0.000016067 + ----------------------------------------- +Total Dipole Moment : 0.241741122 -0.128708364 0.000007033 + ----------------------------------------- +Magnitude (a.u.) : 0.273869701 +Magnitude (Debye) : 0.696121457 + + + +-------------------- +Rotational spectrum +-------------------- + +Rotational constants in cm-1: 0.268338 0.120855 0.087215 +Rotational constants in MHz : 8044.566360 3623.145038 2614.631852 + +Dipole components along the rotational axes: +x,y,z [a.u.] : 0.240265 -0.131444 0.000000 +x,y,z [Debye]: 0.610705 -0.334103 0.000001 + + + +Dipole moment calculation done in 0.0 sec + +Maximum memory used throughout the entire PROP-calculation: 10.3 MB + +-------------------------------- +SUGGESTED CITATIONS FOR THIS RUN +-------------------------------- + +Below you find a list of papers that are relevant to this ORCA run +We neither can nor want to force you to cite these papers, but we appreciate if you do +You receive ORCA, which is the product of decades of hard work by many enthusiastic individuals, for free +The only thing we kindly ask in return is that you cite our papers, +We deeply appreciate it, if you show your appreciation for ORCA by not just citing the generic ORCA reference. + +Please note that relegating all ORCA citations to the supporting information does *not* help us. +SI sections are not indexed - citations you put there will not count into any citation statistics +But we need these citations in order to attract the funding resources that allow us to do what we are doing + +Therefore, if you are a happy ORCA user, please consider citing a few of the papers listed below in the main body of your paper + +In addition to the list printed below, the program has created the file input.bibtex that contains the list in bibtex format +You can import this file easily into all common literature databanks and citation aid programs + + +List of essential papers. We consider these as the minimum necessary citations + + 1. Neese,F. + Software update: the ORCA program system, version 5.0 + WIRES Comput. Molec. Sci., 2022 12(1)e1606 + doi.org/10.1002/wcms.1606 + +List of papers to cite with high priority. The work reported in these papers was absolutely +necessary for this run to complete. +Our perspective: the developers of density functionals and basis sets usually get cited in chemistry papers +Good! But without the algorithms to do something with them, the functionals or basis sets would not do anything. +Hence, in our opinion, the algorithm design and method developments papers are equally worthy of getting cited + + 1. Neese,F. + An improvement of the resolution of the identity approximation for the formation of the Coulomb matrix + J. Comp. Chem., 2003 24(14)1740-1747 + doi.org/10.1002/jcc.10318 + 2. Neese,F.; Wennmohs,F.; Hansen,A.; Becker,U. + Efficient, approximate and parallel Hartree-Fock and hybrid DFT calculations. A 'chain-of-spheres' algorithm for the Hartree-Fock exchange + Chem. Phys., 2009 356(1-3)98-109 + doi.org/10.1016/j.chemphys.2008.10.036 + 3. Helmich-Paris,B.; de Souza,B.; Neese,F.; Izsák,R. + An improved chain of spheres for exchange algorithm + J. Chem. Phys., 2021 155 104109 + doi.org/doi: 10.1063/5.0058766. + 4. Neese,F. + The SHARK Integral Generation and Digestion System + J. Comp. Chem., 2022 1-16 + doi.org/10.1002/jcc.26942 + +List of suggested additional citations. These are papers that are important in the 'surrounding' of +of this run, or papers that preceded the highly important papers. If you like your results we are grateful for a citation. + + 1. Izsak,R.; Neese,F. + An overlap fitted chain of spheres exchange method + J. Chem. Phys., 2011 135 144105 + doi.org/10.1063/1.3646921 + 2. Izsak,R.; Hansen,A.; Neese,F. + The resolution of identity and chain of spheres approximations for the LPNO-CCSD singles Fock term + Molec. Phys., 2012 110 2413-2417 + doi.org/10.1080/00268976.2012.687466 + 3. Neese,F. + The ORCA program system + WIRES Comput. Molec. Sci., 2012 2(1)73-78 + doi.org/10.1002/wcms.81 + 4. Izsak,R.; Neese,F.; Klopper,W. + Robust fitting techniques in the chain of spheres approximation to the Fock exchange: The role of the complementary space + J. Chem. Phys., 2013 139 + doi.org/10.1063/1.4819264 + 5. Neese,F. + Software update: the ORCA program system, version 4.0 + WIRES Comput. Molec. Sci., 2018 8(1)1-6 + doi.org/10.1002/wcms.1327 + 6. Neese,F.; Wennmohs,F.; Becker,U.; Riplinger,C. + The ORCA quantum chemistry program package + J. Chem. Phys., 2020 152 Art. No. L224108 + doi.org/10.1063/5.0004608 + +List of optional additional citations + + 1. Neese,F. + Approximate second-order SCF convergence for spin unrestricted wavefunctions + Chem. Phys. Lett., 2000 325(1-3)93-98 + doi.org/10.1016/s0009-2614(00)00662-x + +Timings for individual modules: + +Sum of individual times ... 145.610 sec (= 2.427 min) +Startup calculation ... 6.184 sec (= 0.103 min) 4.2 % +SCF iterations ... 138.238 sec (= 2.304 min) 94.9 % +Property calculations ... 1.187 sec (= 0.020 min) 0.8 % + ****ORCA TERMINATED NORMALLY**** +TOTAL RUN TIME: 0 days 0 hours 2 minutes 26 seconds 763 msec diff --git a/arc/testing/stability/orca_stable_restricted_singlet_ts.out b/arc/testing/stability/orca_stable_restricted_singlet_ts.out new file mode 100644 index 0000000000..12665f46c1 --- /dev/null +++ b/arc/testing/stability/orca_stable_restricted_singlet_ts.out @@ -0,0 +1,1164 @@ + + ***************** + * O R C A * + ***************** + + #, + ### + #### + ##### + ###### + ########, + ,,################,,,,, + ,,#################################,, + ,,##########################################,, + ,#########################################, ''#####, + ,#############################################,, '####, + ,##################################################,,,,####, + ,###########'''' ''''############################### + ,#####'' ,,,,##########,,,, '''####''' '#### + ,##' ,,,,###########################,,, '## + ' ,,###'''' '''############,,, + ,,##'' '''############,,,, ,,,,,,###'' + ,#'' '''#######################''' + ' ''''####'''' + ,#######, #######, ,#######, ## + ,#' '#, ## ## ,#' '#, #''# ,####, ,####, + ## ## ## ,#' ## #' '# #' #' '# + ## ## ####### ## ,######, #####, # # + '#, ,#' ## ## '#, ,#' ,# #, #, # #, ,# + '#######' ## ## '#######' #' '# '####' # '####' + + + + ######################################################### + # -***- # + # Department of theory and spectroscopy # + # # + # Frank Neese # + # # + # Directorship, Architecture, Infrastructure # + # SHARK, DRIVERS # + # Core code/Algorithms in most modules # + # # + # Max Planck Institute fuer Kohlenforschung # + # Kaiser Wilhelm Platz 1 # + # D-45470 Muelheim/Ruhr # + # Germany # + # # + # All rights reserved # + # -***- # + ######################################################### + + + Program Version 6.0.0 - RELEASE - + + + With contributions from (in alphabetic order): + Daniel Aravena : Magnetic Suceptibility + Michael Atanasov : Ab Initio Ligand Field Theory (pilot matlab implementation) + Alexander A. Auer : GIAO ZORA, VPT2 properties, NMR spectrum + Ute Becker : All parallelization in ORCA, NUMFREQ, NUMCALC + Giovanni Bistoni : ED, misc. LED, open-shell LED, HFLD + Martin Brehm : Molecular dynamics + Dmytro Bykov : pre 5.0 version of the SCF Hessian + Marcos Casanova-Páez : Triplet and SCS-CIS(D). UHF-(DLPNO)-IP/EA/STEOM-CCSD. UHF-CVS-IP/STEOM-CCSD + Vijay G. Chilkuri : MRCI spin determinant printing, contributions to CSF-ICE + Pauline Colinet : FMM embedding + Dipayan Datta : RHF DLPNO-CCSD density + Achintya Kumar Dutta : EOM-CC, STEOM-CC + Nicolas Foglia : Exact transition moments, OPA infrastructure, MCD improvements + Dmitry Ganyushin : Spin-Orbit,Spin-Spin,Magnetic field MRCI + Miquel Garcia : C-PCM and meta-GGA Hessian, CCSD/C-PCM, Gaussian charge scheme + Tiago L. C. Gouveia : GS-ROHF, GS-ROCIS + Yang Guo : DLPNO-NEVPT2, F12-NEVPT2, CIM, IAO-localization + Andreas Hansen : Spin unrestricted coupled pair/coupled cluster methods + Ingolf Harden : AUTO-CI MPn and infrastructure + Benjamin Helmich-Paris : MC-RPA, TRAH-(SCF,CASSCF), AVAS, COSX integrals, SCF dyn. polar. + Lee Huntington : MR-EOM, pCC + Robert Izsak : Overlap fitted RIJCOSX, COSX-SCS-MP3, EOM + Riya Kayal : Wick's Theorem for AUTO-CI, AUTO-CI UHF-CCSDT + Emily Kempfer : AUTO-CI, RHF CISDT and CCSDT + Christian Kollmar : KDIIS, OOCD, Brueckner-CCSD(T), CCSD density, CASPT2, CASPT2-K, improved NEVPT2 + Axel Koslowski : Symmetry handling + Simone Kossmann : Meta GGA functionals, TD-DFT gradient, OOMP2, (MP2 Hessian; deprecated post 5.0) + Lucas Lang : DCDCAS + Marvin Lechner : AUTO-CI (C++ implementation), FIC-MRCC + Spencer Leger : CASSCF response + Dagmar Lenk : GEPOL surface, SMD, ORCA-2-JSON + Dimitrios Liakos : Extrapolation schemes; Compound Job, initial MDCI parallelization + Dimitrios Manganas : Further ROCIS development; embedding schemes. LFT, Crystal Embedding + Dimitrios Pantazis : SARC Basis sets + Anastasios Papadopoulos: AUTO-CI, single reference methods and gradients + Taras Petrenko : pre 6.0 DFT Hessian and TD-DFT gradient, (ASA, deprecated), ECA, 1-Electron XAS/XES, NRVS + Peter Pinski : DLPNO-MP2, DLPNO-MP2 Gradient + Christoph Reimann : Effective Core Potentials + Marius Retegan : Local ZFS, SOC + Christoph Riplinger : Optimizer, TS searches, QM/MM, DLPNO-CCSD(T), (RO)-DLPNO pert. Triples + Michael Roemelt : Original ROCIS implementation + Masaaki Saitow : Open-shell DLPNO-CCSD energy and density + Barbara Sandhoefer : DKH picture change effects + Kantharuban Sivalingam : CASSCF convergence/infrastructure, NEVPT2 and variants, FIC-MRCI + Bernardo de Souza : ESD, SOC TD-DFT + Georgi Stoychev : AutoAux, RI-MP2 NMR, DLPNO-MP2 response, X2C + Van Anh Tran : RI-MP2 g-tensors + Willem Van den Heuvel : Paramagnetic NMR + Zikuan Wang : NOTCH, Electric field optimization + Frank Wennmohs : Technical directorship and infrastructure + Hang Xu : AUTO-CI-Response properties + + + We gratefully acknowledge several colleagues who have allowed us to + interface, adapt or use parts of their codes: + Stefan Grimme, W. Hujo, H. Kruse, P. Pracht, : VdW corrections, initial TS optimization, + C. Bannwarth, S. Ehlert, DFT functionals, gCP, sTDA/sTD-DF + L. Wittmann, M. Mueller + Ed Valeev, F. Pavosevic, A. Kumar : LibInt (2-el integral package), F12 methods + Garnet Chan, S. Sharma, J. Yang, R. Olivares : DMRG + Ulf Ekstrom : XCFun DFT Library + Mihaly Kallay : mrcc (arbitrary order and MRCC methods) + Frank Weinhold : gennbo (NPA and NBO analysis) + Simon Mueller : openCOSMO-RS + Christopher J. Cramer and Donald G. Truhlar : smd solvation model + Lars Goerigk : TD-DFT with DH, B97 family of functionals + V. Asgeirsson, H. Jonsson : NEB implementation + FAccTs GmbH : IRC, NEB, NEB-TS, DLPNO-Multilevel, CI-OPT + MM, QMMM, 2- and 3-layer-ONIOM, Crystal-QMMM, + LR-CPCM, SF, NACMEs, symmetry and pop. for TD-DFT, + nearIR, NL-DFT gradient (VV10), updates on ESD, + ML-optimized integration grids, MBIS, APM, + GOAT, DOCKER, SOLVATOR, interface openCOSMO-RS + S Lehtola, MJT Oliveira, MAL Marques : LibXC Library + Liviu Ungur et al : ANISO software + + + Your calculation uses the libint2 library for the computation of 2-el integrals + For citations please refer to: http://libint.valeyev.net + + Your ORCA version has been built with support for libXC version: 6.2.2 + For citations please refer to: https://libxc.gitlab.io + + This ORCA versions uses: + CBLAS interface : Fast vector & matrix operations + LAPACKE interface : Fast linear algebra routines + SCALAPACK package : Parallel linear algebra routines + Shared memory : Shared parallel matrices + BLAS/LAPACK : OpenBLAS 0.3.27 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Cooperlake SINGLE_THREADED + Core in use : Cooperlake + Copyright (c) 2011-2014, The OpenBLAS Project + + +NOTE: MaxCore=3500 MB was set to SCF,MP2,MDCI,CIPSI,MRCI and CIS + => If you want to overwrite this, your respective input block should be placed after the MaxCore statement +Warning: RI is on but no J-basis has been assigned. Assigning Def2/J (nothing to worry about!) +================================================================================ + +----- Orbital basis set information ----- +Your calculation utilizes the basis: def2-TZVP + F. Weigend and R. Ahlrichs, Phys. Chem. Chem. Phys. 7, 3297 (2005). + +----- AuxJ basis set information ----- +Your calculation utilizes the auxiliary basis: def2/J + F. Weigend, Phys. Chem. Chem. Phys. 8, 1057 (2006). + +================================================================================ + WARNINGS + Please study these warnings very carefully! +================================================================================ + + +================================================================================ + INPUT FILE +================================================================================ +NAME = input.in +| 1> !RKS B3LYP def2-TZVP TightSCF defgrid3 +| 2> %maxcore 3500 +| 3> %pal nprocs 8 end +| 4> +| 5> * xyz 0 1 +| 6> C -1.29545 0.32293 0.00000 +| 7> C 1.13241 0.23585 0.00000 +| 8> O 0.16551 -0.50307 0.00000 +| 9> H -1.72265 -0.21710 -0.86208 +| 10> H -1.72266 -0.21708 0.86209 +| 11> H 2.12997 -0.21237 0.00001 +| 12> H 0.96946 1.31837 -0.00001 +| 13> * +| 14> +| 15> %scf +| 16> MaxIter 999 +| 17> STABPerform true +| 18> STABRestartUHFifUnstable false +| 19> STABNRoots 6 +| 20> end +| 21> +| 22> ****END OF INPUT**** +================================================================================ + + **************************** + * Single Point Calculation * + **************************** + +--------------------------------- +CARTESIAN COORDINATES (ANGSTROEM) +--------------------------------- + C -1.295450 0.322930 0.000000 + C 1.132410 0.235850 0.000000 + O 0.165510 -0.503070 0.000000 + H -1.722650 -0.217100 -0.862080 + H -1.722660 -0.217080 0.862090 + H 2.129970 -0.212370 0.000010 + H 0.969460 1.318370 -0.000010 + +---------------------------- +CARTESIAN COORDINATES (A.U.) +---------------------------- + NO LB ZA FRAG MASS X Y Z + 0 C 6.0000 0 12.011 -2.448046 0.610249 0.000000 + 1 C 6.0000 0 12.011 2.139945 0.445692 0.000000 + 2 O 8.0000 0 15.999 0.312769 -0.950665 0.000000 + 3 H 1.0000 0 1.008 -3.255337 -0.410260 -1.629095 + 4 H 1.0000 0 1.008 -3.255356 -0.410222 1.629114 + 5 H 1.0000 0 1.008 4.025060 -0.401321 0.000019 + 6 H 1.0000 0 1.008 1.832014 2.491358 -0.000019 + +-------------------------------- +INTERNAL COORDINATES (ANGSTROEM) +-------------------------------- + C 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 2.429421146282 0.00000000 0.00000000 + O 2 1 0 1.216921680471 39.44177034 0.00000000 + H 1 2 3 1.103319612488 111.67875369 302.77288956 + H 1 2 3 1.103321509035 111.67931307 57.22833525 + H 2 1 3 1.093630249262 157.85898379 0.00000000 + H 2 1 3 1.094715603707 79.38548209 179.99946750 + +--------------------------- +INTERNAL COORDINATES (A.U.) +--------------------------- + C 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 4.590940630429 0.00000000 0.00000000 + O 2 1 0 2.299648702521 39.44177034 0.00000000 + H 1 2 3 2.084971905786 111.67875369 302.77288956 + H 1 2 3 2.084975489741 111.67931307 57.22833525 + H 2 1 3 2.066661662876 157.85898379 0.00000000 + H 2 1 3 2.068712685537 79.38548209 179.99946750 + +--------------------- +BASIS SET INFORMATION +--------------------- +There are 3 groups of distinct atoms + + Group 1 Type C : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 2 Type O : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 3 Type H : 5s1p contracted to 3s1p pattern {311/1} + +Atom 0C basis set group => 1 +Atom 1C basis set group => 1 +Atom 2O basis set group => 2 +Atom 3H basis set group => 3 +Atom 4H basis set group => 3 +Atom 5H basis set group => 3 +Atom 6H basis set group => 3 +--------------------------------- +AUXILIARY/J BASIS SET INFORMATION +--------------------------------- +There are 3 groups of distinct atoms + + Group 1 Type C : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 2 Type O : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 3 Type H : 5s2p1d contracted to 3s1p1d pattern {311/2/1} + +Atom 0C basis set group => 1 +Atom 1C basis set group => 1 +Atom 2O basis set group => 2 +Atom 3H basis set group => 3 +Atom 4H basis set group => 3 +Atom 5H basis set group => 3 +Atom 6H basis set group => 3 + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------ + ORCA STARTUP CALCULATIONS + -- RI-GTO INTEGRALS CHOSEN -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + ___ + / \ - P O W E R E D B Y - + / \ + | | | _ _ __ _____ __ __ + | | | | | | | / \ | _ \ | | / | + \ \/ | | | | / \ | | | | | | / / + / \ \ | |__| | / /\ \ | |_| | | |/ / + | | | | __ | / /__\ \ | / | \ + | | | | | | | | __ | | \ | |\ \ + \ / | | | | | | | | | |\ \ | | \ \ + \___/ |_| |_| |__| |__| |_| \__\ |__| \__/ + + - O R C A' S B I G F R I E N D - + & + - I N T E G R A L F E E D E R - + + v1 FN, 2020, v2 2021, v3 2022-2024 +------------------------------------------------------------------------------ + + +---------------------- +SHARK INTEGRAL PACKAGE +---------------------- + +Number of atoms ... 7 +Number of basis functions ... 117 +Number of shells ... 49 +Maximum angular momentum ... 3 +Integral batch strategy ... SHARK/LIBINT Hybrid +RI-J (if used) integral strategy ... SPLIT-RIJ (Revised 2003 algorithm where possible) +Printlevel ... 1 +Contraction scheme used ... SEGMENTED contraction +Prescreening option ... SCHWARTZ + Thresh ... 2.500e-11 + Tcut ... 2.500e-12 + Tpresel ... 2.500e-12 +Coulomb Range Separation ... NOT USED +Exchange Range Separation ... NOT USED +Multipole approximations ... NOT USED +Finite Nucleus Model ... NOT USED +CABS basis ... NOT available +Auxiliary Coulomb fitting basis ... AVAILABLE + # of basis functions in Aux-J ... 191 + # of shells in Aux-J ... 65 + Maximum angular momentum in Aux-J ... 4 +Auxiliary J/K fitting basis ... NOT available +Auxiliary Correlation fitting basis ... NOT available +Auxiliary 'external' fitting basis ... NOT available + +Checking pre-screening integrals ... done ( 0.0 sec) Dimension = 49 +Check shell pair data ... done ( 0.0 sec) +Shell pair information +Shell pair cut-off parameter TPreSel ... 2.5e-12 +Total number of shell pairs ... 1225 +Shell pairs after pre-screening ... 1209 +Total number of primitive shell pairs ... 3648 +Primitive shell pairs kept ... 3052 + la=0 lb=0: 363 shell pairs + la=1 lb=0: 350 shell pairs + la=1 lb=1: 91 shell pairs + la=2 lb=0: 162 shell pairs + la=2 lb=1: 78 shell pairs + la=2 lb=2: 21 shell pairs + la=3 lb=0: 81 shell pairs + la=3 lb=1: 39 shell pairs + la=3 lb=2: 18 shell pairs + la=3 lb=3: 6 shell pairs + +Calculating one electron integrals ... done ( 0.0 sec) +Calculating RI/J V-Matrix + Cholesky decomp.... done ( 0.0 sec) +Calculating Nuclear repulsion ... done ( 0.0 sec) ENN= 69.190779034557 Eh + +Diagonalization of the overlap matrix: +Smallest eigenvalue ... 1.077e-03 +Time for diagonalization ... 0.002 sec +Threshold for overlap eigenvalues ... 1.000e-07 +Number of eigenvalues below threshold ... 0 +Time for construction of square roots ... 0.001 sec +Total time needed ... 0.005 sec + +------------------- +DFT GRID GENERATION +------------------- + +General Integration Accuracy IntAcc ... 4.959 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 6 (Lebedev-590) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... off +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 79398 +Total number of batches ... 1245 +Average number of points per batch ... 63 +Average number of grid points per atom ... 11343 + +-------------------- +COSX GRID GENERATION +-------------------- + +GRIDX 1 +------- +General Integration Accuracy IntAcc ... 4.020 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 2 (Lebedev-110) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 8766 +Total number of batches ... 72 +Average number of points per batch ... 121 +Average number of grid points per atom ... 1252 +UseSFitting ... on + +GRIDX 2 +------- +General Integration Accuracy IntAcc ... 4.338 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 3 (Lebedev-194) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 19312 +Total number of batches ... 153 +Average number of points per batch ... 126 +Average number of grid points per atom ... 2759 +UseSFitting ... on + +GRIDX 3 +------- +General Integration Accuracy IntAcc ... 4.871 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 4 (Lebedev-302) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 37851 +Total number of batches ... 299 +Average number of points per batch ... 126 +Average number of grid points per atom ... 5407 +UseSFitting ... on +Initializing property integral containers ... done ( 0.0 sec) + +SHARK setup successfully completed in 2.4 seconds + +Maximum memory used throughout the entire STARTUP-calculation: 19.6 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------- + ORCA GUESS + Start orbitals & Density for SCF / CASSCF +------------------------------------------------------------------------------- + +------------ +SCF SETTINGS +------------ +Hamiltonian: + Density Functional Method .... DFT(GTOs) + Exchange Functional Exchange .... B88 + X-Alpha parameter XAlpha .... 0.666667 + Becke's b parameter XBeta .... 0.004200 + Correlation Functional Correlation .... LYP + LDA part of GGA corr. LDAOpt .... VWN-5 + Gradients option PostSCFGGA .... off + Hybrid DFT is turned on + Fraction HF Exchange ScalHFX .... 0.200000 + Scaling of DF-GGA-X ScalDFX .... 0.720000 + Scaling of DF-GGA-C ScalDFC .... 0.810000 + Scaling of DF-LDA-C ScalLDAC .... 1.000000 + Perturbative correction .... 0.000000 + NL short-range parameter .... 4.800000 + RI-approximation to the Coulomb term is turned on + Number of AuxJ basis functions .... 191 + RIJ-COSX (HFX calculated with COS-X)).... on + + +General Settings: + Integral files IntName .... input + Hartree-Fock type HFTyp .... RHF + Total Charge Charge .... 0 + Multiplicity Mult .... 1 + Number of Electrons NEL .... 24 + Basis Dimension Dim .... 117 + Nuclear Repulsion ENuc .... 69.1907790346 Eh + +Convergence Acceleration: + AO-DIIS CNVDIIS .... on + Start iteration DIISMaxIt .... 12 + Startup error DIISStart .... 0.200000 + # of expansion vecs DIISMaxEq .... 5 + Bias factor DIISBfac .... 1.050 + Max. coefficient DIISMaxC .... 10.000 + MO-DIIS CNVKDIIS .... off + Trust-Rad. Augm. Hess. CNVTRAH .... auto + Auto Start mean grad. ratio tolernc. .... 1.125000 + Auto Start start iteration .... 50 + Auto Start num. interpolation iter. .... 10 + Max. Number of Micro iterations .... 24 + Max. Number of Macro iterations .... Maxiter - #DIIS iter + Number of Davidson start vectors .... 2 + Converg. threshold (grad. norm) .... 1.000e-05 + Grad. Scal. Fac. for Micro threshold .... 0.100 + Minimum threshold for Micro iter. .... 1.000e-02 + NR start threshold (gradient norm) .... 1.000e-04 + Initial trust radius .... 0.400 + Minimum AH scaling param. (alpha) .... 1.000 + Maximum AH scaling param. (alpha) .... 1000.000 + Quad. conv. algorithm .... NR + White noise on init. David. guess .... on + Maximum white noise .... 0.010 + Pseudo random numbers .... off + Inactive MOs .... canonical + Orbital update algorithm .... Taylor + Preconditioner .... Diag + Full preconditioner red. dimension .... 250 + SOSCF CNVSOSCF .... on + Start iteration SOSCFMaxIt .... 150 + Startup grad/error SOSCFStart .... 0.003300 + Hessian update SOSCFHessUp .... L-BFGS + Level Shifting CNVShift .... on + Level shift para. LevelShift .... 0.2500 + Turn off err/grad. ShiftErr .... 0.0010 + Zerner damping CNVZerner .... off + Static damping CNVDamp .... on + Fraction old density DampFac .... 0.7000 + Max. Damping (<1) DampMax .... 0.9800 + Min. Damping (>=0) DampMin .... 0.0000 + Turn off err/grad. DampErr .... 0.1000 + +SCF Procedure: + Maximum # iterations MaxIter .... 999 + SCF integral mode SCFMode .... Direct + Integral package .... SHARK and LIBINT hybrid scheme + Reset frequency DirectResetFreq .... 20 + Integral Threshold Thresh .... 2.500e-11 Eh + Primitive CutOff TCut .... 2.500e-12 Eh + +Convergence Tolerance: + Convergence Check Mode ConvCheckMode .... Total+1el-Energy + Convergence forced ConvForced .... 0 + Energy Change TolE .... 1.000e-08 Eh + 1-El. energy change .... 1.000e-05 Eh + Orbital Gradient TolG .... 1.000e-05 + Orbital Rotation angle TolX .... 1.000e-05 + DIIS Error TolErr .... 5.000e-07 + +------------------------------ +INITIAL GUESS: MODEL POTENTIAL +------------------------------ +Loading Hartree-Fock densities ... done +Calculating cut-offs ... done +Initializing the effective Hamiltonian ... done +Setting up the integral package (SHARK) ... done +Starting the Coulomb interaction ... done ( 0.0 sec) +Making the grid ... done ( 0.1 sec) +Mapping shells ... done +Starting the XC term evaluation ... done ( 0.0 sec) + promolecular density results + # of electrons = 23.998223446 + EX = -19.575304631 + EC = -0.788393495 + EX+EC = -20.363698127 +Transforming the Hamiltonian ... done ( 0.0 sec) +Diagonalizing the Hamiltonian ... done ( 0.0 sec) +Back transforming the eigenvectors ... done ( 0.0 sec) +Now organizing SCF variables ... done + ------------------ + INITIAL GUESS DONE ( 0.1 sec) + ------------------ + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** +Finished Guess after 1.1 sec +Maximum memory used throughout the entire GUESS-calculation: 8.3 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------------------- + ORCA LEAN-SCF + memory conserving SCF solver +------------------------------------------------------------------------------------------- + +----------------------------------------D-I-I-S-------------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP DIISErr Damp Time(sec) +------------------------------------------------------------------------------------------- + *** Starting incremental Fock matrix formation *** + 1 -153.5583509804788491 0.00e+00 2.07e-03 4.07e-02 1.86e-01 0.700 0.9 +Warning: op=0 Small HOMO/LUMO gap ( 0.009) - skipping pre-diagonalization + Will do a full diagonalization + 2 -153.6005216590920668 -4.22e-02 1.83e-03 3.34e-02 9.51e-02 0.700 0.6 + ***Turning on AO-DIIS*** + 3 -153.6171180037558770 -1.66e-02 8.31e-04 1.24e-02 2.94e-02 0.700 0.7 + 4 -153.6266756172826149 -9.56e-03 1.21e-03 1.93e-02 1.59e-02 0.000 0.6 + 5 -153.6481287648181251 -2.15e-02 4.02e-04 7.83e-03 7.06e-03 0.000 0.5 + *** Initializing SOSCF *** +---------------------------------------S-O-S-C-F-------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP MaxGrad Time(sec) +-------------------------------------------------------------------------------------- + 6 -153.6483780191632604 -2.49e-04 1.94e-04 4.17e-03 2.48e-03 0.5 + *** Restarting incremental Fock matrix formation *** + 7 -153.6484089867136618 -3.10e-05 1.82e-04 4.34e-03 5.95e-04 0.9 + 8 -153.6484089862681230 4.46e-10 7.61e-05 1.54e-03 1.48e-03 0.8 + **** Energy Check signals convergence **** + + ***************************************************** + * SUCCESS * + * SCF CONVERGED AFTER 8 CYCLES * + ***************************************************** + +Recomputing exchange energy using gridx3 ... done ( 1.039 sec) +Old exchange energy : -3.971873928 Eh +New exchange energy : -3.971874330 Eh +Exchange energy change after final integration : -0.000000402 Eh +Total energy after final integration : -153.648409388 Eh + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** + +------------------------------------------------------------------------------------------- + WAVEFUNCTION STABILITY ANALYSIS +------------------------------------------------------------------------------------------- + + + ****Iteration 0**** + Lowest Energy : 0.026318461086 + Maximum Energy change : 0.188357933921 (vector 5) + Maximum residual norm : 0.011655306424 + + ****Iteration 1**** + Lowest Energy : 0.024573343854 + Maximum Energy change : 0.030553444630 (vector 3) + Maximum residual norm : 0.002889820715 + + ****Iteration 2**** + Lowest Energy : 0.024544953523 + Maximum Energy change : 0.003275457402 (vector 3) + Maximum residual norm : 0.000054488773 + + *** CONVERGENCE OF RESIDUAL NORM REACHED *** +The eigenvalues of the stability matrix: + E( 0) = 0.02454495 Eh + E( 1) = 0.03104480 Eh + E( 2) = 0.08700829 Eh + E( 3) = 0.12767497 Eh + E( 4) = 0.15275048 Eh + E( 5) = 0.18269788 Eh + +The stability analysis shows that the wavefunction is stable + +---------------- +TOTAL SCF ENERGY +---------------- + +Total Energy : -153.64840938835118 Eh -4180.98578 eV + +Components: +Nuclear Repulsion : 69.19077903455708 Eh 1882.77682 eV +Electronic Energy : -222.83918802082522 Eh -6063.76258 eV +One Electron Energy: -344.47161366516428 Eh -9373.54915 eV +Two Electron Energy: 121.63242564433907 Eh 3309.78657 eV + +Virial components: +Potential Energy : -230.15342047027818 Eh -6262.79297 eV +Kinetic Energy : 76.50501108192699 Eh 2081.80719 eV +Virial Ratio : 3.00834438444579 + +DFT components: +N(Alpha) : 12.000000541261 electrons +N(Beta) : 12.000000541261 electrons +N(Total) : 24.000001082521 electrons +E(X) : -15.809795888555 Eh +E(C) : -0.935404802668 Eh +E(XC) : -16.745200691223 Eh + +--------------- +SCF CONVERGENCE +--------------- + + Last Energy change ... -4.4554e-10 Tolerance : 1.0000e-08 + Last MAX-Density change ... 1.5449e-03 Tolerance : 1.0000e-07 + Last RMS-Density change ... 7.6068e-05 Tolerance : 5.0000e-09 + Last DIIS Error ... 2.4823e-03 Tolerance : 5.0000e-07 + Last Orbital Gradient ... 1.4800e-03 Tolerance : 1.0000e-05 + Last Orbital Rotation ... 1.5263e-03 Tolerance : 1.0000e-05 + + +---------------- +ORBITAL ENERGIES +---------------- + + NO OCC E(Eh) E(eV) + 0 2.0000 -19.228621 -523.2374 + 1 2.0000 -10.316786 -280.7340 + 2 2.0000 -10.153148 -276.2812 + 3 2.0000 -1.140009 -31.0212 + 4 2.0000 -0.712684 -19.3931 + 5 2.0000 -0.631708 -17.1897 + 6 2.0000 -0.551657 -15.0114 + 7 2.0000 -0.494502 -13.4561 + 8 2.0000 -0.477599 -12.9961 + 9 2.0000 -0.365236 -9.9386 + 10 2.0000 -0.340346 -9.2613 + 11 2.0000 -0.180674 -4.9164 + 12 0.0000 -0.105261 -2.8643 + 13 0.0000 0.037298 1.0149 + 14 0.0000 0.042826 1.1653 + 15 0.0000 0.077587 2.1113 + 16 0.0000 0.098732 2.6866 + 17 0.0000 0.145470 3.9585 + 18 0.0000 0.149470 4.0673 + 19 0.0000 0.179735 4.8908 + 20 0.0000 0.183152 4.9838 + 21 0.0000 0.263194 7.1619 + 22 0.0000 0.279913 7.6168 +*Only the first 10 virtual orbitals were printed. + + ******************************** + * MULLIKEN POPULATION ANALYSIS * + ******************************** + +----------------------- +MULLIKEN ATOMIC CHARGES +----------------------- + 0 C : -0.515601 + 1 C : 0.099483 + 2 O : -0.068051 + 3 H : 0.098409 + 4 H : 0.098410 + 5 H : 0.144080 + 6 H : 0.143272 +Sum of atomic charges: 0.0000000 + +-------------------------------- +MULLIKEN REDUCED ORBITAL CHARGES +-------------------------------- + 0 C s : 3.606604 s : 3.606604 + pz : 0.987006 p : 2.851904 + px : 0.494507 + py : 1.370390 + dz2 : 0.005626 d : 0.053742 + dxz : 0.005455 + dyz : 0.017091 + dx2y2 : 0.005596 + dxy : 0.019973 + f0 : 0.000214 f : 0.003351 + f+1 : 0.000481 + f-1 : 0.000732 + f+2 : 0.000055 + f-2 : 0.000224 + f+3 : 0.000489 + f-3 : 0.001157 + + 1 C s : 3.279307 s : 3.279307 + pz : 0.621344 p : 2.492247 + px : 0.911909 + py : 0.958994 + dz2 : 0.006341 d : 0.116406 + dxz : 0.015520 + dyz : 0.011212 + dx2y2 : 0.058021 + dxy : 0.025313 + f0 : 0.001854 f : 0.012556 + f+1 : 0.000914 + f-1 : 0.000718 + f+2 : 0.000123 + f-2 : 0.001957 + f+3 : 0.003844 + f-3 : 0.003146 + + 2 O s : 3.785606 s : 3.785606 + pz : 1.349876 p : 4.239268 + px : 1.306905 + py : 1.582486 + dz2 : 0.002727 d : 0.041167 + dxz : 0.009337 + dyz : 0.005218 + dx2y2 : 0.009970 + dxy : 0.013915 + f0 : 0.000232 f : 0.002010 + f+1 : 0.000159 + f-1 : 0.000077 + f+2 : 0.000065 + f-2 : 0.000397 + f+3 : 0.000688 + f-3 : 0.000392 + + 3 H s : 0.879844 s : 0.879844 + pz : 0.009817 p : 0.021748 + px : 0.003813 + py : 0.008117 + + 4 H s : 0.879843 s : 0.879843 + pz : 0.009818 p : 0.021748 + px : 0.003813 + py : 0.008117 + + 5 H s : 0.835838 s : 0.835838 + pz : 0.002279 p : 0.020081 + px : 0.012798 + py : 0.005004 + + 6 H s : 0.834791 s : 0.834791 + pz : 0.002188 p : 0.021938 + px : 0.003977 + py : 0.015772 + + + + ******************************* + * LOEWDIN POPULATION ANALYSIS * + ******************************* + +---------------------- +LOEWDIN ATOMIC CHARGES +---------------------- + 0 C : -0.550875 + 1 C : -0.155457 + 2 O : 0.314098 + 3 H : 0.080228 + 4 H : 0.080229 + 5 H : 0.116027 + 6 H : 0.115751 + +------------------------------- +LOEWDIN REDUCED ORBITAL CHARGES +------------------------------- + 0 C s : 3.216827 s : 3.216827 + pz : 1.095068 p : 3.111678 + px : 0.588752 + py : 1.427858 + dz2 : 0.028595 d : 0.196569 + dxz : 0.035669 + dyz : 0.039125 + dx2y2 : 0.024948 + dxy : 0.068232 + f0 : 0.000919 f : 0.025801 + f+1 : 0.004305 + f-1 : 0.004632 + f+2 : 0.000642 + f-2 : 0.004431 + f+3 : 0.003044 + f-3 : 0.007828 + + 1 C s : 2.927171 s : 2.927171 + pz : 0.633338 p : 2.704226 + px : 1.020345 + py : 1.050543 + dz2 : 0.033974 d : 0.443928 + dxz : 0.040128 + dyz : 0.025898 + dx2y2 : 0.212267 + dxy : 0.131661 + f0 : 0.007031 f : 0.080132 + f+1 : 0.007212 + f-1 : 0.005387 + f+2 : 0.000945 + f-2 : 0.012357 + f+3 : 0.029722 + f-3 : 0.017478 + + 2 O s : 3.313719 s : 3.313719 + pz : 1.256175 p : 4.256066 + px : 1.392570 + py : 1.607321 + dz2 : 0.009852 d : 0.108753 + dxz : 0.015950 + dyz : 0.004179 + dx2y2 : 0.034973 + dxy : 0.043798 + f0 : 0.000290 f : 0.007364 + f+1 : 0.000739 + f-1 : 0.000403 + f+2 : 0.000074 + f-2 : 0.000839 + f+3 : 0.002995 + f-3 : 0.002025 + + 3 H s : 0.852847 s : 0.852847 + pz : 0.028438 p : 0.066925 + px : 0.010758 + py : 0.027729 + + 4 H s : 0.852847 s : 0.852847 + pz : 0.028438 p : 0.066925 + px : 0.010758 + py : 0.027728 + + 5 H s : 0.823399 s : 0.823399 + pz : 0.007365 p : 0.060574 + px : 0.036552 + py : 0.016657 + + 6 H s : 0.818197 s : 0.818197 + pz : 0.006838 p : 0.066053 + px : 0.011147 + py : 0.048067 + + + + ***************************** + * MAYER POPULATION ANALYSIS * + ***************************** + + NA - Mulliken gross atomic population + ZA - Total nuclear charge + QA - Mulliken gross atomic charge + VA - Mayer's total valence + BVA - Mayer's bonded valence + FA - Mayer's free valence + + ATOM NA ZA QA VA BVA FA + 0 C 6.5156 6.0000 -0.5156 2.5801 2.5801 0.0000 + 1 C 5.9005 6.0000 0.0995 3.7785 3.7785 0.0000 + 2 O 8.0681 8.0000 -0.0681 2.3800 2.3800 0.0000 + 3 H 0.9016 1.0000 0.0984 0.9617 0.9617 0.0000 + 4 H 0.9016 1.0000 0.0984 0.9617 0.9617 -0.0000 + 5 H 0.8559 1.0000 0.1441 0.9438 0.9438 0.0000 + 6 H 0.8567 1.0000 0.1433 1.0076 1.0076 -0.0000 + + Mayer bond orders larger than 0.100000 +B( 0-C , 2-O ) : 0.5125 B( 0-C , 3-H ) : 0.9612 B( 0-C , 4-H ) : 0.9612 +B( 1-C , 2-O ) : 1.8618 B( 1-C , 5-H ) : 0.9207 B( 1-C , 6-H ) : 0.9283 + + +------- +TIMINGS +------- + +Total SCF time: 0 days 0 hours 0 min 7 sec + +Total time .... 7.938 sec +Sum of individual times .... 11.080 sec (139.6%) + +SCF preparation .... 1.234 sec ( 15.5%) +Fock matrix formation .... 6.316 sec ( 79.6%) + Startup .... 0.049 sec ( 0.8% of F) + Split-RI-J .... 0.376 sec ( 5.9% of F) + Chain of spheres X .... 4.288 sec ( 67.9% of F) + XC integration .... 1.538 sec ( 24.4% of F) + XC Preparation .... 0.000 sec ( 0.0% of XC) + Basis function eval. .... 0.339 sec ( 22.1% of XC) + Density eval. .... 0.163 sec ( 10.6% of XC) + XC-Functional eval. .... 0.100 sec ( 6.5% of XC) + XC-Potential eval. .... 0.328 sec ( 21.3% of XC) +Diagonalization .... 0.000 sec ( 0.0%) +Density matrix formation .... 0.023 sec ( 0.3%) +Total Energy calculation .... 0.053 sec ( 0.7%) +Population analysis .... 0.016 sec ( 0.2%) +Orbital Transformation .... 0.021 sec ( 0.3%) +Orbital Orthonormalization .... 0.000 sec ( 0.0%) +DIIS solution .... 0.192 sec ( 2.4%) +SOSCF solution .... 0.055 sec ( 0.7%) +SCF Stability Analysis .... 3.171 sec ( 39.9%) +Finished LeanSCF after 11.1 sec + +Maximum memory used throughout the entire LEANSCF-calculation: 27.9 MB + +------------------------- -------------------- +FINAL SINGLE POINT ENERGY -153.648409388351 +------------------------- -------------------- + + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------ + ORCA PROPERTY CALCULATIONS +------------------------------------------------------------------------------ + +GBWName ... input.gbw +Number of atoms ... 7 +Number of basis functions ... 117 +Max core memory ... 3500 MB + +Electric properties: +Dipole moment ... YES +Quadrupole moment ... NO +Static polarizability (Dipole/Dipole) ... NO +Static polarizability (Dipole/Quad.) ... NO +Static polarizability (Quad./Quad.) ... NO +Static polarizability (Velocity) ... NO + +Atomic electric properties: +Dipole moment ... NO +Quadrupole moment ... NO +Static polarizability ... NO + +Choice of electric origin ... Center of mass +Position of electric origin ... 0.014631 -0.028308 0.000000 + +General magnetic properties: +Magnetizability ... NO + +EPR properties: +g-Tensor (aka g-matrix) ... NO +Zero-Field splitting spin-orbit ... NO +Zero-field splitting spin-spin ... NO +Hyperfine couplings ... NO ( 0 nuclei) +Quadrupole couplings ... NO ( 0 nuclei) +Contact density ... NO ( 0 nuclei) + +NMR properties: +Chemical shifts ... NO ( 0 nuclei) +Spin-rotation constants ... NO ( 0 nuclei) +Spin-spin couplings ... NO ( 0 nuclei, 0 pairs) + +Choice of magnetic origin ... GIAO +Position of magnetic origin ... 0.000000 0.000000 0.000000 + +Properties with geometric perturbations: +SCF Hessian ... NO +IR spectrum ... NO +VCD spectrum ... NO +X-ray spectroscopy properties: +SCF XES/XAS/RIXS spectra ... NO + + +------------- +DIPOLE MOMENT +------------- + +Method : SCF +Type of density : Electron Density +Multiplicity : 1 +Irrep : 0 +Energy : -153.6484093883511832 Eh +Relativity type : +Basis : AO + X Y Z +Electronic contribution: 1.992387502 -1.026597443 -0.000002350 +Nuclear contribution : -0.351217970 0.679282861 0.000008520 + ----------------------------------------- +Total Dipole Moment : 1.641169533 -0.347314582 0.000006170 + ----------------------------------------- +Magnitude (a.u.) : 1.677517468 +Magnitude (Debye) : 4.263910545 + + + +-------------------- +Rotational spectrum +-------------------- + +Rotational constants in cm-1: 1.814708 0.343633 0.304565 +Rotational constants in MHz : 54403.576504 10301.866783 9130.616101 + +Dipole components along the rotational axes: +x,y,z [a.u.] : 1.653522 0.282721 0.000007 +x,y,z [Debye]: 4.202918 0.718620 0.000017 + + + +Dipole moment calculation done in 0.0 sec + +Maximum memory used throughout the entire PROP-calculation: 5.2 MB + +-------------------------------- +SUGGESTED CITATIONS FOR THIS RUN +-------------------------------- + +Below you find a list of papers that are relevant to this ORCA run +We neither can nor want to force you to cite these papers, but we appreciate if you do +You receive ORCA, which is the product of decades of hard work by many enthusiastic individuals, for free +The only thing we kindly ask in return is that you cite our papers, +We deeply appreciate it, if you show your appreciation for ORCA by not just citing the generic ORCA reference. + +Please note that relegating all ORCA citations to the supporting information does *not* help us. +SI sections are not indexed - citations you put there will not count into any citation statistics +But we need these citations in order to attract the funding resources that allow us to do what we are doing + +Therefore, if you are a happy ORCA user, please consider citing a few of the papers listed below in the main body of your paper + +In addition to the list printed below, the program has created the file input.bibtex that contains the list in bibtex format +You can import this file easily into all common literature databanks and citation aid programs + + +List of essential papers. We consider these as the minimum necessary citations + + 1. Neese,F. + Software update: the ORCA program system, version 5.0 + WIRES Comput. Molec. Sci., 2022 12(1)e1606 + doi.org/10.1002/wcms.1606 + +List of papers to cite with high priority. The work reported in these papers was absolutely +necessary for this run to complete. +Our perspective: the developers of density functionals and basis sets usually get cited in chemistry papers +Good! But without the algorithms to do something with them, the functionals or basis sets would not do anything. +Hence, in our opinion, the algorithm design and method developments papers are equally worthy of getting cited + + 1. Neese,F. + An improvement of the resolution of the identity approximation for the formation of the Coulomb matrix + J. Comp. Chem., 2003 24(14)1740-1747 + doi.org/10.1002/jcc.10318 + 2. Neese,F.; Wennmohs,F.; Hansen,A.; Becker,U. + Efficient, approximate and parallel Hartree-Fock and hybrid DFT calculations. A 'chain-of-spheres' algorithm for the Hartree-Fock exchange + Chem. Phys., 2009 356(1-3)98-109 + doi.org/10.1016/j.chemphys.2008.10.036 + 3. Helmich-Paris,B.; de Souza,B.; Neese,F.; Izsák,R. + An improved chain of spheres for exchange algorithm + J. Chem. Phys., 2021 155 104109 + doi.org/doi: 10.1063/5.0058766. + 4. Neese,F. + The SHARK Integral Generation and Digestion System + J. Comp. Chem., 2022 1-16 + doi.org/10.1002/jcc.26942 + +List of suggested additional citations. These are papers that are important in the 'surrounding' of +of this run, or papers that preceded the highly important papers. If you like your results we are grateful for a citation. + + 1. Izsak,R.; Neese,F. + An overlap fitted chain of spheres exchange method + J. Chem. Phys., 2011 135 144105 + doi.org/10.1063/1.3646921 + 2. Izsak,R.; Hansen,A.; Neese,F. + The resolution of identity and chain of spheres approximations for the LPNO-CCSD singles Fock term + Molec. Phys., 2012 110 2413-2417 + doi.org/10.1080/00268976.2012.687466 + 3. Neese,F. + The ORCA program system + WIRES Comput. Molec. Sci., 2012 2(1)73-78 + doi.org/10.1002/wcms.81 + 4. Izsak,R.; Neese,F.; Klopper,W. + Robust fitting techniques in the chain of spheres approximation to the Fock exchange: The role of the complementary space + J. Chem. Phys., 2013 139 + doi.org/10.1063/1.4819264 + 5. Neese,F. + Software update: the ORCA program system, version 4.0 + WIRES Comput. Molec. Sci., 2018 8(1)1-6 + doi.org/10.1002/wcms.1327 + 6. Neese,F.; Wennmohs,F.; Becker,U.; Riplinger,C. + The ORCA quantum chemistry program package + J. Chem. Phys., 2020 152 Art. No. L224108 + doi.org/10.1063/5.0004608 + +List of optional additional citations + + 1. Neese,F. + Approximate second-order SCF convergence for spin unrestricted wavefunctions + Chem. Phys. Lett., 2000 325(1-3)93-98 + doi.org/10.1016/s0009-2614(00)00662-x + +Timings for individual modules: + +Sum of individual times ... 21.282 sec (= 0.355 min) +Startup calculation ... 3.953 sec (= 0.066 min) 18.6 % +SCF iterations ... 14.337 sec (= 0.239 min) 67.4 % +Property calculations ... 2.992 sec (= 0.050 min) 14.1 % + ****ORCA TERMINATED NORMALLY**** +TOTAL RUN TIME: 0 days 0 hours 0 minutes 24 seconds 488 msec diff --git a/arc/testing/stability/orca_stable_spin_contaminated_doublet_ts.out b/arc/testing/stability/orca_stable_spin_contaminated_doublet_ts.out new file mode 100644 index 0000000000..36081d5a33 --- /dev/null +++ b/arc/testing/stability/orca_stable_spin_contaminated_doublet_ts.out @@ -0,0 +1,1484 @@ + + ***************** + * O R C A * + ***************** + + #, + ### + #### + ##### + ###### + ########, + ,,################,,,,, + ,,#################################,, + ,,##########################################,, + ,#########################################, ''#####, + ,#############################################,, '####, + ,##################################################,,,,####, + ,###########'''' ''''############################### + ,#####'' ,,,,##########,,,, '''####''' '#### + ,##' ,,,,###########################,,, '## + ' ,,###'''' '''############,,, + ,,##'' '''############,,,, ,,,,,,###'' + ,#'' '''#######################''' + ' ''''####'''' + ,#######, #######, ,#######, ## + ,#' '#, ## ## ,#' '#, #''# ,####, ,####, + ## ## ## ,#' ## #' '# #' #' '# + ## ## ####### ## ,######, #####, # # + '#, ,#' ## ## '#, ,#' ,# #, #, # #, ,# + '#######' ## ## '#######' #' '# '####' # '####' + + + + ######################################################### + # -***- # + # Department of theory and spectroscopy # + # # + # Frank Neese # + # # + # Directorship, Architecture, Infrastructure # + # SHARK, DRIVERS # + # Core code/Algorithms in most modules # + # # + # Max Planck Institute fuer Kohlenforschung # + # Kaiser Wilhelm Platz 1 # + # D-45470 Muelheim/Ruhr # + # Germany # + # # + # All rights reserved # + # -***- # + ######################################################### + + + Program Version 6.0.0 - RELEASE - + + + With contributions from (in alphabetic order): + Daniel Aravena : Magnetic Suceptibility + Michael Atanasov : Ab Initio Ligand Field Theory (pilot matlab implementation) + Alexander A. Auer : GIAO ZORA, VPT2 properties, NMR spectrum + Ute Becker : All parallelization in ORCA, NUMFREQ, NUMCALC + Giovanni Bistoni : ED, misc. LED, open-shell LED, HFLD + Martin Brehm : Molecular dynamics + Dmytro Bykov : pre 5.0 version of the SCF Hessian + Marcos Casanova-Páez : Triplet and SCS-CIS(D). UHF-(DLPNO)-IP/EA/STEOM-CCSD. UHF-CVS-IP/STEOM-CCSD + Vijay G. Chilkuri : MRCI spin determinant printing, contributions to CSF-ICE + Pauline Colinet : FMM embedding + Dipayan Datta : RHF DLPNO-CCSD density + Achintya Kumar Dutta : EOM-CC, STEOM-CC + Nicolas Foglia : Exact transition moments, OPA infrastructure, MCD improvements + Dmitry Ganyushin : Spin-Orbit,Spin-Spin,Magnetic field MRCI + Miquel Garcia : C-PCM and meta-GGA Hessian, CCSD/C-PCM, Gaussian charge scheme + Tiago L. C. Gouveia : GS-ROHF, GS-ROCIS + Yang Guo : DLPNO-NEVPT2, F12-NEVPT2, CIM, IAO-localization + Andreas Hansen : Spin unrestricted coupled pair/coupled cluster methods + Ingolf Harden : AUTO-CI MPn and infrastructure + Benjamin Helmich-Paris : MC-RPA, TRAH-(SCF,CASSCF), AVAS, COSX integrals, SCF dyn. polar. + Lee Huntington : MR-EOM, pCC + Robert Izsak : Overlap fitted RIJCOSX, COSX-SCS-MP3, EOM + Riya Kayal : Wick's Theorem for AUTO-CI, AUTO-CI UHF-CCSDT + Emily Kempfer : AUTO-CI, RHF CISDT and CCSDT + Christian Kollmar : KDIIS, OOCD, Brueckner-CCSD(T), CCSD density, CASPT2, CASPT2-K, improved NEVPT2 + Axel Koslowski : Symmetry handling + Simone Kossmann : Meta GGA functionals, TD-DFT gradient, OOMP2, (MP2 Hessian; deprecated post 5.0) + Lucas Lang : DCDCAS + Marvin Lechner : AUTO-CI (C++ implementation), FIC-MRCC + Spencer Leger : CASSCF response + Dagmar Lenk : GEPOL surface, SMD, ORCA-2-JSON + Dimitrios Liakos : Extrapolation schemes; Compound Job, initial MDCI parallelization + Dimitrios Manganas : Further ROCIS development; embedding schemes. LFT, Crystal Embedding + Dimitrios Pantazis : SARC Basis sets + Anastasios Papadopoulos: AUTO-CI, single reference methods and gradients + Taras Petrenko : pre 6.0 DFT Hessian and TD-DFT gradient, (ASA, deprecated), ECA, 1-Electron XAS/XES, NRVS + Peter Pinski : DLPNO-MP2, DLPNO-MP2 Gradient + Christoph Reimann : Effective Core Potentials + Marius Retegan : Local ZFS, SOC + Christoph Riplinger : Optimizer, TS searches, QM/MM, DLPNO-CCSD(T), (RO)-DLPNO pert. Triples + Michael Roemelt : Original ROCIS implementation + Masaaki Saitow : Open-shell DLPNO-CCSD energy and density + Barbara Sandhoefer : DKH picture change effects + Kantharuban Sivalingam : CASSCF convergence/infrastructure, NEVPT2 and variants, FIC-MRCI + Bernardo de Souza : ESD, SOC TD-DFT + Georgi Stoychev : AutoAux, RI-MP2 NMR, DLPNO-MP2 response, X2C + Van Anh Tran : RI-MP2 g-tensors + Willem Van den Heuvel : Paramagnetic NMR + Zikuan Wang : NOTCH, Electric field optimization + Frank Wennmohs : Technical directorship and infrastructure + Hang Xu : AUTO-CI-Response properties + + + We gratefully acknowledge several colleagues who have allowed us to + interface, adapt or use parts of their codes: + Stefan Grimme, W. Hujo, H. Kruse, P. Pracht, : VdW corrections, initial TS optimization, + C. Bannwarth, S. Ehlert, DFT functionals, gCP, sTDA/sTD-DF + L. Wittmann, M. Mueller + Ed Valeev, F. Pavosevic, A. Kumar : LibInt (2-el integral package), F12 methods + Garnet Chan, S. Sharma, J. Yang, R. Olivares : DMRG + Ulf Ekstrom : XCFun DFT Library + Mihaly Kallay : mrcc (arbitrary order and MRCC methods) + Frank Weinhold : gennbo (NPA and NBO analysis) + Simon Mueller : openCOSMO-RS + Christopher J. Cramer and Donald G. Truhlar : smd solvation model + Lars Goerigk : TD-DFT with DH, B97 family of functionals + V. Asgeirsson, H. Jonsson : NEB implementation + FAccTs GmbH : IRC, NEB, NEB-TS, DLPNO-Multilevel, CI-OPT + MM, QMMM, 2- and 3-layer-ONIOM, Crystal-QMMM, + LR-CPCM, SF, NACMEs, symmetry and pop. for TD-DFT, + nearIR, NL-DFT gradient (VV10), updates on ESD, + ML-optimized integration grids, MBIS, APM, + GOAT, DOCKER, SOLVATOR, interface openCOSMO-RS + S Lehtola, MJT Oliveira, MAL Marques : LibXC Library + Liviu Ungur et al : ANISO software + + + Your calculation uses the libint2 library for the computation of 2-el integrals + For citations please refer to: http://libint.valeyev.net + + Your ORCA version has been built with support for libXC version: 6.2.2 + For citations please refer to: https://libxc.gitlab.io + + This ORCA versions uses: + CBLAS interface : Fast vector & matrix operations + LAPACKE interface : Fast linear algebra routines + SCALAPACK package : Parallel linear algebra routines + Shared memory : Shared parallel matrices + BLAS/LAPACK : OpenBLAS 0.3.27 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Cooperlake SINGLE_THREADED + Core in use : Cooperlake + Copyright (c) 2011-2014, The OpenBLAS Project + + +NOTE: MaxCore=3500 MB was set to SCF,MP2,MDCI,CIPSI,MRCI and CIS + => If you want to overwrite this, your respective input block should be placed after the MaxCore statement +Warning: RI is on but no J-basis has been assigned. Assigning Def2/J (nothing to worry about!) +================================================================================ + +----- Orbital basis set information ----- +Your calculation utilizes the basis: def2-TZVP + F. Weigend and R. Ahlrichs, Phys. Chem. Chem. Phys. 7, 3297 (2005). + +----- AuxJ basis set information ----- +Your calculation utilizes the auxiliary basis: def2/J + F. Weigend, Phys. Chem. Chem. Phys. 8, 1057 (2006). + +================================================================================ + WARNINGS + Please study these warnings very carefully! +================================================================================ + + +================================================================================ + INPUT FILE +================================================================================ +NAME = input.in +| 1> !UKS B3LYP def2-TZVP TightSCF defgrid3 +| 2> %maxcore 3500 +| 3> %pal nprocs 8 end +| 4> +| 5> * xyz 0 2 +| 6> O -1.99995 0.00000 0.00000 +| 7> C 1.77716 0.00000 0.00000 +| 8> H 2.31932 -0.93318 -0.00002 +| 9> H 2.31917 0.93326 -0.00002 +| 10> H 0.69808 -0.00009 0.00004 +| 11> * +| 12> +| 13> %scf +| 14> MaxIter 999 +| 15> STABPerform true +| 16> STABRestartUHFifUnstable false +| 17> STABNRoots 6 +| 18> end +| 19> +| 20> ****END OF INPUT**** +================================================================================ + + **************************** + * Single Point Calculation * + **************************** + +--------------------------------- +CARTESIAN COORDINATES (ANGSTROEM) +--------------------------------- + O -1.999950 0.000000 0.000000 + C 1.777160 0.000000 0.000000 + H 2.319320 -0.933180 -0.000020 + H 2.319170 0.933260 -0.000020 + H 0.698080 -0.000090 0.000040 + +---------------------------- +CARTESIAN COORDINATES (A.U.) +---------------------------- + NO LB ZA FRAG MASS X Y Z + 0 O 8.0000 0 15.999 -3.779358 0.000000 0.000000 + 1 C 6.0000 0 12.011 3.358346 0.000000 0.000000 + 2 H 1.0000 0 1.008 4.382880 -1.763455 -0.000038 + 3 H 1.0000 0 1.008 4.382596 1.763606 -0.000038 + 4 H 1.0000 0 1.008 1.319180 -0.000170 0.000076 + +-------------------------------- +INTERNAL COORDINATES (ANGSTROEM) +-------------------------------- + O 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 3.777110000000 0.00000000 0.00000000 + H 2 1 0 1.079241575552 120.15578078 0.00000000 + H 2 1 3 1.079235409028 120.14676157 179.99754417 + H 2 1 4 1.079080004495 0.00522944 156.03873889 + +--------------------------- +INTERNAL COORDINATES (A.U.) +--------------------------- + O 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 7.137703477695 0.00000000 0.00000000 + H 2 1 0 2.039471010135 120.15578078 0.00000000 + H 2 1 3 2.039459357094 120.14676157 179.99754417 + H 2 1 4 2.039165685085 0.00522944 156.03873889 + +--------------------- +BASIS SET INFORMATION +--------------------- +There are 3 groups of distinct atoms + + Group 1 Type O : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 2 Type C : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 3 Type H : 5s1p contracted to 3s1p pattern {311/1} + +Atom 0O basis set group => 1 +Atom 1C basis set group => 2 +Atom 2H basis set group => 3 +Atom 3H basis set group => 3 +Atom 4H basis set group => 3 +--------------------------------- +AUXILIARY/J BASIS SET INFORMATION +--------------------------------- +There are 3 groups of distinct atoms + + Group 1 Type O : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 2 Type C : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 3 Type H : 5s2p1d contracted to 3s1p1d pattern {311/2/1} + +Atom 0O basis set group => 1 +Atom 1C basis set group => 2 +Atom 2H basis set group => 3 +Atom 3H basis set group => 3 +Atom 4H basis set group => 3 + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------ + ORCA STARTUP CALCULATIONS + -- RI-GTO INTEGRALS CHOSEN -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + ___ + / \ - P O W E R E D B Y - + / \ + | | | _ _ __ _____ __ __ + | | | | | | | / \ | _ \ | | / | + \ \/ | | | | / \ | | | | | | / / + / \ \ | |__| | / /\ \ | |_| | | |/ / + | | | | __ | / /__\ \ | / | \ + | | | | | | | | __ | | \ | |\ \ + \ / | | | | | | | | | |\ \ | | \ \ + \___/ |_| |_| |__| |__| |_| \__\ |__| \__/ + + - O R C A' S B I G F R I E N D - + & + - I N T E G R A L F E E D E R - + + v1 FN, 2020, v2 2021, v3 2022-2024 +------------------------------------------------------------------------------ + + +---------------------- +SHARK INTEGRAL PACKAGE +---------------------- + +Number of atoms ... 5 +Number of basis functions ... 80 +Number of shells ... 34 +Maximum angular momentum ... 3 +Integral batch strategy ... SHARK/LIBINT Hybrid +RI-J (if used) integral strategy ... SPLIT-RIJ (Revised 2003 algorithm where possible) +Printlevel ... 1 +Contraction scheme used ... SEGMENTED contraction +Prescreening option ... SCHWARTZ + Thresh ... 2.500e-11 + Tcut ... 2.500e-12 + Tpresel ... 2.500e-12 +Coulomb Range Separation ... NOT USED +Exchange Range Separation ... NOT USED +Multipole approximations ... NOT USED +Finite Nucleus Model ... NOT USED +CABS basis ... NOT available +Auxiliary Coulomb fitting basis ... AVAILABLE + # of basis functions in Aux-J ... 131 + # of shells in Aux-J ... 45 + Maximum angular momentum in Aux-J ... 4 +Auxiliary J/K fitting basis ... NOT available +Auxiliary Correlation fitting basis ... NOT available +Auxiliary 'external' fitting basis ... NOT available + +Checking pre-screening integrals ... done ( 0.0 sec) Dimension = 34 +Check shell pair data ... done ( 0.0 sec) +Shell pair information +Shell pair cut-off parameter TPreSel ... 2.5e-12 +Total number of shell pairs ... 595 +Shell pairs after pre-screening ... 547 +Total number of primitive shell pairs ... 1764 +Primitive shell pairs kept ... 1349 + la=0 lb=0: 175 shell pairs + la=1 lb=0: 159 shell pairs + la=1 lb=1: 43 shell pairs + la=2 lb=0: 69 shell pairs + la=2 lb=1: 33 shell pairs + la=2 lb=2: 9 shell pairs + la=3 lb=0: 32 shell pairs + la=3 lb=1: 16 shell pairs + la=3 lb=2: 8 shell pairs + la=3 lb=3: 3 shell pairs + +Calculating one electron integrals ... done ( 0.0 sec) +Calculating RI/J V-Matrix + Cholesky decomp.... done ( 0.0 sec) +Calculating Nuclear repulsion ... done ( 0.0 sec) ENN= 19.885582635568 Eh + +Diagonalization of the overlap matrix: +Smallest eigenvalue ... 2.927e-03 +Time for diagonalization ... 0.001 sec +Threshold for overlap eigenvalues ... 1.000e-07 +Number of eigenvalues below threshold ... 0 +Time for construction of square roots ... 0.001 sec +Total time needed ... 0.003 sec + +------------------- +DFT GRID GENERATION +------------------- + +General Integration Accuracy IntAcc ... 4.959 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 6 (Lebedev-590) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... off +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 56325 +Total number of batches ... 882 +Average number of points per batch ... 63 +Average number of grid points per atom ... 11265 + +-------------------- +COSX GRID GENERATION +-------------------- + +GRIDX 1 +------- +General Integration Accuracy IntAcc ... 4.020 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 2 (Lebedev-110) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 6167 +Total number of batches ... 50 +Average number of points per batch ... 123 +Average number of grid points per atom ... 1233 +UseSFitting ... on + +GRIDX 2 +------- +General Integration Accuracy IntAcc ... 4.338 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 3 (Lebedev-194) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 13621 +Total number of batches ... 109 +Average number of points per batch ... 124 +Average number of grid points per atom ... 2724 +UseSFitting ... on + +GRIDX 3 +------- +General Integration Accuracy IntAcc ... 4.871 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 4 (Lebedev-302) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 27051 +Total number of batches ... 215 +Average number of points per batch ... 125 +Average number of grid points per atom ... 5410 +UseSFitting ... on +Initializing property integral containers ... done ( 0.0 sec) + +SHARK setup successfully completed in 1.7 seconds + +Maximum memory used throughout the entire STARTUP-calculation: 15.0 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------- + ORCA GUESS + Start orbitals & Density for SCF / CASSCF +------------------------------------------------------------------------------- + +------------ +SCF SETTINGS +------------ +Hamiltonian: + Density Functional Method .... DFT(GTOs) + Exchange Functional Exchange .... B88 + X-Alpha parameter XAlpha .... 0.666667 + Becke's b parameter XBeta .... 0.004200 + Correlation Functional Correlation .... LYP + LDA part of GGA corr. LDAOpt .... VWN-5 + Gradients option PostSCFGGA .... off + Hybrid DFT is turned on + Fraction HF Exchange ScalHFX .... 0.200000 + Scaling of DF-GGA-X ScalDFX .... 0.720000 + Scaling of DF-GGA-C ScalDFC .... 0.810000 + Scaling of DF-LDA-C ScalLDAC .... 1.000000 + Perturbative correction .... 0.000000 + NL short-range parameter .... 4.800000 + RI-approximation to the Coulomb term is turned on + Number of AuxJ basis functions .... 131 + RIJ-COSX (HFX calculated with COS-X)).... on + + +General Settings: + Integral files IntName .... input + Hartree-Fock type HFTyp .... UHF + Total Charge Charge .... 0 + Multiplicity Mult .... 2 + Number of Electrons NEL .... 17 + Basis Dimension Dim .... 80 + Nuclear Repulsion ENuc .... 19.8855826356 Eh + +Convergence Acceleration: + AO-DIIS CNVDIIS .... on + Start iteration DIISMaxIt .... 12 + Startup error DIISStart .... 0.200000 + # of expansion vecs DIISMaxEq .... 5 + Bias factor DIISBfac .... 1.050 + Max. coefficient DIISMaxC .... 10.000 + MO-DIIS CNVKDIIS .... off + Trust-Rad. Augm. Hess. CNVTRAH .... auto + Auto Start mean grad. ratio tolernc. .... 1.125000 + Auto Start start iteration .... 50 + Auto Start num. interpolation iter. .... 10 + Max. Number of Micro iterations .... 24 + Max. Number of Macro iterations .... Maxiter - #DIIS iter + Number of Davidson start vectors .... 2 + Converg. threshold (grad. norm) .... 1.000e-05 + Grad. Scal. Fac. for Micro threshold .... 0.100 + Minimum threshold for Micro iter. .... 1.000e-02 + NR start threshold (gradient norm) .... 1.000e-04 + Initial trust radius .... 0.400 + Minimum AH scaling param. (alpha) .... 1.000 + Maximum AH scaling param. (alpha) .... 1000.000 + Quad. conv. algorithm .... NR + White noise on init. David. guess .... on + Maximum white noise .... 0.010 + Pseudo random numbers .... off + Inactive MOs .... canonical + Orbital update algorithm .... Taylor + Preconditioner .... Diag + Full preconditioner red. dimension .... 250 + SOSCF CNVSOSCF .... on + Start iteration SOSCFMaxIt .... 150 + Startup grad/error SOSCFStart .... 0.003300 + Hessian update SOSCFHessUp .... L-BFGS + Level Shifting CNVShift .... on + Level shift para. LevelShift .... 0.2500 + Turn off err/grad. ShiftErr .... 0.0010 + Zerner damping CNVZerner .... off + Static damping CNVDamp .... on + Fraction old density DampFac .... 0.7000 + Max. Damping (<1) DampMax .... 0.9800 + Min. Damping (>=0) DampMin .... 0.0000 + Turn off err/grad. DampErr .... 0.1000 + +SCF Procedure: + Maximum # iterations MaxIter .... 999 + SCF integral mode SCFMode .... Direct + Integral package .... SHARK and LIBINT hybrid scheme + Reset frequency DirectResetFreq .... 20 + Integral Threshold Thresh .... 2.500e-11 Eh + Primitive CutOff TCut .... 2.500e-12 Eh + +Convergence Tolerance: + Convergence Check Mode ConvCheckMode .... Total+1el-Energy + Convergence forced ConvForced .... 0 + Energy Change TolE .... 1.000e-08 Eh + 1-El. energy change .... 1.000e-05 Eh + Orbital Gradient TolG .... 1.000e-05 + Orbital Rotation angle TolX .... 1.000e-05 + DIIS Error TolErr .... 5.000e-07 + +------------------------------ +INITIAL GUESS: MODEL POTENTIAL +------------------------------ +Loading Hartree-Fock densities ... done +Calculating cut-offs ... done +Initializing the effective Hamiltonian ... done +Setting up the integral package (SHARK) ... done +Starting the Coulomb interaction ... done ( 0.0 sec) +Making the grid ... done ( 0.0 sec) +Mapping shells ... done +Starting the XC term evaluation ... done ( 0.0 sec) + promolecular density results + # of electrons = 16.998715748 + EX = -14.034545920 + EC = -0.536580986 + EX+EC = -14.571126906 +Transforming the Hamiltonian ... done ( 0.0 sec) +Diagonalizing the Hamiltonian ... done ( 0.0 sec) +Back transforming the eigenvectors ... done ( 0.0 sec) +Now organizing SCF variables ... done + ------------------ + INITIAL GUESS DONE ( 0.1 sec) + ------------------ + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** +Finished Guess after 1.1 sec +Maximum memory used throughout the entire GUESS-calculation: 7.3 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------------------- + ORCA LEAN-SCF + memory conserving SCF solver +------------------------------------------------------------------------------------------- + +----------------------------------------D-I-I-S-------------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP DIISErr Damp Time(sec) +------------------------------------------------------------------------------------------- + *** Starting incremental Fock matrix formation *** + 1 -114.6054673453213155 0.00e+00 5.82e-03 1.37e-01 1.91e-01 0.700 0.4 +Warning: op=0 Small HOMO/LUMO gap ( -0.125) - skipping pre-diagonalization + Will do a full diagonalization + 2 -114.7483489518391622 -1.43e-01 2.34e-03 5.57e-02 5.39e-02 0.700 0.3 + ***Turning on AO-DIIS*** + 3 -114.6780190880943877 7.03e-02 1.70e-03 3.90e-02 1.05e-01 0.700 0.3 + 4 -114.5647640141256289 1.13e-01 1.27e-03 2.73e-02 1.51e-01 0.700 0.3 + 5 -114.4571036462389060 1.08e-01 9.29e-04 1.91e-02 1.80e-01 0.700 0.3 + 6 -114.3682704677295163 8.88e-02 6.01e-04 1.34e-02 2.03e-01 0.700 0.3 + 7 -114.2770479104012367 9.12e-02 4.40e-04 9.36e-03 2.35e-01 0.700 0.3 + 8 -114.2072210490607205 6.98e-02 3.60e-04 7.14e-03 2.57e-01 0.700 0.3 + 9 -114.1792049620001279 2.80e-02 7.36e-04 1.43e-02 2.59e-01 0.700 0.3 + 10 -114.1908484725376667 -1.16e-02 3.13e-03 8.35e-02 2.40e-01 0.700 0.8 + 11 -114.6463432911657065 -4.55e-01 2.17e-03 5.43e-02 8.33e-02 0.700 0.3 + 12 -114.7683196062546216 -1.22e-01 4.93e-03 1.16e-01 2.75e-02 0.000 0.3 + 13 -114.5250126470475465 2.43e-01 1.19e-04 2.07e-03 2.10e-01 0.000 0.3 + 14 -114.5318230399872874 -6.81e-03 1.08e-05 1.57e-04 2.08e-01 0.700 0.3 + 15 -114.5313884804564992 4.35e-04 1.68e-05 2.35e-04 2.08e-01 0.700 0.5 + 16 -114.5305822538142735 8.06e-04 1.51e-05 2.24e-04 2.09e-01 0.700 0.3 + 17 -114.5302346023874094 3.48e-04 1.37e-02 3.99e-01 2.09e-01 0.700 0.3 + 18 -114.6666398058531939 -1.36e-01 3.41e-03 7.45e-02 4.48e-02 0.700 0.3 + 19 -114.5208149492192575 1.46e-01 9.62e-03 2.29e-01 1.31e-01 0.000 0.3 + 20 -113.9383800586998206 5.82e-01 1.32e-03 4.26e-02 2.88e-01 0.700 0.3 + *** Restarting incremental Fock matrix formation *** + ****Resetting DIIS**** +Warning: op=0 Small HOMO/LUMO gap ( -1.216) - skipping pre-diagonalization + LevelShift set to 1.000 Eh + Will do a full diagonalization + 21 -113.9637128837939173 -2.53e-02 4.44e-03 1.16e-01 2.83e-01 0.700 0.8 + 22 -114.5526653995031978 -5.89e-01 2.89e-03 5.84e-02 4.18e-02 0.700 0.3 + 23 -114.6802732096298172 -1.28e-01 6.55e-03 1.09e-01 8.05e-02 0.000 0.3 + 24 -114.3240556677245792 3.56e-01 6.58e-04 1.13e-02 2.59e-01 0.000 0.5 + 25 -114.3910125061487832 -6.70e-02 1.01e-04 1.98e-03 2.36e-01 0.700 0.7 + 26 -114.3996902990032964 -8.68e-03 1.22e-04 2.45e-03 2.34e-01 0.700 0.7 + 27 -114.4095860758802559 -9.90e-03 1.13e-04 2.28e-03 2.30e-01 0.700 0.4 + 28 -114.4182340493085377 -8.65e-03 1.40e-03 2.48e-02 2.27e-01 0.700 0.3 + 29 -114.5255709401239272 -1.07e-01 1.44e-03 2.44e-02 1.66e-01 0.700 0.3 + 30 -114.5984862574755851 -7.29e-02 1.35e-03 2.45e-02 1.22e-01 0.700 0.3 + 31 -114.6452686199794329 -4.68e-02 1.27e-03 2.60e-02 9.08e-02 0.700 0.3 + 32 -114.6756075243956872 -3.03e-02 3.97e-03 8.49e-02 6.64e-02 0.000 0.3 + 33 -114.7329153750839197 -5.73e-02 1.02e-03 3.67e-02 1.02e-02 0.000 0.3 + 34 -114.7343365685334362 -1.42e-03 8.84e-04 3.37e-02 9.01e-03 0.000 0.3 + 35 -114.7354338262200173 -1.10e-03 7.42e-04 2.94e-02 8.80e-03 0.000 0.3 + 36 -114.7363547353011910 -9.21e-04 6.35e-04 2.55e-02 1.06e-02 0.000 0.3 + 37 -114.7372209454803595 -8.66e-04 5.59e-04 2.22e-02 1.26e-02 0.000 0.3 + 38 -114.7381168498280744 -8.96e-04 5.04e-04 1.93e-02 1.48e-02 0.000 0.3 + 39 -114.7391137257925635 -9.97e-04 4.72e-04 1.72e-02 1.73e-02 0.000 0.3 + 40 -114.7402859250098999 -1.17e-03 4.52e-04 1.56e-02 1.98e-02 0.000 0.3 + *** Restarting incremental Fock matrix formation *** + ****Resetting DIIS**** +Warning: op=0 Small HOMO/LUMO gap ( -0.186) - skipping pre-diagonalization + LevelShift set to 0.286 Eh + Will do a full diagonalization + 41 -114.7417179722865370 -1.43e-03 2.41e-03 6.03e-02 2.24e-02 0.000 0.3 + 42 -114.7663916451074471 -2.47e-02 1.91e-03 5.98e-02 2.98e-02 0.000 0.3 + 43 -114.7510400195740345 1.54e-02 1.93e-03 5.56e-02 8.50e-02 0.000 0.3 + 44 -114.6910909728511143 5.99e-02 3.21e-03 5.89e-02 1.35e-01 0.000 0.3 + 45 -114.5249375737090105 1.66e-01 1.26e-03 2.77e-02 1.98e-01 0.700 0.3 + 46 -114.4156917180894908 1.09e-01 1.53e-03 4.15e-02 2.28e-01 0.700 0.3 + 47 -114.3155555482442622 1.00e-01 1.67e-03 5.11e-02 2.50e-01 0.700 0.3 + 48 -114.2509250890248467 6.46e-02 1.91e-03 5.74e-02 2.59e-01 0.700 0.3 + 49 -114.3492137442195968 -9.83e-02 1.93e-03 4.75e-02 2.24e-01 0.700 0.3 + 50 -114.5049436586030396 -1.56e-01 2.32e-03 4.16e-02 1.75e-01 0.700 0.3 + + ****************************************************************************** + *** *** + *** Auto-TRAH *** + *** --------- *** + *** the maximum gradient error decreased on average only by a factor 0.9 *** + *** during the last 10 iterations *** + *** *** + *** Leaving SCF to start the TRAH-SCF procedure *** + *** *** + ****************************************************************************** + + -------------------------------------------------------------------------------------------- + Iter. energy ||Error||_2 Shift TRadius Mac/Mic Rej. + -------------------------------------------------------------------------------------------- + 0 -114.737186606545 3.251220e-01 0.400 (TRAH MAcro) No +WARNING: 5 diagonal Hessian elements are negative! +WARNING : negative HOMO - LUMO gap : (op = alpha) -0.210043 +WARNING : negative HOMO - LUMO gap : (op = beta) -0.260596 +WARNING : negative HOMO - LUMO gap : (op = alpha) -0.210043 +WARNING : negative HOMO - LUMO gap : (op = beta) -0.260596 + 0 dE -7.015251e-02 3.084325e-01 -6.4799e-02 0.287 (TRAH MIcro) + 0 dE -8.827189e-02 1.211719e-01 -2.3174e-01 0.353 (TRAH MIcro) + 0 dE -6.398179e-02 3.402241e-02 -4.2039e-01 0.193 (TRAH MIcro) + 0 dE -6.332434e-02 4.768046e-03 -4.2348e-01 0.186 (TRAH MIcro) + 1 -114.797028654616 5.398304e-02 0.480 (TRAH MAcro) No +WARNING: 4 diagonal Hessian elements are negative! +WARNING : negative HOMO - LUMO gap : (op = alpha) -0.032579 +WARNING : negative HOMO - LUMO gap : (op = beta) -0.022196 +WARNING : negative HOMO - LUMO gap : (op = alpha) -0.032579 +WARNING : negative HOMO - LUMO gap : (op = beta) -0.022196 + 1 dE -3.741055e-03 5.859226e-02 -3.7106e-03 0.091 (TRAH MIcro) + 1 dE -6.164213e-03 1.063824e-01 -5.9279e-03 0.200 (TRAH MIcro) + 1 dE -1.010841e-02 6.234630e-02 -1.1003e-01 0.224 (TRAH MIcro) + 1 dE -2.799473e-02 2.730695e-02 -1.3733e-01 0.403 (TRAH MIcro) + 1 dE -3.126818e-02 1.229725e-02 -1.4005e-01 0.426 (TRAH MIcro) + 1 dE -3.625685e-02 1.166535e-02 -1.4137e-01 0.464 (TRAH MIcro) + 1 dE -3.857871e-02 4.069418e-03 -1.4186e-01 0.480 (TRAH MIcro) + 2 -114.826813489980 6.183459e-02 0.576 (TRAH MAcro) No + 2 dE -4.739117e-02 2.397422e-01 -6.9014e-02 0.576 (TRAH MIcro) + 2 dE -5.588945e-02 6.662834e-02 -8.9008e-02 0.576 (TRAH MIcro) + 2 dE -5.683551e-02 1.974979e-02 -9.9224e-02 0.563 (TRAH MIcro) + 2 dE -5.713988e-02 9.590476e-03 -9.9774e-02 0.563 (TRAH MIcro) + 2 dE -5.723996e-02 5.353428e-03 -9.9904e-02 0.563 (TRAH MIcro) + 3 -114.865924436824 3.316399e-02 0.576 (TRAH MAcro) No + 3 dE -1.409929e-03 4.800134e-02 -1.3937e-03 0.108 (TRAH MIcro) + 3 dE -2.114129e-03 1.078924e-02 -2.0789e-03 0.130 (TRAH MIcro) + 3 dE -2.179834e-03 2.593001e-03 -2.1404e-03 0.136 (TRAH MIcro) + 4 -114.868178063919 5.348352e-03 0.691 (TRAH MAcro) No + 4 dE -7.406805e-05 5.888539e-03 -7.4028e-05 0.023 (TRAH MIcro) + 4 dE -1.004981e-04 2.127713e-03 -1.0036e-04 0.037 (TRAH MIcro) + 4 dE -1.033001e-04 6.151124e-04 -1.0313e-04 0.040 (TRAH MIcro) + 4 dE -1.040210e-04 7.933639e-04 -1.0385e-04 0.040 (TRAH MIcro) + 4 dE -1.088803e-04 2.627993e-03 -1.0864e-04 0.047 (TRAH MIcro) + 4 dE -1.834219e-04 1.026750e-02 -1.6920e-04 0.290 (TRAH MIcro) + 4 dE -5.104821e-04 5.959664e-03 -5.2368e-04 0.691 (TRAH MIcro) + 4 dE -5.233848e-04 1.385865e-03 -5.7092e-04 0.682 (TRAH MIcro) + 4 dE -5.262237e-04 4.301393e-04 -5.7209e-04 0.684 (TRAH MIcro) + --------------------------------- + TRAH Step control + --------------------------------- + predicted energy change = -5.262236872670e-04 + actual energy change = 9.700130929389e-04 + energy change ratio = -1.843347 + old trust radius = 0.691200 + new trust radius = 0.463104 + reject step? = YES + 5 -114.867208050826 5.348352e-03 0.463 (TRAH MAcro) Yes + 6 -114.867208050826 6.664059e-02 0.463 (TRAH MAcro) No + 6 dE -1.137266e-03 2.141266e-02 -1.1354e-03 0.041 (TRAH MIcro) + 6 dE -1.266518e-03 3.560407e-03 -1.2649e-03 0.036 (TRAH MIcro) + 7 -114.868476034200 3.573556e-03 0.556 (TRAH MAcro) No + 7 dE -9.879632e-06 1.440089e-03 -9.8791e-06 0.008 (TRAH MIcro) + 7 dE -1.093560e-05 9.452386e-04 -1.0935e-05 0.009 (TRAH MIcro) + 7 dE -1.179401e-05 1.190118e-03 -1.1792e-05 0.011 (TRAH MIcro) + 7 dE -1.365387e-05 2.615930e-03 -1.3650e-05 0.017 (TRAH MIcro) + 7 dE -3.958232e-05 4.026009e-03 -3.8898e-05 0.133 (TRAH MIcro) + 7 dE -5.242028e-05 1.463889e-03 -5.0629e-05 0.188 (TRAH MIcro) + 7 dE -5.452314e-05 6.746960e-04 -5.2489e-05 0.197 (TRAH MIcro) + 7 dE -5.508728e-05 5.747607e-04 -5.2993e-05 0.199 (TRAH MIcro) + 7 dE -5.774435e-05 2.244858e-03 -5.5350e-05 0.208 (TRAH MIcro) + 7 dE -8.654108e-05 5.622357e-03 -7.7579e-05 0.340 (TRAH MIcro) + 7 dE -1.245421e-04 2.097669e-03 -9.9323e-05 0.504 (TRAH MIcro) + 7 dE -1.275607e-04 4.813858e-04 -1.0079e-04 0.515 (TRAH MIcro) + 7 dE -1.277484e-04 1.503070e-04 -1.0088e-04 0.516 (TRAH MIcro) + --------------------------------- + TRAH Step control + --------------------------------- + predicted energy change = -1.277484338086e-04 + actual energy change = 3.611613828838e-04 + energy change ratio = -2.827130 + old trust radius = 0.555725 + new trust radius = 0.372336 + reject step? = YES + 8 -114.868114872818 3.573556e-03 0.372 (TRAH MAcro) Yes + 9 -114.868114872818 3.879058e-02 0.372 (TRAH MAcro) No + 9 dE -4.036235e-04 1.164940e-02 -4.0341e-04 0.023 (TRAH MIcro) + 9 dE -4.407807e-04 2.388817e-03 -4.4057e-04 0.022 (TRAH MIcro) + 10 -114.868556304189 2.389529e-03 0.447 (TRAH MAcro) No + 10 dE -4.216402e-06 1.308495e-03 -4.2163e-06 0.006 (TRAH MIcro) + 10 dE -4.946037e-06 8.728835e-04 -4.9459e-06 0.006 (TRAH MIcro) + 10 dE -6.018856e-06 1.234161e-03 -6.0183e-06 0.010 (TRAH MIcro) + 10 dE -9.254208e-06 3.195344e-03 -9.2488e-06 0.024 (TRAH MIcro) + 10 dE -3.770774e-05 3.212627e-03 -3.6687e-05 0.167 (TRAH MIcro) + 10 dE -4.344242e-05 8.812963e-04 -4.1865e-05 0.194 (TRAH MIcro) + 10 dE -4.419567e-05 4.765968e-04 -4.2534e-05 0.198 (TRAH MIcro) + 10 dE -4.460932e-05 5.343164e-04 -4.2903e-05 0.199 (TRAH MIcro) + 10 dE -4.829753e-05 2.744214e-03 -4.6116e-05 0.218 (TRAH MIcro) + 10 dE -6.429306e-05 2.384171e-03 -5.8395e-05 0.318 (TRAH MIcro) + 10 dE -6.776389e-05 6.582638e-04 -6.0733e-05 0.340 (TRAH MIcro) + 10 dE -6.797068e-05 8.912555e-05 -6.0870e-05 0.342 (TRAH MIcro) + --------------------------------- + TRAH Step control + --------------------------------- + predicted energy change = -6.797067926901e-05 + actual energy change = 6.805058302461e-05 + energy change ratio = -1.001176 + old trust radius = 0.446803 + new trust radius = 0.299358 + reject step? = YES + 11 -114.868488253606 2.389529e-03 0.299 (TRAH MAcro) Yes + 12 -114.868488253606 1.748144e-02 0.299 (TRAH MAcro) No + 12 dE -1.121662e-04 2.370170e-03 -1.1215e-04 0.013 (TRAH MIcro) + 12 dE -1.148689e-04 1.309312e-03 -1.1484e-04 0.015 (TRAH MIcro) + 13 -114.868603215536 1.305303e-03 0.359 (TRAH MAcro) No + 13 dE -5.037437e-07 7.866988e-04 -5.0374e-07 0.001 (TRAH MIcro) + 13 dE -1.026132e-06 9.900201e-04 -1.0261e-06 0.003 (TRAH MIcro) + 13 dE -1.773371e-06 1.252597e-03 -1.7733e-06 0.007 (TRAH MIcro) + 13 dE -6.696718e-06 4.349455e-03 -6.6845e-06 0.043 (TRAH MIcro) + 13 dE -1.708790e-05 3.053989e-03 -1.6854e-05 0.118 (TRAH MIcro) + 13 dE -1.978196e-05 4.282970e-04 -1.9419e-05 0.137 (TRAH MIcro) + 13 dE -1.983872e-05 1.513401e-04 -1.9472e-05 0.137 (TRAH MIcro) + 13 dE -2.002681e-05 6.606376e-04 -1.9652e-05 0.138 (TRAH MIcro) + 13 dE -2.241605e-05 2.154169e-03 -2.1871e-05 0.158 (TRAH MIcro) + 13 dE -3.292465e-05 2.651974e-03 -3.0137e-05 0.304 (TRAH MIcro) + 13 dE -3.793296e-05 8.394490e-04 -4.1695e-05 0.359 (TRAH MIcro) + 13 dE -3.819966e-05 1.976302e-04 -4.4154e-05 0.359 (TRAH MIcro) + 13 dE -3.822881e-05 1.233342e-04 -4.4411e-05 0.359 (TRAH MIcro) + --------------------------------- + TRAH Step control + --------------------------------- + predicted energy change = -3.822881055134e-05 + actual energy change = 7.334237866985e-05 + energy change ratio = -1.918511 + old trust radius = 0.359229 + new trust radius = 0.240684 + reject step? = YES + 14 -114.868529873157 1.305303e-03 0.241 (TRAH MAcro) Yes + 15 -114.868529873157 1.935357e-02 0.241 (TRAH MAcro) No + 15 dE -9.268215e-05 5.755355e-03 -9.2673e-05 0.010 (TRAH MIcro) + 15 dE -1.013085e-04 9.874142e-04 -1.0130e-04 0.009 (TRAH MIcro) + 16 -114.868631224600 9.886497e-04 0.289 (TRAH MAcro) No + 16 dE -6.665520e-07 4.458537e-04 -6.6655e-07 0.002 (TRAH MIcro) + 16 dE -7.333861e-07 2.607381e-04 -7.3338e-07 0.003 (TRAH MIcro) + 16 dE -7.539635e-07 8.982302e-05 -7.5396e-07 0.003 (TRAH MIcro) + 17 -114.868631977673 9.076635e-05 (NR MAcro) + 17 dE -6.528763e-09 6.259490e-05 (NR MIcro) + 17 dE -2.252934e-08 1.731688e-04 (NR MIcro) + 17 dE -1.722416e-07 7.223161e-04 (NR MIcro) + 17 dE -6.502718e-07 4.252907e-04 (NR MIcro) + 17 dE -7.748609e-07 2.346587e-04 (NR MIcro) + 17 dE -7.947682e-07 4.826326e-05 (NR MIcro) + 17 dE -7.986959e-07 6.657535e-05 (NR MIcro) + 17 dE -8.240080e-07 2.660889e-04 (NR MIcro) + 17 dE -1.006777e-06 4.190239e-04 (NR MIcro) + 17 dE -1.125684e-06 1.654465e-04 (NR MIcro) + 17 dE -1.139888e-06 5.581121e-05 (NR MIcro) + 17 dE -1.142744e-06 4.000794e-05 (NR MIcro) + 17 dE -1.156003e-06 2.247439e-04 (NR MIcro) + 17 dE -1.300224e-06 4.222278e-04 (NR MIcro) + 17 dE -1.424972e-06 2.107951e-04 (NR MIcro) + 17 dE -1.435114e-06 2.431945e-05 (NR MIcro) + 17 dE -1.435253e-06 3.401373e-06 (NR MIcro) + 17 dE -1.435258e-06 8.188931e-07 (NR MIcro) + 18 -114.868633299312 8.216576e-04 0.347 (TRAH MAcro) No + 18 dE -1.586185e-07 2.251835e-04 -1.5862e-07 0.000 (TRAH MIcro) + 18 dE -1.714594e-07 3.271718e-05 -1.7146e-07 0.000 (TRAH MIcro) + 19 -114.868633470899 3.272155e-05 (NR MAcro) + 19 dE -7.111169e-10 1.317107e-05 (NR MIcro) + 19 dE -7.912916e-10 9.456554e-06 (NR MIcro) + 19 dE -8.264917e-10 4.356998e-06 (NR MIcro) + 19 dE -8.549459e-10 7.036999e-06 (NR MIcro) + 19 dE -1.305113e-09 2.396785e-05 (NR MIcro) + 19 dE -2.386207e-09 2.214005e-05 (NR MIcro) + 19 dE -2.764447e-09 8.274219e-06 (NR MIcro) + 19 dE -2.804933e-09 2.381263e-06 (NR MIcro) + 19 dE -2.808296e-09 1.024880e-06 (NR MIcro) + 19 dE -2.812736e-09 2.966538e-06 (NR MIcro) + 19 dE -2.903465e-09 1.621697e-05 (NR MIcro) + 19 dE -3.285783e-09 1.012334e-05 (NR MIcro) + 19 dE -3.334836e-09 3.048067e-06 (NR MIcro) + 19 dE -3.339408e-09 8.025383e-07 (NR MIcro) + 20 -114.868633474299 1.215959e-06 (NR MAcro) + + ***************************************************** + * SUCCESS * + * SCF CONVERGED AFTER 178 CYCLES * + ***************************************************** + +Recomputing exchange energy using gridx3 ... done ( 0.380 sec) +Old exchange energy : -2.867873986 Eh +New exchange energy : -2.867873464 Eh +Exchange energy change after final integration : 0.000000522 Eh +Total energy after final integration : -114.868632952 Eh +Warning: op=0 Small HOMO/LUMO gap ( 0.035) - skipping pre-diagonalization + Will do a full diagonalization + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** + +------------------------------------------------------------------------------------------- + WAVEFUNCTION STABILITY ANALYSIS +------------------------------------------------------------------------------------------- + + + ****Iteration 0**** + Lowest Energy : 0.077046554962 + Maximum Energy change : 0.256666207420 (vector 5) + Maximum residual norm : 0.058777365437 + + ****Iteration 1**** + Lowest Energy : 0.065609958655 + Maximum Energy change : 0.032296267864 (vector 3) + Maximum residual norm : 0.002319964033 + + ****Iteration 2**** + Lowest Energy : 0.065601033398 + Maximum Energy change : 0.001101837633 (vector 3) + Maximum residual norm : 0.000136483902 + + ****Iteration 3**** + Lowest Energy : 0.065601017390 + Maximum Energy change : 0.000063202894 (vector 3) + Maximum residual norm : 0.000013795926 + + *** CONVERGENCE OF RESIDUAL NORM REACHED *** +The eigenvalues of the stability matrix: + E( 0) = 0.06560102 Eh + E( 1) = 0.06609196 Eh + E( 2) = 0.06651715 Eh + E( 3) = 0.10398992 Eh + E( 4) = 0.21064880 Eh + E( 5) = 0.25409240 Eh + +The stability analysis shows that the wavefunction is stable + +---------------- +TOTAL SCF ENERGY +---------------- + +Total Energy : -114.86863295212513 Eh -3125.73441 eV + +Components: +Nuclear Repulsion : 19.88558263556816 Eh 541.11421 eV +Electronic Energy : -134.75421610986757 Eh -3666.84864 eV +One Electron Energy: -195.32636367324878 Eh -5315.10057 eV +Two Electron Energy: 60.57214756338121 Eh 1648.25193 eV + +Virial components: +Potential Energy : -229.30475315046098 Eh -6239.69955 eV +Kinetic Energy : 114.43612019833586 Eh 3113.96514 eV +Virial Ratio : 2.00377951256159 + +DFT components: +N(Alpha) : 9.000004451010 electrons +N(Beta) : 8.000001221686 electrons +N(Total) : 17.000005672696 electrons +E(X) : -11.382507579456 Eh +E(C) : -0.629685611089 Eh +E(XC) : -12.012193190545 Eh + +--------------- +SCF CONVERGENCE +--------------- + + Last Energy change ... -3.4003e-09 Tolerance : 1.0000e-08 + Last MAX-Density change ... 3.2372e-02 Tolerance : 1.0000e-07 + Last RMS-Density change ... 1.7710e-03 Tolerance : 5.0000e-09 + Last DIIS Error ... 1.1432e-01 Tolerance : 5.0000e-07 + + +---------------------- +UHF SPIN CONTAMINATION +---------------------- + +Warning: in a DFT calculation there is little theoretical justification to + calculate as in Hartree-Fock theory. We will do it anyways + but you should keep in mind that the values have only limited relevance + +Expectation value of : 1.700055 +Ideal value S*(S+1) for S=0.5 : 0.750000 +Deviation : 0.950055 + +---------------- +ORBITAL ENERGIES +---------------- + SPIN UP ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -19.240574 -523.5626 + 1 1.0000 -10.192428 -277.3501 + 2 1.0000 -0.932782 -25.3823 + 3 1.0000 -0.694395 -18.8954 + 4 1.0000 -0.430372 -11.7110 + 5 1.0000 -0.429773 -11.6947 + 6 1.0000 -0.425987 -11.5917 + 7 1.0000 -0.349662 -9.5148 + 8 1.0000 -0.238456 -6.4887 + 9 0.0000 -0.138456 -3.7676 + 10 0.0000 0.127489 3.4692 + 11 0.0000 0.184891 5.0311 + 12 0.0000 0.202588 5.5127 + 13 0.0000 0.262125 7.1328 + 14 0.0000 0.264269 7.1911 + 15 0.0000 0.287851 7.8328 + 16 0.0000 0.296747 8.0749 + 17 0.0000 0.422342 11.4925 + 18 0.0000 0.460793 12.5388 + 19 0.0000 0.504905 13.7392 + + SPIN DOWN ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -19.239264 -523.5270 + 1 1.0000 -10.178888 -276.9816 + 2 1.0000 -0.928341 -25.2614 + 3 1.0000 -0.656512 -17.8646 + 4 1.0000 -0.421296 -11.4640 + 5 1.0000 -0.420875 -11.4526 + 6 1.0000 -0.420810 -11.4508 + 7 1.0000 -0.348064 -9.4713 + 8 0.0000 -0.130532 -3.5520 + 9 0.0000 -0.017338 -0.4718 + 10 0.0000 0.135400 3.6844 + 11 0.0000 0.186992 5.0883 + 12 0.0000 0.205269 5.5857 + 13 0.0000 0.263670 7.1748 + 14 0.0000 0.266945 7.2639 + 15 0.0000 0.316838 8.6216 + 16 0.0000 0.332620 9.0510 + 17 0.0000 0.425839 11.5877 + 18 0.0000 0.461377 12.5547 +*Only the first 10 virtual orbitals were printed. + + ******************************** + * MULLIKEN POPULATION ANALYSIS * + ******************************** + +-------------------------------------------- +MULLIKEN ATOMIC CHARGES AND SPIN POPULATIONS +-------------------------------------------- + 0 O : -0.043762 0.054373 + 1 C : -0.360679 1.048131 + 2 H : 0.128547 -0.034567 + 3 H : 0.128548 -0.034567 + 4 H : 0.147346 -0.033369 +Sum of atomic charges : -0.0000000 +Sum of atomic spin populations: 1.0000000 + +----------------------------------------------------- +MULLIKEN REDUCED ORBITAL CHARGES AND SPIN POPULATIONS +----------------------------------------------------- +CHARGE + 0 O s : 3.997908 s : 3.997908 + pz : 1.054349 p : 4.044238 + px : 1.990092 + py : 0.999796 + dz2 : 0.000950 d : 0.001367 + dxz : 0.000004 + dyz : 0.000000 + dx2y2 : 0.000413 + dxy : 0.000001 + f0 : 0.000074 f : 0.000248 + f+1 : 0.000050 + f-1 : 0.000035 + f+2 : 0.000002 + f-2 : 0.000000 + f+3 : 0.000044 + f-3 : 0.000043 + + 1 C s : 3.342899 s : 3.342899 + pz : 0.929388 p : 3.005545 + px : 1.049782 + py : 1.026376 + dz2 : 0.004698 d : 0.009814 + dxz : 0.000003 + dyz : 0.000000 + dx2y2 : 0.002577 + dxy : 0.002536 + f0 : -0.000002 f : 0.002421 + f+1 : 0.000488 + f-1 : 0.000469 + f+2 : -0.000000 + f-2 : 0.000000 + f+3 : 0.001466 + f-3 : 0.000000 + + 2 H s : 0.849130 s : 0.849130 + pz : 0.005385 p : 0.022322 + px : 0.006053 + py : 0.010884 + + 3 H s : 0.849130 s : 0.849130 + pz : 0.005385 p : 0.022323 + px : 0.006052 + py : 0.010886 + + 4 H s : 0.829760 s : 0.829760 + pz : 0.005413 p : 0.022894 + px : 0.014000 + py : 0.003482 + + +SPIN + 0 O s : -0.000014 s : -0.000014 + pz : -0.945373 p : 0.054349 + px : -0.000054 + py : 0.999776 + dz2 : -0.000225 d : 0.000023 + dxz : 0.000003 + dyz : 0.000000 + dx2y2 : 0.000245 + dxy : 0.000001 + f0 : -0.000069 f : 0.000014 + f+1 : -0.000038 + f-1 : 0.000035 + f+2 : 0.000000 + f-2 : 0.000000 + f+3 : 0.000042 + f-3 : 0.000043 + + 1 C s : 0.057573 s : 0.057573 + pz : 0.929267 p : 0.993973 + px : 0.031639 + py : 0.033067 + dz2 : -0.004535 d : -0.002021 + dxz : -0.000003 + dyz : 0.000000 + dx2y2 : 0.001222 + dxy : 0.001294 + f0 : -0.000002 f : -0.001394 + f+1 : -0.000660 + f-1 : -0.000657 + f+2 : -0.000000 + f-2 : -0.000000 + f+3 : -0.000075 + f-3 : -0.000000 + + 2 H s : -0.040364 s : -0.040364 + pz : 0.005385 p : 0.005797 + px : 0.000145 + py : 0.000267 + + 3 H s : -0.040364 s : -0.040364 + pz : 0.005385 p : 0.005797 + px : 0.000145 + py : 0.000267 + + 4 H s : -0.039175 s : -0.039175 + pz : 0.005407 p : 0.005806 + px : 0.000313 + py : 0.000086 + + + + ******************************* + * LOEWDIN POPULATION ANALYSIS * + ******************************* + +------------------------------------------- +LOEWDIN ATOMIC CHARGES AND SPIN POPULATIONS +------------------------------------------- + 0 O : -0.042115 0.054247 + 1 C : -0.229007 0.939309 + 2 H : 0.091224 0.001927 + 3 H : 0.091222 0.001927 + 4 H : 0.088676 0.002590 + +---------------------------------------------------- +LOEWDIN REDUCED ORBITAL CHARGES AND SPIN POPULATIONS +---------------------------------------------------- +CHARGE + 0 O s : 3.996434 s : 3.996434 + pz : 1.054295 p : 4.044060 + px : 1.989913 + py : 0.999851 + dz2 : 0.000951 d : 0.001372 + dxz : 0.000004 + dyz : 0.000000 + dx2y2 : 0.000416 + dxy : 0.000001 + f0 : 0.000074 f : 0.000249 + f+1 : 0.000050 + f-1 : 0.000035 + f+2 : 0.000002 + f-2 : 0.000000 + f+3 : 0.000044 + f-3 : 0.000043 + + 1 C s : 3.004122 s : 3.004122 + pz : 0.896656 p : 3.145002 + px : 1.129202 + py : 1.119144 + dz2 : 0.005641 d : 0.071567 + dxz : 0.000003 + dyz : 0.000000 + dx2y2 : 0.031993 + dxy : 0.033931 + f0 : 0.000113 f : 0.008315 + f+1 : 0.002612 + f-1 : 0.002655 + f+2 : 0.000000 + f-2 : 0.000000 + f+3 : 0.002935 + f-3 : 0.000000 + + 2 H s : 0.839040 s : 0.839040 + pz : 0.016261 p : 0.069736 + px : 0.019800 + py : 0.033675 + + 3 H s : 0.839041 s : 0.839041 + pz : 0.016262 p : 0.069737 + px : 0.019797 + py : 0.033679 + + 4 H s : 0.839264 s : 0.839264 + pz : 0.016329 p : 0.072060 + px : 0.043355 + py : 0.012376 + + +SPIN + 0 O s : -0.000033 s : -0.000033 + pz : -0.945410 p : 0.054243 + px : -0.000185 + py : 0.999838 + dz2 : -0.000230 d : 0.000024 + dxz : 0.000003 + dyz : 0.000000 + dx2y2 : 0.000250 + dxy : 0.000001 + f0 : -0.000069 f : 0.000014 + f+1 : -0.000038 + f-1 : 0.000035 + f+2 : 0.000001 + f-2 : 0.000000 + f+3 : 0.000042 + f-3 : 0.000043 + + 1 C s : 0.024758 s : 0.024758 + pz : 0.896521 p : 0.922782 + px : 0.012918 + py : 0.013343 + dz2 : -0.003506 d : -0.006570 + dxz : -0.000002 + dyz : -0.000000 + dx2y2 : -0.001500 + dxy : -0.001561 + f0 : 0.000113 f : -0.001661 + f+1 : -0.000694 + f-1 : -0.000698 + f+2 : -0.000000 + f-2 : -0.000000 + f+3 : -0.000382 + f-3 : -0.000000 + + 2 H s : -0.017375 s : -0.017375 + pz : 0.016261 p : 0.019301 + px : 0.000869 + py : 0.002171 + + 3 H s : -0.017375 s : -0.017375 + pz : 0.016262 p : 0.019302 + px : 0.000868 + py : 0.002172 + + 4 H s : -0.016763 s : -0.016763 + pz : 0.016321 p : 0.019352 + px : 0.002817 + py : 0.000215 + + + + ***************************** + * MAYER POPULATION ANALYSIS * + ***************************** + + NA - Mulliken gross atomic population + ZA - Total nuclear charge + QA - Mulliken gross atomic charge + VA - Mayer's total valence + BVA - Mayer's bonded valence + FA - Mayer's free valence + + ATOM NA ZA QA VA BVA FA + 0 O 8.0438 8.0000 -0.0438 2.0258 0.1250 1.9008 + 1 C 6.3607 6.0000 -0.3607 3.8606 2.9905 0.8701 + 2 H 0.8715 1.0000 0.1285 0.9728 0.9713 0.0016 + 3 H 0.8715 1.0000 0.1285 0.9728 0.9713 0.0016 + 4 H 0.8527 1.0000 0.1473 0.9912 0.9898 0.0014 + + Mayer bond orders larger than 0.100000 +B( 1-C , 2-H ) : 0.9672 B( 1-C , 3-H ) : 0.9672 B( 1-C , 4-H ) : 0.9591 + + +------- +TIMINGS +------- + +Total SCF time: 0 days 0 hours 0 min 44 sec + +Total time .... 44.060 sec +Sum of individual times .... 43.795 sec ( 99.4%) + +SCF preparation .... 0.397 sec ( 0.9%) +Fock matrix formation .... 37.383 sec ( 84.8%) + Startup .... 0.132 sec ( 0.4% of F) + Split-RI-J .... 3.178 sec ( 8.5% of F) + Chain of spheres X .... 23.987 sec ( 64.2% of F) + XC integration .... 9.306 sec ( 24.9% of F) + XC Preparation .... 0.000 sec ( 0.0% of XC) + Basis function eval. .... 1.674 sec ( 18.0% of XC) + Density eval. .... 1.091 sec ( 11.7% of XC) + XC-Functional eval. .... 0.900 sec ( 9.7% of XC) + XC-Potential eval. .... 1.997 sec ( 21.5% of XC) +Diagonalization .... 0.000 sec ( 0.0%) +Density matrix formation .... 0.419 sec ( 1.0%) +Total Energy calculation .... 0.501 sec ( 1.1%) +Population analysis .... 0.018 sec ( 0.0%) +Orbital Transformation .... 0.974 sec ( 2.2%) +Orbital Orthonormalization .... 0.000 sec ( 0.0%) +DIIS solution .... 2.356 sec ( 5.3%) +SOSCF solution .... 0.000 sec ( 0.0%) +NR solution .... 0.007 sec ( 0.0%) +SCF Stability Analysis .... 1.740 sec ( 3.9%) +Finished LeanSCF after 45.8 sec + +Maximum memory used throughout the entire LEANSCF-calculation: 17.5 MB + +------------------------- -------------------- +FINAL SINGLE POINT ENERGY -114.868632952125 +------------------------- -------------------- + + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------ + ORCA PROPERTY CALCULATIONS +------------------------------------------------------------------------------ + +GBWName ... input.gbw +Number of atoms ... 5 +Number of basis functions ... 80 +Max core memory ... 3500 MB + +Electric properties: +Dipole moment ... YES +Quadrupole moment ... NO +Static polarizability (Dipole/Dipole) ... NO +Static polarizability (Dipole/Quad.) ... NO +Static polarizability (Quad./Quad.) ... NO +Static polarizability (Velocity) ... NO + +Atomic electric properties: +Dipole moment ... NO +Quadrupole moment ... NO +Static polarizability ... NO + +Choice of electric origin ... Center of mass +Position of electric origin ... -0.321052 -0.000001 0.000000 + +General magnetic properties: +Magnetizability ... NO + +EPR properties: +g-Tensor (aka g-matrix) ... NO +Zero-Field splitting spin-orbit ... NO +Zero-field splitting spin-spin ... NO +Hyperfine couplings ... NO ( 0 nuclei) +Quadrupole couplings ... NO ( 0 nuclei) +Contact density ... NO ( 0 nuclei) + +NMR properties: +Chemical shifts ... NO ( 0 nuclei) +Spin-rotation constants ... NO ( 0 nuclei) +Spin-spin couplings ... NO ( 0 nuclei, 0 pairs) + +Choice of magnetic origin ... GIAO +Position of magnetic origin ... 0.000000 0.000000 0.000000 + +Properties with geometric perturbations: +SCF Hessian ... NO +IR spectrum ... NO +VCD spectrum ... NO +X-ray spectroscopy properties: +SCF XES/XAS/RIXS spectra ... NO + + +------------- +DIPOLE MOMENT +------------- + +Method : SCF +Type of density : Electron Density +Multiplicity : 2 +Irrep : 0 +Energy : -114.8686329521251253 Eh +Relativity type : +Basis : AO + X Y Z +Electronic contribution: -5.145565919 0.000007675 0.000005972 +Nuclear contribution : 5.457748532 -0.000008463 0.000000000 + ----------------------------------------- +Total Dipole Moment : 0.312182612 -0.000000787 0.000005972 + ----------------------------------------- +Magnitude (a.u.) : 0.312182612 +Magnitude (Debye) : 0.793505140 + + + +-------------------- +Rotational spectrum +-------------------- + +Rotational constants in cm-1: 9.601482 0.150024 0.147716 +Rotational constants in MHz : 287845.203797 4497.602086 4428.407894 + +Dipole components along the rotational axes: +x,y,z [a.u.] : 0.312183 0.000001 0.000006 +x,y,z [Debye]: 0.793505 0.000002 0.000016 + + + +Dipole moment calculation done in 0.0 sec + +Maximum memory used throughout the entire PROP-calculation: 4.2 MB + +-------------------------------- +SUGGESTED CITATIONS FOR THIS RUN +-------------------------------- + +Below you find a list of papers that are relevant to this ORCA run +We neither can nor want to force you to cite these papers, but we appreciate if you do +You receive ORCA, which is the product of decades of hard work by many enthusiastic individuals, for free +The only thing we kindly ask in return is that you cite our papers, +We deeply appreciate it, if you show your appreciation for ORCA by not just citing the generic ORCA reference. + +Please note that relegating all ORCA citations to the supporting information does *not* help us. +SI sections are not indexed - citations you put there will not count into any citation statistics +But we need these citations in order to attract the funding resources that allow us to do what we are doing + +Therefore, if you are a happy ORCA user, please consider citing a few of the papers listed below in the main body of your paper + +In addition to the list printed below, the program has created the file input.bibtex that contains the list in bibtex format +You can import this file easily into all common literature databanks and citation aid programs + + +List of essential papers. We consider these as the minimum necessary citations + + 1. Neese,F. + Software update: the ORCA program system, version 5.0 + WIRES Comput. Molec. Sci., 2022 12(1)e1606 + doi.org/10.1002/wcms.1606 + +List of papers to cite with high priority. The work reported in these papers was absolutely +necessary for this run to complete. +Our perspective: the developers of density functionals and basis sets usually get cited in chemistry papers +Good! But without the algorithms to do something with them, the functionals or basis sets would not do anything. +Hence, in our opinion, the algorithm design and method developments papers are equally worthy of getting cited + + 1. Neese,F. + An improvement of the resolution of the identity approximation for the formation of the Coulomb matrix + J. Comp. Chem., 2003 24(14)1740-1747 + doi.org/10.1002/jcc.10318 + 2. Neese,F.; Wennmohs,F.; Hansen,A.; Becker,U. + Efficient, approximate and parallel Hartree-Fock and hybrid DFT calculations. A 'chain-of-spheres' algorithm for the Hartree-Fock exchange + Chem. Phys., 2009 356(1-3)98-109 + doi.org/10.1016/j.chemphys.2008.10.036 + 3. Helmich-Paris,B.; de Souza,B.; Neese,F.; Izsák,R. + An improved chain of spheres for exchange algorithm + J. Chem. Phys., 2021 155 104109 + doi.org/doi: 10.1063/5.0058766. + 4. Helmich-Paris,B. + A trust-region augmented Hessian implementation for restricted and unrestricted Hartree–Fock and Kohn–Sham methods + J. Chem. Phys., 2021 154 164104 + doi.org/10.1063/5.0040798 + 5. Neese,F. + The SHARK Integral Generation and Digestion System + J. Comp. Chem., 2022 1-16 + doi.org/10.1002/jcc.26942 + +List of suggested additional citations. These are papers that are important in the 'surrounding' of +of this run, or papers that preceded the highly important papers. If you like your results we are grateful for a citation. + + 1. Izsak,R.; Neese,F. + An overlap fitted chain of spheres exchange method + J. Chem. Phys., 2011 135 144105 + doi.org/10.1063/1.3646921 + 2. Izsak,R.; Hansen,A.; Neese,F. + The resolution of identity and chain of spheres approximations for the LPNO-CCSD singles Fock term + Molec. Phys., 2012 110 2413-2417 + doi.org/10.1080/00268976.2012.687466 + 3. Neese,F. + The ORCA program system + WIRES Comput. Molec. Sci., 2012 2(1)73-78 + doi.org/10.1002/wcms.81 + 4. Izsak,R.; Neese,F.; Klopper,W. + Robust fitting techniques in the chain of spheres approximation to the Fock exchange: The role of the complementary space + J. Chem. Phys., 2013 139 + doi.org/10.1063/1.4819264 + 5. Neese,F. + Software update: the ORCA program system, version 4.0 + WIRES Comput. Molec. Sci., 2018 8(1)1-6 + doi.org/10.1002/wcms.1327 + 6. Neese,F.; Wennmohs,F.; Becker,U.; Riplinger,C. + The ORCA quantum chemistry program package + J. Chem. Phys., 2020 152 Art. No. L224108 + doi.org/10.1063/5.0004608 + +List of optional additional citations + + 1. Neese,F. + Approximate second-order SCF convergence for spin unrestricted wavefunctions + Chem. Phys. Lett., 2000 325(1-3)93-98 + doi.org/10.1016/s0009-2614(00)00662-x + +Timings for individual modules: + +Sum of individual times ... 53.777 sec (= 0.896 min) +Startup calculation ... 3.762 sec (= 0.063 min) 7.0 % +SCF iterations ... 48.802 sec (= 0.813 min) 90.7 % +Property calculations ... 1.213 sec (= 0.020 min) 2.3 % + ****ORCA TERMINATED NORMALLY**** +TOTAL RUN TIME: 0 days 0 hours 0 minutes 54 seconds 958 msec diff --git a/arc/testing/stability/orca_stable_unrestricted_doublet_ts.out b/arc/testing/stability/orca_stable_unrestricted_doublet_ts.out new file mode 100644 index 0000000000..fd806f5b89 --- /dev/null +++ b/arc/testing/stability/orca_stable_unrestricted_doublet_ts.out @@ -0,0 +1,1461 @@ + + ***************** + * O R C A * + ***************** + + #, + ### + #### + ##### + ###### + ########, + ,,################,,,,, + ,,#################################,, + ,,##########################################,, + ,#########################################, ''#####, + ,#############################################,, '####, + ,##################################################,,,,####, + ,###########'''' ''''############################### + ,#####'' ,,,,##########,,,, '''####''' '#### + ,##' ,,,,###########################,,, '## + ' ,,###'''' '''############,,, + ,,##'' '''############,,,, ,,,,,,###'' + ,#'' '''#######################''' + ' ''''####'''' + ,#######, #######, ,#######, ## + ,#' '#, ## ## ,#' '#, #''# ,####, ,####, + ## ## ## ,#' ## #' '# #' #' '# + ## ## ####### ## ,######, #####, # # + '#, ,#' ## ## '#, ,#' ,# #, #, # #, ,# + '#######' ## ## '#######' #' '# '####' # '####' + + + + ######################################################### + # -***- # + # Department of theory and spectroscopy # + # # + # Frank Neese # + # # + # Directorship, Architecture, Infrastructure # + # SHARK, DRIVERS # + # Core code/Algorithms in most modules # + # # + # Max Planck Institute fuer Kohlenforschung # + # Kaiser Wilhelm Platz 1 # + # D-45470 Muelheim/Ruhr # + # Germany # + # # + # All rights reserved # + # -***- # + ######################################################### + + + Program Version 6.0.0 - RELEASE - + + + With contributions from (in alphabetic order): + Daniel Aravena : Magnetic Suceptibility + Michael Atanasov : Ab Initio Ligand Field Theory (pilot matlab implementation) + Alexander A. Auer : GIAO ZORA, VPT2 properties, NMR spectrum + Ute Becker : All parallelization in ORCA, NUMFREQ, NUMCALC + Giovanni Bistoni : ED, misc. LED, open-shell LED, HFLD + Martin Brehm : Molecular dynamics + Dmytro Bykov : pre 5.0 version of the SCF Hessian + Marcos Casanova-Páez : Triplet and SCS-CIS(D). UHF-(DLPNO)-IP/EA/STEOM-CCSD. UHF-CVS-IP/STEOM-CCSD + Vijay G. Chilkuri : MRCI spin determinant printing, contributions to CSF-ICE + Pauline Colinet : FMM embedding + Dipayan Datta : RHF DLPNO-CCSD density + Achintya Kumar Dutta : EOM-CC, STEOM-CC + Nicolas Foglia : Exact transition moments, OPA infrastructure, MCD improvements + Dmitry Ganyushin : Spin-Orbit,Spin-Spin,Magnetic field MRCI + Miquel Garcia : C-PCM and meta-GGA Hessian, CCSD/C-PCM, Gaussian charge scheme + Tiago L. C. Gouveia : GS-ROHF, GS-ROCIS + Yang Guo : DLPNO-NEVPT2, F12-NEVPT2, CIM, IAO-localization + Andreas Hansen : Spin unrestricted coupled pair/coupled cluster methods + Ingolf Harden : AUTO-CI MPn and infrastructure + Benjamin Helmich-Paris : MC-RPA, TRAH-(SCF,CASSCF), AVAS, COSX integrals, SCF dyn. polar. + Lee Huntington : MR-EOM, pCC + Robert Izsak : Overlap fitted RIJCOSX, COSX-SCS-MP3, EOM + Riya Kayal : Wick's Theorem for AUTO-CI, AUTO-CI UHF-CCSDT + Emily Kempfer : AUTO-CI, RHF CISDT and CCSDT + Christian Kollmar : KDIIS, OOCD, Brueckner-CCSD(T), CCSD density, CASPT2, CASPT2-K, improved NEVPT2 + Axel Koslowski : Symmetry handling + Simone Kossmann : Meta GGA functionals, TD-DFT gradient, OOMP2, (MP2 Hessian; deprecated post 5.0) + Lucas Lang : DCDCAS + Marvin Lechner : AUTO-CI (C++ implementation), FIC-MRCC + Spencer Leger : CASSCF response + Dagmar Lenk : GEPOL surface, SMD, ORCA-2-JSON + Dimitrios Liakos : Extrapolation schemes; Compound Job, initial MDCI parallelization + Dimitrios Manganas : Further ROCIS development; embedding schemes. LFT, Crystal Embedding + Dimitrios Pantazis : SARC Basis sets + Anastasios Papadopoulos: AUTO-CI, single reference methods and gradients + Taras Petrenko : pre 6.0 DFT Hessian and TD-DFT gradient, (ASA, deprecated), ECA, 1-Electron XAS/XES, NRVS + Peter Pinski : DLPNO-MP2, DLPNO-MP2 Gradient + Christoph Reimann : Effective Core Potentials + Marius Retegan : Local ZFS, SOC + Christoph Riplinger : Optimizer, TS searches, QM/MM, DLPNO-CCSD(T), (RO)-DLPNO pert. Triples + Michael Roemelt : Original ROCIS implementation + Masaaki Saitow : Open-shell DLPNO-CCSD energy and density + Barbara Sandhoefer : DKH picture change effects + Kantharuban Sivalingam : CASSCF convergence/infrastructure, NEVPT2 and variants, FIC-MRCI + Bernardo de Souza : ESD, SOC TD-DFT + Georgi Stoychev : AutoAux, RI-MP2 NMR, DLPNO-MP2 response, X2C + Van Anh Tran : RI-MP2 g-tensors + Willem Van den Heuvel : Paramagnetic NMR + Zikuan Wang : NOTCH, Electric field optimization + Frank Wennmohs : Technical directorship and infrastructure + Hang Xu : AUTO-CI-Response properties + + + We gratefully acknowledge several colleagues who have allowed us to + interface, adapt or use parts of their codes: + Stefan Grimme, W. Hujo, H. Kruse, P. Pracht, : VdW corrections, initial TS optimization, + C. Bannwarth, S. Ehlert, DFT functionals, gCP, sTDA/sTD-DF + L. Wittmann, M. Mueller + Ed Valeev, F. Pavosevic, A. Kumar : LibInt (2-el integral package), F12 methods + Garnet Chan, S. Sharma, J. Yang, R. Olivares : DMRG + Ulf Ekstrom : XCFun DFT Library + Mihaly Kallay : mrcc (arbitrary order and MRCC methods) + Frank Weinhold : gennbo (NPA and NBO analysis) + Simon Mueller : openCOSMO-RS + Christopher J. Cramer and Donald G. Truhlar : smd solvation model + Lars Goerigk : TD-DFT with DH, B97 family of functionals + V. Asgeirsson, H. Jonsson : NEB implementation + FAccTs GmbH : IRC, NEB, NEB-TS, DLPNO-Multilevel, CI-OPT + MM, QMMM, 2- and 3-layer-ONIOM, Crystal-QMMM, + LR-CPCM, SF, NACMEs, symmetry and pop. for TD-DFT, + nearIR, NL-DFT gradient (VV10), updates on ESD, + ML-optimized integration grids, MBIS, APM, + GOAT, DOCKER, SOLVATOR, interface openCOSMO-RS + S Lehtola, MJT Oliveira, MAL Marques : LibXC Library + Liviu Ungur et al : ANISO software + + + Your calculation uses the libint2 library for the computation of 2-el integrals + For citations please refer to: http://libint.valeyev.net + + Your ORCA version has been built with support for libXC version: 6.2.2 + For citations please refer to: https://libxc.gitlab.io + + This ORCA versions uses: + CBLAS interface : Fast vector & matrix operations + LAPACKE interface : Fast linear algebra routines + SCALAPACK package : Parallel linear algebra routines + Shared memory : Shared parallel matrices + BLAS/LAPACK : OpenBLAS 0.3.27 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Cooperlake SINGLE_THREADED + Core in use : Cooperlake + Copyright (c) 2011-2014, The OpenBLAS Project + + +NOTE: MaxCore=3500 MB was set to SCF,MP2,MDCI,CIPSI,MRCI and CIS + => If you want to overwrite this, your respective input block should be placed after the MaxCore statement +Warning: RI is on but no J-basis has been assigned. Assigning Def2/J (nothing to worry about!) +================================================================================ + +----- Orbital basis set information ----- +Your calculation utilizes the basis: def2-TZVP + F. Weigend and R. Ahlrichs, Phys. Chem. Chem. Phys. 7, 3297 (2005). + +----- AuxJ basis set information ----- +Your calculation utilizes the auxiliary basis: def2/J + F. Weigend, Phys. Chem. Chem. Phys. 8, 1057 (2006). + +================================================================================ + WARNINGS + Please study these warnings very carefully! +================================================================================ + + +================================================================================ + INPUT FILE +================================================================================ +NAME = input.in +| 1> !UKS B3LYP def2-TZVP TightSCF defgrid3 +| 2> %maxcore 3500 +| 3> %pal nprocs 8 end +| 4> +| 5> * xyz 0 2 +| 6> O 2.44052 -0.74022 0.00006 +| 7> C 1.23040 -0.15444 0.00004 +| 8> C 0.99241 1.16752 0.00007 +| 9> Cl -2.24715 -0.15396 -0.00008 +| 10> H 3.13998 -0.07190 0.00010 +| 11> H 0.42979 -0.88112 -0.00001 +| 12> H 1.79721 1.89374 0.00012 +| 13> H -0.02639 1.51989 0.00005 +| 14> * +| 15> +| 16> %scf +| 17> MaxIter 999 +| 18> STABPerform true +| 19> STABRestartUHFifUnstable false +| 20> STABNRoots 6 +| 21> end +| 22> +| 23> ****END OF INPUT**** +================================================================================ + + **************************** + * Single Point Calculation * + **************************** + +--------------------------------- +CARTESIAN COORDINATES (ANGSTROEM) +--------------------------------- + O 2.440520 -0.740220 0.000060 + C 1.230400 -0.154440 0.000040 + C 0.992410 1.167520 0.000070 + Cl -2.247150 -0.153960 -0.000080 + H 3.139980 -0.071900 0.000100 + H 0.429790 -0.881120 -0.000010 + H 1.797210 1.893740 0.000120 + H -0.026390 1.519890 0.000050 + +---------------------------- +CARTESIAN COORDINATES (A.U.) +---------------------------- + NO LB ZA FRAG MASS X Y Z + 0 O 8.0000 0 15.999 4.611914 -1.398813 0.000113 + 1 C 6.0000 0 12.011 2.325119 -0.291849 0.000076 + 2 C 6.0000 0 12.011 1.875383 2.206293 0.000132 + 3 Cl 17.0000 0 35.453 -4.246498 -0.290942 -0.000151 + 4 H 1.0000 0 1.008 5.933702 -0.135871 0.000189 + 5 H 1.0000 0 1.008 0.812185 -1.665075 -0.000019 + 6 H 1.0000 0 1.008 3.396235 3.578650 0.000227 + 7 H 1.0000 0 1.008 -0.049870 2.872176 0.000094 + +-------------------------------- +INTERNAL COORDINATES (ANGSTROEM) +-------------------------------- + O 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 1.344443611015 0.00000000 0.00000000 + C 2 1 0 1.343211629863 126.03565995 0.00000000 + Cl 2 1 3 3.477550035197 154.17778385 179.99942492 + H 1 2 3 0.967417136296 110.47409280 0.00000000 + H 2 1 3 1.081221622518 111.94117180 179.99968941 + H 3 2 1 1.084019617396 121.85632196 0.00000000 + H 3 2 1 1.078015796406 119.28438476 180.00004859 + +--------------------------- +INTERNAL COORDINATES (A.U.) +--------------------------- + O 0 0 0 0.000000000000 0.00000000 0.00000000 + C 1 0 0 2.540630227319 0.00000000 0.00000000 + C 2 1 0 2.538302120340 126.03565995 0.00000000 + Cl 2 1 3 6.571617183531 154.17778385 179.99942492 + H 1 2 3 1.828153444863 110.47409280 0.00000000 + H 2 1 3 2.043212756633 111.94117180 179.99968941 + H 3 2 1 2.048500200677 121.85632196 0.00000000 + H 3 2 1 2.037154623248 119.28438476 180.00004859 + +--------------------- +BASIS SET INFORMATION +--------------------- +There are 4 groups of distinct atoms + + Group 1 Type O : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 2 Type C : 11s6p2d1f contracted to 5s3p2d1f pattern {62111/411/11/1} + Group 3 Type Cl : 14s9p3d1f contracted to 5s5p2d1f pattern {73211/51111/21/1} + Group 4 Type H : 5s1p contracted to 3s1p pattern {311/1} + +Atom 0O basis set group => 1 +Atom 1C basis set group => 2 +Atom 2C basis set group => 2 +Atom 3Cl basis set group => 3 +Atom 4H basis set group => 4 +Atom 5H basis set group => 4 +Atom 6H basis set group => 4 +Atom 7H basis set group => 4 +--------------------------------- +AUXILIARY/J BASIS SET INFORMATION +--------------------------------- +There are 4 groups of distinct atoms + + Group 1 Type O : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 2 Type C : 12s5p4d2f1g contracted to 6s4p3d1f1g pattern {711111/2111/211/2/1} + Group 3 Type Cl : 14s5p5d2f1g contracted to 8s4p3d1f1g pattern {71111111/2111/311/2/1} + Group 4 Type H : 5s2p1d contracted to 3s1p1d pattern {311/2/1} + +Atom 0O basis set group => 1 +Atom 1C basis set group => 2 +Atom 2C basis set group => 2 +Atom 3Cl basis set group => 3 +Atom 4H basis set group => 4 +Atom 5H basis set group => 4 +Atom 6H basis set group => 4 +Atom 7H basis set group => 4 + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------ + ORCA STARTUP CALCULATIONS + -- RI-GTO INTEGRALS CHOSEN -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + ___ + / \ - P O W E R E D B Y - + / \ + | | | _ _ __ _____ __ __ + | | | | | | | / \ | _ \ | | / | + \ \/ | | | | / \ | | | | | | / / + / \ \ | |__| | / /\ \ | |_| | | |/ / + | | | | __ | / /__\ \ | / | \ + | | | | | | | | __ | | \ | |\ \ + \ / | | | | | | | | | |\ \ | | \ \ + \___/ |_| |_| |__| |__| |_| \__\ |__| \__/ + + - O R C A' S B I G F R I E N D - + & + - I N T E G R A L F E E D E R - + + v1 FN, 2020, v2 2021, v3 2022-2024 +------------------------------------------------------------------------------ + + +---------------------- +SHARK INTEGRAL PACKAGE +---------------------- + +Number of atoms ... 8 +Number of basis functions ... 154 +Number of shells ... 62 +Maximum angular momentum ... 3 +Integral batch strategy ... SHARK/LIBINT Hybrid +RI-J (if used) integral strategy ... SPLIT-RIJ (Revised 2003 algorithm where possible) +Printlevel ... 1 +Contraction scheme used ... SEGMENTED contraction +Prescreening option ... SCHWARTZ + Thresh ... 2.500e-11 + Tcut ... 2.500e-12 + Tpresel ... 2.500e-12 +Coulomb Range Separation ... NOT USED +Exchange Range Separation ... NOT USED +Multipole approximations ... NOT USED +Finite Nucleus Model ... NOT USED +CABS basis ... NOT available +Auxiliary Coulomb fitting basis ... AVAILABLE + # of basis functions in Aux-J ... 242 + # of shells in Aux-J ... 82 + Maximum angular momentum in Aux-J ... 4 +Auxiliary J/K fitting basis ... NOT available +Auxiliary Correlation fitting basis ... NOT available +Auxiliary 'external' fitting basis ... NOT available + +Checking pre-screening integrals ... done ( 0.0 sec) Dimension = 62 +Check shell pair data ... done ( 0.0 sec) +Shell pair information +Shell pair cut-off parameter TPreSel ... 2.5e-12 +Total number of shell pairs ... 1953 +Shell pairs after pre-screening ... 1779 +Total number of primitive shell pairs ... 6330 +Primitive shell pairs kept ... 4479 + la=0 lb=0: 478 shell pairs + la=1 lb=0: 520 shell pairs + la=1 lb=1: 158 shell pairs + la=2 lb=0: 232 shell pairs + la=2 lb=1: 132 shell pairs + la=2 lb=2: 35 shell pairs + la=3 lb=0: 118 shell pairs + la=3 lb=1: 67 shell pairs + la=3 lb=2: 30 shell pairs + la=3 lb=3: 9 shell pairs + +Calculating one electron integrals ... done ( 0.0 sec) +Calculating RI/J V-Matrix + Cholesky decomp.... done ( 0.0 sec) +Calculating Nuclear repulsion ... done ( 0.0 sec) ENN= 126.786712095351 Eh + +Diagonalization of the overlap matrix: +Smallest eigenvalue ... 2.054e-04 +Time for diagonalization ... 0.004 sec +Threshold for overlap eigenvalues ... 1.000e-07 +Number of eigenvalues below threshold ... 0 +Time for construction of square roots ... 0.002 sec +Total time needed ... 0.007 sec + +------------------- +DFT GRID GENERATION +------------------- + +General Integration Accuracy IntAcc ... 4.959 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 6 (Lebedev-590) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... off +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 95364 +Total number of batches ... 1494 +Average number of points per batch ... 63 +Average number of grid points per atom ... 11920 + +-------------------- +COSX GRID GENERATION +-------------------- + +GRIDX 1 +------- +General Integration Accuracy IntAcc ... 4.020 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 2 (Lebedev-110) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 10663 +Total number of batches ... 87 +Average number of points per batch ... 122 +Average number of grid points per atom ... 1333 +UseSFitting ... on + +GRIDX 2 +------- +General Integration Accuracy IntAcc ... 4.338 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 3 (Lebedev-194) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 24174 +Total number of batches ... 193 +Average number of points per batch ... 125 +Average number of grid points per atom ... 3022 +UseSFitting ... on + +GRIDX 3 +------- +General Integration Accuracy IntAcc ... 4.871 +Radial Grid Type RadialGrid ... OptM3 with GC (2021) +Angular Grid (max. ang.) AngularGrid ... 4 (Lebedev-302) +Angular grid pruning method GridPruning ... 4 (adaptive) +Weight generation scheme WeightScheme... mBecke (2022) +Basis function cutoff BFCut ... 1.0000e-11 +Integration weight cutoff WCut ... 1.0000e-14 +Partially contracted basis set ... on +Rotationally invariant grid construction ... off +Angular grids for H and He will be reduced by one unit + +Total number of grid points ... 46049 +Total number of batches ... 363 +Average number of points per batch ... 126 +Average number of grid points per atom ... 5756 +UseSFitting ... on +Initializing property integral containers ... done ( 0.0 sec) + +SHARK setup successfully completed in 2.8 seconds + +Maximum memory used throughout the entire STARTUP-calculation: 23.2 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ +------------------------------------------------------------------------------- + ORCA GUESS + Start orbitals & Density for SCF / CASSCF +------------------------------------------------------------------------------- + +------------ +SCF SETTINGS +------------ +Hamiltonian: + Density Functional Method .... DFT(GTOs) + Exchange Functional Exchange .... B88 + X-Alpha parameter XAlpha .... 0.666667 + Becke's b parameter XBeta .... 0.004200 + Correlation Functional Correlation .... LYP + LDA part of GGA corr. LDAOpt .... VWN-5 + Gradients option PostSCFGGA .... off + Hybrid DFT is turned on + Fraction HF Exchange ScalHFX .... 0.200000 + Scaling of DF-GGA-X ScalDFX .... 0.720000 + Scaling of DF-GGA-C ScalDFC .... 0.810000 + Scaling of DF-LDA-C ScalLDAC .... 1.000000 + Perturbative correction .... 0.000000 + NL short-range parameter .... 4.800000 + RI-approximation to the Coulomb term is turned on + Number of AuxJ basis functions .... 242 + RIJ-COSX (HFX calculated with COS-X)).... on + + +General Settings: + Integral files IntName .... input + Hartree-Fock type HFTyp .... UHF + Total Charge Charge .... 0 + Multiplicity Mult .... 2 + Number of Electrons NEL .... 41 + Basis Dimension Dim .... 154 + Nuclear Repulsion ENuc .... 126.7867120954 Eh + +Convergence Acceleration: + AO-DIIS CNVDIIS .... on + Start iteration DIISMaxIt .... 12 + Startup error DIISStart .... 0.200000 + # of expansion vecs DIISMaxEq .... 5 + Bias factor DIISBfac .... 1.050 + Max. coefficient DIISMaxC .... 10.000 + MO-DIIS CNVKDIIS .... off + Trust-Rad. Augm. Hess. CNVTRAH .... auto + Auto Start mean grad. ratio tolernc. .... 1.125000 + Auto Start start iteration .... 50 + Auto Start num. interpolation iter. .... 10 + Max. Number of Micro iterations .... 24 + Max. Number of Macro iterations .... Maxiter - #DIIS iter + Number of Davidson start vectors .... 2 + Converg. threshold (grad. norm) .... 1.000e-05 + Grad. Scal. Fac. for Micro threshold .... 0.100 + Minimum threshold for Micro iter. .... 1.000e-02 + NR start threshold (gradient norm) .... 1.000e-04 + Initial trust radius .... 0.400 + Minimum AH scaling param. (alpha) .... 1.000 + Maximum AH scaling param. (alpha) .... 1000.000 + Quad. conv. algorithm .... NR + White noise on init. David. guess .... on + Maximum white noise .... 0.010 + Pseudo random numbers .... off + Inactive MOs .... canonical + Orbital update algorithm .... Taylor + Preconditioner .... Diag + Full preconditioner red. dimension .... 250 + SOSCF CNVSOSCF .... on + Start iteration SOSCFMaxIt .... 150 + Startup grad/error SOSCFStart .... 0.003300 + Hessian update SOSCFHessUp .... L-BFGS + Level Shifting CNVShift .... on + Level shift para. LevelShift .... 0.2500 + Turn off err/grad. ShiftErr .... 0.0010 + Zerner damping CNVZerner .... off + Static damping CNVDamp .... on + Fraction old density DampFac .... 0.7000 + Max. Damping (<1) DampMax .... 0.9800 + Min. Damping (>=0) DampMin .... 0.0000 + Turn off err/grad. DampErr .... 0.1000 + +SCF Procedure: + Maximum # iterations MaxIter .... 999 + SCF integral mode SCFMode .... Direct + Integral package .... SHARK and LIBINT hybrid scheme + Reset frequency DirectResetFreq .... 20 + Integral Threshold Thresh .... 2.500e-11 Eh + Primitive CutOff TCut .... 2.500e-12 Eh + +Convergence Tolerance: + Convergence Check Mode ConvCheckMode .... Total+1el-Energy + Convergence forced ConvForced .... 0 + Energy Change TolE .... 1.000e-08 Eh + 1-El. energy change .... 1.000e-05 Eh + Orbital Gradient TolG .... 1.000e-05 + Orbital Rotation angle TolX .... 1.000e-05 + DIIS Error TolErr .... 5.000e-07 + +------------------------------ +INITIAL GUESS: MODEL POTENTIAL +------------------------------ +Loading Hartree-Fock densities ... done +Calculating cut-offs ... done +Initializing the effective Hamiltonian ... done +Setting up the integral package (SHARK) ... done +Starting the Coulomb interaction ... done ( 0.0 sec) +Making the grid ... done ( 0.1 sec) +Mapping shells ... done +Starting the XC term evaluation ... done ( 0.0 sec) + promolecular density results + # of electrons = 40.997398061 + EX = -47.126198895 + EC = -1.496150499 + EX+EC = -48.622349395 +Transforming the Hamiltonian ... done ( 0.0 sec) +Diagonalizing the Hamiltonian ... done ( 0.0 sec) +Back transforming the eigenvectors ... done ( 0.0 sec) +Now organizing SCF variables ... done + ------------------ + INITIAL GUESS DONE ( 0.2 sec) + ------------------ + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** +Finished Guess after 1.0 sec +Maximum memory used throughout the entire GUESS-calculation: 9.3 MB + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------------------- + ORCA LEAN-SCF + memory conserving SCF solver +------------------------------------------------------------------------------------------- + +----------------------------------------D-I-I-S-------------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP DIISErr Damp Time(sec) +------------------------------------------------------------------------------------------- + *** Starting incremental Fock matrix formation *** + 1 -613.7876585753726886 0.00e+00 8.04e-04 2.11e-02 1.10e-01 0.700 1.6 +Warning: op=1 Small HOMO/LUMO gap ( 0.020) - skipping pre-diagonalization + Will do a full diagonalization + 2 -613.8412204099199698 -5.36e-02 5.99e-04 1.66e-02 4.64e-02 0.700 1.2 + ***Turning on AO-DIIS*** + 3 -613.8614898999501293 -2.03e-02 2.85e-04 9.78e-03 1.82e-02 0.700 1.1 + 4 -613.8728251704071681 -1.13e-02 5.79e-04 1.95e-02 9.79e-03 0.000 0.9 + 5 -613.8990562866531491 -2.62e-02 1.79e-04 8.65e-03 5.55e-03 0.000 0.9 + 6 -613.8996439005713910 -5.88e-04 8.42e-05 3.59e-03 3.62e-03 0.000 0.9 + *** Initializing SOSCF *** +---------------------------------------S-O-S-C-F-------------------------------------- +Iteration Energy (Eh) Delta-E RMSDP MaxDP MaxGrad Time(sec) +-------------------------------------------------------------------------------------- + 7 -613.8998225756233751 -1.79e-04 6.68e-05 2.33e-03 1.81e-03 0.9 + *** Restarting incremental Fock matrix formation *** + 8 -613.8999264584922457 -1.04e-04 1.01e-04 4.67e-03 2.24e-03 1.7 + 9 -613.9000143115217725 -8.79e-05 1.74e-04 4.68e-03 1.44e-03 1.3 + 10 -613.9000258281173501 -1.15e-05 5.03e-05 1.86e-03 1.27e-03 1.3 + 11 -613.9000548103836081 -2.90e-05 9.18e-06 2.33e-04 1.43e-04 1.4 + 12 -613.9000548805859125 -7.02e-08 3.48e-06 1.19e-04 1.45e-04 1.3 + 13 -613.9000552312797936 -3.51e-07 2.41e-06 7.92e-05 4.43e-05 1.3 + 14 -613.9000552458835500 -1.46e-08 1.07e-06 4.42e-05 4.43e-05 1.1 + 15 -613.9000552661482288 -2.03e-08 4.41e-07 1.60e-05 1.53e-05 1.2 + 16 -613.9000552682580292 -2.11e-09 3.24e-07 1.24e-05 1.23e-05 1.0 + **** Energy Check signals convergence **** + + ***************************************************** + * SUCCESS * + * SCF CONVERGED AFTER 16 CYCLES * + ***************************************************** + +Recomputing exchange energy using gridx3 ... done ( 1.891 sec) +Old exchange energy : -9.490955113 Eh +New exchange energy : -9.490952360 Eh +Exchange energy change after final integration : 0.000002753 Eh +Total energy after final integration : -613.900052515 Eh + **** ENERGY FILE WAS UPDATED (input.en.tmp) **** + +------------------------------------------------------------------------------------------- + WAVEFUNCTION STABILITY ANALYSIS +------------------------------------------------------------------------------------------- + + + ****Iteration 0**** + Lowest Energy : 0.010637590845 + Maximum Energy change : 0.158891560502 (vector 5) + Maximum residual norm : 0.105460130322 + + ****Iteration 1**** + Lowest Energy : 0.002715558220 + Maximum Energy change : 0.057592373536 (vector 2) + Maximum residual norm : 0.006492806314 + + ****Iteration 2**** + Lowest Energy : 0.002455600041 + Maximum Energy change : 0.003219681544 (vector 2) + Maximum residual norm : 0.000620645477 + + ****Iteration 3**** + Lowest Energy : 0.002449842051 + Maximum Energy change : 0.000370714276 (vector 2) + Maximum residual norm : 0.000094210218 + + *** CONVERGENCE OF RESIDUAL NORM REACHED *** +The eigenvalues of the stability matrix: + E( 0) = 0.00244984 Eh + E( 1) = 0.00314027 Eh + E( 2) = 0.07412928 Eh + E( 3) = 0.11776270 Eh + E( 4) = 0.14384624 Eh + E( 5) = 0.15664275 Eh + +The stability analysis shows that the wavefunction is stable + +---------------- +TOTAL SCF ENERGY +---------------- + +Total Energy : -613.90005251538696 Eh -16705.06970 eV + +Components: +Nuclear Repulsion : 126.78671209535065 Eh 3450.04183 eV +Electronic Energy : -740.68676736360862 Eh -20155.11161 eV +One Electron Energy: -1095.51713802135009 Eh -29810.53686 eV +Two Electron Energy: 354.83037065774141 Eh 9655.42526 eV + +Virial components: +Potential Energy : -1226.55552841316853 Eh -33376.27275 eV +Kinetic Energy : 612.65547589778157 Eh 16671.20305 eV +Virial Ratio : 2.00203144616602 + +DFT components: +N(Alpha) : 20.999999262132 electrons +N(Beta) : 19.999999193591 electrons +N(Total) : 40.999998455723 electrons +E(X) : -37.727324785858 Eh +E(C) : -1.764052608412 Eh +E(XC) : -39.491377394269 Eh + +--------------- +SCF CONVERGENCE +--------------- + + Last Energy change ... 2.1098e-09 Tolerance : 1.0000e-08 + Last MAX-Density change ... 1.2428e-05 Tolerance : 1.0000e-07 + Last RMS-Density change ... 3.2373e-07 Tolerance : 5.0000e-09 + Last DIIS Error ... 1.8063e-03 Tolerance : 5.0000e-07 + Last Orbital Gradient ... 1.2339e-05 Tolerance : 1.0000e-05 + Last Orbital Rotation ... 4.6384e-05 Tolerance : 1.0000e-05 + + +---------------------- +UHF SPIN CONTAMINATION +---------------------- + +Warning: in a DFT calculation there is little theoretical justification to + calculate as in Hartree-Fock theory. We will do it anyways + but you should keep in mind that the values have only limited relevance + +Expectation value of : 0.753696 +Ideal value S*(S+1) for S=0.5 : 0.750000 +Deviation : 0.003696 + +---------------- +ORBITAL ENERGIES +---------------- + SPIN UP ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -101.515877 -2762.3875 + 1 1.0000 -19.197079 -522.3791 + 2 1.0000 -10.262528 -279.2576 + 3 1.0000 -10.192349 -277.3479 + 4 1.0000 -9.445381 -257.0219 + 5 1.0000 -7.213997 -196.3028 + 6 1.0000 -7.197191 -195.8455 + 7 1.0000 -7.197125 -195.8437 + 8 1.0000 -1.102512 -30.0009 + 9 1.0000 -0.794179 -21.6107 + 10 1.0000 -0.782180 -21.2842 + 11 1.0000 -0.656791 -17.8722 + 12 1.0000 -0.529900 -14.4193 + 13 1.0000 -0.513361 -13.9693 + 14 1.0000 -0.435291 -11.8449 + 15 1.0000 -0.416602 -11.3363 + 16 1.0000 -0.400941 -10.9102 + 17 1.0000 -0.351073 -9.5532 + 18 1.0000 -0.309385 -8.4188 + 19 1.0000 -0.308781 -8.4024 + 20 1.0000 -0.274120 -7.4592 + 21 0.0000 -0.010915 -0.2970 + 22 0.0000 0.008972 0.2441 + 23 0.0000 0.071637 1.9494 + 24 0.0000 0.091448 2.4884 + 25 0.0000 0.118937 3.2364 + 26 0.0000 0.151642 4.1264 + 27 0.0000 0.187064 5.0903 + 28 0.0000 0.192959 5.2507 + 29 0.0000 0.217268 5.9122 + 30 0.0000 0.272329 7.4104 + 31 0.0000 0.279961 7.6181 + + SPIN DOWN ORBITALS + NO OCC E(Eh) E(eV) + 0 1.0000 -101.510078 -2762.2296 + 1 1.0000 -19.195577 -522.3382 + 2 1.0000 -10.262075 -279.2453 + 3 1.0000 -10.190054 -277.2855 + 4 1.0000 -9.440261 -256.8826 + 5 1.0000 -7.196371 -195.8232 + 6 1.0000 -7.193986 -195.7583 + 7 1.0000 -7.193922 -195.7566 + 8 1.0000 -1.099556 -29.9204 + 9 1.0000 -0.777682 -21.1618 + 10 1.0000 -0.751656 -20.4536 + 11 1.0000 -0.654818 -17.8185 + 12 1.0000 -0.528168 -14.3722 + 13 1.0000 -0.511597 -13.9213 + 14 1.0000 -0.426258 -11.5991 + 15 1.0000 -0.415551 -11.3077 + 16 1.0000 -0.399106 -10.8602 + 17 1.0000 -0.297997 -8.1089 + 18 1.0000 -0.297399 -8.0926 + 19 1.0000 -0.254944 -6.9374 + 20 0.0000 -0.217177 -5.9097 + 21 0.0000 -0.001393 -0.0379 + 22 0.0000 0.009401 0.2558 + 23 0.0000 0.072408 1.9703 + 24 0.0000 0.093047 2.5320 + 25 0.0000 0.119857 3.2615 + 26 0.0000 0.153065 4.1651 + 27 0.0000 0.188230 5.1220 + 28 0.0000 0.198230 5.3941 + 29 0.0000 0.218204 5.9376 + 30 0.0000 0.273827 7.4512 +*Only the first 10 virtual orbitals were printed. + + ******************************** + * MULLIKEN POPULATION ANALYSIS * + ******************************** + +-------------------------------------------- +MULLIKEN ATOMIC CHARGES AND SPIN POPULATIONS +-------------------------------------------- + 0 O : -0.354661 0.050542 + 1 C : 0.109277 0.029843 + 2 C : -0.294467 0.160987 + 3 Cl: -0.192054 0.776127 + 4 H : 0.316672 -0.001426 + 5 H : 0.150776 -0.003279 + 6 H : 0.118841 -0.006042 + 7 H : 0.145616 -0.006751 +Sum of atomic charges : 0.0000000 +Sum of atomic spin populations: 1.0000000 + +----------------------------------------------------- +MULLIKEN REDUCED ORBITAL CHARGES AND SPIN POPULATIONS +----------------------------------------------------- +CHARGE + 0 O s : 3.771529 s : 3.771529 + pz : 1.762227 p : 4.550258 + px : 1.231532 + py : 1.556500 + dz2 : 0.004320 d : 0.031122 + dxz : 0.003493 + dyz : 0.003544 + dx2y2 : 0.004971 + dxy : 0.014794 + f0 : 0.000242 f : 0.001752 + f+1 : 0.000408 + f-1 : 0.000225 + f+2 : 0.000064 + f-2 : 0.000093 + f+3 : 0.000361 + f-3 : 0.000359 + + 1 C s : 3.172428 s : 3.172428 + pz : 0.883726 p : 2.584813 + px : 0.759614 + py : 0.941472 + dz2 : 0.004134 d : 0.120844 + dxz : 0.025795 + dyz : 0.021766 + dx2y2 : 0.019937 + dxy : 0.049211 + f0 : 0.002186 f : 0.012640 + f+1 : 0.001154 + f-1 : 0.000604 + f+2 : 0.001597 + f-2 : 0.001041 + f+3 : 0.003558 + f-3 : 0.002500 + + 2 C s : 3.280720 s : 3.280720 + pz : 1.026066 p : 2.978584 + px : 1.061532 + py : 0.890986 + dz2 : 0.005835 d : 0.030585 + dxz : 0.000818 + dyz : 0.008805 + dx2y2 : 0.004331 + dxy : 0.010797 + f0 : 0.001030 f : 0.004579 + f+1 : 0.000573 + f-1 : 0.000410 + f+2 : 0.000399 + f-2 : 0.000086 + f+3 : 0.000997 + f-3 : 0.001084 + + 3 Cls : 5.993241 s : 5.993241 + pz : 3.226891 p : 11.196265 + px : 3.982716 + py : 3.986658 + dz2 : 0.001096 d : 0.002198 + dxz : 0.000227 + dyz : 0.000011 + dx2y2 : 0.000336 + dxy : 0.000527 + f0 : 0.000137 f : 0.000351 + f+1 : 0.000096 + f-1 : 0.000092 + f+2 : 0.000002 + f-2 : 0.000000 + f+3 : 0.000008 + f-3 : 0.000016 + + 4 H s : 0.637654 s : 0.637654 + pz : 0.014702 p : 0.045673 + px : 0.016021 + py : 0.014951 + + 5 H s : 0.826264 s : 0.826264 + pz : 0.004149 p : 0.022960 + px : 0.010581 + py : 0.008231 + + 6 H s : 0.858830 s : 0.858830 + pz : 0.005253 p : 0.022329 + px : 0.008624 + py : 0.008452 + + 7 H s : 0.830165 s : 0.830165 + pz : 0.005650 p : 0.024219 + px : 0.014029 + py : 0.004540 + + +SPIN + 0 O s : 0.001935 s : 0.001935 + pz : 0.046961 p : 0.048727 + px : 0.001460 + py : 0.000307 + dz2 : -0.000023 d : -0.000085 + dxz : 0.000053 + dyz : -0.000112 + dx2y2 : -0.000004 + dxy : 0.000002 + f0 : -0.000016 f : -0.000035 + f+1 : -0.000014 + f-1 : -0.000009 + f+2 : -0.000002 + f-2 : 0.000007 + f+3 : -0.000000 + f-3 : -0.000000 + + 1 C s : 0.000478 s : 0.000478 + pz : 0.029029 p : 0.025328 + px : -0.001150 + py : -0.002551 + dz2 : -0.000079 d : 0.003873 + dxz : 0.000196 + dyz : 0.003833 + dx2y2 : 0.000035 + dxy : -0.000112 + f0 : -0.000022 f : 0.000165 + f+1 : -0.000037 + f-1 : -0.000036 + f+2 : 0.000243 + f-2 : 0.000002 + f+3 : 0.000011 + f-3 : 0.000004 + + 2 C s : 0.007751 s : 0.007751 + pz : 0.144877 p : 0.152890 + px : 0.005332 + py : 0.002681 + dz2 : -0.000703 d : 0.000549 + dxz : 0.000088 + dyz : 0.000810 + dx2y2 : 0.000193 + dxy : 0.000160 + f0 : -0.000031 f : -0.000203 + f+1 : -0.000123 + f-1 : -0.000115 + f+2 : 0.000059 + f-2 : 0.000005 + f+3 : 0.000003 + f-3 : -0.000001 + + 3 Cls : 0.000632 s : 0.000632 + pz : 0.772411 p : 0.774617 + px : 0.001255 + py : 0.000951 + dz2 : 0.000656 d : 0.000577 + dxz : -0.000068 + dyz : -0.000003 + dx2y2 : -0.000003 + dxy : -0.000006 + f0 : 0.000128 f : 0.000300 + f+1 : 0.000085 + f-1 : 0.000088 + f+2 : -0.000000 + f-2 : -0.000000 + f+3 : -0.000000 + f-3 : -0.000000 + + 4 H s : -0.001705 s : -0.001705 + pz : 0.000297 p : 0.000279 + px : -0.000002 + py : -0.000016 + + 5 H s : -0.003273 s : -0.003273 + pz : 0.000000 p : -0.000006 + px : -0.000018 + py : 0.000012 + + 6 H s : -0.006782 s : -0.006782 + pz : 0.000681 p : 0.000740 + px : 0.000035 + py : 0.000024 + + 7 H s : -0.007383 s : -0.007383 + pz : 0.000575 p : 0.000632 + px : 0.000049 + py : 0.000008 + + + + ******************************* + * LOEWDIN POPULATION ANALYSIS * + ******************************* + +------------------------------------------- +LOEWDIN ATOMIC CHARGES AND SPIN POPULATIONS +------------------------------------------- + 0 O : 0.098693 0.046403 + 1 C : -0.294734 0.045753 + 2 C : -0.218586 0.133980 + 3 Cl: -0.159862 0.776096 + 4 H : 0.194306 0.000117 + 5 H : 0.133969 -0.001086 + 6 H : 0.119574 -0.000188 + 7 H : 0.126641 -0.001076 + +---------------------------------------------------- +LOEWDIN REDUCED ORBITAL CHARGES AND SPIN POPULATIONS +---------------------------------------------------- +CHARGE + 0 O s : 3.331927 s : 3.331927 + pz : 1.650085 p : 4.488605 + px : 1.289457 + py : 1.549063 + dz2 : 0.008655 d : 0.075658 + dxz : 0.010533 + dyz : 0.003780 + dx2y2 : 0.016710 + dxy : 0.035979 + f0 : 0.000401 f : 0.005118 + f+1 : 0.000885 + f-1 : 0.000301 + f+2 : 0.000176 + f-2 : 0.000405 + f+3 : 0.001939 + f-3 : 0.001012 + + 1 C s : 2.815116 s : 2.815116 + pz : 0.843998 p : 2.839152 + px : 0.887030 + py : 1.108124 + dz2 : 0.036032 d : 0.559581 + dxz : 0.083676 + dyz : 0.078083 + dx2y2 : 0.130232 + dxy : 0.231557 + f0 : 0.006373 f : 0.080886 + f+1 : 0.007815 + f-1 : 0.005711 + f+2 : 0.012437 + f-2 : 0.006207 + f+3 : 0.025054 + f-3 : 0.017289 + + 2 C s : 2.868737 s : 2.868737 + pz : 0.962053 p : 3.109813 + px : 1.050775 + py : 1.096985 + dz2 : 0.017824 d : 0.213016 + dxz : 0.001639 + dyz : 0.027526 + dx2y2 : 0.066060 + dxy : 0.099967 + f0 : 0.002027 f : 0.027020 + f+1 : 0.002773 + f-1 : 0.004452 + f+2 : 0.003134 + f-2 : 0.000586 + f+3 : 0.007101 + f-3 : 0.006947 + + 3 Cls : 5.982100 s : 5.982100 + pz : 3.225606 p : 11.175101 + px : 3.961746 + py : 3.987750 + dz2 : 0.001089 d : 0.002294 + dxz : 0.000219 + dyz : 0.000012 + dx2y2 : 0.000283 + dxy : 0.000690 + f0 : 0.000138 f : 0.000367 + f+1 : 0.000100 + f-1 : 0.000094 + f+2 : 0.000002 + f-2 : 0.000001 + f+3 : 0.000009 + f-3 : 0.000023 + + 4 H s : 0.657306 s : 0.657306 + pz : 0.038854 p : 0.148388 + px : 0.048044 + py : 0.061490 + + 5 H s : 0.804337 s : 0.804337 + pz : 0.011573 p : 0.061694 + px : 0.027827 + py : 0.022294 + + 6 H s : 0.817663 s : 0.817663 + pz : 0.014944 p : 0.062762 + px : 0.026024 + py : 0.021795 + + 7 H s : 0.806047 s : 0.806047 + pz : 0.015531 p : 0.067312 + px : 0.038872 + py : 0.012909 + + +SPIN + 0 O s : 0.000873 s : 0.000873 + pz : 0.043897 p : 0.044811 + px : 0.000763 + py : 0.000151 + dz2 : 0.000008 d : 0.000682 + dxz : 0.000692 + dyz : 0.000120 + dx2y2 : -0.000033 + dxy : -0.000105 + f0 : 0.000025 f : 0.000038 + f+1 : -0.000013 + f-1 : -0.000007 + f+2 : 0.000008 + f-2 : 0.000032 + f+3 : -0.000005 + f-3 : -0.000001 + + 1 C s : 0.000066 s : 0.000066 + pz : 0.029934 p : 0.027914 + px : -0.000921 + py : -0.001099 + dz2 : -0.000062 d : 0.015812 + dxz : 0.002827 + dyz : 0.012313 + dx2y2 : 0.000481 + dxy : 0.000253 + f0 : 0.000100 f : 0.001961 + f+1 : -0.000014 + f-1 : -0.000047 + f+2 : 0.001713 + f-2 : 0.000109 + f+3 : 0.000036 + f-3 : 0.000063 + + 2 C s : 0.003083 s : 0.003083 + pz : 0.128967 p : 0.131629 + px : 0.001593 + py : 0.001069 + dz2 : -0.000633 d : -0.000517 + dxz : 0.000076 + dyz : 0.000434 + dx2y2 : -0.000052 + dxy : -0.000341 + f0 : -0.000058 f : -0.000215 + f+1 : -0.000119 + f-1 : -0.000138 + f+2 : 0.000150 + f-2 : 0.000008 + f+3 : -0.000023 + f-3 : -0.000035 + + 3 Cls : 0.000158 s : 0.000158 + pz : 0.773208 p : 0.774977 + px : 0.001258 + py : 0.000511 + dz2 : 0.000720 d : 0.000652 + dxz : -0.000057 + dyz : -0.000002 + dx2y2 : -0.000001 + dxy : -0.000009 + f0 : 0.000129 f : 0.000310 + f+1 : 0.000093 + f-1 : 0.000089 + f+2 : -0.000000 + f-2 : 0.000000 + f+3 : -0.000000 + f-3 : -0.000000 + + 4 H s : -0.001096 s : -0.001096 + pz : 0.001073 p : 0.001212 + px : 0.000084 + py : 0.000056 + + 5 H s : -0.001200 s : -0.001200 + pz : 0.000167 p : 0.000114 + px : -0.000063 + py : 0.000010 + + 6 H s : -0.002880 s : -0.002880 + pz : 0.002263 p : 0.002693 + px : 0.000238 + py : 0.000192 + + 7 H s : -0.003284 s : -0.003284 + pz : 0.001874 p : 0.002208 + px : 0.000294 + py : 0.000041 + + + + ***************************** + * MAYER POPULATION ANALYSIS * + ***************************** + + NA - Mulliken gross atomic population + ZA - Total nuclear charge + QA - Mulliken gross atomic charge + VA - Mayer's total valence + BVA - Mayer's bonded valence + FA - Mayer's free valence + + ATOM NA ZA QA VA BVA FA + 0 O 8.3547 8.0000 -0.3547 2.1498 2.1473 0.0024 + 1 C 5.8907 6.0000 0.1093 3.8978 3.8962 0.0016 + 2 C 6.2945 6.0000 -0.2945 3.8228 3.8007 0.0220 + 3 Cl 17.1921 17.0000 -0.1921 1.0258 0.4216 0.6042 + 4 H 0.6833 1.0000 0.3167 0.9165 0.9165 0.0000 + 5 H 0.8492 1.0000 0.1508 1.0030 1.0030 0.0000 + 6 H 0.8812 1.0000 0.1188 0.9768 0.9767 0.0000 + 7 H 0.8544 1.0000 0.1456 1.0159 1.0159 0.0000 + + Mayer bond orders larger than 0.100000 +B( 0-O , 1-C ) : 1.1669 B( 0-O , 4-H ) : 0.8781 B( 1-C , 2-C ) : 1.6879 +B( 1-C , 5-H ) : 0.9411 B( 2-C , 3-Cl) : 0.1765 B( 2-C , 6-H ) : 0.9654 +B( 2-C , 7-H ) : 0.9453 + +------- +TIMINGS +------- + +Total SCF time: 0 days 0 hours 0 min 22 sec + +Total time .... 22.724 sec +Sum of individual times .... 29.236 sec (128.7%) + +SCF preparation .... 1.446 sec ( 6.4%) +Fock matrix formation .... 20.220 sec ( 89.0%) + Startup .... 0.062 sec ( 0.3% of F) + Split-RI-J .... 0.912 sec ( 4.5% of F) + Chain of spheres X .... 13.524 sec ( 66.9% of F) + XC integration .... 5.516 sec ( 27.3% of F) + XC Preparation .... 0.000 sec ( 0.0% of XC) + Basis function eval. .... 0.960 sec ( 17.4% of XC) + Density eval. .... 0.921 sec ( 16.7% of XC) + XC-Functional eval. .... 0.387 sec ( 7.0% of XC) + XC-Potential eval. .... 1.680 sec ( 30.5% of XC) +Diagonalization .... 0.000 sec ( 0.0%) +Density matrix formation .... 0.110 sec ( 0.5%) +Total Energy calculation .... 0.107 sec ( 0.5%) +Population analysis .... 0.033 sec ( 0.1%) +Orbital Transformation .... 0.082 sec ( 0.4%) +Orbital Orthonormalization .... 0.000 sec ( 0.0%) +DIIS solution .... 0.423 sec ( 1.9%) +SOSCF solution .... 0.282 sec ( 1.2%) +SCF Stability Analysis .... 6.534 sec ( 28.8%) +Finished LeanSCF after 29.3 sec + +Maximum memory used throughout the entire LEANSCF-calculation: 39.7 MB + +------------------------- -------------------- +FINAL SINGLE POINT ENERGY -613.900052515387 +------------------------- -------------------- + + + + ************************************************************ + * Program running with 8 parallel MPI-processes * + * working on a common directory * + ************************************************************ + +------------------------------------------------------------------------------ + ORCA PROPERTY CALCULATIONS +------------------------------------------------------------------------------ + +GBWName ... input.gbw +Number of atoms ... 8 +Number of basis functions ... 154 +Max core memory ... 3500 MB + +Electric properties: +Dipole moment ... YES +Quadrupole moment ... NO +Static polarizability (Dipole/Dipole) ... NO +Static polarizability (Dipole/Quad.) ... NO +Static polarizability (Quad./Quad.) ... NO +Static polarizability (Velocity) ... NO + +Atomic electric properties: +Dipole moment ... NO +Quadrupole moment ... NO +Static polarizability ... NO + +Choice of electric origin ... Center of mass +Position of electric origin ... -0.203002 -0.063051 -0.000007 + +General magnetic properties: +Magnetizability ... NO + +EPR properties: +g-Tensor (aka g-matrix) ... NO +Zero-Field splitting spin-orbit ... NO +Zero-field splitting spin-spin ... NO +Hyperfine couplings ... NO ( 0 nuclei) +Quadrupole couplings ... NO ( 0 nuclei) +Contact density ... NO ( 0 nuclei) + +NMR properties: +Chemical shifts ... NO ( 0 nuclei) +Spin-rotation constants ... NO ( 0 nuclei) +Spin-spin couplings ... NO ( 0 nuclei, 0 pairs) + +Choice of magnetic origin ... GIAO +Position of magnetic origin ... 0.000000 0.000000 0.000000 + +Properties with geometric perturbations: +SCF Hessian ... NO +IR spectrum ... NO +VCD spectrum ... NO +X-ray spectroscopy properties: +SCF XES/XAS/RIXS spectra ... NO + + +------------- +DIPOLE MOMENT +------------- + +Method : SCF +Type of density : Electron Density +Multiplicity : 2 +Irrep : 0 +Energy : -613.9000525153869603 Eh +Relativity type : +Basis : AO + X Y Z +Electronic contribution: -6.869584749 -2.053267588 -0.000296132 +Nuclear contribution : 8.323184450 2.585105134 0.000361128 + ----------------------------------------- +Total Dipole Moment : 1.453599701 0.531837547 0.000064996 + ----------------------------------------- +Magnitude (a.u.) : 1.547838257 +Magnitude (Debye) : 3.934292187 + + + +-------------------- +Rotational spectrum +-------------------- + +Rotational constants in cm-1: 0.512609 0.053209 0.048206 +Rotational constants in MHz : 15367.624774 1595.177982 1445.167820 + +Dipole components along the rotational axes: +x,y,z [a.u.] : 1.448848 -0.544650 -0.000001 +x,y,z [Debye]: 3.682678 -1.384390 -0.000002 + + + +Dipole moment calculation done in 0.0 sec + +Maximum memory used throughout the entire PROP-calculation: 6.5 MB + +-------------------------------- +SUGGESTED CITATIONS FOR THIS RUN +-------------------------------- + +Below you find a list of papers that are relevant to this ORCA run +We neither can nor want to force you to cite these papers, but we appreciate if you do +You receive ORCA, which is the product of decades of hard work by many enthusiastic individuals, for free +The only thing we kindly ask in return is that you cite our papers, +We deeply appreciate it, if you show your appreciation for ORCA by not just citing the generic ORCA reference. + +Please note that relegating all ORCA citations to the supporting information does *not* help us. +SI sections are not indexed - citations you put there will not count into any citation statistics +But we need these citations in order to attract the funding resources that allow us to do what we are doing + +Therefore, if you are a happy ORCA user, please consider citing a few of the papers listed below in the main body of your paper + +In addition to the list printed below, the program has created the file input.bibtex that contains the list in bibtex format +You can import this file easily into all common literature databanks and citation aid programs + + +List of essential papers. We consider these as the minimum necessary citations + + 1. Neese,F. + Software update: the ORCA program system, version 5.0 + WIRES Comput. Molec. Sci., 2022 12(1)e1606 + doi.org/10.1002/wcms.1606 + +List of papers to cite with high priority. The work reported in these papers was absolutely +necessary for this run to complete. +Our perspective: the developers of density functionals and basis sets usually get cited in chemistry papers +Good! But without the algorithms to do something with them, the functionals or basis sets would not do anything. +Hence, in our opinion, the algorithm design and method developments papers are equally worthy of getting cited + + 1. Neese,F. + An improvement of the resolution of the identity approximation for the formation of the Coulomb matrix + J. Comp. Chem., 2003 24(14)1740-1747 + doi.org/10.1002/jcc.10318 + 2. Neese,F.; Wennmohs,F.; Hansen,A.; Becker,U. + Efficient, approximate and parallel Hartree-Fock and hybrid DFT calculations. A 'chain-of-spheres' algorithm for the Hartree-Fock exchange + Chem. Phys., 2009 356(1-3)98-109 + doi.org/10.1016/j.chemphys.2008.10.036 + 3. Helmich-Paris,B.; de Souza,B.; Neese,F.; Izsák,R. + An improved chain of spheres for exchange algorithm + J. Chem. Phys., 2021 155 104109 + doi.org/doi: 10.1063/5.0058766. + 4. Neese,F. + The SHARK Integral Generation and Digestion System + J. Comp. Chem., 2022 1-16 + doi.org/10.1002/jcc.26942 + +List of suggested additional citations. These are papers that are important in the 'surrounding' of +of this run, or papers that preceded the highly important papers. If you like your results we are grateful for a citation. + + 1. Izsak,R.; Neese,F. + An overlap fitted chain of spheres exchange method + J. Chem. Phys., 2011 135 144105 + doi.org/10.1063/1.3646921 + 2. Izsak,R.; Hansen,A.; Neese,F. + The resolution of identity and chain of spheres approximations for the LPNO-CCSD singles Fock term + Molec. Phys., 2012 110 2413-2417 + doi.org/10.1080/00268976.2012.687466 + 3. Neese,F. + The ORCA program system + WIRES Comput. Molec. Sci., 2012 2(1)73-78 + doi.org/10.1002/wcms.81 + 4. Izsak,R.; Neese,F.; Klopper,W. + Robust fitting techniques in the chain of spheres approximation to the Fock exchange: The role of the complementary space + J. Chem. Phys., 2013 139 + doi.org/10.1063/1.4819264 + 5. Neese,F. + Software update: the ORCA program system, version 4.0 + WIRES Comput. Molec. Sci., 2018 8(1)1-6 + doi.org/10.1002/wcms.1327 + 6. Neese,F.; Wennmohs,F.; Becker,U.; Riplinger,C. + The ORCA quantum chemistry program package + J. Chem. Phys., 2020 152 Art. No. L224108 + doi.org/10.1063/5.0004608 + +List of optional additional citations + + 1. Neese,F. + Approximate second-order SCF convergence for spin unrestricted wavefunctions + Chem. Phys. Lett., 2000 325(1-3)93-98 + doi.org/10.1016/s0009-2614(00)00662-x + +Timings for individual modules: + +Sum of individual times ... 38.858 sec (= 0.648 min) +Startup calculation ... 4.313 sec (= 0.072 min) 11.1 % +SCF iterations ... 32.455 sec (= 0.541 min) 83.5 % +Property calculations ... 2.091 sec (= 0.035 min) 5.4 % + ****ORCA TERMINATED NORMALLY**** +TOTAL RUN TIME: 0 days 0 hours 0 minutes 41 seconds 600 msec diff --git a/arc/testing/stability/rhf_uhf_instability_singlet_ts.out b/arc/testing/stability/rhf_uhf_instability_singlet_ts.out new file mode 100644 index 0000000000..1e6f50308e --- /dev/null +++ b/arc/testing/stability/rhf_uhf_instability_singlet_ts.out @@ -0,0 +1,952 @@ + Entering Gaussian System, Link 0=g16 + Initial command: + /usr/local/g16-gpu/g16/l1.exe "/scratch/g16/job/Gau-1868569.inp" -scrdir="/scratch/g16/job/" + Entering Link 1 = /usr/local/g16-gpu/g16/l1.exe PID= 1868578. + + Copyright (c) 1988-2021, Gaussian, Inc. All Rights Reserved. + + This is part of the Gaussian(R) 16 program. It is based on + the Gaussian(R) 09 system (copyright 2009, Gaussian, Inc.), + the Gaussian(R) 03 system (copyright 2003, Gaussian, Inc.), + the Gaussian(R) 98 system (copyright 1998, Gaussian, Inc.), + the Gaussian(R) 94 system (copyright 1995, Gaussian, Inc.), + the Gaussian 92(TM) system (copyright 1992, Gaussian, Inc.), + the Gaussian 90(TM) system (copyright 1990, Gaussian, Inc.), + the Gaussian 88(TM) system (copyright 1988, Gaussian, Inc.), + the Gaussian 86(TM) system (copyright 1986, Carnegie Mellon + University), and the Gaussian 82(TM) system (copyright 1983, + Carnegie Mellon University). Gaussian is a federally registered + trademark of Gaussian, Inc. + + This software contains proprietary and confidential information, + including trade secrets, belonging to Gaussian, Inc. + + This software is provided under written license and may be + used, copied, transmitted, or stored only in accord with that + written license. + + The following legend is applicable only to US Government + contracts under FAR: + + RESTRICTED RIGHTS LEGEND + + Use, reproduction and disclosure by the US Government is + subject to restrictions as set forth in subparagraphs (a) + and (c) of the Commercial Computer Software - Restricted + Rights clause in FAR 52.227-19. + + Gaussian, Inc. + 340 Quinnipiac St., Bldg. 40, Wallingford CT 06492 + + + --------------------------------------------------------------- + Warning -- This program may not be used in any manner that + competes with the business of Gaussian, Inc. or will provide + assistance to any competitor of Gaussian, Inc. The licensee + of this program is prohibited from giving any competitor of + Gaussian, Inc. access to this program. By using this program, + the user acknowledges that Gaussian, Inc. is engaged in the + business of creating and licensing software in the field of + computational chemistry and represents and warrants to the + licensee that it is not a competitor of Gaussian, Inc. and that + it will not use this program in any manner prohibited above. + --------------------------------------------------------------- + + + Cite this work as: + Gaussian 16, Revision C.02, + M. J. Frisch, G. W. Trucks, H. B. Schlegel, G. E. Scuseria, + M. A. Robb, J. R. Cheeseman, G. Scalmani, V. Barone, + G. A. Petersson, H. Nakatsuji, X. Li, M. Caricato, A. V. Marenich, + J. Bloino, B. G. Janesko, R. Gomperts, B. Mennucci, H. P. Hratchian, + J. V. Ortiz, A. F. Izmaylov, J. L. Sonnenberg, D. Williams-Young, + F. Ding, F. Lipparini, F. Egidi, J. Goings, B. Peng, A. Petrone, + T. Henderson, D. Ranasinghe, V. G. Zakrzewski, J. Gao, N. Rega, + G. Zheng, W. Liang, M. Hada, M. Ehara, K. Toyota, R. Fukuda, + J. Hasegawa, M. Ishida, T. Nakajima, Y. Honda, O. Kitao, H. Nakai, + T. Vreven, K. Throssell, J. A. Montgomery, Jr., J. E. Peralta, + F. Ogliaro, M. J. Bearpark, J. J. Heyd, E. N. Brothers, K. N. Kudin, + V. N. Staroverov, T. A. Keith, R. Kobayashi, J. Normand, + K. Raghavachari, A. P. Rendell, J. C. Burant, S. S. Iyengar, + J. Tomasi, M. Cossi, J. M. Millam, M. Klene, C. Adamo, R. Cammi, + J. W. Ochterski, R. L. Martin, K. Morokuma, O. Farkas, + J. B. Foresman, and D. J. Fox, Gaussian, Inc., Wallingford CT, 2019. + + ****************************************** + Gaussian 16: ES64L-G16RevC.02 7-Dec-2021 + 13-Aug-2026 + ****************************************** + %mem=16000mb + %NProcShared=8 + Will use up to 8 processors via shared memory. + %chk=check.chk + ---------------------------------------------------------------------- + #P b3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, Acc2E= + 12) scf=(direct,tight) + ---------------------------------------------------------------------- + 1/38=1,172=1/1; + 2/12=2,17=6,18=5,40=1/2; + 3/5=44,7=101,11=2,25=1,27=12,30=1,74=-5,75=-5/1,2,3; + 4//1; + 5/5=2,32=2,38=5,87=12/2; + 8/6=1,10=90,11=11,87=12/1; + 9/8=-1,42=1,87=12/14; + 6/7=2,8=2,9=2,10=2,28=1,87=12/1; + 99/5=1,9=1/99; + Leave Link 1 at Thu Aug 13 03:09:37 2026, MaxMem= 2097152000 cpu: 0.0 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l101.exe) + ------------------------------------------------- + stability test reaction_08_intra_rh_add_exocyclic + ------------------------------------------------- + Symbolic Z-matrix: + Charge = 0 Multiplicity = 1 + C 0.42654 1.47789 -0.00008 + C 0.49428 0.01192 0. + C 1.79226 -0.71266 0.00004 + C -0.76953 -0.70318 0.00004 + C -2.09552 -0.11756 0.00001 + H 1.39854 1.97009 -0.00011 + H -0.16267 1.83052 -0.8669 + H 2.40601 -0.45645 -0.87511 + H 2.406 -0.45637 0.87517 + H 1.65287 -1.79552 0.00009 + H -0.701 -1.41388 0.84851 + H -0.70101 -1.41397 -0.84837 + H -2.27706 0.94605 -0.00004 + H -0.16266 1.83061 0.86672 + H -2.94717 -0.77952 0.00004 + + ITRead= 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + MicOpt= -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 + NAtoms= 15 NQM= 15 NQMF= 0 NMMI= 0 NMMIF= 0 + NMic= 0 NMicF= 0. + Isotopes and Nuclear Properties: + (Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) + in nuclear magnetons) + + Atom 1 2 3 4 5 6 7 8 9 10 + IAtWgt= 12 12 12 12 12 1 1 1 1 1 + AtmWgt= 12.0000000 12.0000000 12.0000000 12.0000000 12.0000000 1.0078250 1.0078250 1.0078250 1.0078250 1.0078250 + NucSpn= 0 0 0 0 0 1 1 1 1 1 + AtZEff= -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 2.7928460 2.7928460 2.7928460 2.7928460 2.7928460 + AtZNuc= 6.0000000 6.0000000 6.0000000 6.0000000 6.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 + + Atom 11 12 13 14 15 + IAtWgt= 1 1 1 1 1 + AtmWgt= 1.0078250 1.0078250 1.0078250 1.0078250 1.0078250 + NucSpn= 1 1 1 1 1 + AtZEff= -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 2.7928460 2.7928460 2.7928460 2.7928460 2.7928460 + AtZNuc= 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 + Leave Link 101 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l202.exe) + Input orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 6 0 0.426535 1.477892 -0.000077 + 2 6 0 0.494278 0.011915 -0.000003 + 3 6 0 1.792259 -0.712657 0.000036 + 4 6 0 -0.769525 -0.703182 0.000035 + 5 6 0 -2.095524 -0.117561 0.000011 + 6 1 0 1.398544 1.970089 -0.000109 + 7 1 0 -0.162672 1.830519 -0.866904 + 8 1 0 2.406008 -0.456448 -0.875111 + 9 1 0 2.406000 -0.456368 0.875165 + 10 1 0 1.652868 -1.795523 0.000085 + 11 1 0 -0.701001 -1.413883 0.848513 + 12 1 0 -0.701006 -1.413967 -0.848372 + 13 1 0 -2.277062 0.946049 -0.000035 + 14 1 0 -0.162658 1.830608 0.866722 + 15 1 0 -2.947166 -0.779520 0.000039 + --------------------------------------------------------------------- + Distance matrix (angstroms): + 1 2 3 4 5 + 1 C 0.000000 + 2 C 1.467541 0.000000 + 3 C 2.581416 1.486526 0.000000 + 4 C 2.487497 1.452089 2.561802 0.000000 + 5 C 2.984334 2.593037 3.933064 1.449560 0.000000 + 6 H 1.089523 2.156883 2.711483 3.441933 4.070233 + 7 H 1.105848 2.119061 3.322813 2.745814 2.877929 + 8 H 2.902700 2.154040 1.099187 3.303145 4.598312 + 9 H 2.902704 2.154040 1.099187 3.303139 4.598304 + 10 H 3.495588 2.146896 1.091801 2.657291 4.106823 + 11 H 3.217733 2.044889 2.725431 1.108921 2.084491 + 12 H 3.217732 2.044890 2.725436 1.108920 2.084491 + 13 H 2.755412 2.924540 4.394392 2.234420 1.078991 + 14 H 1.105847 2.119061 3.322806 2.745820 2.877937 + 15 H 4.059282 3.531275 4.739897 2.178979 1.078649 + 6 7 8 9 10 + 6 H 0.000000 + 7 H 1.791147 0.000000 + 8 H 2.769241 3.439244 0.000000 + 9 H 2.769254 3.855221 1.750276 0.000000 + 10 H 3.774191 4.146810 1.768137 1.768137 0.000000 + 11 H 4.071795 3.709258 3.679819 3.251308 2.531043 + 12 H 4.071793 3.288896 3.251322 3.679818 2.531045 + 13 H 3.815591 2.450387 4.966276 4.966268 4.791719 + 14 H 1.791146 1.733626 3.855211 3.439235 4.146808 + 15 H 5.142523 3.913732 5.433851 5.433844 4.710900 + 11 12 13 14 15 + 11 H 0.000000 + 12 H 1.696885 0.000000 + 13 H 2.961972 2.961976 0.000000 + 14 H 3.288901 3.709263 2.450391 0.000000 + 15 H 2.483462 2.483457 1.851115 3.913744 0.000000 + Stoichiometry C5H10 + Framework group C1[X(C5H10)] + Deg. of freedom 39 + Full point group C1 NOp 1 + Largest Abelian subgroup C1 NOp 1 + Largest concise Abelian subgroup C1 NOp 1 + Standard orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 6 0 0.426535 1.477892 -0.000077 + 2 6 0 0.494278 0.011915 -0.000003 + 3 6 0 1.792259 -0.712657 0.000036 + 4 6 0 -0.769525 -0.703182 0.000035 + 5 6 0 -2.095524 -0.117561 0.000011 + 6 1 0 1.398544 1.970089 -0.000109 + 7 1 0 -0.162672 1.830519 -0.866904 + 8 1 0 2.406008 -0.456448 -0.875111 + 9 1 0 2.406000 -0.456368 0.875165 + 10 1 0 1.652868 -1.795523 0.000085 + 11 1 0 -0.701001 -1.413883 0.848513 + 12 1 0 -0.701006 -1.413967 -0.848372 + 13 1 0 -2.277062 0.946049 -0.000035 + 14 1 0 -0.162658 1.830608 0.866722 + 15 1 0 -2.947166 -0.779520 0.000039 + --------------------------------------------------------------------- + Rotational constants (GHZ): 8.0496015 3.6257695 2.6165098 + Leave Link 202 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l301.exe) + Standard basis: def2TZVP (5D, 7F) + Ernie: Thresh= 0.10000D-02 Tol= 0.10000D-05 Strict=F. + There are 240 symmetry adapted cartesian basis functions of A symmetry. + There are 215 symmetry adapted basis functions of A symmetry. + 215 basis functions, 335 primitive gaussians, 240 cartesian basis functions + 20 alpha electrons 20 beta electrons + nuclear repulsion energy 175.2833562378 Hartrees. + IExCor= 402 DFT=T Ex+Corr=B3LYP ExCW=0 ScaHFX= 0.200000 + ScaDFX= 0.800000 0.720000 1.000000 0.810000 ScalE2= 1.000000 1.000000 + IRadAn= 5 IRanWt= -1 IRanGd= 0 ICorTp=0 IEmpDi= 4 + NAtoms= 15 NActive= 15 NUniq= 15 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F + Integral buffers will be 131072 words long. + Raffenetti 2 integral format. + Two-electron integral symmetry is turned on. + Leave Link 301 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l302.exe) + NPDir=0 NMtPBC= 1 NCelOv= 1 NCel= 1 NClECP= 1 NCelD= 1 + NCelK= 1 NCelE2= 1 NClLst= 1 CellRange= 0.0. + One-electron integrals computed using PRISM. + One-electron integral symmetry used in STVInt + 1 Symmetry operations used in ECPInt. + ECPInt: NShTT= 4560 NPrTT= 13020 LenC2= 4531 LenP2D= 10932. + LDataN: DoStor=T MaxTD1= 6 Len= 172 + NBasis= 215 RedAO= T EigKep= 1.55D-04 NBF= 215 + NBsUse= 215 1.00D-06 EigRej= -1.00D+00 NBFU= 215 + Precomputing XC quadrature grid using + IXCGrd= 4 IRadAn= 5 IRanWt= -1 IRanGd= 0 AccXCQ= 1.00D-12. + Generated NRdTot= 0 NPtTot= 0 NUsed= 0 NTot= 32 + NSgBfM= 239 239 239 239 239 MxSgAt= 15 MxSgA2= 15. + Leave Link 302 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 1.0 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l303.exe) + DipDrv: MaxL=1. + Leave Link 303 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l401.exe) + ExpMin= 9.52D-02 ExpMax= 1.36D+04 ExpMxC= 4.63D+02 IAcc=3 IRadAn= 5 AccDes= 0.00D+00 + Harris functional with IExCor= 402 and IRadAn= 5 diagonalized for initial guess. + HarFok: IExCor= 402 AccDes= 0.00D+00 IRadAn= 5 IDoV= 1 UseB2=F ITyADJ=14 + ICtDFT= 3500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000 + FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0 + NFxFlg= 0 DoJE=T BraDBF=F KetDBF=T FulRan=T + wScrn= 0.000000 ICntrl= 500 IOpCl= 0 I1Cent= 200000004 NGrid= 0 + NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Petite list used in FoFCou. + Harris En= -196.585055363282 + JPrj=0 DoOrth=F DoCkMO=F. + Leave Link 401 at Thu Aug 13 03:09:40 2026, MaxMem= 2097152000 cpu: 4.1 elap: 0.7 + (Enter /usr/local/g16-gpu/g16/l502.exe) + Integral symmetry usage will be decided dynamically. + Closed shell SCF: + Using DIIS extrapolation, IDIIS= 1040. + NGot= 2097152000 LenX= 2097032154 LenY= 2096974113 + Requested convergence on RMS density matrix=1.00D-08 within 128 cycles. + Requested convergence on MAX density matrix=1.00D-06. + Requested convergence on energy=1.00D-06. + No special actions if energy rises. + Fock matrices will be formed incrementally for 20 cycles. + Integral accuracy reduced to 1.0D-05 until final iterations. + + Cycle 1 Pass 0 IDiag 1: + FoFJK: IHMeth= 1 ICntrl= 0 DoSepK=F KAlg= 0 I1Cent= 0 FoldK=F + IRaf= 980000000 NMat= 1 IRICut= 1 DoRegI=T DoRafI=F ISym2E= 0 IDoP0=0 IntGTp=1. + FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 0 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + E= -196.175201054756 + DIIS: error= 4.11D-02 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -196.175201054756 IErMin= 1 ErrMin= 4.11D-02 + ErrMax= 4.11D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.96D-01 BMatP= 2.96D-01 + IDIUse=3 WtCom= 5.89D-01 WtEn= 4.11D-01 + Coeff-Com: 0.100D+01 + Coeff-En: 0.100D+01 + Coeff: 0.100D+01 + Gap= -0.093 Goal= None Shift= 0.000 + GapD= -0.093 DampG=0.250 DampE=0.500 DampFc=0.2500 IDamp=-1. + Damping current iteration by 2.50D-01 + RMSDP=6.58D-03 MaxDP=2.04D-01 OVMax= 8.43D-01 + + Cycle 2 Pass 0 IDiag 1: + RMSU= 1.62D-03 CP: 9.70D-01 + E= -196.298076373743 Delta-E= -0.122875318987 Rises=F Damp=T + DIIS: error= 1.69D-02 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 2 EnMin= -196.298076373743 IErMin= 2 ErrMin= 1.69D-02 + ErrMax= 1.69D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.15D-02 BMatP= 2.96D-01 + IDIUse=3 WtCom= 8.31D-01 WtEn= 1.69D-01 + Coeff-Com: -0.456D+00 0.146D+01 + Coeff-En: 0.000D+00 0.100D+01 + Coeff: -0.379D+00 0.138D+01 + Gap= 0.104 Goal= None Shift= 0.000 + RMSDP=2.44D-03 MaxDP=1.37D-01 DE=-1.23D-01 OVMax= 9.04D-01 + + Cycle 3 Pass 0 IDiag 1: + RMSU= 2.24D-03 CP: 9.46D-01 4.32D-01 + E= -196.279057812271 Delta-E= 0.019018561471 Rises=F Damp=F + DIIS: error= 2.49D-02 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 2 EnMin= -196.298076373743 IErMin= 2 ErrMin= 1.69D-02 + ErrMax= 2.49D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.50D-01 BMatP= 6.15D-02 + IDIUse=2 WtCom= 0.00D+00 WtEn= 1.00D+00 + Coeff-En: 0.000D+00 0.540D+00 0.460D+00 + Coeff: 0.000D+00 0.540D+00 0.460D+00 + Gap= -0.078 Goal= None Shift= 0.000 + RMSDP=4.42D-03 MaxDP=1.85D-01 DE= 1.90D-02 OVMax= 8.85D-01 + + Cycle 4 Pass 0 IDiag 1: + RMSU= 1.75D-03 CP: 9.22D-01 2.25D+00 -2.48D-01 + E= -195.926823100101 Delta-E= 0.352234712171 Rises=F Damp=F + DIIS: error= 3.98D-02 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 2 EnMin= -196.298076373743 IErMin= 2 ErrMin= 1.69D-02 + ErrMax= 3.98D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 3.94D-01 BMatP= 6.15D-02 + IDIUse=2 WtCom= 0.00D+00 WtEn= 1.00D+00 + Coeff-En: 0.000D+00 0.000D+00 0.650D+00 0.350D+00 + Coeff: 0.000D+00 0.000D+00 0.650D+00 0.350D+00 + Gap= 0.032 Goal= None Shift= 0.000 + RMSDP=2.76D-03 MaxDP=9.60D-02 DE= 3.52D-01 OVMax= 5.49D-01 + + Problem detected with inexpensive integrals. + Switching to full accuracy and repeating last cycle. + Cycle 5 Pass 1 IDiag 1: + E= -195.926806468303 Delta-E= 0.000016631798 Rises=F Damp=F + DIIS: error= 3.98D-02 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -195.926806468303 IErMin= 1 ErrMin= 3.98D-02 + ErrMax= 3.98D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 3.95D-01 BMatP= 3.95D-01 + IDIUse=3 WtCom= 6.02D-01 WtEn= 3.98D-01 + Coeff-Com: 0.100D+01 + Coeff-En: 0.100D+01 + Coeff: 0.100D+01 + Gap= -0.454 Goal= None Shift= 0.000 + GapD= -0.454 DampG=0.250 DampE=0.500 DampFc=0.2500 IDamp=-1. + Damping current iteration by 2.50D-01 + RMSDP=2.31D-02 MaxDP=1.72D+00 DE= 1.66D-05 OVMax= 7.28D-01 + + Cycle 6 Pass 1 IDiag 1: + RMSU= 5.77D-03 CP: 9.56D-01 + E= -196.113371562626 Delta-E= -0.186565094323 Rises=F Damp=T + DIIS: error= 9.51D-03 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 2 EnMin= -196.113371562626 IErMin= 2 ErrMin= 9.51D-03 + ErrMax= 9.51D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.10D-02 BMatP= 3.95D-01 + IDIUse=3 WtCom= 9.05D-01 WtEn= 9.51D-02 + Coeff-Com: -0.123D+00 0.112D+01 + Coeff-En: 0.220D+00 0.780D+00 + Coeff: -0.907D-01 0.109D+01 + Gap= 0.003 Goal= None Shift= 0.000 + GapD= 0.003 DampG=0.250 DampE=1.000 DampFc=0.2500 IDamp=-1. + Damping current iteration by 2.50D-01 + RMSDP=6.29D-03 MaxDP=4.50D-01 DE=-1.87D-01 OVMax= 5.71D-01 + + Cycle 7 Pass 1 IDiag 1: + RMSU= 9.59D-04 CP: 9.39D-01 7.86D-01 + E= -196.210474086713 Delta-E= -0.097102524087 Rises=F Damp=T + DIIS: error= 6.92D-03 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -196.210474086713 IErMin= 3 ErrMin= 6.92D-03 + ErrMax= 6.92D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.94D-03 BMatP= 2.10D-02 + IDIUse=3 WtCom= 9.31D-01 WtEn= 6.92D-02 + Coeff-Com: 0.123D+00-0.841D+00 0.172D+01 + Coeff-En: 0.194D+00 0.000D+00 0.806D+00 + Coeff: 0.128D+00-0.783D+00 0.165D+01 + Gap= 0.049 Goal= None Shift= 0.000 + RMSDP=4.58D-03 MaxDP=3.34D-01 DE=-9.71D-02 OVMax= 2.48D-01 + + Cycle 8 Pass 1 IDiag 1: + RMSU= 9.62D-04 CP: 9.15D-01 9.85D-02 3.00D+00 + E= -196.484599279029 Delta-E= -0.274125192317 Rises=F Damp=F + DIIS: error= 6.18D-03 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 4 EnMin= -196.484599279029 IErMin= 4 ErrMin= 6.18D-03 + ErrMax= 6.18D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.42D-03 BMatP= 6.94D-03 + IDIUse=3 WtCom= 9.38D-01 WtEn= 6.18D-02 + Coeff-Com: 0.899D-01-0.722D-01 0.123D+00 0.859D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.100D+01 + Coeff: 0.844D-01-0.677D-01 0.115D+00 0.868D+00 + Gap= 0.066 Goal= None Shift= 0.000 + RMSDP=5.08D-04 MaxDP=1.74D-02 DE=-2.74D-01 OVMax= 9.21D-02 + + Cycle 9 Pass 1 IDiag 1: + RMSU= 2.96D-04 CP: 9.30D-01 7.92D-02 2.77D+00 1.13D+00 + E= -196.488609058477 Delta-E= -0.004009779447 Rises=F Damp=F + DIIS: error= 3.62D-03 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -196.488609058477 IErMin= 5 ErrMin= 3.62D-03 + ErrMax= 3.62D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.11D-03 BMatP= 4.42D-03 + IDIUse=3 WtCom= 9.64D-01 WtEn= 3.62D-02 + Coeff-Com: -0.122D-01 0.575D-01-0.705D-01 0.317D+00 0.708D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.302D+00 0.698D+00 + Coeff: -0.118D-01 0.554D-01-0.679D-01 0.316D+00 0.708D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=2.02D-04 MaxDP=9.23D-03 DE=-4.01D-03 OVMax= 4.16D-02 + + Cycle 10 Pass 1 IDiag 1: + RMSU= 7.93D-05 CP: 9.24D-01 8.58D-02 2.95D+00 1.09D+00 9.35D-01 + E= -196.489976762339 Delta-E= -0.001367703863 Rises=F Damp=F + DIIS: error= 8.14D-04 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -196.489976762339 IErMin= 6 ErrMin= 8.14D-04 + ErrMax= 8.14D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.46D-05 BMatP= 1.11D-03 + IDIUse=3 WtCom= 9.92D-01 WtEn= 8.14D-03 + Coeff-Com: -0.338D-02 0.265D-01-0.356D-01 0.583D-01 0.268D+00 0.686D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.127D+00 0.873D+00 + Coeff: -0.335D-02 0.263D-01-0.353D-01 0.579D-01 0.267D+00 0.687D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=2.99D-05 MaxDP=1.08D-03 DE=-1.37D-03 OVMax= 5.54D-03 + + Cycle 11 Pass 1 IDiag 1: + RMSU= 1.29D-05 CP: 9.25D-01 8.47D-02 2.93D+00 1.10D+00 9.40D-01 + CP: 8.72D-01 + E= -196.490050683372 Delta-E= -0.000073921032 Rises=F Damp=F + DIIS: error= 2.07D-04 at cycle 7 NSaved= 7. + NSaved= 7 IEnMin= 7 EnMin= -196.490050683372 IErMin= 7 ErrMin= 2.07D-04 + ErrMax= 2.07D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.74D-06 BMatP= 6.46D-05 + IDIUse=3 WtCom= 9.98D-01 WtEn= 2.07D-03 + Coeff-Com: -0.992D-03 0.106D-01-0.144D-01 0.691D-02 0.102D+00 0.248D+00 + Coeff-Com: 0.649D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.100D+01 + Coeff: -0.990D-03 0.106D-01-0.144D-01 0.689D-02 0.101D+00 0.247D+00 + Coeff: 0.649D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=6.78D-06 MaxDP=1.94D-04 DE=-7.39D-05 OVMax= 8.40D-04 + + Cycle 12 Pass 1 IDiag 1: + RMSU= 4.06D-06 CP: 9.25D-01 8.45D-02 2.92D+00 1.10D+00 9.44D-01 + CP: 8.84D-01 9.02D-01 + E= -196.490054850638 Delta-E= -0.000004167266 Rises=F Damp=F + DIIS: error= 9.70D-05 at cycle 8 NSaved= 8. + NSaved= 8 IEnMin= 8 EnMin= -196.490054850638 IErMin= 8 ErrMin= 9.70D-05 + ErrMax= 9.70D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.21D-06 BMatP= 4.74D-06 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.150D-03 0.241D-02-0.313D-02-0.368D-02 0.261D-01-0.937D-02 + Coeff-Com: 0.266D+00 0.722D+00 + Coeff: -0.150D-03 0.241D-02-0.313D-02-0.368D-02 0.261D-01-0.937D-02 + Coeff: 0.266D+00 0.722D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=3.09D-06 MaxDP=1.45D-04 DE=-4.17D-06 OVMax= 4.79D-04 + + Cycle 13 Pass 1 IDiag 1: + RMSU= 1.63D-06 CP: 9.25D-01 8.45D-02 2.92D+00 1.10D+00 9.47D-01 + CP: 8.77D-01 9.25D-01 8.43D-01 + E= -196.490056001816 Delta-E= -0.000001151178 Rises=F Damp=F + DIIS: error= 4.95D-05 at cycle 9 NSaved= 9. + NSaved= 9 IEnMin= 9 EnMin= -196.490056001816 IErMin= 9 ErrMin= 4.95D-05 + ErrMax= 4.95D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.01D-07 BMatP= 1.21D-06 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.431D-04 0.227D-03-0.305D-03-0.254D-02 0.614D-02-0.377D-01 + Coeff-Com: 0.385D-01 0.318D+00 0.677D+00 + Coeff: 0.431D-04 0.227D-03-0.305D-03-0.254D-02 0.614D-02-0.377D-01 + Coeff: 0.385D-01 0.318D+00 0.677D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=1.85D-06 MaxDP=6.65D-05 DE=-1.15D-06 OVMax= 3.61D-04 + + Cycle 14 Pass 1 IDiag 1: + RMSU= 3.77D-07 CP: 9.25D-01 8.44D-02 2.92D+00 1.10D+00 9.48D-01 + CP: 8.72D-01 9.51D-01 9.01D-01 8.74D-01 + E= -196.490056251799 Delta-E= -0.000000249983 Rises=F Damp=F + DIIS: error= 8.10D-06 at cycle 10 NSaved= 10. + NSaved=10 IEnMin=10 EnMin= -196.490056251799 IErMin=10 ErrMin= 8.10D-06 + ErrMax= 8.10D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 5.89D-09 BMatP= 2.01D-07 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.872D-05-0.381D-04 0.563D-04-0.373D-03 0.201D-02-0.915D-02 + Coeff-Com: -0.348D-02 0.513D-01 0.125D+00 0.835D+00 + Coeff: 0.872D-05-0.381D-04 0.563D-04-0.373D-03 0.201D-02-0.915D-02 + Coeff: -0.348D-02 0.513D-01 0.125D+00 0.835D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=3.81D-07 MaxDP=1.84D-05 DE=-2.50D-07 OVMax= 7.33D-05 + + Cycle 15 Pass 1 IDiag 1: + RMSU= 7.88D-08 CP: 9.25D-01 8.44D-02 2.92D+00 1.10D+00 9.48D-01 + CP: 8.71D-01 9.52D-01 9.13D-01 8.97D-01 9.31D-01 + E= -196.490056259355 Delta-E= -0.000000007556 Rises=F Damp=F + DIIS: error= 4.78D-07 at cycle 11 NSaved= 11. + NSaved=11 IEnMin=11 EnMin= -196.490056259355 IErMin=11 ErrMin= 4.78D-07 + ErrMax= 4.78D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.22D-11 BMatP= 5.89D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.121D-05-0.153D-04 0.187D-04-0.900D-04 0.744D-03-0.308D-02 + Coeff-Com: -0.253D-02 0.148D-01 0.330D-01 0.371D+00 0.586D+00 + Coeff: 0.121D-05-0.153D-04 0.187D-04-0.900D-04 0.744D-03-0.308D-02 + Coeff: -0.253D-02 0.148D-01 0.330D-01 0.371D+00 0.586D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=3.38D-08 MaxDP=1.19D-06 DE=-7.56D-09 OVMax= 4.28D-06 + + Cycle 16 Pass 1 IDiag 1: + RMSU= 1.81D-08 CP: 9.25D-01 8.44D-02 2.92D+00 1.10D+00 9.48D-01 + CP: 8.71D-01 9.51D-01 9.14D-01 8.98D-01 9.59D-01 + CP: 8.47D-01 + E= -196.490056259391 Delta-E= -0.000000000036 Rises=F Damp=F + DIIS: error= 1.67D-07 at cycle 12 NSaved= 12. + NSaved=12 IEnMin=12 EnMin= -196.490056259391 IErMin=12 ErrMin= 1.67D-07 + ErrMax= 1.67D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.80D-12 BMatP= 4.22D-11 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.251D-06-0.425D-05 0.569D-05-0.842D-06 0.871D-04-0.239D-03 + Coeff-Com: -0.581D-03 0.935D-03 0.122D-02 0.658D-01 0.223D+00 0.710D+00 + Coeff: 0.251D-06-0.425D-05 0.569D-05-0.842D-06 0.871D-04-0.239D-03 + Coeff: -0.581D-03 0.935D-03 0.122D-02 0.658D-01 0.223D+00 0.710D+00 + Gap= 0.072 Goal= None Shift= 0.000 + RMSDP=9.54D-09 MaxDP=2.67D-07 DE=-3.65D-11 OVMax= 9.54D-07 + + SCF Done: E(RB3LYP) = -196.490056259 A.U. after 16 cycles + NFock= 16 Conv=0.95D-08 -V/T= 2.0057 + KE= 1.953691366413D+02 PE=-8.047985831498D+02 EE= 2.376560340114D+02 + Leave Link 502 at Thu Aug 13 03:10:01 2026, MaxMem= 2097152000 cpu: 163.3 elap: 21.2 + (Enter /usr/local/g16-gpu/g16/l801.exe) + DoSCS=F DFT=T ScalE2(SS,OS)= 1.000000 1.000000 + Range of M.O.s used for correlation: 1 215 + NBasis= 215 NAE= 20 NBE= 20 NFC= 0 NFV= 0 + NROrb= 215 NOA= 20 NOB= 20 NVA= 195 NVB= 195 + + **** Warning!!: The largest alpha MO coefficient is 0.32751423D+02 + + + **** Warning!!: The smallest alpha delta epsilon is 0.71830400D-01 + + Leave Link 801 at Thu Aug 13 03:10:01 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l914.exe) + RHF ground state + Doing stability rather than CIS. + Keep R1 and R2 ints in memory in canonical form, NReq=597927820. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 23220 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + MDV= 2097152000 DFT=T DoStab=T Mixed=T DoRPA=F DoScal=F NonHer=F + Making orbital integer symmetry assigments: + Orbital symmetries: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) + 24 initial guesses have been made. + Convergence on wavefunction: 0.001000000000000 + Davidson Disk Diagonalization: ConvIn= 1.00D-03 SkipCon=T Conv= 1.00D-03. + Max sub-space: 2000 roots to seek: 24 dimension of matrix: 7800 + Iteration 1 Dimension 24 NMult 0 NNew 24 + CISAX will form 24 AO SS matrices at one time. + NMat= 24 NSing= 12 JSym2X= 0. + New state 1 was old state 2 + New state 2 was old state 4 + New state 4 was old state 6 + New state 5 was old state 8 + New state 6 was old state 5 + New state 8 was old state 20 + New state 9 was old state 10 + New state 10 was old state 12 + New state 11 was old state 9 + New state 12 was old state 16 + Excitation Energies [eV] at current iteration: + Root 1 : -1.387161839294639 + Root 2 : 3.651575869737887 + Root 3 : 3.793083657698255 + Root 4 : 4.626520238793075 + Root 5 : 4.782200080776246 + Root 6 : 4.797820084599688 + Root 7 : 5.023414875221465 + Root 8 : 5.232687365786575 + Root 9 : 5.460245349561833 + Root 10 : 5.578328464867063 + Root 11 : 5.583689204932692 + Root 12 : 5.827419543986363 + Root 13 : 5.871679816412684 + Root 14 : 5.905085505223077 + Root 15 : 5.940885412791725 + Root 16 : 6.016610661200549 + Root 17 : 6.021832388097392 + Root 18 : 6.235482888282137 + Root 19 : 6.246583311485919 + Root 20 : 6.265725516795872 + Root 21 : 6.412088418664652 + Root 22 : 6.777991272020793 + Root 23 : 6.839004232131201 + Root 24 : 11.397271420285314 + Iteration 2 Dimension 48 NMult 24 NNew 24 + CISAX will form 24 AO SS matrices at one time. + NMat= 24 NSing= 12 JSym2X= 0. + Root 1 not converged, maximum delta is 0.062556259992600 + Root 2 not converged, maximum delta is 0.020758163583757 + Root 3 not converged, maximum delta is 0.009552769157554 + Root 4 not converged, maximum delta is 0.079715473244838 + New state 5 was old state 11 + Root 5 not converged, maximum delta is 0.288323915225202 + New state 6 was old state 5 + Root 6 not converged, maximum delta is 0.082028137255767 + New state 7 was old state 6 + Root 7 not converged, maximum delta is 0.019340319369726 + Root 8 not converged, maximum delta is 0.047514007156046 + New state 9 was old state 7 + Root 9 not converged, maximum delta is 0.019442184851195 + New state 10 was old state 9 + Root 10 not converged, maximum delta is 0.019701289056325 + New state 11 was old state 10 + Root 11 not converged, maximum delta is 0.063651304184373 + New state 12 was old state 15 + Root 12 not converged, maximum delta is 0.430942845584740 + Excitation Energies [eV] at current iteration: + Root 1 : -1.744784384591761 Change is -0.357622545297123 + Root 2 : 3.608642140040290 Change is -0.042933729697597 + Root 3 : 3.768726002605715 Change is -0.024357655092539 + Root 4 : 4.540093906789965 Change is -0.086426332003110 + Root 5 : 4.681051777413604 Change is -0.902637427519087 + Root 6 : 4.692716223794632 Change is -0.089483856981613 + Root 7 : 4.769465733673051 Change is -0.028354350926636 + Root 8 : 4.992590401270695 Change is -0.240096964515880 + Root 9 : 4.994517007670930 Change is -0.028897867550535 + Root 10 : 5.407045715755402 Change is -0.053199633806432 + Root 11 : 5.473583037084625 Change is -0.104745427782439 + Root 12 : 5.716753651347402 Change is -0.224131761444324 + Root 13 : 5.743792058183457 Change is -0.083627485802905 + Root 14 : 5.803850456354883 Change is -0.067829360057801 + Root 15 : 5.827835777376086 Change is -0.077249727846990 + Root 16 : 5.934797936514411 Change is -0.087034451582981 + Root 17 : 5.994338842663652 Change is -0.022271818536897 + Root 18 : 6.022416209019176 Change is -0.213066679262961 + Root 19 : 6.098422194868016 Change is -0.313666223796636 + Root 20 : 6.157877491717120 Change is -0.107848025078752 + Root 21 : 6.180419414174506 Change is -0.066163897311413 + Root 22 : 6.409695121955941 Change is -0.429309110175260 + Root 23 : 6.553857044613558 Change is -0.224134227407235 + Root 24 : 7.321318194930937 Change is -4.075953225354377 + Iteration 3 Dimension 54 NMult 48 NNew 6 + CISAX will form 6 AO SS matrices at one time. + NMat= 6 NSing= 3 JSym2X= 0. + Root 1 not converged, maximum delta is 0.001896257675242 + Root 2 not converged, maximum delta is 0.002438300188929 + Root 3 not converged, maximum delta is 0.003499536476415 + New state 4 was old state 5 + Root 4 not converged, maximum delta is 0.086034902627899 + New state 5 was old state 4 + Root 5 not converged, maximum delta is 0.008682940492231 + New state 6 was old state 7 + Root 6 not converged, maximum delta is 0.006648984259557 + Excitation Energies [eV] at current iteration: + Root 1 : -1.747519901002225 Change is -0.002735516410464 + Root 2 : 3.607924719869657 Change is -0.000717420170633 + Root 3 : 3.767910323328349 Change is -0.000815679277367 + Root 4 : 4.385906606793863 Change is -0.295145170619741 + Root 5 : 4.537720630484963 Change is -0.002373276305003 + Root 6 : 4.767835379224842 Change is -0.001630354448210 + Iteration 4 Dimension 60 NMult 54 NNew 6 + CISAX will form 6 AO SS matrices at one time. + NMat= 6 NSing= 3 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Root 4 not converged, maximum delta is 0.010504247981094 + Root 5 not converged, maximum delta is 0.002345135391837 + Root 6 not converged, maximum delta is 0.002306132483433 + Excitation Energies [eV] at current iteration: + Root 1 : -1.747566575173292 Change is -0.000046674171067 + Root 2 : 3.607907106698316 Change is -0.000017613171341 + Root 3 : 3.767888778137062 Change is -0.000021545191287 + Root 4 : 4.348315207345856 Change is -0.037591399448007 + Root 5 : 4.537619006129645 Change is -0.000101624355319 + Root 6 : 4.767725046805693 Change is -0.000110332419148 + Iteration 5 Dimension 63 NMult 60 NNew 3 + CISAX will form 3 AO SS matrices at one time. + NMat= 3 NSing= 2 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Root 4 not converged, maximum delta is 0.003245167366910 + Root 5 has converged. + Root 6 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : -1.747566575174192 Change is -0.000000000000900 + Root 2 : 3.607907101503447 Change is -0.000000005194870 + Root 3 : 3.767888583999009 Change is -0.000000194138052 + Root 4 : 4.345637272270506 Change is -0.002677935075350 + Root 5 : 4.537612777047745 Change is -0.000006229081899 + Root 6 : 4.767720091449765 Change is -0.000004955355928 + Iteration 6 Dimension 64 NMult 63 NNew 1 + CISAX will form 1 AO SS matrices at one time. + NMat= 1 NSing= 1 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Root 4 has converged. + Root 5 has converged. + Root 6 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : -1.747566575174229 Change is -0.000000000000036 + Root 2 : 3.607907101503470 Change is 0.000000000000024 + Root 3 : 3.767888583999027 Change is 0.000000000000018 + Root 4 : 4.345346625131095 Change is -0.000290647139410 + Root 5 : 4.537612777047710 Change is -0.000000000000036 + Root 6 : 4.767720091449663 Change is -0.000000000000103 + Convergence achieved on expansion vectors. + *********************************************************************** + Stability analysis using singles matrix: + *********************************************************************** + 1PDM for each excited state written to RWF 633 + Ground to excited state transition densities written to RWF 633 + + Eigenvectors of the stability matrix: + + Eigenvector 1: Triplet-A Eigenvalue=-0.0642219 =2.000 + 20 -> 21 0.69751 + + Eigenvector 2: Triplet-A Eigenvalue= 0.1325881 =2.000 + 20 -> 22 0.69722 + + Eigenvector 3: Singlet-A Eigenvalue= 0.1384674 =0.000 + 20 -> 22 0.70170 + + Eigenvector 4: Singlet-A Eigenvalue= 0.1596886 =0.000 + 20 -> 21 0.58389 + 20 -> 25 0.22909 + 20 -> 28 -0.20296 + 20 -> 30 -0.10039 + + Eigenvector 5: Triplet-A Eigenvalue= 0.1667542 =2.000 + 19 -> 21 -0.10525 + 20 -> 23 0.65417 + 20 -> 24 -0.18789 + + Eigenvector 6: Singlet-A Eigenvalue= 0.1752105 =0.000 + 20 -> 23 0.68398 + 20 -> 24 0.16092 + The wavefunction has an RHF -> UHF instability. + Leave Link 914 at Thu Aug 13 03:11:25 2026, MaxMem= 2097152000 cpu: 659.5 elap: 83.6 + (Enter /usr/local/g16-gpu/g16/l601.exe) + Copying SCF densities to generalized density rwf, IOpCl= 0 IROHF=0. + + ********************************************************************** + + Population analysis using the SCF Density. + + ********************************************************************** + + Orbital symmetries: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) + The electronic state is 1-A. + Alpha occ. eigenvalues -- -10.18991 -10.18284 -10.17657 -10.17227 -10.14108 + Alpha occ. eigenvalues -- -0.82830 -0.73841 -0.70812 -0.61656 -0.53119 + Alpha occ. eigenvalues -- -0.47042 -0.45745 -0.44362 -0.40472 -0.39482 + Alpha occ. eigenvalues -- -0.39290 -0.38272 -0.36233 -0.34015 -0.14822 + Alpha virt. eigenvalues -- -0.07639 0.02394 0.06177 0.06648 0.09660 + Alpha virt. eigenvalues -- 0.09786 0.10475 0.10779 0.11095 0.12369 + Alpha virt. eigenvalues -- 0.14178 0.15296 0.17043 0.17709 0.22822 + Alpha virt. eigenvalues -- 0.23039 0.23730 0.23893 0.26492 0.28247 + Alpha virt. eigenvalues -- 0.29246 0.31128 0.31468 0.33650 0.35204 + Alpha virt. eigenvalues -- 0.36906 0.37391 0.39328 0.41438 0.42782 + Alpha virt. eigenvalues -- 0.43564 0.44251 0.44565 0.44846 0.47199 + Alpha virt. eigenvalues -- 0.47702 0.48836 0.49644 0.51595 0.52144 + Alpha virt. eigenvalues -- 0.55148 0.59002 0.61461 0.62375 0.64501 + Alpha virt. eigenvalues -- 0.65291 0.66572 0.70340 0.82133 0.84605 + Alpha virt. eigenvalues -- 0.88495 0.90340 0.91178 0.94346 0.95637 + Alpha virt. eigenvalues -- 0.97359 0.99315 1.02708 1.02749 1.05373 + Alpha virt. eigenvalues -- 1.07557 1.09481 1.13836 1.17245 1.19607 + Alpha virt. eigenvalues -- 1.24585 1.26025 1.28249 1.34299 1.41513 + Alpha virt. eigenvalues -- 1.43349 1.49034 1.50087 1.50335 1.50909 + Alpha virt. eigenvalues -- 1.52281 1.52628 1.53577 1.54839 1.57163 + Alpha virt. eigenvalues -- 1.57170 1.61450 1.61637 1.65173 1.68659 + Alpha virt. eigenvalues -- 1.78700 1.80189 1.81237 1.84711 1.86076 + Alpha virt. eigenvalues -- 1.88551 1.92619 1.93048 1.93879 1.98248 + Alpha virt. eigenvalues -- 2.00280 2.02906 2.05014 2.06360 2.11736 + Alpha virt. eigenvalues -- 2.14987 2.19790 2.25212 2.26494 2.26621 + Alpha virt. eigenvalues -- 2.32076 2.34086 2.35801 2.37173 2.40355 + Alpha virt. eigenvalues -- 2.42185 2.46054 2.46331 2.52040 2.52340 + Alpha virt. eigenvalues -- 2.55317 2.56618 2.57269 2.59387 2.61465 + Alpha virt. eigenvalues -- 2.63943 2.67063 2.67958 2.74428 2.75249 + Alpha virt. eigenvalues -- 2.80263 2.84621 2.85884 2.87292 2.89822 + Alpha virt. eigenvalues -- 2.93138 2.95069 2.97473 3.01207 3.02229 + Alpha virt. eigenvalues -- 3.05948 3.09846 3.11928 3.13394 3.15125 + Alpha virt. eigenvalues -- 3.16410 3.21863 3.21923 3.23641 3.25951 + Alpha virt. eigenvalues -- 3.27351 3.27976 3.29690 3.29806 3.30884 + Alpha virt. eigenvalues -- 3.33431 3.34159 3.37127 3.40187 3.41082 + Alpha virt. eigenvalues -- 3.43541 3.44699 3.56671 3.57224 3.63852 + Alpha virt. eigenvalues -- 3.67523 3.70854 3.73497 3.83129 3.83272 + Alpha virt. eigenvalues -- 3.87908 3.89171 3.91895 3.96921 3.99882 + Alpha virt. eigenvalues -- 4.05476 4.13747 4.14678 4.17126 4.19252 + Alpha virt. eigenvalues -- 4.20623 4.30629 4.39750 4.41763 4.45492 + Alpha virt. eigenvalues -- 4.50650 4.52482 4.55588 4.65362 4.68230 + Alpha virt. eigenvalues -- 4.74166 4.85801 4.90628 5.11521 5.30736 + Alpha virt. eigenvalues -- 22.18153 22.28265 22.33695 22.48969 22.79357 + Condensed to atoms (all electrons): + 1 2 3 4 5 6 + 1 C 4.905156 0.321373 -0.032487 -0.053871 0.003151 0.420704 + 2 C 0.321373 5.470042 0.301611 0.390142 -0.137160 -0.053669 + 3 C -0.032487 0.301611 4.899456 -0.030169 0.005129 -0.004188 + 4 C -0.053871 0.390142 -0.030169 4.866818 0.363490 0.008787 + 5 C 0.003151 -0.137160 0.005129 0.363490 5.371499 0.000124 + 6 H 0.420704 -0.053669 -0.004188 0.008787 0.000124 0.558703 + 7 H 0.396563 -0.063285 0.000166 -0.006209 0.019106 -0.022859 + 8 H -0.002941 -0.056793 0.393722 -0.002456 0.000922 0.000390 + 9 H -0.002941 -0.056793 0.393721 -0.002456 0.000922 0.000390 + 10 H 0.006388 -0.073784 0.432162 0.008271 0.001122 0.000292 + 11 H 0.001430 -0.037521 0.001443 0.365916 -0.012385 -0.000368 + 12 H 0.001430 -0.037521 0.001443 0.365916 -0.012385 -0.000368 + 13 H 0.003674 -0.011239 -0.000060 -0.052160 0.427386 0.000225 + 14 H 0.396564 -0.063284 0.000166 -0.006209 0.019106 -0.022860 + 15 H -0.000857 0.009488 -0.000392 -0.049495 0.421501 -0.000006 + 7 8 9 10 11 12 + 1 C 0.396563 -0.002941 -0.002941 0.006388 0.001430 0.001430 + 2 C -0.063285 -0.056793 -0.056793 -0.073784 -0.037521 -0.037521 + 3 C 0.000166 0.393722 0.393721 0.432162 0.001443 0.001443 + 4 C -0.006209 -0.002456 -0.002456 0.008271 0.365916 0.365916 + 5 C 0.019106 0.000922 0.000922 0.001122 -0.012385 -0.012385 + 6 H -0.022859 0.000390 0.000390 0.000292 -0.000368 -0.000368 + 7 H 0.620861 0.005929 -0.002960 -0.000369 0.000903 -0.001497 + 8 H 0.005929 0.633922 -0.064139 -0.024986 0.001136 -0.001486 + 9 H -0.002960 -0.064139 0.633923 -0.024986 -0.001486 0.001136 + 10 H -0.000369 -0.024986 -0.024986 0.563378 0.000125 0.000125 + 11 H 0.000903 0.001136 -0.001486 0.000125 0.537320 -0.015297 + 12 H -0.001497 -0.001486 0.001136 0.000125 -0.015297 0.537320 + 13 H -0.001377 0.000002 0.000002 0.000039 0.004238 0.004238 + 14 H -0.067119 -0.002960 0.005929 -0.000369 -0.001498 0.000903 + 15 H 0.000116 0.000015 0.000015 -0.000067 -0.003838 -0.003838 + 13 14 15 + 1 C 0.003674 0.396564 -0.000857 + 2 C -0.011239 -0.063284 0.009488 + 3 C -0.000060 0.000166 -0.000392 + 4 C -0.052160 -0.006209 -0.049495 + 5 C 0.427386 0.019106 0.421501 + 6 H 0.000225 -0.022860 -0.000006 + 7 H -0.001377 -0.067119 0.000116 + 8 H 0.000002 -0.002960 0.000015 + 9 H 0.000002 0.005929 0.000015 + 10 H 0.000039 -0.000369 -0.000067 + 11 H 0.004238 -0.001498 -0.003838 + 12 H 0.004238 0.000903 -0.003838 + 13 H 0.530828 -0.001377 -0.025576 + 14 H -0.001377 0.620861 0.000116 + 15 H -0.025576 0.000116 0.540108 + Mulliken charges: + 1 + 1 C -0.363335 + 2 C 0.098394 + 3 C -0.361724 + 4 C -0.166315 + 5 C -0.471528 + 6 H 0.114704 + 7 H 0.122032 + 8 H 0.119724 + 9 H 0.119724 + 10 H 0.112660 + 11 H 0.159882 + 12 H 0.159882 + 13 H 0.121157 + 14 H 0.122032 + 15 H 0.112711 + Sum of Mulliken charges = -0.00000 + Mulliken charges with hydrogens summed into heavy atoms: + 1 + 1 C -0.004567 + 2 C 0.098394 + 3 C -0.009616 + 4 C 0.153449 + 5 C -0.237659 + Electronic spatial extent (au): = 529.0799 + Charge= -0.0000 electrons + Dipole moment (field-independent basis, Debye): + X= 1.8484 Y= -0.5668 Z= 0.0000 Tot= 1.9334 + Quadrupole moment (field-independent basis, Debye-Ang): + XX= -37.6617 YY= -31.6537 ZZ= -35.6473 + XY= 0.7487 XZ= -0.0000 YZ= -0.0002 + Traceless Quadrupole moment (field-independent basis, Debye-Ang): + XX= -2.6741 YY= 3.3338 ZZ= -0.6597 + XY= 0.7487 XZ= -0.0000 YZ= -0.0002 + Octapole moment (field-independent basis, Debye-Ang**2): + XXX= 13.4749 YYY= -2.8652 ZZZ= 0.0001 XYY= -0.5610 + XXY= -0.1015 XXZ= -0.0001 XZZ= 5.3601 YZZ= -1.0165 + YYZ= 0.0000 XYZ= 0.0002 + Hexadecapole moment (field-independent basis, Debye-Ang**3): + XXXX= -488.8447 YYYY= -228.3132 ZZZZ= -63.9591 XXXY= 7.0591 + XXXZ= -0.0001 YYYX= 1.3503 YYYZ= 0.0044 ZZZX= 0.0003 + ZZZY= 0.0041 XXYY= -113.1249 XXZZ= -99.1294 YYZZ= -47.5929 + XXYZ= 0.0008 YYXZ= 0.0001 ZZXY= 0.7248 + N-N= 1.752833562378D+02 E-N=-8.047985810788D+02 KE= 1.953691366413D+02 + No NMR shielding tensors so no spin-rotation constants. + Leave Link 601 at Thu Aug 13 03:11:25 2026, MaxMem= 2097152000 cpu: 0.6 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l9999.exe) + Unable to Open any file for archive entry. + 1\1\GINC-N013\Stability\RB3LYP\def2TZVP\C5H10\CALVIN.P\13-Aug-2026\0\\ + #P b3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, Acc2E= + 12) scf=(direct,tight)\\stability test reaction_08_intra_rh_add_exocyc + lic\\0,1\C,0,0.426535,1.477892,-0.000077\C,0,0.494278,0.011915,-0.0000 + 03\C,0,1.792259,-0.712657,0.000036\C,0,-0.769525,-0.703182,0.000035\C, + 0,-2.095524,-0.117561,0.000011\H,0,1.398544,1.970089,-0.000109\H,0,-0. + 162672,1.830519,-0.866904\H,0,2.406008,-0.456448,-0.875111\H,0,2.406,- + 0.456368,0.875165\H,0,1.652868,-1.795523,0.000085\H,0,-0.701001,-1.413 + 883,0.848513\H,0,-0.701006,-1.413967,-0.848372\H,0,-2.277062,0.946049, + -0.000035\H,0,-0.162658,1.830608,0.866722\H,0,-2.947166,-0.77952,0.000 + 039\\Version=ES64L-G16RevC.02\State=1-A\HF=-196.4900563\RMSD=9.539e-09 + \Dipole=0.7272295,-0.2229895,0.0000106\Quadrupole=-1.9881327,2.478632, + -0.4904994,0.5566679,-0.0000175,-0.0001356\PG=C01 [X(C5H10)]\\@ + The archive entry for this job was punched. + + + DESK: A WASTEBASKET WITH DRAWERS. + Job cpu time: 0 days 0 hours 13 minutes 49.2 seconds. + Elapsed time: 0 days 0 hours 1 minutes 46.2 seconds. + File lengths (MBytes): RWF= 208 Int= 0 D2E= 0 Chk= 12 Scr= 1 + Normal termination of Gaussian 16 at Thu Aug 13 03:11:25 2026. diff --git a/arc/testing/stability/stable_restricted_singlet_ts.out b/arc/testing/stability/stable_restricted_singlet_ts.out new file mode 100644 index 0000000000..4c1ff286f9 --- /dev/null +++ b/arc/testing/stability/stable_restricted_singlet_ts.out @@ -0,0 +1,740 @@ + Entering Gaussian System, Link 0=g16 + Initial command: + /usr/local/g16-gpu/g16/l1.exe "/scratch/g16/job/Gau-1868570.inp" -scrdir="/scratch/g16/job/" + Entering Link 1 = /usr/local/g16-gpu/g16/l1.exe PID= 1868576. + + Copyright (c) 1988-2021, Gaussian, Inc. All Rights Reserved. + + This is part of the Gaussian(R) 16 program. It is based on + the Gaussian(R) 09 system (copyright 2009, Gaussian, Inc.), + the Gaussian(R) 03 system (copyright 2003, Gaussian, Inc.), + the Gaussian(R) 98 system (copyright 1998, Gaussian, Inc.), + the Gaussian(R) 94 system (copyright 1995, Gaussian, Inc.), + the Gaussian 92(TM) system (copyright 1992, Gaussian, Inc.), + the Gaussian 90(TM) system (copyright 1990, Gaussian, Inc.), + the Gaussian 88(TM) system (copyright 1988, Gaussian, Inc.), + the Gaussian 86(TM) system (copyright 1986, Carnegie Mellon + University), and the Gaussian 82(TM) system (copyright 1983, + Carnegie Mellon University). Gaussian is a federally registered + trademark of Gaussian, Inc. + + This software contains proprietary and confidential information, + including trade secrets, belonging to Gaussian, Inc. + + This software is provided under written license and may be + used, copied, transmitted, or stored only in accord with that + written license. + + The following legend is applicable only to US Government + contracts under FAR: + + RESTRICTED RIGHTS LEGEND + + Use, reproduction and disclosure by the US Government is + subject to restrictions as set forth in subparagraphs (a) + and (c) of the Commercial Computer Software - Restricted + Rights clause in FAR 52.227-19. + + Gaussian, Inc. + 340 Quinnipiac St., Bldg. 40, Wallingford CT 06492 + + + --------------------------------------------------------------- + Warning -- This program may not be used in any manner that + competes with the business of Gaussian, Inc. or will provide + assistance to any competitor of Gaussian, Inc. The licensee + of this program is prohibited from giving any competitor of + Gaussian, Inc. access to this program. By using this program, + the user acknowledges that Gaussian, Inc. is engaged in the + business of creating and licensing software in the field of + computational chemistry and represents and warrants to the + licensee that it is not a competitor of Gaussian, Inc. and that + it will not use this program in any manner prohibited above. + --------------------------------------------------------------- + + + Cite this work as: + Gaussian 16, Revision C.02, + M. J. Frisch, G. W. Trucks, H. B. Schlegel, G. E. Scuseria, + M. A. Robb, J. R. Cheeseman, G. Scalmani, V. Barone, + G. A. Petersson, H. Nakatsuji, X. Li, M. Caricato, A. V. Marenich, + J. Bloino, B. G. Janesko, R. Gomperts, B. Mennucci, H. P. Hratchian, + J. V. Ortiz, A. F. Izmaylov, J. L. Sonnenberg, D. Williams-Young, + F. Ding, F. Lipparini, F. Egidi, J. Goings, B. Peng, A. Petrone, + T. Henderson, D. Ranasinghe, V. G. Zakrzewski, J. Gao, N. Rega, + G. Zheng, W. Liang, M. Hada, M. Ehara, K. Toyota, R. Fukuda, + J. Hasegawa, M. Ishida, T. Nakajima, Y. Honda, O. Kitao, H. Nakai, + T. Vreven, K. Throssell, J. A. Montgomery, Jr., J. E. Peralta, + F. Ogliaro, M. J. Bearpark, J. J. Heyd, E. N. Brothers, K. N. Kudin, + V. N. Staroverov, T. A. Keith, R. Kobayashi, J. Normand, + K. Raghavachari, A. P. Rendell, J. C. Burant, S. S. Iyengar, + J. Tomasi, M. Cossi, J. M. Millam, M. Klene, C. Adamo, R. Cammi, + J. W. Ochterski, R. L. Martin, K. Morokuma, O. Farkas, + J. B. Foresman, and D. J. Fox, Gaussian, Inc., Wallingford CT, 2019. + + ****************************************** + Gaussian 16: ES64L-G16RevC.02 7-Dec-2021 + 13-Aug-2026 + ****************************************** + %mem=16000mb + %NProcShared=8 + Will use up to 8 processors via shared memory. + %chk=check.chk + ---------------------------------------------------------------------- + #P b3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, Acc2E= + 12) scf=(direct,tight) + ---------------------------------------------------------------------- + 1/38=1,172=1/1; + 2/12=2,17=6,18=5,40=1/2; + 3/5=44,7=101,11=2,25=1,27=12,30=1,74=-5,75=-5/1,2,3; + 4//1; + 5/5=2,32=2,38=5,87=12/2; + 8/6=1,10=90,11=11,87=12/1; + 9/8=-1,42=1,87=12/14; + 6/7=2,8=2,9=2,10=2,28=1,87=12/1; + 99/5=1,9=1/99; + Leave Link 1 at Thu Aug 13 03:09:37 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l101.exe) + ----------------------------------------------- + stability test reaction_r2_01_1_2_cycloaddition + ----------------------------------------------- + Symbolic Z-matrix: + Charge = 0 Multiplicity = 1 + C -1.29545 0.32293 0. + C 1.13241 0.23585 0. + O 0.16551 -0.50307 0. + H -1.72265 -0.2171 -0.86208 + H -1.72266 -0.21708 0.86209 + H 2.12997 -0.21237 0.00001 + H 0.96946 1.31837 -0.00001 + + ITRead= 0 0 0 0 0 0 0 + MicOpt= -1 -1 -1 -1 -1 -1 -1 + NAtoms= 7 NQM= 7 NQMF= 0 NMMI= 0 NMMIF= 0 + NMic= 0 NMicF= 0. + Isotopes and Nuclear Properties: + (Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) + in nuclear magnetons) + + Atom 1 2 3 4 5 6 7 + IAtWgt= 12 12 16 1 1 1 1 + AtmWgt= 12.0000000 12.0000000 15.9949146 1.0078250 1.0078250 1.0078250 1.0078250 + NucSpn= 0 0 0 1 1 1 1 + AtZEff= -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 0.0000000 0.0000000 0.0000000 2.7928460 2.7928460 2.7928460 2.7928460 + AtZNuc= 6.0000000 6.0000000 8.0000000 1.0000000 1.0000000 1.0000000 1.0000000 + Leave Link 101 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l202.exe) + Input orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 6 0 -1.295448 0.322934 -0.000001 + 2 6 0 1.132413 0.235850 0.000000 + 3 8 0 0.165512 -0.503065 0.000000 + 4 1 0 -1.722654 -0.217098 -0.862083 + 5 1 0 -1.722657 -0.217083 0.862090 + 6 1 0 2.129967 -0.212374 0.000007 + 7 1 0 0.969456 1.318371 -0.000007 + --------------------------------------------------------------------- + Distance matrix (angstroms): + 1 2 3 4 5 + 1 C 0.000000 + 2 C 2.429422 0.000000 + 3 O 1.678296 1.216919 0.000000 + 4 H 1.103324 3.016580 2.095265 0.000000 + 5 H 1.103325 3.016583 2.095273 1.724173 0.000000 + 6 H 3.466990 1.093626 1.985846 3.947899 3.947901 + 7 H 2.474002 1.094718 1.990968 3.216877 3.216878 + 6 7 + 6 H 0.000000 + 7 H 1.920928 0.000000 + Stoichiometry C2H4O + Framework group C1[X(C2H4O)] + Deg. of freedom 15 + Full point group C1 NOp 1 + Largest Abelian subgroup C1 NOp 1 + Largest concise Abelian subgroup C1 NOp 1 + Standard orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 6 0 -1.295448 0.322934 -0.000001 + 2 6 0 1.132413 0.235850 -0.000000 + 3 8 0 0.165512 -0.503065 -0.000000 + 4 1 0 -1.722654 -0.217098 -0.862083 + 5 1 0 -1.722657 -0.217083 0.862090 + 6 1 0 2.129967 -0.212374 0.000007 + 7 1 0 0.969456 1.318371 -0.000007 + --------------------------------------------------------------------- + Rotational constants (GHZ): 54.4238144 10.3092175 9.1368768 + Leave Link 202 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l301.exe) + Standard basis: def2TZVP (5D, 7F) + Ernie: Thresh= 0.10000D-02 Tol= 0.10000D-05 Strict=F. + There are 132 symmetry adapted cartesian basis functions of A symmetry. + There are 117 symmetry adapted basis functions of A symmetry. + 117 basis functions, 185 primitive gaussians, 132 cartesian basis functions + 12 alpha electrons 12 beta electrons + nuclear repulsion energy 69.1908107766 Hartrees. + IExCor= 402 DFT=T Ex+Corr=B3LYP ExCW=0 ScaHFX= 0.200000 + ScaDFX= 0.800000 0.720000 1.000000 0.810000 ScalE2= 1.000000 1.000000 + IRadAn= 5 IRanWt= -1 IRanGd= 0 ICorTp=0 IEmpDi= 4 + NAtoms= 7 NActive= 7 NUniq= 7 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F + Integral buffers will be 131072 words long. + Raffenetti 2 integral format. + Two-electron integral symmetry is turned on. + Leave Link 301 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l302.exe) + NPDir=0 NMtPBC= 1 NCelOv= 1 NCel= 1 NClECP= 1 NCelD= 1 + NCelK= 1 NCelE2= 1 NClLst= 1 CellRange= 0.0. + One-electron integrals computed using PRISM. + One-electron integral symmetry used in STVInt + 1 Symmetry operations used in ECPInt. + ECPInt: NShTT= 1225 NPrTT= 3648 LenC2= 1224 LenP2D= 3228. + LDataN: DoStor=T MaxTD1= 6 Len= 172 + NBasis= 117 RedAO= T EigKep= 1.08D-03 NBF= 117 + NBsUse= 117 1.00D-06 EigRej= -1.00D+00 NBFU= 117 + Precomputing XC quadrature grid using + IXCGrd= 4 IRadAn= 5 IRanWt= -1 IRanGd= 0 AccXCQ= 1.00D-12. + Generated NRdTot= 0 NPtTot= 0 NUsed= 0 NTot= 32 + NSgBfM= 132 132 132 132 132 MxSgAt= 7 MxSgA2= 7. + Leave Link 302 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.7 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l303.exe) + DipDrv: MaxL=1. + Leave Link 303 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l401.exe) + ExpMin= 9.52D-02 ExpMax= 2.70D+04 ExpMxC= 9.22D+02 IAcc=3 IRadAn= 5 AccDes= 0.00D+00 + Harris functional with IExCor= 402 and IRadAn= 5 diagonalized for initial guess. + HarFok: IExCor= 402 AccDes= 0.00D+00 IRadAn= 5 IDoV= 1 UseB2=F ITyADJ=14 + ICtDFT= 3500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000 + FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0 + NFxFlg= 0 DoJE=T BraDBF=F KetDBF=T FulRan=T + wScrn= 0.000000 ICntrl= 500 IOpCl= 0 I1Cent= 200000004 NGrid= 0 + NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Petite list used in FoFCou. + Harris En= -153.766743278583 + JPrj=0 DoOrth=F DoCkMO=F. + Leave Link 401 at Thu Aug 13 03:09:40 2026, MaxMem= 2097152000 cpu: 1.7 elap: 0.4 + (Enter /usr/local/g16-gpu/g16/l502.exe) + Keep R1 ints in memory in canonical form, NReq=31507998. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 6903 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + Closed shell SCF: + Using DIIS extrapolation, IDIIS= 1040. + NGot= 2097152000 LenX= 2073285452 LenY= 2073267587 + Requested convergence on RMS density matrix=1.00D-08 within 128 cycles. + Requested convergence on MAX density matrix=1.00D-06. + Requested convergence on energy=1.00D-06. + No special actions if energy rises. + Integral accuracy reduced to 1.0D-05 until final iterations. + + Cycle 1 Pass 0 IDiag 1: + E= -153.645475334625 + DIIS: error= 3.35D-02 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -153.645475334625 IErMin= 1 ErrMin= 3.35D-02 + ErrMax= 3.35D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.06D-02 BMatP= 8.06D-02 + IDIUse=3 WtCom= 6.65D-01 WtEn= 3.35D-01 + Coeff-Com: 0.100D+01 + Coeff-En: 0.100D+01 + Coeff: 0.100D+01 + Gap= -0.083 Goal= None Shift= 0.000 + GapD= -0.083 DampG=0.250 DampE=0.500 DampFc=0.2500 IDamp=-1. + Damping current iteration by 2.50D-01 + RMSDP=8.70D-03 MaxDP=2.19D-01 OVMax= 9.82D-01 + + Cycle 2 Pass 0 IDiag 1: + E= -153.636730322570 Delta-E= 0.008745012055 Rises=F Damp=T + DIIS: error= 1.32D-02 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 1 EnMin= -153.645475334625 IErMin= 2 ErrMin= 1.32D-02 + ErrMax= 1.32D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.59D-02 BMatP= 8.06D-02 + IDIUse=3 WtCom= 8.68D-01 WtEn= 1.32D-01 + Coeff-Com: 0.533D-01 0.947D+00 + Coeff-En: 0.552D+00 0.448D+00 + Coeff: 0.119D+00 0.881D+00 + Gap= -0.118 Goal= None Shift= 0.000 + RMSDP=2.94D-03 MaxDP=5.45D-02 DE= 8.75D-03 OVMax= 9.87D-01 + + Cycle 3 Pass 0 IDiag 1: + E= -153.686275690935 Delta-E= -0.049545368365 Rises=F Damp=F + DIIS: error= 2.10D-02 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -153.686275690935 IErMin= 2 ErrMin= 1.32D-02 + ErrMax= 2.10D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 5.28D-02 BMatP= 2.59D-02 + IDIUse=2 WtCom= 0.00D+00 WtEn= 1.00D+00 + Coeff-En: 0.000D+00 0.250D+00 0.750D+00 + Coeff: 0.000D+00 0.250D+00 0.750D+00 + Gap= 0.020 Goal= None Shift= 0.000 + RMSDP=2.25D-03 MaxDP=4.16D-02 DE=-4.95D-02 OVMax= 1.29D-01 + + Cycle 4 Pass 0 IDiag 1: + E= -153.703949562024 Delta-E= -0.017673871089 Rises=F Damp=F + DIIS: error= 2.06D-02 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 4 EnMin= -153.703949562024 IErMin= 2 ErrMin= 1.32D-02 + ErrMax= 2.06D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.31D-02 BMatP= 2.59D-02 + IDIUse=2 WtCom= 0.00D+00 WtEn= 1.00D+00 + Coeff-En: 0.000D+00 0.000D+00 0.402D+00 0.598D+00 + Coeff: 0.000D+00 0.000D+00 0.402D+00 0.598D+00 + Gap= 0.069 Goal= None Shift= 0.000 + RMSDP=1.24D-03 MaxDP=3.77D-02 DE=-1.77D-02 OVMax= 9.35D-02 + + Cycle 5 Pass 0 IDiag 1: + E= -153.725099296300 Delta-E= -0.021149734276 Rises=F Damp=F + DIIS: error= 1.07D-02 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -153.725099296300 IErMin= 5 ErrMin= 1.07D-02 + ErrMax= 1.07D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.56D-02 BMatP= 2.59D-02 + IDIUse=3 WtCom= 8.93D-01 WtEn= 1.07D-01 + Coeff-Com: 0.215D-02 0.541D-01 0.254D+00 0.376D+00 0.314D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.280D+00 0.720D+00 + Coeff: 0.192D-02 0.483D-01 0.227D+00 0.366D+00 0.357D+00 + Gap= 0.076 Goal= None Shift= 0.000 + RMSDP=5.52D-04 MaxDP=1.79D-02 DE=-2.11D-02 OVMax= 5.05D-02 + + Cycle 6 Pass 0 IDiag 1: + E= -153.736026747870 Delta-E= -0.010927451570 Rises=F Damp=F + DIIS: error= 2.02D-03 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -153.736026747870 IErMin= 6 ErrMin= 2.02D-03 + ErrMax= 2.02D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 5.28D-04 BMatP= 1.56D-02 + IDIUse=3 WtCom= 9.80D-01 WtEn= 2.02D-02 + Coeff-Com: -0.218D-01 0.168D-01 0.215D-01 0.744D-01 0.186D+00 0.723D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.100D+01 + Coeff: -0.214D-01 0.165D-01 0.211D-01 0.729D-01 0.183D+00 0.728D+00 + Gap= 0.076 Goal= None Shift= 0.000 + RMSDP=1.17D-04 MaxDP=2.99D-03 DE=-1.09D-02 OVMax= 8.76D-03 + + Cycle 7 Pass 0 IDiag 1: + E= -153.736488910937 Delta-E= -0.000462163066 Rises=F Damp=F + DIIS: error= 2.48D-04 at cycle 7 NSaved= 7. + NSaved= 7 IEnMin= 7 EnMin= -153.736488910937 IErMin= 7 ErrMin= 2.48D-04 + ErrMax= 2.48D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.28D-06 BMatP= 5.28D-04 + IDIUse=3 WtCom= 9.98D-01 WtEn= 2.48D-03 + Coeff-Com: -0.126D-01 0.141D-01-0.323D-02 0.420D-02 0.295D-01 0.186D+00 + Coeff-Com: 0.782D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.100D+01 + Coeff: -0.125D-01 0.140D-01-0.322D-02 0.419D-02 0.295D-01 0.186D+00 + Coeff: 0.782D+00 + Gap= 0.076 Goal= None Shift= 0.000 + RMSDP=1.22D-05 MaxDP=2.15D-04 DE=-4.62D-04 OVMax= 4.53D-04 + + Cycle 8 Pass 0 IDiag 1: + E= -153.736492597751 Delta-E= -0.000003686814 Rises=F Damp=F + DIIS: error= 1.89D-04 at cycle 8 NSaved= 8. + NSaved= 8 IEnMin= 8 EnMin= -153.736492597751 IErMin= 8 ErrMin= 1.89D-04 + ErrMax= 1.89D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.28D-06 BMatP= 8.28D-06 + IDIUse=3 WtCom= 9.98D-01 WtEn= 1.89D-03 + Coeff-Com: -0.554D-02 0.562D-02-0.465D-02 0.508D-03 0.343D-02 0.899D-02 + Coeff-Com: 0.381D-01 0.954D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.100D+01 + Coeff: -0.553D-02 0.561D-02-0.464D-02 0.507D-03 0.342D-02 0.897D-02 + Coeff: 0.380D-01 0.954D+00 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=1.33D-05 MaxDP=1.98D-04 DE=-3.69D-06 OVMax= 7.43D-04 + + Cycle 9 Pass 0 IDiag 1: + E= -153.736497634047 Delta-E= -0.000005036296 Rises=F Damp=F + DIIS: error= 5.90D-05 at cycle 9 NSaved= 9. + NSaved= 9 IEnMin= 9 EnMin= -153.736497634047 IErMin= 9 ErrMin= 5.90D-05 + ErrMax= 5.90D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 5.69D-07 BMatP= 4.28D-06 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.353D-03 0.487D-03-0.885D-03 0.245D-03-0.650D-03-0.103D-01 + Coeff-Com: -0.121D+00-0.125D+00 0.126D+01 + Coeff: -0.353D-03 0.487D-03-0.885D-03 0.245D-03-0.650D-03-0.103D-01 + Coeff: -0.121D+00-0.125D+00 0.126D+01 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=6.10D-06 MaxDP=9.28D-05 DE=-5.04D-06 OVMax= 3.11D-04 + + Initial convergence to 1.0D-05 achieved. Increase integral accuracy. + Cycle 10 Pass 1 IDiag 1: + E= -153.736506763522 Delta-E= -0.000009129475 Rises=F Damp=F + DIIS: error= 7.88D-06 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -153.736506763522 IErMin= 1 ErrMin= 7.88D-06 + ErrMax= 7.88D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.23D-09 BMatP= 6.23D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.100D+01 + Coeff: 0.100D+01 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=6.10D-06 MaxDP=9.28D-05 DE=-9.13D-06 OVMax= 1.04D-04 + + Cycle 11 Pass 1 IDiag 1: + E= -153.736506764630 Delta-E= -0.000000001108 Rises=F Damp=F + DIIS: error= 7.89D-06 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 2 EnMin= -153.736506764630 IErMin= 1 ErrMin= 7.88D-06 + ErrMax= 7.89D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 7.69D-09 BMatP= 6.23D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.530D+00 0.470D+00 + Coeff: 0.530D+00 0.470D+00 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=7.15D-07 MaxDP=1.19D-05 DE=-1.11D-09 OVMax= 3.95D-05 + + Cycle 12 Pass 1 IDiag 1: + E= -153.736506773424 Delta-E= -0.000000008794 Rises=F Damp=F + DIIS: error= 1.42D-06 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -153.736506773424 IErMin= 3 ErrMin= 1.42D-06 + ErrMax= 1.42D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.20D-10 BMatP= 6.23D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.883D-01 0.155D+00 0.757D+00 + Coeff: 0.883D-01 0.155D+00 0.757D+00 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=1.27D-07 MaxDP=2.28D-06 DE=-8.79D-09 OVMax= 6.42D-06 + + Cycle 13 Pass 1 IDiag 1: + E= -153.736506773608 Delta-E= -0.000000000184 Rises=F Damp=F + DIIS: error= 4.15D-07 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 4 EnMin= -153.736506773608 IErMin= 4 ErrMin= 4.15D-07 + ErrMax= 4.15D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.22D-11 BMatP= 2.20D-10 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.313D-02 0.259D-01 0.273D+00 0.705D+00 + Coeff: -0.313D-02 0.259D-01 0.273D+00 0.705D+00 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=4.87D-08 MaxDP=1.10D-06 DE=-1.84D-10 OVMax= 2.64D-06 + + Cycle 14 Pass 1 IDiag 1: + E= -153.736506773629 Delta-E= -0.000000000021 Rises=F Damp=F + DIIS: error= 1.47D-07 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -153.736506773629 IErMin= 5 ErrMin= 1.47D-07 + ErrMax= 1.47D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.56D-12 BMatP= 2.22D-11 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.635D-02 0.465D-02 0.815D-01 0.323D+00 0.597D+00 + Coeff: -0.635D-02 0.465D-02 0.815D-01 0.323D+00 0.597D+00 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=1.24D-08 MaxDP=2.61D-07 DE=-2.12D-11 OVMax= 5.55D-07 + + Cycle 15 Pass 1 IDiag 1: + E= -153.736506773631 Delta-E= -0.000000000002 Rises=F Damp=F + DIIS: error= 6.28D-08 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -153.736506773631 IErMin= 6 ErrMin= 6.28D-08 + ErrMax= 6.28D-08 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.40D-13 BMatP= 2.56D-12 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.346D-02 0.171D-02 0.358D-01 0.160D+00 0.375D+00 0.430D+00 + Coeff: -0.346D-02 0.171D-02 0.358D-01 0.160D+00 0.375D+00 0.430D+00 + Gap= 0.075 Goal= None Shift= 0.000 + RMSDP=3.72D-09 MaxDP=1.08D-07 DE=-1.99D-12 OVMax= 2.96D-07 + + SCF Done: E(RB3LYP) = -153.736506774 A.U. after 15 cycles + NFock= 15 Conv=0.37D-08 -V/T= 2.0047 + KE= 1.530122899781D+02 PE=-4.974736075343D+02 EE= 1.215340000060D+02 + Leave Link 502 at Thu Aug 13 03:09:42 2026, MaxMem= 2097152000 cpu: 11.9 elap: 2.0 + (Enter /usr/local/g16-gpu/g16/l801.exe) + DoSCS=F DFT=T ScalE2(SS,OS)= 1.000000 1.000000 + Range of M.O.s used for correlation: 1 117 + NBasis= 117 NAE= 12 NBE= 12 NFC= 0 NFV= 0 + NROrb= 117 NOA= 12 NOB= 12 NVA= 105 NVB= 105 + + **** Warning!!: The smallest alpha delta epsilon is 0.74946426D-01 + + Leave Link 801 at Thu Aug 13 03:09:42 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l914.exe) + RHF ground state + Doing stability rather than CIS. + Keep R1 and R2 ints in memory in canonical form, NReq=70607630. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 6903 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + MDV= 2097152000 DFT=T DoStab=T Mixed=T DoRPA=F DoScal=F NonHer=F + Making orbital integer symmetry assigments: + Orbital symmetries: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) + 24 initial guesses have been made. + Convergence on wavefunction: 0.001000000000000 + Davidson Disk Diagonalization: ConvIn= 1.00D-03 SkipCon=T Conv= 1.00D-03. + Max sub-space: 2000 roots to seek: 24 dimension of matrix: 2520 + Iteration 1 Dimension 24 NMult 0 NNew 24 + CISAX will form 24 AO SS matrices at one time. + NMat= 24 NSing= 12 JSym2X= 0. + New state 1 was old state 2 + New state 2 was old state 1 + New state 3 was old state 4 + New state 4 was old state 8 + New state 5 was old state 12 + New state 7 was old state 3 + New state 8 was old state 5 + New state 9 was old state 11 + New state 11 was old state 9 + New state 12 was old state 24 + Excitation Energies [eV] at current iteration: + Root 1 : 0.701188301398732 + Root 2 : 0.849503142622134 + Root 3 : 2.761688655354039 + Root 4 : 3.921875048602650 + Root 5 : 4.412830667424200 + Root 6 : 5.078500608052171 + Root 7 : 5.307284528904440 + Root 8 : 5.376246999516780 + Root 9 : 5.558832014312793 + Root 10 : 5.610555057717087 + Root 11 : 6.016741084412386 + Root 12 : 6.305968547361344 + Root 13 : 6.450223496504074 + Root 14 : 6.625435940401826 + Root 15 : 6.751438463649646 + Root 16 : 6.936533682199688 + Root 17 : 7.549074041044095 + Root 18 : 8.282980956889551 + Root 19 : 8.637513218309950 + Root 20 : 8.684000979893140 + Root 21 : 8.744358281166848 + Root 22 : 9.104671414127042 + Root 23 : 9.430595411127126 + Root 24 : 19.507227742056351 + Iteration 2 Dimension 48 NMult 24 NNew 24 + CISAX will form 24 AO SS matrices at one time. + NMat= 24 NSing= 12 JSym2X= 0. + Root 1 not converged, maximum delta is 0.019287067136828 + Root 2 not converged, maximum delta is 0.006192578702887 + Root 3 not converged, maximum delta is 0.092270274140888 + Root 4 not converged, maximum delta is 0.052415487884385 + Root 5 not converged, maximum delta is 0.048606302867809 + Root 6 not converged, maximum delta is 0.063945978534209 + Root 7 not converged, maximum delta is 0.345727247682244 + Root 8 not converged, maximum delta is 0.270353622885384 + Root 9 not converged, maximum delta is 0.019674537061977 + Root 10 not converged, maximum delta is 0.050716585223624 + Root 11 not converged, maximum delta is 0.217441903239677 + New state 12 was old state 14 + Root 12 not converged, maximum delta is 0.471059396809248 + Excitation Energies [eV] at current iteration: + Root 1 : 0.657658861063748 Change is -0.043529440334984 + Root 2 : 0.834913663971318 Change is -0.014589478650816 + Root 3 : 2.370576626736479 Change is -0.391112028617560 + Root 4 : 3.508363608508220 Change is -0.413511440094430 + Root 5 : 4.178836109531954 Change is -0.233994557892246 + Root 6 : 4.994188523750971 Change is -0.084312084301200 + Root 7 : 5.005728900014900 Change is -0.301555628889540 + Root 8 : 5.292287897608905 Change is -0.083959101907875 + Root 9 : 5.471798690753952 Change is -0.087033323558842 + Root 10 : 5.481448535114036 Change is -0.129106522603051 + Root 11 : 5.925424455381946 Change is -0.091316629030441 + Root 12 : 5.996499511310830 Change is -0.628936429090996 + Root 13 : 6.109987923342467 Change is -0.195980624018877 + Root 14 : 6.357073678512812 Change is -0.394364785136834 + Root 15 : 6.386339631104407 Change is -0.063883865399667 + Root 16 : 6.692853054505819 Change is -0.243680627693869 + Root 17 : 7.284351610989339 Change is -0.264722430054756 + Root 18 : 8.013609620474757 Change is -0.269371336414794 + Root 19 : 8.126997445221798 Change is -0.557003534671342 + Root 20 : 8.456749961172827 Change is -0.180763257137123 + Root 21 : 8.688423413579210 Change is -0.055934867587638 + Root 22 : 8.887700607108409 Change is -0.216970807018633 + Root 23 : 8.964628336485774 Change is -0.465967074641352 + Root 24 : 12.115777712893415 + Iteration 3 Dimension 54 NMult 48 NNew 6 + CISAX will form 6 AO SS matrices at one time. + NMat= 6 NSing= 3 JSym2X= 0. + Root 1 not converged, maximum delta is 0.002081986253043 + Root 2 not converged, maximum delta is 0.001613279377804 + Root 3 not converged, maximum delta is 0.003746453712370 + Root 4 not converged, maximum delta is 0.009438329160490 + New state 5 was old state 7 + Root 5 not converged, maximum delta is 0.013325230143762 + New state 6 was old state 8 + Root 6 not converged, maximum delta is 0.004621600124462 + Excitation Energies [eV] at current iteration: + Root 1 : 0.657057585551454 Change is -0.000601275512294 + Root 2 : 0.834508269087464 Change is -0.000405394883854 + Root 3 : 2.367442386902632 Change is -0.003134239833847 + Root 4 : 3.500806035297685 Change is -0.007557573210535 + Root 5 : 4.994446390446473 Change is -0.011282509568428 + Root 6 : 5.289988683132621 Change is -0.002299214476284 + Iteration 4 Dimension 60 NMult 54 NNew 6 + CISAX will form 6 AO SS matrices at one time. + NMat= 6 NSing= 3 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Root 4 not converged, maximum delta is 0.002720655556638 + Root 5 not converged, maximum delta is 0.003894101785809 + Root 6 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : 0.657049126966748 Change is -0.000008458584706 + Root 2 : 0.834498508859455 Change is -0.000009760228009 + Root 3 : 2.367378029368884 Change is -0.000064357533748 + Root 4 : 3.500519015470193 Change is -0.000287019827492 + Root 5 : 4.993705528040978 Change is -0.000740862405495 + Root 6 : 5.289838243637845 Change is -0.000150439494776 + Iteration 5 Dimension 62 NMult 60 NNew 2 + CISAX will form 2 AO SS matrices at one time. + NMat= 2 NSing= 1 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Root 4 has converged. + Root 5 has converged. + Root 6 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : 0.657049126966591 Change is -0.000000000000157 + Root 2 : 0.834498508859406 Change is -0.000000000000048 + Root 3 : 2.367377760626593 Change is -0.000000268742292 + Root 4 : 3.500510165126136 Change is -0.000008850344057 + Root 5 : 4.993676378599534 Change is -0.000029149441445 + Root 6 : 5.289838208719337 Change is -0.000000034918507 + Convergence achieved on expansion vectors. + *********************************************************************** + Stability analysis using singles matrix: + *********************************************************************** + 1PDM for each excited state written to RWF 633 + Ground to excited state transition densities written to RWF 633 + + Eigenvectors of the stability matrix: + + Eigenvector 1: Triplet-A Eigenvalue= 0.0241461 =2.000 + 12 -> 13 0.70433 + + Eigenvector 2: Singlet-A Eigenvalue= 0.0306673 =0.000 + 12 -> 13 0.70680 + + Eigenvector 3: Triplet-A Eigenvalue= 0.0869995 =2.000 + 12 -> 14 0.67615 + 12 -> 19 0.11711 + + Eigenvector 4: Triplet-A Eigenvalue= 0.1286414 =2.000 + 9 -> 13 -0.46138 + 11 -> 13 0.52154 + + Eigenvector 5: Singlet-A Eigenvalue= 0.1835142 =0.000 + 11 -> 13 -0.20152 + 12 -> 14 0.66372 + + Eigenvector 6: Singlet-A Eigenvalue= 0.1943980 =0.000 + 11 -> 13 0.31250 + 12 -> 15 0.63061 + The wavefunction is stable under the perturbations considered. + Leave Link 914 at Thu Aug 13 03:10:03 2026, MaxMem= 2097152000 cpu: 165.5 elap: 21.0 + (Enter /usr/local/g16-gpu/g16/l601.exe) + Copying SCF densities to generalized density rwf, IOpCl= 0 IROHF=0. + + ********************************************************************** + + Population analysis using the SCF Density. + + ********************************************************************** + + Orbital symmetries: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) + The electronic state is 1-A. + Alpha occ. eigenvalues -- -19.23707 -10.31955 -10.15648 -1.14509 -0.71656 + Alpha occ. eigenvalues -- -0.63523 -0.55546 -0.49885 -0.48229 -0.36962 + Alpha occ. eigenvalues -- -0.34381 -0.18397 + Alpha virt. eigenvalues -- -0.10902 0.03371 0.04015 0.07459 0.09588 + Alpha virt. eigenvalues -- 0.14298 0.14652 0.17695 0.18044 0.26037 + Alpha virt. eigenvalues -- 0.27644 0.28098 0.32537 0.34294 0.39288 + Alpha virt. eigenvalues -- 0.44408 0.45424 0.47179 0.47815 0.49708 + Alpha virt. eigenvalues -- 0.54876 0.58045 0.60492 0.66625 0.74731 + Alpha virt. eigenvalues -- 0.79577 0.81188 0.83294 0.92920 1.01000 + Alpha virt. eigenvalues -- 1.02327 1.04679 1.06425 1.27533 1.33394 + Alpha virt. eigenvalues -- 1.42298 1.44616 1.46893 1.51046 1.56834 + Alpha virt. eigenvalues -- 1.56836 1.61417 1.65416 1.70876 1.74842 + Alpha virt. eigenvalues -- 1.80690 1.88214 1.91504 1.92995 1.93203 + Alpha virt. eigenvalues -- 1.94726 2.07670 2.14047 2.20986 2.30358 + Alpha virt. eigenvalues -- 2.35060 2.36766 2.45600 2.52368 2.54515 + Alpha virt. eigenvalues -- 2.64601 2.65533 2.72098 2.81087 2.85084 + Alpha virt. eigenvalues -- 2.88368 2.92117 2.95943 3.03682 3.04065 + Alpha virt. eigenvalues -- 3.07382 3.08084 3.11647 3.13999 3.20975 + Alpha virt. eigenvalues -- 3.22590 3.23140 3.35350 3.36256 3.51588 + Alpha virt. eigenvalues -- 3.53114 3.57805 3.72106 3.75217 3.97249 + Alpha virt. eigenvalues -- 4.01016 4.20940 4.24855 4.33041 4.47622 + Alpha virt. eigenvalues -- 5.22418 5.29415 5.49851 5.70150 5.95350 + Alpha virt. eigenvalues -- 6.18915 6.22353 6.43946 6.59575 6.70778 + Alpha virt. eigenvalues -- 6.99763 7.09857 21.85205 22.36525 43.64943 + Condensed to atoms (all electrons): + 1 2 3 4 5 6 + 1 C 5.735211 -0.056226 0.062517 0.363340 0.363340 0.012784 + 2 C -0.056226 4.716938 0.492755 -0.004467 -0.004467 0.362730 + 3 O 0.062517 0.492755 7.650115 -0.017913 -0.017912 -0.040486 + 4 H 0.363340 -0.004467 -0.017913 0.611759 -0.050959 -0.000963 + 5 H 0.363340 -0.004467 -0.017912 -0.050959 0.611758 -0.000963 + 6 H 0.012784 0.362730 -0.040486 -0.000963 -0.000963 0.572205 + 7 H 0.037115 0.394643 -0.059621 -0.000959 -0.000959 -0.050462 + 7 + 1 C 0.037115 + 2 C 0.394643 + 3 O -0.059621 + 4 H -0.000959 + 5 H -0.000959 + 6 H -0.050462 + 7 H 0.536278 + Mulliken charges: + 1 + 1 C -0.518081 + 2 C 0.098093 + 3 O -0.069456 + 4 H 0.100161 + 5 H 0.100162 + 6 H 0.145155 + 7 H 0.143966 + Sum of Mulliken charges = -0.00000 + Mulliken charges with hydrogens summed into heavy atoms: + 1 + 1 C -0.317758 + 2 C 0.387214 + 3 O -0.069456 + Electronic spatial extent (au): = 170.6532 + Charge= -0.0000 electrons + Dipole moment (field-independent basis, Debye): + X= 4.1669 Y= -0.8784 Z= 0.0000 Tot= 4.2585 + Quadrupole moment (field-independent basis, Debye-Ang): + XX= -16.5245 YY= -22.2831 ZZ= -19.0506 + XY= 3.2077 XZ= -0.0000 YZ= 0.0000 + Traceless Quadrupole moment (field-independent basis, Debye-Ang): + XX= 2.7616 YY= -2.9970 ZZ= 0.2354 + XY= 3.2077 XZ= -0.0000 YZ= 0.0000 + Octapole moment (field-independent basis, Debye-Ang**2): + XXX= 14.4304 YYY= -6.1131 ZZZ= 0.0000 XYY= 7.4005 + XXY= -3.8282 XXZ= 0.0001 XZZ= 2.5942 YZZ= -2.2530 + YYZ= -0.0000 XYZ= -0.0000 + Hexadecapole moment (field-independent basis, Debye-Ang**3): + XXXX= -156.0363 YYYY= -51.0625 ZZZZ= -26.6316 XXXY= 3.2359 + XXXZ= -0.0000 YYYX= 9.1932 YYYZ= 0.0000 ZZZX= -0.0001 + ZZZY= 0.0000 XXYY= -40.6336 XXZZ= -32.3387 YYZZ= -13.1748 + XXYZ= 0.0000 YYXZ= -0.0000 ZZXY= 2.2026 + N-N= 6.919081077657D+01 E-N=-4.974736030616D+02 KE= 1.530122899781D+02 + No NMR shielding tensors so no spin-rotation constants. + Leave Link 601 at Thu Aug 13 03:10:04 2026, MaxMem= 2097152000 cpu: 0.7 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l9999.exe) + Unable to Open any file for archive entry. + 1\1\GINC-N013\Stability\RB3LYP\def2TZVP\C2H4O1\CALVIN.P\13-Aug-2026\0\ + \#P b3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, Acc2E + =12) scf=(direct,tight)\\stability test reaction_r2_01_1_2_cycloadditi + on\\0,1\C,0,-1.295448,0.322934,-0.000001\C,0,1.132413,0.23585,0.\O,0,0 + .165512,-0.503065,0.\H,0,-1.722654,-0.217098,-0.862083\H,0,-1.722657,- + 0.217083,0.86209\H,0,2.129967,-0.212374,0.000007\H,0,0.969456,1.318371 + ,-0.000007\\Version=ES64L-G16RevC.02\State=1-A\HF=-153.7365068\RMSD=3. + 722e-09\Dipole=1.6393841,-0.3455828,0.0000054\Quadrupole=2.0531769,-2. + 2282124,0.1750355,2.3848277,-0.0000136,0.000013\PG=C01 [X(C2H4O1)]\\@ + The archive entry for this job was punched. + + + FAULTILY FAULTLESS, ICILY REGULAR, SPLENDIDLY NULL... + MAUDE BY TENNYSON + Job cpu time: 0 days 0 hours 3 minutes 1.2 seconds. + Elapsed time: 0 days 0 hours 0 minutes 24.2 seconds. + File lengths (MBytes): RWF= 90 Int= 0 D2E= 0 Chk= 5 Scr= 1 + Normal termination of Gaussian 16 at Thu Aug 13 03:10:04 2026. diff --git a/arc/testing/stability/stable_spin_contaminated_doublet_ts.out b/arc/testing/stability/stable_spin_contaminated_doublet_ts.out new file mode 100644 index 0000000000..bd0a3cae8a --- /dev/null +++ b/arc/testing/stability/stable_spin_contaminated_doublet_ts.out @@ -0,0 +1,818 @@ + Entering Gaussian System, Link 0=g16 + Initial command: + /usr/local/g16-gpu/g16/l1.exe "/scratch/g16/job/Gau-1868572.inp" -scrdir="/scratch/g16/job/" + Entering Link 1 = /usr/local/g16-gpu/g16/l1.exe PID= 1868575. + + Copyright (c) 1988-2021, Gaussian, Inc. All Rights Reserved. + + This is part of the Gaussian(R) 16 program. It is based on + the Gaussian(R) 09 system (copyright 2009, Gaussian, Inc.), + the Gaussian(R) 03 system (copyright 2003, Gaussian, Inc.), + the Gaussian(R) 98 system (copyright 1998, Gaussian, Inc.), + the Gaussian(R) 94 system (copyright 1995, Gaussian, Inc.), + the Gaussian 92(TM) system (copyright 1992, Gaussian, Inc.), + the Gaussian 90(TM) system (copyright 1990, Gaussian, Inc.), + the Gaussian 88(TM) system (copyright 1988, Gaussian, Inc.), + the Gaussian 86(TM) system (copyright 1986, Carnegie Mellon + University), and the Gaussian 82(TM) system (copyright 1983, + Carnegie Mellon University). Gaussian is a federally registered + trademark of Gaussian, Inc. + + This software contains proprietary and confidential information, + including trade secrets, belonging to Gaussian, Inc. + + This software is provided under written license and may be + used, copied, transmitted, or stored only in accord with that + written license. + + The following legend is applicable only to US Government + contracts under FAR: + + RESTRICTED RIGHTS LEGEND + + Use, reproduction and disclosure by the US Government is + subject to restrictions as set forth in subparagraphs (a) + and (c) of the Commercial Computer Software - Restricted + Rights clause in FAR 52.227-19. + + Gaussian, Inc. + 340 Quinnipiac St., Bldg. 40, Wallingford CT 06492 + + + --------------------------------------------------------------- + Warning -- This program may not be used in any manner that + competes with the business of Gaussian, Inc. or will provide + assistance to any competitor of Gaussian, Inc. The licensee + of this program is prohibited from giving any competitor of + Gaussian, Inc. access to this program. By using this program, + the user acknowledges that Gaussian, Inc. is engaged in the + business of creating and licensing software in the field of + computational chemistry and represents and warrants to the + licensee that it is not a competitor of Gaussian, Inc. and that + it will not use this program in any manner prohibited above. + --------------------------------------------------------------- + + + Cite this work as: + Gaussian 16, Revision C.02, + M. J. Frisch, G. W. Trucks, H. B. Schlegel, G. E. Scuseria, + M. A. Robb, J. R. Cheeseman, G. Scalmani, V. Barone, + G. A. Petersson, H. Nakatsuji, X. Li, M. Caricato, A. V. Marenich, + J. Bloino, B. G. Janesko, R. Gomperts, B. Mennucci, H. P. Hratchian, + J. V. Ortiz, A. F. Izmaylov, J. L. Sonnenberg, D. Williams-Young, + F. Ding, F. Lipparini, F. Egidi, J. Goings, B. Peng, A. Petrone, + T. Henderson, D. Ranasinghe, V. G. Zakrzewski, J. Gao, N. Rega, + G. Zheng, W. Liang, M. Hada, M. Ehara, K. Toyota, R. Fukuda, + J. Hasegawa, M. Ishida, T. Nakajima, Y. Honda, O. Kitao, H. Nakai, + T. Vreven, K. Throssell, J. A. Montgomery, Jr., J. E. Peralta, + F. Ogliaro, M. J. Bearpark, J. J. Heyd, E. N. Brothers, K. N. Kudin, + V. N. Staroverov, T. A. Keith, R. Kobayashi, J. Normand, + K. Raghavachari, A. P. Rendell, J. C. Burant, S. S. Iyengar, + J. Tomasi, M. Cossi, J. M. Millam, M. Klene, C. Adamo, R. Cammi, + J. W. Ochterski, R. L. Martin, K. Morokuma, O. Farkas, + J. B. Foresman, and D. J. Fox, Gaussian, Inc., Wallingford CT, 2019. + + ****************************************** + Gaussian 16: ES64L-G16RevC.02 7-Dec-2021 + 13-Aug-2026 + ****************************************** + %mem=16000mb + %NProcShared=8 + Will use up to 8 processors via shared memory. + %chk=check.chk + ---------------------------------------------------------------------- + #P ub3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, Acc2E + =12) scf=(direct,tight) + ---------------------------------------------------------------------- + 1/38=1,172=1/1; + 2/12=2,17=6,18=5,40=1/2; + 3/5=44,7=101,11=2,25=1,27=12,30=1,74=-5,75=-5,116=2/1,2,3; + 4//1; + 5/5=2,32=2,38=5,87=12/2; + 8/6=1,10=90,11=11,87=12/1; + 9/8=-1,42=1,87=12/14; + 6/7=2,8=2,9=2,10=2,28=1,87=12/1; + 99/5=1,9=1/99; + Leave Link 1 at Thu Aug 13 03:09:37 2026, MaxMem= 2097152000 cpu: 0.0 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l101.exe) + ----------------------------------------------- + stability test reaction_r2_17_intra_h_migration + ----------------------------------------------- + Symbolic Z-matrix: + Charge = 0 Multiplicity = 2 + O -1.99995 0. 0. + C 1.77716 0. 0. + H 2.31932 -0.93318 -0.00002 + H 2.31917 0.93326 -0.00002 + H 0.69808 -0.00009 0.00004 + + ITRead= 0 0 0 0 0 + MicOpt= -1 -1 -1 -1 -1 + NAtoms= 5 NQM= 5 NQMF= 0 NMMI= 0 NMMIF= 0 + NMic= 0 NMicF= 0. + Isotopes and Nuclear Properties: + (Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) + in nuclear magnetons) + + Atom 1 2 3 4 5 + IAtWgt= 16 12 1 1 1 + AtmWgt= 15.9949146 12.0000000 1.0078250 1.0078250 1.0078250 + NucSpn= 0 0 1 1 1 + AtZEff= -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 0.0000000 0.0000000 2.7928460 2.7928460 2.7928460 + AtZNuc= 8.0000000 6.0000000 1.0000000 1.0000000 1.0000000 + Leave Link 101 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l202.exe) + Input orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 8 0 -1.999945 0.000000 -0.000002 + 2 6 0 1.777164 0.000000 0.000002 + 3 1 0 2.319322 -0.933176 -0.000018 + 4 1 0 2.319171 0.933263 -0.000018 + 5 1 0 0.698083 -0.000087 0.000037 + --------------------------------------------------------------------- + Distance matrix (angstroms): + 1 2 3 4 5 + 1 O 0.000000 + 2 C 3.777109 0.000000 + 3 H 4.418923 1.079237 0.000000 + 4 H 4.418794 1.079236 1.866439 0.000000 + 5 H 2.698028 1.079081 1.870580 1.870580 0.000000 + Stoichiometry CH3O(2) + Framework group C1[X(CH3O)] + Deg. of freedom 9 + Full point group C1 NOp 1 + Largest Abelian subgroup C1 NOp 1 + Largest concise Abelian subgroup C1 NOp 1 + Standard orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 8 0 -1.999945 0.000000 -0.000002 + 2 6 0 1.777164 0.000000 0.000002 + 3 1 0 2.319322 -0.933176 -0.000018 + 4 1 0 2.319171 0.933263 -0.000018 + 5 1 0 0.698083 -0.000087 0.000037 + --------------------------------------------------------------------- + Rotational constants (GHZ): 287.8952156 4.4999116 4.4306588 + Leave Link 202 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.0 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l301.exe) + Standard basis: def2TZVP (5D, 7F) + Ernie: Thresh= 0.10000D-02 Tol= 0.10000D-05 Strict=F. + There are 90 symmetry adapted cartesian basis functions of A symmetry. + There are 80 symmetry adapted basis functions of A symmetry. + 80 basis functions, 126 primitive gaussians, 90 cartesian basis functions + 9 alpha electrons 8 beta electrons + nuclear repulsion energy 19.8855943039 Hartrees. + IExCor= 402 DFT=T Ex+Corr=B3LYP ExCW=0 ScaHFX= 0.200000 + ScaDFX= 0.800000 0.720000 1.000000 0.810000 ScalE2= 1.000000 1.000000 + IRadAn= 5 IRanWt= -1 IRanGd= 0 ICorTp=0 IEmpDi= 4 + NAtoms= 5 NActive= 5 NUniq= 5 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F + Integral buffers will be 131072 words long. + Raffenetti 2 integral format. + Two-electron integral symmetry is turned on. + Leave Link 301 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l302.exe) + NPDir=0 NMtPBC= 1 NCelOv= 1 NCel= 1 NClECP= 1 NCelD= 1 + NCelK= 1 NCelE2= 1 NClLst= 1 CellRange= 0.0. + One-electron integrals computed using PRISM. + One-electron integral symmetry used in STVInt + 1 Symmetry operations used in ECPInt. + ECPInt: NShTT= 595 NPrTT= 1764 LenC2= 584 LenP2D= 1470. + LDataN: DoStor=T MaxTD1= 6 Len= 172 + NBasis= 80 RedAO= T EigKep= 2.93D-03 NBF= 80 + NBsUse= 80 1.00D-06 EigRej= -1.00D+00 NBFU= 80 + Precomputing XC quadrature grid using + IXCGrd= 4 IRadAn= 5 IRanWt= -1 IRanGd= 0 AccXCQ= 1.00D-12. + Generated NRdTot= 0 NPtTot= 0 NUsed= 0 NTot= 32 + NSgBfM= 89 89 89 89 89 MxSgAt= 5 MxSgA2= 5. + Leave Link 302 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.7 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l303.exe) + DipDrv: MaxL=1. + Leave Link 303 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l401.exe) + ExpMin= 9.52D-02 ExpMax= 2.70D+04 ExpMxC= 9.22D+02 IAcc=3 IRadAn= 5 AccDes= 0.00D+00 + Harris functional with IExCor= 402 and IRadAn= 5 diagonalized for initial guess. + HarFok: IExCor= 402 AccDes= 0.00D+00 IRadAn= 5 IDoV= 1 UseB2=F ITyADJ=14 + ICtDFT= 3500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000 + FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0 + NFxFlg= 0 DoJE=T BraDBF=F KetDBF=T FulRan=T + wScrn= 0.000000 ICntrl= 500 IOpCl= 0 I1Cent= 200000004 NGrid= 0 + NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Petite list used in FoFCou. + Harris En= -114.916980463043 + JPrj=0 DoOrth=F DoCkMO=F. + Initial guess = 0.0000 = 0.0000 = 0.5000 = 0.7500 S= 0.5000 + Leave Link 401 at Thu Aug 13 03:09:40 2026, MaxMem= 2097152000 cpu: 1.4 elap: 0.3 + (Enter /usr/local/g16-gpu/g16/l502.exe) + Keep R1 and R2 ints in memory in canonical form, NReq=17815140. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 3240 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + UHF open shell SCF: + Using DIIS extrapolation, IDIIS= 1040. + NGot= 2097152000 LenX= 2086633160 LenY= 2086624619 + Requested convergence on RMS density matrix=1.00D-08 within 128 cycles. + Requested convergence on MAX density matrix=1.00D-06. + Requested convergence on energy=1.00D-06. + No special actions if energy rises. + Integral accuracy reduced to 1.0D-05 until final iterations. + + Cycle 1 Pass 0 IDiag 1: + E= -114.689803685572 + DIIS: error= 7.52D-02 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -114.689803685572 IErMin= 1 ErrMin= 7.52D-02 + ErrMax= 7.52D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.33D-01 BMatP= 4.33D-01 + IDIUse=3 WtCom= 2.48D-01 WtEn= 7.52D-01 + Coeff-Com: 0.100D+01 + Coeff-En: 0.100D+01 + Coeff: 0.100D+01 + Gap= -0.426 Goal= None Shift= 0.000 + Gap= 0.147 Goal= None Shift= 0.000 + GapD= -0.426 DampG=0.250 DampE=0.500 DampFc=0.2500 IDamp=-1. + Damping current iteration by 2.50D-01 + RMSDP=1.23D-01 MaxDP=5.83D+00 OVMax= 1.00D+00 + + Cycle 2 Pass 0 IDiag 1: + E= -114.489183266511 Delta-E= 0.200620419062 Rises=F Damp=T + DIIS: error= 3.54D-02 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 1 EnMin= -114.689803685572 IErMin= 2 ErrMin= 3.54D-02 + ErrMax= 3.54D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.90D-01 BMatP= 4.33D-01 + IDIUse=3 WtCom= 6.46D-01 WtEn= 3.54D-01 + Coeff-Com: 0.369D+00 0.631D+00 + Coeff-En: 0.669D+00 0.331D+00 + Coeff: 0.475D+00 0.525D+00 + Gap= -0.020 Goal= None Shift= 0.000 + Gap= 0.057 Goal= None Shift= 0.000 + RMSDP=3.09D-02 MaxDP=1.45D+00 DE= 2.01D-01 OVMax= 9.99D-01 + + Cycle 3 Pass 0 IDiag 1: + E= -114.852461357326 Delta-E= -0.363278090815 Rises=F Damp=F + DIIS: error= 5.86D-02 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -114.852461357326 IErMin= 2 ErrMin= 3.54D-02 + ErrMax= 5.86D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 7.44D-02 BMatP= 1.90D-01 + IDIUse=3 WtCom= 4.14D-01 WtEn= 5.86D-01 + Coeff-Com: 0.101D+00 0.375D+00 0.524D+00 + Coeff-En: 0.000D+00 0.000D+00 0.100D+01 + Coeff: 0.418D-01 0.155D+00 0.803D+00 + Gap= -0.072 Goal= None Shift= 0.000 + Gap= -0.062 Goal= None Shift= 0.000 + RMSDP=8.30D-03 MaxDP=2.29D-01 DE=-3.63D-01 OVMax= 9.89D-01 + + Cycle 4 Pass 0 IDiag 1: + E= -114.016024641048 Delta-E= 0.836436716278 Rises=F Damp=F + DIIS: error= 1.52D-01 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 3 EnMin= -114.852461357326 IErMin= 2 ErrMin= 3.54D-02 + ErrMax= 1.52D-01 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.78D+00 BMatP= 7.44D-02 + IDIUse=2 WtCom= 0.00D+00 WtEn= 1.00D+00 + Coeff-En: 0.000D+00 0.000D+00 0.840D+00 0.160D+00 + Coeff: 0.000D+00 0.000D+00 0.840D+00 0.160D+00 + Gap= 0.044 Goal= None Shift= 0.000 + Gap= 0.064 Goal= None Shift= 0.000 + RMSDP=6.70D-03 MaxDP=2.45D-01 DE= 8.36D-01 OVMax= 1.00D+00 + + Cycle 5 Pass 0 IDiag 1: + E= -114.933240730133 Delta-E= -0.917216089085 Rises=F Damp=F + DIIS: error= 2.60D-02 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -114.933240730133 IErMin= 5 ErrMin= 2.60D-02 + ErrMax= 2.60D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.95D-02 BMatP= 7.44D-02 + IDIUse=3 WtCom= 7.40D-01 WtEn= 2.60D-01 + Coeff-Com: 0.876D-01 0.116D+00 0.336D+00-0.402D-01 0.501D+00 + Coeff-En: 0.000D+00 0.000D+00 0.119D+00 0.000D+00 0.881D+00 + Coeff: 0.648D-01 0.861D-01 0.279D+00-0.297D-01 0.599D+00 + Gap= 0.170 Goal= None Shift= 0.000 + Gap= 0.092 Goal= None Shift= 0.000 + RMSDP=1.01D-03 MaxDP=2.32D-02 DE=-9.17D-01 OVMax= 6.26D-02 + + Cycle 6 Pass 0 IDiag 1: + E= -114.946739059792 Delta-E= -0.013498329659 Rises=F Damp=F + DIIS: error= 2.10D-02 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -114.946739059792 IErMin= 6 ErrMin= 2.10D-02 + ErrMax= 2.10D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.93D-02 BMatP= 6.95D-02 + IDIUse=3 WtCom= 7.90D-01 WtEn= 2.10D-01 + Coeff-Com: 0.117D+00 0.515D-01 0.114D-01-0.371D-01-0.527D+00 0.138D+01 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.100D+01 + Coeff: 0.921D-01 0.407D-01 0.900D-02-0.293D-01-0.416D+00 0.130D+01 + Gap= 0.267 Goal= None Shift= 0.000 + Gap= 0.056 Goal= None Shift= 0.000 + RMSDP=1.03D-03 MaxDP=2.31D-02 DE=-1.35D-02 OVMax= 4.30D-02 + + Cycle 7 Pass 0 IDiag 1: + E= -114.954180636959 Delta-E= -0.007441577167 Rises=F Damp=F + DIIS: error= 6.70D-03 at cycle 7 NSaved= 7. + NSaved= 7 IEnMin= 7 EnMin= -114.954180636959 IErMin= 7 ErrMin= 6.70D-03 + ErrMax= 6.70D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.14D-03 BMatP= 2.93D-02 + IDIUse=3 WtCom= 9.33D-01 WtEn= 6.70D-02 + Coeff-Com: -0.109D-01 0.108D-01-0.393D-02-0.118D-01-0.248D+00-0.822D-01 + Coeff-Com: 0.135D+01 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.100D+01 + Coeff: -0.101D-01 0.101D-01-0.367D-02-0.110D-01-0.232D+00-0.767D-01 + Coeff: 0.132D+01 + Gap= 0.327 Goal= None Shift= 0.000 + Gap= 0.042 Goal= None Shift= 0.000 + RMSDP=6.21D-04 MaxDP=1.34D-02 DE=-7.44D-03 OVMax= 1.83D-02 + + Cycle 8 Pass 0 IDiag 1: + E= -114.955485748775 Delta-E= -0.001305111816 Rises=F Damp=F + DIIS: error= 1.10D-03 at cycle 8 NSaved= 8. + NSaved= 8 IEnMin= 8 EnMin= -114.955485748775 IErMin= 8 ErrMin= 1.10D-03 + ErrMax= 1.10D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.45D-04 BMatP= 4.14D-03 + IDIUse=3 WtCom= 9.89D-01 WtEn= 1.10D-02 + Coeff-Com: -0.450D-02 0.707D-02 0.624D-02 0.936D-03 0.822D-01-0.968D-01 + Coeff-Com: 0.801D-02 0.997D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.100D+01 + Coeff: -0.445D-02 0.699D-02 0.617D-02 0.926D-03 0.813D-01-0.958D-01 + Coeff: 0.792D-02 0.997D+00 + Gap= 0.315 Goal= None Shift= 0.000 + Gap= 0.045 Goal= None Shift= 0.000 + RMSDP=1.35D-04 MaxDP=3.93D-03 DE=-1.31D-03 OVMax= 1.95D-02 + + Cycle 9 Pass 0 IDiag 1: + E= -114.955532877744 Delta-E= -0.000047128969 Rises=F Damp=F + DIIS: error= 4.45D-04 at cycle 9 NSaved= 9. + NSaved= 9 IEnMin= 9 EnMin= -114.955532877744 IErMin= 9 ErrMin= 4.45D-04 + ErrMax= 4.45D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.36D-05 BMatP= 1.45D-04 + IDIUse=3 WtCom= 9.96D-01 WtEn= 4.45D-03 + Coeff-Com: -0.189D-02 0.252D-02-0.188D-02 0.265D-03-0.186D-01 0.457D-01 + Coeff-Com: -0.628D-01-0.863D-01 0.112D+01 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.000D+00 0.100D+01 + Coeff: -0.189D-02 0.251D-02-0.188D-02 0.264D-03-0.185D-01 0.455D-01 + Coeff: -0.625D-01-0.860D-01 0.112D+01 + Gap= 0.314 Goal= None Shift= 0.000 + Gap= 0.046 Goal= None Shift= 0.000 + RMSDP=3.05D-05 MaxDP=8.72D-04 DE=-4.71D-05 OVMax= 4.50D-03 + + Cycle 10 Pass 0 IDiag 1: + E= -114.955533358545 Delta-E= -0.000000480801 Rises=F Damp=F + DIIS: error= 3.34D-04 at cycle 10 NSaved= 10. + NSaved=10 IEnMin=10 EnMin= -114.955533358545 IErMin=10 ErrMin= 3.34D-04 + ErrMax= 3.34D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 9.35D-06 BMatP= 1.36D-05 + IDIUse=3 WtCom= 9.97D-01 WtEn= 3.34D-03 + Coeff-Com: 0.188D-03 0.285D-03-0.244D-02 0.541D-03-0.150D-01 0.309D-01 + Coeff-Com: -0.123D-01-0.164D+00 0.114D+00 0.105D+01 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.100D+01 + Coeff: 0.188D-03 0.284D-03-0.243D-02 0.539D-03-0.149D-01 0.308D-01 + Coeff: -0.123D-01-0.164D+00 0.114D+00 0.105D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=1.47D-05 MaxDP=3.23D-04 DE=-4.81D-07 OVMax= 5.13D-04 + + Cycle 11 Pass 0 IDiag 1: + E= -114.955535509628 Delta-E= -0.000002151083 Rises=F Damp=F + DIIS: error= 1.39D-04 at cycle 11 NSaved= 11. + NSaved=11 IEnMin=11 EnMin= -114.955535509628 IErMin=11 ErrMin= 1.39D-04 + ErrMax= 1.39D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.51D-06 BMatP= 9.35D-06 + IDIUse=3 WtCom= 9.99D-01 WtEn= 1.39D-03 + Coeff-Com: 0.710D-04-0.115D-03-0.104D-02 0.198D-03-0.288D-02 0.382D-02 + Coeff-Com: 0.103D-01-0.241D-01-0.108D+00 0.123D-01 0.111D+01 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.100D+01 + Coeff: 0.709D-04-0.115D-03-0.104D-02 0.198D-03-0.288D-02 0.382D-02 + Coeff: 0.103D-01-0.240D-01-0.108D+00 0.122D-01 0.111D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=1.19D-05 MaxDP=3.32D-04 DE=-2.15D-06 OVMax= 1.70D-03 + + Cycle 12 Pass 0 IDiag 1: + E= -114.955536202005 Delta-E= -0.000000692377 Rises=F Damp=F + DIIS: error= 3.86D-05 at cycle 12 NSaved= 12. + NSaved=12 IEnMin=12 EnMin= -114.955536202005 IErMin=12 ErrMin= 3.86D-05 + ErrMax= 3.86D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.28D-07 BMatP= 1.51D-06 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.253D-04-0.546D-04-0.246D-03 0.125D-04-0.135D-03 0.148D-02 + Coeff-Com: -0.363D-02 0.793D-02 0.431D-01-0.772D-01-0.331D+00 0.136D+01 + Coeff: 0.253D-04-0.546D-04-0.246D-03 0.125D-04-0.135D-03 0.148D-02 + Coeff: -0.363D-02 0.793D-02 0.431D-01-0.772D-01-0.331D+00 0.136D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=1.11D-05 MaxDP=3.58D-04 DE=-6.92D-07 OVMax= 1.82D-03 + + Cycle 13 Pass 0 IDiag 1: + E= -114.955536393933 Delta-E= -0.000000191928 Rises=F Damp=F + DIIS: error= 9.42D-06 at cycle 13 NSaved= 13. + NSaved=13 IEnMin=13 EnMin= -114.955536393933 IErMin=13 ErrMin= 9.42D-06 + ErrMax= 9.42D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.15D-09 BMatP= 1.28D-07 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.150D-04-0.138D-04-0.952D-04-0.268D-05-0.806D-04 0.242D-03 + Coeff-Com: -0.321D-03-0.136D-02 0.243D-02 0.221D-01 0.347D-01-0.277D+00 + Coeff-Com: 0.122D+01 + Coeff: 0.150D-04-0.138D-04-0.952D-04-0.268D-05-0.806D-04 0.242D-03 + Coeff: -0.321D-03-0.136D-02 0.243D-02 0.221D-01 0.347D-01-0.277D+00 + Coeff: 0.122D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=3.65D-06 MaxDP=1.17D-04 DE=-1.92D-07 OVMax= 5.89D-04 + + Initial convergence to 1.0D-05 achieved. Increase integral accuracy. + Cycle 14 Pass 1 IDiag 1: + E= -114.955543226279 Delta-E= -0.000006832346 Rises=F Damp=F + DIIS: error= 8.41D-06 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -114.955543226279 IErMin= 1 ErrMin= 8.41D-06 + ErrMax= 8.41D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.48D-09 BMatP= 8.48D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.100D+01 + Coeff: 0.100D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=3.65D-06 MaxDP=1.17D-04 DE=-6.83D-06 OVMax= 1.17D-04 + + Cycle 15 Pass 1 IDiag 1: + E= -114.955543229045 Delta-E= -0.000000002766 Rises=F Damp=F + DIIS: error= 1.34D-06 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 2 EnMin= -114.955543229045 IErMin= 2 ErrMin= 1.34D-06 + ErrMax= 1.34D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.43D-10 BMatP= 8.48D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.324D-01 0.103D+01 + Coeff: -0.324D-01 0.103D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=4.18D-07 MaxDP=1.31D-05 DE=-2.77D-09 OVMax= 6.56D-05 + + Cycle 16 Pass 1 IDiag 1: + E= -114.955543229386 Delta-E= -0.000000000341 Rises=F Damp=F + DIIS: error= 1.05D-06 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -114.955543229386 IErMin= 3 ErrMin= 1.05D-06 + ErrMax= 1.05D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.34D-11 BMatP= 1.43D-10 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.170D-01 0.420D+00 0.597D+00 + Coeff: -0.170D-01 0.420D+00 0.597D+00 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=1.28D-07 MaxDP=3.78D-06 DE=-3.41D-10 OVMax= 1.95D-05 + + Cycle 17 Pass 1 IDiag 1: + E= -114.955543229455 Delta-E= -0.000000000069 Rises=F Damp=F + DIIS: error= 4.55D-07 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 4 EnMin= -114.955543229455 IErMin= 4 ErrMin= 4.55D-07 + ErrMax= 4.55D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.27D-11 BMatP= 8.34D-11 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.422D-02-0.272D+00-0.289D-01 0.130D+01 + Coeff: 0.422D-02-0.272D+00-0.289D-01 0.130D+01 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=2.12D-07 MaxDP=6.65D-06 DE=-6.94D-11 OVMax= 3.35D-05 + + Cycle 18 Pass 1 IDiag 1: + E= -114.955543229508 Delta-E= -0.000000000053 Rises=F Damp=F + DIIS: error= 1.37D-07 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -114.955543229508 IErMin= 5 ErrMin= 1.37D-07 + ErrMax= 1.37D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.69D-13 BMatP= 1.27D-11 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.825D-03-0.692D-01-0.424D-01 0.159D+00 0.952D+00 + Coeff: 0.825D-03-0.692D-01-0.424D-01 0.159D+00 0.952D+00 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=5.61D-08 MaxDP=1.78D-06 DE=-5.28D-11 OVMax= 9.00D-06 + + Cycle 19 Pass 1 IDiag 1: + E= -114.955543229511 Delta-E= -0.000000000003 Rises=F Damp=F + DIIS: error= 7.76D-08 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -114.955543229511 IErMin= 6 ErrMin= 7.76D-08 + ErrMax= 7.76D-08 0.00D+00 EMaxC= 1.00D-01 BMatC= 7.73D-13 BMatP= 8.69D-13 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.123D-02-0.259D-01-0.335D-01-0.798D-01 0.482D+00 0.656D+00 + Coeff: 0.123D-02-0.259D-01-0.335D-01-0.798D-01 0.482D+00 0.656D+00 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=2.47D-08 MaxDP=7.47D-07 DE=-3.41D-12 OVMax= 3.76D-06 + + Cycle 20 Pass 1 IDiag 1: + E= -114.955543229512 Delta-E= -0.000000000001 Rises=F Damp=F + DIIS: error= 1.53D-08 at cycle 7 NSaved= 7. + NSaved= 7 IEnMin= 7 EnMin= -114.955543229512 IErMin= 7 ErrMin= 1.53D-08 + ErrMax= 1.53D-08 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.75D-14 BMatP= 7.73D-13 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.111D-03 0.593D-02 0.648D-02-0.192D-01-0.166D-01 0.840D-01 + Coeff-Com: 0.939D+00 + Coeff: -0.111D-03 0.593D-02 0.648D-02-0.192D-01-0.166D-01 0.840D-01 + Coeff: 0.939D+00 + Gap= 0.313 Goal= None Shift= 0.000 + Gap= 0.047 Goal= None Shift= 0.000 + RMSDP=2.56D-09 MaxDP=6.43D-08 DE=-7.67D-13 OVMax= 3.24D-07 + + SCF Done: E(UB3LYP) = -114.955543230 A.U. after 20 cycles + NFock= 20 Conv=0.26D-08 -V/T= 2.0042 + = 0.0000 = 0.0000 = 0.5000 = 1.7488 S= 0.9138 + = 0.00000000000 + KE= 1.144751114996D+02 PE=-3.098015823937D+02 EE= 6.048533336070D+01 + Annihilation of the first spin contaminant: + S**2 before annihilation 1.7488, after 0.7740 + Leave Link 502 at Thu Aug 13 03:09:42 2026, MaxMem= 2097152000 cpu: 9.8 elap: 1.6 + (Enter /usr/local/g16-gpu/g16/l801.exe) + DoSCS=F DFT=T ScalE2(SS,OS)= 1.000000 1.000000 + Range of M.O.s used for correlation: 1 80 + NBasis= 80 NAE= 9 NBE= 8 NFC= 0 NFV= 0 + NROrb= 80 NOA= 9 NOB= 8 NVA= 71 NVB= 72 + + **** Warning!!: The smallest beta delta epsilon is 0.47207657D-01 + + Leave Link 801 at Thu Aug 13 03:09:42 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l914.exe) + UHF ground state + Doing stability rather than CIS. + Keep R1 and R2 ints in memory in canonical form, NReq=21388304. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 3240 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + MDV= 2097152000 DFT=T DoStab=T Mixed=T DoRPA=F DoScal=F NonHer=F + Making orbital integer symmetry assigments: + Orbital symmetries: + Alpha Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + Beta Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + 12 initial guesses have been made. + Convergence on wavefunction: 0.001000000000000 + Davidson Disk Diagonalization: ConvIn= 1.00D-03 SkipCon=T Conv= 1.00D-03. + Max sub-space: 2000 roots to seek: 12 dimension of matrix: 1215 + Iteration 1 Dimension 12 NMult 0 NNew 12 + CISAX will form 12 AO SS matrices at one time. + NMat= 12 NSing= 12 JSym2X= 0. + New state 1 was old state 4 + New state 2 was old state 3 + New state 3 was old state 2 + Excitation Energies [eV] at current iteration: + Root 1 : 0.320506903459961 + Root 2 : 0.323801573248312 + Root 3 : 0.534591222451582 + Root 4 : 0.813281585833440 + Root 5 : 5.561730719820025 + Root 6 : 5.600068952300090 + Root 7 : 5.708367733487290 + Root 8 : 5.748985398211230 + Root 9 : 6.806180585678113 + Root 10 : 6.851495103909549 + Root 11 : 6.921232088017772 + Root 12 : 7.903440381947742 + Iteration 2 Dimension 24 NMult 12 NNew 12 + CISAX will form 12 AO SS matrices at one time. + NMat= 12 NSing= 12 JSym2X= 0. + Root 1 not converged, maximum delta is 0.059147770712232 + Root 2 not converged, maximum delta is 0.063666352794040 + Root 3 not converged, maximum delta is 0.002824738178800 + Excitation Energies [eV] at current iteration: + Root 1 : 0.018545483143587 Change is -0.301961420316374 + Root 2 : 0.024103568756134 Change is -0.299698004492179 + Root 3 : 0.532814045483812 Change is -0.001777176967770 + Root 4 : 0.680729099708168 Change is -0.132552486125272 + Root 5 : 5.550604472954074 Change is -0.011126246865951 + Root 6 : 5.596542840568065 Change is -0.003526111732024 + Root 7 : 5.699652101430251 Change is -0.008715632057039 + Root 8 : 5.748425026520437 Change is -0.000560371690794 + Root 9 : 6.521849250263801 Change is -0.284331335414312 + Root 10 : 6.594364432333781 Change is -0.257130671575768 + Root 11 : 6.617423349484943 Change is -0.303808738532829 + Root 12 : 7.887136706199735 Change is -0.016303675748006 + Iteration 3 Dimension 27 NMult 24 NNew 3 + CISAX will form 3 AO SS matrices at one time. + NMat= 3 NSing= 3 JSym2X= 0. + Root 1 not converged, maximum delta is 0.004799753560252 + Root 2 not converged, maximum delta is 0.005232859633331 + Root 3 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : 0.015814330850812 Change is -0.002731152292775 + Root 2 : 0.021518819216497 Change is -0.002584749539637 + Root 3 : 0.532804741418113 Change is -0.000009304065699 + Iteration 4 Dimension 29 NMult 27 NNew 2 + CISAX will form 2 AO SS matrices at one time. + NMat= 2 NSing= 2 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : 0.015791776773517 Change is -0.000022554077295 + Root 2 : 0.021508046141222 Change is -0.000010773075275 + Root 3 : 0.532804741418101 Change is -0.000000000000012 + Convergence achieved on expansion vectors. + *********************************************************************** + Stability analysis using singles matrix: + *********************************************************************** + 1PDM for each excited state written to RWF 633 + Ground to excited state transition densities written to RWF 633 + + Eigenvectors of the stability matrix: + + Eigenvector 1: 2.830-A Eigenvalue= 0.0005803 =1.752 + 7B -> 10B 0.99332 + + Eigenvector 2: 2.836-A Eigenvalue= 0.0007904 =1.761 + 7B -> 9B 0.99338 + + Eigenvector 3: 2.026-A Eigenvalue= 0.0195802 =0.777 + 8B -> 10B 0.99998 + The wavefunction is stable under the perturbations considered. + Leave Link 914 at Thu Aug 13 03:09:46 2026, MaxMem= 2097152000 cpu: 26.6 elap: 3.5 + (Enter /usr/local/g16-gpu/g16/l601.exe) + Copying SCF densities to generalized density rwf, IOpCl= 1 IROHF=0. + + ********************************************************************** + + Population analysis using the SCF Density. + + ********************************************************************** + + Orbital symmetries: + Alpha Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + Beta Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + The electronic state is 2-A. + Alpha occ. eigenvalues -- -19.27861 -10.16874 -1.02292 -0.64881 -0.46486 + Alpha occ. eigenvalues -- -0.46429 -0.41661 -0.41437 -0.38760 + Alpha virt. eigenvalues -- -0.07485 0.07196 0.12459 0.13728 0.20088 + Alpha virt. eigenvalues -- 0.20168 0.25447 0.27197 0.33910 0.37970 + Alpha virt. eigenvalues -- 0.38134 0.46946 0.49352 0.49731 0.62334 + Alpha virt. eigenvalues -- 0.65160 0.65253 0.89700 0.90067 0.91761 + Alpha virt. eigenvalues -- 1.34803 1.35909 1.35912 1.39782 1.39909 + Alpha virt. eigenvalues -- 1.43943 1.44469 1.47350 1.54554 1.56645 + Alpha virt. eigenvalues -- 1.79922 1.84348 1.84822 1.96728 2.03296 + Alpha virt. eigenvalues -- 2.06921 2.36289 2.38842 2.38860 2.39820 + Alpha virt. eigenvalues -- 2.47352 2.56126 2.57014 2.58426 2.67052 + Alpha virt. eigenvalues -- 2.99249 2.99269 3.18508 3.18802 3.19551 + Alpha virt. eigenvalues -- 3.23039 3.26188 3.49550 3.62844 4.08686 + Alpha virt. eigenvalues -- 4.08973 4.50370 4.96441 4.96441 5.00654 + Alpha virt. eigenvalues -- 5.00655 5.03191 5.03223 5.04386 5.99195 + Alpha virt. eigenvalues -- 5.99196 6.05355 6.05384 6.10600 21.92397 + Alpha virt. eigenvalues -- 42.65890 + Beta occ. eigenvalues -- -19.22736 -10.18275 -0.86499 -0.68792 -0.42396 + Beta occ. eigenvalues -- -0.42365 -0.33919 -0.23467 + Beta virt. eigenvalues -- -0.18746 -0.18674 0.06449 0.12270 0.13859 + Beta virt. eigenvalues -- 0.19957 0.20163 0.22523 0.23431 0.36025 + Beta virt. eigenvalues -- 0.43775 0.43977 0.45245 0.49253 0.50028 + Beta virt. eigenvalues -- 0.61493 0.61621 0.63225 0.87338 0.89496 + Beta virt. eigenvalues -- 0.90236 1.32337 1.37245 1.45496 1.45780 + Beta virt. eigenvalues -- 1.46939 1.47131 1.47138 1.47765 1.53166 + Beta virt. eigenvalues -- 1.56416 1.77415 1.83127 1.83603 1.96529 + Beta virt. eigenvalues -- 2.02262 2.06160 2.36003 2.38147 2.51805 + Beta virt. eigenvalues -- 2.52274 2.52340 2.55112 2.55956 2.56886 + Beta virt. eigenvalues -- 2.72994 2.92582 2.92583 3.13463 3.15115 + Beta virt. eigenvalues -- 3.15352 3.20037 3.23554 3.45556 3.62405 + Beta virt. eigenvalues -- 4.06974 4.07255 4.48548 5.09914 5.09915 + Beta virt. eigenvalues -- 5.10373 5.10391 5.10486 5.11289 5.11289 + Beta virt. eigenvalues -- 6.15941 6.16028 6.19894 6.19897 6.20071 + Beta virt. eigenvalues -- 21.90756 42.71320 + Condensed to atoms (all electrons): + 1 2 3 4 5 + 1 O 7.992385 -0.004380 0.000072 0.000072 0.010348 + 2 C -0.004380 5.201645 0.395693 0.395693 0.397700 + 3 H 0.000072 0.395693 0.533438 -0.028207 -0.025752 + 4 H 0.000072 0.395693 -0.028207 0.533437 -0.025752 + 5 H 0.010348 0.397700 -0.025752 -0.025752 0.508121 + Atomic-Atomic Spin Densities. + 1 2 3 4 5 + 1 O 1.999135 0.001544 -0.000036 -0.000036 -0.005002 + 2 C 0.001544 -1.103428 -0.000177 -0.000177 0.004073 + 3 H -0.000036 -0.000177 0.038137 -0.001099 -0.000765 + 4 H -0.000036 -0.000177 -0.001099 0.038137 -0.000765 + 5 H -0.005002 0.004073 -0.000765 -0.000765 0.032896 + Mulliken charges and spin densities: + 1 2 + 1 O 0.001504 1.995606 + 2 C -0.386351 -1.098164 + 3 H 0.124756 0.036060 + 4 H 0.124756 0.036060 + 5 H 0.135334 0.030438 + Sum of Mulliken charges = -0.00000 1.00000 + Mulliken charges and spin densities with hydrogens summed into heavy atoms: + 1 2 + 1 O 0.001504 1.995606 + 2 C -0.001504 -0.995606 + Electronic spatial extent (au): = 257.3880 + Charge= -0.0000 electrons + Dipole moment (field-independent basis, Debye): + X= -0.0030 Y= 0.0000 Z= 0.0000 Tot= 0.0030 + Quadrupole moment (field-independent basis, Debye-Ang): + XX= -13.2482 YY= -12.0151 ZZ= -13.8393 + XY= 0.0000 XZ= -0.0002 YZ= 0.0000 + Traceless Quadrupole moment (field-independent basis, Debye-Ang): + XX= -0.2140 YY= 1.0191 ZZ= -0.8051 + XY= 0.0000 XZ= -0.0002 YZ= 0.0000 + Octapole moment (field-independent basis, Debye-Ang**2): + XXX= -4.4761 YYY= 0.0002 ZZZ= -0.0000 XYY= -2.6950 + XXY= -0.0004 XXZ= 0.0003 XZZ= -6.7695 YZZ= 0.0000 + YYZ= -0.0000 XYZ= -0.0000 + Hexadecapole moment (field-independent basis, Debye-Ang**3): + XXXX= -307.3859 YYYY= -18.5599 ZZZZ= -15.0175 XXXY= -0.0005 + XXXZ= -0.0021 YYYX= 0.0004 YYYZ= 0.0000 ZZZX= -0.0001 + ZZZY= 0.0000 XXYY= -45.2402 XXZZ= -53.9331 YYZZ= -5.9630 + XXYZ= 0.0000 YYXZ= -0.0001 ZZXY= 0.0000 + N-N= 1.988559430394D+01 E-N=-3.098015822703D+02 KE= 1.144751114996D+02 + Isotropic Fermi Contact Couplings + Atom a.u. MegaHertz Gauss 10(-4) cm-1 + 1 O(17) 0.02287 -13.86071 -4.94585 -4.62343 + 2 C(13) -0.06676 -75.05090 -26.78003 -25.03429 + 3 H(1) 0.01324 59.19546 21.12241 19.74548 + 4 H(1) 0.01324 59.19547 21.12242 19.74548 + 5 H(1) 0.01339 59.86726 21.36213 19.96957 + -------------------------------------------------------- + Center ---- Spin Dipole Couplings ---- + 3XX-RR 3YY-RR 3ZZ-RR + -------------------------------------------------------- + 1 Atom -4.073430 2.055991 2.017439 + 2 Atom 0.587068 0.572426 -1.159494 + 3 Atom 0.043523 -0.038106 -0.005417 + 4 Atom 0.043544 -0.038127 -0.005417 + 5 Atom -0.045366 0.060837 -0.015471 + -------------------------------------------------------- + XY XZ YZ + -------------------------------------------------------- + 1 Atom 0.000253 -0.000596 0.000000 + 2 Atom -0.000000 -0.000057 -0.000000 + 3 Atom 0.061516 -0.000001 -0.000002 + 4 Atom -0.061504 -0.000001 0.000002 + 5 Atom -0.000013 0.000003 0.000000 + -------------------------------------------------------- + + + --------------------------------------------------------------------------------- + Anisotropic Spin Dipole Couplings in Principal Axis System + --------------------------------------------------------------------------------- + + Atom a.u. MegaHertz Gauss 10(-4) cm-1 Axes + + Baa -4.0734 294.751 105.174 98.318 1.0000 -0.0000 0.0001 + 1 O(17) Bbb 2.0174 -145.980 -52.089 -48.694 -0.0001 -0.0000 1.0000 + Bcc 2.0560 -148.770 -53.085 -49.624 0.0000 1.0000 0.0000 + + Baa -1.1595 -155.593 -55.519 -51.900 0.0000 0.0000 1.0000 + 2 C(13) Bbb 0.5724 76.814 27.409 25.622 0.0000 1.0000 -0.0000 + Bcc 0.5871 78.779 28.110 26.278 1.0000 -0.0000 -0.0000 + + Baa -0.0711 -37.944 -13.539 -12.657 -0.4728 0.8812 0.0000 + 3 H(1) Bbb -0.0054 -2.890 -1.031 -0.964 0.0000 -0.0000 1.0000 + Bcc 0.0765 40.834 14.571 13.621 0.8812 0.4728 -0.0000 + + Baa -0.0711 -37.945 -13.540 -12.657 0.4727 0.8812 -0.0000 + 4 H(1) Bbb -0.0054 -2.890 -1.031 -0.964 0.0000 0.0000 1.0000 + Bcc 0.0765 40.835 14.571 13.621 0.8812 -0.4727 -0.0000 + + Baa -0.0454 -24.205 -8.637 -8.074 1.0000 0.0001 -0.0001 + 5 H(1) Bbb -0.0155 -8.254 -2.945 -2.753 0.0001 0.0000 1.0000 + Bcc 0.0608 32.460 11.582 10.827 -0.0001 1.0000 -0.0000 + + + --------------------------------------------------------------------------------- + + No NMR shielding tensors so no spin-rotation constants. + Leave Link 601 at Thu Aug 13 03:09:46 2026, MaxMem= 2097152000 cpu: 1.0 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l9999.exe) + Unable to Open any file for archive entry. + 1\1\GINC-N013\Stability\UB3LYP\def2TZVP\C1H3O1(2)\CALVIN.P\13-Aug-2026 + \0\\#P ub3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, A + cc2E=12) scf=(direct,tight)\\stability test reaction_r2_17_intra_h_mig + ration\\0,2\O,0,-1.999945,0.,-0.000002\C,0,1.777164,0.,0.000002\H,0,2. + 319322,-0.933176,-0.000018\H,0,2.319171,0.933263,-0.000018\H,0,0.69808 + 3,-0.000087,0.000037\\Version=ES64L-G16RevC.02\State=2-A\HF=-114.95554 + 32\S2=1.748776\S2-1=0.\S2A=0.77398\RMSD=2.560e-09\Dipole=-0.0011975,0. + ,0.\Quadrupole=-0.1590935,0.7576847,-0.5985912,0.0000361,-0.0001348,0. + \PG=C01 [X(C1H3O1)]\\@ + The archive entry for this job was punched. + + + TRUTH, IN SCIENCE, CAN BE DEFINED AS THE WORKING HYPOTHESIS + BEST FITTED TO OPEN THE WAY TO THE NEXT BETTER ONE. + + -- KONRAD LORENZ + Job cpu time: 0 days 0 hours 0 minutes 40.3 seconds. + Elapsed time: 0 days 0 hours 0 minutes 6.3 seconds. + File lengths (MBytes): RWF= 50 Int= 0 D2E= 0 Chk= 2 Scr= 1 + Normal termination of Gaussian 16 at Thu Aug 13 03:09:47 2026. diff --git a/arc/testing/stability/stable_unrestricted_doublet_ts.out b/arc/testing/stability/stable_unrestricted_doublet_ts.out new file mode 100644 index 0000000000..bdc388a27d --- /dev/null +++ b/arc/testing/stability/stable_unrestricted_doublet_ts.out @@ -0,0 +1,944 @@ + Entering Gaussian System, Link 0=g16 + Initial command: + /usr/local/g16-gpu/g16/l1.exe "/scratch/g16/job/Gau-1868571.inp" -scrdir="/scratch/g16/job/" + Entering Link 1 = /usr/local/g16-gpu/g16/l1.exe PID= 1868577. + + Copyright (c) 1988-2021, Gaussian, Inc. All Rights Reserved. + + This is part of the Gaussian(R) 16 program. It is based on + the Gaussian(R) 09 system (copyright 2009, Gaussian, Inc.), + the Gaussian(R) 03 system (copyright 2003, Gaussian, Inc.), + the Gaussian(R) 98 system (copyright 1998, Gaussian, Inc.), + the Gaussian(R) 94 system (copyright 1995, Gaussian, Inc.), + the Gaussian 92(TM) system (copyright 1992, Gaussian, Inc.), + the Gaussian 90(TM) system (copyright 1990, Gaussian, Inc.), + the Gaussian 88(TM) system (copyright 1988, Gaussian, Inc.), + the Gaussian 86(TM) system (copyright 1986, Carnegie Mellon + University), and the Gaussian 82(TM) system (copyright 1983, + Carnegie Mellon University). Gaussian is a federally registered + trademark of Gaussian, Inc. + + This software contains proprietary and confidential information, + including trade secrets, belonging to Gaussian, Inc. + + This software is provided under written license and may be + used, copied, transmitted, or stored only in accord with that + written license. + + The following legend is applicable only to US Government + contracts under FAR: + + RESTRICTED RIGHTS LEGEND + + Use, reproduction and disclosure by the US Government is + subject to restrictions as set forth in subparagraphs (a) + and (c) of the Commercial Computer Software - Restricted + Rights clause in FAR 52.227-19. + + Gaussian, Inc. + 340 Quinnipiac St., Bldg. 40, Wallingford CT 06492 + + + --------------------------------------------------------------- + Warning -- This program may not be used in any manner that + competes with the business of Gaussian, Inc. or will provide + assistance to any competitor of Gaussian, Inc. The licensee + of this program is prohibited from giving any competitor of + Gaussian, Inc. access to this program. By using this program, + the user acknowledges that Gaussian, Inc. is engaged in the + business of creating and licensing software in the field of + computational chemistry and represents and warrants to the + licensee that it is not a competitor of Gaussian, Inc. and that + it will not use this program in any manner prohibited above. + --------------------------------------------------------------- + + + Cite this work as: + Gaussian 16, Revision C.02, + M. J. Frisch, G. W. Trucks, H. B. Schlegel, G. E. Scuseria, + M. A. Robb, J. R. Cheeseman, G. Scalmani, V. Barone, + G. A. Petersson, H. Nakatsuji, X. Li, M. Caricato, A. V. Marenich, + J. Bloino, B. G. Janesko, R. Gomperts, B. Mennucci, H. P. Hratchian, + J. V. Ortiz, A. F. Izmaylov, J. L. Sonnenberg, D. Williams-Young, + F. Ding, F. Lipparini, F. Egidi, J. Goings, B. Peng, A. Petrone, + T. Henderson, D. Ranasinghe, V. G. Zakrzewski, J. Gao, N. Rega, + G. Zheng, W. Liang, M. Hada, M. Ehara, K. Toyota, R. Fukuda, + J. Hasegawa, M. Ishida, T. Nakajima, Y. Honda, O. Kitao, H. Nakai, + T. Vreven, K. Throssell, J. A. Montgomery, Jr., J. E. Peralta, + F. Ogliaro, M. J. Bearpark, J. J. Heyd, E. N. Brothers, K. N. Kudin, + V. N. Staroverov, T. A. Keith, R. Kobayashi, J. Normand, + K. Raghavachari, A. P. Rendell, J. C. Burant, S. S. Iyengar, + J. Tomasi, M. Cossi, J. M. Millam, M. Klene, C. Adamo, R. Cammi, + J. W. Ochterski, R. L. Martin, K. Morokuma, O. Farkas, + J. B. Foresman, and D. J. Fox, Gaussian, Inc., Wallingford CT, 2019. + + ****************************************** + Gaussian 16: ES64L-G16RevC.02 7-Dec-2021 + 13-Aug-2026 + ****************************************** + %mem=16000mb + %NProcShared=8 + Will use up to 8 processors via shared memory. + %chk=check.chk + ---------------------------------------------------------------------- + #P ub3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine, Acc2E + =12) scf=(direct,tight) + ---------------------------------------------------------------------- + 1/38=1,172=1/1; + 2/12=2,17=6,18=5,40=1/2; + 3/5=44,7=101,11=2,25=1,27=12,30=1,74=-5,75=-5,116=2/1,2,3; + 4//1; + 5/5=2,32=2,38=5,87=12/2; + 8/6=1,10=90,11=11,87=12/1; + 9/8=-1,42=1,87=12/14; + 6/7=2,8=2,9=2,10=2,28=1,87=12/1; + 99/5=1,9=1/99; + Leave Link 1 at Thu Aug 13 03:09:37 2026, MaxMem= 2097152000 cpu: 0.0 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l101.exe) + -------------------------------------------------- + stability test reaction_21_intra_halogen_migration + -------------------------------------------------- + Symbolic Z-matrix: + Charge = 0 Multiplicity = 2 + O 2.44052 -0.74022 0.00006 + C 1.2304 -0.15444 0.00004 + C 0.99241 1.16752 0.00007 + Cl -2.24715 -0.15396 -0.00008 + H 3.13998 -0.0719 0.0001 + H 0.42979 -0.88112 -0.00001 + H 1.79721 1.89374 0.00012 + H -0.02639 1.51989 0.00005 + + ITRead= 0 0 0 0 0 0 0 0 + MicOpt= -1 -1 -1 -1 -1 -1 -1 -1 + NAtoms= 8 NQM= 8 NQMF= 0 NMMI= 0 NMMIF= 0 + NMic= 0 NMicF= 0. + Isotopes and Nuclear Properties: + (Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) + in nuclear magnetons) + + Atom 1 2 3 4 5 6 7 8 + IAtWgt= 16 12 12 35 1 1 1 1 + AtmWgt= 15.9949146 12.0000000 12.0000000 34.9688527 1.0078250 1.0078250 1.0078250 1.0078250 + NucSpn= 0 0 0 3 1 1 1 1 + AtZEff= -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 -0.0000000 + NQMom= 0.0000000 0.0000000 0.0000000 -8.1650000 0.0000000 0.0000000 0.0000000 0.0000000 + NMagM= 0.0000000 0.0000000 0.0000000 0.8218740 2.7928460 2.7928460 2.7928460 2.7928460 + AtZNuc= 8.0000000 6.0000000 6.0000000 17.0000000 1.0000000 1.0000000 1.0000000 1.0000000 + Leave Link 101 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l202.exe) + Input orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 8 0 2.440519 -0.740222 0.000056 + 2 6 0 1.230401 -0.154439 0.000037 + 3 6 0 0.992406 1.167521 0.000070 + 4 17 0 -2.247152 -0.153960 -0.000079 + 5 1 0 3.139983 -0.071898 0.000098 + 6 1 0 0.429789 -0.881122 -0.000010 + 7 1 0 1.797209 1.893741 0.000117 + 8 1 0 -0.026387 1.519886 0.000049 + --------------------------------------------------------------------- + Distance matrix (angstroms): + 1 2 3 4 5 + 1 O 0.000000 + 2 C 1.344443 0.000000 + 3 C 2.395102 1.343213 0.000000 + 4 Cl 4.724189 3.477553 3.498721 0.000000 + 5 H 0.967423 1.911365 2.479566 5.387760 0.000000 + 6 H 2.015661 1.081225 2.124494 2.773946 2.828426 + 7 H 2.711385 2.125162 1.084022 4.533204 2.380500 + 8 H 3.345701 2.093533 1.078008 2.780927 3.543963 + 6 7 8 + 6 H 0.000000 + 7 H 3.093494 0.000000 + 8 H 2.443959 1.861524 0.000000 + Stoichiometry C2H4ClO(2) + Framework group C1[X(C2H4ClO)] + Deg. of freedom 18 + Full point group C1 NOp 1 + Largest Abelian subgroup C1 NOp 1 + Largest concise Abelian subgroup C1 NOp 1 + Standard orientation: + --------------------------------------------------------------------- + Center Atomic Atomic Coordinates (Angstroms) + Number Number Type X Y Z + --------------------------------------------------------------------- + 1 8 0 2.440519 -0.740222 0.000056 + 2 6 0 1.230401 -0.154439 0.000037 + 3 6 0 0.992406 1.167521 0.000070 + 4 17 0 -2.247152 -0.153960 -0.000079 + 5 1 0 3.139983 -0.071898 0.000098 + 6 1 0 0.429789 -0.881122 -0.000010 + 7 1 0 1.797209 1.893741 0.000117 + 8 1 0 -0.026387 1.519886 0.000049 + --------------------------------------------------------------------- + Rotational constants (GHZ): 15.3811042 1.6067831 1.4548071 + Leave Link 202 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l301.exe) + Standard basis: def2TZVP (5D, 7F) + Ernie: Thresh= 0.10000D-02 Tol= 0.10000D-05 Strict=F. + There are 174 symmetry adapted cartesian basis functions of A symmetry. + There are 154 symmetry adapted basis functions of A symmetry. + 154 basis functions, 254 primitive gaussians, 174 cartesian basis functions + 21 alpha electrons 20 beta electrons + nuclear repulsion energy 126.7866546617 Hartrees. + IExCor= 402 DFT=T Ex+Corr=B3LYP ExCW=0 ScaHFX= 0.200000 + ScaDFX= 0.800000 0.720000 1.000000 0.810000 ScalE2= 1.000000 1.000000 + IRadAn= 5 IRanWt= -1 IRanGd= 0 ICorTp=0 IEmpDi= 4 + NAtoms= 8 NActive= 8 NUniq= 8 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F + Integral buffers will be 131072 words long. + Raffenetti 2 integral format. + Two-electron integral symmetry is turned on. + Leave Link 301 at Thu Aug 13 03:09:38 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l302.exe) + NPDir=0 NMtPBC= 1 NCelOv= 1 NCel= 1 NClECP= 1 NCelD= 1 + NCelK= 1 NCelE2= 1 NClLst= 1 CellRange= 0.0. + One-electron integrals computed using PRISM. + One-electron integral symmetry used in STVInt + 1 Symmetry operations used in ECPInt. + ECPInt: NShTT= 1953 NPrTT= 6330 LenC2= 1888 LenP2D= 4987. + LDataN: DoStor=T MaxTD1= 6 Len= 172 + NBasis= 154 RedAO= T EigKep= 2.05D-04 NBF= 154 + NBsUse= 154 1.00D-06 EigRej= -1.00D+00 NBFU= 154 + Precomputing XC quadrature grid using + IXCGrd= 4 IRadAn= 5 IRanWt= -1 IRanGd= 0 AccXCQ= 1.00D-12. + Generated NRdTot= 0 NPtTot= 0 NUsed= 0 NTot= 32 + NSgBfM= 173 173 173 173 173 MxSgAt= 8 MxSgA2= 8. + Leave Link 302 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.7 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l303.exe) + DipDrv: MaxL=1. + Leave Link 303 at Thu Aug 13 03:09:39 2026, MaxMem= 2097152000 cpu: 0.1 elap: 0.1 + (Enter /usr/local/g16-gpu/g16/l401.exe) + ExpMin= 9.52D-02 ExpMax= 6.95D+04 ExpMxC= 2.37D+03 IAcc=3 IRadAn= 5 AccDes= 0.00D+00 + Harris functional with IExCor= 402 and IRadAn= 5 diagonalized for initial guess. + HarFok: IExCor= 402 AccDes= 0.00D+00 IRadAn= 5 IDoV= 1 UseB2=F ITyADJ=14 + ICtDFT= 3500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000 + FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0 + NFxFlg= 0 DoJE=T BraDBF=F KetDBF=T FulRan=T + wScrn= 0.000000 ICntrl= 500 IOpCl= 0 I1Cent= 200000004 NGrid= 0 + NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Petite list used in FoFCou. + Harris En= -614.011389393909 + JPrj=0 DoOrth=F DoCkMO=F. + Initial guess = 0.0000 = 0.0000 = 0.5000 = 0.7500 S= 0.5000 + Leave Link 401 at Thu Aug 13 03:09:40 2026, MaxMem= 2097152000 cpu: 2.1 elap: 0.4 + (Enter /usr/local/g16-gpu/g16/l502.exe) + Keep R1 and R2 ints in memory in canonical form, NReq=150468028. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 11935 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + UHF open shell SCF: + Using DIIS extrapolation, IDIIS= 1040. + NGot= 2097152000 LenX= 1954632054 LenY= 1954601337 + Requested convergence on RMS density matrix=1.00D-08 within 128 cycles. + Requested convergence on MAX density matrix=1.00D-06. + Requested convergence on energy=1.00D-06. + No special actions if energy rises. + Integral accuracy reduced to 1.0D-05 until final iterations. + + Cycle 1 Pass 0 IDiag 1: + E= -613.910747029835 + DIIS: error= 3.35D-02 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -613.910747029835 IErMin= 1 ErrMin= 3.35D-02 + ErrMax= 3.35D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.88D-01 BMatP= 6.88D-01 + IDIUse=3 WtCom= 6.65D-01 WtEn= 3.35D-01 + Coeff-Com: 0.100D+01 + Coeff-En: 0.100D+01 + Coeff: 0.100D+01 + Gap= 0.578 Goal= None Shift= 0.000 + Gap= 0.086 Goal= None Shift= 0.000 + GapD= 0.086 DampG=0.500 DampE=0.500 DampFc=0.2500 IDamp=-1. + Damping current iteration by 2.50D-01 + RMSDP=4.91D-03 MaxDP=2.81D-01 OVMax= 9.90D-01 + + Cycle 2 Pass 0 IDiag 1: + E= -613.973516124823 Delta-E= -0.062769094988 Rises=F Damp=T + DIIS: error= 1.49D-02 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 2 EnMin= -613.973516124823 IErMin= 2 ErrMin= 1.49D-02 + ErrMax= 1.49D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.38D-01 BMatP= 6.88D-01 + IDIUse=3 WtCom= 8.51D-01 WtEn= 1.49D-01 + Coeff-Com: -0.539D+00 0.154D+01 + Coeff-En: 0.000D+00 0.100D+01 + Coeff: -0.459D+00 0.146D+01 + Gap= 0.274 Goal= None Shift= 0.000 + Gap= 0.167 Goal= None Shift= 0.000 + RMSDP=1.56D-03 MaxDP=7.00D-02 DE=-6.28D-02 OVMax= 9.93D-01 + + Cycle 3 Pass 0 IDiag 1: + E= -614.021324142472 Delta-E= -0.047808017649 Rises=F Damp=F + DIIS: error= 1.77D-02 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -614.021324142472 IErMin= 2 ErrMin= 1.49D-02 + ErrMax= 1.77D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.35D-02 BMatP= 1.38D-01 + IDIUse=3 WtCom= 8.23D-01 WtEn= 1.77D-01 + Coeff-Com: -0.438D+00 0.911D+00 0.527D+00 + Coeff-En: 0.000D+00 0.000D+00 0.100D+01 + Coeff: -0.361D+00 0.750D+00 0.610D+00 + Gap= 0.332 Goal= None Shift= 0.000 + Gap= 0.073 Goal= None Shift= 0.000 + RMSDP=2.97D-03 MaxDP=1.90D-01 DE=-4.78D-02 OVMax= 8.22D-01 + + Cycle 4 Pass 0 IDiag 1: + E= -613.981289182215 Delta-E= 0.040034960257 Rises=F Damp=F + DIIS: error= 2.88D-02 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 3 EnMin= -614.021324142472 IErMin= 2 ErrMin= 1.49D-02 + ErrMax= 2.88D-02 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.62D-01 BMatP= 8.35D-02 + IDIUse=2 WtCom= 0.00D+00 WtEn= 1.00D+00 + Coeff-En: 0.000D+00 0.000D+00 0.627D+00 0.373D+00 + Coeff: 0.000D+00 0.000D+00 0.627D+00 0.373D+00 + Gap= 0.264 Goal= None Shift= 0.000 + Gap= 0.009 Goal= None Shift= 0.000 + RMSDP=1.94D-03 MaxDP=1.52D-01 DE= 4.00D-02 OVMax= 5.77D-01 + + Cycle 5 Pass 0 IDiag 1: + E= -614.051875023105 Delta-E= -0.070585840890 Rises=F Damp=F + DIIS: error= 3.29D-03 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -614.051875023105 IErMin= 5 ErrMin= 3.29D-03 + ErrMax= 3.29D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 4.85D-03 BMatP= 8.35D-02 + IDIUse=3 WtCom= 9.67D-01 WtEn= 3.29D-02 + Coeff-Com: -0.841D-01 0.152D+00 0.242D+00 0.140D+00 0.550D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.338D-01 0.966D+00 + Coeff: -0.813D-01 0.147D+00 0.234D+00 0.137D+00 0.564D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.030 Goal= None Shift= 0.000 + RMSDP=2.66D-04 MaxDP=1.07D-02 DE=-7.06D-02 OVMax= 6.11D-02 + + Cycle 6 Pass 0 IDiag 1: + E= -614.053247746096 Delta-E= -0.001372722992 Rises=F Damp=F + DIIS: error= 2.03D-03 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -614.053247746096 IErMin= 6 ErrMin= 2.03D-03 + ErrMax= 2.03D-03 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.03D-03 BMatP= 4.85D-03 + IDIUse=3 WtCom= 9.80D-01 WtEn= 2.03D-02 + Coeff-Com: -0.484D-01 0.704D-01 0.648D-01 0.464D-01 0.390D+00 0.477D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.117D+00 0.883D+00 + Coeff: -0.474D-01 0.690D-01 0.634D-01 0.455D-01 0.384D+00 0.485D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.034 Goal= None Shift= 0.000 + RMSDP=1.46D-04 MaxDP=6.11D-03 DE=-1.37D-03 OVMax= 3.20D-02 + + Cycle 7 Pass 0 IDiag 1: + E= -614.053608069601 Delta-E= -0.000360323504 Rises=F Damp=F + DIIS: error= 8.33D-04 at cycle 7 NSaved= 7. + NSaved= 7 IEnMin= 7 EnMin= -614.053608069601 IErMin= 7 ErrMin= 8.33D-04 + ErrMax= 8.33D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.07D-04 BMatP= 2.03D-03 + IDIUse=3 WtCom= 9.92D-01 WtEn= 8.33D-03 + Coeff-Com: 0.503D-02-0.101D-01 0.110D-02-0.126D-01 0.612D-01 0.148D+00 + Coeff-Com: 0.807D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.114D+00 + Coeff-En: 0.886D+00 + Coeff: 0.499D-02-0.100D-01 0.109D-02-0.125D-01 0.607D-01 0.148D+00 + Coeff: 0.808D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.037 Goal= None Shift= 0.000 + RMSDP=2.60D-05 MaxDP=7.89D-04 DE=-3.60D-04 OVMax= 3.35D-03 + + Cycle 8 Pass 0 IDiag 1: + E= -614.053651482912 Delta-E= -0.000043413311 Rises=F Damp=F + DIIS: error= 5.29D-04 at cycle 8 NSaved= 8. + NSaved= 8 IEnMin= 8 EnMin= -614.053651482912 IErMin= 8 ErrMin= 5.29D-04 + ErrMax= 5.29D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 6.74D-05 BMatP= 2.07D-04 + IDIUse=3 WtCom= 9.95D-01 WtEn= 5.29D-03 + Coeff-Com: 0.265D-02-0.447D-02 0.444D-02-0.117D-01 0.365D-01 0.316D-01 + Coeff-Com: 0.138D+00 0.803D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.100D+01 + Coeff: 0.263D-02-0.445D-02 0.441D-02-0.116D-01 0.363D-01 0.314D-01 + Coeff: 0.137D+00 0.805D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=2.29D-05 MaxDP=1.21D-03 DE=-4.34D-05 OVMax= 5.66D-03 + + Cycle 9 Pass 0 IDiag 1: + E= -614.053675095330 Delta-E= -0.000023612418 Rises=F Damp=F + DIIS: error= 2.23D-04 at cycle 9 NSaved= 9. + NSaved= 9 IEnMin= 9 EnMin= -614.053675095330 IErMin= 9 ErrMin= 2.23D-04 + ErrMax= 2.23D-04 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.40D-05 BMatP= 6.74D-05 + IDIUse=3 WtCom= 9.98D-01 WtEn= 2.23D-03 + Coeff-Com: -0.168D-02 0.310D-02 0.441D-02-0.699D-02 0.162D-01-0.123D-01 + Coeff-Com: -0.136D+00 0.354D+00 0.779D+00 + Coeff-En: 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + Coeff-En: 0.000D+00 0.000D+00 0.100D+01 + Coeff: -0.168D-02 0.310D-02 0.440D-02-0.698D-02 0.161D-01-0.122D-01 + Coeff: -0.136D+00 0.353D+00 0.780D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=1.37D-05 MaxDP=7.10D-04 DE=-2.36D-05 OVMax= 3.53D-03 + + Cycle 10 Pass 0 IDiag 1: + E= -614.053680945009 Delta-E= -0.000005849679 Rises=F Damp=F + DIIS: error= 4.72D-05 at cycle 10 NSaved= 10. + NSaved=10 IEnMin=10 EnMin= -614.053680945009 IErMin=10 ErrMin= 4.72D-05 + ErrMax= 4.72D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.77D-07 BMatP= 1.40D-05 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.370D-03 0.605D-03-0.445D-03 0.140D-02-0.574D-02-0.568D-02 + Coeff-Com: -0.326D-01-0.248D+00 0.123D+00 0.117D+01 + Coeff: -0.370D-03 0.605D-03-0.445D-03 0.140D-02-0.574D-02-0.568D-02 + Coeff: -0.326D-01-0.248D+00 0.123D+00 0.117D+01 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=7.03D-06 MaxDP=2.84D-04 DE=-5.85D-06 OVMax= 1.48D-03 + + Initial convergence to 1.0D-05 achieved. Increase integral accuracy. + Cycle 11 Pass 1 IDiag 1: + E= -614.053677201194 Delta-E= 0.000003743815 Rises=F Damp=F + DIIS: error= 2.93D-05 at cycle 1 NSaved= 1. + NSaved= 1 IEnMin= 1 EnMin= -614.053677201194 IErMin= 1 ErrMin= 2.93D-05 + ErrMax= 2.93D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.67D-07 BMatP= 2.67D-07 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.100D+01 + Coeff: 0.100D+01 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=7.03D-06 MaxDP=2.84D-04 DE= 3.74D-06 OVMax= 2.58D-03 + + Cycle 12 Pass 1 IDiag 1: + E= -614.053676270920 Delta-E= 0.000000930274 Rises=F Damp=F + DIIS: error= 9.85D-05 at cycle 2 NSaved= 2. + NSaved= 2 IEnMin= 1 EnMin= -614.053677201194 IErMin= 1 ErrMin= 2.93D-05 + ErrMax= 9.85D-05 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.67D-06 BMatP= 2.67D-07 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.791D+00 0.209D+00 + Coeff: 0.791D+00 0.209D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=7.61D-06 MaxDP=4.58D-04 DE= 9.30D-07 OVMax= 2.19D-03 + + Cycle 13 Pass 1 IDiag 1: + E= -614.053677311429 Delta-E= -0.000001040509 Rises=F Damp=F + DIIS: error= 9.34D-06 at cycle 3 NSaved= 3. + NSaved= 3 IEnMin= 3 EnMin= -614.053677311429 IErMin= 3 ErrMin= 9.34D-06 + ErrMax= 9.34D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.98D-08 BMatP= 2.67D-07 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.336D-01 0.807D-01 0.886D+00 + Coeff: 0.336D-01 0.807D-01 0.886D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=9.77D-07 MaxDP=4.57D-05 DE=-1.04D-06 OVMax= 2.54D-04 + + Cycle 14 Pass 1 IDiag 1: + E= -614.053677329482 Delta-E= -0.000000018053 Rises=F Damp=F + DIIS: error= 6.10D-06 at cycle 4 NSaved= 4. + NSaved= 4 IEnMin= 4 EnMin= -614.053677329482 IErMin= 4 ErrMin= 6.10D-06 + ErrMax= 6.10D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.45D-09 BMatP= 2.98D-08 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.684D-01-0.200D-02 0.374D+00 0.697D+00 + Coeff: -0.684D-01-0.200D-02 0.374D+00 0.697D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=3.73D-07 MaxDP=1.88D-05 DE=-1.81D-08 OVMax= 6.69D-05 + + Cycle 15 Pass 1 IDiag 1: + E= -614.053677334062 Delta-E= -0.000000004580 Rises=F Damp=F + DIIS: error= 3.81D-06 at cycle 5 NSaved= 5. + NSaved= 5 IEnMin= 5 EnMin= -614.053677334062 IErMin= 5 ErrMin= 3.81D-06 + ErrMax= 3.81D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 2.99D-09 BMatP= 8.45D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: -0.267D-01-0.475D-01-0.188D+00 0.162D+00 0.110D+01 + Coeff: -0.267D-01-0.475D-01-0.188D+00 0.162D+00 0.110D+01 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=4.15D-07 MaxDP=1.71D-05 DE=-4.58D-09 OVMax= 7.46D-05 + + Cycle 16 Pass 1 IDiag 1: + E= -614.053677336810 Delta-E= -0.000000002747 Rises=F Damp=F + DIIS: error= 2.44D-06 at cycle 6 NSaved= 6. + NSaved= 6 IEnMin= 6 EnMin= -614.053677336810 IErMin= 6 ErrMin= 2.44D-06 + ErrMax= 2.44D-06 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.35D-09 BMatP= 2.99D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.911D-02-0.384D-01-0.292D+00-0.164D+00 0.800D+00 0.685D+00 + Coeff: 0.911D-02-0.384D-01-0.292D+00-0.164D+00 0.800D+00 0.685D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=2.47D-07 MaxDP=1.15D-05 DE=-2.75D-09 OVMax= 4.59D-05 + + Cycle 17 Pass 1 IDiag 1: + E= -614.053677337549 Delta-E= -0.000000000739 Rises=F Damp=F + DIIS: error= 4.13D-07 at cycle 7 NSaved= 7. + NSaved= 7 IEnMin= 7 EnMin= -614.053677337549 IErMin= 7 ErrMin= 4.13D-07 + ErrMax= 4.13D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 8.01D-11 BMatP= 1.35D-09 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.617D-02-0.176D-01-0.145D+00-0.961D-01 0.360D+00 0.369D+00 + Coeff-Com: 0.524D+00 + Coeff: 0.617D-02-0.176D-01-0.145D+00-0.961D-01 0.360D+00 0.369D+00 + Coeff: 0.524D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=3.13D-08 MaxDP=1.33D-06 DE=-7.39D-10 OVMax= 6.18D-06 + + Cycle 18 Pass 1 IDiag 1: + E= -614.053677337566 Delta-E= -0.000000000018 Rises=F Damp=F + DIIS: error= 1.76D-07 at cycle 8 NSaved= 8. + NSaved= 8 IEnMin= 8 EnMin= -614.053677337566 IErMin= 8 ErrMin= 1.76D-07 + ErrMax= 1.76D-07 0.00D+00 EMaxC= 1.00D-01 BMatC= 1.35D-11 BMatP= 8.01D-11 + IDIUse=1 WtCom= 1.00D+00 WtEn= 0.00D+00 + Coeff-Com: 0.245D-02-0.506D-02-0.449D-01-0.322D-01 0.970D-01 0.124D+00 + Coeff-Com: 0.321D+00 0.538D+00 + Coeff: 0.245D-02-0.506D-02-0.449D-01-0.322D-01 0.970D-01 0.124D+00 + Coeff: 0.321D+00 0.538D+00 + Gap= 0.263 Goal= None Shift= 0.000 + Gap= 0.038 Goal= None Shift= 0.000 + RMSDP=8.08D-09 MaxDP=2.88D-07 DE=-1.75D-11 OVMax= 1.06D-06 + + SCF Done: E(UB3LYP) = -614.053677338 A.U. after 18 cycles + NFock= 18 Conv=0.81D-08 -V/T= 2.0023 + = 0.0000 = 0.0000 = 0.5000 = 0.7536 S= 0.5018 + = 0.00000000000 + KE= 6.126643386659D+02 PE=-1.708196810389D+03 EE= 3.546921397242D+02 + Annihilation of the first spin contaminant: + S**2 before annihilation 0.7536, after 0.7500 + Leave Link 502 at Thu Aug 13 03:09:49 2026, MaxMem= 2097152000 cpu: 41.7 elap: 8.7 + (Enter /usr/local/g16-gpu/g16/l801.exe) + DoSCS=F DFT=T ScalE2(SS,OS)= 1.000000 1.000000 + Range of M.O.s used for correlation: 1 154 + NBasis= 154 NAE= 21 NBE= 20 NFC= 0 NFV= 0 + NROrb= 154 NOA= 21 NOB= 20 NVA= 133 NVB= 134 + + **** Warning!!: The largest alpha MO coefficient is 0.19859257D+02 + + + **** Warning!!: The largest beta MO coefficient is 0.19848601D+02 + + + **** Warning!!: The smallest beta delta epsilon is 0.37722939D-01 + + Leave Link 801 at Thu Aug 13 03:09:49 2026, MaxMem= 2097152000 cpu: 0.0 elap: 0.0 + (Enter /usr/local/g16-gpu/g16/l914.exe) + UHF ground state + Doing stability rather than CIS. + Keep R1 and R2 ints in memory in canonical form, NReq=163689768. + FoFCou: FMM=F IPFlag= 0 FMFlag= 0 FMFlg1= 0 + NFxFlg= 0 DoJE=F BraDBF=F KetDBF=F FulRan=T + wScrn= 0.000000 ICntrl= 600 IOpCl= 0 I1Cent= 0 NGrid= 0 + NMat0= 1 NMatS0= 11935 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0 + Symmetry not used in FoFCou. + Two-electron integral symmetry not used. + MDV= 2097152000 DFT=T DoStab=T Mixed=T DoRPA=F DoScal=F NonHer=F + Making orbital integer symmetry assigments: + Orbital symmetries: + Alpha Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) + Beta Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) + 12 initial guesses have been made. + Convergence on wavefunction: 0.001000000000000 + Davidson Disk Diagonalization: ConvIn= 1.00D-03 SkipCon=T Conv= 1.00D-03. + Max sub-space: 2000 roots to seek: 12 dimension of matrix: 5473 + Iteration 1 Dimension 12 NMult 0 NNew 12 + CISAX will form 12 AO SS matrices at one time. + NMat= 12 NSing= 12 JSym2X= 0. + New state 1 was old state 2 + New state 2 was old state 3 + New state 3 was old state 7 + Excitation Energies [eV] at current iteration: + Root 1 : 0.287809507366659 + Root 2 : 0.305306338808830 + Root 3 : 3.693445236926746 + Root 4 : 3.972937973331037 + Root 5 : 4.260140842382059 + Root 6 : 4.323235356760486 + Root 7 : 5.452234124386406 + Root 8 : 6.066569049716820 + Root 9 : 6.495181850440853 + Root 10 : 6.995570484340544 + Root 11 : 7.240827349603387 + Root 12 : 12.518479238679790 + Iteration 2 Dimension 24 NMult 12 NNew 12 + CISAX will form 12 AO SS matrices at one time. + NMat= 12 NSing= 12 JSym2X= 0. + Root 1 not converged, maximum delta is 0.080709987182331 + Root 2 not converged, maximum delta is 0.080907225248186 + New state 3 was old state 5 + Root 3 not converged, maximum delta is 0.230779454794897 + Excitation Energies [eV] at current iteration: + Root 1 : 0.074014118528514 Change is -0.213795388838145 + Root 2 : 0.092307766200499 Change is -0.212998572608332 + Root 3 : 2.123256851745771 Change is -2.136883990636288 + Root 4 : 3.236732219418885 Change is -0.456713017507862 + Root 5 : 3.919889711084740 Change is -0.053048262246296 + Root 6 : 4.265197830622467 Change is -0.058037526138019 + Root 7 : 4.854521419509651 Change is -0.597712704876755 + Root 8 : 5.946549548951164 Change is -0.120019500765657 + Root 9 : 6.427956684935390 Change is -0.067225165505463 + Root 10 : 6.887304872201069 Change is -0.108265612139474 + Root 11 : 7.228685178442135 Change is -0.012142171161252 + Root 12 : 9.662463882926380 + Iteration 3 Dimension 27 NMult 24 NNew 3 + CISAX will form 3 AO SS matrices at one time. + NMat= 3 NSing= 3 JSym2X= 0. + Root 1 not converged, maximum delta is 0.015004464215541 + Root 2 not converged, maximum delta is 0.014993864549171 + Root 3 not converged, maximum delta is 0.015819865660268 + Excitation Energies [eV] at current iteration: + Root 1 : 0.067094807749410 Change is -0.006919310779105 + Root 2 : 0.085639159495016 Change is -0.006668606705482 + Root 3 : 2.037339206639396 Change is -0.085917645106375 + Iteration 4 Dimension 30 NMult 27 NNew 3 + CISAX will form 3 AO SS matrices at one time. + NMat= 3 NSing= 3 JSym2X= 0. + Root 1 not converged, maximum delta is 0.002587908914357 + Root 2 not converged, maximum delta is 0.002607425530167 + Root 3 not converged, maximum delta is 0.005334022775534 + Excitation Energies [eV] at current iteration: + Root 1 : 0.066995391188385 Change is -0.000099416561025 + Root 2 : 0.085597241034006 Change is -0.000041918461010 + Root 3 : 2.027329048905484 Change is -0.010010157733911 + Iteration 5 Dimension 33 NMult 30 NNew 3 + CISAX will form 3 AO SS matrices at one time. + NMat= 3 NSing= 3 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 not converged, maximum delta is 0.001810706099070 + Excitation Energies [eV] at current iteration: + Root 1 : 0.066992604926564 Change is -0.000002786261821 + Root 2 : 0.085595469900637 Change is -0.000001771133369 + Root 3 : 2.026471834315779 Change is -0.000857214589706 + Iteration 6 Dimension 34 NMult 33 NNew 1 + CISAX will form 1 AO SS matrices at one time. + NMat= 1 NSing= 1 JSym2X= 0. + Root 1 has converged. + Root 2 has converged. + Root 3 has converged. + Excitation Energies [eV] at current iteration: + Root 1 : 0.066992604926582 Change is 0.000000000000018 + Root 2 : 0.085595469900643 Change is 0.000000000000006 + Root 3 : 2.026417390051019 Change is -0.000054444264760 + Convergence achieved on expansion vectors. + *********************************************************************** + Stability analysis using singles matrix: + *********************************************************************** + 1PDM for each excited state written to RWF 633 + Ground to excited state transition densities written to RWF 633 + + Eigenvectors of the stability matrix: + + Eigenvector 1: 2.012-A Eigenvalue= 0.0024619 =0.762 + 18B -> 21B 0.22876 + 19B -> 21B 0.96922 + + Eigenvector 2: 2.012-A Eigenvalue= 0.0031456 =0.762 + 18B -> 21B 0.96931 + 19B -> 21B -0.22909 + + Eigenvector 3: 2.041-A Eigenvalue= 0.0744695 =0.791 + 20B -> 21B 0.94816 + The wavefunction is stable under the perturbations considered. + Leave Link 914 at Thu Aug 13 03:10:14 2026, MaxMem= 2097152000 cpu: 197.5 elap: 25.3 + (Enter /usr/local/g16-gpu/g16/l601.exe) + Copying SCF densities to generalized density rwf, IOpCl= 1 IROHF=0. + + ********************************************************************** + + Population analysis using the SCF Density. + + ********************************************************************** + + Orbital symmetries: + Alpha Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) + Beta Orbitals: + Occupied (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) + Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) + (A) (A) + The electronic state is 2-A. + Alpha occ. eigenvalues -- -101.51917 -19.20084 -10.26633 -10.19618 -9.44869 + Alpha occ. eigenvalues -- -7.21776 -7.20021 -7.20017 -1.10610 -0.79733 + Alpha occ. eigenvalues -- -0.78569 -0.66034 -0.53345 -0.51691 -0.43884 + Alpha occ. eigenvalues -- -0.42014 -0.40449 -0.35408 -0.31253 -0.31194 + Alpha occ. eigenvalues -- -0.27762 + Alpha virt. eigenvalues -- -0.01435 0.00600 0.06858 0.08841 0.11584 + Alpha virt. eigenvalues -- 0.14857 0.18399 0.19007 0.21424 0.26923 + Alpha virt. eigenvalues -- 0.27684 0.28336 0.32302 0.34211 0.35051 + Alpha virt. eigenvalues -- 0.37670 0.38403 0.39712 0.41183 0.41540 + Alpha virt. eigenvalues -- 0.41987 0.44261 0.45441 0.46037 0.49172 + Alpha virt. eigenvalues -- 0.49816 0.52362 0.53113 0.56624 0.59973 + Alpha virt. eigenvalues -- 0.65367 0.68032 0.72305 0.75968 0.82616 + Alpha virt. eigenvalues -- 0.83306 0.94278 0.96737 1.03931 1.06828 + Alpha virt. eigenvalues -- 1.12316 1.21440 1.26495 1.34767 1.36798 + Alpha virt. eigenvalues -- 1.49908 1.51730 1.52316 1.56161 1.62671 + Alpha virt. eigenvalues -- 1.66552 1.70849 1.71162 1.71832 1.71997 + Alpha virt. eigenvalues -- 1.75257 1.77343 1.77605 1.80872 1.81975 + Alpha virt. eigenvalues -- 1.82512 1.95489 1.96628 2.05814 2.06322 + Alpha virt. eigenvalues -- 2.06436 2.07743 2.07791 2.09323 2.11058 + Alpha virt. eigenvalues -- 2.11291 2.15431 2.17963 2.18615 2.19491 + Alpha virt. eigenvalues -- 2.23304 2.26115 2.28199 2.36124 2.38486 + Alpha virt. eigenvalues -- 2.47658 2.51487 2.54279 2.58288 2.65942 + Alpha virt. eigenvalues -- 2.74929 2.75362 2.79666 2.80834 2.85699 + Alpha virt. eigenvalues -- 2.96808 3.00576 3.01237 3.03600 3.03993 + Alpha virt. eigenvalues -- 3.13109 3.15609 3.25388 3.31063 3.35819 + Alpha virt. eigenvalues -- 3.36075 3.38710 3.50118 3.71001 3.79186 + Alpha virt. eigenvalues -- 3.86001 4.04750 4.13314 4.24959 4.28964 + Alpha virt. eigenvalues -- 4.37764 4.55166 4.59938 4.79807 5.18980 + Alpha virt. eigenvalues -- 5.33892 5.42048 5.74476 5.80773 6.12361 + Alpha virt. eigenvalues -- 6.24379 6.33920 6.65542 6.69859 6.88202 + Alpha virt. eigenvalues -- 7.11109 10.63254 10.68440 10.70330 22.06652 + Alpha virt. eigenvalues -- 22.70218 23.95733 43.65309 + Beta occ. eigenvalues -- -101.51340 -19.19934 -10.26587 -10.19390 -9.44360 + Beta occ. eigenvalues -- -7.20022 -7.19703 -7.19699 -1.10315 -0.78126 + Beta occ. eigenvalues -- -0.75506 -0.65838 -0.53173 -0.51515 -0.42980 + Beta occ. eigenvalues -- -0.41910 -0.40267 -0.30126 -0.30067 -0.25845 + Beta virt. eigenvalues -- -0.22073 -0.00483 0.00643 0.06934 0.09000 + Beta virt. eigenvalues -- 0.11676 0.14998 0.18514 0.19530 0.21517 + Beta virt. eigenvalues -- 0.27071 0.28182 0.28445 0.32389 0.35448 + Beta virt. eigenvalues -- 0.36574 0.37933 0.38755 0.40009 0.43712 + Beta virt. eigenvalues -- 0.44570 0.45150 0.45676 0.46558 0.47705 + Beta virt. eigenvalues -- 0.49339 0.50050 0.52651 0.53360 0.57081 + Beta virt. eigenvalues -- 0.60095 0.65695 0.68525 0.73107 0.76175 + Beta virt. eigenvalues -- 0.82903 0.83564 0.94424 0.97172 1.04289 + Beta virt. eigenvalues -- 1.07083 1.12352 1.21656 1.26753 1.35003 + Beta virt. eigenvalues -- 1.37565 1.49974 1.51964 1.52582 1.56787 + Beta virt. eigenvalues -- 1.62779 1.66649 1.71865 1.73409 1.73586 + Beta virt. eigenvalues -- 1.74295 1.75372 1.77609 1.77949 1.81166 + Beta virt. eigenvalues -- 1.82287 1.82901 1.95785 1.96761 2.09401 + Beta virt. eigenvalues -- 2.10249 2.10359 2.10429 2.10613 2.10763 + Beta virt. eigenvalues -- 2.11287 2.11438 2.16922 2.18909 2.19607 + Beta virt. eigenvalues -- 2.20945 2.23971 2.26729 2.28593 2.36258 + Beta virt. eigenvalues -- 2.38652 2.48336 2.51630 2.54490 2.58833 + Beta virt. eigenvalues -- 2.66180 2.75426 2.75569 2.80097 2.81076 + Beta virt. eigenvalues -- 2.85773 2.97412 3.01174 3.01331 3.04067 + Beta virt. eigenvalues -- 3.04160 3.13405 3.16157 3.25704 3.31199 + Beta virt. eigenvalues -- 3.36457 3.36509 3.39193 3.50380 3.71401 + Beta virt. eigenvalues -- 3.79423 3.86188 4.04979 4.13531 4.25664 + Beta virt. eigenvalues -- 4.29186 4.37908 4.55472 4.60088 4.79977 + Beta virt. eigenvalues -- 5.19312 5.34175 5.42341 5.74833 5.81026 + Beta virt. eigenvalues -- 6.12420 6.24695 6.34444 6.66011 6.70167 + Beta virt. eigenvalues -- 6.88366 7.11203 10.66109 10.68924 10.70812 + Beta virt. eigenvalues -- 22.06873 22.70326 23.96675 43.65461 + Condensed to atoms (all electrons): + 1 2 3 4 5 6 + 1 O 7.822274 0.360797 -0.090033 0.000047 0.291462 -0.030942 + 2 C 0.360797 4.706826 0.556032 -0.014005 -0.047670 0.404128 + 3 C -0.090033 0.556032 5.091116 -0.009535 -0.002402 -0.045778 + 4 Cl 0.000047 -0.014005 -0.009535 17.174535 -0.000058 0.023151 + 5 H 0.291462 -0.047670 -0.002402 -0.000058 0.428587 0.007608 + 6 H -0.030942 0.404128 -0.045778 0.023151 0.007608 0.488266 + 7 H -0.004284 -0.052396 0.411255 0.000702 0.004746 0.003722 + 8 H 0.004492 -0.019608 0.385776 0.018322 0.000916 -0.002685 + 7 8 + 1 O -0.004284 0.004492 + 2 C -0.052396 -0.019608 + 3 C 0.411255 0.385776 + 4 Cl 0.000702 0.018322 + 5 H 0.004746 0.000916 + 6 H 0.003722 -0.002685 + 7 H 0.533214 -0.017491 + 8 H -0.017491 0.482646 + Atomic-Atomic Spin Densities. + 1 2 3 4 5 6 + 1 O 0.066399 -0.011275 -0.004198 0.000083 -0.000083 -0.000203 + 2 C -0.011275 0.018707 0.022422 -0.001666 0.000277 0.001781 + 3 C -0.004198 0.022422 0.144378 -0.003942 0.000002 0.000631 + 4 Cl 0.000083 -0.001666 -0.003942 0.785746 0.000002 -0.002877 + 5 H -0.000083 0.000277 0.000002 0.000002 -0.001614 0.000009 + 6 H -0.000203 0.001781 0.000631 -0.002877 0.000009 -0.002888 + 7 H 0.000049 0.000044 0.000628 -0.000069 0.000002 -0.000112 + 8 H -0.000039 0.000058 0.001052 -0.002085 -0.000009 0.000410 + 7 8 + 1 O 0.000049 -0.000039 + 2 C 0.000044 0.000058 + 3 C 0.000628 0.001052 + 4 Cl -0.000069 -0.002085 + 5 H 0.000002 -0.000009 + 6 H -0.000112 0.000410 + 7 H -0.006635 0.000149 + 8 H 0.000149 -0.006179 + Mulliken charges and spin densities: + 1 2 + 1 O -0.353813 0.050734 + 2 C 0.105896 0.030349 + 3 C -0.296432 0.160974 + 4 Cl -0.193158 0.775193 + 5 H 0.316811 -0.001414 + 6 H 0.152531 -0.003249 + 7 H 0.120531 -0.005944 + 8 H 0.147632 -0.006642 + Sum of Mulliken charges = -0.00000 1.00000 + Mulliken charges and spin densities with hydrogens summed into heavy atoms: + 1 2 + 1 O -0.037001 0.049320 + 2 C 0.258427 0.027100 + 3 C -0.028269 0.148388 + 4 Cl -0.193158 0.775193 + Electronic spatial extent (au): = 717.3794 + Charge= -0.0000 electrons + Dipole moment (field-independent basis, Debye): + X= 3.7084 Y= 1.3557 Z= 0.0002 Tot= 3.9485 + Quadrupole moment (field-independent basis, Debye-Ang): + XX= -29.1606 YY= -31.5725 ZZ= -32.1583 + XY= 3.4002 XZ= 0.0002 YZ= 0.0001 + Traceless Quadrupole moment (field-independent basis, Debye-Ang): + XX= 1.8032 YY= -0.6087 ZZ= -1.1945 + XY= 3.4002 XZ= 0.0002 YZ= 0.0001 + Octapole moment (field-independent basis, Debye-Ang**2): + XXX= 46.2058 YYY= -0.1491 ZZZ= -0.0006 XYY= 0.3684 + XXY= 10.3841 XXZ= 0.0020 XZZ= -3.0556 YZZ= -2.6662 + YYZ= 0.0002 XYZ= 0.0005 + Hexadecapole moment (field-independent basis, Debye-Ang**3): + XXXX= -663.9522 YYYY= -123.3861 ZZZZ= -34.7567 XXXY= 19.8822 + XXXZ= -0.0091 YYYX= 0.7380 YYYZ= -0.0012 ZZZX= -0.0116 + ZZZY= -0.0019 XXYY= -153.1648 XXZZ= -126.7908 YYZZ= -28.8400 + XXYZ= -0.0001 YYXZ= -0.0039 ZZXY= -2.4411 + N-N= 1.267866546617D+02 E-N=-1.708196809853D+03 KE= 6.126643386659D+02 + Isotropic Fermi Contact Couplings + Atom a.u. MegaHertz Gauss 10(-4) cm-1 + 1 O(17) 0.00705 -4.27652 -1.52597 -1.42649 + 2 C(13) -0.00455 -5.11070 -1.82363 -1.70475 + 3 C(13) 0.00700 7.87017 2.80827 2.62521 + 4 Cl(35) 0.09465 41.49937 14.80801 13.84270 + 5 H(1) -0.00083 -3.71522 -1.32568 -1.23926 + 6 H(1) -0.00048 -2.14009 -0.76364 -0.71386 + 7 H(1) -0.00210 -9.39319 -3.35172 -3.13323 + 8 H(1) -0.00209 -9.32025 -3.32570 -3.10890 + -------------------------------------------------------- + Center ---- Spin Dipole Couplings ---- + 3XX-RR 3YY-RR 3ZZ-RR + -------------------------------------------------------- + 1 Atom -0.116747 -0.122072 0.238819 + 2 Atom -0.025444 -0.022848 0.048292 + 3 Atom -0.096266 -0.097846 0.194111 + 4 Atom -2.457258 -2.459796 4.917054 + 5 Atom 0.005081 -0.000395 -0.004686 + 6 Atom 0.006813 -0.000067 -0.006746 + 7 Atom 0.001536 0.000997 -0.002534 + 8 Atom 0.013560 -0.007781 -0.005779 + -------------------------------------------------------- + XY XZ YZ + -------------------------------------------------------- + 1 Atom -0.000913 -0.000011 -0.000011 + 2 Atom -0.004047 -0.000002 -0.000002 + 3 Atom 0.002022 -0.000009 -0.000009 + 4 Atom -0.000061 -0.000290 -0.000243 + 5 Atom 0.006828 0.000001 0.000000 + 6 Atom 0.001263 0.000000 0.000000 + 7 Atom 0.013780 0.000001 0.000001 + 8 Atom -0.002931 0.000001 -0.000000 + -------------------------------------------------------- + + + --------------------------------------------------------------------------------- + Anisotropic Spin Dipole Couplings in Principal Axis System + --------------------------------------------------------------------------------- + + Atom a.u. MegaHertz Gauss 10(-4) cm-1 Axes + + Baa -0.1222 8.844 3.156 2.950 0.1645 0.9864 0.0000 + 1 O(17) Bbb -0.1166 8.437 3.010 2.814 0.9864 -0.1645 0.0000 + Bcc 0.2388 -17.281 -6.166 -5.764 -0.0000 -0.0000 1.0000 + + Baa -0.0284 -3.810 -1.360 -1.271 0.8079 0.5893 0.0000 + 2 C(13) Bbb -0.0199 -2.670 -0.953 -0.891 -0.5893 0.8079 0.0000 + Bcc 0.0483 6.480 2.312 2.162 -0.0000 -0.0000 1.0000 + + Baa -0.0992 -13.315 -4.751 -4.441 -0.5639 0.8258 0.0000 + 3 C(13) Bbb -0.0949 -12.733 -4.543 -4.247 0.8258 0.5639 0.0000 + Bcc 0.1941 26.048 9.295 8.689 -0.0000 -0.0000 1.0000 + + Baa -2.4598 -128.740 -45.938 -42.943 0.0241 0.9997 0.0000 + 4 Cl(35) Bbb -2.4573 -128.607 -45.890 -42.899 0.9997 -0.0241 0.0000 + Bcc 4.9171 257.347 91.828 85.842 -0.0000 -0.0000 1.0000 + + Baa -0.0050 -2.675 -0.955 -0.892 -0.5603 0.8283 0.0000 + 5 H(1) Bbb -0.0047 -2.500 -0.892 -0.834 -0.0000 -0.0000 1.0000 + Bcc 0.0097 5.175 1.847 1.726 0.8283 0.5603 0.0000 + + Baa -0.0067 -3.600 -1.284 -1.201 -0.0000 -0.0000 1.0000 + 6 H(1) Bbb -0.0003 -0.156 -0.056 -0.052 -0.1751 0.9846 0.0000 + Bcc 0.0070 3.755 1.340 1.253 0.9846 0.1751 0.0000 + + Baa -0.0125 -6.678 -2.383 -2.228 -0.7002 0.7140 0.0000 + 7 H(1) Bbb -0.0025 -1.352 -0.482 -0.451 -0.0000 -0.0000 1.0000 + Bcc 0.0150 8.030 2.865 2.678 0.7140 0.7002 0.0000 + + Baa -0.0082 -4.362 -1.557 -1.455 0.1336 0.9910 0.0000 + 8 H(1) Bbb -0.0058 -3.084 -1.100 -1.029 -0.0000 -0.0000 1.0000 + Bcc 0.0140 7.446 2.657 2.484 0.9910 -0.1336 0.0000 + + + --------------------------------------------------------------------------------- + + No NMR shielding tensors so no spin-rotation constants. + Leave Link 601 at Thu Aug 13 03:10:14 2026, MaxMem= 2097152000 cpu: 0.9 elap: 0.2 + (Enter /usr/local/g16-gpu/g16/l9999.exe) + Unable to Open any file for archive entry. + 1\1\GINC-N013\Stability\UB3LYP\def2TZVP\C2H4Cl1O1(2)\CALVIN.P\13-Aug-2 + 026\0\\#P ub3lyp/def2tzvp stable=(rext,noopt) integral=(grid=ultrafine + , Acc2E=12) scf=(direct,tight)\\stability test reaction_21_intra_halog + en_migration\\0,2\O,0,2.440519,-0.740222,0.000056\C,0,1.230401,-0.1544 + 39,0.000037\C,0,0.992406,1.167521,0.00007\Cl,0,-2.247152,-0.15396,-0.0 + 00079\H,0,3.139983,-0.071898,0.000098\H,0,0.429789,-0.881122,-0.00001\ + H,0,1.797209,1.893741,0.000117\H,0,-0.026387,1.519886,0.000049\\Versio + n=ES64L-G16RevC.02\State=2-A\HF=-614.0536773\S2=0.753646\S2-1=0.\S2A=0 + .750009\RMSD=8.083e-09\Dipole=1.4590137,0.533372,0.0000645\Quadrupole= + 1.3406082,-0.4525309,-0.8880773,2.5279978,0.000133,0.0000905\PG=C01 [X + (C2H4Cl1O1)]\\@ + The archive entry for this job was punched. + + + CHILDREN YOU ARE VERY LITTLE, + AND YOUR BONES ARE VERY BRITTLE; + IF YOU WOULD GROW GREAT AND STATELY + YOU MUST TRY TO WALK SEDATELY. + YOU MUST STILL BE BRIGHT AND QUIET, + AND CONTENT WITH SIMPLE DIET; + AND REMAIN, THROUGH ALL BEWILD'RING + INNOCENT AND HONEST CHILDREN. + -- A CHILD'S GARDEN OF VERSE, + ROBERT LOUIS STEVENSON + Job cpu time: 0 days 0 hours 4 minutes 3.8 seconds. + Elapsed time: 0 days 0 hours 0 minutes 35.3 seconds. + File lengths (MBytes): RWF= 139 Int= 0 D2E= 0 Chk= 6 Scr= 1 + Normal termination of Gaussian 16 at Thu Aug 13 03:10:14 2026. From 92019f69c5899e4b5d7b38660beb68f3cbdd80a6 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 02/12] Add the Yamaguchi approximate spin-projection arithmetic E_LS = E_BS + [(_BS - _LS) / (_HS - _BS)] * (E_BS - E_HS) K. Yamaguchi, F. Jensen, A. Dorigo, K. N. Houk, Chem. Phys. Lett. 1988, 149, 537; applied to broken-symmetry DFT by T. Soda et al., Chem. Phys. Lett. 2000, 319, 223. Nothing reads it. No job is spawned, no verdict is consumed, no dispatch path is touched, and what Arkane receives is unchanged. The design it was first written for -- gating on a stability verdict, recomputing the saddle with a broken-symmetry reference and recording a projected energy -- was withdrawn by the chemistry review of its motivating dataset and is not revived. The arithmetic is here because it is self-contained and exactly derived, and because it is what says what an adopted unrestricted energy still is not: a broken-symmetry determinant is not a spin eigenfunction, it mixes in the higher multiplicity, so its energy lies ABOVE the spin-pure low-spin energy, while the restricted energy it replaces lies above the broken-symmetry one in turn. The ordering is E_projected < E_BS < E_restricted, so an adoption is a step toward the spin-pure energy that stops short of it, and ARC projects nothing. The module is registered in arc/checks/__init__.py, which listed common, nmd and ts and omitted spin, so arc.checks.spin raised AttributeError under the package's own access pattern. The source it was carried from was labelled WIP, and the label described the module as well as the withheld design. Four defects a quantum-chemistry review and an adversarial code review found independently are repaired here rather than carried on faith. GENERALISED BEYOND A SINGLET TARGET. The closed form that was implemented, (_HS * E_BS - _BS * E_HS) / (_HS - _BS), is the general expression with _LS = 0 substituted in: it is singlet-only, and nothing in its name, signature, docstring or tests said so. A doublet TS, which is routine in ARC, was silently projected as if its spin-pure were 0 rather than 0.75. For a broken-symmetry doublet / high-spin quartet pair with _BS = 1.0, _HS = 3.80 and a 0.1 Hartree gap the error is 0.0268 Hartree, 16.8 kcal/mol. The general form is implemented instead, and the target state is a REQUIRED argument with no default: both entry points take the multiplicity of the state being projected onto and derive _LS from it through parser.s_squared_expected_from_multiplicity, which is the arithmetic ARC already had for exactly this value. A default of 0.0 would be the same singlet-only assumption made once more, silently, at every call site that omitted it, and the size of that mistake is the 16.8 kcal/mol above. A multiplicity that names no spin state -- missing, non-numeric, below one, non-finite -- is refused with a warning rather than treated as any particular one. BROKEN_SYMMETRY_S2_THRESHOLD had the same defect and is fixed the same way. It compared the ABSOLUTE _BS against 1e-2, not its deviation from S(S+1), so for any non-singlet broken-symmetry reference the flag was unconditionally True and therefore carried no information -- a clean doublet at = 0.7536 read as 'symmetry broken'. The comparison is now against s2_bs - s2_ls, which the signature can express only because s2_ls is now an argument. THE SEPARATION GUARD IS A PHYSICAL FLOOR, NOT A DIVISION-BY-ZERO GUARD. MIN_S2_SEPARATION was 1e-3, which prevents a ZeroDivisionError and nothing else. Two ordinary UHF doublets at 0.7540 and 0.7560, a pair that should never have been projected at all, returned -209.803 Hartree from energies of about -195.29, i.e. 14.5 Hartree and some 9,100 kcal/mol below its own E_BS, reported as a number rather than as None. A genuine broken-symmetry singlet / high-spin triplet pair is separated by about 1.0 and a doublet / quartet pair by about 3.0, so the floor is raised to 0.1: below that the two references do not describe two distinguishable spin states. At a floor of 0.1 no division-by-zero guard is needed on top. THE AMPLIFICATION IS BOUNDED AS WELL, so the floor is not a cliff. A separation floor alone says nothing about the result: at a separation a hair above it the ratio multiplying (E_BS - E_HS) is unbounded, so the first pair admitted past the guard can return an arbitrarily large correction, while the pair a hair below it is refused on logger.debug, i.e. silently. Both are addressed. Every refusal is a logger.warning, because a numeric routine that declines to answer has to say so. And the quantity that decides how far the projection moves the energy, (_BS - _LS) / separation, is capped directly at MAX_PROJECTION_AMPLIFICATION = 2.0. That ratio is w / (1 - w) in the high-spin weight w of the BS determinant: an ideal, fully spin-flipped broken-symmetry solution has w = 0.5 and a ratio of exactly 1, so a ratio above 1 means the BS determinant carries more high-spin than target-spin character. The cap admits w up to two thirds and refuses beyond it, where the correction exceeds twice the BS-to-HS gap. The largest correction any accepted projection can apply is therefore 2.0 * |E_BS - E_HS|, and the first pair accepted past the separation floor is bounded by the same amount as every other. THE INVERTED CASE IS A DIFFERENT FAILURE and no longer shares a branch with the near-degenerate one. For a variationally converged UHF/UKS determinant >= S_z(S_z + 1) always -- spin contamination only ever adds -- so for a properly matched pair at the same geometry and level _HS > _BS is guaranteed, not merely typical. An inversion therefore does not mean 'too close to project'; it means the two references are not the same calculation: the HS SCF converged to a different state, the geometries or levels differ, the arguments were transposed, or an SCF did not converge. It has its own branch and a logger.warning naming the inversion, worded distinctly from the benign near-degenerate one, instead of the arithmetically true but diagnostically misleading 'separated by -1.0, below the 0.001 required'. The mirror-image inconsistency, a broken-symmetry below the target state's own S(S+1), is refused and warned about on the same grounds. NaN AND INFINITY BYPASSED EVERY GUARD, since NaN < 0.1 is False. s2_bs = NaN returned NaN, and get_spin_projection reported broken_symmetry = False for it, which reads as an affirmative 'this reference did not break symmetry' when the truth is that is unknown. All five inputs are now validated with math.isfinite, and the three arguments additionally for non-negativity, which no expectation value of S**2 can violate. broken_symmetry is None, never False, whenever it cannot be judged, as the docstring already promised for the projected energy. The docstring said 'interpolating in between the BS reference and the high-spin reference'. It is extrapolation: the low-spin target lies outside the interval the two references bracket, always, which is the whole point of the scheme. The stated reason for refusing an inverted pair, that it 'places the low-spin state outside the interval the two references bracket', was wrong for the same reason. Both are corrected. The tests are rewritten against literal numbers. The originals referenced MIN_S2_SEPARATION and BROKEN_SYMMETRY_S2_THRESHOLD symbolically -- for instance s2_hs = 2.0 + MIN_S2_SEPARATION / 2 -- which is tautological: it holds for any value of the constant, so mutating 1e-3 to 1e-12 and 1e-2 to 1e3 left all 12 tests green. The constants are now exercised through literal values that fail if any moves, and all three are additionally asserted directly so that changing one is a deliberate act. Each comparison boundary is pinned at the boundary itself: a separation of exactly MIN_S2_SEPARATION is projected and anything below it is not, an amplification of exactly MAX_PROJECTION_AMPLIFICATION is projected and anything above it is not, and a deviation of exactly BROKEN_SYMMETRY_S2_THRESHOLD is not reported as symmetry broken. 36 tests, from 12. Verified by mutation, not only by a green run. Returning None unconditionally fails 13 tests; inverting the sign of the projection term fails 8; replacing the separation guard with a never-taken branch fails 3; reverting the non-finite validation to the original `any(value is None ...)` fails 3; MIN_S2_SEPARATION 0.1 -> 1e-12 fails 4; and BROKEN_SYMMETRY_S2_THRESHOLD 1e-2 -> 1e3 fails 3. Each of the last two survived every one of the original 12 tests. The three boundary comparisons were mutated one at a time: the separation guard's < to <= fails 2, the symmetry-breaking > to >= fails 1, and the amplification cap's > to >= fails 1. THE RECORD NAMES WHAT PRODUCED THE ENERGIES. get_spin_projection takes the level of theory and the geometry as required arguments and carries both, along with the target multiplicity and the _LS derived from it. The scheme extrapolates between two points of ONE potential energy surface, so a pair taken at two levels, or each from its own state's optimized geometry -- which ARC has lying around for the high-spin state -- is not a pair the projection is defined for. Nothing in the record said which surface its two energies came from; now it does. A BROKEN-SYMMETRY BELOW THE SPIN-PURE TARGET BY LESS THAN MIN_S2_SEPARATION is the noise of a determinant that is spin-pure to within that separation, so its amplification is taken as zero and the projected energy is E_BS itself. Amplifying by a negative number returns an energy above E_BS, since E_BS - E_HS is negative, which is the wrong side of the reference the projection starts from and contradicts E_projected < E_BS. A multiplicity is 2S + 1 for a total spin S that is whole or half-integral, so it is a positive integer; a fractional value names no spin state and is refused with the warning every other unusable multiplicity gets, rather than read as the quarter-integral spin the arithmetic would otherwise give it. --- arc/checks/__init__.py | 1 + arc/checks/spin.py | 248 +++++++++++++++++++++++++++ arc/checks/spin_test.py | 367 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 616 insertions(+) create mode 100644 arc/checks/spin.py create mode 100644 arc/checks/spin_test.py diff --git a/arc/checks/__init__.py b/arc/checks/__init__.py index 2fb61ac04c..35a7fbc9fb 100644 --- a/arc/checks/__init__.py +++ b/arc/checks/__init__.py @@ -1,3 +1,4 @@ import arc.checks.common import arc.checks.nmd +import arc.checks.spin import arc.checks.ts diff --git a/arc/checks/spin.py b/arc/checks/spin.py new file mode 100644 index 0000000000..e3f5da8d3a --- /dev/null +++ b/arc/checks/spin.py @@ -0,0 +1,248 @@ +""" +A module for approximate spin projection of a broken-symmetry wavefunction. +""" + +import math +from typing import TYPE_CHECKING + +from arc.common import get_logger +from arc.parser.parser import s_squared_expected_from_multiplicity + +if TYPE_CHECKING: + from arc.level import Level + +logger = get_logger() + +MIN_S2_SEPARATION = 0.1 + +MAX_PROJECTION_AMPLIFICATION = 2.0 + +BROKEN_SYMMETRY_S2_THRESHOLD = 1e-2 + + +def _is_finite(value: float | None) -> bool: + """ + Return whether a value is present and a finite number. + + Args: + value (float | None): The value to test. + + Returns: bool + ``True`` when the value is not ``None`` and is neither ``NaN`` nor infinite. + """ + if value is None: + return False + try: + return math.isfinite(value) + except TypeError: + return False + + +def _is_finite_s2(value: float | None) -> bool: + """ + Return whether a value is usable as an ````. + + Args: + value (float | None): The value to test. + + Returns: bool + ``True`` when the value is present, finite and non-negative, which every + expectation value of the total-spin operator is. + """ + return _is_finite(value) and value >= 0.0 + + +def target_low_spin_s_squared(multiplicity: int | float | None) -> float | None: + """ + Return the spin-pure ```` of the low-spin state a projection targets. + + The value is ``S(S+1)`` of the target multiplicity, computed by + ``arc.parser.parser.s_squared_expected_from_multiplicity``: 0 for a singlet, + 0.75 for a doublet, 2 for a triplet. A multiplicity that is missing, not a + number, below one, not finite or not a whole number names no spin state, and is + refused with a warning rather than treated as any particular one. A multiplicity + is ``2S + 1`` for a total spin ``S`` that is a whole or half-integral number, so + it is itself a positive integer and a fractional one names nothing: ``1.5`` would + otherwise be read as ``S = 0.25``, which no state has. + + Args: + multiplicity (int | float | None): The spin multiplicity of the target low-spin state. + + Returns: float | None + The spin-pure ``S(S+1)`` of the target state, or ``None``. + """ + s2_ls = s_squared_expected_from_multiplicity(multiplicity) \ + if _is_finite(multiplicity) and not isinstance(multiplicity, bool) and float(multiplicity).is_integer() \ + else None + if not _is_finite_s2(s2_ls): + logger.warning(f'Cannot spin-project onto a target low-spin state: {multiplicity!r} is not a spin ' + f'multiplicity, so the spin-pure that state is projected onto is undefined. ' + f'The multiplicity of the state the projection targets is what decides that value.') + return None + return s2_ls + + +def yamaguchi_projected_energy(e_bs: float | None, + e_hs: float | None, + s2_bs: float | None, + s2_hs: float | None, + multiplicity: int | float | None, + ) -> float | None: + """ + Compute the Yamaguchi approximate spin-projected low-spin energy. + + Applies the approximate spin projection (AP) scheme of Yamaguchi and co-workers, + which removes the high-spin contamination of a broken-symmetry (BS) solution by + extrapolating in ```` from the BS reference away from the high-spin (HS) + reference, both computed at the same geometry and level:: + + E_LS = E_BS + [(_BS - _LS) / (_HS - _BS)] * (E_BS - E_HS) + + ``_LS = S_LS(S_LS + 1)`` is the spin-pure expectation value of the target + low-spin state, and is taken from ``multiplicity``, the multiplicity of the state + the projection targets: 0 for a singlet, 0.75 for a doublet, 2 for a triplet. The + target state is an argument because it moves the answer by tens of kJ/mol, so there + is no default. For a singlet target the expression reduces to the familiar closed + form ``(_HS * E_BS - _BS * E_HS) / (_HS - _BS)``. + + K. Yamaguchi, F. Jensen, A. Dorigo, K. N. Houk, Chem. Phys. Lett. 1988, 149, 537. + T. Soda et al., Chem. Phys. Lett. 2000, 319, 223 applies it to broken-symmetry DFT. + + Every refusal is logged as a warning and returns ``None`` rather than a number. The + projection is refused when any argument is missing, non-finite, a negative ```` + or not a spin multiplicity; when the two references are separated in ```` by + less than ``MIN_S2_SEPARATION``, below which they do not describe two distinguishable + spin states; when the pair is inconsistent, meaning either that the HS reference is + the less contaminated of the two or that the BS reference is less contaminated than + the spin-pure target; and when the ratio multiplying ``E_BS - E_HS`` exceeds + ``MAX_PROJECTION_AMPLIFICATION``. + + That ratio is ``w / (1 - w)`` in the high-spin weight ``w`` of the BS determinant, so + it is the quantity that decides how far the projection moves the energy, and capping + it rather than the denominator is what bounds the result. An ideal, fully spin-flipped + broken-symmetry solution has ``w = 0.5`` and a ratio of exactly 1; a ratio above 1 + means the BS determinant carries more high-spin than target-spin character. The cap of + ``MAX_PROJECTION_AMPLIFICATION`` admits ``w`` up to two thirds, a BS reference twice as + high-spin as the ideal one, and refuses beyond it, where the correction exceeds twice + the BS-to-HS energy gap and the pair no longer describes the target state. So the + largest correction an accepted projection can apply is + ``MAX_PROJECTION_AMPLIFICATION * |E_BS - E_HS|``, and the first pair accepted past the + separation floor is bounded by the same amount as every other. + + A converged unrestricted determinant satisfies ``_LS <= _BS <= _HS``, + so an inconsistent ordering is a property of the calculation rather than of the chemistry. + A broken-symmetry ```` below the spin-pure target by less than ``MIN_S2_SEPARATION`` + is the noise of a determinant that is spin-pure to within it, so the amplification it gives + is taken as zero and the projected energy is ``E_BS`` itself. Amplifying by a negative + number would return an energy ABOVE ``E_BS``, since ``E_BS - E_HS`` is negative, which is + the wrong side of the reference the projection starts from. + + Args: + e_bs (float | None): The broken-symmetry electronic energy. + e_hs (float | None): The high-spin electronic energy, at the same geometry and level. + s2_bs (float | None): The broken-symmetry ````. + s2_hs (float | None): The high-spin ````. + multiplicity (int | float | None): The spin multiplicity of the target low-spin state. + + Returns: float | None + The projected low-spin energy in the units of ``e_bs``, or ``None``. + """ + s2_ls = target_low_spin_s_squared(multiplicity) + if s2_ls is None: + return None + if not (_is_finite(e_bs) and _is_finite(e_hs)): + return None + if not (_is_finite_s2(s2_bs) and _is_finite_s2(s2_hs)): + return None + separation = s2_hs - s2_bs + if separation < -MIN_S2_SEPARATION: + logger.warning(f'Not projecting: the high-spin ({s2_hs}) is below the broken-symmetry ' + f' ({s2_bs}), which a pair of converged unrestricted determinants of the ' + f'same system cannot be. The two references do not describe the same calculation.') + return None + if separation < MIN_S2_SEPARATION: + logger.warning(f'Not projecting: _HS ({s2_hs}) and _BS ({s2_bs}) are separated by ' + f'{separation}, below the {MIN_S2_SEPARATION} two distinguishable spin states of ' + f'the same system differ by.') + return None + if s2_bs < s2_ls - MIN_S2_SEPARATION: + logger.warning(f'Not projecting: the broken-symmetry ({s2_bs}) is below the spin-pure ' + f' of the target low-spin state ({s2_ls}). Either the target state or the ' + f'broken-symmetry reference is not the one it is taken to be.') + return None + amplification = max((s2_bs - s2_ls) / separation, 0.0) + if amplification > MAX_PROJECTION_AMPLIFICATION: + logger.warning(f'Not projecting: with a broken-symmetry of {s2_bs} against a spin-pure ' + f'{s2_ls} and a high-spin {s2_hs}, the projection would move the energy by ' + f'{amplification} times the broken-symmetry to high-spin gap, above the ' + f'{MAX_PROJECTION_AMPLIFICATION} such an amplification of the two energies is ' + f'trusted to. The broken-symmetry reference carries more high-spin than ' + f'target-spin character.') + return None + return e_bs + amplification * (e_bs - e_hs) + + +def get_spin_projection(e_bs: float | None, + e_hs: float | None, + s2_bs: float | None, + s2_hs: float | None, + multiplicity: int | float | None, + level: 'Level | str | None', + xyz: dict | str | None, + e_restricted: float | None = None, + ) -> dict: + """ + Assemble the record of an approximate spin projection. + + Collects the quantities the projection was computed from alongside its result, so the + projected energy can be reproduced and audited from the record alone. ``r_u_gap`` is + the restricted minus broken-symmetry energy difference, a diradicaloid diagnostic in + its own right: it is positive by the variational principle whenever the broken-symmetry + solution is genuinely lower, and near zero when the BS optimisation collapsed back onto + the restricted solution. ``broken_symmetry`` reports whether the BS reference actually + broke symmetry, judged by how far its ```` lies above the spin-pure ``s2_ls`` of + the target state, and is ``None`` rather than ``False`` whenever that cannot be judged. + + ``level`` and ``xyz`` are the provenance of the energies: the single level of theory and + the single geometry that ``e_bs``, ``e_hs`` and ``e_restricted`` were all computed at. + The scheme extrapolates between two points of one potential energy surface, so energies + taken from two levels or from each state's own optimized geometry are not a pair this + projection is defined for, and the record names what it was given so a reader can tell. + + Args: + e_bs (float | None): The broken-symmetry electronic energy. + e_hs (float | None): The high-spin electronic energy, at the same geometry and level. + s2_bs (float | None): The broken-symmetry ````. + s2_hs (float | None): The high-spin ````. + multiplicity (int | float | None): The spin multiplicity of the target low-spin state. + level (Level | str | None): The level of theory all the energies were computed at. + xyz (dict | str | None): The geometry all the energies were computed at. + e_restricted (float | None, optional): The restricted electronic energy of the same geometry. + + Returns: dict + ``{'e_bs': float | None, 'e_hs': float | None, 's2_bs': float | None, + 's2_hs': float | None, 's2_ls': float | None, 'multiplicity': int | float | None, + 'level': str | None, 'xyz': dict | str | None, 'e_restricted': float | None, + 'r_u_gap': float | None, 'broken_symmetry': bool | None, + 'e_projected': float | None, 'scheme': 'yamaguchi_ap'}``. + """ + s2_ls = target_low_spin_s_squared(multiplicity) + r_u_gap = e_restricted - e_bs if _is_finite(e_restricted) and _is_finite(e_bs) else None + broken_symmetry = s2_bs - s2_ls > BROKEN_SYMMETRY_S2_THRESHOLD \ + if _is_finite_s2(s2_bs) and _is_finite_s2(s2_ls) else None + return {'e_bs': e_bs, + 'e_hs': e_hs, + 's2_bs': s2_bs, + 's2_hs': s2_hs, + 's2_ls': s2_ls, + 'multiplicity': multiplicity, + 'level': str(level) if level is not None else None, + 'xyz': xyz, + 'e_restricted': e_restricted, + 'r_u_gap': r_u_gap, + 'broken_symmetry': broken_symmetry, + 'e_projected': yamaguchi_projected_energy(e_bs=e_bs, e_hs=e_hs, s2_bs=s2_bs, + s2_hs=s2_hs, multiplicity=multiplicity) + if s2_ls is not None else None, + 'scheme': 'yamaguchi_ap', + } diff --git a/arc/checks/spin_test.py b/arc/checks/spin_test.py new file mode 100644 index 0000000000..75a97e0a9c --- /dev/null +++ b/arc/checks/spin_test.py @@ -0,0 +1,367 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +""" +This module contains unit tests for the arc.checks.spin module +""" + +import math +import unittest + +from arc.checks.spin import (BROKEN_SYMMETRY_S2_THRESHOLD, + MAX_PROJECTION_AMPLIFICATION, + MIN_S2_SEPARATION, + get_spin_projection, + target_low_spin_s_squared, + yamaguchi_projected_energy, + ) + +LEVEL = 'wb97xd/def2tzvp' +XYZ = {'symbols': ('H', 'H'), 'isotopes': (1, 1), + 'coords': ((0.0, 0.0, 0.0), (0.0, 0.0, 0.74))} + + +class TestTargetLowSpinSSquared(unittest.TestCase): + """ + Contains unit tests for the spin-pure of a target low-spin state. + """ + + def test_the_first_three_multiplicities(self): + """Test S(S+1) for a singlet, a doublet and a triplet""" + self.assertEqual(target_low_spin_s_squared(1), 0.0) + self.assertEqual(target_low_spin_s_squared(2), 0.75) + self.assertEqual(target_low_spin_s_squared(3), 2.0) + + def test_a_missing_multiplicity_is_refused_rather_than_assumed_to_be_a_singlet(self): + """Test that no multiplicity yields None and a warning, never the singlet value""" + with self.assertLogs('arc', level='WARNING') as captured: + self.assertIsNone(target_low_spin_s_squared(None)) + self.assertTrue(any('is not a spin multiplicity' in record for record in captured.output)) + + def test_a_value_that_names_no_spin_state_is_refused(self): + """Test that a multiplicity below one, non-numeric, non-finite or fractional yields None""" + for multiplicity in [0, -2, 'doublet', float('nan'), float('inf'), float('-inf'), 1.5, 2.5, 0.5]: + with self.assertLogs('arc', level='WARNING'): + self.assertIsNone(target_low_spin_s_squared(multiplicity), + msg=f'{multiplicity!r} was accepted as a multiplicity') + + +class TestYamaguchiProjectedEnergy(unittest.TestCase): + """ + Contains unit tests for the Yamaguchi approximate spin projection. + """ + + def test_fully_broken_pair_reproduces_the_standard_limit(self): + """Test that _BS = 1, _HS = 2 gives the standard 2*E_BS - E_HS limit""" + e_bs, e_hs = -195.2885, -195.2500 + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=e_bs, e_hs=e_hs, s2_bs=1.0, s2_hs=2.0, + multiplicity=1), + 2 * e_bs - e_hs, places=10) + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=e_bs, e_hs=e_hs, s2_bs=1.0, s2_hs=2.0, + multiplicity=1), + -195.3270, places=10) + + def test_no_spin_contamination_reduces_to_the_broken_symmetry_energy(self): + """Test that _BS = 0 returns E_BS unchanged""" + self.assertEqual(yamaguchi_projected_energy(e_bs=-195.2885, e_hs=-195.25, s2_bs=0.0, s2_hs=2.0, + multiplicity=1), + -195.2885) + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=1e-6, s2_hs=2.0, + multiplicity=1), + -100.0, places=5) + + def test_a_hand_checkable_intermediate_case(self): + """Test a partially contaminated case against the formula evaluated by hand""" + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=0.5, s2_hs=2.0, + multiplicity=1), + (2.0 * -100.0 - 0.5 * -99.0) / 1.5, places=10) + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=0.5, s2_hs=2.0, + multiplicity=1), + -100.3333333333, places=9) + + def test_the_projection_lies_below_the_broken_symmetry_energy(self): + """Test that removing high-spin contamination lowers the energy when the HS state is higher""" + projected = yamaguchi_projected_energy(e_bs=-195.2885, e_hs=-195.2500, s2_bs=1.0, s2_hs=2.0, + multiplicity=1) + self.assertLess(projected, -195.2885) + + def test_a_non_singlet_target_state_is_projected_to_its_own_spin_purity(self): + """Test the general form against a hand-evaluated broken-symmetry doublet / high-spin quartet pair""" + projected = yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.9, s2_bs=1.0, s2_hs=3.80, multiplicity=2) + self.assertAlmostEqual(projected, -100.0 + ((1.0 - 0.75) / 2.80) * (-100.0 - -99.9), places=10) + self.assertAlmostEqual(projected, -100.0089285714, places=9) + + def test_projecting_a_doublet_onto_a_singlet_target_misses_by_a_chemically_large_amount(self): + """Test that the target multiplicity moves the answer by tens of kJ/mol""" + doublet = yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.9, s2_bs=1.0, s2_hs=3.80, multiplicity=2) + singlet = yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.9, s2_bs=1.0, s2_hs=3.80, multiplicity=1) + self.assertAlmostEqual(singlet, -100.0357142857, places=9) + self.assertAlmostEqual(doublet - singlet, 0.0267857142, places=9) + + def test_a_triplet_target_state(self): + """Test the general form for a triplet target, whose spin-pure is 2""" + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-50.0, e_hs=-49.5, s2_bs=2.4, s2_hs=6.0, + multiplicity=3), + -50.0 + (0.4 / 3.6) * (-50.0 - -49.5), places=10) + + def test_a_target_state_equal_to_the_broken_symmetry_reference_returns_the_bs_energy(self): + """Test that an uncontaminated BS reference of a non-singlet target returns E_BS""" + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=0.75, s2_hs=3.75, + multiplicity=2), + -100.0, places=10) + + def test_references_too_close_in_s_squared_return_none(self): + """Test that a pair whose values nearly coincide is refused rather than amplified""" + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=2.0, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=2.0, s2_hs=2.002, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-195.2885, e_hs=-195.2500, s2_bs=0.7540, + s2_hs=0.7560, multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=1.0, s2_hs=1.05, + multiplicity=1)) + + def test_a_separation_exactly_at_the_floor_is_projected(self): + """Test that the floor itself is inside the accepted range and anything below it is not""" + s2_bs, s2_hs = 0.1, 0.2 + self.assertEqual(s2_hs - s2_bs, MIN_S2_SEPARATION) + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=s2_bs, s2_hs=s2_hs, + multiplicity=1), + -100.0 + (s2_bs / MIN_S2_SEPARATION) * (-100.0 - -99.0), places=10) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=s2_bs, + s2_hs=s2_hs - 1e-9, multiplicity=1)) + + def test_a_pair_separated_by_exactly_the_floor_and_spin_pure_returns_the_bs_energy(self): + """Test the floor with a BS reference carrying no contamination to remove""" + self.assertEqual(MIN_S2_SEPARATION - 0.0, MIN_S2_SEPARATION) + self.assertEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=0.0, + s2_hs=MIN_S2_SEPARATION, multiplicity=1), + -100.0) + + def test_a_refusal_below_the_floor_is_warned_about_rather_than_silent(self): + """Test that a near-degenerate pair says why it was refused on the warning channel""" + with self.assertLogs('arc', level='WARNING') as captured: + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=2.0, s2_hs=2.002, + multiplicity=1)) + message = ' '.join(captured.output) + self.assertIn('are separated by', message) + self.assertNotIn('below the broken-symmetry', message) + + def test_a_refused_projection_never_lies_far_below_the_broken_symmetry_energy(self): + """Test that no near-degenerate pair yields an energy displaced by more than the energy gap""" + for s2_hs in [2.0, 2.0005, 2.002, 2.05, 2.09]: + projected = yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=2.0, s2_hs=s2_hs, + multiplicity=1) + self.assertIsNone(projected) + + def test_an_over_amplified_pair_is_refused(self): + """Test that a BS reference more high-spin than target-spin is refused rather than amplified""" + with self.assertLogs('arc', level='WARNING') as captured: + self.assertIsNone(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=1.0, s2_hs=1.2, + multiplicity=1)) + self.assertTrue(any('an amplification of' in record for record in captured.output)) + + def test_an_amplification_exactly_at_the_cap_is_projected(self): + """Test that the cap itself is inside the accepted range and anything above it is not""" + s2_bs, s2_hs = 1.0, 1.5 + self.assertEqual(s2_bs / (s2_hs - s2_bs), MAX_PROJECTION_AMPLIFICATION) + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=s2_bs, s2_hs=s2_hs, + multiplicity=1), + -102.0, places=10) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=s2_bs, s2_hs=1.49, + multiplicity=1)) + + def test_the_amplification_cap_bounds_how_far_the_projection_moves_the_energy(self): + """Test that every accepted projection stays within the cap times the BS to HS gap""" + e_bs, e_hs = -100.0, -99.0 + for s2_bs, s2_hs in [(1.0, 2.0), (0.5, 2.0), (1.0, 1.5), (1.2, 1.8), (0.0, 0.1)]: + projected = yamaguchi_projected_energy(e_bs=e_bs, e_hs=e_hs, s2_bs=s2_bs, s2_hs=s2_hs, + multiplicity=1) + if projected is not None: + self.assertLessEqual(abs(projected - e_bs), + MAX_PROJECTION_AMPLIFICATION * abs(e_bs - e_hs) + 1e-10, + msg=f'({s2_bs}, {s2_hs}) moved the energy past the cap') + + def test_a_bs_reference_spin_pure_to_within_the_tolerance_is_not_moved_upward(self): + """Test that a BS marginally below the target projects to E_BS rather than above it""" + e_bs, e_hs = -100.0, -99.0 + for s2_bs in [0.75, 0.70, 0.6501]: + projected = yamaguchi_projected_energy(e_bs=e_bs, e_hs=e_hs, s2_bs=s2_bs, s2_hs=2.0, + multiplicity=2) + self.assertIsNotNone(projected, msg=f'a BS of {s2_bs} was refused') + self.assertLessEqual(projected, e_bs, + msg=f'a BS of {s2_bs} projected above the BS energy') + self.assertAlmostEqual(yamaguchi_projected_energy(e_bs=e_bs, e_hs=e_hs, s2_bs=0.7, s2_hs=2.0, + multiplicity=2), + e_bs, places=10) + + def test_an_inverted_pair_is_reported_as_a_mismatched_calculation(self): + """Test that _HS below _BS returns None and warns, the pair being inconsistent""" + with self.assertLogs('arc', level='WARNING') as captured: + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=2.0, s2_hs=1.0, + multiplicity=1)) + self.assertTrue(any('below the broken-symmetry' in record for record in captured.output)) + + def test_a_bs_reference_below_the_target_spin_purity_is_refused(self): + """Test that a BS below the target's S(S+1) returns None and warns""" + with self.assertLogs('arc', level='WARNING') as captured: + self.assertIsNone(yamaguchi_projected_energy(e_bs=-100.0, e_hs=-99.0, s2_bs=0.5, s2_hs=3.5, + multiplicity=3)) + self.assertTrue(any('target low-spin state' in record for record in captured.output)) + + def test_missing_inputs_return_none(self): + """Test that any missing argument yields None""" + self.assertIsNone(yamaguchi_projected_energy(e_bs=None, e_hs=-0.9, s2_bs=1.0, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=None, s2_bs=1.0, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=None, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=1.0, s2_hs=None, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=1.0, s2_hs=2.0, + multiplicity=None)) + + def test_non_finite_inputs_return_none(self): + """Test that NaN and infinite arguments yield None rather than propagating""" + for bad in [float('nan'), float('inf'), float('-inf')]: + self.assertIsNone(yamaguchi_projected_energy(e_bs=bad, e_hs=-0.9, s2_bs=1.0, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=bad, s2_bs=1.0, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=bad, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=1.0, s2_hs=bad, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=1.0, s2_hs=2.0, + multiplicity=bad)) + + def test_a_negative_s_squared_returns_none(self): + """Test that a negative , which no expectation value can be, yields None""" + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=-1.0, s2_hs=2.0, + multiplicity=1)) + self.assertIsNone(yamaguchi_projected_energy(e_bs=-1.0, e_hs=-0.9, s2_bs=1.0, s2_hs=-2.0, + multiplicity=1)) + + +class TestGetSpinProjection(unittest.TestCase): + """ + Contains unit tests for assembling a spin projection record. + """ + + def test_the_record_carries_every_quantity_the_projection_used(self): + """Test that the record allows the projected energy to be recomputed from it""" + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.2500, s2_bs=1.0, s2_hs=2.0, + multiplicity=1, level=LEVEL, xyz=XYZ, e_restricted=-195.2693) + self.assertEqual(record['e_bs'], -195.2885) + self.assertEqual(record['e_hs'], -195.2500) + self.assertEqual(record['s2_bs'], 1.0) + self.assertEqual(record['s2_hs'], 2.0) + self.assertEqual(record['s2_ls'], 0.0) + self.assertEqual(record['multiplicity'], 1) + self.assertEqual(record['e_restricted'], -195.2693) + self.assertEqual(record['scheme'], 'yamaguchi_ap') + self.assertAlmostEqual(record['e_projected'], + yamaguchi_projected_energy(e_bs=record['e_bs'], e_hs=record['e_hs'], + s2_bs=record['s2_bs'], s2_hs=record['s2_hs'], + multiplicity=record['multiplicity']), + places=10) + + def test_the_record_names_the_level_and_the_geometry_the_energies_came_from(self): + """Test that the two energies are bound to the level and geometry that produced them""" + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.2500, s2_bs=1.0, s2_hs=2.0, + multiplicity=1, level=LEVEL, xyz=XYZ) + self.assertEqual(record['level'], LEVEL) + self.assertEqual(record['xyz'], XYZ) + + def test_an_absent_provenance_is_reported_as_absent(self): + """Test that a record built without a level or a geometry says so rather than omitting the keys""" + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.2500, s2_bs=1.0, s2_hs=2.0, + multiplicity=1, level=None, xyz=None) + self.assertIsNone(record['level']) + self.assertIsNone(record['xyz']) + + def test_the_target_spin_purity_is_carried_and_applied(self): + """Test that a non-singlet target is recorded and used by the projection""" + record = get_spin_projection(e_bs=-100.0, e_hs=-99.9, s2_bs=1.0, s2_hs=3.80, multiplicity=2, + level=LEVEL, xyz=XYZ) + self.assertEqual(record['s2_ls'], 0.75) + self.assertEqual(record['multiplicity'], 2) + self.assertAlmostEqual(record['e_projected'], -100.0089285714, places=9) + + def test_the_r_u_gap_is_positive_when_the_broken_symmetry_solution_is_lower(self): + """Test the restricted minus broken-symmetry energy gap""" + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, s2_bs=1.0, s2_hs=2.0, multiplicity=1, + level=LEVEL, xyz=XYZ, e_restricted=-195.2693) + self.assertAlmostEqual(record['r_u_gap'], 0.0192, places=10) + self.assertGreater(record['r_u_gap'], 0) + + def test_a_collapsed_broken_symmetry_solution_is_reported_as_such(self): + """Test that a BS optimization that fell back onto the closed-shell solution is flagged""" + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, s2_bs=0.0, s2_hs=2.0, multiplicity=1, + level=LEVEL, xyz=XYZ, e_restricted=-195.2885) + self.assertFalse(record['broken_symmetry']) + self.assertEqual(record['e_projected'], record['e_bs']) + self.assertEqual(record['r_u_gap'], 0.0) + + def test_a_genuinely_broken_solution_is_reported_as_such(self): + """Test that a spin-contaminated BS reference is flagged as symmetry broken""" + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, s2_bs=0.1, s2_hs=2.0, multiplicity=1, + level=LEVEL, xyz=XYZ) + self.assertTrue(record['broken_symmetry']) + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, s2_bs=0.001, s2_hs=2.0, multiplicity=1, + level=LEVEL, xyz=XYZ) + self.assertFalse(record['broken_symmetry']) + + def test_a_deviation_exactly_at_the_symmetry_breaking_threshold_is_not_broken(self): + """Test that the threshold itself lies outside the range reported as symmetry broken""" + self.assertEqual(BROKEN_SYMMETRY_S2_THRESHOLD - 0.0, BROKEN_SYMMETRY_S2_THRESHOLD) + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, s2_bs=BROKEN_SYMMETRY_S2_THRESHOLD, + s2_hs=2.0, multiplicity=1, level=LEVEL, xyz=XYZ) + self.assertFalse(record['broken_symmetry']) + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, + s2_bs=BROKEN_SYMMETRY_S2_THRESHOLD * 1.001, + s2_hs=2.0, multiplicity=1, level=LEVEL, xyz=XYZ) + self.assertTrue(record['broken_symmetry']) + + def test_symmetry_breaking_is_judged_against_the_target_state_not_against_zero(self): + """Test that a clean doublet is not flagged as broken merely for having near 0.75""" + record = get_spin_projection(e_bs=-100.0, e_hs=-99.0, s2_bs=0.7536, s2_hs=3.75, multiplicity=2, + level=LEVEL, xyz=XYZ) + self.assertFalse(record['broken_symmetry']) + record = get_spin_projection(e_bs=-100.0, e_hs=-99.0, s2_bs=1.0, s2_hs=3.75, multiplicity=2, + level=LEVEL, xyz=XYZ) + self.assertTrue(record['broken_symmetry']) + + def test_missing_inputs_leave_the_record_undecided(self): + """Test that absent quantities yield None entries rather than raising""" + record = get_spin_projection(e_bs=None, e_hs=None, s2_bs=None, s2_hs=None, multiplicity=None, + level=None, xyz=None) + self.assertIsNone(record['e_projected']) + self.assertIsNone(record['r_u_gap']) + self.assertIsNone(record['broken_symmetry']) + self.assertIsNone(record['s2_ls']) + self.assertEqual(record['scheme'], 'yamaguchi_ap') + + def test_a_non_finite_s_squared_leaves_symmetry_breaking_undecided(self): + """Test that an unreadable yields None, never False, for broken_symmetry""" + for bad in [float('nan'), float('inf'), float('-inf')]: + record = get_spin_projection(e_bs=-195.2885, e_hs=-195.25, s2_bs=bad, s2_hs=2.0, + multiplicity=1, level=LEVEL, xyz=XYZ) + self.assertIsNone(record['broken_symmetry']) + self.assertIsNone(record['e_projected']) + record = get_spin_projection(e_bs=float('nan'), e_hs=-195.25, s2_bs=1.0, s2_hs=2.0, + multiplicity=1, level=LEVEL, xyz=XYZ, e_restricted=-195.2693) + self.assertIsNone(record['r_u_gap']) + self.assertIsNone(record['e_projected']) + + def test_the_constants_are_the_ones_the_module_documents(self): + """Test the physical floors themselves, so a change to either is a deliberate one""" + self.assertEqual(MIN_S2_SEPARATION, 0.1) + self.assertEqual(MAX_PROJECTION_AMPLIFICATION, 2.0) + self.assertEqual(BROKEN_SYMMETRY_S2_THRESHOLD, 1e-2) + self.assertFalse(math.isnan(MIN_S2_SEPARATION)) + + +if __name__ == '__main__': + unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) From 308d70305619c06b4c6e900e0abaea013374f836 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 03/12] Add an opt-in Gaussian 'stability' job type running stable=(rext,noopt) Registers a new job type, off by default, that submits one Gaussian stability analysis at the freq level of theory and on the freq geometry. PLACEMENT. Stable is itself a Gaussian job type keyword, and Gaussian documents that only one job type keyword should be specified, the exceptions being Opt Freq and Polar Freq. So the keyword cannot be appended to the TS freq route. It could syntactically be appended to ARC's sp route, which carries no job type keyword, but ARC's sp is typically a composite or wavefunction-method energy, where stability analysis is unavailable (it is documented for HF and DFT only) and where a second job type keyword would displace the energy of record. A separate job at the freq level tests the wavefunction the Hessian is built from, and follows the shape of ARC's existing 'orbitals' job: a diagnostic that nothing depends on. KEYWORD. The route emits stable=(rext,noopt). NoOpt is Gaussian's default and is stated explicitly: it reports an instability without reoptimizing the wavefunction into the lower solution, so no rotated orbitals are produced. ARC also never propagates this job's checkfile -- species.checkfile is only repointed from opt, optfreq and composite jobs, and from troubleshooting, which this job is exempt from. Stable=Opt, RepOpt and 1Opt are never emitted, and complex-orbital testing is not enabled. RExt is kept over Int: it costs nothing extra, and Int would discard the broken-symmetry information the diagnostic exists to count. The job is skipped unless the freq level is HF or DFT and a checkfile exists to start from; without one the route would fall back to guess=mix, whose deliberately symmetry-broken SCF is a different wavefunction than the one under test, and which would then report itself stable. THE DIAGNOSTIC DEFAULTS TO OFF, in both default_job_types and initialize_job_types. Enabling it by default would make every species wait on a job that only a Gaussian species can satisfy, and on a run restarted from a restart.yml written before this job type existed it would raise KeyError in check_all_done, which reads output['job_types'][job_type] before reaching the exemption and is not backfilled by initialize_output_dict. JobAdapter.as_dict also gains restricted_used, the SCF reference this job's input declared. It is the one job attribute a restart cannot rebuild: restore_running_jobs calls job_factory, which calls set_files, which composes the input file again and so calls is_restricted against the species' CURRENT state, so a restricted sp job queued before a reference decision changed would come back from a restart claiming to be unrestricted. Narrowing the docstring to admit the memo is only session-durable was rejected -- reading the memo instead of recomputing is the entire reason the per-job records are trustworthy, and a record that is right until the run is interrupted is not a record. ARC's end-of-run status report prints the stability summary string alongside a converged species, so the diagnostic is visible without opening output.yml. Dropping restricted_used from as_dict fails 1 test; the job-type registration is pinned by the job-type dictionaries in arc/main_test.py. The project forbids a file carrying both `import X` and `from X import Y` for the same X. arc/main_test.py, which this commit edits, carried `import unittest` alongside `from unittest import mock`. The submodule import is spelled `import unittest.mock` and its four call sites are qualified, so the file now imports `unittest` one way only. The base class also stops hard-coding the checkfile name. local_path_to_check_file was 'check.chk' for every adapter, which is a Gaussian name that psi_4 and terachem happen to share; ORCA writes its orbitals to a file named after the input file. JobAdapter now resolves two names per ESS: check_file_name, the file the ESS writes its orbitals to and the file that is downloaded, and guess_file_name, the name a previous job's orbitals are uploaded under. They differ only where an ESS cannot read and write one file the way Gaussian reuses a single checkfile. Both default to 'check.chk', so Gaussian, psi_4 and terachem are unchanged. check_file_name and guess_file_name are per-subclass class attributes on JobAdapter, overridden in OrcaAdapter, rather than a registry in the base class keyed by adapter name: the base class should not enumerate its subclasses, and the per-subclass attribute is the idiom job_adapter itself already uses. JobAdapter also gains readable_checkfile, which refuses a checkfile whose base name is neither the adapter's own check_file_name nor the '_' form ARC writes for a directed rotor. Scheduler hands every job the checkfile its species holds whichever ESS wrote it, so without this an ORCA input.gbw reaches Gaussian and is uploaded as check.chk and read with guess=read. The hazard predates this branch through terachem; this branch makes it live for the two ESSs people actually mix, so it is closed here. READABLE_CHECKFILE ALSO REFUSES A PATH THAT NAMES NO FILE AND ONE NAMING AN EMPTY FILE. SSHClient.download_file leaves a zero-byte file behind where the download failed, and an SCF handed one either errors or starts from the guess it would have started from anyway while the input claims to read orbitals it does not have. Its docstring says what the method tests, the ESS that wrote the file and whether it holds anything, and that it examines neither the directory the path points into nor its relation to the project directory. The Gaussian adapter's fallback to an orbitals file sitting in its own job directory is refused while the species carries an adopted wavefunction-stability verdict and holds no checkfile. The species is holding none deliberately in that state: the orbitals it dropped describe the restricted reference the verdict rejected, and an unrestricted SCF seeded from them returns to that solution. The job directory of a job whose name a previous job of the same species already carried holds exactly such a file, and the route to the lower solution there is guess=mix rather than guess=read. The fallback also goes through readable_checkfile, so an empty file left in the job directory is refused the same way one handed in from the species is. THE RUN SUMMARY PRINTS THE WARNINGS OF A CONVERGED SPECIES, not only of a failed one. A species that mixes SCF references converges, so the failure branch that printed output['warnings'] never reached it and MIXED_SCF_REFERENCE_MESSAGE, raised for exactly the configuration the reference gate exists for, reached neither the summary nor any other in-band trace: outside scheduler.py nothing downstream consumes reference_mismatch. The invalid-analytic-frequency and spin-contamination warnings are raised on a converged species too. The converged branch now prints them alongside the stability line, and summary()'s docstring says so. --- arc/common.py | 2 +- arc/common_test.py | 1 + arc/job/adapter.py | 71 +++++++++++++++- arc/job/adapters/gaussian.py | 20 +++-- arc/job/adapters/gaussian_test.py | 133 +++++++++++++++++++++++++++++- arc/main.py | 13 ++- arc/main_test.py | 27 +++++- arc/settings/settings.py | 1 + 8 files changed, 255 insertions(+), 13 deletions(-) diff --git a/arc/common.py b/arc/common.py index 1db45bf329..37d55829a6 100644 --- a/arc/common.py +++ b/arc/common.py @@ -88,7 +88,7 @@ def initialize_job_types(job_types: dict | None = None, del job_types['fine_grid'] defaults_to_true = ['conf_opt', 'fine', 'freq', 'irc', 'opt', 'rotors', 'sp'] - defaults_to_false = ['conf_sp', 'bde', 'onedmin', 'orbitals'] + defaults_to_false = ['conf_sp', 'bde', 'onedmin', 'orbitals', 'stability'] if job_types is None: job_types = default_job_types logger.info("Job types were not specified, using ARC's defaults") diff --git a/arc/common_test.py b/arc/common_test.py index 5f3b6c9c6b..b8dc59054d 100644 --- a/arc/common_test.py +++ b/arc/common_test.py @@ -69,6 +69,7 @@ def setUpClass(cls): 'irc': True, 'conf_sp': False, 'orbitals': False, + 'stability': False, 'onedmin': False, 'bde': False, } diff --git a/arc/job/adapter.py b/arc/job/adapter.py index 4256b914e4..d188e33ac3 100644 --- a/arc/job/adapter.py +++ b/arc/job/adapter.py @@ -140,6 +140,7 @@ class JobTypeEnum(str, Enum): scan = 'scan' directed_scan = 'directed_scan' sp = 'sp' + stability = 'stability' tsg = 'tsg' # TS search (TS guess) @@ -156,8 +157,18 @@ class JobExecutionTypeEnum(str, Enum): class JobAdapter(ABC): """ An abstract class for job adapters. + + ``check_file_name`` is the name of the file the ESS writes its converged orbitals to, the + name that file is downloaded under and the name ``local_path_to_check_file`` points at. + ``guess_file_name`` is the name a previous job's orbitals are uploaded under to serve as + this job's initial guess; the two are equal for an ESS that reads and writes one file, as + Gaussian does with its checkfile. A subclass whose ESS names these files differently + overrides them, as ``OrcaAdapter`` does. """ + check_file_name = 'check.chk' + guess_file_name = 'check.chk' + @abstractmethod def write_input_file(self) -> None: """ @@ -406,6 +417,51 @@ def write_submit_script(self) -> None: with open(os.path.join(self.local_path, submit_filenames[servers[self.server]['cluster_soft']]), 'w') as f: f.write(submit_script) + def readable_checkfile(self, checkfile: str | None) -> str | None: + """ + Report the checkfile this adapter may read as an initial guess, or ``None`` for one it may not. + + ``Scheduler`` hands every job the checkfile its species holds, whichever ESS wrote it, so a + species optimized in one ESS reaches an adapter of another carrying orbitals that adapter + cannot read: an ORCA ``input.gbw`` uploaded to Gaussian as ``check.chk`` and read with + ``guess=read`` is not a Gaussian checkpoint file. Each ESS names its orbitals file, so the + base name identifies the ESS that wrote it: a checkfile whose base name is neither this + adapter's ``check_file_name`` nor the ``_`` form ARC itself writes + when it keeps a directed rotor's orbitals aside is refused here and logged, and the job runs + from its own initial guess. + + A path that names no file, and one naming an empty file, are refused for the same reason: + ``SSHClient.download_file`` leaves a zero-byte file behind where the download failed, and + an SCF handed one either errors or starts from the guess it would have started from + anyway, while the job's input claims to read orbitals it does not have. + + This is a test of what the file is, not of where it is: the base name says which ESS wrote + it and the size says whether it holds anything, and neither the directory the path points + into nor the path's relation to the project directory is examined here. + + Args: + checkfile (str, optional): The path of the checkfile offered to this job. + + Returns: str | None + The checkfile path when this adapter's ESS wrote it and it holds orbitals, else ``None``. + """ + if checkfile is None: + return None + base_name = os.path.basename(checkfile) + if base_name != self.check_file_name and not base_name.endswith(f'_{self.check_file_name}'): + logger.info(f'Not reading {checkfile} as an initial guess for a {self.job_adapter} job: ' + f'{self.job_adapter} reads a {self.check_file_name} file.') + return None + if not os.path.isfile(checkfile): + logger.info(f'Not reading {checkfile} as an initial guess for a {self.job_adapter} job: ' + f'the path names no file.') + return None + if not os.path.getsize(checkfile): + logger.info(f'Not reading {checkfile} as an initial guess for a {self.job_adapter} job: ' + f'the file is empty, which is what a failed download leaves behind.') + return None + return checkfile + def set_file_paths(self) -> None: """ Set local and remote job file paths. @@ -424,7 +480,7 @@ def set_file_paths(self) -> None: self.local_path_to_output_file = os.path.join(self.local_path, settings['output_filenames'][self.job_adapter]) \ if self.job_adapter in settings['output_filenames'] else 'output.out' self.local_path_to_orbitals_file = os.path.join(self.local_path, 'orbitals.fchk') - self.local_path_to_check_file = os.path.join(self.local_path, 'check.chk') + self.local_path_to_check_file = os.path.join(self.local_path, self.check_file_name) self.local_path_to_hess_file = os.path.join(self.local_path, 'input.hess') self.local_path_to_xyz = None @@ -483,9 +539,10 @@ def upload_files(self, ssh: SSHClient | None = None) -> None: else: # running locally, just copy the check file, if exists, to the job folder for up_file in self.files_to_upload: - if up_file['file_name'] == 'check.chk': + if up_file['file_name'] in [self.check_file_name, self.guess_file_name]: try: - shutil.copyfile(src=up_file['local'], dst=os.path.join(self.local_path, 'check.chk')) + shutil.copyfile(src=up_file['local'], + dst=os.path.join(self.local_path, up_file['file_name'])) except shutil.SameFileError: pass self.initial_time = datetime.datetime.now() @@ -747,6 +804,11 @@ def set_cpu_and_mem(self): def as_dict(self) -> dict: """ A helper function for dumping this object as a dictionary, used for saving in the restart file. + + ``restricted_used``, the SCF reference this job's input declared, is included when the job + composed an input file. It is the one entry that cannot be recomputed on restore: rebuilding + the adapter re-composes the input from the species' current state, so a job queued before a + reference decision changed would otherwise come back describing a reference it never ran. """ job_dict = dict() job_dict['job_adapter'] = self.job_adapter @@ -791,6 +853,9 @@ def as_dict(self) -> dict: job_dict['server'] = self.server if isinstance(self.server_nodes, dict) and self.server_nodes: job_dict['server_nodes'] = self.server_nodes + restricted_used = getattr(self, 'restricted_used', None) + if isinstance(restricted_used, (bool, list)): + job_dict['restricted_used'] = restricted_used if self.species is not None: job_dict['species_labels'] = [species.label for species in self.species] if self.torsions is not None: diff --git a/arc/job/adapters/gaussian.py b/arc/job/adapters/gaussian.py index 33b1e695bf..8e205e8996 100644 --- a/arc/job/adapters/gaussian.py +++ b/arc/job/adapters/gaussian.py @@ -17,6 +17,7 @@ from arc.job.adapter import JobAdapter, constraint_type_dict from arc.job.adapters.common import (_initialize_adapter, is_restricted, + species_may_read_previous_orbitals, update_input_dict_with_args, which, combine_parameters @@ -46,6 +47,8 @@ # reservation constant. GAUSSIAN_MEMORY_HEADROOM_FRACTION = gaussian_memory_headroom_fractions[0] +STABILITY_KEYWORD = 'stable=(rext,noopt)' + # job_type_1: '' for sp, irc, or composite methods, 'opt=calcfc', 'opt=(calcfc,ts,noeigen)', # job_type_2: '' or 'freq iop(7/33=1)' (cannot be combined with CBS-QB3) @@ -215,11 +218,11 @@ def __init__(self, if isinstance(self.level, Level) and self.level.basis is not None: self.level.basis = re.sub('def2-', 'def2', self.level.basis.lower()) - if self.checkfile is None: - if os.path.isfile(os.path.join(self.local_path, 'check.chk')): - self.checkfile = os.path.join(self.local_path, 'check.chk') - elif self.species[0].checkfile is not None and os.path.isfile(self.species[0].checkfile): - self.checkfile = self.species[0].checkfile + if self.checkfile is None and species_may_read_previous_orbitals(self.species[0]): + if os.path.isfile(os.path.join(self.local_path, self.check_file_name)): + self.checkfile = self.readable_checkfile(os.path.join(self.local_path, self.check_file_name)) + elif self.species[0].checkfile is not None: + self.checkfile = self.readable_checkfile(self.species[0].checkfile) def write_input_file(self) -> None: """ @@ -328,6 +331,13 @@ def write_input_file(self) -> None: input_dict['trsh'] += ' ' input_dict['trsh'] += 'scf=(tight, direct)' + elif self.job_type == 'stability': + input_dict['job_type_1'] = f'{STABILITY_KEYWORD} ' \ + f'integral=(grid=ultrafine, {integral_algorithm})' + if input_dict['trsh']: + input_dict['trsh'] += ' ' + input_dict['trsh'] += 'scf=(tight, direct)' + elif self.job_type == 'scan': scans, scans_strings = list(), list() if self.rotor_index is not None and self.species[0].rotors_dict: diff --git a/arc/job/adapters/gaussian_test.py b/arc/job/adapters/gaussian_test.py index a0b8af26eb..39e11fac48 100644 --- a/arc/job/adapters/gaussian_test.py +++ b/arc/job/adapters/gaussian_test.py @@ -7,11 +7,12 @@ import math import os +import re import shutil import tempfile import unittest -from arc.job.adapters.gaussian import GaussianAdapter, get_memory_headroom_fraction +from arc.job.adapters.gaussian import STABILITY_KEYWORD, GaussianAdapter, get_memory_headroom_fraction from arc.level import Level from arc.settings.settings import input_filenames, output_filenames, servers, submit_filenames from arc.species import ARCSpecies @@ -1227,6 +1228,136 @@ def test_user_keyword_args_survive_a_level_round_trip(self): self.assertEqual(len(route_section), 1) self.assertIn('verytight', route_section[0]) + def _route_for_job_type(self, job_type: str) -> str: + """Write a Gaussian input file for a TS job of the given type and return its route line.""" + job = GaussianAdapter(execution_type='queue', + job_type=job_type, + level=Level(method='wb97xd', basis='def2-TZVP'), + project='test', + project_directory=self.project_directory, + species=[ARCSpecies(label='TS0', is_ts=True, xyz=['O 0 0 1\nH 0 0 2'])], + testing=True, + ) + job.write_input_file() + with open(os.path.join(job.local_path, input_filenames[job.job_adapter]), 'r') as f: + content = f.read() + return [line for line in content.splitlines() if line.startswith('#P')][0] + + def test_stability_keyword_in_route(self): + """Test that the wavefunction stability keyword is written for a stability job only""" + stability_route = self._route_for_job_type('stability') + self.assertIn('stable=(rext,noopt)', stability_route) + for job_type in ['opt', 'freq', 'sp', 'composite']: + self.assertNotIn('stable', self._route_for_job_type(job_type)) + + def test_stability_keyword_never_reoptimizes(self): + """Test that the stability route asks for no reoptimization and no complex orbitals""" + route = self._route_for_job_type('stability').lower() + options = re.search(r'stable=\(([^)]*)\)', route) + self.assertIsNotNone(options, msg=f'no stable=(...) group in route {route!r}') + options = [option.strip() for option in options.group(1).split(',')] + self.assertIn('noopt', options) + self.assertIn('rext', options) + for option in options: + self.assertNotIn(option, ['opt', 'repopt', '1opt', 'crhf', 'cuhf', 'int'], + msg=f'route {route!r} carries the {option!r} stability option') + self.assertNotIn('stable=opt', route) + self.assertEqual(STABILITY_KEYWORD.lower(), f"stable=({','.join(options)})") + + def test_a_checkfile_written_by_another_ess_is_refused(self): + """Test that an ORCA input.gbw offered to Gaussian is not read as a checkpoint file""" + scratch_dir = tempfile.mkdtemp(prefix='arc_test_gaussian_foreign_checkfile_') + self.addCleanup(shutil.rmtree, scratch_dir, ignore_errors=True) + foreign = os.path.join(scratch_dir, 'input.gbw') + with open(foreign, 'w') as f: + f.write('orbitals') + spc = ARCSpecies(label='TS0', is_ts=True, xyz=['O 0 0 1\nH 0 0 2']) + spc.checkfile = foreign + job = GaussianAdapter(execution_type='queue', + job_type='sp', + level=Level(method='wb97xd', basis='def2-TZVP'), + project='test', + project_directory=os.path.join(scratch_dir, 'test_GaussianAdapter'), + checkfile=foreign, + species=[spc], + testing=True, + ) + self.assertIsNone(job.checkfile) + self.assertNotIn(foreign, [up_file['local'] for up_file in job.files_to_upload]) + job.write_input_file() + with open(os.path.join(job.local_path, input_filenames[job.job_adapter]), 'r') as f: + content = f.read() + self.assertNotIn('guess=read', content) + + def _checkfile_job(self, + scratch_dir: str, + checkfile: str | None = None, + species: ARCSpecies | None = None, + **kwargs, + ) -> GaussianAdapter: + """Build a testing Gaussian job under a scratch directory of its own.""" + return GaussianAdapter(execution_type='queue', + job_type='sp', + level=Level(method='wb97xd', basis='def2-TZVP'), + project='test', + project_directory=os.path.join(scratch_dir, 'test_GaussianCheckfile'), + checkfile=checkfile, + species=[species if species is not None + else ARCSpecies(label='TS0', is_ts=True, xyz=['O 0 0 1\nH 0 0 2'])], + testing=True, + **kwargs, + ) + + def test_an_empty_checkfile_is_refused(self): + """Test that the zero-byte file a failed download leaves behind is not read as a guess""" + scratch_dir = tempfile.mkdtemp(prefix='arc_test_gaussian_empty_checkfile_') + self.addCleanup(shutil.rmtree, scratch_dir, ignore_errors=True) + empty = os.path.join(scratch_dir, 'check.chk') + with open(empty, 'w'): + pass + job = self._checkfile_job(scratch_dir, checkfile=empty) + self.assertIsNone(job.checkfile) + self.assertNotIn(empty, [up_file['local'] for up_file in job.files_to_upload]) + job.write_input_file() + with open(os.path.join(job.local_path, input_filenames[job.job_adapter]), 'r') as f: + self.assertNotIn('guess=read', f.read()) + + def test_orbitals_dropped_for_an_adopted_verdict_are_not_re_adopted(self): + """Test that a species holding no checkpoint of its adopted reference reads none from its directory""" + scratch_dir = tempfile.mkdtemp(prefix='arc_test_gaussian_reused_directory_') + self.addCleanup(shutil.rmtree, scratch_dir, ignore_errors=True) + spc = ARCSpecies(label='TS0', is_ts=True, xyz=['O 0 0 1\nH 0 0 2\nH 0 0 3'], multiplicity=1) + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'relaxations': ['RHF -> UHF']} + first = self._checkfile_job(scratch_dir, species=spc) + with open(os.path.join(first.local_path, 'check.chk'), 'w') as f: + f.write('orbitals') + second = self._checkfile_job(scratch_dir, species=spc, + job_name=first.job_name, job_num=first.job_num) + self.assertEqual(second.local_path, first.local_path) + self.assertIsNone(second.checkfile) + second.write_input_file() + with open(os.path.join(second.local_path, input_filenames[second.job_adapter]), 'r') as f: + content = f.read() + self.assertNotIn('guess=read', content) + self.assertIn('guess=mix', content) + + def test_a_species_holding_orbitals_reads_them_from_its_job_directory(self): + """Test that the job directory remains a source of orbitals for a species holding none""" + scratch_dir = tempfile.mkdtemp(prefix='arc_test_gaussian_own_directory_') + self.addCleanup(shutil.rmtree, scratch_dir, ignore_errors=True) + first = self._checkfile_job(scratch_dir) + planted = os.path.join(first.local_path, 'check.chk') + with open(planted, 'w') as f: + f.write('orbitals') + second = self._checkfile_job(scratch_dir, job_name=first.job_name, job_num=first.job_num) + self.assertEqual(second.checkfile, planted) + + def test_stability_keyword_absent_from_other_job_types(self): + """Test that no other job type emits any form of the stability keyword""" + for job_type in ['opt', 'freq', 'sp', 'composite']: + self.assertNotIn('stable', self._route_for_job_type(job_type).lower()) + class TestGetMemoryHeadroomFraction(unittest.TestCase): """ diff --git a/arc/main.py b/arc/main.py index e79cb85532..df2771b0e4 100644 --- a/arc/main.py +++ b/arc/main.py @@ -770,6 +770,12 @@ def summary(self) -> dict: """ Report status and data of all species / reactions. + A converged species reports its warnings alongside its wavefunction stability verdict, + as a species that failed reports them. A warning raised about a species that converged + describes the number the run reports rather than the reason it has none: a mixed SCF + reference, an analytic Hessian outside the range in which it is defined and a + spin-contaminated wavefunction are all raised on a species that converges. + Returns: dict Status dictionary indicating which species converged successfully. """ @@ -778,7 +784,12 @@ def summary(self) -> dict: for label, output in self.output.items(): if output['convergence']: status_dict[label] = True - logger.info(f'Species {label} converged successfully\n') + logger.info(f'Species {label} converged successfully') + if output.get('wavefunction_stability'): + logger.info(f' Wavefunction stability: {output["wavefunction_stability"]}') + if output.get('warnings'): + logger.info(f' with warnings: {output["warnings"]}') + logger.info('\n') elif not label.startswith('IRC_'): status_dict[label] = False job_type_status = {key: val for key, val in self.output[label]['job_types'].items() diff --git a/arc/main_test.py b/arc/main_test.py index bf373d514d..c93aad080b 100644 --- a/arc/main_test.py +++ b/arc/main_test.py @@ -123,7 +123,8 @@ def test_as_dict(self): 'opt': True, 'orbitals': False, 'rotors': False, - 'sp': True}, + 'sp': True, + 'stability': False}, 'max_job_time': 120, 'opt_level': {'basis': '6-311+g(3df,2p)', 'method': 'b3lyp', @@ -203,7 +204,8 @@ def test_from_dict_specific_job(self): } arc1 = ARC(**restart_dict) job_type_expected = {'conf_opt': False, 'conf_sp': False, 'opt': True, 'freq': True, 'sp': True, 'rotors': False, - 'orbitals': False, 'bde': True, 'onedmin': False, 'fine': True, 'irc': False} + 'orbitals': False, 'bde': True, 'onedmin': False, 'fine': True, 'irc': False, + 'stability': False} self.assertEqual(arc1.job_types, job_type_expected) def test_rotor_scan_resolution_input_key(self): @@ -552,6 +554,27 @@ def test_unknown_ts_adapter(self): ts_adapters=['WRONG ADAPTER', 'AutoTST', 'GCN', 'xtb_gsm'], ) + def test_summary_reports_the_warnings_of_a_converged_species(self): + """Test that the run summary prints the warnings of a species that converged""" + arc0 = ARC(project='arc_test', + job_types=self.job_types1, + species=[ARCSpecies(label='spc1', smiles='CC', compute_thermo=False)], + level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)', + ) + arc0.output = {'spc1': {'convergence': True, + 'job_types': {}, + 'info': '', + 'warnings': 'the electronic energy and the ZPE were computed with different ' + 'SCF references; ', + 'errors': '', + 'wavefunction_stability': 'external_instability (RHF-->UHF, -0.0312)', + }} + with self.assertLogs(logger=get_logger(), level=logging.INFO) as captured: + status_dict = arc0.summary() + self.assertTrue(status_dict['spc1']) + self.assertTrue(any('different SCF references' in record for record in captured.output)) + self.assertTrue(any('external_instability' in record for record in captured.output)) + @classmethod def tearDownClass(cls): """ diff --git a/arc/settings/settings.py b/arc/settings/settings.py index 8bf3aa449e..c19e68b56a 100644 --- a/arc/settings/settings.py +++ b/arc/settings/settings.py @@ -131,6 +131,7 @@ 'rotors': True, # defaults to True if not specified 'irc': True, # defaults to True if not specified 'orbitals': False, # defaults to False if not specified + 'stability': False, 'lennard_jones': False, # defaults to False if not specified 'bde': False, # defaults to False if not specified } From 3cd60137c061541c567d3a1adc2ba817487e3ea8 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 04/12] Run the wavefunction stability analysis in ORCA Adds the ORCA side of the 'stability' job type: a single point at the frequency level and on the frequency geometry that adds STABPerform and STABRestartUHFifUnstable to the existing %scf block, reading the orbitals of the job under test. THE INSTABILITY IS ALWAYS FOLLOWED, and that is not a preference. With STABRestartUHFifUnstable false, ORCA 6.0.0 prints the verdict and the stability-matrix roots and then dies in LEANSCF with a BLAS incompatible-matrices error and mpirun exit code 62. Measured at eight processes and at one, and at six roots and at three, so it is not an MPI artifact; LeanSCF false does not help, failing earlier, in the SCF, before any verdict is printed. The three stable jobs run to a normal termination on the same settings, so it is the re-entry into LeanSCF after an instability that breaks. ORCA therefore has no equivalent of Gaussian's NoOpt, which reports an instability without following it. With the key true the job terminates normally and the log holds two analyses; the parser reads the verdict of the first, which is the wavefunction under test. A crashed job would additionally be misread by determine_ess_status, whose orca branch matches 'error termination in SCF' and not 'in LEANSCF', so the job would be an unrecognised error and the verdict never read. THE ORBITALS UNDER TEST ARE HANDED OVER, because ORCA's analysis is an SCF post-step: it converges an SCF first, and from its own initial guess that need not be the solution the frequency job reached. This is the hazard Gaussian's checkfile requirement exists to prevent, and ARC's scheduler already refuses to spawn the job unless the species still holds the checkfile its frequency job used. ORCA names its own orbitals after the input file, so it cannot read and write one file the way Gaussian reuses a single checkfile: the previous orbitals are uploaded as guess.gbw and read with !MORead and %moinp, while the job's own input.gbw is downloaded and becomes the next job's guess. The adapter adopts a checkfile on construction the way the Gaussian adapter does. INPUT.GBW IS DOWNLOADED ONLY WHERE SOMETHING READS IT. A def2-TZVP .gbw runs to tens of MB and the job type is off by default, so downloading one from every ORCA job would cost every run bandwidth and disk for a file nothing opens. It is fetched for the job types the guess chain actually reads from -- the opt, optfreq and composite jobs Scheduler.end_job adopts a checkfile from -- plus the stability job, whose own orbitals are the relaxed solution. A job array takes the data.hdf5 branch and fetches no orbitals at all, since its members share one remote path; the docstring now says so rather than leaving it to be inferred. EVERY ORCA JOB THAT RUNS AN SCF READS THE GUESS, as every Gaussian job carrying a checkfile gets guess=read. OrcaAdapter.reads_orbital_guess is the single predicate behind both halves of it, the !MORead and %moinp keywords and the guess.gbw upload, so the file is uploaded for exactly the jobs that read it; emitting the keywords without the file aborts the job on a missing guess. ORBITALS_GUESS_JOB_TYPES holds the job types this adapter writes an SCF on one starting structure for: opt, conf_opt, optfreq and scan, whose first SCF the guess seeds and whose later points ORCA propagates orbitals through itself, and freq, sp, conf_sp and stability, each a single SCF. The rest are the job types write_input_file emits no keyword for, so ORCA is handed no calculation for a guess to seed -- composite, for which ORCA offers no composite method; irc and orbitals; and directed_scan, for which this adapter writes neither the scan block nor the constraints such a job needs -- plus gen_confs, tsg and onedmin, which belong to other adapters. A job array is excluded because it writes no input file and its members share one remote path, where one uploaded guess would stand in for every member, and a monatomic species because ARC spawns it neither an optimization nor a frequency job. WHAT THE CHAIN BUYS IS MEASURED. On a C5H10 TS at UKS B3LYP/def2-TZVP, same geometry and same input but for the guess, a fresh guess collapsed to the closed-shell solution (E = -196.344572 Eh, = 0.000000) while !MORead held the broken-symmetry solution (E = -196.364789 Eh, = 0.864739), reproducing the followed solution to 1e-9 Eh -- 12.7 kcal/mol apart. Without the chain the freq job converges from ORCA's own initial guess while the stability job reads the optimization's orbitals, and those are two different SCF solutions in exactly the cases the analysis exists to find. NO LEVEL OR BASIS IS TRACKED, because ORCA projects a guess written in another basis onto the basis of the job reading it. A def2-SVP job reading a def2-TZVP .gbw logs 'Atom 0: N(Shells)= 6 and 11 - projection required' and terminates normally at a sane def2-SVP energy, so the chain crosses the basis change ARC makes between the optimization and the single point on its own. The predicate is whether a checkfile this ESS wrote exists, and no new state is stored on the species, in the restart dict or in output.yml. The single point runs on defgrid3, the grid a frequency job uses, rather than the defgrid2 an sp would take, so the SCF under test integrates on the grid the Hessian was built on. The input template gains two placeholders that render empty for every other job type, so every existing ORCA input is emitted byte for byte as before. The test module's project directory moves from a shared path under arc/testing to a private tempfile.mkdtemp(), which is what the project requires of writable test scratch. It adopts the exact form open PR #1008 uses for the same file -- cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_orca_') with project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter') -- so the two PRs' overlapping lines are textually identical and merge without conflict. AN EMPTY ORBITALS FILE IS NOT READ AS A GUESS. reads_orbital_guess tests the size of the checkfile as well as its presence: the server-side copy of a .gbw an ORCA job died before writing is silent, and a failed download leaves a zero-byte file behind, so the file can be present and empty at the moment the input is composed. The adapter's fallback to an orbitals file sitting in its own job directory goes through readable_checkfile, which applies the same test, and is refused outright while the species carries an adopted wavefunction-stability verdict and holds no checkfile, in which state the route to the lower solution is BrokenSym rather than a guess. --- arc/job/adapters/orca.py | 223 ++++++++++- arc/job/adapters/orca_test.py | 690 +++++++++++++++++++++++++++++++++- 2 files changed, 885 insertions(+), 28 deletions(-) diff --git a/arc/job/adapters/orca.py b/arc/job/adapters/orca.py index 190de98a1a..2b0bb9f8f9 100644 --- a/arc/job/adapters/orca.py +++ b/arc/job/adapters/orca.py @@ -11,11 +11,15 @@ from mako.template import Template -from arc.common import get_logger, torsions_to_scans +from arc.common import count_electrons, get_logger, is_multiplicity_parity_valid, torsions_to_scans from arc.imports import incore_commands, settings from arc.job.adapter import JobAdapter from arc.job.adapters.common import (_initialize_adapter, + adopted_reference_is_unrestricted, + derived_instability_breaks_spin_symmetry, is_restricted, + job_scf_reference_is_restricted, + species_may_read_previous_orbitals, update_input_dict_with_args, which, ) @@ -94,7 +98,7 @@ def _format_orca_basis(basis: str) -> str: # options: additional keywords to control job (e.g., TightSCF, NormalPNO ...) input_template = """!${restricted}${method_class} ${method} ${basis} ${auxiliary_basis}${cabs} ${keywords} !${job_type_1} -${job_type_2} +${job_type_2}${orbital_guess} %%maxcore ${memory} %%pal nprocs ${cpus} end @@ -103,12 +107,18 @@ def _format_orca_basis(basis: str) -> str: * %%scf -MaxIter 999 +MaxIter 999${scf_keys} end${scan} ${block} """ +ORBITALS_DOWNLOAD_JOB_TYPES = ['composite', 'opt', 'optfreq', 'stability'] +ORBITALS_GUESS_JOB_TYPES = ['conf_opt', 'conf_sp', 'freq', 'opt', 'optfreq', 'scan', 'sp', 'stability'] +SYMMETRY_BREAKING_JOB_TYPES = ['conf_opt', 'conf_sp', 'freq', 'opt', 'optfreq', 'scan', 'sp'] +MULTIREFERENCE_METHOD_TOKENS = ('casscf', 'mrci', 'nevpt2', 'caspt2', 'rs2') + + class OrcaAdapter(JobAdapter): """ A class for executing Orca jobs. @@ -124,7 +134,7 @@ class OrcaAdapter(JobAdapter): block to the input file (e.g., change server or change scan resolution). bath_gas (str, optional): A bath gas. Currently only used in OneDMin to calculate L-J parameters. Allowed values are: ``'He'``, ``'Ne'``, ``'Ar'``, ``'Kr'``, ``'H2'``, ``'N2'``, or ``'O2'``. - checkfile (str, optional): The path to a previous Gaussian checkfile to be used in the current job. + checkfile (str, optional): The path to a previous job's orbitals file (``.gbw``) to be used in the current job. conformer (int, optional): Conformer number if optimizing conformers. constraints (list, optional): A list of constraints to use during an optimization or scan. cpu_cores (int, optional): The total number of cpu cores requested for a job. @@ -159,6 +169,9 @@ class OrcaAdapter(JobAdapter): xyz (dict, optional): The 3D coordinates to use. If not give, species.get_xyz() will be used. """ + check_file_name = 'input.gbw' + guess_file_name = 'guess.gbw' + def __init__(self, project: str, project_directory: str, @@ -252,9 +265,170 @@ def __init__(self, xyz=xyz, ) + if self.checkfile is None and species_may_read_previous_orbitals(self.species[0]): + if os.path.isfile(os.path.join(self.local_path, self.check_file_name)): + self.checkfile = self.readable_checkfile(os.path.join(self.local_path, self.check_file_name)) + elif self.species[0].checkfile is not None: + self.checkfile = self.readable_checkfile(self.species[0].checkfile) + + def scf_accepts_a_starting_guess(self) -> bool: + """ + Report whether this job composes an SCF a starting guess can be handed to. + + The shape of the job alone, without asking whether a guess is available: the job type, + the job array and the atom count. ``reads_orbital_guess`` answers it together with the + presence of a readable orbitals file, and ``spin_symmetry_breaking_operands`` answers it + together with the absence of one, so the same SCF is described by whichever of the two + mechanisms is open to it. + + ``ORBITALS_GUESS_JOB_TYPES`` holds the job types this adapter writes an SCF on one + starting structure for: the ``opt``, ``conf_opt``, ``optfreq`` and ``scan`` jobs, whose + first SCF is the one the guess seeds and whose later points ORCA propagates orbitals + through itself, and the ``freq``, ``sp``, ``conf_sp`` and ``stability`` jobs, which run + a single SCF. The job types absent from it are those ``write_input_file`` writes no + keyword for, so ORCA is handed no calculation for a guess to seed: ``composite``, for + which ORCA offers no composite method; ``irc`` and ``orbitals``, for which this adapter + writes neither a path-following nor an orbital-printing input; ``directed_scan``, for + which it writes neither the scan block nor the constraints such a job needs; and + ``gen_confs``, ``tsg`` and ``onedmin``, which belong to other adapters entirely. + + A job array writes no input file at all and its members share one remote path, where a + single uploaded guess would stand in for every member; this is the reason its orbitals + are not downloaded either. A monatomic species is excluded as it is in Gaussian, since + ARC spawns it neither an optimization nor a frequency job; it is excluded for + ``spin_symmetry_breaking_operands`` too, which acts for a transition state only and so + reaches no monatomic species at all. + + Returns: bool + Whether this job composes an SCF that a starting guess seeds. + """ + return self.job_type in ORBITALS_GUESS_JOB_TYPES \ + and not self.iterate_by \ + and self.species[0].number_of_atoms > 1 + + def reads_orbital_guess(self) -> bool: + """ + Report whether this job starts its SCF from a previous job's orbitals. + + The single predicate behind both halves of reading a guess: the ``!MORead`` and + ``%moinp`` keywords ``write_input_file`` emits and the ``guess.gbw`` upload + ``set_files`` adds. Emitting the keywords without uploading the file aborts the job on + a missing guess, so the two are answered here rather than tested twice. + + ORCA names its own orbitals after the input file and cannot read and write one file the + way Gaussian reuses a single checkfile, so the guess is uploaded under a name the job + will not overwrite. ORCA projects a guess written in another basis set onto this job's + basis, so no level or basis is tracked here and the question is only whether a checkfile + this adapter's ESS wrote exists and holds orbitals. An empty one holds none: a failed + download leaves a zero-byte file behind, and the server-side copy of a ``.gbw`` an ORCA + job died before writing is silent, so the file can be present and empty at the moment the + input is composed. + + Returns: bool + Whether this job reads a previous job's orbitals as its initial guess. + """ + return self.scf_accepts_a_starting_guess() \ + and self.checkfile is not None \ + and os.path.isfile(self.checkfile) \ + and bool(os.path.getsize(self.checkfile)) + + def spin_symmetry_breaking_operands(self) -> tuple[int, int] | None: + """ + Report the ``BrokenSym`` operands that break this job's spin symmetry, or ``None`` for none. + + WHAT THE DIRECTIVE IS FOR. A species carrying an adopted wavefunction-stability verdict + runs every job that follows it unrestricted, and an unrestricted SCF started from a + spin-symmetric guess converges in all but pathological cases back to the restricted + solution the verdict rejected: a restricted solution is a stationary point of the + unrestricted equations too, so a gradient-following SCF sits on it. ORCA reaches the lower + solution only when the symmetry is broken for it, either by the orbitals of a previous + broken-symmetry job, which is what ``reads_orbital_guess`` supplies, or by ``BrokenSym``, + which needs no guess at all: it converges a high-spin determinant of Na + Nb unpaired + electrons, localizes its singly-occupied orbitals and flips the Nb of them on the second + fragment. This is what a species optimized in one ESS and given a single point in ORCA + depends on, since ORCA refuses the foreign orbitals of the first. It is not the same + construction as Gaussian's ``guess=mix``, which perturbs the closed-shell guess by mixing + the frontier orbitals, so the two can converge to different broken-symmetry solutions. + + WHEN IT IS EMITTED. Only where all of the following hold. The species carries a verdict + ARC acts on, which ``adopted_reference_is_unrestricted`` defines, and that verdict names a + SPIN relaxation, which ``derived_instability_breaks_spin_symmetry`` defines: an external + instability that relaxed a constraint other than spin pairing, Gaussian's RHF -> CRHF + among them, points at a lower solution no real symmetry-broken determinant reaches. The + job composes an unrestricted reference, read off the memo ``is_restricted`` writes while + the input is composed, so the reference-agnostic method types and a multi-species job, for + which that memo is not a single reference decision, emit nothing. The job type is one of + ``SYMMETRY_BREAKING_JOB_TYPES``, which is the guess-reading job types without + ``stability``: the analysis job's subject is the reference ARC composed for it, and + ``check_stability_job`` reads the first analysis of its log as that subject, so a forced + broken-symmetry determinant would replace what is under test. The job composes an SCF a + guess could seed, and no readable orbitals file is held: where one is, ``!MORead`` already + starts the SCF from the broken-symmetry solution and the two must not both fire, since + ``BrokenSym`` discards the guess to converge its own high-spin determinant first. The + level is not a multireference one: ``BrokenSym`` is the single-determinant substitute for + a multireference treatment, and seeding a CASSCF or MRCI job from localized + spin-contaminated orbitals changes which reference space it converges to. + + THE OPERANDS. ``BrokenSym Na,Nb`` leaves Ms = (Na - Nb) / 2, so the target multiplicity + fixes Na = Nb, and the number of pairs to break is what the verdict establishes. An + adopted verdict is an external instability of a RESTRICTED reference: ARC composes a + restricted reference only at multiplicity 1 with no declared ``number_of_radicals``, so + the species is a closed-shell singlet, and a spin instability of its closed-shell + determinant says that at least ONE electron pair prefers to break. The count of negative + eigenvectors the verdict also carries is not read: a species whose lower solution breaks + two pairs is under-corrected by ``1,1``, which fails in the same direction as emitting + nothing, while over-correcting it forces unpaired electrons the measurement did not ask + for. One pair is what a single directive describes, so the operands are ``1,1``. + + WHAT IS RELIED ON AND WHAT IS CHECKED. The multiplicity is checked here rather than + inferred from the verdict, because the verdict records the reference that was tested and + not the multiplicity it was tested at, and a species whose multiplicity is not 1 admits + no Na = Nb that reaches its Ms. The electron count is checked against the multiplicity for + the same reason: ``1,1`` describes one broken pair, which a composition of fewer than two + electrons does not have and a composition of odd electron count cannot pair off. A species + failing either check is handed no directive rather than a guessed one. + + Returns: tuple[int, int] | None + The ``Na, Nb`` operands, or ``None`` where this job is handed no directive. + """ + if not adopted_reference_is_unrestricted(self.species[0]) \ + or derived_instability_breaks_spin_symmetry(self.species[0]) is not True \ + or job_scf_reference_is_restricted(self) is not False \ + or self.job_type not in SYMMETRY_BREAKING_JOB_TYPES \ + or not self.scf_accepts_a_starting_guess() \ + or self.reads_orbital_guess() \ + or self.multiplicity != 1 \ + or any(token in (self.level.method or '').lower() for token in MULTIREFERENCE_METHOD_TOKENS): + return None + xyz = self.xyz or self.species[0].get_xyz(generate=False) + symbols = xyz.get('symbols', tuple()) if isinstance(xyz, dict) else tuple() + if not len(symbols): + return None + n_electrons = count_electrons(symbols=symbols, charge=self.charge, label=self.species_label) + if n_electrons < 2 or not is_multiplicity_parity_valid(n_electrons=n_electrons, + multiplicity=self.multiplicity): + return None + return 1, 1 + def write_input_file(self) -> None: """ Write the input file to execute the job on the server. + + Where ``reads_orbital_guess`` holds, the input carries ``!MORead`` and a ``%moinp`` + naming the uploaded ``guess.gbw``, so the SCF starts from the orbitals a previous job + converged and a species' jobs describe one wavefunction rather than whichever solution + each fresh SCF happens to reach. + + Where ``spin_symmetry_breaking_operands`` returns operands instead, the ``%scf`` block + carries a ``BrokenSym``, which breaks the spin symmetry of a species running on an + adopted unrestricted reference with no orbitals of that reference to start from. The two + are alternatives of one another and exactly one of them is written. + + A ``stability`` job is a single point that adds ``STABPerform`` and + ``STABRestartUHFifUnstable true`` to the ``%scf`` block. ORCA follows an instability it + finds and analyses the relaxed solution again, so such a log holds two analyses; the + verdict of the wavefunction under test is the first of them. + ``docs/source/advanced.rst`` records why the follow is not optional. """ if 'f12' in self.level.method and not self.level.cabs: raise ValueError( @@ -264,7 +438,9 @@ def write_input_file(self) -> None: ) input_dict = dict() for key in ['block', + 'orbital_guess', 'scan', + 'scf_keys', 'job_type_1', 'job_type_2', 'keywords', @@ -294,7 +470,7 @@ def write_input_file(self) -> None: # Use a consistent DFT grid for fine_opt jobs and for any job with a frequency calculation # (`freq` and `optfreq`), so `optfreq` is treated like `freq` here and defaults to `defgrid3`. # Users can override by setting `dft_grid` in args.keyword (e.g. dft_grid: DEFGRID1). - self.args['keyword'].setdefault('dft_grid', 'defgrid3' if self.fine or self.job_type in ['freq', 'optfreq'] else 'defgrid2') + self.args['keyword'].setdefault('dft_grid', 'defgrid3' if self.fine or self.job_type in ['freq', 'optfreq', 'stability'] else 'defgrid2') elif self.level.method_type == 'wavefunction': input_dict['method_class'] = 'HF' if 'dlpno' in self.level.method: @@ -360,6 +536,10 @@ def write_input_file(self) -> None: block += f'\n\n%mrci\n citype MRCI\n davidsonopt true\n maxiter 999\nend\n' input_dict['block'] += block + elif self.job_type == 'stability': + input_dict['job_type_1'] = 'sp' + input_dict['scf_keys'] = '\nSTABPerform true\nSTABRestartUHFifUnstable true' + elif self.job_type == 'scan': scans, torsion_strings = list(), list() if self.rotor_index is not None: @@ -394,6 +574,14 @@ def write_input_file(self) -> None: """, key1='block') + if self.reads_orbital_guess(): + orbital_guess = f'!MORead\n%moinp "{self.guess_file_name}"' + input_dict['orbital_guess'] = f'\n{orbital_guess}' if input_dict['job_type_2'] else orbital_guess + else: + operands = self.spin_symmetry_breaking_operands() + if operands is not None: + input_dict['scf_keys'] += f'\nBrokenSym {operands[0]},{operands[1]}' + input_dict = update_input_dict_with_args(args=self.args, input_dict=input_dict) with open(os.path.join(self.local_path, input_filenames[self.job_adapter]), 'w') as f: @@ -412,6 +600,18 @@ def set_files(self) -> None: Else if ``'source'`` = ``'input_files'``, then the value in ``'local'`` will be taken from the respective entry in inputs.py If ``'make_x'`` is ``True``, the file will be made executable. + + THE ORBITALS FILE. Where ``reads_orbital_guess`` holds, the checkfile the job holds is + uploaded as ``guess.gbw``, a name ORCA will not overwrite with the ``input.gbw`` the + job itself writes; that same predicate decides the ``!MORead`` and ``%moinp`` keywords + of the input file, so the file is uploaded for exactly the jobs that read it. + ``input.gbw`` is downloaded only for the job types something later reads it from: the + ``opt``, ``optfreq`` and ``composite`` jobs ``Scheduler.end_job`` adopts a checkfile + from, and the ``stability`` job, whose own orbitals are the relaxed solution. Every + other job type would download tens of MB that nothing consumes; a job reading a guess + is not thereby a job whose own orbitals anything reads. A job array takes the + ``data.hdf5`` branch and downloads no orbitals at all, since its members share one + remote path and would overwrite one another's. """ # 1. ** Upload ** # 1.1. submit file @@ -425,10 +625,14 @@ def set_files(self) -> None: # if this is not a job array, we need the ESS input file self.write_input_file() self.files_to_upload.append(self.get_file_property_dictionary(file_name=input_filenames[self.job_adapter])) - # 1.3. HDF5 file + # 1.3. orbitals file, uploaded under a name the job will not overwrite with its own + if self.reads_orbital_guess(): + self.files_to_upload.append(self.get_file_property_dictionary(file_name=self.guess_file_name, + local=self.checkfile)) + # 1.4. HDF5 file if self.iterate_by and os.path.isfile(os.path.join(self.local_path, 'data.hdf5')): self.files_to_upload.append(self.get_file_property_dictionary(file_name='data.hdf5')) - # 1.4 job.sh + # 1.5 job.sh job_sh_dict = self.set_job_shell_file_to_upload() # Set optional job.sh files if relevant. if job_sh_dict is not None: self.files_to_upload.append(job_sh_dict) @@ -440,7 +644,10 @@ def set_files(self) -> None: # 2.2. log file self.files_to_download.append(self.get_file_property_dictionary( file_name=output_filenames[self.job_adapter])) - # 2.3. Hessian file generated by frequency calculations + # 2.3. orbitals file, the guess of any job that follows + if self.job_type in ORBITALS_DOWNLOAD_JOB_TYPES: + self.files_to_download.append(self.get_file_property_dictionary(file_name=self.check_file_name)) + # 2.4. Hessian file generated by frequency calculations # The Hessian file is useful when the user would like to project out the rotors if self.job_type in ['freq', 'optfreq']: self.files_to_download.append(self.get_file_property_dictionary(file_name='input.hess')) diff --git a/arc/job/adapters/orca_test.py b/arc/job/adapters/orca_test.py index c0ce422c89..cb8947e0a1 100644 --- a/arc/job/adapters/orca_test.py +++ b/arc/job/adapters/orca_test.py @@ -9,10 +9,15 @@ import math import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH -from arc.job.adapters.orca import (OrcaAdapter, +from arc.job.adapter import JobTypeEnum +from arc.job.adapters.orca import (MULTIREFERENCE_METHOD_TOKENS, + ORBITALS_DOWNLOAD_JOB_TYPES, + ORBITALS_GUESS_JOB_TYPES, + SYMMETRY_BREAKING_JOB_TYPES, + OrcaAdapter, _format_orca_basis, _format_orca_basis_token, _format_orca_method, @@ -32,11 +37,13 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_orca_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = OrcaAdapter(execution_type='queue', job_type='sp', level=Level(method='DLPNO-CCSD(T)', basis='def2-tzvp', auxiliary_basis='def2-tzvp/c'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -50,7 +57,7 @@ def setUpClass(cls): level=Level(method='DLPNO-CCSD(T)', basis='def2-tzvp', auxiliary_basis='def2-tzvp/c', solvation_method='SMD', solvent='DMSO'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -64,7 +71,7 @@ def setUpClass(cls): level=Level(method='DLPNO-CCSD(T)', basis='def2-tzvp', auxiliary_basis='def2-tzvp/c', solvation_method='cpcm', solvent='water'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -77,7 +84,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MP2_CASSCF_MRCI', basis='aug-cc-pVTZ'), project='test4', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', active=(14, 7), xyz="""C 0.03807240 0.00035621 -0.00484242 @@ -197,7 +204,7 @@ def test_write_input_file_f12_with_cabs(self): auxiliary_basis='aug-cc-pVTZ/C', cabs='cc-pVTZ-F12-CABS'), project='test_f12', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='O_atom', smiles='[O]', xyz='O 0.0 0.0 0.0')], testing=True, @@ -223,7 +230,7 @@ def test_write_input_file_f12_without_cabs_raises(self): basis='cc-pVTZ-F12', auxiliary_basis='aug-cc-pVTZ/C'), project='test_f12_bad', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='O_atom', smiles='[O]', xyz='O 0.0 0.0 0.0')], testing=True, @@ -321,7 +328,7 @@ def test_dft_grid_regular_opt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -343,7 +350,7 @@ def test_dft_grid_fine_opt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid_fine', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -364,7 +371,7 @@ def test_dft_grid_freq(self): job_type='freq', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid_freq', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -385,7 +392,7 @@ def test_dft_grid_optfreq(self): job_type='optfreq', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid_optfreq', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -406,7 +413,7 @@ def test_fine_opt_convergence_tightopt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_fine_opt_conv', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -428,7 +435,7 @@ def test_recalc_hess_in_optts(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_optts_hess', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='TS_example', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -454,7 +461,7 @@ def test_recalc_hess_not_in_regular_opt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_opt_no_hess', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -483,7 +490,7 @@ def test_writing_input_does_not_pollute_level_args(self): job_type='opt', level=level, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -497,13 +504,656 @@ def test_writing_input_does_not_pollute_level_args(self): self.assertEqual(level.args, {'keyword': dict(), 'block': dict()}) self.assertNotIn('args', level.as_dict()) + +class TestOrcaStabilityJob(unittest.TestCase): + """ + Contains unit tests for the ORCA wavefunction stability analysis job. + """ + @classmethod - def tearDownClass(cls): + def setUpClass(cls): """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests + A method that is run before all unit tests in this class. """ - shutil.rmtree(os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), ignore_errors=True) + cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_orca_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) + cls.xyz = """O -0.00032 0.39999 0.00000 +H -0.76950 -0.19750 0.00000 +H 0.76982 -0.20249 0.00000""" + cls.torsional_xyz = """H 0.86000 -0.03000 0.62000 +O 0.10000 0.00000 0.00000 +O -1.10000 0.00000 0.00000 +H -1.30000 0.94000 0.00000""" + cls.job_type_args = {'directed_scan': {'torsions': [[0, 1, 2, 3]], 'dihedrals': [120.0]}, + 'irc': {'irc_direction': 'forward'}, + 'scan': {'torsions': [[0, 1, 2, 3]]}, + } + + def _job(self, + job_type: str = 'stability', + checkfile: str | None = None, + species: list | None = None, + **kwargs, + ) -> OrcaAdapter: + """Build a testing ORCA job of the requested type.""" + return OrcaAdapter(execution_type='queue', + job_type=job_type, + level=Level(method='b3lyp', basis='def2tzvp'), + project='test', + project_directory=os.path.join(self.scratch_dir, 'test_OrcaStabilityJob'), + checkfile=checkfile, + species=species if species is not None else [ARCSpecies(label='H2O', xyz=self.xyz)], + testing=True, + **kwargs, + ) + + def _torsional_job(self, job_type: str, checkfile: str | None = None) -> OrcaAdapter: + """Build a testing ORCA job of any job type, on a species carrying a torsion.""" + return self._job(job_type=job_type, + checkfile=checkfile, + species=[ARCSpecies(label='HOOH', xyz=self.torsional_xyz)], + **self.job_type_args.get(job_type, dict()), + ) + + def _checkfile(self, file_name: str = 'input.gbw', content: str = 'orbitals') -> str: + """Write a stand-in for a previous job's orbitals file and return its path.""" + directory = tempfile.mkdtemp(prefix='arc_test_orca_gbw_', dir=self.scratch_dir) + path = os.path.join(directory, file_name) + with open(path, 'w') as f: + f.write(content) + self.addCleanup(shutil.rmtree, directory, ignore_errors=True) + return path + + def _input_file(self, job: OrcaAdapter) -> str: + """Write a job's input file and return its content.""" + job.write_input_file() + with open(os.path.join(job.local_path, input_filenames[job.job_adapter]), 'r') as f: + return f.read() + + def _plant_orbitals(self, job: OrcaAdapter, content: str = 'orbitals') -> str: + """Write an orbitals file into a job's own directory and return its path.""" + path = os.path.join(job.local_path, job.check_file_name) + with open(path, 'w') as f: + f.write(content) + self.addCleanup(lambda: os.path.isfile(path) and os.remove(path)) + return path + + def test_write_stability_input_file(self): + """Test that a stability job is a single point carrying the two STAB keys""" + job = self._job() + expected_input_file = f"""!rKS b3lyp def2-tzvp tightscf defgrid3 +!sp + +%maxcore {job.input_file_memory} +%pal nprocs {job.cpu_cores} end + +* xyz 0 1 +O -0.00032000 0.39999000 0.00000000 +H -0.76950000 -0.19750000 0.00000000 +H 0.76982000 -0.20249000 0.00000000 +* + +%scf +MaxIter 999 +STABPerform true +STABRestartUHFifUnstable true +end + +""" + self.assertEqual(self._input_file(job), expected_input_file) + + def test_the_instability_is_always_followed(self): + """Test that the restart key is true, which ORCA 6.0.0 needs to survive an instability""" + content = self._input_file(self._job()) + self.assertIn('STABRestartUHFifUnstable true', content) + self.assertNotIn('STABRestartUHFifUnstable false', content) + + def test_stability_input_file_reads_the_orbitals_under_test(self): + """Test that a stability job holding a checkfile reads it as its initial guess""" + job = self._job(checkfile=self._checkfile()) + expected_input_file = f"""!rKS b3lyp def2-tzvp tightscf defgrid3 +!sp +!MORead +%moinp "guess.gbw" +%maxcore {job.input_file_memory} +%pal nprocs {job.cpu_cores} end + +* xyz 0 1 +O -0.00032000 0.39999000 0.00000000 +H -0.76950000 -0.19750000 0.00000000 +H 0.76982000 -0.20249000 0.00000000 +* + +%scf +MaxIter 999 +STABPerform true +STABRestartUHFifUnstable true +end + +""" + self.assertEqual(self._input_file(job), expected_input_file) + + def test_no_guess_is_read_without_a_checkfile(self): + """Test that a stability job holding no checkfile emits no MORead""" + content = self._input_file(self._job()) + self.assertNotIn('MORead', content) + self.assertNotIn('moinp', content) + + def test_a_missing_checkfile_is_not_read(self): + """Test that a checkfile path that does not exist emits no MORead""" + content = self._input_file(self._job(checkfile=os.path.join(self.scratch_dir, 'nonexistent.gbw'))) + self.assertNotIn('MORead', content) + + def test_every_guess_reading_job_type_reads_the_guess(self): + """Test that each job type listed as reading a guess emits MORead when a checkfile is held""" + for job_type in ORBITALS_GUESS_JOB_TYPES: + content = self._input_file(self._torsional_job(job_type=job_type, checkfile=self._checkfile())) + self.assertIn('!MORead', content, msg=f'a {job_type} job emitted no MORead') + self.assertIn('%moinp "guess.gbw"', content, msg=f'a {job_type} job emitted no moinp') + + def test_only_the_stability_job_analyses_the_wavefunction(self): + """Test that reading a guess does not make another job type request a stability analysis""" + for job_type in ['sp', 'opt', 'freq']: + content = self._input_file(self._job(job_type=job_type, checkfile=self._checkfile())) + self.assertNotIn('STABPerform', content, msg=f'a {job_type} job emitted STABPerform') + + def test_the_frequency_job_reads_the_optimization_orbitals(self): + """Test that a freq job holding a checkfile starts its SCF from it""" + job = self._job(job_type='freq', checkfile=self._checkfile()) + expected_input_file = f"""!rKS b3lyp def2-tzvp tightscf defgrid3 +!Freq +!MORead +%moinp "guess.gbw" +%maxcore {job.input_file_memory} +%pal nprocs {job.cpu_cores} end + +* xyz 0 1 +O -0.00032000 0.39999000 0.00000000 +H -0.76950000 -0.19750000 0.00000000 +H 0.76982000 -0.20249000 0.00000000 +* + +%scf +MaxIter 999 +end + +""" + self.assertEqual(self._input_file(job), expected_input_file) + + def test_a_frequency_job_holding_no_checkfile_reads_no_guess(self): + """Test that a freq job with no checkfile emits neither keyword""" + content = self._input_file(self._job(job_type='freq')) + self.assertNotIn('MORead', content) + self.assertNotIn('moinp', content) + + def test_the_guess_keywords_occupy_their_own_lines(self): + """Test that MORead and moinp each begin a line rather than running into the keyword above""" + for job_type in ORBITALS_GUESS_JOB_TYPES: + content = self._input_file(self._torsional_job(job_type=job_type, checkfile=self._checkfile())) + self.assertIn('\n!MORead\n%moinp "guess.gbw"\n', content, + msg=f'a {job_type} job ran the guess keywords into the line above') + + def test_job_types_that_read_no_guess(self): + """Test that a job type ORCA is handed no calculation for reads no guess""" + for job_type in ['composite', 'directed_scan', 'irc', 'orbitals']: + self.assertNotIn(job_type, ORBITALS_GUESS_JOB_TYPES) + content = self._input_file(self._torsional_job(job_type=job_type, checkfile=self._checkfile())) + self.assertNotIn('MORead', content, msg=f'a {job_type} job emitted MORead') + self.assertNotIn('moinp', content, msg=f'a {job_type} job emitted moinp') + + def test_a_monatomic_species_reads_no_guess(self): + """Test that a species of one atom is excluded, as it is in Gaussian""" + job = OrcaAdapter(execution_type='queue', + job_type='sp', + level=Level(method='b3lyp', basis='def2tzvp'), + project='test', + project_directory=os.path.join(self.scratch_dir, 'test_OrcaStabilityJob'), + checkfile=self._checkfile(), + species=[ARCSpecies(label='H', smiles='[H]')], + testing=True, + ) + self.assertFalse(job.reads_orbital_guess()) + self.assertNotIn('MORead', self._input_file(job)) + self.assertNotIn('guess.gbw', [up_file['file_name'] for up_file in job.files_to_upload]) + + def test_the_stability_job_uses_the_frequency_job_grid(self): + """Test that the stability single point integrates on the grid a frequency job uses""" + self.assertIn('defgrid3', self._input_file(self._job())) + self.assertIn('defgrid2', self._input_file(self._job(job_type='sp'))) + + def test_orbital_file_names(self): + """Test that ORCA writes its orbitals to input.gbw and reads a guess from another name""" + job = self._job() + self.assertEqual(job.check_file_name, 'input.gbw') + self.assertEqual(job.guess_file_name, 'guess.gbw') + self.assertNotEqual(job.check_file_name, job.guess_file_name) + self.assertEqual(job.local_path_to_check_file, os.path.join(job.local_path, 'input.gbw')) + + def test_set_files_uploads_the_guess_and_downloads_the_orbitals(self): + """Test that a stability job uploads the orbitals under test and downloads its own""" + checkfile = self._checkfile() + job = self._job(checkfile=checkfile) + self.assertIn({'file_name': 'guess.gbw', + 'local': checkfile, + 'remote': os.path.join(job.remote_path, 'guess.gbw'), + 'source': 'path', + 'make_x': False}, + job.files_to_upload) + self.assertIn({'file_name': 'input.gbw', + 'local': os.path.join(job.local_path, 'input.gbw'), + 'remote': os.path.join(job.remote_path, 'input.gbw'), + 'source': 'path', + 'make_x': False}, + job.files_to_download) + + def test_no_guess_is_uploaded_without_a_checkfile(self): + """Test that a job holding no checkfile uploads no orbitals""" + job = self._job() + self.assertNotIn('guess.gbw', [up_file['file_name'] for up_file in job.files_to_upload]) + self.assertIn('input.gbw', [file['file_name'] for file in job.files_to_download]) + + def test_every_guess_reading_job_type_uploads_the_guess(self): + """Test that each job type listed as reading a guess uploads the orbitals it reads""" + for job_type in ORBITALS_GUESS_JOB_TYPES: + job = self._torsional_job(job_type=job_type, checkfile=self._checkfile()) + self.assertIn('guess.gbw', [up_file['file_name'] for up_file in job.files_to_upload], + msg=f'a {job_type} job uploaded no guess') + + def test_job_types_that_upload_no_guess(self): + """Test that a job type ORCA is handed no calculation for uploads no orbitals""" + for job_type in ['composite', 'directed_scan', 'irc', 'orbitals']: + job = self._torsional_job(job_type=job_type, checkfile=self._checkfile()) + self.assertNotIn('guess.gbw', [up_file['file_name'] for up_file in job.files_to_upload], + msg=f'a {job_type} job uploaded a guess') + + def test_the_upload_set_and_the_emission_set_agree(self): + """Test that over every job type a guess is uploaded for exactly the jobs that read one""" + job_types = [job_type.value for job_type in JobTypeEnum] + self.assertTrue(set(ORBITALS_GUESS_JOB_TYPES).issubset(set(job_types))) + for job_type in job_types: + job = self._torsional_job(job_type=job_type, checkfile=self._checkfile()) + uploaded = 'guess.gbw' in [up_file['file_name'] for up_file in job.files_to_upload] + emitted = 'MORead' in self._input_file(job) + self.assertEqual(uploaded, emitted, + msg=f'a {job_type} job uploaded a guess: {uploaded}, emitted MORead: {emitted}') + self.assertEqual(emitted, job.reads_orbital_guess(), + msg=f'a {job_type} job emitted MORead: {emitted}, ' + f'reads_orbital_guess: {job.reads_orbital_guess()}') + self.assertEqual(emitted, job_type in ORBITALS_GUESS_JOB_TYPES, + msg=f'a {job_type} job emitted MORead: {emitted}') + + def test_a_job_array_reads_no_guess(self): + """Test that a job array, whose members share one remote path, reads no guess""" + job = self._job(job_type='sp', checkfile=self._checkfile()) + self.assertTrue(job.reads_orbital_guess()) + job.iterate_by = ['species'] + self.assertFalse(job.reads_orbital_guess()) + + def test_the_orbitals_are_downloaded_only_where_they_are_read(self): + """Test that only the job types something later reads a .gbw from download one""" + for job_type in ORBITALS_DOWNLOAD_JOB_TYPES: + job = self._job(job_type=job_type) + self.assertIn('input.gbw', [file['file_name'] for file in job.files_to_download], + msg=f'a {job_type} job did not download its orbitals') + for job_type in ['sp', 'freq', 'orbitals']: + job = self._job(job_type=job_type) + self.assertNotIn('input.gbw', [file['file_name'] for file in job.files_to_download], + msg=f'a {job_type} job downloaded orbitals nothing reads') + + def test_a_checkfile_written_by_another_ess_is_refused(self): + """Test that a Gaussian check.chk is not uploaded to ORCA as an initial guess""" + job = self._job(checkfile=self._checkfile(file_name='check.chk')) + self.assertIsNone(job.checkfile) + self.assertNotIn('guess.gbw', [up_file['file_name'] for up_file in job.files_to_upload]) + self.assertNotIn('MORead', self._input_file(job)) + + def test_an_empty_orbitals_file_is_refused(self): + """Test that the zero-byte file a failed download leaves behind is not read as a guess""" + job = self._job(checkfile=self._checkfile(content='')) + self.assertIsNone(job.checkfile) + self.assertFalse(job.reads_orbital_guess()) + self.assertNotIn('guess.gbw', [up_file['file_name'] for up_file in job.files_to_upload]) + self.assertNotIn('MORead', self._input_file(job)) + + def test_an_orbitals_file_emptied_after_the_job_was_built_is_not_read(self): + """Test that the guess predicate answers on the file rather than on the path""" + checkfile = self._checkfile() + job = self._job(checkfile=checkfile) + self.assertTrue(job.reads_orbital_guess()) + with open(checkfile, 'w'): + pass + self.assertFalse(job.reads_orbital_guess()) + + def test_an_empty_orbitals_file_in_a_reused_job_directory_is_not_adopted(self): + """Test that a zero-byte orbitals file left in the job directory is not picked up""" + first = self._job() + planted = self._plant_orbitals(first, content='') + second = self._job(job_name=first.job_name, job_num=first.job_num) + self.assertEqual(second.local_path, first.local_path) + self.assertIsNone(second.checkfile) + self.assertTrue(os.path.isfile(planted)) + + def test_an_orbitals_file_in_a_reused_job_directory_is_adopted(self): + """Test that the job directory remains a source of orbitals for a species holding none""" + first = self._job() + planted = self._plant_orbitals(first) + second = self._job(job_name=first.job_name, job_num=first.job_num) + self.assertEqual(second.checkfile, planted) + + def test_a_directed_rotor_gbw_is_still_read(self): + """Test that the name ARC gives a directed rotor's orbitals is not read as a foreign one""" + directed = self._checkfile(file_name='directed_rotor_input.gbw') + job = self._job(checkfile=directed) + self.assertEqual(job.checkfile, directed) + self.assertIn('MORead', self._input_file(job)) + + +class TestOrcaBrokenSymmetry(unittest.TestCase): + """ + Contains unit tests for the ORCA symmetry-breaking directive of an adopted unrestricted reference. + """ + + @classmethod + def setUpClass(cls): + """ + A method that is run before all unit tests in this class. + """ + cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_orca_bs_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) + cls.xyz = """O -0.00032 0.39999 0.00000 +H -0.76950 -0.19750 0.00000 +H 0.76982 -0.20249 0.00000""" + cls.torsional_xyz = """H 0.86000 -0.03000 0.62000 +O 0.10000 0.00000 0.00000 +O -1.10000 0.00000 0.00000 +H -1.30000 0.94000 0.00000""" + cls.adopted_verdict = {'verdict': 'external_instability', 'restricted': True, + 'relaxations': ['RHF -> UHF']} + cls.job_type_args = {'directed_scan': {'torsions': [[0, 1, 2, 3]], 'dihedrals': [120.0]}, + 'irc': {'irc_direction': 'forward'}, + 'scan': {'torsions': [[0, 1, 2, 3]]}, + } + + def _species(self, + verdict: dict | None = None, + multiplicity: int | None = None, + xyz: str | None = None, + is_ts: bool = True, + label: str | None = None, + **kwargs, + ) -> ARCSpecies: + """Build a testing species carrying a wavefunction stability verdict.""" + species = ARCSpecies(label=label if label is not None else 'TS0' if is_ts else 'HOH', + xyz=xyz if xyz is not None else self.xyz, + is_ts=is_ts, + multiplicity=multiplicity, + **kwargs, + ) + species.derived_stability_verdict = verdict if verdict is not None else self.adopted_verdict + return species + + def _job(self, + job_type: str = 'sp', + checkfile: str | None = None, + species: ARCSpecies | None = None, + level: Level | None = None, + **kwargs, + ) -> OrcaAdapter: + """Build a testing ORCA job on a species carrying a wavefunction stability verdict.""" + return OrcaAdapter(execution_type='queue', + job_type=job_type, + level=level if level is not None else Level(method='b3lyp', basis='def2tzvp'), + project='test', + project_directory=os.path.join(self.scratch_dir, 'test_OrcaBrokenSymmetry'), + checkfile=checkfile, + species=[species if species is not None + else self._species(xyz=self.torsional_xyz) + if job_type in self.job_type_args else self._species()], + testing=True, + **self.job_type_args.get(job_type, dict()), + **kwargs, + ) + + def _checkfile(self, file_name: str = 'input.gbw') -> str: + """Write a stand-in for a previous job's orbitals file and return its path.""" + directory = tempfile.mkdtemp(prefix='arc_test_orca_bs_gbw_', dir=self.scratch_dir) + path = os.path.join(directory, file_name) + with open(path, 'w') as f: + f.write('orbitals') + self.addCleanup(shutil.rmtree, directory, ignore_errors=True) + return path + + def _input_file(self, job: OrcaAdapter) -> str: + """Write a job's input file and return its content.""" + job.write_input_file() + with open(os.path.join(job.local_path, input_filenames[job.job_adapter]), 'r') as f: + return f.read() + + def _plant_orbitals(self, job: OrcaAdapter, content: str = 'orbitals') -> str: + """Write an orbitals file into a job's own directory and return its path.""" + path = os.path.join(job.local_path, job.check_file_name) + with open(path, 'w') as f: + f.write(content) + self.addCleanup(lambda: os.path.isfile(path) and os.remove(path)) + return path + + def test_the_directive_is_emitted_for_an_adopted_reference_with_no_guess(self): + """Test that a job on an adopted unrestricted reference with no orbitals carries BrokenSym""" + job = self._job() + content = self._input_file(job) + self.assertIn('\n%scf\nMaxIter 999\nBrokenSym 1,1\nend', content) + self.assertIn('!uKS', content) + self.assertNotIn('MORead', content) + + def test_the_operands_are_one_broken_pair(self): + """Test that the operands are the single pair a closed-shell external instability establishes""" + self.assertEqual(self._job().spin_symmetry_breaking_operands(), (1, 1)) + + def test_no_directive_where_a_readable_guess_exists(self): + """Test that the orbitals of the broken-symmetry solution are read instead of the directive""" + job = self._job(checkfile=self._checkfile()) + content = self._input_file(job) + self.assertIn('!MORead', content) + self.assertNotIn('BrokenSym', content) + self.assertIsNone(job.spin_symmetry_breaking_operands()) + + def test_a_directive_where_the_guess_is_a_foreign_checkfile(self): + """Test that orbitals ORCA refuses to read leave the directive as the mechanism in play""" + job = self._job(checkfile=self._checkfile(file_name='check.chk')) + content = self._input_file(job) + self.assertIsNone(job.checkfile) + self.assertNotIn('MORead', content) + self.assertIn('BrokenSym 1,1', content) + + def test_orbitals_dropped_for_an_adopted_verdict_are_not_re_adopted(self): + """Test that a species holding no orbitals of its adopted reference reads none from its directory""" + first = self._job() + self._plant_orbitals(first) + second = self._job(job_name=first.job_name, job_num=first.job_num) + self.assertEqual(second.local_path, first.local_path) + self.assertIsNone(second.checkfile) + content = self._input_file(second) + self.assertNotIn('MORead', content) + self.assertIn('BrokenSym 1,1', content) + + def test_no_directive_without_a_verdict(self): + """Test that a species carrying no stability verdict is handed no directive""" + species = self._species() + species.derived_stability_verdict = None + job = self._job(species=species) + self.assertIsNone(job.spin_symmetry_breaking_operands()) + self.assertNotIn('BrokenSym', self._input_file(job)) + + def test_no_directive_for_a_verdict_arc_does_not_act_on(self): + """Test that only the verdict adoption acts on emits the directive""" + for verdict in [{'verdict': 'stable', 'restricted': True}, + {'verdict': 'internal_instability', 'restricted': True}, + {'verdict': 'external_instability', 'restricted': False}, + {'verdict': 'external_instability', 'restricted': None}, + {'verdict': 'unknown', 'restricted': True}, + ]: + job = self._job(species=self._species(verdict=verdict)) + self.assertIsNone(job.spin_symmetry_breaking_operands(), + msg=f'a job on the verdict {verdict} was handed operands') + self.assertNotIn('BrokenSym', self._input_file(job), + msg=f'a job on the verdict {verdict} emitted BrokenSym') + + def test_no_directive_for_a_species_that_is_not_a_transition_state(self): + """Test that a verdict ARC reports without acting on it emits no directive""" + job = self._job(species=self._species(is_ts=False)) + self.assertNotIn('BrokenSym', self._input_file(job)) + + def test_no_directive_where_the_user_declared_the_reference(self): + """Test that a declared number_of_radicals blocks the directive as it blocks the adoption""" + job = self._job(species=self._species(multiplicity=1, number_of_radicals=2)) + content = self._input_file(job) + self.assertIn('!uKS', content) + self.assertNotIn('BrokenSym', content) + + def test_no_directive_for_a_restricted_job(self): + """Test that a job composing a restricted reference is handed no directive""" + species = self._species() + species.derived_stability_verdict = None + job = self._job(species=species) + content = self._input_file(job) + self.assertIn('!rKS', content) + self.assertNotIn('BrokenSym', content) + + def test_no_directive_for_an_unrestricted_job_of_an_open_shell_species(self): + """Test that a species unrestricted by its own multiplicity is handed no directive""" + job = self._job(species=self._species(verdict=self.adopted_verdict, multiplicity=3)) + content = self._input_file(job) + self.assertIn('!uKS', content) + self.assertNotIn('BrokenSym', content) + self.assertIsNone(job.spin_symmetry_breaking_operands()) + + def test_no_directive_where_the_job_declared_no_single_unrestricted_reference(self): + """Test that the directive follows the reference the input declared and not the species alone""" + job = self._job() + self.assertEqual(job.spin_symmetry_breaking_operands(), (1, 1)) + for restricted_used in [None, True, [False], [False, False]]: + job.restricted_used = restricted_used + self.assertIsNone(job.spin_symmetry_breaking_operands(), + msg=f'a job whose reference memo is {restricted_used} was handed operands') + + def test_no_directive_for_a_monatomic_species(self): + """Test that a species ARC spawns no geometry chain for is handed no directive""" + job = self._job(species=self._species(xyz='O 0.0 0.0 0.0', multiplicity=1)) + self.assertIsNone(job.spin_symmetry_breaking_operands()) + self.assertNotIn('BrokenSym', self._input_file(job)) + + def test_no_directive_for_a_job_array(self): + """Test that a job array, which writes no input file, is handed no directive""" + job = self._job() + self.assertEqual(job.spin_symmetry_breaking_operands(), (1, 1)) + job.iterate_by = ['species'] + self.assertIsNone(job.spin_symmetry_breaking_operands()) + + def test_job_types_that_compose_no_seedable_scf(self): + """Test that a job type ORCA is written no SCF keyword for is handed no directive""" + for job_type in [job_type.value for job_type in JobTypeEnum + if job_type.value not in ORBITALS_GUESS_JOB_TYPES]: + job = self._job(job_type=job_type) + self.assertIsNone(job.spin_symmetry_breaking_operands(), + msg=f'a {job_type} job was handed operands') + + def test_every_guess_reading_job_type_takes_the_directive(self): + """Test that each job type reading a guess takes the directive when no guess is held""" + for job_type in SYMMETRY_BREAKING_JOB_TYPES: + job = self._job(job_type=job_type) + self.assertEqual(job.spin_symmetry_breaking_operands(), (1, 1), + msg=f'a {job_type} job was handed no operands') + self.assertIn('BrokenSym 1,1', self._input_file(job), + msg=f'a {job_type} job emitted no BrokenSym') + + def test_the_guess_and_the_directive_are_alternatives(self): + """Test that exactly one of the two mechanisms is written for every job that admits either""" + for job_type in SYMMETRY_BREAKING_JOB_TYPES: + for checkfile in [None, self._checkfile()]: + job = self._job(job_type=job_type, checkfile=checkfile) + content = self._input_file(job) + self.assertEqual(['MORead' in content, 'BrokenSym' in content].count(True), 1, + msg=f'a {job_type} job holding checkfile {checkfile} wrote ' + f'MORead: {"MORead" in content}, BrokenSym: {"BrokenSym" in content}') + + def test_the_symmetry_breaking_job_types_are_the_guess_reading_ones_without_the_analysis(self): + """Test that the directive covers the guess-reading job types except the analysis itself""" + self.assertEqual(set(ORBITALS_GUESS_JOB_TYPES) - set(SYMMETRY_BREAKING_JOB_TYPES), {'stability'}) + self.assertEqual(set(SYMMETRY_BREAKING_JOB_TYPES) - set(ORBITALS_GUESS_JOB_TYPES), set()) + + def test_the_analysis_job_takes_no_directive(self): + """Test that a job analysing a reference is not handed a directive that would replace it""" + job = self._job(job_type='stability') + self.assertIsNone(job.spin_symmetry_breaking_operands()) + content = self._input_file(job) + self.assertIn('STABPerform true', content) + self.assertNotIn('BrokenSym', content) + + def test_no_directive_without_a_spin_relaxation(self): + """Test that an external instability of a constraint other than spin takes no directive""" + for relaxations in [['RHF -> CRHF'], ['RHF -> CRHF', 'RKS -> CRKS'], list(), None]: + species = self._species(verdict=dict(self.adopted_verdict, relaxations=relaxations)) + job = self._job(species=species) + self.assertIsNone(job.spin_symmetry_breaking_operands(), + msg=f'the relaxations {relaxations} were handed operands') + self.assertNotIn('BrokenSym', self._input_file(job), + msg=f'the relaxations {relaxations} emitted BrokenSym') + + def test_a_spin_relaxation_among_several_takes_the_directive(self): + """Test that a verdict naming a spin relaxation alongside another one takes the directive""" + species = self._species(verdict=dict(self.adopted_verdict, relaxations=['RHF -> CRHF', 'RHF -> UHF'])) + self.assertEqual(self._job(species=species).spin_symmetry_breaking_operands(), (1, 1)) + + def test_no_directive_for_a_multireference_level(self): + """Test that a level whose reference space is optimized is handed no directive""" + for token in MULTIREFERENCE_METHOD_TOKENS: + job = self._job(level=Level(method=token, basis='def2tzvp')) + self.assertIsNone(job.spin_symmetry_breaking_operands(), + msg=f'a {token} job was handed operands') + self.assertNotIn('BrokenSym', self._input_file(job), + msg=f'a {token} job emitted BrokenSym') + + def test_no_directive_for_a_composition_with_no_pair_to_break(self): + """Test that a composition of fewer than two electrons is handed no directive""" + species = self._species(xyz='H 0.00 0.00 0.00\nH 0.00 0.00 0.74') + species.charge = 2 + job = self._job(species=species) + self.assertEqual(job.charge, 2) + self.assertIsNone(job.spin_symmetry_breaking_operands()) + self.assertNotIn('BrokenSym', self._input_file(job)) + + def test_no_directive_for_an_electron_count_the_multiplicity_contradicts(self): + """Test that a composition whose electron count cannot pair off is handed no directive""" + species = self._species() + species.charge = 1 + job = self._job(species=species) + self.assertEqual(job.multiplicity, 1) + self.assertIsNone(job.spin_symmetry_breaking_operands()) + self.assertNotIn('BrokenSym', self._input_file(job)) + + def test_a_two_electron_species_takes_the_directive(self): + """Test that the smallest composition holding one pair is handed the directive""" + job = self._job(species=self._species(xyz='H 0.00 0.00 0.00\nH 0.00 0.00 0.74')) + self.assertEqual(job.spin_symmetry_breaking_operands(), (1, 1)) + self.assertIn('BrokenSym 1,1', self._input_file(job)) + + def test_a_charged_species_takes_the_directive_on_its_own_electron_count(self): + """Test that the electron count the guards read is the charged one""" + species = self._species() + species.charge = 2 + job = self._job(species=species) + self.assertEqual(job.spin_symmetry_breaking_operands(), (1, 1)) + self.assertIn('BrokenSym 1,1', self._input_file(job)) + + def test_the_stability_job_of_a_restricted_species_is_unchanged(self): + """Test that the analysis itself, which runs before any adoption, carries no directive""" + species = self._species() + species.derived_stability_verdict = None + content = self._input_file(self._job(job_type='stability', species=species)) + self.assertIn('\n%scf\nMaxIter 999\nSTABPerform true\nSTABRestartUHFifUnstable true\nend', content) + self.assertNotIn('BrokenSym', content) if __name__ == '__main__': From 1ddf7b4071b1ed065b0c4d5f2998c2b77fd8fcb7 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 05/12] Let a measured stability verdict decide the SCF reference the user did not The stability job was added as a pure diagnostic, and the argument that nothing should branch on its verdict was about TS SELECTION: switching guesses on an instability would burn the guess list to no effect, since within one reaction six geometries shared an eigenvalue to seven decimals, and it would bias rather than filter, since in one reaction the three lowest saddles were the unstable ones. None of that is touched. No guess is rejected, no job is re-run, and no check gates on the verdict. What changes is the one thing the diagnostic is direct evidence for and nothing else in ARC measures: whether the restricted reference is the ground state. THE CONTRACT. 1. A user-declared number_of_radicals ALWAYS wins, and is never overwritten by a calculation. 2. ARC still runs and still assesses the check when the user declared a value. 3. Disagreement is a WARNING, never a crash. Both pictures are recorded; the user's is the one used. 4. With nothing declared and an external (R -> U) instability of a RESTRICTED reference reported, ARC adopts the measured verdict for the reference decision on subsequent jobs and records the provenance. WHERE THE DERIVED VALUE LIVES. NOT in number_of_radicals. That field is read in 13 places, 8 of them molecular-graph perception and validation (six sites in species.py and the scheduler's four n_radicals= call sites), plus xtb_adapter.py's `uhf = number_of_radicals or multiplicity - 1`. A measured SCF property must not steer graph perception or an xTB UHF count, so a declared radical count and a measured wavefunction verdict cannot share a field. ARCSpecies gains derived_stability_verdict instead, defaulting to None, serialised through as_dict / from_dict only when set. It is deliberately not an __init__ keyword: it is not user input and there is no way to declare it. The name avoids output[label]['wavefunction_stability'], which is the summary STRING the run report reads and is a different object. ARCSpecies also gains scf_references, the per-job-type record of which reference each completed job actually declared. is_species_restricted consults the verdict LAST. The multiplicity > 1 branch is untouched, the signature and the species=None fallback are unchanged, and the new branch is reached only when number_of_radicals is None. Only an EXTERNAL instability of a RESTRICTED reference flips it. An INTERNAL instability must never flip the reference: it is a lower solution inside the reference's own spin symmetry, which is a different problem and is not evidence of broken-symmetry character. Nor does an external instability of an already-unrestricted reference, which says nothing about a restricted one. THE PRECEDENCE IS WRITTEN ONCE. adopted_reference_is_unrestricted is the predicate for "a verdict ARC acts on", and it is the only place the rule that a declared number_of_radicals of ANY value blocks adoption is stated; is_species_restricted, open_shell_character_source and the scheduler's TS-switch carry all read it rather than restating it. A declaration of 0 or 1 asks for a restricted reference, so it blocks the verdict as surely as a declaration of 2 imposes an unrestricted one; a predicate that only checked for "no declaration at all" would carry a verdict across a TS switch for a species that will never run on it. MEASUREMENT WIDENS TO EVERY RESTRICTED SPECIES. ADOPTION STAYS TS-ONLY. These are two decisions, and left alone the first would have made the second for free. Variationally E(UKS) <= E(RKS), with equality if and only if the restricted solution is stable. So for a stable closed-shell species the two references give the same number, and a stability analysis is the only thing that says whether holding a species restricted changed its energy at all; an already-unrestricted job is free to break spin symmetry and has nothing to learn from the test. That is why the measurement gate admits a RESTRICTED reference rather than testing multiplicity: job_scf_reference_is_restricted reads the optimization job's own restricted_used memo, which is what that input actually declared, whereas recomputing answers what the species would get today. `is True` and not truthiness, because the helper returns None for a job with no memo, so a pipe task is refused rather than admitted by accident. Force field, composite and semiempirical levels are excluded: is_species_restricted returns True for them before any other consideration and ARC writes no r/u prefix, so their flag is not a reference choice ARC made. A multi-species memo is a list, not a decision, and is refused. record_scf_reference had open-coded the same two exclusions and now calls this helper instead of carrying a second copy. Adoption is refused for a well, deliberately. Acting on a verdict means re-optimizing on the lower solution and running every job after it there, and the energy that produces is a broken-symmetry one: spin-contaminated and unprojected, so it still sits above the spin-pure energy of the state it is reported for. The blast radius of writing such a number differs in kind between the two cases. A TS's energy prices one barrier; a well's prices its own thermo and every reaction it appears in, through Arkane and through AEC/BAC corrections parameterised against the reference ARC normally picks. So a well is not moved onto a contaminated surface on the strength of a measurement of its reference alone, while a TS, which has no thermo of its own and whose remaining jobs' reference is the decision the analysis informs, is. Declaring number_of_radicals = 2 runs a well unrestricted from its first job, consistently -- the widened diagnostic is exactly what tells a user to do that. So "derived" stays a property of the verdict and "adopted" is the verdict ARC acts on, and adoption is a TS's undeclared verdict only. WHAT A WELL'S VERDICT IS FOR, GIVEN THAT IT WILL SAY 'stable'. This is not a hunt for instabilities. Well under a few per cent of closed-shell equilibrium geometries are RHF -> UHF unstable; a stretched partial bond at a saddle is where the instability lives. The diagnostic is worth its cost for what a 'stable' verdict LICENSES: a well verified stable has identical restricted and unrestricted energies, so a barrier or reaction energy taken between it and a TS that ARC has made unrestricted is a difference on one surface rather than a comparison across two. Second, it catches an undeclared singlet biradical, whose restricted energy is simply wrong and which nothing else in ARC detects. The docstrings say this, so that a long run of 'stable' verdicts is read as the diagnostic working rather than as it having nothing to do. open_shell_character_source reports 'declared' only ABOVE one. Zero and one attribute no open-shell character beyond the multiplicity -- is_species_restricted turns a declaration into an unrestricted reference only at 2 -- so naming them as the source contradicts what the function is for. They report None while declared_number_of_radicals still carries the value, so output.yml says both that nothing was attributed and that a declaration was nevertheless present, which is what blocked the measured verdict. is_restricted memoizes its decision on the job adapter as obj.restricted_used. Adapters call it while writing their input, so the memo is the reference that job's input actually declared. THE COMPOSITE EARLY RETURN IS ASSESSED, NOT CHANGED. is_species_restricted returns True for force_field, composite and semiempirical levels before any multiplicity check, which makes 'uCBS-QB3' unreachable through this path. A derived instability on a composite-method species is therefore ignored, and bypassing is deliberately not done here: it would change composite energies repo-wide, since Gaussian's CBS-QB3 already selects UHF internally above multiplicity 1 and forcing the prefix applies UHF to every step of a recipe whose extrapolation and empirical corrections are parameterised against the standard one. It would also be worst exactly here -- the stability job runs only at DFT or HF levels, so a composite-level species can carry a verdict only when its freq level is DFT while its sp level is composite, and bypassing would flip the reference of the run's most consequential energy on a diagnostic measured at a different level of theory. Pinned by a test so a later bypass is a deliberate act. WHAT AN ADOPTED ENERGY IS NOT. A broken-symmetry energy is not a spin eigenfunction: it mixes in the higher multiplicity, so it lies ABOVE the spin-pure low-spin energy, and the restricted energy it replaces lies above the broken-symmetry one in turn. The ordering is E_projected < E_BS < E_restricted, so an adoption is a step toward the spin-pure energy that stops short of it rather than a step past it. ARC projects nothing, so the residual error after an adoption is the contamination, not the reference, and it keeps the sign and direction it had. That is said in adopted_reference_is_unrestricted rather than left for a reader to infer from the absence of a claim. Two test fixtures were also corrected, and neither is a behaviour change: the Gaussian adapter helper built its species from a lone oxygen atom at multiplicity 1, i.e. singlet O, when O(3P) is the ground state, and the species round trip hung an external instability on ethane. Both are pure plumbing tests that never touch chemistry. They are water and ozone now -- the second being the textbook closed-shell singlet with genuine diradical character, which is the species the verdict under test would actually be measured on. Verified by mutation. Deleting the derived branch from is_species_restricted fails 3; ignoring the reference the verdict was measured on, 2; letting an internal instability flip the reference, 3; dropping the declaration guard from adopted_reference_is_unrestricted, 1; removing the is_restricted memo, 2, and renaming it, 2; dropping 'composite' from REFERENCE_AGNOSTIC_METHOD_TYPES, 3; crediting any declaration as the source, 1, and crediting a declared 1, 1; inverting the non-TS measurement admission, 3; deleting the non-TS branch, 2; requiring a restricted reference of a TS as well, 4; admitting anything not explicitly unrestricted, 2; reading a per-species list as one decision, 1; reading the reference under a name other than the memo's, 7; widening adoption to wells, 5; and dropping the is_ts term from adopted_reference_is_unrestricted, 1. One mutant SURVIVES and is left unpinned: replacing `job_scf_reference_is_restricted(job) is True` with plain truthiness. It is an equivalent mutant -- the helper's isinstance guard means its codomain is exactly {True, False, None} and the two spellings agree on every element of it. The `is True` is a guard against a future widening of that return type, and is documented as such rather than tested. REQUIRED AT MERGE WITH feature_gaussian_trsh_remedies, WHICH IS NOT EDITED HERE. That branch gates guess=mix in arc/job/adapters/gaussian.py on elif any(spc.multiplicity == 1 and spc.number_of_radicals is not None and spc.number_of_radicals > 1 for spc in self.species): It needs the derived term, or the derived verdict will change the u prefix without changing the guess keyword and the symmetry-broken SCF will have no broken guess to start from: elif any(spc.multiplicity == 1 and ((spc.number_of_radicals is not None and spc.number_of_radicals > 1) or adopted_reference_is_unrestricted(spc)) for spc in self.species): adding adopted_reference_is_unrestricted to that file's existing `from arc.job.adapters.common import (...)` block. No separate `number_of_radicals is None` guard is needed on the derived term: the predicate carries it, which is the point of having one predicate. It now also excludes a well, so a well cannot get a symmetry-broken guess for a reference ARC did not change. adopted_reference_is_unrestricted's docstring now says where the residual error lands, not only that it exists. Adoption acts for a TS only, so a TS whose restricted reference was unstable runs unrestricted while its reactants and products stay restricted; the adopted TS energy still sits above the spin-pure one while the wells, whose restricted references are stable, carry no such contamination, so the barrier is systematically OVERestimated by the residual contamination of the TS -- less so than the all-restricted barrier it replaces, which sat higher still. The direction is what a user meets, and it was the one thing the paragraph did not state. A VERDICT THE RUN'S ESSs CANNOT REACH IS REPORTED AND NEVER ACTED ON. A verdict carrying REFERENCE_CHANGE_AVAILABLE_KEY set to False is not one adopted_reference_is_unrestricted returns True for, so it decides no reference and is credited as no open-shell character source, while derived_reference_is_unrestricted still reports the measurement it holds. The key records whether every ESS the species' E0 is built from can be given a symmetry-breaking reference, which the scheduler decides when the verdict is recorded. species_may_read_previous_orbitals reports whether a job of a species may adopt an orbitals file the species itself does not hold. A species carrying an adopted verdict and no checkfile holds none deliberately, and the adapters read that answer before falling back to whatever sits in their own job directory. The derived_stability_verdict attribute is documented as one the run that measures it writes and a restart file reads back, like every other attribute, rather than as one no input can carry: number_of_radicals is the input that declares open-shell character. A DOUBLE HYBRID ADMITS NO BROKEN-SYMMETRY REFERENCE, and DOUBLE_HYBRID_METHODS is read before the method type because ARC types one as DFT. A double hybrid's energy is not its Kohn-Sham determinant's: a perturbative second-order correlation term is added to it, expanded about that determinant, which is the construction level_admits_a_broken_symmetry_reference already excludes the correlated wavefunction methods for. BROKEN_SYMMETRY_METHOD_TYPES = ['dft'] alone let B2PLYP, DSD-PBEP86 and wB97X-2 take a spin-broken reference that CCSD(T)-F12 is refused, and BS-MP2 about a spin-broken KS reference is the pathology the gate exists to prevent. Double hybrids are a normal sp_level choice in ARC, so the case is not hypothetical. The list is a deny-list rather than a classification of every functional: ARC has no double-hybrid predicate to reuse -- deduce_method_type in arc/level.py knows only composite, wavefunction, semiempirical, force field and DFT, and data/ess_methods.yml marks the group with a YAML comment whose grouping has since drifted, PW6B95 and MN15 sitting inside it. Names are matched with their hyphens and underscores dropped so a level written either way is recognized, and a double hybrid the list does not name is admitted as ordinary DFT. HF-3c IS ADMITTED, the mirror image of the same question. Its geometrical counterpoise, dispersion and short-range basis corrections are additive functions of the nuclear coordinates rather than of the wavefunction, so the level's energy is still the energy of its determinant plus a number the reference does not enter. It carries the 'wavefunction' method type and is not spelled 'hf', so the name list is what admits it. 'rhf' IS KEPT IN BROKEN_SYMMETRY_METHODS. Level(method='rhf', basis='cc-pvdz') raises IndexError in deduce_software only because rhf is registered for TeraChem alone while the wavefunction preferred-ESS order does not list TeraChem; Level(method='rhf', basis='cc-pvdz', software='terachem') builds and reaches this gate, so the entry is live rather than dead. --- arc/job/adapters/common.py | 340 +++++++++++++++++++++++++++++++- arc/job/adapters/common_test.py | 340 ++++++++++++++++++++++++++++++++ arc/species/species.py | 46 +++++ arc/species/species_test.py | 43 ++++ 4 files changed, 763 insertions(+), 6 deletions(-) diff --git a/arc/job/adapters/common.py b/arc/job/adapters/common.py index 43d567cddc..5d88bfebc4 100644 --- a/arc/job/adapters/common.py +++ b/arc/job/adapters/common.py @@ -27,6 +27,22 @@ default_job_settings, global_ess_settings, rotor_scan_resolution = \ settings['default_job_settings'], settings['global_ess_settings'], settings['rotor_scan_resolution'] +REFERENCE_AGNOSTIC_METHOD_TYPES = ['force_field', 'composite', 'semiempirical'] + +BROKEN_SYMMETRY_METHOD_TYPES = ['dft'] +BROKEN_SYMMETRY_METHODS = ['hf', 'hf3c', 'rhf', 'uhf', 'rohf'] +DOUBLE_HYBRID_METHODS = ['b2plyp', 'b2plypd', 'b2plypd3', 'b2plypd3bj', 'b2gpplyp', 'b2kplyp', 'b2tplyp', + 'mpw2plyp', 'mpw2plypd', 'wb2plyp', 'wb2gpplyp', + 'pbe0dh', 'pbe02', 'pbeqidh', 'pwpb95', 'ripwpb95', 'ptpss', + 'dsdblyp', 'dsdblypd3', 'dsdpbep86', 'dsdpbep86d3', 'dsdpbeb95', 'dsdpbeb95d3', + 'dsdpbepbe', 'dsdpbepbed3', 'revdsdpbep86', 'revdsdpbep86d3', 'revdsdpbeb95', + 'dodblyp', 'dodpbep86', 'dodpbeb95', + 'xyg3', 'xygjos', 'wb97x2', 'wb97m2'] + +DERIVED_UNRESTRICTED_VERDICT = 'external_instability' +SPIN_RELAXED_REFERENCE_PREFIX = 'U' +REFERENCE_CHANGE_AVAILABLE_KEY = 'reference_change_available' + ts_adapters_by_rmg_family = {'1+2_Cycloaddition': ['kinbot', 'goflow', 'rits', 'linear'], '1,2_Insertion_CO': ['kinbot', 'goflow', 'rits', 'linear'], '1,2_Insertion_carbene': ['kinbot', 'goflow', 'rits', 'linear'], @@ -163,7 +179,7 @@ def _initialize_adapter(obj: JobAdapter, obj.additional_job_info = None obj.args = args or dict() obj.bath_gas = bath_gas - obj.checkfile = checkfile + obj.checkfile = obj.readable_checkfile(checkfile) obj.conformer = conformer obj.constraints = constraints or list() obj.cpu_cores = cpu_cores @@ -316,6 +332,19 @@ def is_restricted(obj: JobAdapter) -> bool | list[bool]: Check whether a Job Adapter should be executed as restricted or unrestricted. If the job adapter contains a list of species, return True or False per species. + The decision is also memoized on the job adapter as ``obj.restricted_used``, in the + same shape it is returned in. Adapters call this while writing their input file, so + the memo is the reference that job's input actually declared, and it is rewritten only + when that input is rewritten. A consumer that recomputes the decision instead reports + the reference the species would get today, which for a job that has already run is not + the same question. + + The memo is written to the restart file by ``JobAdapter.as_dict()`` and restored by + ``Scheduler.restore_running_jobs()`` after the adapter is rebuilt, because rebuilding + it re-composes the input file and so calls this function again: without the restore, a + job that was queued before a reference decision changed would come back from a restart + carrying the reference it would be given now rather than the one it is running with. + Args: obj: The job adapter object. @@ -323,9 +352,282 @@ def is_restricted(obj: JobAdapter) -> bool | list[bool]: bool | list[bool]: Whether to run as restricted (``True``) or not (``False``). """ if not obj.run_multi_species: - return is_species_restricted(obj) + restricted = is_species_restricted(obj) else: - return [is_species_restricted(obj, species) for species in obj.species] + restricted = [is_species_restricted(obj, species) for species in obj.species] + obj.restricted_used = restricted + return restricted + + +def job_scf_reference_is_restricted(obj: JobAdapter) -> bool | None: + """ + Report the SCF reference a job declared in the input it ran, or ``None`` where it declared none. + + The value is read off the job adapter's ``restricted_used`` memo, which ``is_restricted()`` + writes while the input is being composed, so it is the reference that job actually ran with + rather than the one the species would be given today. ``None`` is returned for a job carrying + no memo, a pipe task among them, for a multi-species job, whose memo is a decision per species + rather than a single one, and for the force field, composite and semiempirical method types, + for which ARC writes no reference prefix and whose flag is therefore not a reference choice + ARC made. + + Args: + obj: The job adapter object. + + Returns: + bool | None: Whether the job declared a restricted reference, or ``None`` if it declared none. + """ + restricted = getattr(obj, 'restricted_used', None) + if not isinstance(restricted, bool): + return None + level = getattr(obj, 'level', None) + if level is None or level.method_type in REFERENCE_AGNOSTIC_METHOD_TYPES: + return None + return restricted + + +def level_admits_a_broken_symmetry_reference(level: Level | None) -> bool: + """ + Check whether a broken-symmetry SCF reference describes what a level computes. + + A level whose energy IS the energy of its SCF determinant admits one. The determinant is the + whole description there, so relaxing its spin symmetry onto the lower solution lowers the + number the level reports, and a broken-symmetry determinant is the standard single-reference + description of a species whose restricted determinant is not the ground state. Density + functional theory and Hartree-Fock are those levels, which + ``BROKEN_SYMMETRY_METHOD_TYPES`` and ``BROKEN_SYMMETRY_METHODS`` name between them: the + Hartree-Fock methods carry the ``'wavefunction'`` method type they share with the correlated + methods, so the method type alone does not separate them and the method name is read as well. + ``HF-3c`` is one of them. Its corrections - a geometrical counterpoise term, a dispersion term + and a short-range basis term - are additive functions of the nuclear coordinates rather than + of the wavefunction, so the level's energy is still the energy of its determinant plus a + number the reference does not enter. + + A CORRELATED WAVEFUNCTION METHOD DOES NOT ADMIT ONE. Its SCF determinant is the zeroth-order + reference a correlation expansion is built about rather than the answer, and the expansion is + parameterized about a spin-adapted reference. Breaking the symmetry of that reference lowers + the SCF energy and RAISES the correlated one, because the symmetry-broken orbitals absorb + into themselves the static correlation the expansion would otherwise recover, leaving less of + it for the expansion to find. It also suppresses the ``T1`` diagnostic ARC reads off a coupled + cluster single point, whose purpose is to report a reference the expansion is a poor + description about: on a broken-symmetry reference ``T1`` falls below the threshold at which + ARC reports multireference character, so the character the stability analysis measured is left + both uncorrected and unreported. + + A DOUBLE HYBRID DOES NOT ADMIT ONE EITHER, and ``DOUBLE_HYBRID_METHODS`` is read before the + method type because ARC types a double hybrid as density functional theory. Its energy is not + the energy of its Kohn-Sham determinant: a perturbative second-order correlation term is added + to it, expanded about that determinant, which is the construction the correlated methods are + excluded for. The names are matched with their hyphens and underscores dropped, so a level + written either way is recognized, and the list is a deny-list rather than a classification of + every functional, so a double hybrid it does not name is admitted as ordinary density + functional theory. + + A reference-agnostic level, one ARC writes no reference prefix for at all, admits nothing to + change and is reported here as admitting no broken-symmetry reference. + + Args: + level (Level, optional): The level of theory to check. + + Returns: + bool: Whether a broken-symmetry reference describes what the level computes. + """ + if level is None: + return False + method = (level.method or '').lower().replace('-', '').replace('_', '') + if method in DOUBLE_HYBRID_METHODS: + return False + return level.method_type in BROKEN_SYMMETRY_METHOD_TYPES \ + or method in BROKEN_SYMMETRY_METHODS + + +def derived_reference_is_unrestricted(species: ARCSpecies | None) -> bool: + """ + Check whether a species' measured wavefunction-stability verdict calls for an unrestricted reference. + + Only an external instability of a restricted reference does. An external instability is + a relaxation of a constraint the reference imposes, Gaussian's RHF -> UHF class, so a + lower solution exists outside the spin symmetry the restricted reference holds the + wavefunction in and that reference is not the ground state. An internal instability lies + within the reference's own spin symmetry, so it is not evidence of broken-symmetry + character and does not call for a different reference. A ``'stable'`` verdict, an + ``'unknown'`` one, an absent verdict, and a verdict whose reference could not be read all + return ``False``. + + Args: + species (ARCSpecies, optional): The species to check. + + Returns: + bool: Whether the measured verdict calls for an unrestricted reference. + """ + verdict = getattr(species, 'derived_stability_verdict', None) + if not isinstance(verdict, dict): + return False + return verdict.get('verdict') == DERIVED_UNRESTRICTED_VERDICT and verdict.get('restricted') is True + + +def derived_instability_breaks_spin_symmetry(species: ARCSpecies | None) -> bool | None: + """ + Report whether a measured instability relaxed the SPIN constraint, or ``None`` where it says nothing. + + An external instability names the constraint it relaxed, which an ESS reports as a pair of + reference labels and which the parsers store on the verdict as ``relaxations``. Only a + relaxation whose target reference is an unrestricted one, the RHF -> UHF class and its + RKS -> UKS equivalent, is evidence of broken-symmetry character: the two electrons of a pair + occupy different spatial orbitals in the lower solution, which is what a symmetry-broken real + determinant describes. A relaxation to a COMPLEX reference, which Gaussian reports as + RHF -> CRHF, relaxes the reality of the orbitals rather than the pairing of the spins, and the + lower solution it points to is a complex one that no real determinant reaches, symmetry-broken + or otherwise. Forcing an unpaired real determinant onto such a species describes neither the + restricted solution nor the complex one it is being compared against. + + ``None`` is returned for a verdict naming no relaxation, which is any verdict that is not an + external instability and any verdict reduced to the reference decision it carries, so a caller + acting on the relaxation can tell "relaxed something other than spin" from "does not say". + + Args: + species (ARCSpecies, optional): The species to check. + + Returns: bool | None + Whether the relaxations the verdict names include a spin relaxation. + """ + verdict = getattr(species, 'derived_stability_verdict', None) + relaxations = verdict.get('relaxations') if isinstance(verdict, dict) else None + if not relaxations: + return None + return any(str(relaxation).split('->')[-1].strip().upper().startswith(SPIN_RELAXED_REFERENCE_PREFIX) + for relaxation in relaxations) + + +def adopted_reference_is_unrestricted(species: ARCSpecies | None) -> bool: + """ + Check whether a species' measured stability verdict is one ARC acts on, and not only reports. + + ARC acts on a verdict for a transition state only. The analysis is run for any species whose + tested reference was restricted, and acting on it means re-optimizing the species on the lower + solution and running every job that follows there. The energy that produces is a + broken-symmetry one, spin-contaminated and unprojected, so adopting a verdict for a well would + write a contaminated energy into that species' thermo and into every reaction the species + appears in, on the strength of a measurement of the reference alone. A transition state has no + thermo of its own, and the reference of its remaining jobs is the decision the analysis + informs. A well whose verdict is not adopted is reported instead, and declaring + ``number_of_radicals`` for it runs its optimization, frequency and single point unrestricted + together. + + A declared ``number_of_radicals`` of any value blocks adoption, since ``is_species_restricted`` + decides from the declared value alone whenever there is one, so a verdict measured alongside a + declaration is reported and never acted on. + + A verdict naming the constraints it relaxed, none of which is the spin constraint, is reported + and never acted on. Gaussian's ``RHF -> CRHF`` is such a verdict: it relaxes the reality of the + orbitals rather than the pairing of the spins, and the lower solution it points at is a complex + one that no real determinant reaches, symmetry-broken or otherwise, so running the species + unrestricted describes neither the restricted solution nor the one it is being compared + against. ``derived_instability_breaks_spin_symmetry`` reports that, and its ``None``, a verdict + naming no relaxation at all, does not block adoption. + + A verdict carrying ``REFERENCE_CHANGE_AVAILABLE_KEY`` set to ``False`` is reported and never + acted on either. That key records whether the ESSs that run this species' geometry, its + Hessian and its electronic energy can each be given a symmetry-breaking reference, which + ``Scheduler.stability_verdict_can_be_honoured`` decides when the verdict is recorded. An + unrestricted reference an ESS cannot break the spin symmetry of collapses back to the + restricted solution the verdict rejected, so acting on the verdict there would move the + geometry onto the broken-symmetry surface while leaving the energy on the restricted one, and + the number the run publishes would belong to neither. A verdict carrying the key set to + ``True``, and one carrying no such key at all, is adopted on the strength of the measurement + alone. + + The energy an adopted verdict produces, where the single point runs at one of the levels the + verdict decides and which ``level_admits_a_broken_symmetry_reference`` defines, is a + broken-symmetry one: it is spin-contaminated and it + is not projected here. A broken-symmetry determinant mixes in the higher multiplicity, so its + energy lies ABOVE the spin-pure low-spin energy, and the restricted energy it replaces lies + above the broken-symmetry one in turn: E_projected < E_BS < E_restricted. Adoption therefore + moves the energy toward the spin-pure value without reaching it, and what remains is a + residual of the same sign rather than an overshoot. ``arc/checks/spin.py`` holds the Yamaguchi + approximate spin-projection arithmetic that estimates E_projected from the broken-symmetry and + high-spin energies and their ``S**2`` values; the residual error after adoption is the + contamination, not the reference. + + WHERE THAT ERROR LANDS. Adoption acts for a transition state only, so a TS whose restricted + reference was unstable runs unrestricted while the reactants and products it is compared + against stay restricted. The adopted TS energy still sits above the spin-pure one while the + wells, whose restricted references are stable and carry no such contamination, do not, so the + barrier the run reports is systematically OVERestimated, by the residual contamination of the + TS alone. Adoption shrinks that overestimate without removing it: the restricted TS energy it + replaces sat higher still. The bias is one-sided because the asymmetry is: nothing projects it + out and nothing raises the wells to match. + + Args: + species (ARCSpecies, optional): The species to check. + + Returns: + bool: Whether the measured verdict decides this species' reference. + """ + verdict = getattr(species, 'derived_stability_verdict', None) + if isinstance(verdict, dict) and verdict.get(REFERENCE_CHANGE_AVAILABLE_KEY) is False: + return False + if derived_instability_breaks_spin_symmetry(species) is False: + return False + return (getattr(species, 'number_of_radicals', None) is None + and derived_reference_is_unrestricted(species) + and bool(getattr(species, 'is_ts', False))) + + +def species_may_read_previous_orbitals(species: ARCSpecies | None) -> bool: + """ + Check whether a job of this species may start from orbitals the species does not hold. + + Every adapter that reads an orbital guess takes it from the species, and falls back to + whatever orbitals file sits in its own job directory where the species holds none. A + species carrying an adopted wavefunction-stability verdict and no checkfile is holding + none deliberately: the orbitals it dropped describe the restricted reference the verdict + rejected, and an unrestricted SCF seeded from them returns to that solution, since a + restricted solution is a stationary point of the unrestricted equations too. The job + directory of a job whose name a previous job of the same species already carried holds + exactly such a file, so the fallback is refused for as long as the species holds no + orbitals of the reference it adopted, and the job composes the symmetry-breaking + directive that reaches the lower solution instead. + + Args: + species (ARCSpecies, optional): The species to check. + + Returns: + bool: Whether a job of this species may adopt an orbitals file the species does not hold. + """ + return not (adopted_reference_is_unrestricted(species) and getattr(species, 'checkfile', None) is None) + + +def open_shell_character_source(species: ARCSpecies | None) -> str | None: + """ + Report which source attributed open-shell character to a species beyond its spin multiplicity. + + Returns ``'declared'`` when the user declared a ``number_of_radicals`` greater than one, + which is the only declaration that attributes open-shell character beyond the multiplicity + and which always wins over a measured verdict; ``'derived'`` when the user declared nothing + and a measured wavefunction-stability verdict ARC acts on calls for an unrestricted + reference; and ``None`` when neither applies, in which case the spin multiplicity alone + decides the reference. + + A declared ``number_of_radicals`` of zero or one is not a source: ``is_species_restricted`` + turns a declaration into an unrestricted reference only above one, so such a declaration + attributes no open-shell character. It still blocks a measured verdict from being adopted, + which is why it does not fall through to ``'derived'`` either. A verdict ARC reports without + acting on it, which is any verdict measured for a species that is not a transition state, + likewise decides nothing and is not credited as the source. + + Args: + species (ARCSpecies, optional): The species to check. + + Returns: str | None + ``'declared'``, ``'derived'``, or ``None``. + """ + number_of_radicals = getattr(species, 'number_of_radicals', None) + if number_of_radicals is not None: + return 'declared' if number_of_radicals > 1 else None + if adopted_reference_is_unrestricted(species): + return 'derived' + return None def is_species_restricted(obj: JobAdapter, @@ -334,6 +636,20 @@ def is_species_restricted(obj: JobAdapter, """ Check whether a species should be executed as restricted or unrestricted. + A user-declared ``number_of_radicals`` always decides. Only when the user declared + nothing does a measured wavefunction-stability verdict enter, and then only an external + instability of a restricted reference measured for a transition state, which makes the + species unrestricted. That precedence is written once, in + ``adopted_reference_is_unrestricted``, and is not restated here. + + An adopted verdict decides the reference of the levels a broken-symmetry reference describes, + which ``level_admits_a_broken_symmetry_reference`` defines: the geometry and the Hessian of an + adopted species come from the lower solution, and its correlated single point keeps the + spin-adapted reference its correlation expansion is built about. The spin multiplicity and a + declared ``number_of_radicals`` are not gated on the level and decide every level alike, so an + open-shell species runs unrestricted at a correlated level as it always has; what the level + decides is only whether a MEASURED verdict is what breaks the symmetry. + Args: obj: The job adapter object. species (ARCSpecies, optional): The species to check. @@ -342,12 +658,13 @@ def is_species_restricted(obj: JobAdapter, bool: Whether to run as restricted (``True``) or not (``False``). """ - if obj.level.method_type in ['force_field', 'composite', 'semiempirical']: + if obj.level.method_type in REFERENCE_AGNOSTIC_METHOD_TYPES: return True multiplicity = obj.multiplicity if species is None else species.multiplicity - number_of_radicals = obj.species[0].number_of_radicals if species is None else species.number_of_radicals - species_label = obj.species[0].label if species is None else species.label + species_obj = obj.species[0] if species is None else species + number_of_radicals = species_obj.number_of_radicals + species_label = species_obj.label if multiplicity > 1 or (number_of_radicals is not None and number_of_radicals > 1): # run an unrestricted electronic structure calculation if the spin multiplicity is greater than one, # or if it is one but the number of radicals is greater than one (e.g., bi-rad singlet) @@ -357,6 +674,17 @@ def is_species_restricted(obj: JobAdapter, logger.info(f'Using an unrestricted method for species {species_label} which has ' f'{number_of_radicals} radicals and multiplicity {multiplicity}.') return False + if adopted_reference_is_unrestricted(species_obj): + if not level_admits_a_broken_symmetry_reference(obj.level): + logger.info(f'Composing a restricted reference for the {obj.job_type} job of species {species_label} ' + f'at {obj.level}, whose wavefunction stability analysis was adopted: that level reports a ' + f'correlation energy expanded about its SCF determinant rather than the energy of the ' + f'determinant itself, so a broken-symmetry reference does not describe what it computes.') + return True + logger.info(f'Using an unrestricted method for species {species_label}, whose wavefunction stability ' + f'analysis reported an external instability of its restricted reference and for which no ' + f'number_of_radicals was declared.') + return False return True diff --git a/arc/job/adapters/common_test.py b/arc/job/adapters/common_test.py index 56176b16bd..e4eb970056 100644 --- a/arc/job/adapters/common_test.py +++ b/arc/job/adapters/common_test.py @@ -9,6 +9,8 @@ import tempfile import unittest +from types import SimpleNamespace + import arc.job.adapters.common as common from arc.job.adapters.gaussian import GaussianAdapter from arc.job.adapters.molpro import MolproAdapter @@ -78,6 +80,344 @@ def test_is_restricted(self): benchmark_list = [False, True] self.assertEqual(common.is_restricted(self.job_multi),benchmark_list) + WATER_XYZ = """O 0.00000000 0.00000000 0.11815400 +H 0.00000000 0.76336400 -0.47261500 +H 0.00000000 -0.76336400 -0.47261500""" + + def _singlet_job(self, number_of_radicals=None, method='wb97xd', multiplicity=1, is_ts=False): + """Build a Gaussian adapter whose species is restricted unless something else says otherwise.""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=multiplicity, + number_of_radicals=number_of_radicals) + species.is_ts = is_ts + project_directory = tempfile.mkdtemp(prefix='arc_test_common_') + self.addCleanup(shutil.rmtree, project_directory, ignore_errors=True) + return GaussianAdapter(execution_type='incore', + job_type='sp', + level=Level(method=method, basis='def2tzvp'), + project='test', + project_directory=project_directory, + species=[species], + testing=True, + ) + + def test_a_derived_external_instability_makes_a_silent_ts_unrestricted(self): + """Test that a measured external instability flips the reference when the user declared nothing""" + job = self._singlet_job(is_ts=True) + self.assertTrue(common.is_species_restricted(job)) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertFalse(common.is_species_restricted(job)) + + def test_a_derived_external_instability_does_not_flip_a_well(self): + """Test that a species that is not a TS keeps its reference under a measured external instability""" + job = self._singlet_job() + self.assertFalse(job.species[0].is_ts) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.is_species_restricted(job)) + self.assertTrue(common.derived_reference_is_unrestricted(job.species[0])) + self.assertFalse(common.adopted_reference_is_unrestricted(job.species[0])) + + def test_an_internal_instability_does_not_flip_the_reference(self): + """Test that only an external instability of a restricted reference makes a species unrestricted""" + job = self._singlet_job(is_ts=True) + for verdict in [{'verdict': 'internal_instability', 'restricted': True}, + {'verdict': 'stable', 'restricted': True}, + {'verdict': 'unknown', 'restricted': None}, + {'verdict': 'external_instability', 'restricted': None}, + {'verdict': 'external_instability', 'restricted': False}, + None, + ]: + job.species[0].derived_stability_verdict = verdict + self.assertTrue(common.is_species_restricted(job), + msg=f'{verdict} should not have made the species unrestricted') + + def test_a_spin_relaxation_is_told_from_another_external_one(self): + """Test that only a relaxation to an unrestricted reference reports broken spin symmetry""" + species = ARCSpecies(label='spc', xyz=self.WATER_XYZ, multiplicity=1) + for relaxations, expected in [(['RHF -> UHF'], True), + (['RKS -> UKS'], True), + (['rhf -> uhf'], True), + (['RHF->UHF'], True), + (['RHF -> CRHF'], False), + (['RHF -> CRHF', 'RHF -> UHF'], True), + (['RHF -> CUHF'], False), + (list(), None), + (None, None), + ]: + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'relaxations': relaxations} + self.assertEqual(common.derived_instability_breaks_spin_symmetry(species), expected, + msg=f'the relaxations {relaxations} were not read as {expected}') + + def test_a_verdict_naming_no_relaxation_reports_nothing(self): + """Test that a verdict without relaxations is unknown rather than negative""" + species = ARCSpecies(label='spc', xyz=self.WATER_XYZ, multiplicity=1) + for verdict in [None, dict(), {'verdict': 'stable', 'restricted': True}, 'external_instability']: + species.derived_stability_verdict = verdict + self.assertIsNone(common.derived_instability_breaks_spin_symmetry(species), + msg=f'the verdict {verdict} reported a relaxation') + self.assertIsNone(common.derived_instability_breaks_spin_symmetry(None)) + + def test_a_declared_number_of_radicals_wins_over_a_contradicting_verdict(self): + """Test that a declared closed-shell character is not overridden by a measured instability""" + job = self._singlet_job(number_of_radicals=1, is_ts=True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.is_species_restricted(job)) + + def test_a_declared_biradical_stays_unrestricted_under_a_stable_verdict(self): + """Test that a declared biradical singlet is not made restricted by a stable verdict""" + job = self._singlet_job(number_of_radicals=2) + job.species[0].derived_stability_verdict = {'verdict': 'stable', 'restricted': True} + self.assertFalse(common.is_species_restricted(job)) + + def test_a_derived_verdict_is_read_off_the_species_that_was_passed(self): + """Test that the per-species entry point consults the species it was given, not the job's first""" + job = self._singlet_job() + other = ARCSpecies(label='spc2', xyz=self.WATER_XYZ, multiplicity=1) + other.is_ts = True + other.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.is_species_restricted(job)) + self.assertFalse(common.is_species_restricted(job, other)) + + def test_a_composite_level_ignores_a_derived_verdict(self): + """Test that the composite early return still short-circuits every other consideration""" + job = self._singlet_job(method='cbs-qb3', is_ts=True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertEqual(job.level.method_type, 'composite') + self.assertTrue(common.is_species_restricted(job)) + + def test_a_correlated_single_point_is_not_flipped_by_an_adopted_verdict(self): + """Test that an adopted verdict decides no reference for a correlated wavefunction level""" + for method in ['dlpno-ccsd(t)', 'ccsd(t)-f12', 'ccsd(t)', 'mp2']: + job = self._singlet_job(method=method, is_ts=True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.adopted_reference_is_unrestricted(job.species[0])) + self.assertEqual(job.level.method_type, 'wavefunction') + self.assertTrue(common.is_species_restricted(job), + msg=f'an adopted verdict flipped the reference of a {method} single point') + + def test_an_adopted_verdict_flips_the_levels_a_broken_symmetry_reference_describes(self): + """Test that a DFT and a Hartree-Fock job of an adopted species run unrestricted""" + for method in ['wb97xd', 'b3lyp', 'hf']: + job = self._singlet_job(method=method, is_ts=True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertFalse(common.is_species_restricted(job), + msg=f'an adopted verdict did not flip a {method} job') + + def test_a_correlated_level_keeping_its_reference_is_reported(self): + """Test that a job keeping its reference under an adopted verdict says so""" + job = self._singlet_job(method='dlpno-ccsd(t)', is_ts=True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + with self.assertLogs(logger='arc', level='INFO') as captured: + restricted = common.is_species_restricted(job) + self.assertTrue(restricted) + message = ' '.join(captured.output) + self.assertIn('spc1', message) + self.assertIn('dlpno-ccsd(t)', message) + self.assertIn('restricted reference', message) + + def test_the_level_decides_only_whether_a_measured_verdict_is_acted_on(self): + """Test that a multiplicity and a declaration make a correlated level unrestricted as before""" + triplet = self._singlet_job(method='dlpno-ccsd(t)', multiplicity=3) + self.assertFalse(common.is_species_restricted(triplet)) + biradical = self._singlet_job(method='dlpno-ccsd(t)', number_of_radicals=2) + self.assertFalse(common.is_species_restricted(biradical)) + + def test_level_admits_a_broken_symmetry_reference(self): + """Test which levels a measured wavefunction-stability verdict decides the reference of""" + for method, expected in [('wb97xd', True), ('b3lyp', True), ('m06-hf', True), ('hf', True), + ('rhf', True), ('uhf', True), ('rohf', True), ('ccsd(t)', False), + ('dlpno-ccsd(t)', False), ('ccsd(t)-f12', False), ('mp2', False), + ('casscf', False), ('cbs-qb3', False), ('am1', False), ('gfn2-xtb', False)]: + level = Level(method=method, software='gaussian') + self.assertEqual(common.level_admits_a_broken_symmetry_reference(level), expected, + msg=f'{method} was not read as {expected}') + self.assertFalse(common.level_admits_a_broken_symmetry_reference(None)) + for method_type in common.REFERENCE_AGNOSTIC_METHOD_TYPES: + self.assertNotIn(method_type, common.BROKEN_SYMMETRY_METHOD_TYPES) + + def test_a_double_hybrid_admits_no_broken_symmetry_reference(self): + """Test that a double hybrid is refused although ARC types it as DFT""" + for method in ['b2plyp', 'b2plypd3', 'b2plyp-d3', 'mpw2plyp', 'pbe0dh', 'pbeqidh', 'dsdpbep86', + 'DSD-PBEP86', 'DSD-PBEPBE-D3', 'wb97x-2', 'xyg3', 'pwpb95']: + level = Level(method=method, software='gaussian') + self.assertEqual(level.method_type, 'dft', msg=f'{method} was not typed as DFT') + self.assertFalse(common.level_admits_a_broken_symmetry_reference(level), + msg=f'the double hybrid {method} was admitted') + for method in ['b3lyp', 'wb97xd', 'wb97x-d', 'm062x', 'wb97m-v', 'b97-d3', 'pbe0']: + level = Level(method=method, software='gaussian') + self.assertTrue(common.level_admits_a_broken_symmetry_reference(level), + msg=f'the functional {method} was refused') + + def test_hf_3c_admits_a_broken_symmetry_reference(self): + """Test that HF-3c is read as Hartree-Fock, its corrections not entering the wavefunction""" + for method in ['hf-3c', 'HF-3c', 'hf3c']: + level = Level(method=method, software='orca') + self.assertTrue(common.level_admits_a_broken_symmetry_reference(level), + msg=f'{method} was refused') + + def test_derived_reference_is_unrestricted(self): + """Test that only an external instability of a restricted reference reads as unrestricted""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + self.assertFalse(common.derived_reference_is_unrestricted(species)) + self.assertFalse(common.derived_reference_is_unrestricted(None)) + species.derived_stability_verdict = 'external_instability' + self.assertFalse(common.derived_reference_is_unrestricted(species)) + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.derived_reference_is_unrestricted(species)) + species.derived_stability_verdict = {'verdict': 'internal_instability', 'restricted': True} + self.assertFalse(common.derived_reference_is_unrestricted(species)) + + def test_adopted_reference_is_unrestricted(self): + """Test that a verdict is acted on for a transition state and reported only for anything else""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertFalse(common.adopted_reference_is_unrestricted(species)) + species.is_ts = True + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + species.derived_stability_verdict = {'verdict': 'internal_instability', 'restricted': True} + self.assertFalse(common.adopted_reference_is_unrestricted(species)) + self.assertFalse(common.adopted_reference_is_unrestricted(None)) + + def test_a_verdict_no_ess_can_reach_is_not_one_arc_acts_on(self): + """Test that a verdict stamped as unreachable is reported and decides nothing""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.is_ts = True + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + species.derived_stability_verdict[common.REFERENCE_CHANGE_AVAILABLE_KEY] = True + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + species.derived_stability_verdict[common.REFERENCE_CHANGE_AVAILABLE_KEY] = False + self.assertFalse(common.adopted_reference_is_unrestricted(species)) + self.assertTrue(common.derived_reference_is_unrestricted(species)) + self.assertIsNone(common.open_shell_character_source(species)) + + def test_a_relaxation_that_is_not_the_spin_one_is_not_acted_on(self): + """Test that an instability relaxing the reality of the orbitals decides no reference""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.is_ts = True + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'relaxations': ['RHF -> CRHF']} + self.assertIs(common.derived_instability_breaks_spin_symmetry(species), False) + self.assertFalse(common.adopted_reference_is_unrestricted(species)) + self.assertTrue(common.derived_reference_is_unrestricted(species)) + species.derived_stability_verdict['relaxations'] = ['RHF -> CRHF', 'RHF -> UHF'] + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + species.derived_stability_verdict['relaxations'] = [] + self.assertIsNone(common.derived_instability_breaks_spin_symmetry(species)) + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + + def test_species_may_read_previous_orbitals(self): + """Test that a species holding no orbitals of the reference it adopted reads none""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + self.assertTrue(common.species_may_read_previous_orbitals(species)) + species.is_ts = True + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertFalse(common.species_may_read_previous_orbitals(species)) + species.checkfile = 'a path the species holds' + self.assertTrue(common.species_may_read_previous_orbitals(species)) + species.checkfile = None + species.derived_stability_verdict = {'verdict': 'stable', 'restricted': True} + self.assertTrue(common.species_may_read_previous_orbitals(species)) + + def test_a_declared_number_of_radicals_blocks_the_adoption_of_a_ts_verdict(self): + """Test that a declaration of any value stops a TS verdict from being one ARC acts on""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.is_ts = True + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + for number_of_radicals in [0, 1, 2, 3]: + species.number_of_radicals = number_of_radicals + self.assertFalse(common.adopted_reference_is_unrestricted(species), + msg=f'number_of_radicals = {number_of_radicals} did not block the adoption') + species.number_of_radicals = None + self.assertTrue(common.adopted_reference_is_unrestricted(species)) + + def test_the_reference_memo_round_trips_through_a_restart(self): + """Test that a job's SCF reference is persisted rather than recomputed on restore""" + job = self._singlet_job(is_ts=True) + self.assertTrue(common.is_restricted(job)) + job_dict = job.as_dict() + self.assertIs(job_dict['restricted_used'], True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertFalse(common.is_restricted(job)) + self.assertIs(job.as_dict()['restricted_used'], False) + piped = SimpleNamespace(level=Level(method='wb97xd', basis='def2tzvp')) + self.assertIsNone(common.job_scf_reference_is_restricted(piped)) + + def test_an_unadopted_well_verdict_is_credited_to_no_source(self): + """Test that a verdict ARC reports without acting on it is not named as the deciding source""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertIsNone(common.open_shell_character_source(species)) + species.is_ts = True + self.assertEqual(common.open_shell_character_source(species), 'derived') + + def test_job_scf_reference_is_restricted_reads_the_memo(self): + """Test that the reference reported is the one the job's own memo holds""" + job = self._singlet_job() + self.assertTrue(common.is_restricted(job)) + self.assertIs(common.job_scf_reference_is_restricted(job), True) + triplet = self._singlet_job(multiplicity=3) + common.is_restricted(triplet) + self.assertIs(common.job_scf_reference_is_restricted(triplet), False) + piped = SimpleNamespace(level=Level(method='wb97xd', basis='def2tzvp')) + self.assertIsNone(common.job_scf_reference_is_restricted(piped)) + + def test_job_scf_reference_is_restricted_declines_a_reference_agnostic_level(self): + """Test that a level ARC writes no r/u prefix for reports no reference""" + for method in ['cbs-qb3', 'am1', 'mmff94s']: + job = self._singlet_job(method=method) + common.is_restricted(job) + self.assertIn(job.level.method_type, ['force_field', 'composite', 'semiempirical']) + self.assertIsNone(common.job_scf_reference_is_restricted(job), + msg=f'{method} reported a reference') + + def test_job_scf_reference_is_restricted_declines_a_multi_species_memo(self): + """Test that a per-species memo is not read as a single decision""" + self.assertEqual(common.is_restricted(self.job_multi), [False, True]) + self.assertIsNone(common.job_scf_reference_is_restricted(self.job_multi)) + + def test_open_shell_character_source(self): + """Test that only a declaration that attributes open-shell character is named as the source""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.is_ts = True + self.assertIsNone(common.open_shell_character_source(species)) + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertEqual(common.open_shell_character_source(species), 'derived') + species.number_of_radicals = 2 + self.assertEqual(common.open_shell_character_source(species), 'declared') + species.derived_stability_verdict = None + self.assertEqual(common.open_shell_character_source(species), 'declared') + + def test_a_declaration_that_attributes_no_open_shell_character_is_not_a_source(self): + """Test that a declared 0 or 1 blocks the verdict without being credited with the decision""" + species = ARCSpecies(label='spc1', xyz=self.WATER_XYZ, multiplicity=1) + species.is_ts = True + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + for number_of_radicals in [0, 1]: + species.number_of_radicals = number_of_radicals + self.assertIsNone(common.open_shell_character_source(species), + msg=f'number_of_radicals = {number_of_radicals} was named as the source') + self.assertFalse(common.adopted_reference_is_unrestricted(species), + msg=f'number_of_radicals = {number_of_radicals} did not block the adoption') + self.assertTrue(common.derived_reference_is_unrestricted(species)) + + def test_is_restricted_memoizes_the_decision_it_made(self): + """Test that the reference a job's input declared stays readable off the job afterwards""" + job = self._singlet_job(is_ts=True) + self.assertTrue(common.is_restricted(job)) + self.assertIs(job.restricted_used, True) + job.species[0].derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertIs(job.restricted_used, True) + self.assertFalse(common.is_restricted(job)) + self.assertIs(job.restricted_used, False) + self.assertEqual(common.is_restricted(self.job_multi), [False, True]) + self.assertEqual(self.job_multi.restricted_used, [False, True]) + + def test_reference_agnostic_method_types(self): + """Test the method types whose reference ARC does not prefix""" + self.assertEqual(common.REFERENCE_AGNOSTIC_METHOD_TYPES, ['force_field', 'composite', 'semiempirical']) + def test_check_argument_consistency(self): """Test the check_argument_consistency() function""" common.check_argument_consistency(self.job_1) diff --git a/arc/species/species.py b/arc/species/species.py index 7bc636ce25..3dae4e4051 100644 --- a/arc/species/species.py +++ b/arc/species/species.py @@ -212,6 +212,28 @@ class ARCSpecies(object): Defaults to None. Important, e.g., if a Species is a bi-rad singlet, in which case the job should be unrestricted, but the multiplicity does not have the required information to make that decision (r vs. u). + derived_stability_verdict (dict): The structured verdict of a wavefunction stability analysis, as parsed from + the ESS log. Defaults to None. It is a measured property of one SCF + solution, so it steers only the r vs. u reference decision and never the + molecular graph perception that number_of_radicals feeds, and a declared + number_of_radicals overrides it. It is written by the run that measures it + and read back from a restart file like every other attribute, so a value + placed there by hand is read the same way: number_of_radicals is the input + that declares open-shell character. + scf_references (dict): Which SCF reference each of this species' jobs declared in the input it ran, keyed by + job type ('sp', 'freq') with values 'restricted' or 'unrestricted'. Two different + values mean the electronic energy and the ZPE were computed on different surfaces. + stability_analysis_ran (bool): Whether a wavefunction stability analysis was spawned for this species. + Defaults to False. One analysis is run per species, and this attribute is + what says so across a restart, when the job dictionary holds only the jobs + that were still running. + stability_pending_opt_job (str): The name of the optimization job whose frequency, single point and IRC are + waiting for a wavefunction stability verdict. Defaults to None, and is + cleared once that work is released or the geometry is abandoned. + stability_reoptimized (bool): Whether an adopted wavefunction stability verdict has already re-optimized this + species on an unrestricted reference. Defaults to False. At most one such + re-optimization is run per species, and this attribute is what holds that + across a restart. e_elect (float): The total electronic energy (without ZPE) at the chosen sp level, in kJ/mol. e0 (float): The 0 Kelvin energy (total electronic energy plus ZPE) at the chosen sp level, in kJ/mol. is_ts (bool): Whether the species represents a transition state. `True` if it does. @@ -388,6 +410,11 @@ def __init__(self, self.chosen_ts = None self.rxn_zone_atom_indices = None self.ts_checks = dict() + self.derived_stability_verdict = None + self.scf_references = dict() + self.stability_analysis_ran = False + self.stability_pending_opt_job = None + self.stability_reoptimized = False self.project_directory = project_directory self.label = label self.symmetry_number = None @@ -798,6 +825,16 @@ def as_dict(self, species_dict['run_time'] = self.run_time.total_seconds() if self.number_of_radicals is not None: species_dict['number_of_radicals'] = self.number_of_radicals + if self.derived_stability_verdict is not None: + species_dict['derived_stability_verdict'] = self.derived_stability_verdict + if self.scf_references: + species_dict['scf_references'] = self.scf_references + if self.stability_analysis_ran: + species_dict['stability_analysis_ran'] = self.stability_analysis_ran + if self.stability_pending_opt_job is not None: + species_dict['stability_pending_opt_job'] = self.stability_pending_opt_job + if self.stability_reoptimized: + species_dict['stability_reoptimized'] = self.stability_reoptimized if self.opt_level is not None: species_dict['opt_level'] = self.opt_level if self.directed_rotors: @@ -931,6 +968,15 @@ def from_dict(self, species_dict): self.include_in_thermo_lib = species_dict['include_in_thermo_lib'] if 'include_in_thermo_lib' in species_dict else True self.e0_only = species_dict['e0_only'] if 'e0_only' in species_dict else False self.number_of_radicals = species_dict['number_of_radicals'] if 'number_of_radicals' in species_dict else None + self.derived_stability_verdict = species_dict['derived_stability_verdict'] \ + if 'derived_stability_verdict' in species_dict else None + self.scf_references = species_dict['scf_references'] if 'scf_references' in species_dict else dict() + self.stability_analysis_ran = species_dict['stability_analysis_ran'] \ + if 'stability_analysis_ran' in species_dict else False + self.stability_pending_opt_job = species_dict['stability_pending_opt_job'] \ + if 'stability_pending_opt_job' in species_dict else None + self.stability_reoptimized = species_dict['stability_reoptimized'] \ + if 'stability_reoptimized' in species_dict else False self.opt_level = species_dict['opt_level'] if 'opt_level' in species_dict else None self.number_of_rotors = species_dict['number_of_rotors'] if 'number_of_rotors' in species_dict else 0 self.external_symmetry = species_dict['external_symmetry'] if 'external_symmetry' in species_dict else None diff --git a/arc/species/species_test.py b/arc/species/species_test.py index 1abac6ca85..815c4f426b 100644 --- a/arc/species/species_test.py +++ b/arc/species/species_test.py @@ -923,6 +923,49 @@ def test_process_run_time(self): with self.assertRaises(SpeciesError): process_run_time(non_finite) + def test_derived_stability_verdict_round_trip(self): + """Test that a measured stability verdict and the SCF references used round-trip through a restart""" + default_spc = ARCSpecies(label='ozone', smiles='[O-][O+]=O') + default_dict = default_spc.as_dict() + self.assertNotIn('derived_stability_verdict', default_dict) + self.assertNotIn('scf_references', default_dict) + restored_default = ARCSpecies(species_dict=default_dict) + self.assertIsNone(restored_default.derived_stability_verdict) + self.assertEqual(restored_default.scf_references, dict()) + + spc = ARCSpecies(label='ozone', smiles='[O-][O+]=O') + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'negative_eigenvectors': [{'label': 'Triplet-A', 'eigenvalue': -0.0642}]} + spc.scf_references = {'freq': 'restricted', 'sp': 'unrestricted'} + spc_dict = spc.as_dict() + restored = ARCSpecies(species_dict=spc_dict) + self.assertEqual(restored.derived_stability_verdict['verdict'], 'external_instability') + self.assertIs(restored.derived_stability_verdict['restricted'], True) + self.assertEqual(restored.derived_stability_verdict['negative_eigenvectors'], + [{'label': 'Triplet-A', 'eigenvalue': -0.0642}]) + self.assertEqual(restored.scf_references, {'freq': 'restricted', 'sp': 'unrestricted'}) + self.assertIsNone(restored.number_of_radicals) + + def test_stability_sequencing_state_round_trip(self): + """Test that the stability analysis sequencing state round-trips through a restart""" + default_spc = ARCSpecies(label='ozone', smiles='[O-][O+]=O') + default_dict = default_spc.as_dict() + for key in ['stability_analysis_ran', 'stability_pending_opt_job', 'stability_reoptimized']: + self.assertNotIn(key, default_dict) + restored_default = ARCSpecies(species_dict=default_dict) + self.assertFalse(restored_default.stability_analysis_ran) + self.assertIsNone(restored_default.stability_pending_opt_job) + self.assertFalse(restored_default.stability_reoptimized) + + spc = ARCSpecies(label='ozone', smiles='[O-][O+]=O') + spc.stability_analysis_ran = True + spc.stability_pending_opt_job = 'opt_a7' + spc.stability_reoptimized = True + restored = ARCSpecies(species_dict=spc.as_dict()) + self.assertTrue(restored.stability_analysis_ran) + self.assertEqual(restored.stability_pending_opt_job, 'opt_a7') + self.assertTrue(restored.stability_reoptimized) + def test_from_dict(self): """Test Species.from_dict()""" species_dict = self.spc2.as_dict() From 4c091750233f9c19c7a015088ab1cb6a3024eefa Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 06/12] Record the stability verdict, the SCF-reference provenance and in output.yml Three additions to the per-species output entry, all written from parsed logs. wavefunction_stability, the human-readable summary string the end-of-run report prints, plus the structured block behind it. _parse_wavefunction_stability reads the stability log and records the verdict, the negative stability-matrix eigenvector labels and their eigenvalues, the lowest eigenvalue, the reference the analysis ran on, and invalidates_analytic_freq, together with the run-relative path of the log it came from. It is not recomputed here: the parser derives the verdict and its consequence once, and this entry reads that single result. scf_reference, the provenance block. It records source (declared / derived / null), declared_number_of_radicals, verdict, verdict_restricted, sp_reference, freq_reference, reference_mismatch and the stability log it was read from -- flat, so that arcbench's _spin_diagnostic_payload allow-list is unaffected. reference_mismatch is null, NOT false, when either reference is unknown. A job carrying no reference memo leaves nothing to compare, and publishing that as false is indistinguishable from two references checked and found to agree. Every sibling key in the block uses null for unknown; this one does too. log names the analysis a 'derived' source was decided from even after the stability path is gone. A TS switch resets that path while the species keeps the verdict it carried across, so reading the path alone published a source of 'derived' beside a null log -- a decision with nothing behind it. The block falls back to the log path the species' own verdict carries, made run-relative like the other one. The block is NOT gated on convergence, unlike the parsed quantities beside it and like the wavefunction_stability entry it explains. It records a decision ARC made rather than a number a job produced, and a species that adopted a verdict and then failed to converge is precisely the case where knowing ARC changed its reference explains the failure. Gating it hid that record exactly when it was wanted. A well's verdict reaches output.yml as verdict / verdict_restricted with source null, which the entry's is_ts separates from a TS's identical verdict reading 'derived'. No new key is added for that: the pair already says it, and a column computed from its neighbours is a liability. sp_spin_diagnostic, the block, in the same shape and key names as the arcbench emitter that consumes it, so the two bind unchanged. Its fallback loop now stops at the first candidate path that EXISTS, not at the first that yields a value. Continuing past a log that exists but yields no is not what the fallback was written for: an sp on Molpro or CFOUR, neither of which implements parse_s_squared and both of which therefore inherit the base class's None, together with opt and freq on Gaussian UHF, populated sp_spin_diagnostic from the FREQ log at a different level of theory while d['sp_log'] still named the Molpro file -- and arcbench's TCKDB adapter uploads that block as the sp calculation's . A present-but-silent log now ends the search and the block is omitted, and the block records the run-relative path of the log it was actually read from under 'log', following the precedent _parse_wavefunction_stability sets at the same call site. The new key is additive and safe for the arcbench consumer, which copies an allow-list out of the block and ignores every other key. Verified by mutation. Reading a non-dict scf_references with .get fails 1; publishing an unknown reference_mismatch as false, 1; gating the provenance block on convergence, 1; never reporting reference_mismatch, 1; never naming a source in the provenance block, 3; recording the stability block for a TS only, 2; reversing the sp/freq/opt fallback order, 2; and dropping the `if converged else None` gate on sp_spin_diagnostic, 1. _parse_wavefunction_stability's documented return schema was missing keys it already emitted. n_analyses and followed_to_stable reach output.yml and are now documented, along with the new s_squared_after_follow and the 'unattributed_instability' verdict. The note also records which wavefunction each field describes: verdict, lowest_eigenvalue, negative_eigenvectors and restricted belong to the wavefunction under TEST, while the energies and spin values the published log also holds belong to the FOLLOWED solution the ESS relaxed into. Nothing consumes the followed energy today, but output.yml publishes that log's path, so a future consumer would read the wrong wavefunction off it in silence. --- arc/output.py | 205 +++++++++++++++++++++++++++++- arc/output_test.py | 301 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 505 insertions(+), 1 deletion(-) diff --git a/arc/output.py b/arc/output.py index 97a61ce1fc..a63989d444 100644 --- a/arc/output.py +++ b/arc/output.py @@ -17,9 +17,12 @@ from arc.common import ARC_PATH, VERSION, get_git_commit, get_logger, read_yaml_file, save_yaml_file from arc.constants import E_h_kJmol from arc.imports import settings +from arc.job.adapters.common import open_shell_character_source from arc.job.env_run import rmg_env_command from arc.job.local import execute_command -from arc.parser.parser import parse_1d_scan_energies, parse_e_elect, parse_ess_version, parse_opt_steps, parse_zpe_correction +from arc.parser.parser import (parse_1d_scan_energies, parse_e_elect, parse_ess_version, parse_opt_steps, + parse_s_squared, parse_wavefunction_stability, parse_zpe_correction, + s_squared_expected_from_multiplicity) from arc.species.converter import xyz_to_str from arc.statmech.arkane import ( AEC_SECTION_START, AEC_SECTION_END, @@ -229,6 +232,190 @@ def _parse_zpe(freq_path: str | None, project_directory: str) -> float | None: return None +def _parse_wavefunction_stability(stability_path: str | None, project_directory: str) -> dict | None: + """ + Parse the wavefunction stability verdict from a stability analysis log. + + Returns ``None`` when no stability analysis was run, when its log is missing, + or when the log holds no verdict. Otherwise returns the parsed verdict with the + log's run-relative path added under ``'log'``. + + ``'log'`` names the analysis log, and every other key of an ESS that follows an + instability rather than only reporting it describes one of TWO wavefunctions: + ``verdict``, ``lowest_eigenvalue``, ``negative_eigenvectors`` and ``restricted`` + belong to the wavefunction under TEST, while the energies and spin expectation values + that log also holds belong to the FOLLOWED solution the ESS relaxed into, which is a + different wavefunction. A consumer reading a quantity out of that log rather than out + of this block is reading the followed solution. + + Returns: dict | None + ``{'verdict': 'stable' | 'internal_instability' | 'external_instability' + | 'unattributed_instability' | 'unknown', + 'internal_instability': bool | None, 'external_instability': bool | None, + 'relaxations': list[str], 'negative_eigenvectors': list[dict], + 'lowest_eigenvalue': float | None, 'restricted': bool | None, + 'invalidates_analytic_freq': bool | None, 'log': str}``, plus the keys an + individual ESS reader adds. The ORCA reader adds ``'n_analyses'`` (int), the number + of analyses the log holds, ``'followed_to_stable'`` (bool), whether the last of + several ended stable, and ``'s_squared_after_follow'`` (float | None), the spin + expectation value of the followed solution, from which the sector of a restricted + reference's instability is measured. + ``'unknown'`` means an analysis ran but its verdict could not be read, and is + never to be treated as ``'stable'``. ``'unattributed_instability'`` means the + wavefunction is unstable but the ESS did not report which sector the instability + lies in, and is likewise never to be treated as ``'stable'``. + """ + if not stability_path: + return None + path = stability_path if os.path.isabs(stability_path) else os.path.join(project_directory, stability_path) + if not os.path.isfile(path): + return None + try: + result = parse_wavefunction_stability(path) + except Exception: + logger.debug(f'Failed to parse a wavefunction stability verdict from {path!r}', exc_info=True) + return None + if not result: + return None + result = dict(result) + result['log'] = _make_rel_path(path, project_directory) + return result + + +def _scf_reference_block(spc, stability: dict | None, project_directory: str) -> dict: + """ + Report which source decided a species' open-shell character and which SCF references its jobs used. + + ``source`` is ``'declared'`` when the user gave a ``number_of_radicals``, which always wins + and is reported even where it contradicts the measured verdict; ``'derived'`` when the user + gave nothing and a measured wavefunction-stability verdict made the species unrestricted; + and ``None`` when the spin multiplicity alone decided. ``verdict`` and ``verdict_restricted`` + carry the measured picture whether or not it was the deciding one, and ``log`` names the + stability analysis they were read from, following ``_parse_wavefunction_stability``. + + The analysis is run for a transition state and for any other species whose optimization ran + restricted, but only a transition state's verdict is acted on. So a species carrying an + external instability under a ``source`` of ``None`` is one whose restricted energy sits above + a lower symmetry-broken solution that ARC measured and left alone, which the entry's ``is_ts`` + separates from a transition state whose identical verdict reads ``'derived'`` and did decide. + + ``sp_reference`` and ``freq_reference`` are the references those two jobs declared in the + inputs they actually ran, and ``reference_mismatch`` is ``True`` when they differ, which + means the species' E0 sums an electronic energy and a ZPE taken from two different surfaces. + It is ``None``, not ``False``, whenever either reference is unknown: an sp job that was never + submitted because the sp level equals the opt level, or a job carrying no memo, leaves nothing + to compare, and reporting that as ``False`` would be indistinguishable from two references + checked and found to agree. + + ``source`` is ``None`` where a declared ``number_of_radicals`` of zero or one blocked a measured + verdict without itself attributing open-shell character. ``declared_number_of_radicals`` still + carries the declaration, so the pair says what happened. + + ``measured_on_ts_guess`` is set only on a verdict carried over from an abandoned TS guess, + and names the guess it was measured on; the guess reported elsewhere in the entry is a + different one. A TS switch resets the stability path, so ``log`` falls back to the path the + species' own verdict was read from: a ``source`` of ``'derived'`` names the analysis that + decided it whether or not that analysis is still the surviving geometry's. + + ``verdict`` falls back to the stability log when the species carries none, as a restart + written before the species held one does, while ``source`` never does: the reference + decision reads the species and only the species, so a verdict that reached the log but not + the species decided nothing and is reported without being credited with the decision. + + The block is emitted whether or not the species converged, like the ``wavefunction_stability`` + entry it explains and unlike the parsed results around it. It records a decision ARC made + rather than a quantity a job produced, and a species that adopted a verdict and then failed to + converge is exactly the case where knowing ARC changed its reference explains the failure. + + Args: + spc (ARCSpecies): The species the block describes. + stability (dict, optional): The parsed wavefunction stability verdict, where one was parsed. + project_directory (str): The project directory, which the reported log path is relative to. + + Returns: dict + A flat mapping of scalars; keys are always present, with ``None`` where unknown. + """ + verdict = getattr(spc, 'derived_stability_verdict', None) + if not isinstance(verdict, dict): + verdict = stability if isinstance(stability, dict) else None + log = stability.get('log') if isinstance(stability, dict) else None + if log is None and verdict is not None: + log = _make_rel_path(verdict.get('log'), project_directory) + references = getattr(spc, 'scf_references', None) + references = references if isinstance(references, dict) else dict() + sp_reference, freq_reference = references.get('sp'), references.get('freq') + return {'source': open_shell_character_source(spc), + 'declared_number_of_radicals': getattr(spc, 'number_of_radicals', None), + 'verdict': verdict.get('verdict') if verdict else None, + 'verdict_restricted': verdict.get('restricted') if verdict else None, + 'measured_on_ts_guess': verdict.get('measured_on_ts_guess') if verdict else None, + 'sp_reference': sp_reference, + 'freq_reference': freq_reference, + 'reference_mismatch': sp_reference != freq_reference + if sp_reference is not None and freq_reference is not None else None, + 'log': log, + } + + +def _parse_spin_diagnostic(sp_path: str | None, + freq_path: str | None, + opt_path: str | None, + multiplicity: int | None, + project_directory: str, + ) -> dict | None: + """ + Parse the S**2 spin-contamination diagnostic for a species' single-point calc. + + The diagnostic is a property of the (unrestricted) wavefunction, so it is + parsed from the sp job's log; when the sp energy reused the optimization + output the sp log may be absent, so the first of the sp, freq and opt/geo + logs that exists is the one read. A log that exists but yields no + ```` ends the search: an ESS with no ```` reader, or a + restricted reference, means this calc has no diagnostic, and reading a + different job's wavefunction in its place would attribute another level of + theory's value to the sp calc. The log actually read is recorded under + ``'log'`` so the value can be traced to it. + + Restricted / closed-shell logs print no ```` and this returns ``None`` + for them, so the caller omits the block rather than emitting an all-null one. + + ``s_squared_expected`` is recomputed from ARC's own ``multiplicity`` when + available, falling back to the value the ESS log reported. + + Returns: dict | None + ``{'s_squared': float, 's_squared_expected': float | None (omitted if + None), 's_squared_annihilated': float | None (omitted if None), + 'log': str}`` or ``None`` when no ```` could be parsed. + """ + parsed, source_path = None, None + for candidate in (sp_path, freq_path, opt_path): + if not candidate: + continue + path = candidate if os.path.isabs(candidate) else os.path.join(project_directory, candidate) + if not os.path.isfile(path): + continue + source_path = path + try: + parsed = parse_s_squared(path) + except Exception: + logger.debug(f'Failed to parse an S**2 spin diagnostic from {path!r}', exc_info=True) + parsed = None + break + if parsed is None or parsed.get('s_squared') is None: + return None + result: dict = {'s_squared': float(parsed['s_squared'])} + expected = s_squared_expected_from_multiplicity(multiplicity) + if expected is None: + expected = parsed.get('s_squared_expected') + if expected is not None: + result['s_squared_expected'] = float(expected) + annihilated = parsed.get('s_squared_annihilated') + if annihilated is not None: + result['s_squared_annihilated'] = float(annihilated) + result['log'] = _make_rel_path(source_path, project_directory) + return result + + def _parse_opt_log(geo_path: str | None, project_directory: str) -> tuple: """ Parse opt_n_steps and opt_final_energy_hartree from the geometry opt log. @@ -492,6 +679,22 @@ def _spc_to_dict(spc, output_dict: dict, project_directory: str, d['freq_log'] = _make_rel_path(paths.get('freq') or None, project_directory) d['sp_log'] = _make_rel_path(paths.get('sp') or None, project_directory) + # ── wavefunction stability diagnostic (null unless the job ran) ────────── + stability = _parse_wavefunction_stability(paths.get('stability') or None, project_directory) + d['wavefunction_stability'] = stability + + # ── which source decided the open-shell character, and the references used ── + d['scf_reference'] = _scf_reference_block(spc, stability, project_directory) + + # ── S**2 spin-contamination diagnostic (sp calc, open-shell only) ─────── + d['sp_spin_diagnostic'] = _parse_spin_diagnostic( + paths.get('sp') or None, + paths.get('freq') or None, + paths.get('geo') or None, + spc.multiplicity, + project_directory, + ) if converged else None + # ── ESS software version (from SP log, or fall back to geo/freq log) ── d['ess_versions'] = _get_ess_versions(paths, project_directory) if converged else None diff --git a/arc/output_test.py b/arc/output_test.py index ab0bada2bf..2d20c6f75f 100644 --- a/arc/output_test.py +++ b/arc/output_test.py @@ -22,6 +22,8 @@ _level_to_dict, _make_rel_path, _parse_opt_log, + _parse_spin_diagnostic, + _parse_wavefunction_stability, _parse_zpe, _resolve_freq_scale_factor_source, _rxn_to_dict, @@ -419,6 +421,92 @@ def test_parse_opt_steps_via_make_parser(self): self.assertEqual(parse_opt_steps(opt_path), 4) +class TestParseSpinDiagnostic(unittest.TestCase): + """Tests for _parse_spin_diagnostic (output.yml S**2 plumbing).""" + + def test_open_shell_gaussian_doublet(self): + """Test that an open-shell doublet yields s_squared, expected and annihilated""" + sp = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + sd = _parse_spin_diagnostic(sp, None, None, multiplicity=2, project_directory='/dummy') + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7535) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + self.assertAlmostEqual(sd['s_squared_annihilated'], 0.75) + + def test_expected_recomputed_from_arc_multiplicity(self): + """Test that s_squared_expected comes from ARC's multiplicity, a triplet giving 2.0""" + sp = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'TSs', 'TS_freq.out') + sd = _parse_spin_diagnostic(sp, None, None, multiplicity=3, project_directory='/dummy') + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 2.0153) + self.assertAlmostEqual(sd['s_squared_expected'], 2.0) + + def test_closed_shell_returns_none(self): + """Test that a restricted log, which prints no , yields None""" + sp = os.path.join(ARC_TESTING_PATH, 'composite', 'C2H5NO2__C2H5ONO.out') + self.assertIsNone(_parse_spin_diagnostic(sp, None, None, multiplicity=1, project_directory='/dummy')) + + def test_fallback_to_freq_when_sp_absent(self): + """Test that an absent sp log falls back to the freq log""" + freq = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + sd = _parse_spin_diagnostic(None, freq, None, multiplicity=2, project_directory='/dummy') + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7535) + + def test_no_paths_returns_none(self): + """Test that no candidate log yields None""" + self.assertIsNone(_parse_spin_diagnostic(None, None, None, multiplicity=2, project_directory='/dummy')) + + def test_orca_open_shell_no_annihilation_key(self): + """Test that an ESS reporting no annihilated value omits the key from the block""" + sp = os.path.join(ARC_TESTING_PATH, 'neb', 'neb_res.out') + sd = _parse_spin_diagnostic(sp, None, None, multiplicity=2, project_directory='/dummy') + self.assertIsNotNone(sd) + self.assertNotIn('s_squared_annihilated', sd) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + + def test_a_stability_log_is_not_read_off_its_eigenvectors(self): + """Test that a Stable job's log yields the wavefunction's , not a root's""" + sp = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_unrestricted_doublet_ts.out') + sd = _parse_spin_diagnostic(sp, None, None, multiplicity=2, project_directory='/dummy') + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared'], 0.7536) + restricted = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_restricted_singlet_ts.out') + self.assertIsNone(_parse_spin_diagnostic(restricted, None, None, multiplicity=1, + project_directory='/dummy')) + + def test_the_sp_log_is_preferred_over_the_freq_and_opt_logs(self): + """Test that the sp log wins when several candidate logs exist""" + sp = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + freq = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'TSs', 'TS_freq.out') + opt = os.path.join(ARC_TESTING_PATH, 'freq', 'CH3OO_freq_gaussian.out') + sd = _parse_spin_diagnostic(sp, freq, opt, multiplicity=2, project_directory=ARC_TESTING_PATH) + self.assertAlmostEqual(sd['s_squared'], 0.7535) + self.assertNotAlmostEqual(sd['s_squared'], 2.0153) + self.assertNotAlmostEqual(sd['s_squared'], 0.7544) + + def test_the_log_the_value_was_read_from_is_recorded(self): + """Test that the block names the log its came from""" + freq = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + sd = _parse_spin_diagnostic(None, freq, None, multiplicity=2, project_directory=ARC_TESTING_PATH) + self.assertEqual(sd['log'], os.path.join('restart', '2_restart_rate', 'calcs', 'Species', + 'NH2_freq.out')) + + def test_an_sp_log_that_holds_no_s_squared_is_not_replaced_by_another_job(self): + """Test that a present sp log yielding no ends the search rather than falling through""" + sp = os.path.join(ARC_TESTING_PATH, 'composite', 'C2H5NO2__C2H5ONO.out') + freq = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + self.assertIsNone(_parse_spin_diagnostic(sp, freq, None, multiplicity=2, + project_directory=ARC_TESTING_PATH)) + + def test_the_expected_value_falls_back_to_the_one_the_ess_reported(self): + """Test that ORCA's Ideal value S*(S+1) is used when ARC's multiplicity is unknown""" + sp = os.path.join(ARC_TESTING_PATH, 'neb', 'neb_res.out') + sd = _parse_spin_diagnostic(sp, None, None, multiplicity=None, project_directory=ARC_TESTING_PATH) + self.assertIsNotNone(sd) + self.assertAlmostEqual(sd['s_squared_expected'], 0.75) + + class TestParseEssVersion(unittest.TestCase): """Tests for parse_ess_version across ESS adapters.""" @@ -676,6 +764,9 @@ def test_ts_smiles_null_formula_from_mol(self): spc.rxn_label = 'CHO + CH4 <=> CH2O + CH3' spc.chosen_ts_method = 'heuristics' spc.successful_methods = ['heuristics'] + spc.number_of_radicals = None + spc.derived_stability_verdict = None + spc.scf_references = dict() output_dict = {'TS0': {'convergence': True, 'paths': {'irc': []}, 'job_types': {'opt': True, 'irc': True}}} result = _spc_to_dict(spc, output_dict, '/abs') self.assertIsNone(result['smiles']) @@ -703,6 +794,9 @@ def test_ts_without_mol(self): spc.rxn_label = 'A <=> B' spc.chosen_ts_method = None spc.successful_methods = [] + spc.number_of_radicals = None + spc.derived_stability_verdict = None + spc.scf_references = dict() output_dict = {'TS1': {'convergence': True, 'paths': {'irc': []}, 'job_types': {}}} result = _spc_to_dict(spc, output_dict, '/abs') self.assertIsNone(result['smiles']) @@ -793,6 +887,9 @@ def _make_spc_mock(self, label='CH4', is_ts=False, converged=True, monoatomic=Fa spc.rxn_label = None spc.ts_guesses = [] spc.chosen_ts = None + spc.number_of_radicals = None + spc.derived_stability_verdict = None + spc.scf_references = dict() return spc def test_converged_species(self): @@ -826,6 +923,157 @@ def test_non_converged_species(self): self.assertIsNone(result['thermo']) self.assertIsNone(result['statmech']) + def test_a_non_converged_species_carries_no_spin_diagnostic(self): + """Test that a readable sp log does not give an unconverged species an sp_spin_diagnostic""" + sp = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + spc = self._make_spc_mock(label='NH2') + spc.multiplicity = 2 + output_dict = {'NH2': {'convergence': True, 'paths': {'sp': sp}, 'job_types': {}}} + self.assertIsNotNone(_spc_to_dict(spc, output_dict, ARC_TESTING_PATH)['sp_spin_diagnostic']) + output_dict['NH2']['convergence'] = False + self.assertIsNone(_spc_to_dict(spc, output_dict, ARC_TESTING_PATH)['sp_spin_diagnostic']) + + def test_scf_reference_records_a_declared_source(self): + """Test that a user-declared number_of_radicals is reported as the deciding source""" + spc = self._make_spc_mock() + spc.number_of_radicals = 2 + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + block = _spc_to_dict(spc, output_dict, '/abs')['scf_reference'] + self.assertEqual(block['source'], 'declared') + self.assertEqual(block['declared_number_of_radicals'], 2) + self.assertIsNone(block['verdict']) + + def test_scf_reference_records_a_derived_source_and_its_verdict(self): + """Test that an adopted measured verdict is reported as the deciding source""" + spc = self._make_spc_mock(is_ts=True) + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + block = _spc_to_dict(spc, output_dict, '/abs')['scf_reference'] + self.assertEqual(block['source'], 'derived') + self.assertEqual(block['verdict'], 'external_instability') + self.assertIs(block['verdict_restricted'], True) + self.assertIsNone(block['declared_number_of_radicals']) + + def test_a_well_records_its_verdict_without_being_credited_with_a_decision(self): + """Test that a species that is not a TS records the same verdict under no deciding source""" + spc = self._make_spc_mock() + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + entry = _spc_to_dict(spc, output_dict, '/abs') + self.assertFalse(entry['is_ts']) + block = entry['scf_reference'] + self.assertEqual(block['verdict'], 'external_instability') + self.assertIs(block['verdict_restricted'], True) + self.assertIsNone(block['source']) + + def test_a_well_records_the_stability_log_it_was_measured_from(self): + """Test that the stability diagnostic reaches output.yml for a species that is not a TS""" + stability = os.path.join(ARC_TESTING_PATH, 'stability', 'rhf_uhf_instability_singlet_ts.out') + spc = self._make_spc_mock() + output_dict = {'CH4': {'convergence': True, 'paths': {'stability': stability}, 'job_types': {}}} + entry = _spc_to_dict(spc, output_dict, ARC_TESTING_PATH) + self.assertFalse(entry['is_ts']) + self.assertEqual(entry['wavefunction_stability']['verdict'], 'external_instability') + self.assertEqual(entry['scf_reference']['log'], + os.path.join('stability', 'rhf_uhf_instability_singlet_ts.out')) + + def test_scf_reference_reports_a_declared_source_over_a_contradicting_verdict(self): + """Test that a declared value is still the reported source where the verdict disagrees""" + spc = self._make_spc_mock(is_ts=True) + spc.number_of_radicals = 2 + spc.derived_stability_verdict = {'verdict': 'stable', 'restricted': True} + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + block = _spc_to_dict(spc, output_dict, '/abs')['scf_reference'] + self.assertEqual(block['source'], 'declared') + self.assertEqual(block['verdict'], 'stable') + + def test_a_declaration_attributing_no_open_shell_character_names_no_source(self): + """Test that a declared 1 blocks the verdict and is reported without being called the source""" + spc = self._make_spc_mock(is_ts=True) + spc.number_of_radicals = 1 + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + block = _spc_to_dict(spc, output_dict, '/abs')['scf_reference'] + self.assertIsNone(block['source']) + self.assertEqual(block['declared_number_of_radicals'], 1) + self.assertEqual(block['verdict'], 'external_instability') + + def test_scf_reference_reports_a_mixed_reference(self): + """Test that an electronic energy and a ZPE from different references are recorded as such""" + spc = self._make_spc_mock() + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + spc.scf_references = {'sp': 'unrestricted', 'freq': 'restricted'} + block = _spc_to_dict(spc, output_dict, '/abs')['scf_reference'] + self.assertEqual(block['sp_reference'], 'unrestricted') + self.assertEqual(block['freq_reference'], 'restricted') + self.assertTrue(block['reference_mismatch']) + spc.scf_references = {'sp': 'unrestricted', 'freq': 'unrestricted'} + self.assertIs(_spc_to_dict(spc, output_dict, '/abs')['scf_reference']['reference_mismatch'], False) + + def test_an_unrecorded_reference_is_reported_as_unknown_rather_than_consistent(self): + """Test that a missing sp or freq reference is None, not the False that means checked and equal""" + spc = self._make_spc_mock() + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + for references in [dict(), {'freq': 'restricted'}, {'sp': 'restricted'}, 'not a dict']: + spc.scf_references = references + block = _spc_to_dict(spc, output_dict, '/abs')['scf_reference'] + self.assertIsNone(block['reference_mismatch'], msg=f'{references} reported a mismatch verdict') + + def test_scf_reference_names_the_ts_guess_a_carried_verdict_was_measured_on(self): + """Test that a verdict carried over from an abandoned TS guess says which guess it came from""" + spc = self._make_spc_mock() + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'measured_on_ts_guess': 3} + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + self.assertEqual(_spc_to_dict(spc, output_dict, '/abs')['scf_reference']['measured_on_ts_guess'], 3) + + def test_a_carried_verdict_still_names_the_analysis_that_decided_the_reference(self): + """Test that a TS switch, which resets the stability path, leaves no source without a log""" + stability = os.path.join(ARC_TESTING_PATH, 'stability', 'rhf_uhf_instability_singlet_ts.out') + spc = self._make_spc_mock(is_ts=True) + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'measured_on_ts_guess': 3, 'log': stability} + output_dict = {'CH4': {'convergence': True, 'paths': {'stability': ''}, 'job_types': {}}} + entry = _spc_to_dict(spc, output_dict, ARC_TESTING_PATH) + self.assertIsNone(entry['wavefunction_stability']) + block = entry['scf_reference'] + self.assertEqual(block['source'], 'derived') + self.assertEqual(block['measured_on_ts_guess'], 3) + self.assertEqual(block['log'], os.path.join('stability', 'rhf_uhf_instability_singlet_ts.out')) + + def test_a_verdict_carrying_no_log_reports_none_rather_than_raising(self): + """Test that a verdict restored from a restart written without a log path is still reported""" + spc = self._make_spc_mock(is_ts=True) + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + output_dict = {'CH4': {'convergence': True, 'paths': {}, 'job_types': {}}} + block = _spc_to_dict(spc, output_dict, ARC_TESTING_PATH)['scf_reference'] + self.assertEqual(block['source'], 'derived') + self.assertIsNone(block['log']) + + def test_a_non_converged_species_still_carries_its_scf_reference_block(self): + """Test that the record of what ARC decided survives the species failing to converge""" + spc = self._make_spc_mock(converged=False, is_ts=True) + spc.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + spc.scf_references = {'freq': 'restricted', 'sp': 'unrestricted'} + output_dict = {'CH4': {'convergence': False, 'paths': {}, 'job_types': {}}} + entry = _spc_to_dict(spc, output_dict, '/abs') + self.assertFalse(entry['converged']) + self.assertIsNone(entry['sp_spin_diagnostic']) + block = entry['scf_reference'] + self.assertEqual(block['source'], 'derived') + self.assertEqual(block['verdict'], 'external_instability') + self.assertIs(block['reference_mismatch'], True) + + def test_scf_reference_reads_a_verdict_off_the_log_without_calling_it_the_source(self): + """Test that a verdict only the log holds is reported but is not credited with the decision""" + stability = os.path.join(ARC_TESTING_PATH, 'stability', 'rhf_uhf_instability_singlet_ts.out') + spc = self._make_spc_mock() + output_dict = {'CH4': {'convergence': True, 'paths': {'stability': stability}, 'job_types': {}}} + block = _spc_to_dict(spc, output_dict, ARC_TESTING_PATH)['scf_reference'] + self.assertEqual(block['verdict'], 'external_instability') + self.assertEqual(block['log'], os.path.join('stability', 'rhf_uhf_instability_singlet_ts.out')) + self.assertIsNone(block['source']) + def test_monoatomic_species(self): spc = self._make_spc_mock(label='Ar', monoatomic=True) spc.final_xyz = {'symbols': ('Ar',), 'isotopes': (40,), 'coords': ((0.0, 0.0, 0.0),)} @@ -1020,6 +1268,9 @@ def _make_spc_mock(self, label='CH4'): spc.freqs = [1300.0, 1500.0, 3000.0] spc.rotors_dict = None spc.thermo = ThermoData(H298=-74.6, S298=186.3, Tmin=(300, 'K'), Tmax=(3000, 'K')) + spc.number_of_radicals = None + spc.derived_stability_verdict = None + spc.scf_references = dict() return spc @patch('arc.output._compute_point_groups', return_value={}) @@ -1203,5 +1454,55 @@ def test_point_group_unknown_element(self): sys.path.remove(scripts_dir) +class TestParseWavefunctionStabilityForOutput(unittest.TestCase): + """ + Contains unit tests for the wavefunction stability entry written to output.yml. + """ + + def _write_log(self, body: str) -> str: + """Write a Gaussian stability log to a temporary file and return its path.""" + with tempfile.NamedTemporaryFile(suffix='.log', mode='w', delete=False) as f: + f.write(' Entering Gaussian System, Link 0=g16\n' + body) + return f.name + + def test_freq_validity_reaches_the_output_record(self): + """Test that output.yml carries the reference and the frequency-validity verdict""" + body = ' SCF Done: E(UwB97XD) = -78.5936 A.U.\n' \ + ' Stability analysis using singles matrix:\n' \ + ' Eigenvector 1: Triplet-?Sym Eigenvalue=-0.1434007 =2.000\n' \ + ' The wavefunction has an RHF -> UHF instability.\n' + path = self._write_log(body) + try: + result = _parse_wavefunction_stability(path, os.path.dirname(path)) + self.assertEqual(result['verdict'], 'external_instability') + self.assertIn('restricted', result) + self.assertIn('invalidates_analytic_freq', result) + self.assertFalse(result['restricted']) + self.assertTrue(result['invalidates_analytic_freq']) + self.assertIsNotNone(result['log']) + finally: + if os.path.exists(path): + os.remove(path) + + def test_restricted_external_instability_reaches_output_as_valid(self): + """Test that a restricted external instability is recorded as not invalidating the freq""" + body = ' SCF Done: E(RwB97XD) = -78.5936 A.U.\n' \ + ' Stability analysis using singles matrix:\n' \ + ' The wavefunction has an RHF -> UHF instability.\n' + path = self._write_log(body) + try: + result = _parse_wavefunction_stability(path, os.path.dirname(path)) + self.assertTrue(result['restricted']) + self.assertFalse(result['invalidates_analytic_freq']) + finally: + if os.path.exists(path): + os.remove(path) + + def test_no_stability_log_yields_nothing(self): + """Test that a species with no stability analysis records no entry""" + self.assertIsNone(_parse_wavefunction_stability(None, '/tmp')) + self.assertIsNone(_parse_wavefunction_stability('/nonexistent/stability.log', '/tmp')) + + if __name__ == '__main__': unittest.main() From 0a5e53166b5606c0fb89ec78c453c3cc66ded7ac Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 07/12] Run the stability analysis from the opt, re-optimize on an adopted verdict, carry it across a TS switch The scheduler side of the wavefunction-stability diagnostic: where the analysis sits in a species' job sequence, what an adopted verdict does to that sequence, and what survives a TS guess switch. SEQUENCING. The analysis is a single point, so it can run the moment the optimization converges, and that is where spawn_post_opt_jobs runs it: opt -> stability -> freq / sp / IRC / rotors, or opt -> stability -> opt (unrestricted) -> freq / sp / IRC / rotors Nothing else is enqueued from the post-opt path while the analysis is out. The frequency job, the single point, the IRC and the rotor scans all inherit the SCF reference and the geometry of the optimization, so a reference that is not the ground state is caught before a Hessian and an energy are spent on it, and before a re-optimization would have to throw them away. The optimization job's name is written to the species as stability_pending_opt_job BEFORE the analysis is spawned, and spawn_post_stability_jobs re-enters spawn_post_opt_jobs with it; the analysis runs at most once per species, so the re-entry spawns none and falls through. That resume is reached for every stability job that leaves running_jobs -- converged, errored, or holding a log no verdict could be read from -- so an analysis that produces nothing releases the species rather than stranding it. RE-OPTIMIZATION IS WHAT MAKES AN ADOPTION CORRECT. Adopting a verdict without re-optimizing would leave the geometry a stationary point of the RESTRICTED surface while the Hessian is built on the broken-symmetry reference, which is a Hessian at a non-stationary point and can report imaginary modes belonging to the mismatch rather than to the molecule. So an adopted verdict re-runs the opt at the opt level, from the geometry the first optimization reached, and is_species_restricted reads the adopted verdict off the species, so that job and every job after it run unrestricted. E0 is then E_elect and ZPE from one surface. AT MOST ONE RE-OPTIMIZATION PER SPECIES. ARCSpecies carries stability_analysis_ran, stability_pending_opt_job and stability_reoptimized, all serialised through as_dict / from_dict, so a run resumed between the analysis and the re-optimization spawns neither a second analysis nor a second optimization. schedule_jobs releases any species holding a pending optimization with no analysis of its own still queued, which is the state a run resumed after its analysis ended leaves behind: the job it was waiting on is gone, so nothing else would reach the resume for it. THE ORBITALS THE RE-OPTIMIZATION STARTS FROM depend on what the ESS did with the instability it found, which the verdict reports as followed_to_stable. ORCA runs STABPerform with STABRestartUHFifUnstable, follows the instability, and writes the relaxed orbitals to the analysis job's input.gbw; those are the broken-symmetry solution the re-optimization is meant to sit on, so the species adopts them. Gaussian's stable=(rext,noopt) reports an instability without following it, so its checkfile still holds the restricted orbitals, and handing those to an unrestricted SCF returns it to the very solution the analysis rejected -- a restricted solution is a stationary point of the unrestricted equations too. The checkfile is dropped in that case and the job runs guess=mix, whose deliberately symmetry-broken guess is what finds the lower solution. SPAWNING GUARDS. Gaussian and ORCA only, DFT or HF only, the species must still hold the checkfile its own optimization wrote, at most one analysis per species, and an early return on job_types['stability'], which ships False, so a run that does not ask for this changes in no way. The admission gate is `is_ts or job_scf_reference_is_restricted(opt_job) is True` -- a TS always, and any other species whose optimization actually ran on a restricted reference, since an already-unrestricted job has nothing to learn from the test. A job that is not a submitted ESS job carries none of this and is refused, so a pipe task releases the species rather than holding it. Every guard reports why it declined, including the ESS one. A job that ran in an ESS ARC has no reader for is refused with a warning naming the species and that ESS, and saying that ARC implements the analysis for Gaussian and ORCA only -- not that the ESS cannot perform one, which would send the user looking in the wrong place. It is a warning rather than an info line because the other refusals are per-job conditions that leave the feature working elsewhere in the same run, whereas this one means the job type the user switched on will never run for any species that ESS handles. It is emitted once per ESS per run, recorded in Scheduler.stability_unimplemented_ess, since the condition is a property of the run and not of the species that happened to reach it first; a 200-species project therefore gets one line, not 200, and a mixed-ESS project one line per ESS. CONSUMING. check_stability_job parses the verdict, writes it to the species and to output.yml, and logs it: a warning naming the negative root and its eigenvalue for an instability, an info line for a stable verdict. A restricted external instability does not set invalidates_analytic_freq -- but it is not merely 'a statement about the restricted description, not about the Hessian'. A Hessian built from that description inherits its error: it is a correct second derivative of the surface that was computed, but that surface is not the ground state, and near an RHF -> UHF instability onset the restricted surface is spuriously stiff along the bond-stretching coordinate, which for a TS is the reaction coordinate, so the imaginary frequency and the barrier curvature are wrong in a known direction, too large and too high. Running the analysis before the Hessian is what keeps that Hessian from being computed at all. A campaign scan of every geometry-deduplicated restricted-singlet TS, 56 in all, found 12 unstable across 4 of 19 reactions, eigenvalues from -0.015 to -0.064 Hartree. Every one is an RHF -> UHF instability with a triplet negative root; the scan turned up no singlet negative eigenvalue at all. That scan is also why no guess is rejected on the verdict: within one reaction the six unstable geometries share an eigenvalue to seven decimals, so they are one stationary point found six ways, and rejecting would bias rather than filter -- in one reaction the three lowest-energy saddles are the unstable ones and the only stable one is the highest, while in another the unstable ones sit 61 kcal/mol above the stable set. log_open_shell_character_sources reports, per species, what was measured and whether ARC is acting on it. A well found unstable is told in words that ARC is NOT acting on it, why not, and what to declare to act on it. That last part names `number_of_radicals = 2`, not "a number_of_radicals": the code reads a declaration as open-shell character only ABOVE one, so a user who followed generic advice literally with 1 would get a restricted reference and silence. THE PER-JOB REFERENCE RECORDS remain, and their subject is narrower than the sequencing above. record_scf_reference files each completed job's own restricted_used memo under species.scf_references, so it reports what ran rather than what would run now. SCF_REFERENCE_JOB_TYPES maps a job type onto the two terms of an E0: 'sp' supplies the energy, and 'freq' OR the combined 'optfreq' supplies the ZPE. optfreq is not an afterthought -- a guard listing only ['sp', 'freq'] silently drops every combined job, so a species optimised and differentiated in one job records no ZPE reference at all and can never report a mismatch. Reference-agnostic levels are not recorded, because comparing a CBS-QB3 sp against a uwB97XD freq would report a mismatch that does not exist. check_scf_reference_consistency raises a logger.warning naming both references and spelling out E0 = E_elect() + ZPE(), plus a persistent entry in the species' output warnings. What it catches is a pair of jobs composed on either side of some other change to the species' state: an sp resubmitted by troubleshooting, an sp held past its freq, or a species restored from a restart. Its docstring says so rather than describing an adoption as its subject, since a species that adopts a verdict re-optimizes and runs both terms on one reference. A STALE RECORD WAS A REAL SOURCE OF FALSE POSITIVES, and is fixed here. post_freq_actions returns (True, switch_ts): freq_ok is True EVEN WHEN it switched the TS guess, and check_freq_job recorded the reference one statement after switch_ts had deliberately cleared scf_references. The abandoned guess' {'freq': 'restricted'} went straight back in, the next guess' sp then recorded 'unrestricted' against it, and the mismatch warning fired for a guess whose freq had in fact run unrestricted -- landing in output[label]['warnings'], which delete_all_species_jobs does not reset. check_freq_job records only when the geometry survived the check. THE TS SWITCH CARRY RULE. carry_stability_verdict_across_ts_switch keeps an ADOPTED external instability and drops everything else. Keeping it is NOT justified by any claim that an instability is a property of the reaction rather than of one saddle -- the campaign data refutes that: two of the four reactions carrying instabilities have MIXED verdicts across distinct saddles. What justifies keeping it is that carrying it is FREE when it does not apply. Variationally E(UKS) <= E(RKS) with equality if and only if the restricted solution is stable, so if the next guess is in fact stable, forcing it unrestricted returns exactly the restricted energy and costs SCF effort, not accuracy. What it buys is that the next guess is unrestricted from its very FIRST optimization, which is the reference the discovering guess reaches only by being optimized twice: a carried verdict spares the next guess that second optimization and the analysis that would have prompted it. The pending optimization is released at the same point, since switch_ts abandons that job along with the geometry it converged to. What is dropped in every case is the geometry-specific detail -- the negative eigenvector labels and eigenvalues, the relaxed constraints, the lowest eigenvalue and invalidates_analytic_freq all describe the abandoned wavefunction and its Hessian, and no measurement of them exists for the new guess, since stability_analysis_ran stays set across a switch. A carried verdict keeps verdict and restricted, plus measured_on_ts_guess naming the guess it came from and the path of the analysis log it was read from, both of which output.yml reports. 'stable', 'unknown', an internal instability and an external instability of an unrestricted reference are dropped outright: none decides a reference, and carrying one would attribute a bill of health to a geometry never tested. So is a verdict ARC would not adopt because a number_of_radicals was declared -- the declaration decides the reference, and carrying the verdict would promise the next guess a change that is not coming. species.scf_references is cleared outright at a switch, and so is the mixed-reference warning they raised: opt, freq and sp all re-run for the new guess, so the abandoned guess' per-job records describe nothing. The invalid-Hessian and spin-contamination warnings go with them, for the same reason and about the same jobs. THE TWO RECORDS OF A SWITCHED-AWAY GUESS ARE REDUCED TOGETHER. output[label] ['wavefunction_stability'] and the sentence the verdict added to output[label]['info'] are top-level keys that nothing cleared, while delete_all_species_jobs resets output[label]['paths'] at the same switch. So output.yml reported no verdict for the surviving geometry -- it reads the path -- while the end-of-run summary printed the abandoned guess' summary string against it, down to the negative root: 'external_instability (Triplet-A, -0.0642)', naming a geometry that no longer exists. Both are cleared where the species' own verdict is reduced, so the two records say the same thing about the same geometry. THE CALL ORDER INSIDE switch_ts IS NOW PINNED. measured_on_ts_guess is read off species.chosen_ts, so carry_stability_verdict_across_ts_switch has to run BEFORE determine_most_likely_ts_conformer picks the replacement, or the carried verdict is attributed to the guess that had not been measured. Swapping the two left the suite green: the test covering the path mocked determine_most_likely_ts_conformer out entirely, so chosen_ts never moved and the ordering was invisible. The replacement lets the selection actually change chosen_ts and asserts the carried verdict still names the abandoned one, which fails when the two calls are swapped. THE MIXED-REFERENCE CHECK NO LONGER MISSES THE MOST COMMON CONFIGURATION. record_scf_reference was reachable from check_freq_job and check_sp_job only, and when the sp level equals the opt level run_sp_job takes its equal-level branch and calls post_sp_actions directly -- no sp job is submitted and check_sp_job is never reached. So scf_references['sp'] was never written for a single-level run, check_scf_reference_consistency returned at its first guard forever, and reference_mismatch was permanently null. The recording moves into post_sp_actions, which is the one point both paths pass through, and takes the job whose log the energy is actually read from: the sp job where one ran, the optimization job where none did. record_scf_reference takes the key explicitly for that case, since an opt job's type does not say which term of the E0 it supplied. AN INVALIDATED ANALYTIC HESSIAN REACHES THE USER. invalidates_analytic_freq was parsed, recorded and logged, and then reached no output the user reads: the mixed-reference case wrote its message into output[label]['warnings'], which is what carries a warning into output.yml and the run summary, while the invalid-Hessian case wrote only to ['info']. INVALID_ANALYTIC_FREQ_MESSAGE now goes to ['warnings'] alongside it. No job flow changes: nothing is re-run, re-referenced or invalidated, and the frequencies, the ZPE built from them and the E0 built from that are reported as computed, with the warning attached. SPIN CONTAMINATION IS SURFACED WHERE THE ENERGY IS READ. was measured and published in output.yml and compared against nothing: a doublet TS at 1.7488 against a spin-pure 0.75, 133% contamination, passed as 'stable' with invalidates_analytic_freq False and its E0 went to Arkane in silence. check_spin_contamination reads the diagnostic off the log the electronic energy came from and warns, in the log and in the species' output warnings, when the deviation from the spin-pure S(S+1) exceeds MAX_S_SQUARED_DEVIATION = 0.1. The threshold is an ABSOLUTE deviation, not a fraction of the spin-pure value, because a singlet's spin-pure value is zero and the broken-symmetry singlet is exactly the case that most needs reporting. Its size follows from what a deviation means: the nearest contaminant of a state of spin S is the state of spin S+1, whose S(S+1) lies 2S+2, at least 2, above it, so 0.1 is at most a five percent admixture. A converged doublet at 0.7536 and a triplet at 2.0086 stay silent; an adopted broken-symmetry singlet does not, which is the point. A restricted reference prints no and an ESS with no reader for it reports none, and both are passed over rather than reported uncontaminated. Job flow is unchanged here too. A VERDICT IS ACTED ON ONLY WHERE EVERY ADAPTER COMPOSING A TERM OF THE SPECIES' E0 WRITES A SYMMETRY-BROKEN REFERENCE. stability_verdict_can_be_honoured tests the optimization, which supplies the geometry, the frequency job, which supplies the ZPE, and the single point, which supplies the electronic energy, against SYMMETRY_BREAKING_ADAPTERS, skipping a reference-agnostic level, which adoption does not change what is composed for. Acting on a verdict with only some of those adapters writing such a reference moves the geometry and the Hessian onto the broken-symmetry surface and leaves the energy on the restricted one, so the published E0 sums terms from two surfaces and belongs to neither, and the job that composed no symmetry-broken reference records an unrestricted memo for an SCF that converged to the restricted solution, which check_scf_reference_consistency then reads as agreement. Such a verdict is recorded, logged, and reported in the species' output warnings as UNREACHABLE_REFERENCE_MESSAGE, and decides nothing. A run whose optimization, frequency job and single point are all composed by one of those adapters is unaffected. THE TWO SETS ARE STATEMENTS ABOUT ARC'S ADAPTERS AND NOT ABOUT WHAT THE ESSs CAN DO, and are named and documented as such: STABILITY_CAPABLE_ESS and SYMMETRY_BREAKING_CAPABLE_ESS become STABILITY_ANALYSIS_ADAPTERS and SYMMETRY_BREAKING_ADAPTERS, with a module-level docstring saying what each holds. Molpro is the case the distinction matters for: Molpro has a {uhf} program and takes a ROTATE directive that mixes two starting orbitals, which is how a broken-symmetry singlet is requested of it, while ARC's Molpro adapter writes {hf} in every input it composes and spends the unrestricted decision on the u prefix of the correlation method. The log messages and the output warning say that an adapter writes no symmetry-broken reference rather than that an ESS offers none. A DROPPED VERDICT CLEARS stability_analysis_ran, so the TS guess that survives a switch is measured in its turn. The dropped verdict describes a wavefunction that is gone and the next guess is a different saddle, so leaving the flag set would publish that guess' restricted energy with no verdict of its own and nothing to distinguish a guess never measured from one measured stable. A CARRIED verdict keeps the flag set: its reference is already decided, and a fresh analysis of the unrestricted reference the next guess runs on measures a different question than the one that was adopted. A STABILITY JOB THAT DIED WITH ITS ANALYSIS ALREADY PRINTED IS READ FOR THE VERDICT IT PRINTED. The analysis precedes whatever killed the job, so its blocks are complete or absent rather than truncated into a different verdict, and the log is parsed whenever it exists rather than only where the job status is 'done'. Nothing is troubleshooted or re-run on it. UNREACHABLE_REFERENCE_MESSAGE IS STRIPPED ON A TS SWITCH with the other four. The method's own docstring says the two records are reduced together, and this warning was the one left behind: it outlived the guess it described while output[label]['wavefunction_stability'] was set to None on the same pass. It is always safe to strip, and always right to: it is raised only on a verdict stamped REFERENCE_CHANGE_AVAILABLE_KEY False, which adopted_reference_is_unrestricted reads as well, so such a verdict is never one this method carries over -- it is dropped here along with the geometry it was measured on. The next guess is measured in its turn and raises the warning again where its own verdict cannot be honoured. post_sp_actions' docstring now says why its restart-path caller passes no job, rather than leaving the guard reading as an oversight. That branch runs only where sp_level == opt_level, where one job supplied both the geometry and the energy and the two share one SCF reference by construction, so the reference comparison the record feeds has nothing to find; what it costs is a null rather than a false reference_mismatch in output.yml for a restarted single-level project. The one added inline comment in spawn_post_opt_jobs is dropped: the method's docstring already states, at length, that the analysis is the single job spawned there and that everything else waits on its verdict. --- arc/scheduler.py | 993 +++++++++++++++++++++++++- arc/scheduler_test.py | 1578 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 2553 insertions(+), 18 deletions(-) diff --git a/arc/scheduler.py b/arc/scheduler.py index f606976396..6089725675 100644 --- a/arc/scheduler.py +++ b/arc/scheduler.py @@ -36,8 +36,13 @@ TrshError, ) from arc.imports import settings -from arc.job.adapters.common import (all_families_ts_adapters, +from arc.job.adapters.common import (adopted_reference_is_unrestricted, + all_families_ts_adapters, default_incore_adapters, + derived_reference_is_unrestricted, + job_scf_reference_is_restricted, + level_admits_a_broken_symmetry_reference, + REFERENCE_CHANGE_AVAILABLE_KEY, ts_adapters_by_rmg_family, ts_adapters_for_unknown_unimolecular) from arc.job.factory import job_factory @@ -80,6 +85,45 @@ WRONG_FREQ_MESSAGE = 'wrong number of negative frequencies; ' +MIXED_SCF_REFERENCE_MESSAGE = 'the electronic energy and the ZPE were computed with different SCF references; ' +SCF_REFERENCE_JOB_TYPES = {'sp': 'sp', 'freq': 'freq', 'optfreq': 'freq'} + +INVALID_ANALYTIC_FREQ_MESSAGE = 'the wavefunction instability puts the analytic frequencies outside the range in ' \ + 'which they are defined; ' +SPIN_CONTAMINATION_MESSAGE = 'the wavefunction the electronic energy came from is spin-contaminated; ' +COLLAPSED_REFERENCE_MESSAGE = 'the adopted unrestricted reference could not be reached in the ESS the job ran in, ' \ + 'so the energy reported for it is the restricted one; ' +UNREACHABLE_REFERENCE_MESSAGE = 'the restricted reference is not the ground state and a lower symmetry-broken ' \ + 'solution exists, which is the signature of an open-shell singlet, a state no single ' \ + 'determinant describes; it was not adopted because an adapter this species runs in ' \ + 'writes no symmetry-broken reference, and a broken-symmetry reference approximates ' \ + 'such a state rather than describing it, so a multireference treatment (a CASSCF ' \ + 'reference followed by MRCI or CASPT2) is what this species calls for; ' + +MAX_S_SQUARED_DEVIATION = 0.1 + +STABILITY_ANALYSIS_ADAPTERS = {'gaussian', 'orca'} +SYMMETRY_BREAKING_ADAPTERS = {'gaussian', 'orca'} +""" +The two sets above are statements about ARC'S ADAPTERS and not about what the ESSs can do. + +``STABILITY_ANALYSIS_ADAPTERS`` holds the adapters that compose a wavefunction stability +analysis input and whose parser reads the verdict back. Whether an ESS absent from it offers +the analysis at all is a separate question and is not what the set answers. + +``SYMMETRY_BREAKING_ADAPTERS`` holds the adapters that compose a reference an unrestricted SCF +cannot collapse out of, which is an orbital guess taken from a broken-symmetry solution or a +symmetry-breaking directive. An adapter absent from it composes one spin-symmetric determinant +however its ESS is asked, so an unrestricted SCF it writes converges back to the restricted +solution. Molpro is the case worth naming: Molpro itself has a ``{uhf}`` program and takes a +``ROTATE`` directive that mixes two starting orbitals, which is how a broken-symmetry singlet +is requested of it, but ARC's Molpro adapter writes ``{hf}`` in every input it composes and +spends the unrestricted decision on the ``u`` prefix of the correlation method instead. Naming +the orbitals a ``ROTATE`` would mix needs their index and irreducible representation, which +that adapter has neither at the point it writes its input nor a ``nosym`` geometry to make +unambiguous. +""" + def tsg_method_matches_adapter(method: str | None, job_adapter: str | None) -> bool: """ @@ -144,6 +188,7 @@ class Scheduler(object): 'sp': , 'composite': , 'irc': [list of two IRC paths], + 'stability': , }, 'conformers': , 'isomorphism': , @@ -212,6 +257,11 @@ class Scheduler(object): species_dict (dict): Keys are labels, values are :ref:`ARCSpecies ` objects. rxn_list (list): Contains input :ref:`ARCReaction ` objects. unique_species_labels (list): A list of species labels (checked for duplicates). + stability_unimplemented_ess (set): ESS names already reported as having no wavefunction stability + analysis implemented in ARC, reported once per ESS per run. + unbreakable_reference_ess (set): Names of adapters already reported as writing no symmetry-broken + reference, so that an adopted unrestricted reference collapses in + the jobs they compose. Reported once per adapter per run. job_dict (dict): A dictionary of all scheduled jobs. Keys are species / TS labels, values are dictionaries where keys are job names (corresponding to 'running_jobs' if job is running) and values are the Job objects. @@ -365,6 +415,8 @@ def __init__(self, self.irc_level = irc_level self.orbitals_level = orbitals_level self.unique_species_labels = list() + self.stability_unimplemented_ess = set() + self.unbreakable_reference_ess = set() self.save_restart = False if len(self.rxn_list): @@ -651,7 +703,15 @@ def _flush_pending_pipe_conf_sp(self) -> None: def schedule_jobs(self): """ The main job scheduling block + + A species whose post-optimization work was held for a wavefunction stability verdict is + released here when no analysis of its is still running, which is the state a run resumed + after its analysis ended leaves behind: the job it was waiting on is gone, so nothing else + would reach ``spawn_post_stability_jobs`` for it and the species would hold that work for + the rest of the run. A verdict recorded before the interruption still decides what the + release does, and one that never arrived releases the held jobs unchanged. """ + self.release_held_stability_work() for species in self.species_dict.values(): if species.initial_xyz is None and species.final_xyz is None and species.conformers \ and any([e is not None for e in species.conformer_energies]): @@ -853,6 +913,15 @@ def schedule_jobs(self): pass self.timer = False break + elif 'stability' in job_name: + job = self.job_dict[label]['stability'][job_name] + if not (job.job_id in self.server_job_ids and job.job_id not in self.completed_incore_jobs): + self.end_job(job=job, label=label, job_name=job_name) + self.check_stability_job(label=label, job=job) + if job_name not in self.running_jobs[label]: + self.spawn_post_stability_jobs(label=label) + self.timer = False + break elif 'onedmin' in job_name: job = self.job_dict[label]['onedmin'][job_name] if not (job.job_id in self.server_job_ids and job.job_id not in self.completed_incore_jobs): @@ -1118,6 +1187,7 @@ def run_job(self, self.remote_project_paths[job.server] = job.remote_project_path self.check_max_simultaneous_jobs_limit(job.server) job.execute() + self.warn_on_collapsible_unrestricted_reference(label=label, job=job) self.save_restart_dict() def set_scan_resolution(self, args: dict, job_type: str) -> dict: @@ -1186,6 +1256,13 @@ def end_job(self, job: JobAdapter, """ A helper function for checking job status, saving in csv file, and downloading output files if needed. + A completed geometry job hands the species its converged orbitals, which the jobs that + follow read as an initial guess. The file is ESS-specific, a ``check.chk`` for Gaussian + and an ``input.gbw`` for ORCA, and is adopted under the name the job adapter declares. + A zero-byte file is refused: paramiko creates the local file before it opens the remote + one, so a download that failed leaves an empty file behind that ``os.path.isfile`` cannot + tell from a real one, and adopting it would hand every subsequent job an unreadable guess. + Args: job (JobAdapter): The job object. label (str): The species label. @@ -1198,13 +1275,19 @@ def end_job(self, job: JobAdapter, try: job.determine_job_status() # Also downloads the output file. except IOError: - if job.job_type not in ['orbitals']: + if job.job_type not in ['orbitals', 'stability']: logger.warning(f'Tried to determine status of job {job.job_name}, ' f'but it seems like the job never ran. Re-running job.') self._run_a_job(job=job, label=label) if job_name in self.running_jobs[label]: self.running_jobs[label].pop(self.running_jobs[label].index(job_name)) + if job.job_status[1]['status'] == 'errored' and job.job_type == 'stability': + logger.info(f'The wavefunction stability analysis {job.job_name} errored, not re-running it.') + if job_name in self.running_jobs[label]: + self.running_jobs[label].pop(self.running_jobs[label].index(job_name)) + return False + if job.job_status[1]['status'] == 'errored' and job.job_status[1]['keywords'] == ['memory']: original_mem = job.job_memory_gb if 'insufficient job memory' in job.job_status[1]['error'].lower(): @@ -1245,7 +1328,7 @@ def end_job(self, job: JobAdapter, job.job_status[1]['status'] = 'errored' logger.warning(f'Job {job.job_name} errored because for the second time ARC did not find the output ' f'file path {job.local_path_to_output_file}.') - elif job.job_type not in ['orbitals']: + elif job.job_type not in ['orbitals', 'stability']: job.ess_trsh_methods.append('restart_due_to_file_not_found') logger.warning(f'Did not find the output file of job {job.job_name} with path ' f'{job.local_path_to_output_file}. Maybe the job never ran. Re-running job.') @@ -1262,19 +1345,23 @@ def end_job(self, job: JobAdapter, logger.info(f' Ending job {job_name} for {label} (run time: {job.run_time})') if job.job_status[0] != 'done': return False - if job.job_adapter in ['gaussian', 'terachem'] and os.path.isfile(os.path.join(job.local_path, 'check.chk')) \ + check_file_name = job.check_file_name + check_path = os.path.join(job.local_path, check_file_name) + if job.job_adapter in ['gaussian', 'orca', 'terachem'] and os.path.isfile(check_path) \ and job.job_type in ['opt', 'optfreq', 'composite']: - check_path = os.path.join(job.local_path, 'check.chk') - if os.path.isfile(check_path): - if 'directed_scan' in job.job_name and 'cont' in job.directed_scan_type: - folder_name = 'rxns' if job.is_ts else 'Species' - r_path = os.path.join(self.project_directory, 'output', folder_name, job.species_label, 'rotors') - if not os.path.isdir(r_path): - os.makedirs(r_path) - shutil.copyfile(src=check_path, dst=os.path.join(r_path, 'directed_rotor_check.chk')) - self.species_dict[label].checkfile = os.path.join(r_path, 'directed_rotor_check.chk') - elif label in self.output: - self.species_dict[label].checkfile = check_path + if not os.path.getsize(check_path): + logger.info(f'The {check_file_name} of job {job.job_name} is empty, which is what a failed ' + f'download leaves behind. Not adopting it as the checkfile of {label}.') + elif 'directed_scan' in job.job_name and 'cont' in job.directed_scan_type: + folder_name = 'rxns' if job.is_ts else 'Species' + r_path = os.path.join(self.project_directory, 'output', folder_name, job.species_label, 'rotors') + if not os.path.isdir(r_path): + os.makedirs(r_path) + directed_rotor_path = os.path.join(r_path, f'directed_rotor_{check_file_name}') + shutil.copyfile(src=check_path, dst=directed_rotor_path) + self.species_dict[label].checkfile = directed_rotor_path + elif label in self.output: + self.species_dict[label].checkfile = check_path if job.job_type == 'scan' or job.directed_scan_type == 'ess': for rotors_dict in self.species_dict[label].rotors_dict.values(): if rotors_dict['pivots'] in [job.pivots, job.pivots[0]]: @@ -1559,6 +1646,7 @@ def run_sp_job(self, self.post_sp_actions(label=label, sp_path=os.path.join(recent_opt_job.local_path_to_output_file), level=level, + job=recent_opt_job, ) # If opt is not in the job dictionary, the likely explanation is this job has been restarted elif 'geo' in self.output[label]['paths']: # Then just use this path directly @@ -1735,6 +1823,715 @@ def run_orbitals_job(self, label): job_type='orbitals', ) + def run_stability_job(self, + label: str, + opt_job: JobAdapter, + ) -> bool: + """ + Spawn a wavefunction stability analysis job for a TS or for a species that optimized restricted. + + The analysis is spawned from the optimization, before the frequency job, the single point + and the IRC of that species, so the reference every one of them would be computed on is + measured while it can still be changed. Its level comes from the optimization job, its + geometry is the one that optimization converged to, and its orbitals are the ones that + optimization wrote, so its SCF reproduces the wavefunction under test rather than whichever + solution a fresh SCF reaches: without them Gaussian falls back to ``guess=mix``, whose + deliberately symmetry-broken SCF is a different wavefunction, and ORCA converges from its + own initial guess. + + It is spawned at most once per species, recorded on the species as + ``stability_analysis_ran`` so a restart does not spawn a second one, and only where every + one of the following holds: the species is a TS or its optimization declared a restricted + reference, which is the only reference the analysis can inform, since a restricted solution + gives the same energy as an unrestricted one if and only if it is stable; the optimization + is a submitted ESS job, which a pipe task is not; that job's ESS is in + ``STABILITY_ANALYSIS_ADAPTERS``; its level is DFT or Hartree-Fock, the only ones either of those + ESSs offers the analysis for; and the species still holds the checkfile that optimization + wrote, which is ESS-specific, a ``.chk`` for Gaussian and a ``.gbw`` for ORCA. Each refusal + is logged and the caller runs the jobs that follow unchanged. + + A job that ran in an ESS for which ARC has not implemented the analysis is reported as a + warning once per ESS per run, rather than once per species: the condition holds for every + species that ESS runs, so it is a statement about the run and not about the species that + happened to reach it first. + + WHAT THE ANALYSIS IS FOR ON A SPECIES THAT IS NOT A TS, given that it is expected to return + 'stable' nearly every time: well under a few per cent of closed-shell equilibrium + geometries are RHF -> UHF unstable, and a well is not where instabilities are looked for. + Its value is what a 'stable' verdict licenses rather than what an unstable one reports. A + well verified stable has identical restricted and unrestricted energies, so comparing it + against a TS that ARC has made unrestricted is a comparison on one surface rather than + across two; without the verdict that cannot be asserted. It also catches an undeclared + singlet biradical, whose restricted energy is wrong and which nothing else in ARC detects. + + Args: + label (str): The species label. + opt_job (JobAdapter): The optimization job whose wavefunction is tested. + + Returns: bool + Whether a stability analysis job was spawned. + """ + species = self.species_dict[label] + if not self.job_types.get('stability', False) or species.stability_analysis_ran: + return False + job_adapter = getattr(opt_job, 'job_adapter', None) + level = getattr(opt_job, 'level', None) + checkfile = getattr(opt_job, 'local_path_to_check_file', None) + xyz = species.get_xyz(generate=False) + if job_adapter is None or xyz is None: + logger.info(f'Not running a wavefunction stability analysis for {label}: its optimization job is ' + f'not a submitted ESS job, so the wavefunction under test is not reachable.') + return False + if not species.is_ts and job_scf_reference_is_restricted(opt_job) is not True: + logger.info(f'Not running a wavefunction stability analysis for {label}: it is not a transition ' + f'state and its optimization did not declare a restricted reference, which is the ' + f'only reference the analysis can inform.') + return False + if job_adapter not in STABILITY_ANALYSIS_ADAPTERS: + if job_adapter not in self.stability_unimplemented_ess: + self.stability_unimplemented_ess.add(job_adapter) + logger.warning(f'Not running a wavefunction stability analysis for {label}: ARC implements the ' + f'analysis for {", ".join(sorted(STABILITY_ANALYSIS_ADAPTERS))} only, and the ' + f'optimization job ran in {job_adapter}. No stability analysis will run for any ' + f'species whose jobs run in {job_adapter}. This message is reported once per ESS.') + return False + if not level_admits_a_broken_symmetry_reference(level): + logger.info(f'Not running a wavefunction stability analysis for {label}: {job_adapter} offers it for ' + f'DFT and Hartree-Fock levels only, and the optimization job ran at {level}.') + return False + if checkfile is None or not os.path.isfile(checkfile): + logger.info(f'Not running a wavefunction stability analysis for {label}: its optimization job left ' + f'no checkfile to read the tested wavefunction from.') + return False + species_checkfile = species.checkfile + if species_checkfile is None or not os.path.isfile(species_checkfile) \ + or os.path.realpath(species_checkfile) != os.path.realpath(checkfile): + logger.info(f'Not running a wavefunction stability analysis for {label}: the species does not hold ' + f'the checkfile its optimization job wrote.') + return False + self.run_job(label=label, + xyz=xyz, + level_of_theory=level, + job_type='stability', + job_adapter=job_adapter, + ) + species.stability_analysis_ran = True + return True + + def spawn_post_stability_jobs(self, label: str): + """ + Resume the work a wavefunction stability analysis was holding, once its verdict is in. + + ``spawn_post_opt_jobs`` records the optimization job it was called for on the species as + ``stability_pending_opt_job`` and returns without enqueueing anything whenever it spawns a + stability analysis, so that no Hessian, energy or reaction path is computed on a reference + that is still under test. This method is what releases that work, and it is reached for + every stability job that leaves ``running_jobs``, whether it converged, errored or was + never parsed, so a species is not held by an analysis that produced no verdict. + + A verdict ARC acts on, which ``adopted_reference_is_unrestricted`` defines, re-optimizes the + species instead of releasing the held work. The re-optimization runs at the optimization + level, starts from the geometry the first optimization converged to, and is unrestricted, + because ``is_species_restricted`` reads the adopted verdict off the species. Re-optimizing + is what makes an adoption correct: the restricted geometry is a stationary point of the + restricted surface only, so a Hessian computed there on the broken-symmetry reference sits + at a non-stationary point and can report imaginary modes that belong to the mismatch rather + than to the molecule. Its own completion re-enters ``spawn_post_opt_jobs``, which spawns no + second analysis and releases the frequency, single point and IRC onto the geometry and the + reference they belong with. + + AT MOST ONE RE-OPTIMIZATION per species, recorded on the species as + ``stability_reoptimized`` and written to the restart file, so a run resumed between the + analysis and the re-optimization cannot spawn a second one. + + THE ORBITALS THE RE-OPTIMIZATION STARTS FROM are the analysis' own where the ESS relaxed + into the lower solution, which its verdict reports as ``followed_to_stable``, and none + otherwise. ORCA follows an instability it finds and writes the relaxed orbitals to the + analysis job's ``input.gbw``, which is the broken-symmetry solution the re-optimization is + meant to sit on. Gaussian's ``stable=(rext,noopt)`` reports an instability without + following it, so its checkfile still holds the restricted orbitals; handing those to an + unrestricted SCF returns it to the very solution the analysis rejected, since a restricted + solution is a stationary point of the unrestricted equations too. Dropping the checkfile + sends the job to ``guess=mix``, whose deliberately symmetry-broken guess is what finds the + lower solution. + + Args: + label (str): The species label. + """ + species = self.species_dict[label] + job_name = species.stability_pending_opt_job + if job_name is None: + return + species.stability_pending_opt_job = None + if adopted_reference_is_unrestricted(species) and not species.stability_reoptimized: + species.stability_reoptimized = True + self.adopt_stability_orbitals(label=label) + opt_job = self.job_dict.get(label, dict()).get('opt', dict()).get(job_name) + xyz = species.final_xyz or species.initial_xyz + species.initial_xyz = xyz + logger.info(f'Re-optimizing {label} with an unrestricted reference, which its wavefunction stability ' + f'analysis found lower than the restricted one its geometry was optimized on.') + self.run_job(label=label, + xyz=xyz, + level_of_theory=self.opt_level, + job_type='opt', + fine=getattr(opt_job, 'fine', self.job_types['fine']), + ) + return + self.spawn_post_opt_jobs(label=label, job_name=job_name) + + def release_held_stability_work(self, label: str | None = None): + """ + Release the post-optimization work of every species held for an analysis that is not running. + + A species holds a ``stability_pending_opt_job`` from the moment its wavefunction stability + analysis is spawned until ``spawn_post_stability_jobs`` releases it, and both of those are + written to the restart file. A run resumed in between finds the record but not the job, + since a finished job is not restored into ``running_jobs``, so this is what reaches + ``spawn_post_stability_jobs`` for it. A species whose analysis is still queued is left + alone; the main loop reaches it when that job ends. + + Args: + label (str, optional): A single species label to release, or ``None`` for all of them. + """ + labels = [label] if label is not None else list(self.species_dict.keys()) + for spc_label in labels: + species = self.species_dict.get(spc_label) + if species is None or getattr(species, 'stability_pending_opt_job', None) is None \ + or spc_label not in self.output: + continue + if any('stability' in job_name for job_name in self.running_jobs.get(spc_label, list())): + continue + logger.info(f'Releasing the jobs {spc_label} was holding for a wavefunction stability verdict, ' + f'which no running analysis of its will deliver.') + self.spawn_post_stability_jobs(label=spc_label) + + def adopt_stability_orbitals(self, label: str): + """ + Hand a species the orbitals its wavefunction stability analysis relaxed into, or none. + + A verdict reporting ``followed_to_stable`` was measured by an ESS that rotated the unstable + orbitals, re-converged the SCF and reached a stable solution, and wrote that solution to + the analysis job's own orbitals file. That file is the broken-symmetry reference, so it + becomes the species' checkfile and seeds the SCF of the job that follows. Any other verdict + was measured without relaxing anything, so the file the species holds describes the + reference the analysis rejected and is dropped rather than passed on. + + Args: + label (str): The species label. + """ + species = self.species_dict[label] + verdict = species.derived_stability_verdict + checkfile = None + if isinstance(verdict, dict) and verdict.get('followed_to_stable'): + stability_jobs = self.job_dict.get(label, dict()).get('stability', dict()) + for job in stability_jobs.values(): + path = getattr(job, 'local_path_to_check_file', None) + if path is not None and os.path.isfile(path): + checkfile = path + species.checkfile = checkfile + + def stability_verdict_can_be_honoured(self, label: str) -> bool: + """ + Check whether every ESS this species' E0 is built from can be given a broken-symmetry reference. + + Acting on a wavefunction-stability verdict re-optimizes the species and computes its + Hessian and its electronic energy on the lower, symmetry-broken solution. An unrestricted + SCF reaches that solution only from a reference composed to break the spin symmetry, which + the adapters in ``SYMMETRY_BREAKING_ADAPTERS`` compose and the rest do not: an adapter + absent from that set writes one spin-symmetric determinant, whose SCF converges back to + the restricted solution the verdict rejected. A geometry composed by one adapter and an + energy by another is the standard arrangement, so a verdict adopted with only the first of + them composing a symmetry-broken reference moves the geometry and the Hessian onto the + lower solution and leaves the energy on the restricted one, and the E0 the run publishes + sums terms from two surfaces rather than being the lower solution's E0 or the restricted + one's. The job that could not compose the reference also records an unrestricted memo for + an SCF that reached the restricted solution, which ``check_scf_reference_consistency`` + then reads as agreement. + + The three levels tested are the ones those terms come from: the optimization, which + supplies the geometry, the frequency job, which supplies the ZPE, and the single point, + which supplies the electronic energy. A job type the run does not compute is not tested, + and a species whose single point runs at its optimization level tests that one level twice + rather than none. + + A LEVEL AN ADOPTED VERDICT DOES NOT REACH IS NOT TESTED, since its adapter is asked for no + symmetry-broken reference and so can neither honour a verdict nor fail to. Two kinds of + level are outside the verdict's reach. A reference-agnostic one, for which ARC writes no + reference prefix at all, is one; a correlated wavefunction level, whose energy is an + expansion about a spin-adapted reference rather than the energy of that reference, is the + other, and ``level_admits_a_broken_symmetry_reference`` tells both from the levels a + verdict does decide. A single point at a correlated level therefore keeps its restricted + reference in every adapter alike, and what it costs is a mismatch against the ZPE rather + than a collapse, which ``check_scf_reference_consistency`` reports. + + What this reports is that every level the verdict does reach is composed by an adapter + writing a symmetry-broken reference; anything less is reported as not honourable and the + verdict is measured and logged without being acted on. + + Args: + label (str): The species label. + + Returns: bool + Whether adopting the verdict would give this species one reference throughout. + """ + job_types_and_levels = [('opt', self.opt_level)] + if self.job_types.get('freq', False): + job_types_and_levels.append(('freq', self.freq_level)) + if self.job_types.get('sp', False): + job_types_and_levels.append(('sp', self.sp_level)) + for job_type, level in job_types_and_levels: + if level is None: + continue + level = Level(repr=level) + if not level_admits_a_broken_symmetry_reference(level): + continue + job_adapter = self.deduce_job_adapter(level=level, job_type=job_type) + if job_adapter not in SYMMETRY_BREAKING_ADAPTERS: + logger.info(f'The wavefunction stability verdict of {label} cannot be acted on: its {job_type} job ' + f'is composed by the {job_adapter} adapter, which writes no symmetry-broken reference, ' + f'so the {job_type} of an adopted verdict would converge to the restricted solution ' + f'while the rest of the species ran on the broken-symmetry one.') + return False + return True + + def warn_on_collapsible_unrestricted_reference(self, + label: str, + job: JobAdapter, + ): + """ + Report a job running an adopted unrestricted reference its adapter cannot keep from collapsing. + + A species carrying an adopted wavefunction-stability verdict runs every job that follows + it unrestricted, and an unrestricted SCF started from a spin-symmetric guess converges, in + all but pathological cases, back to the restricted solution the verdict rejected: a + restricted solution is a stationary point of the unrestricted equations too, so a + gradient-following SCF sits on it. The job then reports the restricted energy under an + unrestricted label, which is the energy the analysis found a lower solution than. + + TWO MECHANISMS PREVENT THAT, and the adapters in ``SYMMETRY_BREAKING_ADAPTERS`` write them: + an orbital guess taken from the broken-symmetry solution, which is Gaussian's + ``guess=read`` and ORCA's ``!MORead``, and a symmetry-breaking directive that needs no + guess, which is Gaussian's ``guess=mix`` and ORCA's ``BrokenSym``. Those two adapters + write whichever of the pair the job admits. + + EVERY OTHER ADAPTER WRITES NEITHER. An adopted verdict was measured by an optimization + composed by one of the adapters in ``STABILITY_ANALYSIS_ADAPTERS``, so whatever + broken-symmetry orbitals a later job could start from were written in that ESS's own + format; a third adapter writes no keyword that reads them, and no symmetry-breaking + directive either. Whether its ESS could be asked for one is a separate question: this + reports what ARC composes. The standard arrangement of a geometry from one adapter and an + energy from another is exactly where this lands, and what it costs is the electronic + energy the run publishes. + + WHAT REACHES THIS AT ALL. A verdict is adopted only where the adapters composing every + level of the species the verdict decides write a symmetry-breaking reference, which + ``stability_verdict_can_be_honoured`` decides, so the geometry, the Hessian and an + electronic energy at such a level do not reach this. An electronic energy at a correlated + level does not either: the verdict decides no reference there, so the job composes a + restricted one and is not a collapse. What does reach this is a job type that decision + does not cover, the IRC and the rotor scans of an adopted species, composed at a level + whose adapter writes neither mechanism. + + WHAT IS REPORTED WHERE. The species' output warnings carry + ``COLLAPSED_REFERENCE_MESSAGE``, once per species, so ``output.yml`` names every species + the condition was reached for rather than only the first. The log carries the full + message once per adapter per run, as ``run_stability_job`` reports an adapter with no + analysis implemented, since the statement is the same for every species that adapter + composes a job for. + + WHAT THIS DOES NOT REACH. The ESS name is what decides whether a mechanism exists, so a + Gaussian job whose SCF troubleshooting replaced its guess keyword with ``guess=INDO`` + carries neither ``guess=read`` nor ``guess=mix`` and is not reported. A single point + batched through the pipe is spawned by the pipe planner rather than by ``run_job``, and is + not reported either. + + Args: + label (str): The species label. + job (JobAdapter): The job that was spawned. + """ + species = self.species_dict.get(label) if isinstance(label, str) else None + job_adapter = getattr(job, 'job_adapter', None) + if species is None or job_adapter is None \ + or job_adapter in SYMMETRY_BREAKING_ADAPTERS \ + or not adopted_reference_is_unrestricted(species) \ + or job_scf_reference_is_restricted(job) is not False: + return + if label in self.output and COLLAPSED_REFERENCE_MESSAGE not in self.output[label]['warnings']: + self.output[label]['warnings'] += COLLAPSED_REFERENCE_MESSAGE + if job_adapter in self.unbreakable_reference_ess: + return + self.unbreakable_reference_ess.add(job_adapter) + job_name = getattr(job, 'job_name', None) + logger.warning(f'Job {job_name or "of an unnamed adapter"} of {label} runs in {job_adapter} with the ' + f'unrestricted reference its wavefunction stability analysis found lower than the ' + f'restricted one, and ARC offers {job_adapter} neither of the two ways of reaching that ' + f'reference: it writes a symmetry-breaking directive for ' + f'{" and ".join(sorted(SYMMETRY_BREAKING_ADAPTERS))} only, and whatever ' + f'broken-symmetry orbitals {label} holds were written in the format of the ESS that ran ' + f'its optimization, which {job_adapter} does not read. This SCF starts spin-symmetric and ' + f'converges to the restricted solution the analysis rejected, so the energy it reports is ' + f'the restricted one. Running the affected job types of {label} in ' + f'{" or ".join(sorted(SYMMETRY_BREAKING_ADAPTERS))} is what reaches the lower solution. ' + f'This message is reported once per ESS.') + + def check_stability_job(self, + label: str, + job: JobAdapter, + ): + """ + Parse and record the verdict of a wavefunction stability analysis job. + + Stores a summary of the verdict under the species' output entry, where the run summary + reads it, stores the structured verdict together with the path of the log it was read + from on the species object, where the reference decision reads it, and logs it. A job + that left no log, and a log holding no stability analysis, record nothing. Nothing here + is troubleshooted or re-run: a job that died with its analysis already printed is read + for the verdict it printed, since the analysis precedes whatever killed it and its + blocks are complete or absent rather than truncated into a different verdict. + + A verdict calling for an unrestricted reference is stamped with whether the ESSs this + species runs in can be given one, which ``stability_verdict_can_be_honoured`` decides + and ``adopted_reference_is_unrestricted`` reads. A verdict that cannot be honoured is + recorded, logged and reported in the species' output warnings as + ``UNREACHABLE_REFERENCE_MESSAGE``, and decides nothing. + + A verdict that invalidates the analytic frequencies also writes + ``INVALID_ANALYTIC_FREQ_MESSAGE`` into the species' output warnings, which is what + carries it into ``output.yml`` and into the run summary. Nothing is re-run on it: the + frequencies, the ZPE they give and the E0 built from them are reported as they were + computed, with the warning attached. + + A verdict already on the species, which can only be one carried over from an abandoned + TS guess, is replaced by the one parsed here: a measurement on the live geometry + supersedes one carried from a geometry that is gone. + + An instability is logged as a warning and a stable wavefunction as an info message, + and a verdict carrying a negative stability-matrix root also reports that root's + label and eigenvalue, which name the perturbation the wavefunction broke along and + how far. + + Whether an instability bears on the validity of the analytic frequencies depends on + the reference. Gaussian's rule, which both ESS readers apply so that the same physical + situation gets the same answer whichever ESS measured it, is that for a restricted + wavefunction it suffices that no singlet (internal) instability exists, while for an + unrestricted one any instability, internal or external, invalidates them. Neither ESS + computes a spin-flip root for an unrestricted reference, so both readers report an + undetermined ``external_instability`` there and the external half of that rule is + never reached: a stable verdict on an unrestricted reference covers the spin-conserving + sector alone, which is the sector the analytic Hessian is taken in. So the + frequency-validity warning is raised for an internal instability of either reference, + and additionally for an external instability of an unrestricted one. An instability + whose sector the ESS did not report leaves the question undetermined rather than + answered either way, and is warned about as such. An external instability of a + restricted reference is reported without that warning: a lower symmetry-broken + solution exists, which for a TS with stretched partial bonds is expected, and the + analytic Hessian remains a correct second derivative of the surface that was + computed. That surface is not the ground state, though. Near an RHF -> UHF + instability onset the restricted surface is spuriously stiff along the + bond-stretching coordinate, which for a TS is the reaction coordinate, so the + imaginary frequency and the barrier curvature are wrong in a known direction, + too large and too high. + + Adopting the verdict replaces one biased number with another rather than with the right + one. A broken-symmetry solution is not a spin eigenfunction: it is contaminated by the + higher multiplicity it mixes in, so its energy lies ABOVE the spin-pure low-spin energy, + and the restricted energy it replaces lies above the broken-symmetry one in turn. The + ordering is E_projected < E_BS < E_restricted, so adoption is a step toward the spin-pure + energy that stops short of it, and the residual error keeps the sign and direction it had + before. ARC does not project the contamination out. ``arc/checks/spin.py`` holds the + Yamaguchi approximate spin-projection arithmetic that estimates the projected energy from + the broken-symmetry and high-spin energies and their ``S**2`` values. + + A spin contamination larger than ``MAX_S_SQUARED_DEVIATION`` is warned about where the + electronic energy is read, in ``check_spin_contamination``, and not here: the analysis + log this verdict comes from describes the wavefunction that was tested, or for an ESS + that follows an instability the solution it relaxed into, and neither is the wavefunction + the published energy belongs to. + + Args: + label (str): The species label. + job (JobAdapter): The stability analysis job object instance. + + Returns: + None + """ + if not os.path.isfile(job.local_path_to_output_file): + logger.info(f'The wavefunction stability analysis for {label} left no log, ' + f'no verdict was recorded.') + return + try: + result = parser.parse_wavefunction_stability(log_file_path=str(job.local_path_to_output_file)) + except Exception as e: + logger.info(f'Could not read the wavefunction stability analysis for {label} from ' + f'{job.local_path_to_output_file}: {e.__class__.__name__}: {e}') + return + if result is None: + logger.info(f'Could not parse a wavefunction stability verdict for {label} from ' + f'{job.local_path_to_output_file}.') + return + verdict, restricted = result['verdict'], result['restricted'] + self.species_dict[label].derived_stability_verdict = dict(result, log=job.local_path_to_output_file) + if derived_reference_is_unrestricted(self.species_dict[label]) \ + and not self.stability_verdict_can_be_honoured(label=label): + self.species_dict[label].derived_stability_verdict[REFERENCE_CHANGE_AVAILABLE_KEY] = False + if UNREACHABLE_REFERENCE_MESSAGE not in self.output[label]['warnings']: + self.output[label]['warnings'] += UNREACHABLE_REFERENCE_MESSAGE + self.output[label]['paths']['stability'] = job.local_path_to_output_file + self.output[label]['job_types']['stability'] = True + relaxations = ', '.join(result['relaxations']) or 'an external relaxation' + negative_eigenvectors = result['negative_eigenvectors'] + detail, summary = '', verdict + if negative_eigenvectors: + root = min(negative_eigenvectors, key=lambda eigenvector: eigenvector['eigenvalue']) + root_label = root['label'] or 'an unlabelled root' + detail = f" Its lowest negative stability-matrix root is {root_label} at " \ + f"{root['eigenvalue']:.4f} Hartree." + summary = f"{verdict} ({root_label}, {root['eigenvalue']:.4f})" + if verdict == 'internal_instability': + logger.warning(f'The wavefunction of {label} has an internal instability, so its analytic ' + f'frequencies are outside the range in which they are defined.{detail}') + elif verdict == 'external_instability' and restricted is False: + logger.warning(f'The unrestricted wavefunction of {label} has an instability ({relaxations}), ' + f'so its analytic frequencies are outside the range in which they are ' + f'defined.{detail}') + elif verdict == 'external_instability': + logger.warning(f'The restricted wavefunction of {label} has an external instability ' + f'({relaxations}): a lower symmetry-broken solution exists, so the restricted ' + f'reference is not the ground state.{detail}') + elif verdict == 'unattributed_instability': + logger.warning(f'The wavefunction of {label} is unstable, but the ESS did not report which ' + f'sector the instability lies in, so whether its analytic frequencies remain ' + f'valid and whether a lower symmetry-broken solution exists are both ' + f'undetermined.{detail}') + elif verdict == 'unknown': + logger.info(f'A wavefunction stability analysis ran for {label} but reported no verdict ' + f'that ARC could read.') + else: + logger.info(f'The wavefunction of {label} is stable under the perturbations considered.') + if result['invalidates_analytic_freq'] \ + and INVALID_ANALYTIC_FREQ_MESSAGE not in self.output[label]['warnings']: + self.output[label]['warnings'] += INVALID_ANALYTIC_FREQ_MESSAGE + self.output[label]['wavefunction_stability'] = summary + self.output[label]['info'] += f'Wavefunction stability: {summary}; ' + self.log_open_shell_character_sources(label=label, verdict=verdict, restricted=restricted) + if not self.testing: + self.save_restart_dict() + + def log_open_shell_character_sources(self, + label: str, + verdict: str, + restricted: bool | None, + ): + """ + Log how a species' declared open-shell character and its measured stability verdict stand to each other. + + A user-declared ``number_of_radicals`` always decides the reference and is never + overwritten here, so a conflict with the measured verdict is reported and nothing + else. When the user declared nothing and the verdict calls for an unrestricted + reference, that verdict is what subsequent jobs for a transition state will run on, + and that adoption is logged as such; for any other species, and for a transition state + whose verdict no ESS of the run can be given a symmetry-broken reference for, the + verdict is reported as measured but not acted on, together with what would let it be + acted on. Every branch logs; none raises. + + Args: + label (str): The species label. + verdict (str): The stability verdict that was parsed. + restricted (bool | None): Whether the tested wavefunction used a restricted reference. + + Returns: + None + """ + species = self.species_dict[label] + number_of_radicals, multiplicity = species.number_of_radicals, species.multiplicity + reference = 'restricted' if restricted else 'unrestricted' if restricted is False else 'unreadable' + if number_of_radicals is not None: + if multiplicity == 1 and number_of_radicals > 1 and verdict == 'stable': + logger.warning(f'{label} was declared with number_of_radicals = {number_of_radicals} at ' + f'multiplicity {multiplicity}, i.e. as a broken-symmetry biradical singlet, but its ' + f'wavefunction stability analysis reports its {reference} wavefunction stable under ' + f'the perturbations considered. The declared broken-symmetry character is not ' + f'supported by the calculation. The declared value is the one ARC uses.') + elif number_of_radicals <= 1 and derived_reference_is_unrestricted(species): + logger.warning(f'{label} was declared with number_of_radicals = {number_of_radicals}, which asks ' + f'for a restricted reference, but its wavefunction stability analysis reports an ' + f'external instability of that reference, i.e. a lower symmetry-broken solution ' + f'exists. The declared value is the one ARC uses.') + return + if derived_reference_is_unrestricted(species) and not species.is_ts: + logger.warning(f'The wavefunction stability analysis of {label} reports an external instability of its ' + f'restricted reference, so its restricted energy is above the lower symmetry-broken ' + f'solution. ARC reports this and does not act on it: {label} is not a transition state, ' + f'its geometry and Hessian were already computed on the restricted reference, and ' + f'changing reference for the jobs that follow would give it an E0 summing an energy and ' + f'a zero-point correction from two different surfaces. Declare ' + f'number_of_radicals = 2 for {label}, which is the smallest declaration ARC reads as ' + f'open-shell character, to run it unrestricted throughout.') + return + if derived_reference_is_unrestricted(species) and not adopted_reference_is_unrestricted(species): + logger.warning(f'The wavefunction stability analysis of {label} reports an external instability of its ' + f'restricted reference, so its restricted energy is above the lower symmetry-broken ' + f'solution. ARC reports this and does not act on it: an adapter composing the geometry, ' + f'the Hessian or the electronic energy of {label} writes no symmetry-broken reference, ' + f'so an adopted verdict would move part of {label} onto that solution and leave the ' + f'rest on the restricted one. Running the optimization, the frequency job and the ' + f'single point of {label} all in ' + f'{" or ".join(sorted(SYMMETRY_BREAKING_ADAPTERS))} is what lets the verdict be acted ' + f'on.') + return + if adopted_reference_is_unrestricted(species): + logger.warning(f'No number_of_radicals was declared for {label} and its wavefunction stability ' + f'analysis reports an external instability of its restricted reference, so ARC is ' + f'adopting that verdict: subsequent jobs for {label} run unrestricted. Its already ' + f'completed jobs keep the reference they ran with.') + + def record_scf_reference(self, + label: str, + job: JobAdapter, + reference_key: str | None = None, + ): + """ + Record which SCF reference a completed job declared in the input it ran. + + Only the two job types an E0 is built from are recorded, under the two keys + SCF_REFERENCE_JOB_TYPES maps them to: 'sp', which supplies the electronic energy, and + 'freq' or the combined 'optfreq', which supply the ZPE. Every other job type decides + neither term, so recording it would compare references that are never summed. + + ``reference_key`` names the term the job supplies where the job type does not say it. + A species whose sp level equals its opt level runs no sp job at all and reads its + electronic energy out of the optimization's log, so it is the opt job that supplied + the energy and its memo is recorded under 'sp'. Without that the most common + single-level configuration would record no energy reference at all, and the + mixed-reference check would have nothing to compare for the whole run. + + The value is read off the job adapter's own memo of the decision it made while writing + that input, not recomputed, so a species whose reference decision changed after the job + ran still reports what the job did. Jobs whose level carries no reference prefix, the + force field, composite and semiempirical methods, are not recorded: their 'restricted' + flag is not a reference choice ARC made, and comparing it against a DFT job's would + report a mismatch that does not exist. Anything that is not a submitted ESS job, pipe + tasks among them, carries no memo and is skipped. + + Args: + label (str): The species label. + job (JobAdapter): The completed job object. + reference_key (str, optional): The term the job supplied, 'sp' or 'freq'. Taken + from the job type when not given. + + Returns: + None + """ + restricted = job_scf_reference_is_restricted(job) + reference_key = reference_key or SCF_REFERENCE_JOB_TYPES.get(getattr(job, 'job_type', None)) + if restricted is None or reference_key is None: + return + species = self.species_dict[label] + if not isinstance(species.scf_references, dict): + species.scf_references = dict() + species.scf_references[reference_key] = 'restricted' if restricted else 'unrestricted' + self.check_scf_reference_consistency(label=label) + + def check_scf_reference_consistency(self, label: str): + """ + Warn when a species' electronic energy and its ZPE were computed on different SCF references. + + Its E0 is then the sum of an energy and a zero-point correction taken from two different + potential energy surfaces, so it is not a point on either of them. ARC does not re-run the + species, so the mismatch is reported in the log, in the species' output warnings and in + output.yml, and nothing is invalidated. + + AN ADOPTED STABILITY VERDICT REACHES THIS CHECK THROUGH ITS SINGLE POINT. The verdict + decides the reference of the levels a broken-symmetry one describes, which + ``level_admits_a_broken_symmetry_reference`` defines, so a species whose freq is a DFT one + and whose sp is a correlated wavefunction one takes the broken-symmetry reference for its + ZPE and keeps the spin-adapted one for its electronic energy. That is the mismatch this + reports, and the alternative it is chosen over is a correlated energy expanded about a + symmetry-broken reference, which is a worse number reported by a quieter run. A species + whose freq and sp are both at levels the verdict decides, and one whose sp is at its own + DFT level, run on one reference throughout and are not reported. + + What reaches this check besides is a pair of jobs composed on either side of some other + change to the species' state: an sp resubmitted by troubleshooting, an sp deferred past its + freq, or a species restored from a restart. + + Args: + label (str): The species label. + """ + references = self.species_dict[label].scf_references + references = references if isinstance(references, dict) else dict() + sp_reference, freq_reference = references.get('sp'), references.get('freq') + if sp_reference is None or freq_reference is None or sp_reference == freq_reference: + return + logger.warning(f'The single-point energy of {label} was computed with a {sp_reference} reference while its ' + f'ZPE came from a {freq_reference} frequency job. E0 = E_elect({sp_reference}) + ' + f'ZPE({freq_reference}) mixes two potential energy surfaces and is not a point on either. ' + f'Re-running {label} entirely under one reference is what would remove the mismatch; ARC ' + f'does not do so, and reports it here instead.') + if MIXED_SCF_REFERENCE_MESSAGE not in self.output[label]['warnings']: + self.output[label]['warnings'] += MIXED_SCF_REFERENCE_MESSAGE + + def check_spin_contamination(self, + label: str, + sp_path: str | None, + ): + """ + Warn when the wavefunction the electronic energy came from is spin-contaminated. + + The ```` of an unrestricted determinant exceeds the spin-pure ``S(S+1)`` of the + state it is meant to describe by the weight of the higher multiplicities mixed into + it, so the deviation between the two IS the contamination. An energy carrying it is + not the energy of the state ARC reports it for, and it reaches the thermo and the + rates unchanged: nothing here re-runs the job, changes its reference or projects the + contamination out. The species' output warnings and the log are where it is reported. + + ``MAX_S_SQUARED_DEVIATION`` is the largest deviation reported without a warning. It is + an absolute deviation rather than a fraction of the spin-pure value because a singlet's + spin-pure value is zero, and the broken-symmetry singlet is exactly the case that most + needs reporting, so a fraction is undefined where it matters most. Its size follows + from what a deviation means: the nearest contaminant of a state of spin S is the state + of spin S+1, whose ``S(S+1)`` lies ``2S+2``, at least 2, above it, so a deviation of + 0.1 is at most a five percent admixture of that state. Below it an unrestricted energy + and the Hessian taken at it are customarily used as the state's own. + + A restricted reference prints no ````, and an ESS with no reader for it reports + none either, so both are passed over rather than reported uncontaminated. + + Args: + label (str): The species label. + sp_path (str | None): The path to the log the electronic energy was read from. + + Returns: + None + """ + if not sp_path or not os.path.isfile(sp_path): + return + try: + diagnostic = parser.parse_s_squared(sp_path) + except Exception as e: + logger.debug(f'Could not read an spin diagnostic for {label} from {sp_path}: ' + f'{e.__class__.__name__}: {e}') + return + if diagnostic is None or diagnostic.get('s_squared') is None: + return + s_squared = diagnostic['s_squared'] + expected = parser.s_squared_expected_from_multiplicity(self.species_dict[label].multiplicity) + if expected is None: + expected = diagnostic.get('s_squared_expected') + if expected is None: + return + deviation = s_squared - expected + if deviation <= MAX_S_SQUARED_DEVIATION: + return + logger.warning(f'The wavefunction the electronic energy of {label} was read from has an of ' + f'{s_squared}, {deviation} above the {expected} of a spin-pure state of multiplicity ' + f'{self.species_dict[label].multiplicity}. That energy is the energy of a mixture of ' + f'spin states rather than of the state {label} is reported as, and ARC reports it ' + f'unprojected. See {sp_path}.') + if SPIN_CONTAMINATION_MESSAGE not in self.output[label]['warnings']: + self.output[label]['warnings'] += SPIN_CONTAMINATION_MESSAGE + def run_onedmin_job(self, label): """ Spawn a lennard-jones calculation using OneDMin. @@ -1757,6 +2554,16 @@ def spawn_post_opt_jobs(self, """ Spawn additional jobs after opt has converged. + A wavefunction stability analysis, where ``run_stability_job`` finds the species eligible + for one, is the single job spawned from here and everything else waits for its verdict: + the frequency job, the single point, the IRC and the rotor scans all inherit the SCF + reference and the geometry of the optimization, so computing them before the reference is + measured spends them on a surface that may be about to change. The optimization job's name + is recorded on the species as ``stability_pending_opt_job`` before the analysis is spawned, + so that a run interrupted between the two finds the record in its restart file, and + ``spawn_post_stability_jobs`` re-enters this method with it once the verdict is in. The + analysis runs at most once per species, so the re-entry spawns none and proceeds. + Args: label (str): The species label. job_name (str): The opt job name (used for differentiating between ``opt`` and ``optfreq`` jobs). @@ -1773,6 +2580,13 @@ def spawn_post_opt_jobs(self, self.run_opt_job(label, fine=self.fine_only) return None + if label in self.output.keys() and not composite: + opt_job = self.job_dict.get(label, dict()).get('opt', dict()).get(job_name) + self.species_dict[label].stability_pending_opt_job = job_name + if opt_job is not None and self.run_stability_job(label=label, opt_job=opt_job): + return None + self.species_dict[label].stability_pending_opt_job = None + # Enqueue IRC if requested and if relevant (deferred for pipe batching). if label in self.output.keys() and self.job_types['irc'] and self.species_dict[label].is_ts: self._pending_pipe_irc.add((label, 'forward')) @@ -2769,6 +3583,13 @@ def check_freq_job(self, Check that a freq job converged successfully. Also checks (QA) that no imaginary frequencies were assigned for stable species, and that exactly one imaginary frequency was assigned for a TS. + The SCF reference this job declared is recorded only if its geometry survives the check. A + TS whose normal mode displacement fails is switched to a different guess inside + ``post_freq_actions``, which clears the per-job reference records of the abandoned guess + along with everything else that described it; recording afterwards would write one of them + straight back, and the next guess' sp job would then be compared against the reference of a + geometry that is gone. + Args: label (str): The species label. job (JobAdapter): The frequency job object instance. @@ -2778,7 +3599,9 @@ def check_freq_job(self, if not os.path.isfile(job.local_path_to_output_file): raise SchedulerError('Called check_freq_job with no output file') vibfreqs = parser.parse_frequencies(log_file_path=str(job.local_path_to_output_file)) - freq_ok, _ = self.post_freq_actions(label=label, job=job, vibfreqs=vibfreqs) + freq_ok, switched_ts = self.post_freq_actions(label=label, job=job, vibfreqs=vibfreqs) + if freq_ok and not switched_ts: + self.record_scf_reference(label=label, job=job) if not freq_ok: if not self.species_dict[label].is_ts and self.trsh_ess_jobs: # Only trsh neg freq here for non TS species, trsh TS species is done in check_negative_freq(). @@ -3011,6 +3834,113 @@ def check_rxn_e0_by_spc(self, label: str): # check_all_done reads this to avoid overwriting convergence back to True. self.species_dict[rxn.ts_label].ts_checks['E0'] = False + def carry_stability_verdict_across_ts_switch(self, label: str): + """ + Reduce a TS's stability verdict to what still holds once its geometry is abandoned. + + An adopted external instability is kept, and it is kept because carrying it is cheap rather + than because it is known to transfer. Distinct saddles of one reaction do NOT always agree: + the campaign behind this feature found one reaction whose three lowest-energy saddles are + unstable while its only stable one is the highest, and another whose unstable saddles sit + 61 kcal/mol above its stable ones. What makes carrying it safe is that forcing an + unrestricted reference on a guess that is in fact stable costs nothing but SCF effort: a + stable restricted solution IS the unrestricted minimum, so E(UKS) = E(RKS) exactly there. + What it buys is that the next guess is unrestricted from its very first optimization, + which is the reference the discovering guess reached only by being optimized a second + time: a carried verdict spares the next guess that second optimization and the analysis + that would have prompted it. Every other verdict is dropped rather than carried: a + 'stable', 'unknown' or internal-instability verdict has no consumer, and leaving it would + attribute a bill of health to a geometry that was never tested. A verdict ARC would not + act on is dropped too, so a TS whose user declared a ``number_of_radicals`` carries + nothing: the declaration decides its reference, and carrying a verdict that will never be + adopted would promise the next guess a reference change that is not coming. + + DROPPING A VERDICT CLEARS ``stability_analysis_ran`` with it, so the surviving guess is + measured in its turn. The dropped verdict describes a wavefunction that is gone, and the + next guess comes from a different search and is a different saddle: leaving the flag set + would have ARC publish that guess' restricted energy with no verdict of its own and + nothing to say whether it was measured stable or never measured at all. + + The geometry-specific detail is dropped in either case. The negative-eigenvector labels + and eigenvalues, and whether the analytic frequencies are invalidated, all describe the + abandoned wavefunction and its Hessian, and no measurement of them exists for the new + guess: a CARRIED verdict keeps ``stability_analysis_ran`` set, so no second analysis runs + for the guess it is carried to and the carried verdict is never contradicted by a later + one. Its reference is already decided, and a fresh analysis of the unrestricted reference + the next guess runs on measures a different question than the one that was adopted. The + guess the carried verdict was measured on is recorded alongside it. + + THE RELAXED CONSTRAINTS ARE CARRIED, unlike the rest of the detail, because they name the + CLASS of the instability rather than its size at one geometry, and that class is what the + reference decision reads: a relaxation of the spin constraint calls for a symmetry-broken + determinant, which ``derived_instability_breaks_spin_symmetry`` reports and the ORCA + adapter acts on, while a relaxation of the reality of the orbitals calls for a reference + ARC does not write. Dropping them would leave the surviving guess carrying a verdict whose + class is unknown, which is read as no evidence of broken-symmetry character at all. + + The per-job SCF reference records are cleared outright, and so is any mixed-reference + warning they raised: opt, freq and sp all re-run for the new guess, so the references of + the abandoned guess' jobs describe nothing and a warning about them would outlive its + subject in the species' permanent output entry. The invalid-Hessian and spin-contamination + warnings go with them, for the same reason and about the same jobs. The optimization job + whose post-opt work an analysis was holding is released too, since ``switch_ts`` abandons + that job along with the geometry it converged to. + + The unreachable-reference warning is cleared with them, and it is always cleared. It is + raised only on a verdict stamped ``REFERENCE_CHANGE_AVAILABLE_KEY`` ``False``, which + ``adopted_reference_is_unrestricted`` reads as well, so such a verdict is never one this + method carries over: it is dropped here along with the geometry it was measured on, and + the warning would otherwise name a reference change the surviving guess was never offered. + The next guess is measured in its turn and raises the warning again where its own verdict + cannot be honoured. + + THE TWO RECORDS ARE REDUCED TOGETHER. The verdict summary the run summary prints, and the + sentence it added to the species' info, describe the abandoned geometry down to the + stability-matrix root, so they are cleared alongside the detail this drops from the species + object. ``delete_all_species_jobs`` resets the stability path the same switch, so leaving + them would have ``output.yml`` report no verdict for the surviving geometry while the run + summary printed the abandoned guess' root against it. The log the carried verdict was read + from stays with it, so a carried decision still names the analysis that made it. + + Args: + label (str): The TS species label. + + Returns: + None + """ + species = self.species_dict[label] + species.scf_references = dict() + species.stability_pending_opt_job = None + for message in [MIXED_SCF_REFERENCE_MESSAGE, INVALID_ANALYTIC_FREQ_MESSAGE, SPIN_CONTAMINATION_MESSAGE, + COLLAPSED_REFERENCE_MESSAGE, UNREACHABLE_REFERENCE_MESSAGE]: + if message in self.output[label]['warnings']: + self.output[label]['warnings'] = ''.join(self.output[label]['warnings'].split(message)) + summary = self.output[label].get('wavefunction_stability') + if summary: + fragment = f'Wavefunction stability: {summary}; ' + self.output[label]['info'] = ''.join(self.output[label]['info'].split(fragment)) + self.output[label]['wavefunction_stability'] = None + verdict = species.derived_stability_verdict + if not isinstance(verdict, dict): + species.stability_analysis_ran = False + return + if not adopted_reference_is_unrestricted(species): + logger.info(f'Dropping the wavefunction stability verdict of {label}, which was measured on the TS ' + f'guess being abandoned and does not decide the reference of the next one. The next ' + f'guess is measured in its turn.') + species.derived_stability_verdict = None + species.stability_analysis_ran = False + return + species.derived_stability_verdict = {'verdict': verdict['verdict'], + 'restricted': verdict['restricted'], + 'relaxations': verdict.get('relaxations') or list(), + 'measured_on_ts_guess': species.chosen_ts, + 'log': verdict.get('log'), + } + logger.info(f'Carrying the external instability found for {label} over to its next TS guess, without the ' + f'stability-matrix detail of the abandoned geometry: the next guess runs unrestricted from ' + f'its first job.') + def switch_ts(self, label: str): """ Try the next optimized TS guess in line if a previous TS guess was found to be wrong. @@ -3019,6 +3949,7 @@ def switch_ts(self, label: str): label (str): The TS species label. """ logger.info(f'Switching a TS guess for {label}...') + self.carry_stability_verdict_across_ts_switch(label=label) self.determine_most_likely_ts_conformer(label=label) # Look for a different TS guess. self.delete_all_species_jobs(label=label) # Delete other currently running jobs for this TS. freq_path = os.path.join(self.project_directory, 'output', 'rxns', label, 'geometry', 'freq.out') @@ -3057,6 +3988,7 @@ def check_sp_job(self, self.post_sp_actions(label, sp_path=os.path.join(job.local_path_to_output_file), level=job.level, + job=job, ) # Update restart dictionary and save the yaml restart file: self.save_restart_dict() @@ -3073,20 +4005,39 @@ def post_sp_actions(self, label: str, sp_path: str, level: Level | None = None, + job: JobAdapter | None = None, ): """ Perform post-sp actions. + ``job`` is the job whose log the electronic energy is read from, which is the sp job + where one ran and the optimization job where the sp level equals the opt level and no + sp job was submitted. Its SCF reference is recorded here, under 'sp', because it is the + job that supplied the energy whichever of the two it is. A caller that has no job to + name, a species restored from a restart among them, records nothing. + + THE ONE CALLER THAT NAMES NO JOB is ``run_sp_job``'s path for a project restarted with no + opt job left in its job dictionary, which reaches the optimization log through + ``output[label]['paths']['geo']`` and has no job object to hand over. It is reached only + where the sp level equals the opt level, where one job supplied both the geometry and the + energy and the two therefore share one SCF reference by construction, so the reference + comparison that record feeds has nothing to find. What it costs is that ``output.yml`` + reports a null ``reference_mismatch`` for such a project rather than ``false``. + Args: label (str): The species label. sp_path (str): The path to 'output.out' for the single point job. level (Level, optional): The level of theory used for the sp job. + job (JobAdapter, optional): The job whose log the electronic energy is read from. """ + if job is not None: + self.record_scf_reference(label=label, job=job, reference_key='sp') original_sp_path = self.output[label]['paths']['sp'] if 'sp' in self.output[label]['paths'] else None self.output[label]['paths']['sp'] = sp_path if self.sp_level is not None and 'ccsd' in self.sp_level.method: self.species_dict[label].t1 = parser.parse_t1(self.output[label]['paths']['sp']) self.species_dict[label].e_elect = parser.parse_e_elect(self.output[label]['paths']['sp']) + self.check_spin_contamination(label=label, sp_path=self.output[label]['paths']['sp']) if level is not None and level.method_type == 'wavefunction' and self.species_dict[label].active is None: self.species_dict[label].active = parser.parse_active_space(sp_path=self.output[label]['paths']['sp'], species=self.species_dict[label]) @@ -3497,6 +4448,8 @@ def check_all_done(self, label: str): all_converged = False else: for job_type, spawn_job_type in self.job_types.items(): + if job_type == 'stability': + continue if spawn_job_type and not self.output[label]['job_types'][job_type] \ and not ((self.species_dict[label].is_ts and job_type in ['scan', 'conf_opt']) or (self.species_dict[label].number_of_atoms == 1 @@ -4115,6 +5068,11 @@ def restore_running_jobs(self): """ Make Job objects for jobs which were running in the previous session. Important for the restart feature so long jobs won't run twice. + + Rebuilding a job adapter re-composes its input file, which recomputes the SCF reference + from the species' state as it is now. The reference the queued job actually ran with is + therefore restored onto the rebuilt adapter from the restart file, so that a job which was + submitted before a stability verdict was adopted still reports the reference it declared. """ jobs = self.restart_dict['running_jobs'] if not jobs or not any([job for job in jobs.values()]): @@ -4147,7 +5105,10 @@ def restore_running_jobs(self): if 'reaction_indices' in job_description else None if 'reaction_indices' in job_description: del job_description['reaction_indices'] + restricted_used = job_description.pop('restricted_used', None) job = job_factory(**job_description) + if isinstance(restricted_used, (bool, list)): + job.restricted_used = restricted_used if spc_label not in self.job_dict.keys(): self.job_dict[spc_label] = dict() if job_description['job_type'] not in self.job_dict[spc_label].keys(): diff --git a/arc/scheduler_test.py b/arc/scheduler_test.py index 7803e010c2..35e29d5d00 100644 --- a/arc/scheduler_test.py +++ b/arc/scheduler_test.py @@ -5,6 +5,8 @@ This module contains unit tests for the arc.scheduler module """ +import logging +import tempfile import unittest from unittest.mock import MagicMock, patch import os @@ -15,11 +17,17 @@ import arc.parser.parser as parser from arc.checks.ts import check_ts from arc.common import ARC_PATH, ARC_TESTING_PATH, almost_equal_coords_lists, initialize_job_types, read_yaml_file -from arc.job.adapters.common import default_incore_adapters, ts_adapters_by_rmg_family, ts_adapters_for_unknown_unimolecular +from arc.job.adapters.common import (adopted_reference_is_unrestricted, default_incore_adapters, + derived_instability_breaks_spin_symmetry, is_restricted, + REFERENCE_AGNOSTIC_METHOD_TYPES, REFERENCE_CHANGE_AVAILABLE_KEY, + ts_adapters_by_rmg_family, ts_adapters_for_unknown_unimolecular) from arc.job.factory import job_factory from arc.level import Level from arc.plotter import save_conformers_file -from arc.scheduler import (Scheduler, SchedulerError, species_has_freq, species_has_geo, species_has_sp, +from arc.scheduler import (COLLAPSED_REFERENCE_MESSAGE, INVALID_ANALYTIC_FREQ_MESSAGE, MAX_S_SQUARED_DEVIATION, + MIXED_SCF_REFERENCE_MESSAGE, SPIN_CONTAMINATION_MESSAGE, STABILITY_ANALYSIS_ADAPTERS, + SYMMETRY_BREAKING_ADAPTERS, UNREACHABLE_REFERENCE_MESSAGE, + Scheduler, SchedulerError, species_has_freq, species_has_geo, species_has_sp, species_has_sp_and_freq, tsg_method_matches_adapter) from arc.imports import settings from arc.reaction import ARCReaction @@ -440,6 +448,1546 @@ def test_initialize_output_dict(self): } self.assertEqual(self.sched1.output, initialized_output_dict) + def test_stability_does_not_gate_convergence(self): + """Test that the stability diagnostic never holds a species back from converging""" + original_output = self.sched1.output + original_job_types = self.sched1.job_types + self.addCleanup(setattr, self.sched1, 'output', original_output) + self.addCleanup(setattr, self.sched1, 'job_types', original_job_types) + self.sched1.output = dict() + self.sched1.initialize_output_dict() + self.sched1.job_types = dict(original_job_types) + self.sched1.job_types['stability'] = True + label = 'C2H6' + + self.sched1.output[label]['job_types'] = {job_type: True for job_type in self.sched1.job_types} + self.sched1.output[label]['job_types']['stability'] = False + self.sched1.output[label]['convergence'] = None + self.sched1.check_all_done(label=label) + self.assertTrue(self.sched1.output[label]['convergence'], + msg='an unrun stability diagnostic held the species back from converging') + + self.sched1.output[label]['job_types'] = {job_type: True for job_type in self.sched1.job_types} + self.sched1.output[label]['job_types']['sp'] = False + self.sched1.output[label]['convergence'] = None + self.sched1.check_all_done(label=label) + self.assertNotEqual(self.sched1.output[label]['convergence'], True, + msg='the stability exemption is over-broad: a missing sp job still converged') + + def test_stability_lookup_survives_a_restart_predating_the_job_type(self): + """Test that enabling the diagnostic cannot raise on a restart.yml written without it""" + original_output = self.sched1.output + original_job_types = self.sched1.job_types + self.addCleanup(setattr, self.sched1, 'output', original_output) + self.addCleanup(setattr, self.sched1, 'job_types', original_job_types) + label = 'C2H6' + restart_shaped = {'conf_opt': True, 'opt': True, 'fine': False, 'freq': True, 'sp': True, + 'rotors': True, 'orbitals': False, 'lennard_jones': False, 'conf_sp': False, + 'composite': False, 'onedmin': False} + self.sched1.output = {label: {'job_types': dict(restart_shaped), 'paths': {}, 'convergence': None, + 'conformers': '', 'isomorphism': '', 'restart': '', 'errors': '', + 'warnings': '', 'info': ''}} + self.sched1.job_types = dict(restart_shaped) + self.sched1.job_types['stability'] = True + self.assertNotIn('stability', self.sched1.output[label]['job_types']) + self.sched1.check_all_done(label=label) + self.assertTrue(self.sched1.output[label]['convergence']) + + def test_errored_orbitals_job_is_still_rerun_on_memory_error(self): + """Test that the stability diagnostic did not change how an errored orbitals job is handled""" + for job_type, expected_rerun in [('orbitals', True), ('stability', False)]: + job = MagicMock() + job.job_type = job_type + job.job_name = f'{job_type}_a1' + job.job_id = 1 + job.job_memory_gb = 14 + job.job_status = ['done', {'status': 'errored', 'keywords': ['memory'], + 'error': 'Insufficient job memory'}] + self.sched1.running_jobs['C2H6'] = [job.job_name] + with patch.object(self.sched1, '_run_a_job') as run_a_job: + self.sched1.end_job(job=job, label='C2H6', job_name=job.job_name) + self.assertEqual(run_a_job.called, expected_rerun, + msg=f'{job_type} job re-run was {run_a_job.called}, expected {expected_rerun}') + + def _completed_geometry_job(self, job_adapter, job_type, check_file_name, orbitals=b'orbitals'): + """Build a stand-in for a completed geometry job holding a downloaded orbitals file.""" + local_path = tempfile.mkdtemp(prefix='arc_test_scheduler_end_job_') + self.addCleanup(shutil.rmtree, local_path, ignore_errors=True) + with open(os.path.join(local_path, 'output.out'), 'w') as f: + f.write('output') + if orbitals is not None: + with open(os.path.join(local_path, check_file_name), 'wb') as f: + f.write(orbitals) + job = MagicMock() + job.job_adapter = job_adapter + job.job_type = job_type + job.job_name = f'{job_type}_a1' + job.job_id = 1 + job.check_file_name = check_file_name + job.local_path = local_path + job.local_path_to_output_file = os.path.join(local_path, 'output.out') + job.job_status = ['done', {'status': 'done', 'keywords': list(), 'error': '', 'line': ''}] + job.directed_scan_type = None + job.execution_type = 'queue' + return job + + def _end_a_completed_job(self, job, label='C2H6'): + """Run end_job for a completed job and return the checkfile the species came away with.""" + original_checkfile = self.sched1.species_dict[label].checkfile + self.addCleanup(setattr, self.sched1.species_dict[label], 'checkfile', original_checkfile) + self.sched1.species_dict[label].checkfile = None + self.sched1.running_jobs[label] = [job.job_name] + with patch.object(self.sched1, 'save_restart_dict'): + terminated = self.sched1.end_job(job=job, label=label, job_name=job.job_name) + self.assertTrue(terminated) + return self.sched1.species_dict[label].checkfile + + def test_end_job_adopts_the_orbitals_file_its_ess_names(self): + """Test that an ORCA geometry job hands the species its input.gbw, as Gaussian does its check.chk""" + for job_adapter, check_file_name in [('orca', 'input.gbw'), ('gaussian', 'check.chk')]: + for job_type in ['opt', 'optfreq', 'composite']: + job = self._completed_geometry_job(job_adapter=job_adapter, job_type=job_type, + check_file_name=check_file_name) + self.assertEqual(self._end_a_completed_job(job), + os.path.join(job.local_path, check_file_name), + msg=f'a {job_adapter} {job_type} job did not hand over its {check_file_name}') + + def test_end_job_adopts_no_orbitals_from_a_job_that_is_not_a_geometry_job(self): + """Test that only the job types the guess chain reads from hand over their orbitals""" + for job_type in ['sp', 'freq', 'scan']: + job = self._completed_geometry_job(job_adapter='orca', job_type=job_type, + check_file_name='input.gbw') + self.assertIsNone(self._end_a_completed_job(job), msg=f'a {job_type} job handed over orbitals') + + def test_end_job_refuses_an_empty_orbitals_file(self): + """Test that the zero-byte file a failed download leaves behind is not adopted""" + job = self._completed_geometry_job(job_adapter='orca', job_type='opt', + check_file_name='input.gbw', orbitals=b'') + self.assertTrue(os.path.isfile(os.path.join(job.local_path, 'input.gbw'))) + self.assertEqual(os.path.getsize(os.path.join(job.local_path, 'input.gbw')), 0) + with self.assertLogs('arc', level='INFO') as captured: + checkfile = self._end_a_completed_job(job) + self.assertIsNone(checkfile) + self.assertIn('input.gbw', '\n'.join(captured.output)) + + def test_end_job_adopts_no_orbitals_when_the_download_left_nothing(self): + """Test that a job whose orbitals never came back leaves the species without a checkfile""" + job = self._completed_geometry_job(job_adapter='orca', job_type='opt', + check_file_name='input.gbw', orbitals=None) + self.assertFalse(os.path.isfile(os.path.join(job.local_path, 'input.gbw'))) + self.assertIsNone(self._end_a_completed_job(job)) + + def _stability_opt_job(self, checkfile, method='wb97xd', adapter='gaussian', + basis='def2-TZVP', restricted_used=None, fine=False): + """Build a minimal stand-in for a converged Gaussian opt job.""" + job = MagicMock() + job.job_adapter = adapter + job.job_name = 'opt_a1' + job.job_type = 'opt' + job.fine = fine + job.restricted_used = restricted_used + job.level = Level(method=method, basis=basis) if basis is not None else Level(method=method) + job.local_path_to_check_file = checkfile + job.local_path_to_output_file = '/nonexistent/opt.out' + return job + + def _prepare_stability_ts(self, label='C2H6', checkfile=None, is_ts=True, enabled=True): + """Point a scheduler species at a checkfile and enable the stability diagnostic.""" + species = self.sched1.species_dict[label] + original_job_types = self.sched1.job_types + original_checkfile = species.checkfile + original_is_ts = species.is_ts + original_final_xyz = species.final_xyz + original_jobs = self.sched1.job_dict.get(label) + self.addCleanup(setattr, self.sched1, 'job_types', original_job_types) + self.addCleanup(setattr, species, 'checkfile', original_checkfile) + self.addCleanup(setattr, species, 'is_ts', original_is_ts) + self.addCleanup(setattr, species, 'final_xyz', original_final_xyz) + self.addCleanup(setattr, species, 'stability_analysis_ran', False) + self.addCleanup(setattr, species, 'stability_pending_opt_job', None) + self.addCleanup(setattr, species, 'stability_reoptimized', False) + self.addCleanup(setattr, species, 'derived_stability_verdict', None) + + def _restore_jobs(): + if original_jobs is None: + self.sched1.job_dict.pop(label, None) + else: + self.sched1.job_dict[label] = original_jobs + self.addCleanup(_restore_jobs) + + job_types = initialize_job_types(dict()) + job_types.update(original_job_types) + job_types['stability'] = enabled + self.sched1.job_types = job_types + species.is_ts = is_ts + species.checkfile = checkfile + species.stability_analysis_ran = False + species.stability_pending_opt_job = None + species.stability_reoptimized = False + species.derived_stability_verdict = None + species.final_xyz = {'symbols': ('O', 'H'), 'isotopes': (16, 1), + 'coords': ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))} + self.sched1.job_dict[label] = dict() + return label + + def _spawn_post_opt(self, label, job, job_name='opt_a1'): + """Drive spawn_post_opt_jobs for an opt job and return the run_job mock it spawned through.""" + self.sched1.job_dict[label]['opt'] = {job_name: job} + self.sched1.output[label]['paths']['geo'] = '' + with patch.object(self.sched1, 'run_scan_jobs'), \ + patch.object(self.sched1, 'spawn_ts_jobs'), \ + patch.object(self.sched1, 'run_job') as run_job: + self.sched1.spawn_post_opt_jobs(label=label, job_name=job_name) + return run_job + + def test_stability_job_spawned_from_the_opt_job_state(self): + """Test that the stability job takes its level and orbitals from the opt job and the converged geometry""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile) + job = self._stability_opt_job(checkfile=checkfile) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertTrue(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertTrue(run_job.called) + kwargs = run_job.call_args.kwargs + self.assertEqual(kwargs['job_type'], 'stability') + self.assertEqual(kwargs['job_adapter'], 'gaussian') + self.assertIs(kwargs['xyz'], self.sched1.species_dict[label].final_xyz) + self.assertIs(kwargs['level_of_theory'], job.level) + self.assertTrue(self.sched1.species_dict[label].stability_analysis_ran) + + def test_stability_job_not_spawned_at_a_level_with_no_broken_symmetry_reference(self): + """Test that the analysis runs at the levels a broken-symmetry reference describes and no other""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile) + species = self.sched1.species_dict[label] + for method, spawned in [('wb97xd', True), ('hf', True), ('ccsd(t)', False), ('mp2', False)]: + species.stability_analysis_ran = False + job = self._stability_opt_job(checkfile=checkfile, method=method, restricted_used=True) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertEqual(self.sched1.run_stability_job(label=label, opt_job=job), spawned, + msg=f'an optimization at {method} was not handled as {spawned}') + self.assertEqual(run_job.called, spawned) + + def test_stability_job_not_spawned_when_checkfile_superseded(self): + """Test that a species holding a different checkfile than its opt job wrote is skipped""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f_old, \ + tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f_new: + old_checkfile, new_checkfile = f_old.name, f_new.name + for path in (old_checkfile, new_checkfile): + self.addCleanup(lambda p=path: os.path.isfile(p) and os.remove(p)) + label = self._prepare_stability_ts(checkfile=new_checkfile) + job = self._stability_opt_job(checkfile=old_checkfile) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertFalse(run_job.called) + + def test_stability_job_not_spawned_without_a_checkfile(self): + """Test that an opt job with no checkfile is skipped rather than run with guess=mix""" + label = self._prepare_stability_ts(checkfile=None) + job = self._stability_opt_job(checkfile=None) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertFalse(run_job.called) + + def test_stability_job_not_spawned_for_a_job_that_is_not_a_submitted_ess_job(self): + """Test that a job carrying no ESS state is skipped""" + label = self._prepare_stability_ts(checkfile=None) + piped = SimpleNamespace(local_path_to_output_file='/nonexistent/opt.out', + level=Level(method='wb97xd', basis='def2-TZVP'), + job_status=['done', {'status': 'done'}]) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=piped)) + self.assertFalse(run_job.called) + + def test_stability_job_not_spawned_twice(self): + """Test that a TS gets at most one stability job, and that the guard is species state""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile) + job = self._stability_opt_job(checkfile=checkfile) + self.sched1.species_dict[label].stability_analysis_ran = True + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertFalse(run_job.called) + + def test_stability_job_reports_an_ess_it_is_not_implemented_for(self): + """Test that an opt job of an unsupported ESS is refused with a warning naming it, once per ESS""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + self.addCleanup(self.sched1.stability_unimplemented_ess.clear) + self.sched1.stability_unimplemented_ess.clear() + label = self._prepare_stability_ts(checkfile=checkfile) + job = self._stability_opt_job(checkfile=checkfile, adapter='qchem') + with patch.object(self.sched1, 'run_job') as run_job: + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.run_stability_job(label=label, opt_job=job) + self.assertFalse(run_job.called) + message = '\n'.join(captured.output) + self.assertIn(label, message) + self.assertIn('qchem', message) + for ess in STABILITY_ANALYSIS_ADAPTERS: + self.assertIn(ess, message) + self.assertEqual(self.sched1.stability_unimplemented_ess, {'qchem'}) + + with patch.object(self.sched1, 'run_job') as run_job, \ + patch('arc.scheduler.logger') as mocked_logger: + self.sched1.run_stability_job(label=label, opt_job=job) + self.assertFalse(run_job.called) + self.assertFalse(mocked_logger.warning.called) + + molpro_job = self._stability_opt_job(checkfile=checkfile, adapter='molpro') + with patch.object(self.sched1, 'run_job') as run_job, \ + patch('arc.scheduler.logger') as mocked_logger: + self.sched1.run_stability_job(label=label, opt_job=molpro_job) + self.assertFalse(run_job.called) + self.assertTrue(mocked_logger.warning.called) + self.assertIn('molpro', mocked_logger.warning.call_args.args[0]) + self.assertEqual(self.sched1.stability_unimplemented_ess, {'qchem', 'molpro'}) + + def _adopted_reference_ts(self, label='C2H6'): + """Point a scheduler species at an adopted external instability and return its label.""" + label = self._prepare_stability_ts(label=label, checkfile=None, is_ts=True) + species = self.sched1.species_dict[label] + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(adopted_reference_is_unrestricted(species)) + return label + + def test_an_unbreakable_unrestricted_reference_is_reported_once_per_ess(self): + """Test that an ESS offered neither symmetry-breaking mechanism is warned about, once per ESS""" + self.addCleanup(self.sched1.unbreakable_reference_ess.clear) + self.sched1.unbreakable_reference_ess.clear() + label = self._adopted_reference_ts() + job = self._stability_opt_job(checkfile=None, adapter='molpro', restricted_used=False) + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + message = '\n'.join(captured.output) + self.assertIn(label, message) + self.assertIn('molpro', message) + for ess in SYMMETRY_BREAKING_ADAPTERS: + self.assertIn(ess, message) + self.assertEqual(self.sched1.unbreakable_reference_ess, {'molpro'}) + + with patch('arc.scheduler.logger') as mocked_logger: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertFalse(mocked_logger.warning.called) + + qchem_job = self._stability_opt_job(checkfile=None, adapter='qchem', restricted_used=False) + with patch('arc.scheduler.logger') as mocked_logger: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=qchem_job) + self.assertTrue(mocked_logger.warning.called) + self.assertIn('qchem', mocked_logger.warning.call_args.args[0]) + self.assertEqual(self.sched1.unbreakable_reference_ess, {'molpro', 'qchem'}) + + def test_a_collapsible_reference_is_recorded_on_every_species_it_is_reached_for(self): + """Test that the species output warnings name each species, while the log names each ESS once""" + self.addCleanup(self.sched1.unbreakable_reference_ess.clear) + self.sched1.unbreakable_reference_ess.clear() + label = self._adopted_reference_ts() + original_warnings = self.sched1.output[label]['warnings'] + self.addCleanup(self.sched1.output[label].__setitem__, 'warnings', original_warnings) + job = self._stability_opt_job(checkfile=None, adapter='molpro', restricted_used=False) + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertIn(COLLAPSED_REFERENCE_MESSAGE, self.sched1.output[label]['warnings']) + + with patch('arc.scheduler.logger') as mocked_logger: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertFalse(mocked_logger.warning.called) + self.assertEqual(self.sched1.output[label]['warnings'].count(COLLAPSED_REFERENCE_MESSAGE), 1) + + def test_the_collapsible_reference_report_tolerates_a_job_carrying_no_name(self): + """Test that a job object with no job_name is reported rather than raising""" + self.addCleanup(self.sched1.unbreakable_reference_ess.clear) + self.sched1.unbreakable_reference_ess.clear() + label = self._adopted_reference_ts() + original_warnings = self.sched1.output[label]['warnings'] + self.addCleanup(self.sched1.output[label].__setitem__, 'warnings', original_warnings) + job = SimpleNamespace(job_adapter='molpro', + restricted_used=False, + level=Level(method='wb97xd', basis='def2-TZVP'), + ) + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertIn('molpro', '\n'.join(captured.output)) + self.assertEqual(self.sched1.unbreakable_reference_ess, {'molpro'}) + + def test_no_report_for_an_ess_arc_breaks_the_spin_symmetry_for(self): + """Test that the ESSs ARC writes a guess or a directive for are not reported""" + self.addCleanup(self.sched1.unbreakable_reference_ess.clear) + self.sched1.unbreakable_reference_ess.clear() + label = self._adopted_reference_ts() + for adapter in sorted(SYMMETRY_BREAKING_ADAPTERS): + job = self._stability_opt_job(checkfile=None, adapter=adapter, restricted_used=False) + with patch('arc.scheduler.logger') as mocked_logger: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertFalse(mocked_logger.warning.called, msg=f'{adapter} was reported') + self.assertEqual(self.sched1.unbreakable_reference_ess, set()) + + def test_no_report_without_an_adopted_verdict(self): + """Test that a species whose reference the analysis did not decide is not reported""" + self.addCleanup(self.sched1.unbreakable_reference_ess.clear) + self.sched1.unbreakable_reference_ess.clear() + label = self._prepare_stability_ts(checkfile=None, is_ts=True) + for verdict in [None, + {'verdict': 'stable', 'restricted': True}, + {'verdict': 'external_instability', 'restricted': False}, + ]: + self.sched1.species_dict[label].derived_stability_verdict = verdict + job = self._stability_opt_job(checkfile=None, adapter='molpro', restricted_used=False) + with patch('arc.scheduler.logger') as mocked_logger: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertFalse(mocked_logger.warning.called, msg=f'the verdict {verdict} was reported') + self.assertEqual(self.sched1.unbreakable_reference_ess, set()) + + def test_no_report_for_a_job_that_declared_no_unrestricted_reference(self): + """Test that the report follows the reference the job's input declared""" + self.addCleanup(self.sched1.unbreakable_reference_ess.clear) + self.sched1.unbreakable_reference_ess.clear() + label = self._adopted_reference_ts() + for restricted_used in [None, True, [False]]: + job = self._stability_opt_job(checkfile=None, adapter='molpro', restricted_used=restricted_used) + with patch('arc.scheduler.logger') as mocked_logger: + self.sched1.warn_on_collapsible_unrestricted_reference(label=label, job=job) + self.assertFalse(mocked_logger.warning.called, + msg=f'a job whose reference memo is {restricted_used} was reported') + self.assertEqual(self.sched1.unbreakable_reference_ess, set()) + + def test_stability_job_spawned_for_every_capable_ess(self): + """Test that each ESS ARC implements the analysis for spawns the job in that ESS""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + self.addCleanup(self.sched1.stability_unimplemented_ess.clear) + self.sched1.stability_unimplemented_ess.clear() + label = self._prepare_stability_ts(checkfile=checkfile) + for adapter in sorted(STABILITY_ANALYSIS_ADAPTERS): + job = self._stability_opt_job(checkfile=checkfile, adapter=adapter) + self.sched1.species_dict[label].stability_analysis_ran = False + with patch.object(self.sched1, 'run_job') as run_job: + self.sched1.run_stability_job(label=label, opt_job=job) + self.assertTrue(run_job.called, msg=f'no stability job was spawned for {adapter}') + self.assertEqual(run_job.call_args.kwargs['job_adapter'], adapter) + self.assertEqual(run_job.call_args.kwargs['job_type'], 'stability') + self.assertEqual(self.sched1.stability_unimplemented_ess, set()) + + def test_stability_job_spawned_for_an_orca_gbw_checkfile(self): + """Test that the checkfile identity gate reads an ORCA .gbw as it does a Gaussian .chk""" + with tempfile.NamedTemporaryFile(suffix='.gbw', delete=False) as f_new, \ + tempfile.NamedTemporaryFile(suffix='.gbw', delete=False) as f_old: + checkfile, old_checkfile = f_new.name, f_old.name + for path in (checkfile, old_checkfile): + self.addCleanup(lambda p=path: os.path.isfile(p) and os.remove(p)) + label = self._prepare_stability_ts(checkfile=checkfile) + job = self._stability_opt_job(checkfile=checkfile, adapter='orca') + with patch.object(self.sched1, 'run_job') as run_job: + self.sched1.run_stability_job(label=label, opt_job=job) + self.assertTrue(run_job.called) + self.assertEqual(run_job.call_args.kwargs['job_adapter'], 'orca') + + self.sched1.species_dict[label].stability_analysis_ran = False + self.assertTrue(os.path.isfile(old_checkfile), + msg='the superseded .gbw must exist, or the identity gate is never reached') + superseded = self._stability_opt_job(checkfile=old_checkfile, adapter='orca') + with patch.object(self.sched1, 'run_job') as run_job: + self.sched1.run_stability_job(label=label, opt_job=superseded) + self.assertFalse(run_job.called) + + def test_stability_job_not_spawned_for_a_non_dft_level(self): + """Test that a level Gaussian offers no stability analysis for is skipped""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile) + for method, expected in [('ccsd(t)', False), ('cbs-qb3', False), ('hf', True), ('wb97xd', True)]: + job = self._stability_opt_job(checkfile=checkfile, method=method) + self.sched1.species_dict[label].stability_analysis_ran = False + with patch.object(self.sched1, 'run_job') as run_job: + self.sched1.run_stability_job(label=label, opt_job=job) + self.assertEqual(run_job.called, expected, msg=f'{method} spawned={run_job.called}') + + def test_the_stability_gate_admits_a_restricted_species_that_is_not_a_ts(self): + """Test that a well whose opt job declared a restricted reference is tested""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=False) + job = self._stability_opt_job(checkfile=checkfile, restricted_used=True) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertTrue(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertEqual(run_job.call_args.kwargs['job_type'], 'stability') + + def test_the_stability_gate_refuses_an_unrestricted_species_that_is_not_a_ts(self): + """Test that a well whose opt job already ran unrestricted is not tested""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=False) + job = self._stability_opt_job(checkfile=checkfile, restricted_used=False) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertFalse(run_job.called) + + def test_the_stability_gate_refuses_a_reference_agnostic_species_that_is_not_a_ts(self): + """Test that a method ARC writes no r/u prefix for is not read as a restricted reference""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=False) + for method, basis in [('cbs-qb3', None), ('am1', None), ('mmff94s', None)]: + job = self._stability_opt_job(checkfile=checkfile, method=method, basis=basis, restricted_used=True) + self.assertIn(job.level.method_type, ['force_field', 'composite', 'semiempirical'], + msg=f'{method} is not a reference-agnostic method type') + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job), + msg=f'{method} was admitted to the stability diagnostic') + self.assertFalse(run_job.called) + + def test_the_stability_gate_refuses_a_species_carrying_no_reference_memo(self): + """Test that a well whose opt job never wrote an ESS input is not tested""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=False) + job = self._stability_opt_job(checkfile=checkfile, restricted_used=None) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertFalse(run_job.called) + + def test_the_stability_gate_still_admits_a_ts_whatever_reference_it_ran(self): + """Test that a TS does not depend on the reference its opt job declared""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + for restricted_used in [True, False, None]: + job = self._stability_opt_job(checkfile=checkfile, restricted_used=restricted_used) + self.sched1.species_dict[label].stability_analysis_ran = False + with patch.object(self.sched1, 'run_job'): + self.assertTrue(self.sched1.run_stability_job(label=label, opt_job=job), + msg=f'a TS whose opt job declared {restricted_used} was refused') + + def test_post_opt_jobs_hold_the_freq_the_sp_and_the_irc_until_the_verdict_is_in(self): + """Test that a spawned stability analysis is the only job the post-opt path enqueues""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + self.sched1._pending_pipe_freq.discard(label) + self.sched1._pending_pipe_sp.discard(label) + self.sched1._pending_pipe_irc.discard((label, 'forward')) + self.sched1._pending_pipe_irc.discard((label, 'reverse')) + job = self._stability_opt_job(checkfile=checkfile) + run_job = self._spawn_post_opt(label=label, job=job) + self.assertEqual(run_job.call_args.kwargs['job_type'], 'stability') + self.assertNotIn(label, self.sched1._pending_pipe_freq) + self.assertNotIn(label, self.sched1._pending_pipe_sp) + self.assertNotIn((label, 'forward'), self.sched1._pending_pipe_irc) + self.assertEqual(self.sched1.species_dict[label].stability_pending_opt_job, 'opt_a1') + + def test_the_re_optimization_releases_the_irc_onto_the_adopted_reference(self): + """Test that the IRC an analysis held is enqueued once the re-optimized species comes back""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + for pending in [self.sched1._pending_pipe_freq, self.sched1._pending_pipe_sp]: + pending.discard(label) + self.addCleanup(pending.discard, label) + for direction in ['forward', 'reverse']: + self.sched1._pending_pipe_irc.discard((label, direction)) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, direction)) + species = self.sched1.species_dict[label] + job = self._stability_opt_job(checkfile=checkfile) + run_job = self._spawn_post_opt(label=label, job=job) + self.assertEqual(run_job.call_args.kwargs['job_type'], 'stability') + self.assertNotIn((label, 'forward'), self.sched1._pending_pipe_irc) + + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + with patch.object(self.sched1, 'run_job') as run_job: + self.sched1.spawn_post_stability_jobs(label=label) + self.assertEqual(run_job.call_args.kwargs['job_type'], 'opt') + self.assertTrue(species.stability_reoptimized) + self.assertNotIn((label, 'forward'), self.sched1._pending_pipe_irc) + + run_job = self._spawn_post_opt(label=label, job=job, job_name='opt_a2') + self.assertFalse(run_job.called) + self.assertIn((label, 'forward'), self.sched1._pending_pipe_irc) + self.assertIn((label, 'reverse'), self.sched1._pending_pipe_irc) + self.assertIn(label, self.sched1._pending_pipe_freq) + self.assertIn(label, self.sched1._pending_pipe_sp) + self.assertIsNone(species.stability_pending_opt_job) + + def test_an_irc_rejection_reduces_the_verdict_and_releases_the_held_analysis_state(self): + """Test that a TS the IRC check rejects switches guess with its adopted verdict carried""" + label = self._prepare_stability_ts(checkfile=None, is_ts=True) + species = self.sched1.species_dict[label] + original_convergence = self.sched1.output[label]['convergence'] + self.addCleanup(self.sched1.output[label].__setitem__, 'convergence', original_convergence) + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + species.stability_pending_opt_job = 'opt_a1' + species.populate_ts_checks() + species.ts_checks['IRC'] = False + with patch.object(self.sched1, 'determine_most_likely_ts_conformer'), \ + patch.object(self.sched1, 'delete_all_species_jobs'), \ + patch.object(self.sched1, 'run_opt_job'), \ + patch.object(self.sched1, 'run_composite_job'): + self.sched1.process_irc_verdict(ts_label=label, rxn=None) + self.assertIsNone(species.stability_pending_opt_job) + self.assertEqual(species.derived_stability_verdict['verdict'], 'external_instability') + self.assertTrue(adopted_reference_is_unrestricted(species)) + + def test_post_opt_jobs_proceed_where_no_stability_analysis_is_spawned(self): + """Test that a species the analysis does not admit enqueues its freq and sp as usual""" + label = self._prepare_stability_ts(checkfile=None, is_ts=False, enabled=False) + self.sched1._pending_pipe_freq.discard(label) + self.sched1._pending_pipe_sp.discard(label) + self.addCleanup(self.sched1._pending_pipe_freq.discard, label) + self.addCleanup(self.sched1._pending_pipe_sp.discard, label) + job = self._stability_opt_job(checkfile=None, restricted_used=True) + run_job = self._spawn_post_opt(label=label, job=job) + self.assertFalse(run_job.called) + self.assertIn(label, self.sched1._pending_pipe_freq) + self.assertIn(label, self.sched1._pending_pipe_sp) + self.assertIsNone(self.sched1.species_dict[label].stability_pending_opt_job) + + def test_post_opt_jobs_proceed_where_the_opt_job_carries_no_ess_state(self): + """Test that an opt job the analysis cannot read leaves the freq and the sp enqueued""" + label = self._prepare_stability_ts(checkfile=None, is_ts=True, enabled=True) + self.sched1._pending_pipe_freq.discard(label) + self.sched1._pending_pipe_sp.discard(label) + self.addCleanup(self.sched1._pending_pipe_freq.discard, label) + self.addCleanup(self.sched1._pending_pipe_sp.discard, label) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, 'forward')) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, 'reverse')) + piped = SimpleNamespace(local_path_to_output_file='/nonexistent/opt.out', + level=Level(method='wb97xd', basis='def2-TZVP'), + job_status=['done', {'status': 'done'}]) + run_job = self._spawn_post_opt(label=label, job=piped) + self.assertFalse(run_job.called) + self.assertIn(label, self.sched1._pending_pipe_freq) + self.assertIn(label, self.sched1._pending_pipe_sp) + self.assertIsNone(self.sched1.species_dict[label].stability_pending_opt_job) + + def test_the_re_optimization_reads_the_orbitals_the_analysis_relaxed_into(self): + """Test that orbitals are carried over only from an analysis that followed the instability""" + with tempfile.NamedTemporaryFile(suffix='.gbw', delete=False) as f: + relaxed = f.name + self.addCleanup(lambda: os.path.isfile(relaxed) and os.remove(relaxed)) + label = self._prepare_stability_ts(checkfile=relaxed, is_ts=True) + species = self.sched1.species_dict[label] + stability_job = MagicMock() + stability_job.local_path_to_check_file = relaxed + self.sched1.job_dict[label]['stability'] = {'stability_a2': stability_job} + + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'followed_to_stable': True} + self.sched1.adopt_stability_orbitals(label=label) + self.assertEqual(species.checkfile, relaxed) + + species.checkfile = relaxed + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True, + 'followed_to_stable': False} + self.sched1.adopt_stability_orbitals(label=label) + self.assertIsNone(species.checkfile) + + def test_a_stable_verdict_releases_the_held_jobs_unchanged(self): + """Test that a verdict ARC does not act on lets the freq and the sp proceed""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + self.addCleanup(self.sched1._pending_pipe_freq.discard, label) + self.addCleanup(self.sched1._pending_pipe_sp.discard, label) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, 'forward')) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, 'reverse')) + job = self._stability_opt_job(checkfile=checkfile) + self._spawn_post_opt(label=label, job=job) + self.sched1.species_dict[label].derived_stability_verdict = {'verdict': 'stable', 'restricted': True} + with patch.object(self.sched1, 'run_scan_jobs'), \ + patch.object(self.sched1, 'spawn_ts_jobs'), \ + patch.object(self.sched1, 'run_job') as run_job: + self.sched1.spawn_post_stability_jobs(label=label) + self.assertFalse(run_job.called) + self.assertIn(label, self.sched1._pending_pipe_freq) + self.assertIn(label, self.sched1._pending_pipe_sp) + self.assertIsNone(self.sched1.species_dict[label].stability_pending_opt_job) + self.assertFalse(self.sched1.species_dict[label].stability_reoptimized) + + def test_an_adoptable_verdict_re_optimizes_the_species_exactly_once(self): + """Test that an adopted external instability re-runs the opt and that the guard holds after it""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + self.addCleanup(self.sched1._pending_pipe_freq.discard, label) + self.addCleanup(self.sched1._pending_pipe_sp.discard, label) + self.sched1._pending_pipe_freq.discard(label) + self.sched1._pending_pipe_sp.discard(label) + job = self._stability_opt_job(checkfile=checkfile, fine=True) + self._spawn_post_opt(label=label, job=job) + species = self.sched1.species_dict[label] + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(adopted_reference_is_unrestricted(species)) + with patch.object(self.sched1, 'run_job') as run_job: + self.sched1.spawn_post_stability_jobs(label=label) + self.assertTrue(run_job.called) + kwargs = run_job.call_args.kwargs + self.assertEqual(kwargs['job_type'], 'opt') + self.assertTrue(kwargs['fine']) + self.assertIs(kwargs['xyz'], species.final_xyz) + self.assertIs(species.initial_xyz, species.final_xyz) + self.assertTrue(species.stability_reoptimized) + self.assertNotIn(label, self.sched1._pending_pipe_freq) + + species.stability_pending_opt_job = 'opt_a1' + with patch.object(self.sched1, 'run_scan_jobs'), \ + patch.object(self.sched1, 'spawn_ts_jobs'), \ + patch.object(self.sched1, 'run_job') as run_job: + self.sched1.spawn_post_stability_jobs(label=label) + self.assertFalse(run_job.called) + self.assertIn(label, self.sched1._pending_pipe_freq) + + def test_the_re_optimization_guard_survives_a_restart(self): + """Test that the one-re-optimization guard is written to and read back from the restart dictionary""" + species = ARCSpecies(label='spc_under_test', smiles='CC') + species.stability_analysis_ran = True + species.stability_pending_opt_job = 'opt_a3' + species.stability_reoptimized = True + restored = ARCSpecies(species_dict=species.as_dict()) + self.assertTrue(restored.stability_analysis_ran) + self.assertEqual(restored.stability_pending_opt_job, 'opt_a3') + self.assertTrue(restored.stability_reoptimized) + + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + restored_species = self.sched1.species_dict[label] + restored_species.stability_analysis_ran = True + restored_species.stability_pending_opt_job = 'opt_a1' + restored_species.stability_reoptimized = True + restored_species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.addCleanup(self.sched1._pending_pipe_freq.discard, label) + self.addCleanup(self.sched1._pending_pipe_sp.discard, label) + self.sched1.job_dict[label]['opt'] = {'opt_a1': self._stability_opt_job(checkfile=checkfile)} + with patch.object(self.sched1, 'run_scan_jobs'), \ + patch.object(self.sched1, 'spawn_ts_jobs'), \ + patch.object(self.sched1, 'run_job') as run_job: + self.sched1.spawn_post_stability_jobs(label=label) + self.assertFalse(run_job.called) + + def test_a_restart_releases_work_held_by_an_analysis_that_is_no_longer_running(self): + """Test that a resumed run does not leave a species holding its freq and sp forever""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True) + self.addCleanup(self.sched1._pending_pipe_freq.discard, label) + self.addCleanup(self.sched1._pending_pipe_sp.discard, label) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, 'forward')) + self.addCleanup(self.sched1._pending_pipe_irc.discard, (label, 'reverse')) + self.sched1._pending_pipe_freq.discard(label) + original_running = self.sched1.running_jobs.get(label) + self.addCleanup(self.sched1.running_jobs.__setitem__, label, original_running or list()) + species = self.sched1.species_dict[label] + species.stability_analysis_ran = True + species.stability_pending_opt_job = 'opt_a1' + self.sched1.job_dict[label]['opt'] = {'opt_a1': self._stability_opt_job(checkfile=checkfile)} + + self.sched1.running_jobs[label] = ['stability_a2'] + with patch.object(self.sched1, 'run_scan_jobs'), \ + patch.object(self.sched1, 'spawn_ts_jobs'): + self.sched1.release_held_stability_work(label=label) + self.assertEqual(species.stability_pending_opt_job, 'opt_a1') + self.assertNotIn(label, self.sched1._pending_pipe_freq) + + self.sched1.running_jobs[label] = list() + with patch.object(self.sched1, 'run_scan_jobs'), \ + patch.object(self.sched1, 'spawn_ts_jobs'): + self.sched1.release_held_stability_work(label=label) + self.assertIsNone(species.stability_pending_opt_job) + self.assertIn(label, self.sched1._pending_pipe_freq) + + def test_a_ts_switch_releases_the_held_optimization_and_carries_the_verdict(self): + """Test that abandoning a TS guess drops the pending opt job while keeping an adopted verdict""" + label = self._prepare_stability_ts(checkfile=None, is_ts=True) + species = self.sched1.species_dict[label] + species.stability_pending_opt_job = 'opt_a1' + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.sched1.carry_stability_verdict_across_ts_switch(label=label) + self.assertIsNone(species.stability_pending_opt_job) + self.assertEqual(species.derived_stability_verdict['verdict'], 'external_instability') + self.assertTrue(adopted_reference_is_unrestricted(species), + msg='the next TS guess must start unrestricted from its first optimization') + + def test_the_stability_diagnostic_stays_inert_while_the_job_type_is_off(self): + """Test that a species the gate admits still runs nothing unless the user asked for it""" + with tempfile.NamedTemporaryFile(suffix='.chk', delete=False) as f: + checkfile = f.name + self.addCleanup(lambda: os.path.isfile(checkfile) and os.remove(checkfile)) + label = self._prepare_stability_ts(checkfile=checkfile, is_ts=True, enabled=False) + job = self._stability_opt_job(checkfile=checkfile, restricted_used=True) + with patch.object(self.sched1, 'run_job') as run_job: + self.assertFalse(self.sched1.run_stability_job(label=label, opt_job=job)) + self.assertFalse(run_job.called) + self.assertFalse(self.sched1.species_dict[label].stability_analysis_ran) + self.assertIsNone(self.sched1.species_dict[label].stability_pending_opt_job) + + def test_post_freq_actions_spawns_no_stability_analysis(self): + """Test that the frequency path holds no stability trigger of its own""" + label = self._prepare_stability_ts(checkfile=None, is_ts=True) + self.sched1.species_dict[label].ts_checks = {'NMD': True} + job = MagicMock() + job.job_adapter = 'gaussian' + job.job_name = 'freq_a1' + job.job_type = 'freq' + job.restricted_used = True + job.level = Level(method='wb97xd', basis='def2-TZVP') + job.local_path_to_output_file = '/nonexistent/freq.out' + with patch.object(self.sched1, 'check_negative_freq', return_value=(True, False)), \ + patch.object(self.sched1, 'check_rxn_e0_by_spc'), \ + patch.object(self.sched1, 'run_job') as run_job, \ + patch('arc.scheduler.safe_copy_file'), \ + patch('arc.scheduler.parser.parse_polarizability', return_value=None): + freq_ok, switched = self.sched1.post_freq_actions(label=label, job=job, vibfreqs=[-1000.0]) + self.assertTrue(freq_ok) + self.assertFalse(switched) + self.assertFalse(run_job.called) + self.assertFalse(self.sched1.species_dict[label].stability_analysis_ran) + + def test_check_stability_job_survives_an_unreadable_log(self): + """Test that a corrupt stability log is reported and does not propagate""" + label = 'C2H6' + with tempfile.NamedTemporaryFile(suffix='.log', delete=False) as f: + f.write(b'\xff\xfe\x00binary garbage\n') + log_path = f.name + self.addCleanup(lambda: os.path.isfile(log_path) and os.remove(log_path)) + job = MagicMock() + job.job_status = ['done', {'status': 'done'}] + job.local_path_to_output_file = log_path + self.sched1.output[label]['paths'].pop('stability', None) + self.sched1.check_stability_job(label=label, job=job) + self.assertNotIn('stability', self.sched1.output[label]['paths']) + + def _honour_the_reference_change(self): + """Point every level of the scheduler at an ESS ARC breaks the spin symmetry for.""" + for attribute in ['opt_level', 'freq_level', 'sp_level']: + self.addCleanup(setattr, self.sched1, attribute, getattr(self.sched1, attribute)) + setattr(self.sched1, attribute, Level(method='wb97xd', basis='def2tzvp', software='gaussian')) + + def _run_check_stability(self, fixture_name: str, label: str = 'C2H6', status: str = 'done'): + """Run check_stability_job against a real stability fixture and capture its log records.""" + job = MagicMock() + job.job_status = [status, {'status': status}] + job.local_path_to_output_file = os.path.join(ARC_TESTING_PATH, 'stability', fixture_name) + self.sched1.output[label]['paths'].pop('stability', None) + self.sched1.output[label].pop('wavefunction_stability', None) + self.addCleanup(self.sched1.output[label].__setitem__, 'warnings', + self.sched1.output[label]['warnings']) + self.addCleanup(setattr, self.sched1.species_dict[label], 'derived_stability_verdict', + self.sched1.species_dict[label].derived_stability_verdict) + with self.assertLogs('arc', level='DEBUG') as captured: + self.sched1.check_stability_job(label=label, job=job) + return captured.records + + def test_unstable_ts_is_warned_with_its_eigenvalue(self): + """Test that an instability is a warning naming the negative root and its eigenvalue""" + records = self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + stability = [r for r in records if 'stability' in r.getMessage().lower() + or 'wavefunction' in r.getMessage().lower()] + self.assertTrue(stability, msg='no stability log record emitted') + self.assertTrue(any(r.levelno == logging.WARNING for r in stability), + msg=f'no warning for an unstable TS: {[r.levelno for r in stability]}') + message = ' '.join(r.getMessage() for r in stability) + self.assertIn('Triplet-A', message) + self.assertIn('-0.0642', message) + self.assertIn('RHF -> UHF', message) + self.assertIn('Triplet-A', self.sched1.output['C2H6']['wavefunction_stability']) + + def test_stable_ts_is_not_warned(self): + """Test that a stable wavefunction does not raise a warning""" + records = self._run_check_stability('stable_unrestricted_doublet_ts.out') + self.assertFalse([r for r in records if r.levelno >= logging.WARNING], + msg=f'a stable TS produced {[r.getMessage() for r in records]}') + self.assertEqual(self.sched1.output['C2H6']['wavefunction_stability'], 'stable') + + def test_check_stability_job_records_the_structured_verdict_on_the_species(self): + """Test that the parsed verdict reaches the species object, not only the output summary string""" + self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + verdict = self.sched1.species_dict['C2H6'].derived_stability_verdict + self.assertIsInstance(verdict, dict) + self.assertEqual(verdict['verdict'], 'external_instability') + self.assertIs(verdict['restricted'], True) + + def test_a_declared_number_of_radicals_survives_a_contradicting_verdict(self): + """Test that the check runs, disagrees, warns, and leaves the declared value in place""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + species.number_of_radicals = 1 + records = self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + self.assertEqual(species.number_of_radicals, 1) + self.assertIsInstance(species.derived_stability_verdict, dict) + warnings = ' '.join(r.getMessage() for r in records if r.levelno == logging.WARNING) + self.assertIn('C2H6', warnings) + self.assertIn('number_of_radicals = 1', warnings) + self.assertIn('external instability', warnings) + self.assertIn('The declared value is the one ARC uses', warnings) + + def test_a_declared_biradical_singlet_contradicted_by_a_stable_verdict_warns(self): + """Test that a declared broken-symmetry character the calculation does not support is warned about""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + species.number_of_radicals = 2 + records = self._run_check_stability('stable_restricted_singlet_ts.out') + self.assertEqual(species.number_of_radicals, 2) + warnings = ' '.join(r.getMessage() for r in records if r.levelno == logging.WARNING) + self.assertIn('C2H6', warnings) + self.assertIn('number_of_radicals = 2', warnings) + self.assertIn('stable under the perturbations considered', warnings) + self.assertIn('not supported by the calculation', warnings) + + def test_adopting_a_measured_verdict_is_logged_as_such(self): + """Test that ARC says so when it adopts a verdict the user declared nothing against""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + species.number_of_radicals = None + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + species.is_ts = True + self._honour_the_reference_change() + records = self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + self.assertIsNone(species.number_of_radicals) + warnings = ' '.join(r.getMessage() for r in records if r.levelno == logging.WARNING) + self.assertIn('No number_of_radicals was declared for C2H6', warnings) + self.assertIn('adopting that verdict', warnings) + self.assertIn('run unrestricted', warnings) + self.assertTrue(adopted_reference_is_unrestricted(species)) + self.assertNotIn(UNREACHABLE_REFERENCE_MESSAGE, self.sched1.output['C2H6']['warnings']) + + def test_a_verdict_no_ess_of_the_run_can_reach_is_reported_and_not_adopted(self): + """Test that an instability the run's ESSs cannot break the spin symmetry for decides nothing""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + original_warnings = self.sched1.output['C2H6']['warnings'] + self.addCleanup(self.sched1.output['C2H6'].__setitem__, 'warnings', original_warnings) + species.number_of_radicals = None + species.is_ts = True + self.addCleanup(setattr, self.sched1, 'sp_level', self.sched1.sp_level) + self.sched1.sp_level = Level(method='wb97xd', basis='def2tzvp', software='molpro') + records = self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + verdict = species.derived_stability_verdict + self.assertEqual(verdict['verdict'], 'external_instability') + self.assertFalse(verdict['reference_change_available']) + self.assertFalse(adopted_reference_is_unrestricted(species)) + self.assertIn(UNREACHABLE_REFERENCE_MESSAGE, self.sched1.output['C2H6']['warnings']) + warnings = ' '.join(r.getMessage() for r in records if r.levelno == logging.WARNING) + self.assertIn('does not act on it', warnings) + self.assertNotIn('adopting that verdict', warnings) + + def test_a_correlated_single_point_does_not_block_the_adoption_of_a_verdict(self): + """Test that an sp the verdict decides no reference for is not tested against the adapters""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + original_warnings = self.sched1.output['C2H6']['warnings'] + self.addCleanup(self.sched1.output['C2H6'].__setitem__, 'warnings', original_warnings) + species.number_of_radicals = None + species.is_ts = True + self._honour_the_reference_change() + for method, basis in [('ccsd(t)-f12', 'cc-pvtz-f12'), ('dlpno-ccsd(t)', 'def2-tzvp')]: + self.sched1.sp_level = Level(method=method, basis=basis, software='molpro') + self.assertTrue(self.sched1.stability_verdict_can_be_honoured(label='C2H6'), + msg=f'an sp at {method} in an ESS ARC breaks no symmetry for blocked the adoption') + records = self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + self.assertTrue(adopted_reference_is_unrestricted(species)) + self.assertNotIn(UNREACHABLE_REFERENCE_MESSAGE, self.sched1.output['C2H6']['warnings']) + warnings = ' '.join(r.getMessage() for r in records if r.levelno == logging.WARNING) + self.assertIn('adopting that verdict', warnings) + + def test_stability_verdict_can_be_honoured_reads_the_levels_the_e0_comes_from(self): + """Test that the geometry, the ZPE and the electronic energy each have to be reachable""" + for attribute in ['opt_level', 'freq_level', 'sp_level']: + self.addCleanup(setattr, self.sched1, attribute, getattr(self.sched1, attribute)) + for adapter in sorted(SYMMETRY_BREAKING_ADAPTERS): + for attribute in ['opt_level', 'freq_level', 'sp_level']: + setattr(self.sched1, attribute, Level(method='wb97xd', basis='def2tzvp', software=adapter)) + self.assertTrue(self.sched1.stability_verdict_can_be_honoured(label='C2H6'), + msg=f'an all-{adapter} run was refused') + for attribute in ['opt_level', 'freq_level', 'sp_level']: + for other in ['opt_level', 'freq_level', 'sp_level']: + setattr(self.sched1, other, Level(method='wb97xd', basis='def2tzvp', software='gaussian')) + setattr(self.sched1, attribute, Level(method='wb97xd', basis='def2tzvp', software='qchem')) + self.assertFalse(self.sched1.stability_verdict_can_be_honoured(label='C2H6'), + msg=f'a run whose {attribute} is qchem was accepted') + + def test_a_reference_agnostic_level_neither_honours_a_verdict_nor_blocks_it(self): + """Test that a level ARC writes no reference prefix for is not tested against the adapters""" + for attribute in ['opt_level', 'freq_level', 'sp_level']: + self.addCleanup(setattr, self.sched1, attribute, getattr(self.sched1, attribute)) + for other in ['opt_level', 'freq_level', 'sp_level']: + setattr(self.sched1, other, Level(method='wb97xd', basis='def2tzvp', software='gaussian')) + for method in ['cbs-qb3', 'am1']: + self.sched1.sp_level = Level(method=method, software='molpro') + self.assertIn(self.sched1.sp_level.method_type, REFERENCE_AGNOSTIC_METHOD_TYPES) + self.assertTrue(self.sched1.stability_verdict_can_be_honoured(label='C2H6'), + msg=f'an sp at {method} blocked the adoption') + + def test_a_stability_job_that_died_after_printing_its_verdict_is_read(self): + """Test that a log holding a complete analysis is read whatever the job status says""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'derived_stability_verdict', species.derived_stability_verdict) + species.derived_stability_verdict = None + self._run_check_stability('orca_rhf_uhf_instability_no_restart_crash.out', status='errored') + verdict = species.derived_stability_verdict + self.assertIsInstance(verdict, dict) + self.assertEqual(verdict['verdict'], 'unattributed_instability') + self.assertEqual(verdict['n_analyses'], 1) + + def test_a_well_verdict_is_reported_and_not_adopted(self): + """Test that an instability measured for a species that is not a TS is said to change nothing""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + species.number_of_radicals = None + species.is_ts = False + records = self._run_check_stability('rhf_uhf_instability_singlet_ts.out') + warnings = ' '.join(r.getMessage() for r in records if r.levelno == logging.WARNING) + self.assertIn('external instability', warnings) + self.assertIn('does not act on it', warnings) + self.assertIn('number_of_radicals = 2', warnings) + self.assertNotIn('adopting that verdict', warnings) + self.assertEqual(species.derived_stability_verdict['verdict'], 'external_instability') + self.assertFalse(adopted_reference_is_unrestricted(species)) + + def test_a_stable_verdict_on_a_silent_species_adopts_nothing(self): + """Test that a stable verdict leaves the reference decision exactly where it was""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + species.number_of_radicals = None + records = self._run_check_stability('stable_restricted_singlet_ts.out') + self.assertFalse([r for r in records if r.levelno >= logging.WARNING], + msg=f'a stable verdict produced {[r.getMessage() for r in records]}') + + def _reference_job(self, job_type, restricted, method='wb97xd'): + """Build a stand-in for a completed ESS job that memoized the reference its input declared.""" + return SimpleNamespace(job_type=job_type, + restricted_used=restricted, + level=Level(method=method, basis='def2-TZVP'), + ) + + def _reset_reference_records(self, label='C2H6'): + """Clear the SCF reference records and output warnings of a species, restoring them afterwards.""" + species = self.sched1.species_dict[label] + self.addCleanup(setattr, species, 'scf_references', species.scf_references) + original_warnings = self.sched1.output[label]['warnings'] + self.addCleanup(self.sched1.output[label].__setitem__, 'warnings', original_warnings) + species.scf_references = dict() + self.sched1.output[label]['warnings'] = '' + return species + + def test_a_mixed_scf_reference_between_sp_and_freq_is_warned_about(self): + """Test that an E0 summing an unrestricted energy and a restricted ZPE is reported""" + species = self._reset_reference_records() + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('freq', True)) + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('sp', False)) + message = ' '.join(r.getMessage() for r in captured.records) + self.assertIn('C2H6', message) + self.assertIn('E_elect(unrestricted)', message) + self.assertIn('ZPE(restricted)', message) + self.assertEqual(species.scf_references, {'freq': 'restricted', 'sp': 'unrestricted'}) + self.assertIn('different SCF references', self.sched1.output['C2H6']['warnings']) + + def test_one_scf_reference_for_both_jobs_is_not_warned_about(self): + """Test that the common case, both jobs on one reference, stays silent""" + species = self._reset_reference_records() + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('freq', False)) + with self.assertNoLogs('arc', level='WARNING'): + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('sp', False)) + self.assertEqual(species.scf_references, {'freq': 'unrestricted', 'sp': 'unrestricted'}) + self.assertEqual(self.sched1.output['C2H6']['warnings'], '') + + def test_a_composite_sp_records_no_scf_reference(self): + """Test that a level ARC writes no r/u prefix for is not compared against a DFT job's reference""" + species = self._reset_reference_records() + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('freq', False)) + with self.assertNoLogs('arc', level='WARNING'): + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('sp', True, method='cbs-qb3')) + self.assertEqual(species.scf_references, {'freq': 'unrestricted'}) + + def test_the_reference_recorded_is_the_memo_the_job_adapter_left(self): + """Test that the scheduler reads the reference is_restricted recorded, under that name""" + species = self._reset_reference_records() + probe = SimpleNamespace(run_multi_species=False, + job_type='freq', + level=Level(method='wb97xd', basis='def2-TZVP'), + multiplicity=3, + species=[self.sched1.species_dict['C2H6']], + ) + self.assertFalse(is_restricted(probe)) + self.sched1.record_scf_reference(label='C2H6', job=probe) + self.assertEqual(species.scf_references, {'freq': 'unrestricted'}) + + def test_a_corrupt_reference_record_is_read_as_holding_nothing(self): + """Test that the consistency check treats a scf_references that is not a mapping as empty""" + species = self._reset_reference_records() + for references in [None, [], 'restricted', ['freq', 'restricted']]: + species.scf_references = references + with self.assertNoLogs('arc', level='WARNING'): + self.sched1.check_scf_reference_consistency(label='C2H6') + self.assertEqual(self.sched1.output['C2H6']['warnings'], '') + + def test_a_job_carrying_no_reference_memo_records_nothing(self): + """Test that a pipe task, which never wrote an ESS input, is skipped""" + species = self._reset_reference_records() + piped = SimpleNamespace(job_type='freq', level=Level(method='wb97xd', basis='def2-TZVP')) + self.sched1.record_scf_reference(label='C2H6', job=piped) + self.assertEqual(species.scf_references, dict()) + + def test_an_optfreq_job_records_the_reference_its_zpe_came_from(self): + """Test that a combined opt+freq job is recorded as the source of the ZPE's reference""" + species = self._reset_reference_records() + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('optfreq', True)) + self.assertEqual(species.scf_references, {'freq': 'restricted'}) + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job('sp', False)) + self.assertIn('ZPE(restricted)', ' '.join(r.getMessage() for r in captured.records)) + + def test_a_job_type_that_decides_neither_energy_nor_zpe_records_nothing(self): + """Test that only the jobs an E0 is built from are compared against each other""" + species = self._reset_reference_records() + for job_type in ['opt', 'scan', 'irc', 'orbitals', 'composite', 'conf_opt', 'stability']: + self.sched1.record_scf_reference(label='C2H6', job=self._reference_job(job_type, True)) + self.assertEqual(species.scf_references, dict(), msg=f'{job_type} recorded a reference') + + def test_an_adopted_verdict_with_a_correlated_sp_is_reported_as_a_mixed_reference(self): + """Test that an adopted species whose electronic energy stays restricted is reported as mixing""" + label = 'C2H6' + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + self.addCleanup(setattr, species, 'derived_stability_verdict', species.derived_stability_verdict) + species.is_ts = True + species.number_of_radicals = None + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.assertTrue(adopted_reference_is_unrestricted(species)) + freq_job = job_factory(job_adapter='gaussian', project='project_test', ess_settings=self.ess_settings, + species=[species], job_type='freq', + level=Level(method='wb97xd', basis='def2-TZVP'), + project_directory=self.project_directory, job_num=911) + sp_job = job_factory(job_adapter='molpro', project='project_test', ess_settings=self.ess_settings, + species=[species], job_type='sp', + level=Level(method='ccsd(t)-f12', basis='cc-pvtz-f12'), + project_directory=self.project_directory, job_num=912) + self.assertFalse(is_restricted(freq_job)) + self.assertTrue(is_restricted(sp_job)) + self.sched1.record_scf_reference(label=label, job=freq_job) + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.record_scf_reference(label=label, job=sp_job) + self.assertEqual(species.scf_references, {'freq': 'unrestricted', 'sp': 'restricted'}) + self.assertIn(MIXED_SCF_REFERENCE_MESSAGE, self.sched1.output[label]['warnings']) + message = ' '.join(r.getMessage() for r in captured.records) + self.assertIn('mixes two potential energy surfaces', message) + + def test_a_queued_jobs_scf_reference_survives_a_restart(self): + """Test that a job restored from a restart reports the reference it ran with, not today's""" + label = 'C2H6' + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + self.addCleanup(setattr, species, 'derived_stability_verdict', species.derived_stability_verdict) + self.addCleanup(setattr, self.sched1, 'restart_dict', self.sched1.restart_dict) + self.addCleanup(self.sched1.running_jobs.pop, label, None) + job = job_factory(job_adapter='gaussian', project='project_test', ess_settings=self.ess_settings, + species=[species], job_type='sp', level=Level(method='wb97xd', basis='def2-TZVP'), + project_directory=self.project_directory, job_num=901) + self.addCleanup(self.sched1.job_dict.get(label, dict()).pop, 'sp', None) + self.assertTrue(is_restricted(job)) + job_description = job.as_dict() + self.assertIs(job_description['restricted_used'], True) + + species.is_ts = True + species.derived_stability_verdict = {'verdict': 'external_instability', 'restricted': True} + self.sched1.restart_dict = {'running_jobs': {label: [job_description]}} + self.sched1.restore_running_jobs() + restored = self.sched1.job_dict[label]['sp'][job.job_name] + self.assertIs(restored.restricted_used, True, + msg='the restored job reported the reference it would be given today') + self.sched1.record_scf_reference(label=label, job=restored) + self.assertEqual(species.scf_references, {'sp': 'restricted'}) + + def test_a_restored_job_that_persisted_no_reference_recomputes_one(self): + """Test that a restart written before the memo existed still restores its jobs""" + label = 'C2H6' + species = self._reset_reference_records(label) + self.addCleanup(setattr, self.sched1, 'restart_dict', self.sched1.restart_dict) + self.addCleanup(self.sched1.running_jobs.pop, label, None) + job = job_factory(job_adapter='gaussian', project='project_test', ess_settings=self.ess_settings, + species=[species], job_type='sp', level=Level(method='wb97xd', basis='def2-TZVP'), + project_directory=self.project_directory, job_num=902) + self.addCleanup(self.sched1.job_dict.get(label, dict()).pop, 'sp', None) + job_description = job.as_dict() + del job_description['restricted_used'] + self.sched1.restart_dict = {'running_jobs': {label: [job_description]}} + self.sched1.restore_running_jobs() + restored = self.sched1.job_dict[label]['sp'][job.job_name] + self.assertIs(restored.restricted_used, True) + + def _abandoned_ts_freq_job(self, label='C2H6'): + """Put a species into the state a freq job that fails the NMD check leaves it in.""" + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + self.addCleanup(setattr, species, 'ts_guesses_exhausted', species.ts_guesses_exhausted) + self.addCleanup(setattr, species, 'derived_stability_verdict', species.derived_stability_verdict) + species.is_ts = True + species.ts_guesses_exhausted = True + species.ts_checks = {'NMD': False} + species.scf_references = {'freq': 'restricted', 'sp': 'unrestricted'} + self.sched1.output[label]['warnings'] = MIXED_SCF_REFERENCE_MESSAGE + job = MagicMock() + job.job_adapter = 'gaussian' + job.job_name = 'freq_a1' + job.level = Level(method='wb97xd', basis='def2-TZVP') + job.job_type = 'freq' + job.restricted_used = True + job.job_status = ['done', {'status': 'done'}] + job.local_path_to_output_file = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', + 'calcs', 'Species', 'NH2_freq.out') + return species, job + + def test_a_switched_away_ts_guess_does_not_write_its_reference_back(self): + """Test that the freq job of an abandoned TS guess records nothing after the switch cleared it""" + label = 'C2H6' + species, job = self._abandoned_ts_freq_job(label) + with patch.object(self.sched1, 'check_negative_freq', return_value=(True, False)), \ + patch.object(self.sched1, 'determine_most_likely_ts_conformer'), \ + patch.object(self.sched1, 'delete_all_species_jobs'), \ + patch('arc.scheduler.parser.parse_frequencies', return_value=[-1000.0]), \ + patch('arc.scheduler.safe_copy_file'), \ + patch('arc.scheduler.parser.parse_polarizability', return_value=None): + self.sched1.check_freq_job(label=label, job=job) + self.assertEqual(species.scf_references, dict()) + self.assertNotIn('different SCF references', self.sched1.output[label]['warnings']) + + def test_a_ts_guess_that_is_kept_still_records_its_freq_reference(self): + """Test that suppressing the record at a switch did not suppress it for a TS that passed""" + label = 'C2H6' + species, job = self._abandoned_ts_freq_job(label) + species.ts_checks = {'NMD': True} + species.scf_references = dict() + self.sched1.output[label]['warnings'] = '' + with patch.object(self.sched1, 'check_negative_freq', return_value=(True, False)), \ + patch.object(self.sched1, 'check_rxn_e0_by_spc'), \ + patch('arc.scheduler.parser.parse_frequencies', return_value=[-1000.0]), \ + patch('arc.scheduler.safe_copy_file'), \ + patch('arc.scheduler.parser.parse_polarizability', return_value=None): + self.sched1.check_freq_job(label=label, job=job) + self.assertEqual(species.scf_references, {'freq': 'restricted'}) + + def test_post_sp_actions_records_the_reference_of_the_job_the_energy_came_from(self): + """Test that the job supplying the electronic energy is recorded under the energy's key""" + label = 'C2H6' + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'e_elect', species.e_elect) + self.addCleanup(self.sched1.output[label]['paths'].__setitem__, 'sp', + self.sched1.output[label]['paths'].get('sp')) + sp_path = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + self.sched1.post_sp_actions(label=label, sp_path=sp_path, + level=Level(method='wb97xd', basis='def2-TZVP'), + job=self._reference_job('opt', True)) + self.assertEqual(species.scf_references, {'sp': 'restricted'}) + + def test_post_sp_actions_records_nothing_where_no_job_is_named(self): + """Test that a caller with no job to name, a restored species among them, records nothing""" + label = 'C2H6' + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'e_elect', species.e_elect) + self.addCleanup(self.sched1.output[label]['paths'].__setitem__, 'sp', + self.sched1.output[label]['paths'].get('sp')) + sp_path = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + self.sched1.post_sp_actions(label=label, sp_path=sp_path, + level=Level(method='wb97xd', basis='def2-TZVP')) + self.assertEqual(species.scf_references, dict()) + + def test_an_sp_at_the_opt_level_hands_the_optimization_job_over(self): + """Test that the branch submitting no sp job still names the job the energy is read from""" + label = 'C2H6' + self._reset_reference_records(label) + self.addCleanup(self.sched1.job_dict[label].pop, 'opt', None) + self.addCleanup(self.sched1.output[label]['paths'].__setitem__, 'geo', + self.sched1.output[label]['paths'].get('geo')) + opt_job = self._reference_job('opt', True) + opt_job.local_path_to_output_file = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', + 'calcs', 'Species', 'NH2_freq.out') + opt_job.rename_output_file = MagicMock() + self.sched1.job_dict[label]['opt'] = {'opt_a1': opt_job} + self.sched1.output[label]['paths']['geo'] = opt_job.local_path_to_output_file + with patch.object(self.sched1, 'post_sp_actions') as post_sp_actions: + self.sched1.run_sp_job(label=label, level=self.sched1.opt_level) + self.assertIs(post_sp_actions.call_args.kwargs['job'], opt_job) + + def test_a_single_level_run_can_report_a_mixed_reference(self): + """Test that a species whose sp level equals its opt level is not blind to a mixed reference""" + label = 'C2H6' + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'e_elect', species.e_elect) + self.addCleanup(self.sched1.output[label]['paths'].__setitem__, 'sp', + self.sched1.output[label]['paths'].get('sp')) + sp_path = os.path.join(ARC_TESTING_PATH, 'restart', '2_restart_rate', 'calcs', 'Species', 'NH2_freq.out') + self.sched1.record_scf_reference(label=label, job=self._reference_job('freq', False)) + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.post_sp_actions(label=label, sp_path=sp_path, + level=Level(method='wb97xd', basis='def2-TZVP'), + job=self._reference_job('opt', True)) + self.assertEqual(species.scf_references, {'freq': 'unrestricted', 'sp': 'restricted'}) + self.assertIn('E_elect(restricted)', ' '.join(r.getMessage() for r in captured.records)) + self.assertIn(MIXED_SCF_REFERENCE_MESSAGE, self.sched1.output[label]['warnings']) + + def _stability_verdict_job(self, label='C2H6'): + """Build a completed stability job pointing at a real analysis log.""" + species = self.sched1.species_dict[label] + self.addCleanup(setattr, species, 'derived_stability_verdict', species.derived_stability_verdict) + self.addCleanup(self.sched1.output[label]['paths'].pop, 'stability', None) + self.addCleanup(self.sched1.output[label].pop, 'wavefunction_stability', None) + self.addCleanup(self.sched1.output[label].__setitem__, 'info', self.sched1.output[label]['info']) + job = MagicMock() + job.job_status = ['done', {'status': 'done'}] + job.local_path_to_output_file = os.path.join(ARC_TESTING_PATH, 'stability', + 'stable_restricted_singlet_ts.out') + return job + + def test_an_invalidated_analytic_hessian_reaches_the_output_warnings(self): + """Test that a verdict putting the analytic frequencies out of range is reported in output.yml""" + label = 'C2H6' + self._reset_reference_records(label) + job = self._stability_verdict_job(label) + verdict = {'verdict': 'internal_instability', 'internal_instability': True, + 'external_instability': None, 'relaxations': [], 'negative_eigenvectors': [], + 'lowest_eigenvalue': -0.0731, 'restricted': True, 'invalidates_analytic_freq': True} + with patch('arc.scheduler.parser.parse_wavefunction_stability', return_value=verdict): + self.sched1.check_stability_job(label=label, job=job) + self.assertIn(INVALID_ANALYTIC_FREQ_MESSAGE, self.sched1.output[label]['warnings']) + + def test_a_verdict_leaving_the_analytic_hessian_defined_adds_no_warning(self): + """Test that the warning is raised by the invalidating verdicts alone""" + label = 'C2H6' + self._reset_reference_records(label) + job = self._stability_verdict_job(label) + self.sched1.check_stability_job(label=label, job=job) + self.assertNotIn(INVALID_ANALYTIC_FREQ_MESSAGE, self.sched1.output[label]['warnings']) + + def test_a_stability_verdict_carries_the_log_it_was_read_from(self): + """Test that the verdict on the species names the analysis that produced it""" + label = 'C2H6' + job = self._stability_verdict_job(label) + self.sched1.check_stability_job(label=label, job=job) + self.assertEqual(self.sched1.species_dict[label].derived_stability_verdict['log'], + job.local_path_to_output_file) + + def _spin_contamination_species(self, label='C2H6', multiplicity=2): + """Put a species at a given multiplicity with empty output warnings, restoring both afterwards.""" + species = self._reset_reference_records(label) + self.addCleanup(setattr, species, 'multiplicity', species.multiplicity) + species.multiplicity = multiplicity + return species + + def test_a_spin_contaminated_energy_is_warned_about(self): + """Test that an energy taken from a badly contaminated wavefunction is reported""" + label = 'C2H6' + self._spin_contamination_species(label) + path = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_spin_contaminated_doublet_ts.out') + with self.assertLogs('arc', level='WARNING') as captured: + self.sched1.check_spin_contamination(label=label, sp_path=path) + message = ' '.join(r.getMessage() for r in captured.records) + self.assertIn('1.7488', message) + self.assertIn('0.75', message) + self.assertIn(SPIN_CONTAMINATION_MESSAGE, self.sched1.output[label]['warnings']) + + def test_a_clean_open_shell_energy_is_not_warned_about(self): + """Test that the ordinary contamination of a converged doublet stays off the warning channel""" + label = 'C2H6' + self._spin_contamination_species(label) + path = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_unrestricted_doublet_ts.out') + with self.assertNoLogs('arc', level='WARNING'): + self.sched1.check_spin_contamination(label=label, sp_path=path) + self.assertEqual(self.sched1.output[label]['warnings'], '') + + def test_a_restricted_energy_has_no_spin_diagnostic_to_check(self): + """Test that a closed-shell log, which prints no , is passed over rather than reported clean""" + label = 'C2H6' + self._spin_contamination_species(label, multiplicity=1) + path = os.path.join(ARC_TESTING_PATH, 'stability', 'stable_restricted_singlet_ts.out') + with self.assertNoLogs('arc', level='WARNING'): + self.sched1.check_spin_contamination(label=label, sp_path=path) + self.assertEqual(self.sched1.output[label]['warnings'], '') + + def test_a_missing_energy_log_is_not_a_spin_contamination_verdict(self): + """Test that an absent or unnamed log yields neither a warning nor a raise""" + label = 'C2H6' + self._spin_contamination_species(label) + for path in [None, '', os.path.join(ARC_TESTING_PATH, 'stability', 'no_such_log.out')]: + with self.assertNoLogs('arc', level='WARNING'): + self.sched1.check_spin_contamination(label=label, sp_path=path) + self.assertEqual(self.sched1.output[label]['warnings'], '') + + def test_the_spin_contamination_threshold_is_the_one_the_module_documents(self): + """Test the threshold itself, so a change to it is a deliberate one""" + self.assertEqual(MAX_S_SQUARED_DEVIATION, 0.1) + + def _prepare_verdict_for_switch(self, verdict, chosen_ts=3, label='C2H6', number_of_radicals=None): + """Put a species into the state a TS switch would find it in, restoring it afterwards.""" + species = self.sched1.species_dict[label] + self.addCleanup(setattr, species, 'derived_stability_verdict', species.derived_stability_verdict) + self.addCleanup(setattr, species, 'scf_references', species.scf_references) + self.addCleanup(setattr, species, 'chosen_ts', species.chosen_ts) + self.addCleanup(setattr, species, 'is_ts', species.is_ts) + self.addCleanup(setattr, species, 'number_of_radicals', species.number_of_radicals) + original_warnings = self.sched1.output[label]['warnings'] + self.addCleanup(self.sched1.output[label].__setitem__, 'warnings', original_warnings) + self.sched1.output[label]['warnings'] = MIXED_SCF_REFERENCE_MESSAGE + species.is_ts = True + species.number_of_radicals = number_of_radicals + species.chosen_ts = chosen_ts + species.scf_references = {'freq': 'restricted', 'sp': 'unrestricted'} + species.derived_stability_verdict = verdict + return species + + def test_an_adopted_instability_is_carried_across_a_ts_switch_without_geometry_detail(self): + """Test that the reference decision survives a TS switch while the abandoned numbers do not""" + species = self._prepare_verdict_for_switch( + {'verdict': 'external_instability', 'restricted': True, 'relaxations': ['RHF -> UHF'], + 'negative_eigenvectors': [{'label': 'Triplet-A', 'eigenvalue': -0.0642}], + 'lowest_eigenvalue': -0.0642, 'invalidates_analytic_freq': False, + 'log': '/calcs/TSs/TS0/stability_a5/output.out'}) + self.sched1.carry_stability_verdict_across_ts_switch(label='C2H6') + self.assertEqual(species.derived_stability_verdict, + {'verdict': 'external_instability', 'restricted': True, + 'relaxations': ['RHF -> UHF'], 'measured_on_ts_guess': 3, + 'log': '/calcs/TSs/TS0/stability_a5/output.out'}) + self.assertTrue(derived_instability_breaks_spin_symmetry(species)) + self.assertEqual(species.scf_references, dict()) + self.assertNotIn('different SCF references', self.sched1.output['C2H6']['warnings']) + + def test_a_ts_switch_leaves_no_summary_of_the_abandoned_geometry_behind(self): + """Test that the run summary and output.yml are reduced together, not one of the two""" + label = 'C2H6' + summary = 'external_instability (Triplet-A, -0.0642)' + species = self._prepare_verdict_for_switch( + {'verdict': 'external_instability', 'restricted': True, 'relaxations': ['RHF -> UHF'], + 'negative_eigenvectors': [{'label': 'Triplet-A', 'eigenvalue': -0.0642}], + 'lowest_eigenvalue': -0.0642, 'invalidates_analytic_freq': True}, label=label) + self.addCleanup(self.sched1.output[label].__setitem__, 'info', self.sched1.output[label]['info']) + self.addCleanup(self.sched1.output[label].pop, 'wavefunction_stability', None) + self.sched1.output[label]['wavefunction_stability'] = summary + self.sched1.output[label]['info'] = f'T1 = 0.011; Wavefunction stability: {summary}; ' + self.sched1.output[label]['warnings'] += INVALID_ANALYTIC_FREQ_MESSAGE + SPIN_CONTAMINATION_MESSAGE + self.sched1.carry_stability_verdict_across_ts_switch(label=label) + self.assertIsNone(self.sched1.output[label]['wavefunction_stability']) + self.assertEqual(self.sched1.output[label]['info'], 'T1 = 0.011; ') + self.assertNotIn('Triplet-A', self.sched1.output[label]['info']) + self.assertNotIn(INVALID_ANALYTIC_FREQ_MESSAGE, self.sched1.output[label]['warnings']) + self.assertNotIn(SPIN_CONTAMINATION_MESSAGE, self.sched1.output[label]['warnings']) + self.assertEqual(species.derived_stability_verdict['measured_on_ts_guess'], 3) + + def test_a_ts_switch_strips_the_unreachable_reference_warning(self): + """Test that the warning goes with the verdict it describes, which is always dropped""" + label = 'C2H6' + species = self._prepare_verdict_for_switch( + {'verdict': 'external_instability', 'restricted': True, 'relaxations': ['RHF -> UHF'], + 'negative_eigenvectors': [], 'lowest_eigenvalue': -0.0642, 'invalidates_analytic_freq': False, + REFERENCE_CHANGE_AVAILABLE_KEY: False}, label=label) + self.sched1.output[label]['warnings'] += UNREACHABLE_REFERENCE_MESSAGE + self.sched1.carry_stability_verdict_across_ts_switch(label=label) + self.assertIsNone(species.derived_stability_verdict) + self.assertNotIn(UNREACHABLE_REFERENCE_MESSAGE, self.sched1.output[label]['warnings']) + self.assertNotIn(MIXED_SCF_REFERENCE_MESSAGE, self.sched1.output[label]['warnings']) + + def test_a_verdict_a_declaration_blocks_is_not_carried_across_a_ts_switch(self): + """Test that a verdict ARC will never adopt is not promised to the next TS guess""" + for number_of_radicals in [0, 1, 2]: + species = self._prepare_verdict_for_switch( + {'verdict': 'external_instability', 'restricted': True, 'relaxations': ['RHF -> UHF'], + 'negative_eigenvectors': [], 'lowest_eigenvalue': -0.0642, 'invalidates_analytic_freq': False}, + number_of_radicals=number_of_radicals) + self.sched1.carry_stability_verdict_across_ts_switch(label='C2H6') + self.assertIsNone(species.derived_stability_verdict, + msg=f'a verdict was carried for a declared number_of_radicals ' + f'of {number_of_radicals}') + + def test_every_verdict_that_decides_nothing_is_dropped_at_a_ts_switch(self): + """Test that a verdict with no consumer is not attributed to the next TS guess""" + for verdict in [{'verdict': 'stable', 'restricted': True}, + {'verdict': 'internal_instability', 'restricted': True}, + {'verdict': 'unknown', 'restricted': None}, + {'verdict': 'external_instability', 'restricted': False}, + ]: + species = self._prepare_verdict_for_switch(dict(verdict)) + self.sched1.carry_stability_verdict_across_ts_switch(label='C2H6') + self.assertIsNone(species.derived_stability_verdict, msg=f'{verdict} was carried over') + self.assertEqual(species.scf_references, dict()) + + def test_a_dropped_verdict_leaves_the_next_ts_guess_to_be_measured(self): + """Test that abandoning a guess whose verdict decides nothing re-opens the analysis""" + for verdict in [{'verdict': 'stable', 'restricted': True}, + {'verdict': 'internal_instability', 'restricted': True}, + {'verdict': 'external_instability', 'restricted': False}, + None, + ]: + species = self._prepare_verdict_for_switch(dict(verdict) if verdict is not None else None) + species.stability_analysis_ran = True + self.sched1.carry_stability_verdict_across_ts_switch(label='C2H6') + self.assertIsNone(species.derived_stability_verdict, msg=f'{verdict} was carried over') + self.assertFalse(species.stability_analysis_ran, + msg=f'the next guess is not measured after {verdict} was dropped') + + def test_a_carried_verdict_leaves_the_next_ts_guess_unmeasured(self): + """Test that a verdict that decides the next guess' reference is not measured against""" + species = self._prepare_verdict_for_switch( + {'verdict': 'external_instability', 'restricted': True, 'relaxations': ['RHF -> UHF'], + 'negative_eigenvectors': [], 'lowest_eigenvalue': -0.0642, 'invalidates_analytic_freq': False}) + species.stability_analysis_ran = True + self.sched1.carry_stability_verdict_across_ts_switch(label='C2H6') + self.assertIsNotNone(species.derived_stability_verdict) + self.assertTrue(species.stability_analysis_ran) + + def test_switch_ts_reduces_the_stability_verdict(self): + """Test that the TS switch path is what reduces the verdict, not only the helper""" + species = self.sched1.species_dict['C2H6'] + self.addCleanup(setattr, species, 'ts_guesses_exhausted', species.ts_guesses_exhausted) + species.ts_guesses_exhausted = True + with patch.object(self.sched1, 'determine_most_likely_ts_conformer'), \ + patch.object(self.sched1, 'delete_all_species_jobs'), \ + patch.object(self.sched1, 'carry_stability_verdict_across_ts_switch') as carry: + self.sched1.switch_ts(label='C2H6') + self.assertTrue(carry.called) + + def test_switch_ts_carries_the_verdict_before_the_next_guess_is_chosen(self): + """Test that the carried verdict names the guess it was measured on, not the one replacing it""" + label, abandoned_guess, next_guess = 'C2H6', 3, 7 + species = self._prepare_verdict_for_switch( + {'verdict': 'external_instability', 'restricted': True, 'relaxations': ['RHF -> UHF'], + 'negative_eigenvectors': [], 'lowest_eigenvalue': -0.0642, + 'invalidates_analytic_freq': False}, + chosen_ts=abandoned_guess, label=label) + self.addCleanup(setattr, species, 'ts_guesses_exhausted', species.ts_guesses_exhausted) + self.addCleanup(self.sched1.output[label].pop, 'wavefunction_stability', None) + species.ts_guesses_exhausted = True + + def choose_the_next_guess(label): + """Stand in for the TS guess selection, which picks a different guess.""" + self.sched1.species_dict[label].chosen_ts = next_guess + + with patch.object(self.sched1, 'determine_most_likely_ts_conformer', + side_effect=choose_the_next_guess), \ + patch.object(self.sched1, 'delete_all_species_jobs'): + self.sched1.switch_ts(label=label) + self.assertEqual(species.chosen_ts, next_guess) + self.assertEqual(species.derived_stability_verdict['measured_on_ts_guess'], abandoned_guess) + def test_does_output_dict_contain_info(self): """Test Scheduler.does_output_dict_contain_info""" self.sched1.output = dict() @@ -2031,6 +3579,32 @@ def test_report_running_jobs_snapshot(self): os.remove(path) + @patch('arc.scheduler.job_factory') + def test_run_job_reports_a_collapsible_reference_for_the_job_it_spawned(self, mock_job_factory): + """Test that every job run_job() spawns is offered to the collapsible-reference report""" + job_mock = MagicMock() + job_mock.job_name = 'sp_a0000' + job_mock.server = None + mock_job_factory.return_value = job_mock + level = Level(method='wb97xd', basis='def2tzvp', software='gaussian') + project_directory = os.path.join(ARC_PATH, 'Projects', 'arc_project_run_job_collapsible_reference') + self.addCleanup(shutil.rmtree, project_directory, ignore_errors=True) + sched = Scheduler(project='test_run_job_collapsible_reference', ess_settings=self.ess_settings, + species_list=[ARCSpecies(label='C2H6', smiles='CC')], + opt_level=level, + freq_level=Level(repr=default_levels_of_theory['freq']), + sp_level=Level(repr=default_levels_of_theory['sp']), + ts_guess_level=Level(repr=default_levels_of_theory['ts_guesses']), + project_directory=project_directory, + testing=True, + job_types=self.job_types1, + ) + with patch.object(sched, 'warn_on_collapsible_unrestricted_reference') as reported: + sched.run_job(label='C2H6', job_type='sp', level_of_theory=level, job_adapter='molpro') + self.assertTrue(reported.called) + self.assertEqual(reported.call_args.kwargs['label'], 'C2H6') + self.assertIs(reported.call_args.kwargs['job'], job_mock) + @patch('arc.scheduler.job_factory') def test_run_job_does_not_alias_level_args(self, mock_job_factory): """Test that run_job() passes a detached copy of the level args to the job.""" From fcd3b76fe146102d158f595a24be031c597d2721 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 08/12] Carry the ORCA orbitals file through every shipped submit template The ORCA stability job emits %moinp "guess.gbw" and uploads guess.gbw to the remote job path, but every ORCA template in this file copied only the input file into the scratch $WorkDir, and `grep -n gbw arc/settings/submit.py` returned nothing at all. With ARC's repo defaults ORCA therefore aborts with `Cannot open file guess.gbw` on every stability job, determine_ess_status classifies that as errored/['Unknown'], and ARC troubleshoots a deterministic failure for as long as the run lasts. The feature only worked on the machine it was developed on because that machine's ~/.arc/submit.py overlay happens to glob *.gbw, and a repo settings value says nothing about production: the overlay shallow-replaces whole dicts, so what a developer runs and what this branch ships are different files. Every ORCA template now copies guess.gbw in and input.gbw back out, in each template's own style: the three that name the files they return copy both explicitly, the two that copy the whole work directory back need only the inbound line, and the HTCondor job.sh lists input.gbw beside the input.log and input_property.txt it already names. Both copies are tolerant of an absent file -- most jobs hand ORCA no guess, and a job that died may have written no orbitals -- so a missing file writes nothing to err.txt and does not affect the exit status. This mirrors the Gaussian template, which has copied check.chk in for as long as guess=read has been emitted. --- arc/settings/submit.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arc/settings/submit.py b/arc/settings/submit.py index de86d4558a..6f5a104215 100644 --- a/arc/settings/submit.py +++ b/arc/settings/submit.py @@ -204,9 +204,11 @@ mkdir -p $WorkDir cd $WorkDir cp $SubmitDir/input.in . +cp $SubmitDir/guess.gbw . 2>/dev/null $orcadir/orca input.in > input.log cp input.log $SubmitDir/ +cp input.gbw $SubmitDir/ 2>/dev/null rm -rf $WorkDir touch final_time @@ -458,12 +460,14 @@ cd $WorkDir cp "$SubmitDir/input.in" . +cp "$SubmitDir/guess.gbw" . 2>/dev/null ${{OrcaDir}}/orca input.in > input.log cd $SubmitDir cp "$WorkDir/input.log" . cp "$WorkDir/input_property.txt" . +cp "$WorkDir/input.gbw" . 2>/dev/null rm -rf $WorkDir @@ -633,6 +637,7 @@ cd $WorkDir cp "$SubmitDir/input.in" . +cp "$SubmitDir/guess.gbw" . 2>/dev/null ${ORCA_DIR}/orca input.in > input.log cp * "$SubmitDir/" @@ -851,6 +856,7 @@ cd $WorkDir cp "$SubmitDir/input.in" . +cp "$SubmitDir/guess.gbw" . 2>/dev/null /opt/orca/orca input.in > input.log cp * "$SubmitDir/" @@ -900,9 +906,11 @@ mkdir -p $WorkDir cd $WorkDir cp $SubmitDir/input.in . +cp $SubmitDir/guess.gbw . 2>/dev/null $orcadir/orca input.in > input.log cp input.log $SubmitDir/ +cp input.gbw $SubmitDir/ 2>/dev/null rm -rf $WorkDir touch final_time @@ -1013,9 +1021,11 @@ mkdir -p $WorkDir cd $WorkDir cp $SubmitDir/input.in . +cp $SubmitDir/guess.gbw . 2>/dev/null $orcadir/orca input.in > input.log cp input.log $SubmitDir/ +cp input.gbw $SubmitDir/ 2>/dev/null rm -rf $WorkDir touch final_time From eeb714f6ca953b47d7fb3cc4a7300f93166901a3 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 09/12] Refuse a checkfile written by another ESS in the Psi4 adapter Psi4 is the one ESS adapter that does not route its construction through _initialize_adapter, so the guard JobAdapter.readable_checkfile applies to every other adapter did not reach it. Scheduler hands every job the checkfile its species holds whichever ESS wrote it, and this adapter assigned it unconditionally and then uploaded it as check.chk, so a species optimized in ORCA would have had its input.gbw handed to Psi4 under a Gaussian name. The assignment now goes through the same guard, which is a one-expression change and leaves every other line of the adapter alone. --- arc/job/adapters/psi_4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arc/job/adapters/psi_4.py b/arc/job/adapters/psi_4.py index 8d280f5ebc..3ae8cad131 100644 --- a/arc/job/adapters/psi_4.py +++ b/arc/job/adapters/psi_4.py @@ -209,7 +209,7 @@ def __init__(self, self.job_type = job_type if isinstance(job_type, str) else job_type[0] # always a string self.args = args or dict() self.bath_gas = bath_gas - self.checkfile = checkfile + self.checkfile = self.readable_checkfile(checkfile) self.conformer = conformer self.constraints = constraints or list() self.cpu_cores = cpu_cores From 73dd945a9b7459850c96fbc8542208ff59ac9d6b Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 10/12] Name the TeraChem orbitals file after the file TeraChem writes TeraChem writes its converged orbitals to teracheck.chk, while the JobAdapter defaults name Gaussian's check.chk. The base name is what readable_checkfile identifies the ESS that wrote a checkfile by, and what set_file_paths builds local_path_to_check_file from, so the adapter accepted a Gaussian checkfile as an initial guess and refused TeraChem's own, and the file a completed TeraChem job leaves behind was looked for under a name TeraChem never writes. check_file_name and guess_file_name are declared on TeraChemAdapter as they are on OrcaAdapter, and the two places the name was spelled out in the adapter, the fallback to an orbitals file in the job's own directory and the chkfile line of the input template, read the class attribute. The fallback goes through readable_checkfile, so it refuses an empty file as every other adapter's does. --- arc/job/adapters/terachem.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arc/job/adapters/terachem.py b/arc/job/adapters/terachem.py index 49b9c5af0f..23d6c5181e 100644 --- a/arc/job/adapters/terachem.py +++ b/arc/job/adapters/terachem.py @@ -109,6 +109,9 @@ class TeraChemAdapter(JobAdapter): xyz (dict, optional): The 3D coordinates to use. If not give, species.get_xyz() will be used. """ + check_file_name = 'teracheck.chk' + guess_file_name = 'teracheck.chk' + def __init__(self, project: str, project_directory: str, @@ -204,8 +207,8 @@ def __init__(self, if self.is_ts: raise ValueError('TeraChem does not perform TS optimization jobs') - if self.checkfile is None and os.path.isfile(os.path.join(self.local_path, 'teracheck.chk')): - self.checkfile = os.path.join(self.local_path, 'teracheck.chk') + if self.checkfile is None: + self.checkfile = self.readable_checkfile(os.path.join(self.local_path, self.check_file_name)) def write_input_file(self) -> None: """ @@ -221,7 +224,7 @@ def write_input_file(self) -> None: input_dict[key] = '' input_dict['basis'] = self.level.basis or '' input_dict['charge'] = self.charge - input_dict['checkfile'] = 'teracheck.chk' + input_dict['checkfile'] = self.check_file_name input_dict['memory'] = self.input_file_memory input_dict['method'] = self.level.method input_dict['multiplicity'] = self.multiplicity From 0d1520eb5161fd66bd2e2db4e8fa75ddce8e20c9 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 11/12] Document the stability job type and the SCF-reference adoption contract Adds ``stability`` to the job type list in the advanced documentation, and to the two job-type dictionaries the page shows as examples, so that a reader copying either gets a dictionary matching the one ARC now builds. The entry states the whole user-visible contract in one place: the job runs in Gaussian and ORCA and is off by default; it runs from the optimization, ahead of the frequency job, the single point, the IRC and the rotor scans, all of which are held for its verdict; it runs for a TS and for any other species whose optimization ran with a restricted reference, which is the only reference it can inform; a TS's external instability of a restricted reference re-optimizes the species unrestricted from the geometry the first optimization reached, at most once per species and recorded in the restart file; a declared ``number_of_radicals`` always wins; and for anything that is not a TS the verdict is reported and nothing acts on it. It also states which orbitals the re-optimization starts from and why the answer differs by ESS: ORCA follows the instability and writes the relaxed broken-symmetry orbitals, which are the ones to start from, while Gaussian's ``stable=(rext,noopt)`` leaves its checkfile holding the restricted solution, which an unrestricted SCF reading it would simply return to, so the checkfile is dropped and the job runs ``guess=mix``. It also says what a long run of ``stable`` verdicts means, so that it is read as the diagnostic working rather than as it having nothing to do: a well verified stable has identical restricted and unrestricted energies, so a barrier taken between it and a TS ARC has made unrestricted is a difference on one surface rather than across two, and an undeclared singlet biradical is caught by nothing else in ARC. And it says what an adopted verdict does not buy. The broken-symmetry solution is not a spin eigenfunction; it mixes in the higher multiplicity, so its energy lies ABOVE the spin-pure low-spin energy, and the restricted energy it replaces lies above the broken-symmetry one in turn: E_projected < E_BS < E_restricted. An adoption is therefore a step toward the spin-pure energy that stops short of it. ARC does not project the contamination out; ``arc/checks/spin.py`` holds the Yamaguchi arithmetic that estimates E_projected, so the residual error after an adoption is the contamination itself, in the direction it already had. The size of that residual is not left to be inferred either: an ```` deviating from its spin-pure S(S+1) by more than 0.1 is warned about where the electronic energy is read. The advice to declare ``number_of_radicals = 2`` names the value rather than the key, because ARC reads a declaration as open-shell character only above one. Also documents the ORCA path: why the instability is always followed rather than only reported, that the resulting log holds two analyses and which one is the verdict, how the orbitals under test are handed over given that ORCA names its own orbitals after the input file, and why an ORCA stable verdict on an unrestricted reference says less than a Gaussian one. Corrects the claim that the two codes do not test the same space. They do: Gaussian's Stable=RExt uses the same Ms-conserving singles matrix ORCA uses, for both references, and neither reaches the GHF sector, so neither verdict is the weaker one. The comparison that produced the original claim was also run at unmatched functional -- plain ORCA B3LYP is VWN-5 against Gaussian's VWN3 -- and at matched functional the roots agree to under 0.4% wherever both codes found the same SCF solution. The one system that still disagrees is a near-dissociated radical pair on which the two codes converged to different UHF solutions, and it supports no cross-code conclusion. The section also now records how a restricted reference's sector is measured from the followed solution's , that a barrier taken across an adopted verdict is OVERestimated in a known direction by the TS's residual contamination -- less so than the all-restricted barrier it replaces, which sat higher still -- that neither code computes a spin-flip root for an unrestricted reference so both readers leave the external sector undetermined there, that both ESSs chain their orbitals from the optimization so the tested wavefunction is the optimization's, which ORCA job types read a guess and what the chain is worth on a broken-symmetry TS, and that a site running its own submit.py must copy guess.gbw in and input.gbw out. Also documents that a verdict is acted on only where the optimization, the frequency job and the single point all run in an ESS ARC breaks the spin symmetry for, which the default Molpro single point is not; that a TS switch drops every verdict it does not carry and lets the next guess be measured; that the ORCA sector is read off any solution the log relaxed into rather than only a stable one; and that a single point batched through the pipe composes the same reference, the verdict travelling with the species dictionary the pipe task carries. The paragraph on an ESS ARC can offer neither mechanism is rewritten as a statement about ARC's adapters: Molpro has a {uhf} program and a ROTATE directive that mixes two starting orbitals, while ARC's Molpro adapter writes {hf} in every input it composes, so what the run cannot do is compose the reference rather than ask Molpro for it. THE BS-UHF CCSD(T)-F12 MEASUREMENT IS WITHDRAWN. The three rows behind it were internally consistent -- E_corr equalled E_CC minus E_SCF to machine precision for each -- but they refute one another. Against the ROHF triplet row, another open-shell F12 treatment of the same molecule, same basis, same code family, the BS-UHF reference recovered 0.2237 Eh less correlation, 22.7 per cent of the total; against RHF, 0.3264 Eh, 30 per cent. The RHF and ROHF-triplet total energies agree to 0.011 Eh, 6.9 kcal/mol, which is what a total energy should do once correlation is included; the BS row sits 140 kcal/mol above RHF and 133 above ROHF. Two independent treatments agreeing to 7 kcal/mol and a third disagreeing by 140 is a broken calculation, not a spin-relaxation effect, and the direction is wrong as well: BS-UHF is variationally 64 kcal/mol BELOW RHF at the SCF level and is the better zeroth-order description of a biradicaloid, so coupled cluster built on it cannot land 140 kcal/mol above. The prose also summarised its own table incorrectly, quoting 0.35 Eh where the numbers give 0.3264. The mechanism is Molpro's: ccsd(t)-f12 is its closed-shell program and uccsd(t)-f12 its open-shell one over ROHF orbitals, the U naming spin-unrestricted amplitudes rather than unrestricted orbitals. Neither takes a spin-broken UHF determinant as its reference, so orbitals from {uhf; rotate,...} give an expansion about something that is not the BS determinant, and E_CC minus E_SCF(BS-UHF) then subtracts two different references' energies. The T1 and D1 figures measured on that same BS run are withdrawn with it: a diagnostic read off a calculation that is not an energy of the state is no more trustworthy than the energy. The argument is made on the ROHF triplet row instead, where it is made more cleanly anyway -- T1 falls from 0.0410 to 0.0118, below the 0.015 at which ARC reports multireference character, while the total energy moves under 7 kcal/mol. Spin relaxation of the reference suppresses the diagnostic with none of the weirdness, which is exactly the point the section needed. The section also documents the double-hybrid exclusion and the HF-3c admission, and the run-summary claim it makes about warnings is now true of arc/main.py. --- docs/source/advanced.rst | 237 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/docs/source/advanced.rst b/docs/source/advanced.rst index c8c1325c5d..a688b4c8a9 100644 --- a/docs/source/advanced.rst +++ b/docs/source/advanced.rst @@ -48,6 +48,241 @@ ARC recognizes these current job type keys: * ``rotors`` - rotor scans; * ``irc`` - intrinsic reaction coordinate; * ``orbitals`` - molecular orbitals; +* ``stability`` - wavefunction stability analysis (Gaussian and ORCA, off by default). It runs for + a TS and for any other species whose optimization ran with a restricted reference, which is + the only reference it can inform: a restricted solution gives the same energy as an + unrestricted one if and only if it is stable. + + IT RUNS FROM THE OPTIMIZATION, before the frequency job, the single point, the IRC and the rotor + scans of that species, all of which inherit the SCF reference and the geometry the optimization + converged to. Those jobs are held until the verdict is in, and it is a single point, so the wait + is one job. For a TS an external instability of a restricted reference re-optimizes the species + unrestricted, starting from the geometry the first optimization reached, and every later job at a + level the verdict decides then runs on that one reference and that one geometry - unless + ``number_of_radicals`` was declared for it, which always wins. Re-optimizing is what makes the + change correct: the restricted geometry is a stationary point of the restricted surface only, and + a Hessian computed there on the broken-symmetry reference can report imaginary modes belonging to + the mismatch rather than to the molecule. At most one re-optimization is run per species, and ARC + records it in the restart file so a resumed run does not spawn another. For any other species the + verdict is reported in the log and in ``output.yml`` and nothing acts on it; declare + ``number_of_radicals = 2`` to run such a species unrestricted throughout, since ARC reads a + declaration as open-shell character only above one. + + WHICH LEVELS THE VERDICT DECIDES: density functional theory and Hartree-Fock, and no other. The + energy of those levels IS the energy of their SCF determinant, so relaxing its spin symmetry onto + the lower solution lowers the number the level reports, which is what the analysis measured. A + correlated wavefunction level - ``CCSD(T)``, ``DLPNO-CCSD(T)``, ``CCSD(T)-F12``, ``MP2`` - keeps + its restricted reference, because its energy is a correlation expansion built about a spin-adapted + reference rather than the energy of that reference. Relaxing the spin symmetry of that reference + absorbs into the orbitals the static correlation the expansion is there to recover, and it + suppresses the ``T1`` diagnostic ARC reads off a coupled cluster single point, whose purpose is to + report a reference the expansion is a poor description about. Measured in Molpro 2026 at + ``cc-pVDZ`` on a C5H10 singlet TS, ``T1`` falls from 0.0410 on the RHF reference to 0.0118 on the + ROHF triplet one, below the 0.015 at which ARC reports multireference character, while the two + ``CCSD(T)-F12`` total energies differ by under 7 kcal/mol: the diagnostic moves without the + energy moving, so the character the analysis measured would be left both uncorrected and + unreported. No corresponding energy is quoted for a broken-symmetry UHF reference, because there + is none to quote: Molpro's ``ccsd(t)-f12`` is its closed-shell program and ``uccsd(t)-f12`` its + open-shell one over ROHF orbitals, and neither takes a spin-broken UHF determinant as its + reference, so no coupled cluster energy OF that determinant exists to compare. + + A DOUBLE HYBRID DOES NOT DECIDE A REFERENCE EITHER, although ARC types it as density functional + theory. ``B2PLYP``, ``DSD-PBEP86``, ``PBE0-DH``, ``wB97X-2`` and the rest add a perturbative + second-order correlation term to their Kohn-Sham determinant, so what they report is not that + determinant's energy but an expansion built about it, which is the construction the correlated + wavefunction levels are excluded for. ``DOUBLE_HYBRID_METHODS`` in + ``arc/job/adapters/common.py`` names them and is read before the method type; it is a deny-list + rather than a classification of every functional, so a double hybrid it does not name is treated + as ordinary density functional theory. ``HF-3c`` goes the other way and does decide a reference: + its counterpoise, dispersion and short-range basis corrections are functions of the nuclear + coordinates rather than of the wavefunction, so its energy is still its determinant's energy plus + a number the reference does not enter. + + THE GEOMETRY AND THE ZPE OF AN ADOPTED SPECIES THEN COME FROM ONE REFERENCE AND ITS ELECTRONIC + ENERGY FROM ANOTHER wherever the single point runs at a correlated level. E0 sums the two, so it + is not a point on either surface, and ARC reports that in the log, in the species' ``output.yml`` + warnings and in the run summary rather than re-running the species. Running the single point at + the optimization level, or declaring ``number_of_radicals = 2``, is what puts every term of that + E0 on one reference. + + ONE ANALYSIS PER WAVEFUNCTION. A TS whose guess is abandoned carries an adopted external + instability over to the next guess, which then runs unrestricted from its first job and is not + analysed again: its reference is already decided. Every other verdict is dropped along with the + geometry it was measured on, and the next guess is analysed in its turn, so ``output.yml`` never + reports a guess that was never measured as one measured stable. + + THE ORBITALS THE RE-OPTIMIZATION STARTS FROM are the analysis' own where the ESS relaxed into the + lower solution, and none otherwise. ORCA follows an instability it finds and writes the relaxed + orbitals to the analysis job's ``input.gbw``, which is the broken-symmetry solution the + re-optimization is meant to sit on. Gaussian's ``stable=(rext,noopt)`` reports an instability + without following it, so its checkfile still holds the restricted orbitals; handing those to an + unrestricted SCF returns it to the very solution the analysis rejected, since a restricted + solution is a stationary point of the unrestricted equations too. ARC therefore drops the + checkfile in that case and the job runs ``guess=mix``, whose deliberately symmetry-broken guess + is what finds the lower solution. + + On a species that is not a TS the analysis is expected to report ``stable`` nearly every time: + well under a few per cent of closed-shell equilibrium geometries are RHF -> UHF unstable. That + is the point of running it. A well verified stable has identical restricted and unrestricted + energies, so a barrier taken between it and a TS that ARC has made unrestricted is a difference + on one surface rather than across two, which cannot otherwise be asserted; and an undeclared + singlet biradical, whose restricted energy is simply wrong, is caught by nothing else in ARC. + + Where the electronic energy is one the verdict decides, adopting a verdict for a TS changes which + biased number is used, not which correct one. The broken-symmetry solution ARC moves to is not a + spin eigenfunction; it mixes in the higher multiplicity, so its energy lies ABOVE the spin-pure + low-spin energy, and the restricted energy it replaces lies above the broken-symmetry one in turn: + ``E_projected < E_BS < E_restricted``. Adoption is therefore a step toward the spin-pure energy + that stops short of it. ARC does not project the contamination out. ``arc/checks/spin.py`` holds + the Yamaguchi approximate spin-projection arithmetic that estimates ``E_projected`` from the + broken-symmetry and high-spin energies and their ``S**2`` values; the residual error after an + adoption is the contamination itself, in the direction it already had. + + THE ERROR IS ONE-SIDED, and this is the practical consequence. Adoption acts for a TS only, so a + TS whose restricted reference was unstable runs unrestricted, at the levels the verdict decides, + while the reactants and products it is compared against stay restricted. The adopted TS energy + still sits above the spin-pure one while the wells, whose restricted references are stable, carry + no such contamination, so the barrier the run reports is systematically OVERestimated by roughly + the residual contamination of the TS -- less so than the all-restricted barrier it replaces, which + sat higher still. A species whose ```` deviates from its spin-pure ``S(S+1)`` by more than + 0.1 is warned about where its electronic energy is read, so the size of that residual is reported + rather than left to be inferred. Declaring ``number_of_radicals`` for the wells too, where their + character warrants it, is what puts both ends on the same footing; + + IN ORCA the analysis is requested with ``STABPerform``, and ARC always pairs it with + ``STABRestartUHFifUnstable true``. With the key set to ``false`` ORCA 6.0.0 prints the verdict + and the stability-matrix roots and then aborts in LEANSCF with a BLAS incompatible-matrices + error, measured at one and at eight processes and at three and at six roots, so ORCA has no + equivalent of Gaussian's ``noopt``, which reports an instability without following it. With the + key ``true`` the job terminates normally: ORCA rotates the orbitals of an unstable wavefunction, + re-converges the SCF and analyses the result again, so the log holds two analyses with opposite + verdicts. ARC reads the verdict of the FIRST one, which is the wavefunction under test; whether + the second reached a stable solution is reported separately as ``followed_to_stable``, and the + spin expectation value of that relaxed solution as ``s_squared_after_follow``. Only the verdict, + the roots and the reference describe the tested wavefunction; every energy and spin value in + that log describes the followed one. The ORCA analysis is an SCF post-step rather than a re-read + of a converged wavefunction, so ARC hands it the orbitals of the job under test: ORCA names its + own orbitals after the input file (``input.gbw``) and cannot read and write one file the way + Gaussian reuses a single checkfile, so the previous orbitals are uploaded as ``guess.gbw`` and + read with ``!MORead`` and ``%moinp``, while the job's own ``input.gbw`` is what is downloaded + and becomes the next job's guess. The ORCA submit templates copy ``guess.gbw`` into the scratch + directory and ``input.gbw`` back out; a site running its own ``~/.arc/submit.py`` must do the + same or any ORCA job reading a guess will abort on a missing guess file. + + THE TWO CODES TEST THE SAME SPACE. ORCA analyses an RHF/RKS reference in UHF/UKS space and a + UHF/UKS reference in UHF/UKS space, both Ms-conserving, and Gaussian's ``stable=(rext,noopt)`` + uses the same Ms-conserving ```` singles matrix for both references. Neither code + reaches the spin-flip (GHF) sector, so neither verdict is the weaker one. Measured on four + systems the two agreed on every verdict, and at matched functional - ORCA's ``B3LYP/G`` is + Gaussian's VWN3 parameterisation, while plain ORCA ``B3LYP`` uses VWN-5 - their lowest roots + agreed to under 0.4% on the three systems where both converged to the same SCF solution. On the + fourth, a near-dissociated O(3P)...CH3 pair, the two codes converged to DIFFERENT UHF solutions + (total energies 0.025 Hartree apart, ```` 1.7488 against 1.700055), so its roots compare + two wavefunctions rather than two codes and support no cross-code conclusion. Because neither + code computes a spin-flip root for an unrestricted reference, both readers report the external + sector as undetermined there rather than as clean: a ``stable`` verdict on an unrestricted + reference covers the spin-conserving sector alone, which is the sector the analytic Hessian is + taken in. + + ORCA DOES NOT LABEL THE ROOT it reports, so for a restricted reference, whose single matrix + spans both the internal and the external sector, the sector is measured rather than assumed: a + nominal singlet that relaxes to a stable solution carrying a non-zero ```` broke the spin + symmetry, which is an external (RHF -> UHF) instability, while one that relaxes to a stable + solution still at ```` of zero moved within the spin-conserving sector, which is an + internal instability. The sector is read off whichever solution ORCA relaxed into, whether or + not the last analysis of the log ended stable: ORCA re-converges the SCF before each analysis it + runs and allows five follow attempts, so a biradicaloid singlet that is still marginally + unstable on the last of them has nonetheless broken the spin symmetry, and the question the + sector answers is whether a lower solution exists outside that symmetry rather than whether the + one ORCA stopped on is itself the bottom. An instability ORCA never followed at all leaves + nothing to measure, and such a verdict is recorded as ``unattributed_instability`` with both + flags left undetermined - never as a stable wavefunction, and never as grounds for changing a + TS's reference. + + WHICH WAVEFUNCTION IS TESTED is the optimization's, in both ESSs, and the analysis reads it from + the orbitals that optimization wrote. Gaussian appends ``guess=read`` and ORCA emits ``!MORead`` + and ``%moinp`` for every job that holds a checkfile, so in both codes the analysis converges from + those orbitals rather than from a fresh guess. Gaussian writes an optimization's converged + orbitals to its ``check.chk`` and ORCA writes them to its ``input.gbw``; ARC adopts that file + from an ``opt``, ``optfreq`` or ``composite`` job as the species' checkfile, and the analysis is + spawned only while the species still holds the one its own optimization wrote. ORCA projects a + guess onto the basis set of the job reading it, + reporting the projection per atom in the log, so the chain crosses the basis change ARC makes + between the optimization and the single point without ARC tracking a level or a basis. A guess + reaches every ORCA job that runs an SCF on one starting structure - ``opt``, ``conf_opt``, + ``optfreq``, ``scan``, ``freq``, ``sp``, ``conf_sp`` and ``stability`` - and no other, since + ARC writes no ORCA input for the remaining job types for a guess to seed. What a chained guess + buys is measured: on a C5H10 TS at ``UKS B3LYP/def2-TZVP``, a fresh guess collapsed to the + closed-shell solution at ```` of zero while ``!MORead`` held the broken-symmetry solution + at ```` of 0.86, 12.7 kcal/mol lower. + + WHERE NO GUESS CROSSES THE ESS BOUNDARY, ARC breaks the spin symmetry for ORCA instead. A + species carrying an adopted verdict runs every later job unrestricted, and an unrestricted SCF + started from a spin-symmetric guess converges, in all but pathological cases, back to the + restricted solution the verdict rejected: a restricted solution is a stationary point of the + unrestricted equations too, so a gradient-following SCF sits on it. Each adapter refuses a + checkfile written by another ESS, so the standard arrangement of a Gaussian geometry and an ORCA + single point leaves the ORCA job no orbitals to read. For that job ARC writes + ``%scf BrokenSym 1,1 end``, which converges a high-spin determinant, localizes its + singly-occupied orbitals and flips those on its second fragment, and which needs no orbital + guess at all. ORCA converges the high-spin determinant first, so such a log carries two + ```` values and the one describing the reported wavefunction is the last. This is not the + same construction as Gaussian's ``guess=mix``, which perturbs the closed-shell guess by mixing + the frontier orbitals, so the two can reach different broken-symmetry solutions. + + THE OPERANDS ARE ``1,1`` because ``BrokenSym Na,Nb`` leaves ``Ms = (Na - Nb) / 2``, which fixes + ``Na = Nb`` at the species' own multiplicity, and because an adopted verdict is an external + instability of a RESTRICTED reference, which ARC composes only for a closed-shell singlet: the + instability establishes that one electron pair prefers to break and does not establish that a + second one does. The directive and ``!MORead`` are alternatives of one another and exactly one + of them is written for a given job. + + WHAT IS NOT HANDED THE DIRECTIVE. A verdict whose relaxed constraint is not the spin one, which + Gaussian reports as ``RHF -> CRHF``, points at a complex solution that no real symmetry-broken + determinant reaches, so it takes no directive. Neither does the ``stability`` job itself, whose + subject is the reference ARC composed for it rather than a forced one, nor a multireference + level, for which a broken-symmetry determinant is the substitute rather than the starting point, + nor a correlated level, whose restricted reference the verdict leaves in place, nor a species + whose multiplicity is not 1 or whose electron count cannot pair off. + + WHAT THE DIRECTIVE CHANGES is measured on the same C5H10 TS: at ``UKS B3LYP/def2-TZVP`` a plain + unrestricted job returned -196.344572 Eh at ```` of zero while ``BrokenSym 1,1`` returned + -196.364789 Eh at ```` of 0.865, which matches the ``!MORead`` solution to 1e-9 Eh. The + barrier such a run reports is then built from a TS whose geometry and ZPE are broken-symmetry and + wells whose are restricted, which is a comparison across two reference treatments. + + AN ADAPTER THAT WRITES NEITHER MECHANISM converges to the restricted solution, so a verdict is + acted on only where the adapters composing every level the verdict decides write a + symmetry-broken reference: the optimization, which supplies the geometry, the frequency job, + which supplies the ZPE, and the single point where it too runs at such a level. A single point at + a correlated level is not tested, since it keeps its restricted reference in every adapter alike. + Read that as a statement about ARC's adapters rather than about the ESSs. Molpro is the case worth + spelling out: Molpro has a ``{uhf}`` program and takes a ``ROTATE`` directive that mixes two + starting orbitals, which is how a broken-symmetry singlet is requested of it, but ARC's Molpro + adapter writes ``{hf}`` in every input it composes - the closed-shell program for a singlet and + the same program in its open-shell, i.e. ROHF, mode above one - and spends the unrestricted + decision on the ``u`` prefix of the correlation method, which selects Molpro's UCCSD(T) rather + than its reference. Writing ``{uhf}`` there would change the label and not the number, since a + UHF singlet started from a symmetric guess converges to the RHF solution; naming the orbitals a + ``ROTATE`` would mix needs their index and irreducible representation, which the adapter has + neither at the point it writes its input nor a ``nosym`` geometry to make unambiguous. + + ARC's default single point runs at ``ccsd(t)-f12/cc-pvtz-f12`` in Molpro, a level the verdict + decides no reference for, so the default arrangement of a Gaussian geometry and a Molpro energy + acts on the verdict for the geometry and the ZPE and leaves the electronic energy restricted; the + E0 then sums terms from two references and the species carries that in its ``output.yml`` + warnings. What still refuses a verdict is an optimization, a frequency job or a single point at a + DFT or Hartree-Fock level whose adapter writes neither mechanism - a Molpro or a QChem geometry, + say - since such a job would record an unrestricted reference for an SCF that reached the + restricted solution. Such a species carries that in its ``output.yml`` warnings too and the log + says what would let the verdict be acted on: running the optimization, the frequency job and any + DFT or Hartree-Fock single point all in Gaussian or all in ORCA. A job type that decision does not + cover, the IRC and the rotor scans of an adopted species, is reported in the same warnings, once + per adapter in the log. A single point batched through the pipe composes the same reference, since + the verdict travels with the species dictionary the pipe task carries, but it is not spawned by + the scheduler's own job path and so is outside that report; so is a Gaussian job whose SCF + troubleshooting replaced its guess keyword with ``guess=INDO``, which carries neither + ``guess=read`` nor ``guess=mix``; * ``onedmin`` - Lennard-Jones / OneDMin workflow; * ``bde`` - bond dissociation energy workflow. @@ -595,6 +830,7 @@ input:: 'rotors': True, 'conf_sp': False, 'orbitals': False, + 'stability': False, 'lennard_jones': False, } @@ -642,6 +878,7 @@ The above code generates the following input file:: lennard_jones: false opt: true orbitals: false + stability: false sp: true species: From 3b4986e70b051b3745c85f0a01ef302696da8625 Mon Sep 17 00:00:00 2001 From: Calvin Pieters Date: Mon, 24 Aug 2026 00:38:51 +0300 Subject: [PATCH 12/12] List the stability job type in the input YAML reference input_reference.rst had no mention of `stability` at all, and its job_types example listed six keys out of twelve, so the only place the feature was documented was advanced.rst -- which describes behaviour and is not where a user goes to find out which keys an input file accepts. The feature was therefore discoverable only by reading the settings module. `stability` is added to the job type key list and to the example with its default, and the example now states which keys default to true and which to false, since the example itself lists a mixture of the two and previously implied that the ones it omitted were unavailable rather than defaulted. A short section states what the analysis is, that ARC has implemented it for Gaussian so far and that other ESSs are not wired up yet, when it runs (once per species, after that species' freq job, for a TS or for a species whose freq job actually ran restricted, at a DFT or HF level, with the freq job's checkfile), and what the user gets back. Which instabilities invalidate analytic frequencies, and what an adopted verdict does and does not correct, stay in advanced.rst; this section links there rather than restating them. The `specific_job_type` interaction is documented because it is a trap. That key replaces job_types wholesale with a dictionary in which only the named type is true, so `specific_job_type: stability` is accepted -- stability is a key of default_job_types, so no InputError is raised -- and then produces nothing at all, because opt, freq and sp are all false and run_stability_job is only ever reached from post_freq_actions. bde is special-cased to re-enable opt/fine/freq/sp; stability is not. Verified against initialize_job_types rather than inferred: specific_job_type 'stability' yields opt False, freq False, sp False, stability True. The reference now says to request it through job_types and says why. Deliberately not documented here: which other programs implement a stability analysis and under what keyword. ORCA and Q-Chem both do, but their exact syntax was not verified against their manuals for this commit, and an unverified keyword in ARC's documentation is worse than none. The text is kept to what ARC does. Also records that the job type now runs in ORCA as well as in Gaussian, that ORCA always follows an instability it finds, and that the two codes test the same space and agree on the verdict, with the sector of a restricted reference's instability read off the solution ORCA relaxes into. --- docs/source/input_reference.rst | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/source/input_reference.rst b/docs/source/input_reference.rst index ae01157de5..5cec6e3bbb 100644 --- a/docs/source/input_reference.rst +++ b/docs/source/input_reference.rst @@ -223,6 +223,7 @@ Current job type keys are: * ``rotors`` * ``irc`` * ``orbitals`` +* ``stability`` * ``onedmin`` * ``bde`` @@ -242,6 +243,44 @@ Example: freq: true sp: true rotors: false + stability: false + +``conf_opt``, ``opt``, ``fine``, ``freq``, ``sp``, ``rotors`` and ``irc`` default to +``true`` when omitted; ``conf_sp``, ``orbitals``, ``stability``, ``onedmin`` and ``bde`` +default to ``false``. + +Wavefunction Stability Analysis +------------------------------- + +``stability`` is off by default and is opt-in through ``job_types``. ARC has implemented +the analysis for Gaussian and for ORCA so far; other ESSs are not wired up yet, and a run +whose frequency jobs go to another ESS is told so once per ESS in the log rather than +silently producing nothing. The two ESSs test the same space and agree on the verdict; in +ORCA the analysis always follows an instability it finds, since ORCA 6.0.0 aborts rather +than merely reporting one, and the sector of a restricted reference's instability is read +off the solution it relaxes into. + +It runs once per species, after that species' frequency job, and only for a transition +state or for a species whose frequency job actually ran with a restricted reference - a +restricted reference is the only one the analysis can inform, since a restricted solution +gives the same energy as an unrestricted one if and only if it is stable. It is further +limited to DFT and Hartree-Fock frequency levels, and needs the checkfile the frequency +job used, so that the SCF under test is the one the Hessian was built from. + +What it buys you: a verdict recorded in the log and in ``output.yml`` saying whether the +converged wavefunction is a genuine minimum in the space of orbital rotations, together +with the label and eigenvalue of any negative stability-matrix root, and whether the +analytic frequencies are invalidated by it. For a transition state the verdict can also +decide the restricted-versus-unrestricted reference of the jobs that follow. See +:ref:`Advanced Features ` for the full treatment, including which instabilities +invalidate analytic frequencies and what an adopted verdict does and does not correct. + +``specific_job_type`` cannot be used to request it. That key replaces ``job_types`` +wholesale with a dictionary in which only the named job type is ``true``, so +``specific_job_type: stability`` switches off the ``opt``, ``freq`` and ``sp`` jobs the +analysis is spawned from and nothing runs at all (``bde`` is special-cased to re-enable +them; ``stability`` is not). Any other value of ``specific_job_type`` likewise sets +``stability`` to ``false``. Request it through ``job_types``. ESS Settings ------------