ReactionMechanismGenerator / ReactionMechanismGenerator/ARC

Reaction multiplicity silently resolves to 1 when species are attached after first access

Open
#1,048 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
51
Forks
25
Avg merge
4d 5h
Merged PRs (30d)
15

Description

Describe the bug

ARCReaction.multiplicity returns 1 for any reaction whose species are attached after the property is first read, and the wrong value is then cached for the life of the object. Attaching the species afterwards does not correct it.

The derivation itself is fine. get_rxn_multiplicity() opens with

reactants, products = self.get_reactants_and_products()
multiplicity = None
ordered_r_mult_list, ordered_p_mult_list = list(), list()
if len(reactants):
    if len(reactants) == 1:
        return reactants[0].multiplicity

so a unimolecular reaction returns its reactant's multiplicity, which is right. But when reactants is empty the guarded block is skipped and both ordered lists stay empty, and the first test in the loop below is

if all(m == 1 for m in list_1) and multiplicity is None:
    multiplicity = 1  # S + S = S or T

all() over an empty list is vacuously true, so the function returns 1 rather than None. Because the caller caches into self._multiplicity and only recomputes when it is None, a doublet reaction is permanently a singlet.

How to reproduce

r = ARCSpecies(label='R', smiles='[CH2]C(C)CC')   # multiplicity 2
p = ARCSpecies(label='P', smiles='CC(C)[CH]C')    # multiplicity 2

# species present when the property is first read -> correct
rxn1 = ARCReaction(r_species=[r], p_species=[p])
rxn1.multiplicity          # 2

# species attached later -> wrong, and it sticks
rxn2 = ARCReaction(label='R <=> P', reactants=['R'], products=['P'])
rxn2.multiplicity          # 1
rxn2.r_species = [r]; rxn2.p_species = [p]
rxn2.multiplicity          # still 1

The second form is what an input file produces when a reaction names its species by label:

species:
  - {label: R, smiles: '[CH2]C(C)CC'}
  - {label: P, smiles: 'CC(C)[CH]C'}
reactions:
  - label: R <=> P
    reactants: [R]
    products: [P]

What it costs

The species themselves are perceived correctly — the log shows multiplicity=2 for both — while the reaction is set to 1, so the TS inherits 1 and Gaussian is handed an impossible specification:

Setting multiplicity of reaction R <=> P to 1
...
 The combination of multiplicity 1 and    41 electrons is impossible.
 Error termination via Lnk1e in .../l301.exe

ARC does notice, but too late and in the wrong place. The Linear TS adapter raises

Impossible multiplicity for species TS0: the species has 41 electrons, which requires an even
multiplicity, but a multiplicity of 1 was requested. The nearest valid multiplicities are [2].

and that exception is caught, so the run continues, submits the impossible job, exhausts its troubleshooting on it (int=(Acc2E=14), all_attempted) and reports the TS as unconverged. I lost ten transition-state searches this way before opening a Gaussian log; nothing upstream of that log says "multiplicity".

Expected behavior

  1. get_rxn_multiplicity() should return None when it has no species to reason about, so the property recomputes later instead of caching a guess. Guarding the empty case explicitly would do it — the vacuous all([]) is the only reason 1 is reached.
  2. The parity check that already exists (check_multiplicity_parity) is the right test; it should be applied to the reaction when its multiplicity is set, not only when an adapter happens to build a species. An electron count and a multiplicity of opposite parity is knowable before any job is written.

Installation information

  • ARC main @ 4d67ad4c
  • Python 3.14, Linux, PBS, Gaussian 16

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at ARCReaction.multiplicity and get_rxn_multiplicity(), using the reproduction in the issue to observe caching before and after species attachment. Then inspect check_multiplicity_parity and the Linear TS adapter path. Done means an empty species set does not cache 1, later attachment recomputes the reaction multiplicity, and parity is checked when the reaction multiplicity is set.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.