def test_get_number_of_atoms(): """Test determining the number of atoms in a coordinates dictionary""" assert common.get_number_of_atoms(None) is None assert common.get_number_of_atoms(ch4_coords) == 5 assert common.get_number_of_atoms(n3h5_xyz) == 8 ch4_coords_in_dict = {'coordinates': ch4_coords} assert common.get_number_of_atoms(ch4_coords_in_dict) == 5
def rotational_constants_validator(cls, value, values): """Species.rotational_constants validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' if value is None and common.get_number_of_atoms(values) > 1: raise ValueError(f'No rotational constants specified{label}.') if value is not None: if common.get_number_of_atoms(values) == 1: raise ValueError(f'Rotational constants were specified for a monoatomic species{label} ({value}).') if 'coordinates' in values and 'coords' in values['coordinates']: linear = is_linear(coordinates=np.array(values['coordinates']['coords'])) if len(value) != 1 and linear: raise ValueError(f'More than one rotational constant was specified for a linear species{label} ' f'({value}).') if len(value) != 3 and not linear: raise ValueError(f'The number of rotational constants for a non-linear species{label} must be 3.\n' f'Got {len(value)} rotational constants: {value}.') return value
def statmech_treatment_validator(cls, value, values): """Species.statmech_treatment validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' allowed_values = ['RRHO', 'RRHO-1D', 'RRHO-1D-ND', 'RRHO-ND', 'RRHO-AD', 'RRAO'] if value is None and common.get_number_of_atoms(values) > 2: raise ValueError(f'statmech_treatment was not given{label}. A statistical mechanics treatment ' f'(one of {allowed_values}) must be specified for polyatomic species.') if value is not None and value not in allowed_values: raise ValueError(f'The statmech_treatment {value} is not recognized.\n' f'Allowed values are: {allowed_values}') return value
def frequencies_validator(cls, value, values): """Species.frequencies validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' if value is None and common.get_number_of_atoms(values) > 1: raise ValueError(f'Frequencies were not given{label}. Frequencies must be specified for polyatomic species.') if value is not None: if any(i == 0 for i in value): raise ValueError(f'A frequency cannot be zero, got {value}{label}.') if values['coordinates'] is not None and value is not None: linear = is_linear(coordinates=np.array(values['coordinates']['coords'])) num_atoms = common.get_number_of_atoms(values) if num_atoms is not None: expected_num_freqs = 3 * num_atoms - (6 - int(linear)) # 3N-6 for non linear, 3N-5 for linear if len(value) != expected_num_freqs: linear_txt = 'linear' if linear else 'non-linear' raise ValueError(f'Expected {expected_num_freqs} frequencies for a {linear_txt} molecule, ' f'got {len(value)} frequencies{label}.') if 'is_ts' in values and values['is_ts'] and all(freq > 0 for freq in value): raise ValueError(f'An imaginary frequency must be present for a TS species. ' f'Got all real frequencies{label}.') return value
def hessian_validator(cls, value, values): """Species.hessian validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' num_atoms = common.get_number_of_atoms(values) if num_atoms > 1: if value is None: raise ValueError(f'The Hessian was not given{label}. It must be given for polyatomic species.') if len(value) != num_atoms * 3: raise ValueError(f'The number of rows in the Hessian matrix ({len(value)}){label} is invalid, ' f'expected {num_atoms * 3} rows for {num_atoms} atoms.') for i, row in enumerate(value): if len(row) < i + 1: raise ValueError(f'Row {i} of the Hesian matrix{label} has only {len(row)} elements, ' f'expected {i + 1} elements.') return value
def scaled_projected_frequencies_validator(cls, value, values): """Species.scaled_projected_frequencies validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' if value is None and common.get_number_of_atoms(values) > 1: raise ValueError(f'Scaled projected frequencies were not given{label}.' f'Must be specified for polyatomic species.') if value is not None: if any(i == 0 for i in value): raise ValueError(f'A frequency (scaled_projected_frequencies) cannot be zero, got {value}{label}.') if 'frequencies' in values: if len(value) > len(values['frequencies']): raise ValueError(f"The scaled_projected_frequencies (length {len(value)}) cannot have more " f"entries that the frequencies (length {len(values['frequencies'])}{label}.") if value == values['frequencies']: raise ValueError(f'The scaled_projected_frequencies are identical to the frequencies.\n' f'Did you forget to scale?') return value
def normal_displacement_modes_validator(cls, value, values): """Species.normal_displacement_modes validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' if 'frequencies' in values and values['frequencies'] is not None: if value is None: raise ValueError(f'Normal displacement modes were not given{label}.') if len(value) != len(values['frequencies']): raise ValueError(f"The number of normal displacement modes ({len(value)}) " f"differs from the number of frequencies ({len(values['frequencies'])}){label}.") num_atoms = common.get_number_of_atoms(values) if num_atoms is not None: for ndm in value: if len(ndm) != num_atoms: raise ValueError(f'The number of normal displacement modes per frequency must be equal ' f'to the number of atoms ({num_atoms}), got {len(ndm)}.') for displacement in ndm: if len(displacement) != 3: raise ValueError(f'Each displacement (per frequency per atom) must be a list of length 3, ' f'got {len(displacement)}.') return value
def freq_path_validator(cls, value, values): """Species.freq_path validator""" label = f' for species "{values["label"]}"' if 'label' in values and values['label'] is not None else '' if common.get_number_of_atoms(values) > 1 and value is None: raise ValueError(f'The freq_path was not given{label}.') return value