def _get_angle_type(self, atom_types, warn=False): """Get a particular angle_type between `atom_types` from this ForceField""" if len(atom_types) != 3: raise ValueError( f"AngleType potential can only " f"be extracted for three atoms. Provided {len(atom_types)}") forward = FF_TOKENS_SEPARATOR.join(atom_types) reverse = FF_TOKENS_SEPARATOR.join(reversed(atom_types)) match = None if forward in self.angle_types: match = self.angle_types[forward] if reverse in self.angle_types: match = self.angle_types[reverse] msg = f"AngleType between atoms {atom_types[0]}, {atom_types[1]} " \ f"and {atom_types[2]} is missing from the ForceField" if match: return match elif warn: warnings.warn(msg) return None else: raise MissingPotentialError(msg)
def _get_improper_type(self, atom_types, warn=False): """Get a particular improper_type between `atom_types` from this ForceField.""" if len(atom_types) != 4: raise ValueError( f"ImproperType potential can only " f"be extracted for four atoms. Provided {len(atom_types)}" ) forward = FF_TOKENS_SEPARATOR.join(atom_types) reverse = FF_TOKENS_SEPARATOR.join( [atom_types[0], atom_types[2], atom_types[1], atom_types[3]] ) if forward is self.improper_types: return self.improper_types[forward] if reverse in self.improper_types: return self.improper_types[reverse] match = None for i in range(1, 5): forward_patterns = mask_with(atom_types, i) reverse_patterns = mask_with( [atom_types[0], atom_types[2], atom_types[1], atom_types[3]], i ) for forward_pattern, reverse_pattern in zip( forward_patterns, reverse_patterns ): forward_match_key = FF_TOKENS_SEPARATOR.join(forward_pattern) reverse_match_key = FF_TOKENS_SEPARATOR.join(reverse_pattern) if forward_match_key in self.dihedral_types: match = self.dihedral_types[forward_match_key] break if reverse_match_key in self.dihedral_types: match = self.dihedral_types[reverse_match_key] break if match: break msg = ( f"ImproperType between atoms {atom_types[0]}, {atom_types[1]}, " f"{atom_types[2]} and {atom_types[3]} is missing from the ForceField." ) if match: return match elif warn: warnings.warn(msg) return None else: raise MissingPotentialError(msg)
def parse_ff_connection_types(connectiontypes_el, child_tag='BondType'): """Given an XML etree Element rooted at BondTypes, parse the XML to create topology.core.AtomTypes,""" connectiontypes_dict = {} connectiontype_expression = connectiontypes_el.attrib.get('expression', None) param_unit_dict = _parse_param_units(connectiontypes_el) # Parse all the bondTypes and create a new BondType for connection_type in connectiontypes_el.getiterator(child_tag): ctor_kwargs = { 'name': child_tag, 'expression': '0.5 * k * (r-r_eq)**2', 'parameters': None, 'independent_variables': None, 'member_types': None } if connectiontype_expression: ctor_kwargs['expression'] = connectiontype_expression for kwarg in ctor_kwargs.keys(): ctor_kwargs[kwarg] = connection_type.attrib.get(kwarg, ctor_kwargs[kwarg]) ctor_kwargs['member_types'] = _get_member_types(connection_type) if not ctor_kwargs['parameters']: ctor_kwargs['parameters'] = _parse_params_values(connection_type, param_unit_dict, child_tag, ctor_kwargs['expression']) valued_param_vars = set(sympify(param) for param in ctor_kwargs['parameters'].keys()) ctor_kwargs['independent_variables'] = sympify(connectiontype_expression).free_symbols - valued_param_vars this_conn_type_key = FF_TOKENS_SEPARATOR.join(ctor_kwargs['member_types']) this_conn_type = TAG_TO_CLASS_MAP[child_tag](**ctor_kwargs) connectiontypes_dict[this_conn_type_key] = this_conn_type return connectiontypes_dict
def _get_bond_type(self, atom_types, warn=False): """Get a particular bond_type between `atom_types` from this ForceField""" if len(atom_types) != 2: raise ValueError( f"BondType potential can only " f"be extracted for two atoms. Provided {len(atom_types)}") forward = FF_TOKENS_SEPARATOR.join(atom_types) reverse = FF_TOKENS_SEPARATOR.join(reversed(atom_types)) if forward in self.bond_types: return self.bond_types[forward] if reverse in self.bond_types: return self.bond_types[reverse] msg = f"BondType between atoms {atom_types[0]} and {atom_types[1]} " \ f"is missing from the ForceField" if warn: warnings.warn(msg) return None else: raise MissingPotentialError(msg)
def parse_ff_connection_types(connectiontypes_el, child_tag="BondType"): """Parse an XML etree Element rooted at BondTypes to create topology.core.AtomTypes.""" connectiontypes_dict = {} connectiontype_expression = connectiontypes_el.attrib.get( "expression", None) param_unit_dict = _parse_param_units(connectiontypes_el) # Parse all the bondTypes and create a new BondType for connection_type in connectiontypes_el.getiterator(child_tag): ctor_kwargs = { "name": child_tag, "expression": "0.5 * k * (r-r_eq)**2", "parameters": None, "independent_variables": None, "member_types": None, } if connectiontype_expression: ctor_kwargs["expression"] = connectiontype_expression for kwarg in ctor_kwargs.keys(): ctor_kwargs[kwarg] = connection_type.attrib.get( kwarg, ctor_kwargs[kwarg]) ctor_kwargs["member_types"] = _get_member_types(connection_type) if not ctor_kwargs["parameters"]: ctor_kwargs["parameters"] = _parse_params_values( connection_type, param_unit_dict, child_tag, ctor_kwargs["expression"], ) valued_param_vars = set( sympify(param) for param in ctor_kwargs["parameters"].keys()) ctor_kwargs["independent_variables"] = ( sympify(connectiontype_expression).free_symbols - valued_param_vars) this_conn_type_key = FF_TOKENS_SEPARATOR.join( ctor_kwargs["member_types"]) this_conn_type = TAG_TO_CLASS_MAP[child_tag](**ctor_kwargs) connectiontypes_dict[this_conn_type_key] = this_conn_type return connectiontypes_dict