validate_and_fill_chgmult
- qcelemental.molparse.validate_and_fill_chgmult(zeff, fragment_separators, molecular_charge, fragment_charges, molecular_multiplicity, fragment_multiplicities, zero_ghost_fragments=False, verbose=1)[source]
Forms molecular and fragment charge and multiplicity specification by completing and reconciling information from argument, supplemented by physical constraints and sensible defaults.
- Parameters:
zeff (
ndarray
) – (nat,) electron counts (float) for neutral atoms, generally Z nuclear charge. 0 indicates ghosts such that a full fragment of 0s will be constained to 0 1 charge & multiplicity.fragment_separators (
ndarray
) – (nfr - 1, ) indices splitting zeff into nfr fragments.molecular_charge (
Optional
[float
]) – Total charge for molecular system.fragment_charges (
Optional
[List
[float
]]) – (nfr,) known fragment charges with None as placeholder for unknown. Expected pre-defaulted so even if nothing known, if fragment_separators breaks zeff into nfr=2 fragments, input value should befragment_charges=[None, None]
.molecular_multiplicity (
Optional
[int
]) – Total multiplicity for molecular system.fragment_multiplicities (
Optional
[List
[int
]]) – (nfr,) known fragment charges with None as placeholder for unknown. Expected pre-defaulted so even if nothing known, if fragment_separators breaks zeff into nfr=2 fragments, input value should befragment_multiplicities=[None, None]
.zero_ghost_fragments (
bool
) – Fragments composed entirely of ghost atoms (Zeff=0) are required to have chgmult 0 1. When False, violations of this will cause a ValidationError. When True, treat ghost fragments indicated by zeff to contain superior information over chgmult arguments that might still correspond to full-real molecule. Clears information from molecular_charge and molecular_multiplicity and sets ghost fragments to 0 1, leaving other positions free to readjust. Unused (prefer to set up such manipulations outside function call) but works.verbose (
int
) – Amount of printing.
- Return type:
- Returns:
molecular_charge (float) – Total charge for molecular system.
fragment_charges (list of float) – (nfr,) Charge on each fragment.
molecular_multiplicity (int) – Total multiplicity for molecular system.
fragment_multiplicities (list of int) – (nfr,) Multiplicity for each fragment.
- Raises:
qcelemental.ValidationError – When no solution to input arguments subject to the constraints below can be found.
Notes
Returns combination of total & fragment charge & multiplicity among values of S1-7 that fulfill rules R1-9. A few derived implications in I1-3.
Constraints
R1 require all chg & mult exist
R2 require total charge to be the sum of frag chg
R3 require mult is positive int
R4 require sufficient tot electrons for mult: mult - 1 <= neut_el - chg
R5 require total parity consistent among tot electrons and mult: (mult % 2) != ((neut_el - chg) % 2)
R6 require chg match input argument values
R7 require mult match input argument values
R8 require that tot = sum(frag) mult follow high spin addition unless tot & frag mult fully specified
R9 require that ghost fragments (zeff all 0) be neutral singlet
Allowed values
S1 suggest input argument values for tot chg, frag chg, tot mult or frag mult
S2 suggest sum frag chg for tot chg, allowing for indiv frag chg defaulting to 0
S3 suggest distributing unallocated chg onto frag chg
S4 suggest 0 default for frag chg
S5 suggest range of high-spin sum frag mult for tot mult, allowing for indiv frag mult defaulting to 1 or 2
S6 suggest range of unallocated mult = tot - high_spin_sum(frag - 1), allowing for all indiv but self defaulting to 1 or 2.
S7 suggest 1 or 2 default for frag mult
Implications
I1 won’t form an ion just to be closed shell (would require choosing +1 vs. -1)
I2 unallocated chg or mult lands on the first unspecified fragment able to bear it (enforced by returning first match encountered; subsequent matches distribute charge to later frags)
I3 missing chg or mult from tot - frags will always be allocated as a block, not distributed
Examples
>>> validate_and_fill_chgmult(*sys('He'), 0, [0], 1, [1]) 0, [0], 1, [1] >>> validate_and_fill_chgmult(*sys('He'), None, [None], None, [None]) 0, [0], 1, [1] >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], None, [None, None]) 0, [0, 0], 1, [1, 1]) >>> validate_and_fill_chgmult(*sys('He/He'), 2, [None, None], None, [None, None]) 2, [2, 0], 1, [1, 1]) >>> validate_and_fill_chgmult(*sys('He/He'), None, [2, None], None, [None, None]) 2, [2, 0], 1, [1, 1]) >>> validate_and_fill_chgmult(*sys('He/He'), 0, [2, None], None, [None, None]) 0, [2, -2], 1, [1, 1]) >>> validate_and_fill_chgmult(*sys('Ne/He/He'), -2, [None, 2, None], None, [None, None, None]) -2, [-4, 2, 0], 1, [1, 1, 1] >>> validate_and_fill_chgmult(*sys('Ne/He/He'), 2, [None, -2, None], None, [None, None, None]) 2, [4, -2, 0], 1, [1, 1, 1] # 9 - residual +4 distributes to first fragment able to wholly accept it (He+4 is no-go) >>> validate_and_fill_chgmult(*sys('He/He/Ne'), 2, [None, -2, None], None, [None, None, None]) 2, [0, -2, 4], 1, [1, 1, 1] # 10 - residual +4 unsuited for only open fragment, He, so irreconcilable >>> validate_and_fill_chgmult(*sys('He/He/Ne'), 2, [None, -2, 0], None, [None, None, None]) ValidationError # 11 - non-positive multiplicity >>> validate_and_fill_chgmult(*sys('He/He/Ne'), 2, [2, -2, None], None, [None, None, None]) 2, [2, -2, 2], 1, [1, 1, 1]) >>> validate_and_fill_chgmult(*sys('He/He'), None, [-2, 2], None, [None, None]) 0, [-2, 2], 1, [1, 1] >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, -2], None, [None, None]) -2, [0, -2], 1, [1, 1] >>> validate_and_fill_chgmult(*sys('Ne/Ne'), 0, [None, 4], None, [None, None]) 0, [-4, 4], 1, [1, 1] >>> validate_and_fill_chgmult(*sys('He/He/He'), 4, [2, None, None], None, [None, None, None]) 4, [2, 2, 0], 1, [1, 1, 1] >>> validate_and_fill_chgmult(*sys('He/He'), 0, [-2, 2], None, [None, None]) 0, [-2, 2], 1, [1, 1] >>> validate_and_fill_chgmult(*sys('He/He'), 0, [-2, -2], None, [None, None]) ValidationError >>> validate_and_fill_chgmult(*sys('He'), None, [None], 0, [None]) ValidationError >>> validate_and_fill_chgmult(*sys('He'), None, [None], None, [1]) 0, [0], 1, [1] # 20 - doublet non consistent with closed-shell, neutral default charge >>> validate_and_fill_chgmult(*sys('He'), None, [None], None, [2]) ValidationError >>> validate_and_fill_chgmult(*sys('He'), None, [None], None, [3]) 0, [0], 3, [3] # 22 - insufficient electrons for pentuplet >>> validate_and_fill_chgmult(*sys('He'), None, [None], None, [5]) ValidationError >>> validate_and_fill_chgmult(*sys('He'), None, [-1], None, [2]) -1, [-1], 2, [2] # 24 - doublet not consistent with even charge >>> validate_and_fill_chgmult(*sys('He'), None, [-2], None, [2]) ValidationError >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], None, [1, 1]) 0, [0, 0], 1, [1, 1] >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], None, [3, 1]) 0, [0, 0], 3, [3, 1] >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], None, [1, 3]) 0, [0, 0], 3, [1, 3] >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], None, [3, 3]) 0, [0, 0], 5, [3, 3] >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], 3, [3, 3]) 0, [0, 0], 3, [3, 3] # 30 - bad parity btwn mult and total # electrons >>> validate_and_fill_chgmult(*sys('He/He'), None, [None, None], 2, [3, 3]) ValidationError >>> validate_and_fill_chgmult(*sys('H'), None, [None], None, [None]) 0, [0], 2, [2] >>> validate_and_fill_chgmult(*sys('H'), 1, [None], None, [None]) 1, [1], 1, [1] >>> validate_and_fill_chgmult(*sys('H'), None, [-1], None, [None]) -1, [-1], 1, [1] >>> validate_and_fill_chgmult(*sys('funnyH'), None, [None], None, [None]) 0, [0], 1, [1] # 35 - insufficient electrons >>> validate_and_fill_chgmult(*sys('funnierH'), None, [None], None, [None]) ValidationError >>> validate_and_fill_chgmult(*sys('H/H'), None, [None, None], None, [None, None]) 0, [0, 0], 3, [2, 2] >>> validate_and_fill_chgmult(*sys('H/He'), None, [None, None], None, [None, None]) 0, [0, 0], 2, [2, 1] >>> validate_and_fill_chgmult(*sys('H/He'), None, [1, 1], None, [None, None]) 2, [1, 1], 2, [1, 2] >>> validate_and_fill_chgmult(*sys('H/He'), -2, [-1, None], None, [None, None]) -2, [-1, -1], 2, [1, 2] >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), None, [1, None, 1, None], None, [None, None, None, None]) 2, [1, 0, 1, 0], 1, [1, 1, 1, 1] >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), None, [-1, None, 1, None], None, [None, None, None, None]) 0, [-1, 0, 1, 0], 1, [1, 1, 1, 1] >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), 2, [None, None, 1, None], None, [None, None, None, None]) 2, [1, 0, 1, 0], 1, [1, 1, 1, 1] >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), 3, [None, None, 1, None], None, [None, None, None, None]) 3, [0, 2, 1, 0], 2, [2, 1, 1, 1] >>> validate_and_fill_chgmult(*sys('H/He'), None, [1, None], None, [2, None]) ValidationError >>> validate_and_fill_chgmult(*sys('H/He'), None, [None, 0], None, [None, 2]) ValidationError >>> validate_and_fill_chgmult(*sys('H/He'), None, [None, -1], None, [None, 3]) ValidationError >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), None, [None, 1, 0, 1], None, [None, None, None, None]) 2, [0, 1, 0, 1], 5, [2, 2, 2, 2] >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), None, [None, 1, 0, None], None, [None, None, None, None]) 1, [0, 1, 0, 0], 4, [2, 2, 2, 1] >>> validate_and_fill_chgmult(*sys('H/He/Na/Ne'), None, [None, 1, 0, None], None, [None, None, 4, None]) 1, [0, 1, 0, 0], 6, [2, 2, 4, 1] >>> validate_and_fill_chgmult(*sys('He/He/He'), 0, [None, None, 1], None, [1, None, 2]) 0, [0, -1, 1], 3, [1, 2, 2] >>> validate_and_fill_chgmult(*sys('N/N/N'), None, [1, 1, 1], 3, [None, 3, None]) 3, [1, 1, 1], 3, [1, 3, 1] >>> validate_and_fill_chgmult(*sys('N/N/N'), None, [1, 1, 1], 3, [None, None, None]) 3, [1, 1, 1], 3, [3, 1, 1] >>> validate_and_fill_chgmult(*sys('N/N/N'), None, [None, None, None], 3, [None, None, 2]) ValidationError >>> validate_and_fill_chgmult(*sys('N/N/N'), 1, [None, -1, None], 3, [None, None, 2]) 1, [2, -1, 0], 3, [2, 1, 2] # 55 - both (1, (1, 0.0, 0.0), 4, (1, 3, 2)) and (1, (0.0, 0.0, 1), 4, (2, 3, 1)) plausible >>> validate_and_fill_chgmult(*sys('N/Ne/N'), 1, [None, None, None], 4, [None, 3, None]) 1, [1, 0, 0], 4, [1, 3, 2] >>> validate_and_fill_chgmult(*sys('N/Ne/N'), None, [None, None, 1], 4, [None, 3, None]) 1, [0, 0, 1], 4, [2, 3, 1] >>> validate_and_fill_chgmult(*sys('He/He'), None, [-1, 1], None, [None, None]) 0, [-1, 1], 3, [2, 2] >>> validate_and_fill_chgmult(*sys('Gh'), 1, [None], None, [None]) ValidationError >>> validate_and_fill_chgmult(*sys('Gh'), -1, [None], None, [None]) ValidationError >>> validate_and_fill_chgmult(*sys('Gh'), None, [None], 3, [None]) ValidationError >>> validate_and_fill_chgmult(*sys('He/Gh'), None, [2, None], None, [None, None]) 2, [2, 0], 1, [1, 1] >>> validate_and_fill_chgmult(*sys('Gh/He'), None, [2, None], None, [None, None]) ValidationError >>> validate_and_fill_chgmult(*sys('Gh/He/Ne'), 2, [None, -2, None], None, [None, None, None]) 2, [0, -2, 4], 1, [1, 1, 1] >>> validate_and_fill_chgmult(*sys('Gh/He/Gh'), 1, [None, None, None], None, [None, None, None]) 1, [0, 1, 0], 2, [1, 2, 1] >>> sys = { 'He': (np.array([2]), np.array([])), 'He/He': (np.array([2, 2]), np.array([1])), 'Ne/He/He': (np.array([10, 2, 2]), np.array([1, 2])), 'He/He/Ne': (np.array([2, 2, 10]), np.array([1, 2])), 'Ne/Ne': (np.array([10, 10]), np.array([1])), 'He/He/He': (np.array([2, 2, 2]), np.array([1, 2])), 'H': (np.array([1]), np.array([])), 'funnyH': (np.array([0]), np.array([])), # has no electrons 'funnierH': (np.array([-1]), np.array([])), # has positron 'H/H': (np.array([1, 1]), np.array([1])), 'H/He': (np.array([1, 2]), np.array([1])), 'H/He/Na/Ne': (np.array([1, 2, 11, 10]), np.array([1, 2, 3])), 'N/N/N': (np.array([7, 7, 7]), np.array([1, 2])), 'N/Ne/N': (np.array([7, 10, 7]), np.array([1, 2])), 'He/Gh': (np.array([2, 0]), np.array([1])), 'Gh/He': (np.array([0, 2]), np.array([1])), 'Gh': (np.array([0, 0]), np.array([])), 'Gh/He/Ne': (np.array([0, 0, 2, 10]), np.array([2, 3])), 'Gh/He/Gh': (np.array([0, 2, 0]), np.array([1, 2]))}