diff --git a/docs/source/_autosummary/pywindow.DLPOLY.rst b/docs/source/_autosummary/pywindow.DLPOLY.rst new file mode 100644 index 0000000..5f0b8a8 --- /dev/null +++ b/docs/source/_autosummary/pywindow.DLPOLY.rst @@ -0,0 +1,25 @@ +pywindow.DLPOLY +=============== + +.. currentmodule:: pywindow + +.. autoclass:: DLPOLY + :members: + :inherited-members: + :undoc-members: + :show-inheritance: + + + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + + + + + + \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.Input.rst b/docs/source/_autosummary/pywindow.Input.rst new file mode 100644 index 0000000..5887993 --- /dev/null +++ b/docs/source/_autosummary/pywindow.Input.rst @@ -0,0 +1,27 @@ +pywindow.Input +============== + +.. currentmodule:: pywindow + +.. autoclass:: Input + :members: + :inherited-members: + :undoc-members: + :show-inheritance: + + + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + ~Input.load_file + ~Input.load_rdkit_mol + + + + + + \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.MolecularSystem.rst b/docs/source/_autosummary/pywindow.MolecularSystem.rst new file mode 100644 index 0000000..fee66d6 --- /dev/null +++ b/docs/source/_autosummary/pywindow.MolecularSystem.rst @@ -0,0 +1,35 @@ +pywindow.MolecularSystem +======================== + +.. currentmodule:: pywindow + +.. autoclass:: MolecularSystem + :members: + :inherited-members: + :undoc-members: + :show-inheritance: + + + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + ~MolecularSystem.decipher_atom_keys + ~MolecularSystem.dump_system + ~MolecularSystem.dump_system_json + ~MolecularSystem.load_file + ~MolecularSystem.load_rdkit_mol + ~MolecularSystem.load_system + ~MolecularSystem.make_modular + ~MolecularSystem.rebuild_system + ~MolecularSystem.swap_atom_keys + ~MolecularSystem.system_to_molecule + + + + + + \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.Molecule.rst b/docs/source/_autosummary/pywindow.Molecule.rst new file mode 100644 index 0000000..405bc0a --- /dev/null +++ b/docs/source/_autosummary/pywindow.Molecule.rst @@ -0,0 +1,39 @@ +pywindow.Molecule +================= + +.. currentmodule:: pywindow + +.. autoclass:: Molecule + :members: + :inherited-members: + :undoc-members: + :show-inheritance: + + + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + ~Molecule.calculate_average_diameter + ~Molecule.calculate_centre_of_mass + ~Molecule.calculate_maximum_diameter + ~Molecule.calculate_pore_diameter + ~Molecule.calculate_pore_diameter_opt + ~Molecule.calculate_pore_volume + ~Molecule.calculate_pore_volume_opt + ~Molecule.calculate_windows + ~Molecule.dump_molecule + ~Molecule.dump_properties_json + ~Molecule.full_analysis + ~Molecule.load_rdkit_mol + ~Molecule.molecular_weight + ~Molecule.shift_to_origin + + + + + + \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.PDB.rst b/docs/source/_autosummary/pywindow.PDB.rst new file mode 100644 index 0000000..9bf02ac --- /dev/null +++ b/docs/source/_autosummary/pywindow.PDB.rst @@ -0,0 +1,25 @@ +pywindow.PDB +============ + +.. currentmodule:: pywindow + +.. autoclass:: PDB + :members: + :inherited-members: + :undoc-members: + :show-inheritance: + + + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + + + + + + \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.XYZ.rst b/docs/source/_autosummary/pywindow.XYZ.rst new file mode 100644 index 0000000..8066eb0 --- /dev/null +++ b/docs/source/_autosummary/pywindow.XYZ.rst @@ -0,0 +1,25 @@ +pywindow.XYZ +============ + +.. currentmodule:: pywindow + +.. autoclass:: XYZ + :members: + :inherited-members: + :undoc-members: + :show-inheritance: + + + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + + + + + + \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.compare_properties_dict.rst b/docs/source/_autosummary/pywindow.compare_properties_dict.rst new file mode 100644 index 0000000..8775647 --- /dev/null +++ b/docs/source/_autosummary/pywindow.compare_properties_dict.rst @@ -0,0 +1,6 @@ +pywindow.compare\_properties\_dict +================================== + +.. currentmodule:: pywindow + +.. autofunction:: compare_properties_dict \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.make_supercell.rst b/docs/source/_autosummary/pywindow.make_supercell.rst new file mode 100644 index 0000000..1135625 --- /dev/null +++ b/docs/source/_autosummary/pywindow.make_supercell.rst @@ -0,0 +1,6 @@ +pywindow.make\_supercell +======================== + +.. currentmodule:: pywindow + +.. autofunction:: make_supercell \ No newline at end of file diff --git a/docs/source/_autosummary/pywindow.rst b/docs/source/_autosummary/pywindow.rst new file mode 100644 index 0000000..d3fcb7c --- /dev/null +++ b/docs/source/_autosummary/pywindow.rst @@ -0,0 +1,47 @@ +pywindow +======== + +.. automodule:: pywindow + + + + + + + + .. rubric:: Classes + + .. autosummary:: + :toctree: + :template: class.rst + :nosignatures: + + DLPOLY + Input + MolecularSystem + Molecule + PDB + XYZ + + + + + + + .. rubric:: Functions + + .. autosummary:: + :toctree: + :nosignatures: + + compare_properties_dict + make_supercell + + + + + + + + + diff --git a/docs/source/_static/PUDXES_out.json b/docs/source/_static/PUDXES_out.json index 4b699cd..6fbf9c4 100644 --- a/docs/source/_static/PUDXES_out.json +++ b/docs/source/_static/PUDXES_out.json @@ -1 +1 @@ -{"no_of_atoms": 168, "pore_volume_opt": 82.31154385154417, "maximum_diameter": {"atom_2": 54, "diameter": 22.179369990077188, "atom_1": 12}, "pore_diameter": {"atom": 29, "diameter": 5.397020177310022}, "windows": {"diameters": [3.6377874601388167, 3.6356210328430296, 3.628965122399882, 3.637072370444723], "centre_of_mass": [[10.77105704516109, 10.770977067030907, 14.028939562935404], [14.015448457684588, 14.015412600374392, 14.015398449539077], [13.929655242102346, 10.87029766244962, 10.870341633949108], [10.775422358465416, 14.024532168906696, 10.775466335429106]]}, "pore_volume": 82.31154385154417, "pore_diameter_opt": {"diameter": 5.397020177310022, "centre_of_mass": [12.400000000000011, 12.399999999999991, 12.399999999999991], "atom_1": 29}, "centre_of_mass": [12.400000000000011, 12.399999999999991, 12.399999999999991]} \ No newline at end of file +{"no_of_atoms": 168, "centre_of_mass": [12.400000000000011, 12.399999999999991, 12.399999999999991], "maximum_diameter": {"diameter": 22.179369990077188, "atom_1": 12, "atom_2": 54}, "average_diameter": 13.83201751425547, "pore_diameter": {"diameter": 5.397020177310022, "atom": 29}, "pore_volume": 82.31154385154417, "pore_diameter_opt": {"diameter": 5.397020177310022, "atom_1": 29, "centre_of_mass": [12.400000000000011, 12.399999999999991, 12.399999999999991]}, "pore_volume_opt": 82.31154385154417, "windows": {"diameters": [3.637787460138805, 3.6356210328430296, 3.628965122470937, 3.6370723704447188], "centre_of_mass": [[10.771057045161115, 10.77097706703093, 14.028939562935376], [14.015448457686624, 14.015412600376724, 14.015398449541088], [13.92965526405877, 10.870297640397817, 10.87034161195557], [10.775422358465452, 14.024532168906662, 10.775466335429137]]}} \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 105f8ce..c25b758 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,4 +48,4 @@ html_theme = "furo" html_static_path = ["_static"] html_logo = "_static/pyWINDOW_logo.png" -html_theme_options = {} +html_theme_options = {} # type: ignore[var-annotated] diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 0000000..5906b05 --- /dev/null +++ b/examples/__init__.py @@ -0,0 +1 @@ +"""Examples for pywindow.""" diff --git a/justfile b/justfile index 4604f15..affebb5 100644 --- a/justfile +++ b/justfile @@ -26,7 +26,7 @@ check: ( set -x; uv run ruff format --check . ) echo - ( set -x; uv run mypy src/ tests/ examples/ ) + ( set -x; uv run mypy src/ tests/ examples/ docs/source/ ) echo ( set -x; uv run pytest --cov=src --cov-report term-missing ) diff --git a/src/pywindow/_internal/io_tools.py b/src/pywindow/_internal/io_tools.py index 1bda98f..e5df190 100644 --- a/src/pywindow/_internal/io_tools.py +++ b/src/pywindow/_internal/io_tools.py @@ -3,7 +3,8 @@ from __future__ import annotations import json -import os +import pathlib +from typing import TYPE_CHECKING, Callable import numpy as np @@ -12,85 +13,82 @@ unit_cell_to_lattice_array, ) +if TYPE_CHECKING: + from collections import abc -class _CorruptedPDBFile(Exception): - def __init__(self, message): - self.message = message + import rdkit -class _CorruptedXYZFile(Exception): - def __init__(self, message): +class _CorruptedPDBFileError(Exception): + def __init__(self, message: str) -> None: self.message = message -class _FileAlreadyExists(Exception): - def __init__(self, message): +class _CorruptedXYZFileError(Exception): + def __init__(self, message: str) -> None: self.message = message -class _NotADictionary(Exception): - def __init__(self, message): +class _NotADictionaryError(Exception): + def __init__(self, message: str) -> None: self.message = message class _FileTypeError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message class Input: """Class used to load and process input files.""" - def __init__(self): + def __init__(self) -> None: self._load_funcs = { ".xyz": self._read_xyz, ".pdb": self._read_pdb, ".mol": self._read_mol, } - def load_file(self, filepath): - """This function opens any type of a readable file and decompose - the file object into a list, for each line, of lists containing - splitted line strings using space as a spacer. + def load_file(self, filepath: pathlib.Path | str) -> dict: # type:ignore[type-arg] + """This function opens any type of a readable file. + + It decomposes the file object into a list, for each line, of lists + containing splitted line strings using space as a spacer. - Parameters - ---------- - filepath : :class:`str` - The full path or a relative path to any type of file. + Parameters: + filepath: + The full path or a relative path to any type of file. Returns: - ------- - :class:`dict` - Returns a dictionary containing the molecular information - extracted from the input files. This information will - vary with file type and information stored in it. - The data is sorted into lists that contain one feature - for example key atom_id: [atom_id_1, atom_id_2] - Over the process of analysis this dictionary will be updated - with new data. + :class:`dict` + Returns a dictionary containing the molecular information + extracted from the input files. This information will + vary with file type and information stored in it. + The data is sorted into lists that contain one feature + for example key atom_id: [atom_id_1, atom_id_2] + Over the process of analysis this dictionary will be updated + with new data. """ - self.file_path = filepath - _, self.file_type = os.path.splitext(filepath) - _, self.file_name = os.path.split(filepath) - with open(filepath) as ffile: + self.file_path = pathlib.Path(filepath) + self.file_type = self.file_path.suffix + self.file_name = self.file_path.name + with self.file_path.open("r") as ffile: self.file_content = ffile.readlines() return self._load_funcs[self.file_type]() - def load_rdkit_mol(self, mol): - """Return molecular data from :class:`rdkit.Chem.rdchem.Mol` object. + def load_rdkit_mol(self, mol: rdkit.Chem.Mol) -> dict: # type:ignore[type-arg] + """Return molecular data from :class:`rdkit.Chem.Mol` object. - Parameters - ---------- - mol : :class:`rdkit.Chem.rdchem.Mol` - A molecule object from RDKit. + Parameters: + mol: + A molecule object from RDKit. Returns: - ------- - :class:`dict` - A dictionary with ``elements`` and ``coordinates`` as keys - containing molecular data extracted from - :class:`rdkit.Chem.rdchem.Mol` object. + :class:`dict` + A dictionary with ``elements`` and ``coordinates`` as keys + containing molecular data extracted from + :class:`rdkit.Chem.Mol` object. """ self.system = { @@ -105,10 +103,9 @@ def load_rdkit_mol(self, mol): self.system["coordinates"][atom_id] = x, y, z return self.system - def _read_xyz(self): - """""" + def _read_xyz(self) -> dict: # type:ignore[type-arg] try: - self.system = dict() + self.system = {} self.file_remarks = self.file_content[1] self.system["elements"] = np.array( [i.split()[0] for i in self.file_content[2:]] @@ -119,24 +116,26 @@ def _read_xyz(self): for j in [i.split()[1:] for i in self.file_content[2:]] ] ) - return self.system + except IndexError: - raise _CorruptedXYZFile( + msg = ( "The XYZ file is corrupted in some way. For example, an empty " "line at the end etc. or it is a trajectory. If the latter is " "the case, please use `trajectory` module, otherwise fix it." ) + raise _CorruptedXYZFileError(msg) from None + return self.system - def _read_pdb(self): - """""" + def _read_pdb(self) -> dict: # type:ignore[type-arg] if sum([i.count("END ") for i in self.file_content]) > 1: - raise _CorruptedPDBFile( + msg = ( "Multiple 'END' statements were found in this PDB file." "If this is a trajectory, use a trajectory module, " "Otherwise, fix it." ) - self.system = dict() - self.system["remarks"] = [ + raise _CorruptedPDBFileError(msg) + self.system = {} + self.system["remarks"] = [ # type:ignore[assignment] i for i in self.file_content if i[:6] == "REMARK" ] self.system["unit_cell"] = np.array( @@ -183,17 +182,17 @@ def _read_pdb(self): ) return self.system - def _read_mol(self): - """-V3000""" - self.system = dict() + def _read_mol(self) -> dict: # type:ignore[type-arg] + """Read V3000 mol file.""" + self.system = {} if self.file_content[2] != "\n": - self.system["remarks"] = self.file_content[2] + self.system["remarks"] = self.file_content[2] # type:ignore[assignment] file_body = [i.split() for i in self.file_content] elements = [] coordinates = [] atom_data = False for line in file_body: - if len(line) > 2: + if len(line) > 2: # noqa: PLR2004 if line[2] == "END" and line[3] == "ATOM": atom_data = False if atom_data is True: @@ -209,170 +208,236 @@ def _read_mol(self): class Output: """Class used to process and save output files.""" - def __init__(self): - self.cwd = os.getcwd() - self._save_funcs = { - "xyz": self._save_xyz, - "pdb": self._save_pdb, - } - - def dump2json(self, obj, filepath, override=False, **kwargs): + def __init__(self) -> None: + self.cwd = pathlib.Path.cwd() + self._save_funcs = {".xyz": self._save_xyz, ".pdb": self._save_pdb} + + def dump2json( + self, + obj: dict, # type: ignore[type-arg] + filepath: str | pathlib.Path, + default: Callable, # type:ignore[type-arg] + override: bool = False, # noqa: FBT001, FBT002 + ) -> None: """Dump a dictionary into a JSON dictionary. Uses the json.dump() function. - Parameters - ---------- - obj : :class:`dict` - A dictionary to be dumpped as JSON file. + Parameters: + obj: + A dictionary to be dumpped as JSON file. + + filepath: + The filepath for the dumped file. - filepath : :class:`str` - The filepath for the dumped file. + default: + A callable function that will be used to convert + non-serializable objects to serializable ones. - override : :class:`bool` - If True, any file in the filepath will be override. (default=False) + override: + If True, any file in the filepath will be override. + (default=False) """ + filepath = pathlib.Path(filepath) + # We make sure that the object passed by the user is a dictionary. - if isinstance(obj, dict): - pass - else: - raise _NotADictionary( - "This function only accepts dictionaries as input" - ) + if not isinstance(obj, dict): + msg = "This function only accepts dictionaries as input" # type:ignore[unreachable] + raise _NotADictionaryError(msg) + # We check if the filepath has a json extenstion, if not we add it. - if str(filepath[-4:]) == "json": - pass - else: - filepath = ".".join((str(filepath), "json")) + if ".json" not in filepath.name: + filepath = filepath.with_suffix(".json") + # First we check if the file already exists. If yes and the override # keyword is False (default), we will raise an exception. Otherwise # the file will be overwritten. - if override is False: - if os.path.isfile(filepath): - raise _FileAlreadyExists( - f"The file {filepath} already exists. Use a different filepath, " - "or set the 'override' kwarg to True." + if override is False: # noqa: SIM102 + if filepath.is_file(): + msg = ( + f"The file {filepath} already exists. Use a different " + "filepath, or set the 'override' to True." ) - # We dump the object to the json file. Additional kwargs can be passed. - with open(filepath, "w+") as json_file: - json.dump(obj, json_file, **kwargs) - - def dump2file(self, obj, filepath, override=False, **kwargs): - """Dump a dictionary into a file. (Extensions: XYZ or PDB) + raise FileExistsError(msg) - Parameters - ---------- - obj : :class:`dict` - A dictionary containing molecular information. - - filepath : :class:`str` - The filepath for the dumped file. + # We dump the object to the json file. Additional kwargs can be passed. + with filepath.open("w+") as json_file: + json.dump(obj, json_file, default=default) + + def dump2file( # noqa: PLR0913 + self, + obj: dict, # type: ignore[type-arg] + filepath: str | pathlib.Path, + atom_ids_key: str, + override: bool = False, # noqa: FBT001, FBT002 + elements_key: str = "elements", + coordinates_key: str = "coordinates", + remarks: None | abc.Sequence[str] | str | float = None, + cryst: str = "unit_cell", + space_group: str | None = None, + forcefield: str | None = None, + decipher: bool = False, # noqa: FBT001, FBT002 + resname: str = "MOL", + chainid: str = "A", + resseq: int = 1, + ) -> None: + """Dump a dictionary into a file. (Extensions: XYZ or PDB). + + Parameters: + obj: + A dictionary containing molecular information. + + filepath: + The filepath for the dumped file. + + atom_ids: + Whether to use elements or atom_ids in pdb files. + + override: + If True, any file in the filepath will be override. + (default=False) + + NEED TO UPDATE KWARGS. - override : :class:`bool` - If True, any file in the filepath will be override. (default=False) """ + filepath = pathlib.Path(filepath) # First we check if the file already exists. If yes and the override # keyword is False (default), we will raise an exception. Otherwise # the file will be overwritten. - if override is False: - if os.path.isfile(filepath): - raise _FileAlreadyExists( - f"The file {filepath} already exists. Use a different filepath, " - "or set the 'override' kwarg to True." - ) - if str(filepath[-3:]) not in self._save_funcs.keys(): - raise _FileTypeError( - f"The {filepath[-3:]!s} file extension is " + if override is False and filepath.is_file(): + msg = ( + f"The file {filepath} already exists. " + "Use a different filepath, " + "or set the 'override' kwarg to True." + ) + raise FileExistsError(msg) + + if filepath.suffix == ".pdb": + self._save_pdb( + system=obj, + filepath=filepath, + atom_ids_key=atom_ids_key, + elements_key=elements_key, + coordinates_key=coordinates_key, + remarks=remarks, + cryst=cryst, + space_group=space_group, + forcefield=forcefield, + decipher=decipher, + resname=resname, + chainid=chainid, + resseq=resseq, + ) + elif filepath.suffix == ".xyz": + self._save_xyz( + system=obj, + filepath=filepath, + elements_key=elements_key, + coordinates_key=coordinates_key, + remarks=remarks, + forcefield=forcefield, + decipher=decipher, + ) + else: + msg = ( + f"The {filepath.suffix} file extension is " "not supported for dumping a MolecularSystem or a Molecule. " "Please use XYZ or PDB." ) - self._save_funcs[str(filepath[-3:])](obj, filepath, **kwargs) - - def _save_xyz(self, system, filepath, **kwargs): - """""" - # Initial settings. - settings = { - "elements": "elements", - "coordinates": "coordinates", - "remark": " ", - "decipher": False, - "forcefield": None, - } - settings.update(kwargs) + raise _FileTypeError(msg) + + def _save_xyz( # noqa: PLR0913 + self, + system: dict, # type: ignore[type-arg] + filepath: str | pathlib.Path, + elements_key: str = "elements", + coordinates_key: str = "coordinates", + remarks: None | str | float | abc.Sequence[str] = None, + forcefield: str | None = None, + decipher: bool = False, # noqa: FBT001, FBT002 + ) -> None: + filepath = pathlib.Path(filepath) + + if isinstance(remarks, (list, tuple)): + remarks = ";".join(remarks) + elif remarks is None: + remarks = "" + # Extract neccessary data. - elements = system["elements"] - coordinates = system["coordinates"] - if settings["decipher"] is True: + elements = system[elements_key] + coordinates = system[coordinates_key] + if decipher is True: + if forcefield is None: + msg = "forcefield must be provided when decipher is True" + raise ValueError(msg) elements = np.array( [ - decipher_atom_key(key, forcefield=settings["forcefield"]) + decipher_atom_key(key, forcefield=forcefield) for key in elements ] ) - string = "{0:0d}\n{1}\n".format(len(elements), str(settings["remark"])) + string = f"{len(elements):0d}\n{remarks!s}\n" for i, j in zip(elements, coordinates): - string += "{0} {1:.2f} {2:.2f} {3:.2f}\n".format(i, *j) - with open(filepath, "w+") as file_: + string += "{} {:.2f} {:.2f} {:.2f}\n".format(i, *j) + with filepath.open("w+") as file_: file_.write(string) - def _save_pdb(self, system, filepath, **kwargs): - """""" - settings = { - "atom_ids": "atom_ids", - "elements": "elements", - "coordinates": "coordinates", - "cryst": "unit_cell", - "connect": None, - "remarks": None, - "space_group": None, - "resName": "MOL", - "chainID": "A", - "resSeq": 1, - "decipher": False, - "forcefield": None, - } - settings.update(kwargs) + def _save_pdb( # noqa: C901, PLR0913 + self, + system: dict, # type: ignore[type-arg] + filepath: str | pathlib.Path, + atom_ids_key: str, + elements_key: str = "elements", + coordinates_key: str = "coordinates", + remarks: None | abc.Sequence[str] | str | float = None, + cryst: str = "unit_cell", + space_group: str | None = None, + forcefield: str | None = None, + decipher: bool = False, # noqa: FBT001, FBT002 + resname: str = "MOL", + chainid: str = "A", + resseq: int = 1, + ) -> None: + filepath = pathlib.Path(filepath) + # We create initial string that we will gradually extend while we # process the data and in the end it will be written into a pdb file. string = "REMARK File generated using pyWINDOW." - # Number of items (atoms) in the provided system. - len_ = system[settings["atom_ids"]].shape[0] + # We process the remarks, if any, given by the user (optional). - if isinstance(settings["remarks"], (list, tuple)): + if isinstance(remarks, (list, tuple)): # If a list or tuple of remarks each is written at a new line # with the REMARK prefix not to have to long remark line. - for remark in settings["remarks"]: + for remark in remarks: string = "\n".join([string, f"REMARK {remark}"]) # Otherwise if it's a single string or an int/float we just write # it under single remark line, otherwise nothing happens. - elif isinstance(settings["remarks"], (str, int, float)): - remark = settings["remarks"] + elif isinstance(remarks, (str, int, float)): + remark = remarks string = "\n".join([string, f"REMARK {remark}"]) + # If there is a unit cell (crystal data) provided we need to add it. - if settings["cryst"] in system.keys(): - if system[settings["cryst"]].any(): - cryst_line = "CRYST1" - cryst = system[settings["cryst"]] - # The user have to provide the crystal data as a list/array - # of six items containing unit cell edges lengths a, b and c - # in x, y and z directions and three angles, or it can be. - # Other options are not allowed for simplicity. It can convert - # from the lattice array using function from utilities. - for i in cryst[:3]: - cryst_line = "".join([cryst_line, f"{i:9.3f}"]) - for i in cryst[3:]: - cryst_line = "".join([cryst_line, f"{i:7.2f}"]) - # This is kind of messy, by default the data written in PDB - # file should be P1 symmetry group therefore containing all - # atom coordinates and not considering symmetry operations. - # But, user can still define a space group if he wishes to. - if settings["space_group"] is not None: - space_group = settings["space_group"] - else: - space_group = "{0}".format("P1") - cryst_line = " ".join([cryst_line, space_group]) - # We add the unit cell parameters to the main string. - string = "\n".join([string, cryst_line]) + if cryst in system and system[cryst].any(): + cryst_line = "CRYST1" + cryst = system[cryst] + # The user have to provide the crystal data as a list/array + # of six items containing unit cell edges lengths a, b and c + # in x, y and z directions and three angles, or it can be. + # Other options are not allowed for simplicity. It can convert + # from the lattice array using function from utilities. + for i in cryst[:3]: + cryst_line = "".join([cryst_line, f"{i:9.3f}"]) + for i in cryst[3:]: + cryst_line = "".join([cryst_line, f"{i:7.2f}"]) + # This is kind of messy, by default the data written in PDB + # file should be P1 symmetry group therefore containing all + # atom coordinates and not considering symmetry operations. + # But, user can still define a space group if he wishes to. + if space_group is None: + space_group = "{}".format("P1") + cryst_line = f"{cryst_line} {space_group}" + # We add the unit cell parameters to the main string. + string = f"{string}\n{cryst_line}" # For the sake of code readability we extract interesting data from the # system. Atom_ids are the atom ids written at the third column of a # PDB file and the user has here the freedom to use the forcefield @@ -383,40 +448,46 @@ def _save_pdb(self, system, filepath, **kwargs): # (chainID) and residue sequence (resSeq) can be controlled by # appropriate parameter keyword passed to this function, Otherwise # the default values from settings dictionary are used. - atom_ids = system[settings["atom_ids"]] - elements = system[settings["elements"]] + atom_ids = system[atom_ids_key] + elements = system[elements_key] # If the 'elements' array of the system need deciphering atom keys this # is done if the user sets decipher to True. They can also provided # forcefield, otherwise it's None which equals to DLF. - if settings["decipher"] is True: + if decipher is True: + if forcefield is None: + msg = "forcefield must be provided when decipher is True" + raise ValueError(msg) elements = np.array( [ - decipher_atom_key(key, forcefield=settings["forcefield"]) + decipher_atom_key(key, forcefield=forcefield) for key in elements ] ) - coordinates = system[settings["coordinates"]] - for i in range(len_): - atom_line = f"ATOM {i + 1:5d}" + coordinates = system[coordinates_key] + + # Number of items (atoms) in the provided system. + # No idea why mypy has an issue here... + for i in range(len(list(system[atom_ids_key]))): # type: ignore[assignment] + atom_line = f"ATOM {i + 1:5d}" # type: ignore[operator] atom_id = f"{atom_ids[i].center(4):4}" - resName = "{0:3}".format(settings["resName"]) - chainID = settings["chainID"] - atom_line = " ".join([atom_line, atom_id, resName, chainID]) - resSeq = str(settings["resSeq"]).rjust(4) - atom_line = "".join([atom_line, resSeq]) - coor = f"{coordinates[i][0]:8.3f}{coordinates[i][1]:8.3f}{coordinates[i][2]:8.3f}" - atom_line = " ".join([atom_line, coor]) - big_space = "{0}".format(" ".center(22)) + atom_line = f"{atom_line} {atom_id} {resname:3} {chainid}" + resseq_formatted = str(resseq).rjust(4) + atom_line = f"{atom_line}{resseq_formatted}" + coor = ( + f"{coordinates[i][0]:8.3f}{coordinates[i][1]:8.3f}" + f"{coordinates[i][2]:8.3f}" + ) + atom_line = f"{atom_line} {coor}" + big_space = "{}".format(" ".center(22)) element = f"{elements[i].rjust(2):2} " - atom_line = "".join([atom_line, big_space, element]) - string = "\n".join([string, atom_line]) - # The connectivity part is to be written after a function calculating - # connectivity is finished - # "Everything that has a beginning has an end" by Neo. :) - string = "\n".join([string, "END"]) + atom_line = f"{atom_line}{big_space}{element}" + string = f"{string}\n{atom_line}" + + string = f"{string}\nEND" # Check if .pdb extension is missing from filepath. - if filepath[-4:].lower() != ".pdb": - filepath = ".".join((filepath, "pdb")) + if filepath.suffix != ".pdb": + filepath = pathlib.Path(f"{filepath}.pdb") + # Write the string to a a PDB file. - with open(filepath, "w+") as file: + with filepath.open("w+") as file: file.write(string) diff --git a/src/pywindow/_internal/molecular.py b/src/pywindow/_internal/molecular.py index 2cd2d73..18214c7 100644 --- a/src/pywindow/_internal/molecular.py +++ b/src/pywindow/_internal/molecular.py @@ -4,18 +4,24 @@ at the frontfront of the interaction with the user. The two main classes defined here: :class:`MolecularSystem` and :class:`Molecule` are used to store and analyse single molecules or assemblies of single molecules. + The :class:`MolecularSystem` is used as a first step to the analysis. It allows to load data, to refine it (rebuild molecules in a periodic system, decipher force field atom ids) and to extract single molecules for analysis as :class:`Molecule` instances. + To get started see :class:`MolecularSystem`. + To get started with the analysis of Molecular Dynamic trajectories go to :mod:`pywindow.trajectory`. + """ from __future__ import annotations +import pathlib from copy import deepcopy +from typing import TYPE_CHECKING import numpy as np @@ -37,191 +43,21 @@ to_list, ) +if TYPE_CHECKING: + import rdkit + class _MolecularSystemError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message -class _NotAModularSystem(Exception): - def __init__(self, message): +class _NotAModularSystemError(Exception): + def __init__(self, message: str) -> None: self.message = message -class _Shape: - """Class containing shape descriptors. - - This class allows other classes, such as :class:`Pore` and - :class:`Molecule`, inherit shape descriptors (applicable to any set of - points in a 3D Cartesian space, let it be a shape of an intrinsic pore or - shape of a molecule) such as asphericity, acylidricity and relative shape - anisotropy. This class should not be used by itself. - - """ - - @property - def _asphericity(self): - """Return asphericity of a shape. - - The asphericity of a shape is weighted by the mass assigned to each - coordinate (associated with the element). In case if `elements` is - `None`, mass of each element = 1 and this returns a non-weighted value. - - Returns: - ------- - :class:`float` - The asphericity of a shape. - - """ - return calc_asphericity(self.elements, self.coordinates) - - @property - def _acylidricity(self): - """Return acylidricity of a shape. - - The acylidricity of a shape is weighted by the mass assigned to each - coordinate (associated with the element). In case if `elements` is - `None`, mass of each element = 1 and this returns a non-weighted value. - - Returns: - ------- - :class:`float` - The acylidricity of a shape. - - """ - return calc_acylidricity(self.elements, self.coordinates) - - @property - def _relative_shape_anisotropy(self): - """Return relative shape anisotropy of a shape. - - The relative shape anisotropy of a shape is weighted by the mass - assigned to each coordinate (associated with the element). In case if - `elements` is `None`, mass of each element = 1 and this returns a - non-weighted value. - - Returns: - ------- - :class:`float` - The relative shape anisotropy of a shape. - - """ - return calc_relative_shape_anisotropy(self.elements, self.coordinates) - - @property - def inertia_tensor(self): - """Return inertia tensor of a shape. - - The inertia tensor of a shape is weighted by the mass assigned to each - coordinate (associated with the element). In case if `elements` is - `None`, mass of each element = 1 and this returns a non-weighted value. - - Returns: - ------- - :class:`numpy.array` - The inertia tensor of a shape. - - """ - return get_inertia_tensor(self.elements, self.coordinates) - - @property - def gyration_tensor(self): - """Return gyration tensor of a shape. - - The gyration tensor of a shape is weighted by the mass assigned to each - coordinate (associated with the element). In case if `elements` is - `None`, mass of each element = 1 and this returns a non-weighted value. - - Returns: - ------- - :class:`numpy.array` - The gyration tensor of a shape. - - """ - return get_gyration_tensor(self.elements, self.coordinates) - - -class _Pore(_Shape): - """Under development.""" - - def __init__(self, elements, coordinates, shape=False, **kwargs): - self._elements, self._coordinates = elements, coordinates - self.diameter, self.closest_atom = pore_diameter( - elements, coordinates, **kwargs - ) - self.spherical_volume = sphere_volume(self.diameter / 2) - if "com" in kwargs: - self.centre_coordinates = kwargs["com"] - else: - self.centre_coordinates = center_of_mass(elements, coordinates) - self.optimised = False - - def optimise(self, **kwargs): - (self.diameter, self.closest_atom, self.centre_coordinates) = ( - opt_pore_diameter( - self._elements, - self._coordinates, - com=self.centre_coordinates, - **kwargs, - ) - ) - self.spherical_volume = sphere_volume(self.diameter / 2) - self.optimised = True - - def get_shape(self): - super().__init__(calculate_pore_shape(self._coordinates)) - - def reset(self): - self.__init__(self._elements, self._coordinates) - - -class _Window: - """Under development.""" - - def __init__(self, window, key, elements, coordinates, com_adjust): - self.raw_data = window - self.index = key - self.mol_coordinates = coordinates - self.mol_elements = elements - self.com_correction = com_adjust - self.shape = None - self.convexhull = None - - def calculate_diameter(self, **kwargs): - diameter = calculate_window_diameter( - self.raw_data, self.mol_elements, self.mol_coordinates, **kwargs - ) - return diameter - - def calculate_centre_of_mass(self, **kwargs): - com = get_window_com( - self.raw_data, - self.mol_elements, - self.mol_coordinates, - self.com_correction, - **kwargs, - ) - return com - - def get_shape(self, **kwargs): - self.shape = window_shape( - self.raw_data, self.mol_elements, self.mol_coordinates - ) - return self.shape - - def get_convexhull(self): - hull = ConvexHull(self.shape) - verticesx = np.append( - self.shape[hull.vertices, 0], self.shape[hull.vertices, 0][0] - ) - verticesy = np.append( - self.shape[hull.vertices, 1], self.shape[hull.vertices, 1][0] - ) - self.convexhull = verticesx, verticesy - return self.convexhull - - -class Molecule(_Shape): +class Molecule: """Container for a single molecule. This class is meant for the analysis of single molecules, molecular pores @@ -249,45 +85,45 @@ class Molecule(_Shape): 7. The circular diameter of a window of a molecule. Attributes: - ---------- - mol : :class:`dict` - The :attr:`Molecular.System.system` dictionary passed to the - :class:`Molecule` which is esentially a container of the information - that compose a molecular entity, such as the coordinates and - atom ids and/or elements. + mol : :class:`dict` + The :attr:`Molecular.System.system` dictionary passed to the + :class:`Molecule` which is esentially a container of the + information that compose a molecular entity, such as the + coordinates and atom ids and/or elements. - no_of_atoms : :class:`int` - The number of atoms in the molecule. + no_of_atoms : :class:`int` + The number of atoms in the molecule. - elements : :class:`numpy.array` - An array containing the elements, as strings, composing the molecule. + elements : :class:`numpy.array` + An array containing the elements, as strings, composing the + molecule. - atom_ids : :class:`numpy.array` (conditional) - If the :attr:`Molecule.mol` contains 'atom_ids' keyword, the force - field ids of the elements. + atom_ids : :class:`numpy.array` (conditional) + If the :attr:`Molecule.mol` contains 'atom_ids' keyword, the force + field ids of the elements. - coordinates : :class:`numpy.array` - The x, y and z atomic Cartesian coordinates of all elements. + coordinates : :class:`numpy.array` + The x, y and z atomic Cartesian coordinates of all elements. - parent_system : :class:`str` - The :attr:`name` of :class:`MolecularSystem` passed to - :class:`Molecule`. + parent_system : :class:`str` + The :attr:`name` of :class:`MolecularSystem` passed to + :class:`Molecule`. - molecule_id : :class:`any` - The molecule id passed when initialising :class:`Molecule`. + molecule_id : :class:`any` + The molecule id passed when initialising :class:`Molecule`. - properties : :class:`dict` - A dictionary that is populated by the output of - :class:`Molecule` methods. + properties : :class:`dict` + A dictionary that is populated by the output of + :class:`Molecule` methods. """ - def __init__(self, mol, system_name, mol_id): + def __init__(self, mol: dict, system_name: str, mol_id: int) -> None: # type:ignore[type-arg] self._Output = Output() self.mol = mol self.no_of_atoms = len(mol["elements"]) self.elements = mol["elements"] - if "atom_ids" in mol.keys(): + if "atom_ids" in mol: self.atom_ids = mol["atom_ids"] self.coordinates = mol["coordinates"] self.parent_system = system_name @@ -296,25 +132,28 @@ def __init__(self, mol, system_name, mol_id): self._windows = None @classmethod - def load_rdkit_mol(cls, mol, system_name="rdkit", mol_id=0): + def load_rdkit_mol( + cls, + mol: rdkit.Chem.rdchem.Mol, + system_name: str = "rdkit", + mol_id: int = 0, + ) -> Molecule: """Create a :class:`Molecule` from :class:`rdkit.Chem.rdchem.Mol`. To be used only by expert users. - Parameters - ---------- - mol : :class:`rdkit.Chem.rdchem.Mol` - An RDKit molecule object. + Parameters: + mol : :class:`rdkit.Chem.rdchem.Mol` + An RDKit molecule object. Returns: - ------- - :class:`pywindow.molecular.Molecule` - :class:`Molecule` + :class:`pywindow.Molecule` + """ return cls(Input().load_rdkit_mol(mol), system_name, mol_id) - def full_analysis(self, ncpus=1, **kwargs): + def full_analysis(self, ncpus: int = 1) -> dict: # type:ignore[type-arg] """Perform a full structural analysis of a molecule. This invokes other methods: @@ -339,17 +178,15 @@ def full_analysis(self, ncpus=1, **kwargs): 10. :attr:`calculate_windows()` - Parameters - ---------- - ncpus : :class:`int` - Number of CPUs used for the parallelised parts of - :func:`pywindow.utilities.find_windows()`. (default=1=serial) + Parameters: + ncpus : :class:`int` + Number of CPUs used for the parallelised parts of + :func:`pywindow.utilities.find_windows()`. (default=1=serial) Returns: - ------- - :attr:`Molecule.properties` - The updated :attr:`Molecule.properties` with returns of all - used methods. + :attr:`Molecule.properties` + The updated :attr:`Molecule.properties` with returns of all + used methods. """ self.molecular_weight() @@ -358,124 +195,92 @@ def full_analysis(self, ncpus=1, **kwargs): self.calculate_average_diameter() self.calculate_pore_diameter() self.calculate_pore_volume() - self.calculate_pore_diameter_opt(**kwargs) - self.calculate_pore_volume_opt(**kwargs) - self.calculate_windows(ncpus=ncpus, **kwargs) - # self._circumcircle(**kwargs) + self.calculate_pore_diameter_opt() + self.calculate_pore_volume_opt() + self.calculate_windows(ncpus=ncpus) + return self.properties - def _align_to_principal_axes(self, align_molsys=False): + def _align_to_principal_axes(self, align_molsys: bool = False) -> None: # noqa: FBT001, FBT002 if align_molsys: - self.coordinates[0] = align_principal_ax_all( - self.elements, self.coordinates - ) - else: - self.coordinates[0] = align_principal_ax( - self.elements, self.coordinates - ) - self.aligned_to_principal_axes = True + raise NotImplementedError + # self.coordinates[0] = align_principal_ax_all( + # self.elements, self.coordinates - def _get_pore(self): - return Pore(self.elements, self.coordinates) - - def _get_shape(self, **kwargs): - super().__init__(self.coordinates, elements=self.elements) - - def _get_windows(self, **kwargs): - windows = find_windows_new(self.elements, self.coordinates, **kwargs) - if windows: - self.windows = [ - Window( - np.array(windows[0][window]), - window, - windows[1], - windows[2], - windows[3], - ) - for window in windows[0] - if window != -1 - ] - return self.windows - return None + self.coordinates[0] = align_principal_ax( + self.elements, self.coordinates + ) + self.aligned_to_principal_axes = True - def calculate_centre_of_mass(self): + def calculate_centre_of_mass(self) -> np.ndarray: # type:ignore[type-arg] """Return the xyz coordinates of the centre of mass of a molecule. Returns: - ------- - :class:`numpy.array` The centre of mass of the molecule. """ self.centre_of_mass = center_of_mass(self.elements, self.coordinates) - self.properties["centre_of_mass"] = self.centre_of_mass + self.properties["centre_of_mass"] = self.centre_of_mass # type:ignore[assignment] return self.centre_of_mass - def calculate_maximum_diameter(self): + def calculate_maximum_diameter(self) -> float: """Return the maximum diamension of a molecule. Returns: - ------- - :class:`float` The maximum dimension of the molecule. """ self.maxd_atom_1, self.maxd_atom_2, self.maximum_diameter = max_dim( self.elements, self.coordinates ) - self.properties["maximum_diameter"] = { + self.properties["maximum_diameter"] = { # type:ignore[assignment] "diameter": self.maximum_diameter, "atom_1": int(self.maxd_atom_1), "atom_2": int(self.maxd_atom_2), } return self.maximum_diameter - def calculate_average_diameter(self, **kwargs): + def calculate_average_diameter(self) -> float: """Return the average diamension of a molecule. Returns: - ------- - :class:`float` The average dimension of the molecule. """ self.average_diameter = find_average_diameter( - self.elements, self.coordinates, **kwargs + self.elements, self.coordinates ) + self.properties["average_diameter"] = self.average_diameter # type:ignore[assignment] return self.average_diameter - def calculate_pore_diameter(self): + def calculate_pore_diameter(self) -> float: """Return the intrinsic pore diameter. Returns: - ------- - :class:`float` The intrinsic pore diameter. """ self.pore_diameter, self.pore_closest_atom = pore_diameter( self.elements, self.coordinates ) - self.properties["pore_diameter"] = { + self.properties["pore_diameter"] = { # type:ignore[assignment] "diameter": self.pore_diameter, "atom": int(self.pore_closest_atom), } return self.pore_diameter - def calculate_pore_volume(self): + def calculate_pore_volume(self) -> float: """Return the intrinsic pore volume. Returns: - ------- - :class:`float` The intrinsic pore volume. """ self.pore_volume = sphere_volume(self.calculate_pore_diameter() / 2) - self.properties["pore_volume"] = self.pore_volume + self.properties["pore_volume"] = self.pore_volume # type:ignore[assignment] return self.pore_volume - def calculate_pore_diameter_opt(self, **kwargs): + def calculate_pore_diameter_opt(self) -> float: """Return the intrinsic pore diameter (for the optimised pore centre). Similarly to :func:`calculate_pore_diameter` this method returns the @@ -483,8 +288,6 @@ def calculate_pore_diameter_opt(self, **kwargs): of the pore centre is found with optimisation. Returns: - ------- - :class:`float` The intrinsic pore diameter. """ @@ -492,15 +295,15 @@ def calculate_pore_diameter_opt(self, **kwargs): self.pore_diameter_opt, self.pore_opt_closest_atom, self.pore_opt_COM, - ) = opt_pore_diameter(self.elements, self.coordinates, **kwargs) - self.properties["pore_diameter_opt"] = { + ) = opt_pore_diameter(self.elements, self.coordinates) + self.properties["pore_diameter_opt"] = { # type:ignore[assignment] "diameter": self.pore_diameter_opt, "atom_1": int(self.pore_opt_closest_atom), "centre_of_mass": self.pore_opt_COM, } return self.pore_diameter_opt - def calculate_pore_volume_opt(self, **kwargs): + def calculate_pore_volume_opt(self) -> float: """Return the intrinsic pore volume (for the optimised pore centre). Similarly to :func:`calculate_pore_volume` this method returns the @@ -508,55 +311,47 @@ def calculate_pore_volume_opt(self, **kwargs): :func:`calculate_pore_diameter_opt` returned value. Returns: - ------- - :class:`float` The intrinsic pore volume. """ self.pore_volume_opt = sphere_volume( - self.calculate_pore_diameter_opt(**kwargs) / 2 + self.calculate_pore_diameter_opt() / 2 ) - self.properties["pore_volume_opt"] = self.pore_volume_opt + self.properties["pore_volume_opt"] = self.pore_volume_opt # type:ignore[assignment] return self.pore_volume_opt - def _calculate_pore_shape(self, filepath="shape.xyz", **kwargs): - shape = calculate_pore_shape(self.elements, self.coordinates, **kwargs) - shape_obj = {"elements": shape[0], "coordinates": shape[1]} - Output()._save_xyz(shape_obj, filepath) - return 1 - - def calculate_windows(self, **kwargs): + def calculate_windows(self, ncpus: int = 1) -> np.ndarray | None: # type:ignore[type-arg] """Return the diameters of all windows in a molecule. This function first finds and then measures the diameters of all the window in the molecule. Returns: - ------- - :class:`numpy.array` - An array of windows' diameters. - - :class:`NoneType` - If no windows were found. + An array of windows' diameters. Or, None, ff no windows were found. """ - windows = find_windows(self.elements, self.coordinates, **kwargs) - if windows: + windows = find_windows( + self.elements, + self.coordinates, + processes=ncpus, + ) + if windows is not None: self.properties.update( { - "windows": { + "windows": { # type:ignore[dict-item] "diameters": windows[0], "centre_of_mass": windows[1], } } ) return windows[0] + self.properties.update( - {"windows": {"diameters": None, "centre_of_mass": None}} + {"windows": {"diameters": None, "centre_of_mass": None}} # type:ignore[dict-item] ) return None - def shift_to_origin(self, **kwargs): + def shift_to_origin(self) -> None: """Shift a molecule to Origin. This function takes the molecule's coordinates and adjust them so that @@ -564,43 +359,44 @@ def shift_to_origin(self, **kwargs): coordinate system. Returns: - ------- - None : :class:`NoneType` + None : :class:`NoneType` """ - self.coordinates = shift_com(self.elements, self.coordinates, **kwargs) + self.coordinates = shift_com(self.elements, self.coordinates) self._update() - def molecular_weight(self): + def molecular_weight(self) -> float: """Return the molecular weight of a molecule. Returns: - ------- - :class:`float` - The molecular weight of the molecule. + :class:`float` + The molecular weight of the molecule. """ self.MW = molecular_weight(self.elements) - return self.MW - - def dump_properties_json(self, filepath=None, molecular=False, **kwargs): + return float(self.MW) + + def dump_properties_json( + self, + filepath: pathlib.Path | str | None = None, + molecular: bool = False, # noqa: FBT001, FBT002 + override: bool = False, # noqa: FBT001, FBT002 + ) -> None: """Dump content of :attr:`Molecule.properties` to a JSON dictionary. - Parameters - ---------- - filepath : :class:`str` - The filepath for the dumped file. If :class:`None`, the file is - dumped localy with :attr:`molecule_id` as filename. - (defualt=None) - - molecular : :class:`bool` - If False, dump only the content of :attr:`Molecule.properties`, - if True, dump all the information about :class:`Molecule`. + Parameters: + filepath: + The filepath for the dumped file. If :class:`None`, the file is + dumped localy with :attr:`molecule_id` as filename. + (defualt=None) - Returns: - ------- - None : :class:`NoneType` + molecular: + If False, dump only the content of :attr:`Molecule.properties`, + if True, dump all the information about :class:`Molecule`. + override: + If True, any file in the filepath will be override. + (default=False) """ # We pass a copy of the properties dictionary. dict_obj = deepcopy(self.properties) @@ -609,18 +405,25 @@ def dump_properties_json(self, filepath=None, molecular=False, **kwargs): dict_obj.update(self.mol) # If no filepath is provided we create one. if filepath is None: - filepath = "_".join( - (str(self.parent_system), str(self.molecule_id)) - ) - filepath = "/".join((os.getcwd(), filepath)) + filepath = pathlib.Path(f"{self.parent_system}_{self.molecule_id}") + filepath = pathlib.Path.cwd() / filepath + filepath = pathlib.Path(filepath) # Dump the dictionary to json file. - self._Output.dump2json(dict_obj, filepath, default=to_list, **kwargs) + self._Output.dump2json( + dict_obj, + filepath, + default=to_list, + override=override, + ) - def dump_molecule(self, filepath=None, include_coms=False, **kwargs): + def dump_molecule( + self, + filepath: pathlib.Path | str | None = None, + include_coms: bool = False, # noqa: FBT001, FBT002 + override: bool = False, # noqa: FBT001, FBT002 + ) -> None: """Dump a :class:`Molecule` to a file (PDB or XYZ). - Kwargs are passed to :func:`pywindow.io_tools.Output.dump2file()`. - For validation purposes an overlay of window centres and COMs can also be dumped as: @@ -630,35 +433,33 @@ def dump_molecule(self, filepath=None, include_coms=False, **kwargs): Ar - for the centres of each found window - Parameters - ---------- - filepath : :class:`str` - The filepath for the dumped file. If :class:`None`, the file is - dumped localy with :attr:`molecule_id` as filename. - (defualt=None) + Parameters: + filepath: + The filepath for the dumped file. If :class:`None`, the file is + dumped locally with :attr:`molecule_id` as filename. + (default=None) - include_coms : :class:`bool` - If True, dump also with an overlay of window centres and COMs. - (default=False) + include_coms: + If True, dump also with an overlay of window centres and COMs. + (default=False) - Returns: - ------- - None : :class:`NoneType` + override: + If True, any file in the filepath will be override. + (default=False) """ # If no filepath is provided we create one. if filepath is None: - filepath = "_".join( - (str(self.parent_system), str(self.molecule_id)) + filepath = pathlib.Path( + f"{self.parent_system}_{self.molecule_id}.pdb" ) - filepath = "/".join((os.getcwd(), filepath)) - filepath = ".".join((filepath, "pdb")) + filepath = pathlib.Path.cwd() / filepath + filepath = f"{filepath}.pdb" + + filepath = pathlib.Path(filepath) # Check if there is an 'atom_ids' keyword in the self.mol dict. # Otherwise pass to the dump2file atom_ids='elements'. - if "atom_ids" not in self.mol.keys(): - atom_ids = "elements" - else: - atom_ids = "atom_ids" + atom_ids_key = "elements" if "atom_ids" not in self.mol else "atom_ids" # Dump molecule into a file. # If coms are to be included additional steps are required. # First deepcopy the molecule @@ -668,7 +469,7 @@ def dump_molecule(self, filepath=None, include_coms=False, **kwargs): mmol["elements"] = np.concatenate( (mmol["elements"], np.array(["He"])) ) - if "atom_ids" not in self.mol.keys(): + if "atom_ids" not in self.mol: pass else: mmol["atom_ids"] = np.concatenate( @@ -684,7 +485,7 @@ def dump_molecule(self, filepath=None, include_coms=False, **kwargs): mmol["elements"] = np.concatenate( (mmol["elements"], np.array(["Ne"])) ) - if "atom_ids" not in self.mol.keys(): + if "atom_ids" not in self.mol: pass else: mmol["atom_ids"] = np.concatenate( @@ -695,7 +496,7 @@ def dump_molecule(self, filepath=None, include_coms=False, **kwargs): mmol["coordinates"], np.array( [ - self.properties["pore_diameter_opt"][ + self.properties["pore_diameter_opt"][ # type:ignore[index] "centre_of_mass" ] ] @@ -703,15 +504,15 @@ def dump_molecule(self, filepath=None, include_coms=False, **kwargs): ) ) # add centre of windows as 'Ar'. - if self.properties["windows"]["centre_of_mass"] is not None: + if self.properties["windows"]["centre_of_mass"] is not None: # type:ignore[index] range_ = range( - len(self.properties["windows"]["centre_of_mass"]) + len(self.properties["windows"]["centre_of_mass"]) # type:ignore[index] ) for com in range_: mmol["elements"] = np.concatenate( (mmol["elements"], np.array(["Ar"])) ) - if "atom_ids" not in self.mol.keys(): + if "atom_ids" not in self.mol: pass else: mmol["atom_ids"] = np.concatenate( @@ -722,42 +523,33 @@ def dump_molecule(self, filepath=None, include_coms=False, **kwargs): mmol["coordinates"], np.array( [ - self.properties["windows"][ + self.properties["windows"][ # type:ignore[index] "centre_of_mass" ][com] ] ), ) ) - self._Output.dump2file(mmol, filepath, atom_ids=atom_ids, **kwargs) + self._Output.dump2file( + mmol, + filepath, + atom_ids_key=atom_ids_key, + override=override, + ) else: self._Output.dump2file( - self.mol, filepath, atom_ids=atom_ids, **kwargs + self.mol, + filepath, + atom_ids_key=atom_ids_key, + override=override, ) - def _update(self): + def _update(self) -> None: self.mol["coordinates"] = self.coordinates self.calculate_centre_of_mass() self.calculate_pore_diameter_opt() - def _circumcircle(self, **kwargs): - windows = circumcircle(self.coordinates, kwargs["atom_sets"]) - if "output" in kwargs: - if kwargs["output"] == "windows": - self.properties["circumcircle"] = {"diameter": windows} - elif windows is not None: - self.properties["circumcircle"] = { - "diameter": windows[0], - "centre_of_mass": windows[1], - } - else: - self.properties["circumcircle"] = { - "diameter": None, - "centre_of_mass": None, - } - return windows - class MolecularSystem: """Container for the molecular system. @@ -768,81 +560,78 @@ class MolecularSystem: :class:`MolecularSystem` **should not be initialised by itself.** Examples: - -------- - 1. Using file as an input: + 1. Using file as an input: - .. code-block:: python + .. code-block:: python - pywindow.molecular.MolecularSystem.load_file(`filepath`) + pywindow.MolecularSystem.load_file("filepath") - 2. Using RDKit molecule object as an input: + 2. Using RDKit molecule object as an input: - .. code-block:: python + .. code-block:: python - pywindow.molecular.MolecularSystem.load_rdkit_mol(rdkit.Chem.rdchem.Mol) + pywindow.MolecularSystem.load_rdkit_mol(rdkit.Chem.rdchem.Mol) - 3. Using a dictionary (or another :attr:`MoleculeSystem.system`) as input: + 3. Using a dictionary (or another :attr:`MoleculeSystem.system`) as + input: - .. code-block:: python + .. code-block:: python - pywindow.molecular.MolecularSystem.load_system({...}) + pywindow.MolecularSystem.load_system({...}) Attributes: - ---------- - system_id : :class:`str` or :class:`int` - The input filename or user defined. + system_id : :class:`str` or :class:`int` + The input filename or user defined. - system : :class:`dict` - A dictionary containing all the information extracted from input. + system : :class:`dict` + A dictionary containing all the information extracted from input. - molecules : :class:`list` - A list containing all the returned :class:`Molecule` s after using - :func:`make_modular()`. + molecules: + A dictionary containing all the returned :class:`Molecule` s after + using :func:`make_modular()`. """ - def __init__(self): + def __init__(self) -> None: self._Input = Input() self._Output = Output() - self.system_id = 0 + self.system_id: str | int = 0 + self.system: dict = {} # type: ignore[type-arg] + self.molecules: dict[int | str, Molecule] = {} @classmethod - def load_file(cls, filepath): + def load_file(cls, filepath: pathlib.Path | str) -> MolecularSystem: """Create a :class:`MolecularSystem` from an input file. Recognized input file formats: XYZ, PDB and MOL (V3000). - Parameters - ---------- - filepath : :class:`str` - The input's filepath. + Parameters: + filepath: + The input's filepath. Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` - :class:`MolecularSystem` + :class:`pywindow.MolecularSystem` + """ + filepath = pathlib.Path(filepath) obj = cls() obj.system = obj._Input.load_file(filepath) - obj.filename = os.path.basename(filepath) - obj.system_id = obj.filename.split(".")[0] - obj.name, ext = os.path.splitext(obj.filename) + obj.filename = filepath.name # type: ignore[attr-defined] + obj.system_id = obj.filename.split(".")[0] # type: ignore[attr-defined] + obj.name, ext = obj.filename.split(".") # type: ignore[attr-defined] return obj @classmethod - def load_rdkit_mol(cls, mol): - """Create a :class:`MolecularSystem` from :class:`rdkit.Chem.rdchem.Mol`. + def load_rdkit_mol(cls, mol: rdkit.Chem.Mol) -> MolecularSystem: + """Create a :class:`MolecularSystem` from :class:`rdkit.Chem.Mol`. - Parameters - ---------- - mol : :class:`rdkit.Chem.rdchem.Mol` - An RDKit molecule object. + Parameters: + mol: + An RDKit molecule object. Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` - :class:`MolecularSystem` + :class:`pywindow.MolecularSystem` """ obj = cls() @@ -850,7 +639,11 @@ def load_rdkit_mol(cls, mol): return obj @classmethod - def load_system(cls, dict_, system_id="system"): + def load_system( + cls, + dict_: dict, # type: ignore[type-arg] + system_id: str | int = "system", + ) -> MolecularSystem: """Create a :class:`MolecularSystem` from a python :class:`dict`. As the loaded :class:`MolecularSystem` is storred as a :class:`dict` in @@ -859,18 +652,16 @@ def load_system(cls, dict_, system_id="system"): extracts trajectory frames as dictionaries and returns them as :class:`MolecularSystem` objects through this classmethod. - Parameters - ---------- - dict_ : :class:`dict` - A python dictionary. + Parameters: + dict_: + A python dictionary. - system_id : :class:`str` or :class:'int', optional - Inherited or user defined system id. (default='system') + system_id: + Inherited or user defined system id. (default='system') Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` - :class:`MolecularSystem` + :class:`pywindow.MolecularSystem` + """ obj = cls() @@ -878,24 +669,22 @@ def load_system(cls, dict_, system_id="system"): obj.system_id = system_id return obj - def rebuild_system(self, override=False, **kwargs): + def rebuild_system(self, override: bool = False) -> MolecularSystem: # noqa: FBT001, FBT002 """Rebuild molecules in molecular system. - Parameters - ---------- - override : :class:`bool`, optional (default=False) - If False the rebuild molecular system is returned as a new - :class:`MolecularSystem`, if True, the current - :class:`MolecularSystem` is modified. + Parameters: + override : :class:`bool`, optional (default=False) + If False the rebuild molecular system is returned as a new + :class:`MolecularSystem`, if True, the current + :class:`MolecularSystem` is modified. """ # First we create a 3x3x3 supercell with the initial unit cell in the # centre and the 26 unit cell translations around to provide all the # atom positions necessary for the molecules passing through periodic # boundary reconstruction step. - supercell_333 = create_supercell(self.system, **kwargs) - # smolsys = self.load_system(supercell_333, self.system_id + '_311') - # smolsys.dump_system(override=True) + supercell_333 = create_supercell(self.system) + discrete = discrete_molecules(self.system, rebuild=supercell_333) # This function overrides the initial data for 'coordinates', # 'atom_ids', and 'elements' instances in the 'system' dictionary. @@ -915,10 +704,14 @@ def rebuild_system(self, override=False, **kwargs): } if override is True: self.system.update(rebuild_system) - return None + return self.load_system(rebuild_system) - def swap_atom_keys(self, swap_dict, dict_key="atom_ids"): + def swap_atom_keys( + self, + swap_dict: dict, # type: ignore[type-arg] + dict_key: str = "atom_ids", + ) -> None: """Swap a force field atom id for another user-defined value. This modified all values in :attr:`MolecularSystem.system['atom_ids']` @@ -928,37 +721,36 @@ def swap_atom_keys(self, swap_dict, dict_key="atom_ids"): appropriate dictionary is passed to the function. Example: - ------- - In this example all atom ids 'he' will be exchanged to 'H'. + In this example all atom ids 'he' will be exchanged to 'H'. - .. code-block:: python + .. code-block:: python - pywindow.molecular.MolecularSystem.swap_atom_keys({'he': 'H'}) + pywindow.MolecularSystem.swap_atom_keys({'he': 'H'}) - Parameters - ---------- - swap_dict: :class:`dict` - A dictionary containg force field atom ids (keys) to be swapped - with corresponding values (keys' arguments). + Parameters: + swap_dict: + A dictionary containg force field atom ids (keys) to be swapped + with corresponding values (keys' arguments). - dict_key: :class:`str` - A key in :attr:`MolecularSystem.system` dictionary to perform the - atom keys swapping operation on. (default='atom_ids') + dict_key: + A key in :attr:`MolecularSystem.system` dictionary to perform + the atom keys swapping operation on. (default='atom_ids') Returns: - ------- - None : :class:`NoneType` + None : :class:`NoneType` """ # Similar situation to the one from decipher_atom_keys function. - if "atom_ids" not in self.system.keys(): + if "atom_ids" not in self.system: dict_key = "elements" for atom_key in range(len(self.system[dict_key])): - for key in swap_dict.keys(): + for key, value in swap_dict.items(): if self.system[dict_key][atom_key] == key: - self.system[dict_key][atom_key] = swap_dict[key] + self.system[dict_key][atom_key] = value - def decipher_atom_keys(self, forcefield="DLF", dict_key="atom_ids"): + def decipher_atom_keys( + self, forcefield: str = "DLF", dict_key: str = "atom_ids" + ) -> None: """Decipher force field atom ids. This takes all values in :attr:`MolecularSystem.system['atom_ids']` @@ -973,29 +765,27 @@ def decipher_atom_keys(self, forcefield="DLF", dict_key="atom_ids"): See: C. W. Yong, Descriptions and Implementations of DL_F Notation: A Natural Chemical Expression System of Atom Types for Molecular - Simulations, J. Chem. Inf. Model., 2016, 56, 1405–1409. + Simulations, J. Chem. Inf. Model., 2016, 56, 1405-1409. - Parameters - ---------- - forcefield : :class:`str` - The forcefield used to decipher atom ids. Allowed (not case - sensitive): 'OPLS', 'OPLS2005', 'OPLSAA', 'OPLS3', 'DLF', 'DL_F'. - (default='DLF') + Parameters: + forcefield: + The forcefield used to decipher atom ids. Allowed (not case + sensitive): 'OPLS', 'OPLS2005', 'OPLSAA', 'OPLS3', 'DLF', + 'DL_F'. (default='DLF') - dict_key : :class:`str` - The :attr:`MolecularSystem.system` dictionary key to the array - containing the force field atom ids. (default='atom_ids') + dict_key: + The :attr:`MolecularSystem.system` dictionary key to the array + containing the force field atom ids. (default='atom_ids') Returns: - ------- - None : :class:`NoneType` + None : :class:`NoneType` """ # In case there is no 'atom_ids' key we try 'elements'. This is for # XYZ and MOL files mostly. But, we keep the dict_key keyword for # someone who would want to decipher 'elements' even if 'atom_ids' key # is present in the system's dictionary. - if "atom_ids" not in self.system.keys(): + if "atom_ids" not in self.system: dict_key = "elements" # I do it on temporary object so that it only finishes when successful temp = deepcopy(self.system[dict_key]) @@ -1005,20 +795,18 @@ def decipher_atom_keys(self, forcefield="DLF", dict_key="atom_ids"): ) self.system["elements"] = temp - def make_modular(self, rebuild=False): + def make_modular(self, rebuild: bool = False) -> None: # noqa: FBT001, FBT002 """Find and return all :class:`Molecule` s in :class:`MolecularSystem`. This function populates :attr:`MolecularSystem.molecules` with :class:`Molecule` s. - Parameters - ---------- - rebuild : :class:`bool` - If True, run first the :func:`rebuild_system()`. (default=False) + Parameters: + rebuild: + If True, run first the :func:`rebuild_system()`. Returns: - ------- - None : :class:`NoneType` + None : :class:`NoneType` """ if rebuild is True: @@ -1029,69 +817,63 @@ def make_modular(self, rebuild=False): self.no_of_discrete_molecules = len(dis) self.molecules = {} for i in range(len(dis)): - self.molecules[i] = Molecule(dis[i], self.system_id, i) + self.molecules[i] = Molecule( + mol=dis[i], + system_name=str(self.system_id), + mol_id=i, + ) - def system_to_molecule(self): + def system_to_molecule(self) -> Molecule: """Return :class:`MolecularSystem` as a :class:`Molecule` directly. Only to be used conditionally, when the :class:`MolecularSystem` is a discrete molecule and no input pre-processing is required. Returns: - ------- - :class:`pywindow.molecular.Molecule` - :class:`Molecule` + :class:`pywindow.Molecule` + """ - return Molecule(self.system, self.system_id, 0) - - def _get_pores(self, sampling_points): - """Under development.""" - pores = [] - for point in sampling_points: - pores.append( - Pore( - self.system["elements"], - self.system["coordinates"], - com=point, - ) - ) - return pores + return Molecule( + mol=self.system, system_name=str(self.system_id), mol_id=0 + ) - def dump_system(self, filepath=None, modular=False, **kwargs): + def dump_system( + self, + filepath: pathlib.Path | str | None = None, + modular: bool = False, # noqa: FBT001, FBT002 + override: bool = False, # noqa: FBT001, FBT002 + ) -> None: """Dump a :class:`MolecularSystem` to a file (PDB or XYZ). - Kwargs are passed to :func:`pywindow.io_tools.Output.dump2file()`. - - Parameters - ---------- - filepath : :class:`str` - The filepath for the dumped file. If :class:`None`, the file is - dumped localy with :attr:`system_id` as filename. - (defualt=None) + Parameters: + filepath: + The filepath for the dumped file. If :class:`None`, the file is + dumped localy with :attr:`system_id` as filename. + (defualt=None) - modular : :class:`bool` - If False, dump the :class:`MolecularSystem` as in - :attr:`MolecularSystem.system`, if True, dump the - :class:`MolecularSystem` as catenated :class:Molecule objects - from :attr:`MolecularSystem.molecules` + modular: + If False, dump the :class:`MolecularSystem` as in + :attr:`MolecularSystem.system`, if True, dump the + :class:`MolecularSystem` as catenated :class:Molecule objects + from :attr:`MolecularSystem.molecules` - Returns: - ------- - None : :class:`NoneType` + override: + If True, any file in the filepath will be override. + (default=False) """ # If no filepath is provided we create one. if filepath is None: - filepath = "/".join((os.getcwd(), str(self.system_id))) - filepath = ".".join((filepath, "pdb")) + filepath = pathlib.Path.cwd() / f"{self.system_id}.pdb" + + filepath = pathlib.Path(filepath) # If modular is True substitute the molecular data for modular one. system_dict = deepcopy(self.system) if modular is True: elements = np.array([]) atom_ids = np.array([]) coor = np.array([]).reshape(0, 3) - for mol_ in self.molecules: - mol = self.molecules[mol_] + for mol in self.molecules.values(): elements = np.concatenate((elements, mol.mol["elements"])) atom_ids = np.concatenate((atom_ids, mol.mol["atom_ids"])) coor = np.concatenate((coor, mol.mol["coordinates"]), axis=0) @@ -1101,16 +883,23 @@ def dump_system(self, filepath=None, modular=False, **kwargs): # Check if there is an 'atom_ids' keyword in the self.mol dict. # Otherwise pass to the dump2file atom_ids='elements'. # This is mostly for XYZ files and not deciphered trajectories. - if "atom_ids" not in system_dict.keys(): - atom_ids = "elements" - else: - atom_ids = "atom_ids" + atom_ids_key = ( + "elements" if "atom_ids" not in system_dict else "atom_ids" + ) # Dump system into a file. self._Output.dump2file( - system_dict, filepath, atom_ids=atom_ids, **kwargs + system_dict, + filepath, + atom_ids_key=atom_ids_key, + override=override, ) - def dump_system_json(self, filepath=None, modular=False, **kwargs): + def dump_system_json( + self, + filepath: pathlib.Path | str | None = None, + modular: bool = False, # noqa: FBT001, FBT002 + override: bool = False, # noqa: FBT001, FBT002 + ) -> None: """Dump a :class:`MolecularSystem` to a JSON dictionary. The dumped JSON dictionary, with :class:`MolecularSystem`, can then be @@ -1119,22 +908,21 @@ def dump_system_json(self, filepath=None, modular=False, **kwargs): Kwargs are passed to :func:`pywindow.io_tools.Output.dump2json()`. - Parameters - ---------- - filepath : :class:`str` - The filepath for the dumped file. If :class:`None`, the file is - dumped localy with :attr:`system_id` as filename. - (defualt=None) + Parameters: + filepath: + The filepath for the dumped file. If :class:`None`, the file is + dumped localy with :attr:`system_id` as filename. + (defualt=None) - modular : :class:`bool` - If False, dump the :class:`MolecularSystem` as in - :attr:`MolecularSystem.system`, if True, dump the - :class:`MolecularSystem` as catenated :class:Molecule objects - from :attr:`MolecularSystem.molecules` + modular: + If False, dump the :class:`MolecularSystem` as in + :attr:`MolecularSystem.system`, if True, dump the + :class:`MolecularSystem` as catenated :class:Molecule objects + from :attr:`MolecularSystem.molecules` - Returns: - ------- - None : :class:`NoneType` + override: + If True, any file in the filepath will be override. + (default=False) """ # We pass a copy of the properties dictionary. @@ -1145,16 +933,23 @@ def dump_system_json(self, filepath=None, modular=False, **kwargs): if self.molecules: pass except AttributeError: - raise _NotAModularSystem( + msg = ( "This system is not modular. Please, run first the " "make_modular() function of this class." ) + raise _NotAModularSystemError(msg) from None dict_obj = {} - for molecule in self.molecules: - mol_ = self.molecules[molecule] + for molecule, mol_ in self.molecules.items(): dict_obj[molecule] = mol_.mol # If no filepath is provided we create one. if filepath is None: - filepath = "/".join((os.getcwd(), str(self.system_id))) + filepath = pathlib.Path.cwd() / f"{self.system_id}" + filepath = pathlib.Path(filepath) + # Dump the dictionary to json file. - self._Output.dump2json(dict_obj, filepath, default=to_list, **kwargs) + self._Output.dump2json( + dict_obj, + filepath, + default=to_list, + override=override, + ) diff --git a/src/pywindow/_internal/tables.py b/src/pywindow/_internal/tables.py index cf8c29d..8b4416a 100644 --- a/src/pywindow/_internal/tables.py +++ b/src/pywindow/_internal/tables.py @@ -640,7 +640,6 @@ "Xe": ["Xe", "xe"], } - periodic_table = { "H": 1, "He": 2, diff --git a/src/pywindow/_internal/trajectory.py b/src/pywindow/_internal/trajectory.py index 3ac8a74..923bcf5 100644 --- a/src/pywindow/_internal/trajectory.py +++ b/src/pywindow/_internal/trajectory.py @@ -6,8 +6,11 @@ Example: ------- In this example a DL_POLY_C HISTORY trajectory file is loaded. + .. code-block:: python + pywindow.trajectory.DLPOLY('path/to/HISTORY') + Then, each of the trajectory frames can be extracted and returned as a :class:`pywindow.MolecularSystem` object for analysis. See :mod:`pywindow.molecular` docstring for more information. @@ -25,14 +28,17 @@ properties is miniscule and it is usually the :func:`pywindow.MolecularSystem.rebuild_system()` step that is the bottleneck. + """ from __future__ import annotations +import pathlib from contextlib import closing from copy import deepcopy from mmap import ACCESS_READ, mmap from multiprocessing import Pool +from typing import Any, Literal import numpy as np @@ -47,327 +53,311 @@ class _ParallelAnalysisError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message class _TrajectoryError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message class _FormatError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message class _FunctionError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message -def make_supercell(system, matrix, supercell=[1, 1, 1]): +def make_supercell( + system: dict, # type: ignore[type-arg] + supercell: list[float] | None = None, +) -> MolecularSystem: """Return a supercell. This functions takes the input unitcell and creates a supercell of it that - is returned as a new :class:`pywindow.molecular.MolecularSystem`. + is returned as a new :class:`pywindow.MolecularSystem`. - Parameters - ---------- - system : :attr:`pywindow.molecular.MolecularSystem.system` - The unit cell for creation of the supercell + Parameters: + system: + The unit cell for creation of the supercell - matrix : :class:`numpy.array` - The unit cell parameters in form of a lattice. - - supercell : :class:`list`, optional - A list that specifies the size of the supercell in the a, b and c - direction. (default=[1, 1, 1]) + supercell: + A list that specifies the size of the supercell in the a, b and c + direction. (default=[1, 1, 1]) Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` Returns the created supercell as a new :class:`MolecularSystem`. """ + if supercell is None: + supercell = [1, 1, 1] user_supercell = [[1, supercell[0]], [1, supercell[1]], [1, supercell[1]]] - system = create_supercell(system, matrix, supercell=user_supercell) + system = create_supercell(system=system, supercell=user_supercell) return MolecularSystem.load_system(system) -class DLPOLY: - """A container for a DL_POLY_C type trajectory (HISTORY). - - This function takes a DL_POLY_C trajectory file and maps it for the - binary points in the file where each frame starts/ends. This way the - process is fast, as it not require loading the trajectory into computer - memory. When a frame is being extracted, it is only this frame that gets - loaded to the memory. - - Frames can be accessed individually and loaded as an unmodified string, - returned as a :class:`pywindow.molecular.MolecularSystem` (and analysed), - dumped as PDB or XYZ or JSON (if dumped as a - :attr:`pywindow.molecular.MolecularSystem.system`) - - Attributes: - ---------- - filepath : :class:`str` - The filepath. - - system_id : :class:`str` - The system id inherited from the filename. - - frames : :class:`dict` - A dictionary that is populated, on the fly, with the extracted frames. - - analysis_output : :class:`dict` - A dictionary that is populated, on the fly, with the analysis output. - - """ - - def __init__(self, filepath): - # Image conventions - periodic boundary key. - self._imcon = { - 0: "nonperiodic", - 1: "cubic", - 2: "orthorhombic", - 3: "parallelepiped", - 4: "truncated octahedral", - 5: "rhombic dodecahedral", - 6: "x-y parallelogram", - 7: "hexagonal prism", - } - # Trajectory key - content type. - self._keytrj = { - 0: "coordinates", - 1: "coordinates and velocities", - 2: "coordinates, velocities and forces", - } - self.filepath = filepath - self.system_id = os.path.basename(filepath) - self.frames = {} - self.analysis_output = {} - # Check the history file at init, if no errors, proceed to mapping. - self._check_HISTORY() - # Map the trajectory file at init. - self._map_HISTORY() - - def _map_HISTORY(self): - """ """ - self.trajectory_map = {} - with open(self.filepath) as trajectory_file: - with closing( - mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) - ) as mapped_file: - progress = 0 - line = 0 - frame = 0 - cell_param_line = 0 - # We need to first process trajectory file's header. - header_flag = True - while progress <= len(mapped_file): - line = line + 1 - # We read a binary data from a mapped file. - bline = mapped_file.readline() - # If the bline length equals zero we terminate. - # We reached end of the file but still add the last frame! - if len(bline) == 0: - self.trajectory_map[frame] = [frame_start, progress] - frame = frame + 1 - break - # We need to decode byte line into an utf-8 string. - sline = bline.decode("utf-8").strip("\n").split() - # We extract map's byte coordinates for each frame - if header_flag is False: - if sline[0] == "timestep": - self.trajectory_map[frame] = [ - frame_start, - progress, - ] - frame_start = progress - frame = frame + 1 - # Here we extract the map's byte coordinates for the header - # And also the periodic system type needed for later. - if header_flag is True: - if sline[0] == "timestep": - self.trajectory_map["header"] = self._decode_head( - [0, progress] - ) - frame_start = progress - header_flag = False - progress = progress + len(bline) - self.no_of_frames = frame - - def _decode_head(self, header_coordinates): - start, end = header_coordinates - with open(self.filepath) as trajectory_file: - with closing( - mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) - ) as mapped_file: - header = [ - i.split() - for i in mapped_file[start:end].decode("utf-8").split("\n") - ] - header = [int(i) for i in header[1]] - self.periodic_boundary = self._imcon[header[1]] - self.content_type = self._keytrj[header[0]] - self.no_of_atoms = header[2] - return header - - def get_frames(self, frames="all", override=False, **kwargs): +class Trajectory: + """A base class container for trajectories.""" + + def __init__(self) -> None: + self.frames = {} # type: ignore[var-annotated] + self.analysis_output = {} # type: ignore[var-annotated] + msg = "This is an abstract class" + raise NotImplementedError(msg) + + def get_frames( # noqa: C901 + self, + frames: int + | list[int] + | tuple[int, int] + | Literal["all", "everything"] = "all", + override: bool = False, # noqa: FBT001, FBT002 + swap_atoms: dict | None = None, # type: ignore[type-arg] + forcefield: str | None = None, + extract_data: bool = True, # noqa: FBT001, FBT002 + ) -> dict[int, MolecularSystem]: """Extract frames from the trajectory file. Depending on the passed parameters a frame, a list of particular frames, a range of frames (from, to), or all frames can be extracted with this function. - Parameters - ---------- - frames : :class:`int` or :class:`list` or :class:`touple` or :class:`str` - Specified frame (:class:`int`), or frames (:class:`list`), or - range (:class:`touple`), or `all`/`everything` (:class:`str`). - (default=`all`) + Parameters: + frames : :class:`int` or :class:`list` or :class:`tuple` or + :class:`str` + Specified frame (:class:`int`), or frames (:class:`list`), or + range (:class:`tuple`), or `all`/`everything` (:class:`str`). + (default=`all`) - override : :class:`bool` - If True, a frame already storred in :attr:`frames` can be override. - (default=False) + override : :class:`bool` + If True, a frame already storred in :attr:`frames` can be + override. (default=False) - extract_data : :class:`bool`, optional - If False, a frame is returned as a :class:`str` block as in the - trajectory file. Ohterwise, it is extracted and returned as - :class:`pywindow.molecular.MolecularSystem`. (default=True) + extract_data : :class:`bool`, optional + If False, a frame is returned as a :class:`str` block as in the + trajectory file. Ohterwise, it is extracted and returned as + :class:`pywindow.MolecularSystem`. (default=True) - swap_atoms : :class:`dict`, optional - If this kwarg is passed with an appropriate dictionary a - :func:`pywindow.molecular.MolecularSystem.swap_atom_keys()` will - be applied to the extracted frame. + swap_atoms : :class:`dict`, optional + If this kwarg is passed with an appropriate dictionary a + :func:`pywindow.MolecularSystem.swap_atom_keys()` + will be applied to the extracted frame. - forcefield : :class:`str`, optional - If this kwarg is passed with appropriate forcefield keyword a - :func:`pywindow.molecular.MolecularSystem.decipher_atom_keys()` - will be applied to the extracted frame. + forcefield : :class:`str`, optional + If this kwarg is passed with appropriate forcefield keyword a + :func:`pywindow.MolecularSystem.decipher_atom_keys()` + will be applied to the extracted frame. Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` - If a single frame is extracted. - - None : :class:`NoneType` - If more than one frame is extracted, the frames are returned to - :attr:`frames` + Dictionary of frames. """ + collected_frames = {} if override is True: self.frames = {} + if isinstance(frames, int): - frame = self._get_frame( - self.trajectory_map[frames], frames, **kwargs + frame_system = self._get_frame( + frame_coordinates=self.trajectory_map[frames], # type: ignore[attr-defined] + frame_no=frames, + swap_atoms=swap_atoms, + forcefield=forcefield, + extract_data=extract_data, ) - if frames not in self.frames.keys(): - self.frames[frames] = frame - return frame + if frames not in self.frames: + self.frames[frames] = frame_system + collected_frames[frames] = frame_system + return collected_frames + if isinstance(frames, list): for frame in frames: - if frame not in self.frames.keys(): + if frame not in self.frames: self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs + frame_coordinates=self.trajectory_map[frame], # type: ignore[attr-defined] + frame_no=frame, + swap_atoms=swap_atoms, + forcefield=forcefield, + extract_data=extract_data, ) + collected_frames[frame] = self.frames[frame] + if isinstance(frames, tuple): for frame in range(frames[0], frames[1]): - if frame not in self.frames.keys(): + if frame not in self.frames: self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs + frame_coordinates=self.trajectory_map[frame], # type: ignore[attr-defined] + frame_no=frame, + swap_atoms=swap_atoms, + forcefield=forcefield, + extract_data=extract_data, ) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) + collected_frames[frame] = self.frames[frame] + + if isinstance(frames, str) and frames in ["all", "everything"]: + for frame in range(self.no_of_frames): # type: ignore[attr-defined] + if frame not in self.frames: + self.frames[frame] = self._get_frame( + frame_coordinates=self.trajectory_map[frame], # type: ignore[attr-defined] + frame_no=frame, + swap_atoms=swap_atoms, + forcefield=forcefield, + extract_data=extract_data, + ) + collected_frames[frame] = self.frames[frame] + + return collected_frames + + def _decode_frame(self, frame: list) -> dict: # type:ignore[type-arg] + raise NotImplementedError - def _get_frame(self, frame_coordinates, frame_no, **kwargs): - kwargs_ = {"extract_data": True} - kwargs_.update(kwargs) + def _get_frame( + self, + frame_coordinates: list[int], + frame_no: int, + swap_atoms: dict | None = None, # type: ignore[type-arg] + forcefield: str | None = None, + extract_data: bool = True, # noqa: FBT001, FBT002 + ) -> MolecularSystem: start, end = frame_coordinates - with open(self.filepath) as trajectory_file: - with closing( + with ( + self.filepath.open() as trajectory_file, # type: ignore[attr-defined] + closing( mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) - ) as mapped_file: - if kwargs_["extract_data"] is False: - return mapped_file[start:end].decode("utf-8") - # [:-1] because the split results in last list empty. - frame = [ - i.split() - for i in mapped_file[start:end].decode("utf-8").split("\n") - ][:-1] - decoded_frame = self._decode_frame(frame) - molsys = MolecularSystem.load_system( - decoded_frame, "_".join([self.system_id, str(frame_no)]) - ) - if "swap_atoms" in kwargs: - molsys.swap_atom_keys(kwargs["swap_atoms"]) - if "forcefield" in kwargs: - molsys.decipher_atom_keys(kwargs["forcefield"]) - return molsys - - def _decode_frame(self, frame): - frame_data = { - "frame_info": { - "nstep": int(frame[0][1]), - "natms": int(frame[0][2]), - "keytrj": int(frame[0][3]), - "imcon": int(frame[0][4]), - "tstep": float(frame[0][5]), - } - } - start_line = 1 - if frame_data["frame_info"]["imcon"] in [1, 2, 3]: - frame_data["lattice"] = np.array(frame[1:4], dtype=float).T - frame_data["unit_cell"] = lattice_array_to_unit_cell( - frame_data["lattice"] + ) as mapped_file, + ): + if extract_data is False: + return mapped_file[start:end].decode("utf-8") # type: ignore[return-value] + # [:-1] because the split results in last list empty. + frame = [ + i.split() + for i in mapped_file[start:end].decode("utf-8").split("\n") + ][:-1] + decoded_frame = self._decode_frame(frame) + molsys = MolecularSystem.load_system( + decoded_frame, + "_".join([self.system_id, str(frame_no)]), # type: ignore[attr-defined] ) - start_line = 4 - # Depending on what the trajectory key is (see __init__) we need - # to extract every second/ third/ fourth line for elements and coor. - elements = [] - coordinates = [] - velocities = [] - forces = [] - for i in range(len(frame[start_line:])): - i_ = i + start_line - if frame_data["frame_info"]["keytrj"] == 0: - if i % 2 == 0: - elements.append(frame[i_][0]) - if i % 2 == 1: - coordinates.append(frame[i_]) - if frame_data["frame_info"]["keytrj"] == 1: - if i % 3 == 0: - elements.append(frame[i_][0]) - if i % 3 == 1: - coordinates.append(frame[i_]) - if i % 3 == 2: - velocities.append(frame[i_]) - if frame_data["frame_info"]["keytrj"] == 2: - if i % 4 == 0: - elements.append(frame[i_][0]) - if i % 4 == 1: - coordinates.append(frame[i_]) - if i % 4 == 2: - velocities.append(frame[i_]) - if i % 4 == 3: - forces.append(frame[i_]) - frame_data["atom_ids"] = np.array(elements) - frame_data["coordinates"] = np.array(coordinates, dtype=float) - if velocities: - frame_data["velocities"] = np.array(velocities, dtype=float) - if forces: - frame_data["forces"] = np.array(forces, dtype=float) - return frame_data - def analysis( - self, frames="all", ncpus=1, _ncpus=1, override=False, **kwargs - ): + if swap_atoms is not None: + molsys.swap_atom_keys(swap_atoms) + if forcefield is not None: + molsys.decipher_atom_keys(forcefield) + return molsys + + def save_analysis( + self, + filepath: str | pathlib.Path | None = None, + override: bool = False, # noqa: FBT001, FBT002 + ) -> None: + """Dump the content of :attr:`analysis_output` as JSON dictionary.""" + # We pass a copy of the analysis attribute dictionary. + dict_obj = deepcopy(self.analysis_output) # type: ignore[attr-defined] + # If no filepath is provided we create one. + if filepath is None: + filepath = f"{self.system_id}_pywindow_analysis" # type: ignore[attr-defined] + filepath = pathlib.Path.cwd() / filepath + filepath = pathlib.Path(filepath) + + # Dump the dictionary to json file. + Output().dump2json( + dict_obj, + filepath, + default=to_list, + override=override, + ) + + def save_frames( # noqa: C901, PLR0912 + self, + frames: int | list | tuple | Literal["all", "everything"] = "all", # type: ignore[type-arg] + filepath: str | pathlib.Path | None = None, + decipher: bool = True, # noqa: FBT001, FBT002 + swap_atoms: dict | None = None, # type: ignore[type-arg] + forcefield: str | None = None, + ) -> None: + # If no filepath is provided we create one. + if filepath is None: + filepath = pathlib.Path.cwd() / str(self.system_id) # type: ignore[attr-defined] + filepath = pathlib.Path(filepath) + + frames_to_get = [] + if isinstance(frames, int): + frames_to_get.append(frames) + if isinstance(frames, list): + frames_to_get = frames + if isinstance(frames, tuple): + for frame in range(frames[0], frames[1]): + frames_to_get.append(frame) + if isinstance(frames, str) and frames in ["all", "everything"]: + for frame in range(self.no_of_frames): # type: ignore[attr-defined] + frames_to_get.append(frame) + for frame in frames_to_get: + if frame not in self.frames: + _ = self.get_frames(frame) + + for frame in frames_to_get: + frame_molsys = self.frames[frame] + if decipher is True and forcefield is not None: + if swap_atoms is not None: + if isinstance(swap_atoms, dict): + frame_molsys.swap_atom_keys(swap_atoms) + else: + msg = ( # type: ignore[unreachable] + "The swap_atom_keys function only accepts " + "'swap_atoms' argument in form of a dictionary." + ) + raise _FunctionError(msg) + frame_molsys.decipher_atom_keys(forcefield) + ffilepath = "_".join((str(filepath), str(frame))) + + if "elements" not in frame_molsys.system: + msg = ( + "The frame (MolecularSystem object) needs to have " + "'elements' attribute within the system dictionary. " + "It is, therefore, neccessary that you set a decipher " + "keyword to True. (see manual)" + ) + raise _FunctionError(msg) + + if filepath.suffix == ".pdb": + Output()._save_pdb( # noqa: SLF001 + system=frame_molsys.system, + filepath=ffilepath, + atom_ids_key="elements" + if "atom_ids" not in frame_molsys.system + else "atom_ids", + forcefield=forcefield, + decipher=decipher, + ) + elif filepath.suffix == ".xyz": + Output()._save_xyz( # noqa: SLF001 + system=frame_molsys.system, + filepath=ffilepath, + forcefield=forcefield, + decipher=decipher, + ) + else: + msg = ( + f"The {filepath.suffix} file extension is " + "not supported for dumping a MolecularSystem or a" + " Molecule. Please use XYZ or PDB." + ) + raise _FormatError(msg) + + def analysis( # noqa: C901, PLR0912, PLR0913 + self, + frames: int | list | tuple | str = "all", # type: ignore[type-arg] + ncpus: int = 1, + ncpus_analysis: int = 1, + override: bool = False, # noqa: FBT001, FBT002 + modular: bool = False, # noqa: FBT001, FBT002 + rebuild: bool = False, # noqa: FBT001, FBT002 + swap_atoms: dict | None = None, # type: ignore[type-arg] + forcefield: str | None = None, + ) -> None: """Perform structural analysis on a frame/ set of frames. Depending on the passed parameters a frame, a list of particular @@ -392,47 +382,51 @@ def analysis( returned to the :attr:`frames` mimicking the behaviour of the :func:`get_frames()`. - Parameters - ---------- - frames : :class:`int` or :class:`list` or :class:`touple` or :class:`str` - Specified frame (:class:`int`), or frames (:class:`list`), or - range (:class:`touple`), or `all`/`everything` (:class:`str`). - (default='all') - - override : :class:`bool` - If True, an output already storred in :attr:`analysis_output` can - be override. (default=False) - - swap_atoms : :class:`dict`, optional - If this kwarg is passed with an appropriate dictionary a - :func:`pywindow.molecular.MolecularSystem.swap_atom_keys()` will - be applied to the extracted frame. - - forcefield : :class:`str`, optional - If this kwarg is passed with appropriate forcefield keyword a - :func:`pywindow.molecular.MolecularSystem.decipher_atom_keys()` - will be applied to the extracted frame. - - modular : :class:`bool`, optional - If this kwarg is passed a - :func:`pywindow.molecular.MolecularSystem.make_modular()` - will be applied to the extracted frame. (default=False) - - rebuild : :class:`bool`, optional - If this kwarg is passed a `rebuild=True` is passed to - :func:`pywindow.molecular.MolecularSystem.make_modular()` that - will be applied to the extracted frame. (default=False) - - ncpus : :class:`int`, optional - If ncpus > 1, then the analysis is performed in parallel for the - specified number of parallel jobs. Otherwise, it runs in serial. - (default=1) + Parameters: + frames : :class:`int` or :class:`list` or :class:`tuple` or + :class:`str` + Specified frame (:class:`int`), or frames (:class:`list`), or + range (:class:`touple`), or `all`/`everything` (:class:`str`). + (default='all') + + override : :class:`bool` + If True, an output already storred in :attr:`analysis_output` + can be override. (default=False) + + swap_atoms : :class:`dict`, optional + If this kwarg is passed with an appropriate dictionary a + :func:`pywindow.MolecularSystem.swap_atom_keys()` + will be applied to the extracted frame. + + forcefield : :class:`str`, optional + If this kwarg is passed with appropriate forcefield keyword a + :func:`pywindow.MolecularSystem.decipher_atom_keys()` + will be applied to the extracted frame. + + modular : :class:`bool`, optional + If this kwarg is passed a + :func:`pywindow.MolecularSystem.make_modular()` + will be applied to the extracted frame. (default=False) + + rebuild : :class:`bool`, optional + If this kwarg is passed a `rebuild=True` is passed to + :func:`pywindow.MolecularSystem.make_modular()` that + will be applied to the extracted frame. (default=False) + + ncpus : :class:`int`, optional + If ncpus > 1, then the analysis is performed in parallel for + the specified number of parallel jobs. Otherwise, it runs in + serial. (default=1) + + ncpus_analysis : :class:`int`, optional + If ncpus > 1, then the analysis is performed in parallel for + the specified number of parallel jobs. Otherwise, it runs in + serial. (default=1) Returns: - ------- - None : :class:`NoneType` - The function returns `None`, the analysis output is - returned to :attr:`analysis_output` dictionary. + None : :class:`NoneType` + The function returns `None`, the analysis output is + returned to :attr:`analysis_output` dictionary. """ frames_for_analysis = [] @@ -444,103 +438,104 @@ def analysis( if isinstance(frame, int): frames_for_analysis.append(frame) else: - raise _FunctionError( - "The list should be populated with integers only." - ) - if isinstance(frames, tuple): - if isinstance(frames[0], int) and isinstance(frames[1], int): - for frame in range(frames[0], frames[1]): - frames_for_analysis.append(frame) - raise _FunctionError( - "The tuple should contain only two integers " - "for the begining and the end of the frames range." - ) + msg = "The list should be populated with integers only." + raise _FunctionError(msg) + if ( + isinstance(frames, tuple) + and isinstance(frames[0], int) + and isinstance(frames[1], int) + ): + for frame in range(frames[0], frames[1]): + frames_for_analysis.append(frame) # noqa: PERF402 + msg = ( + "The tuple should contain only two integers " + "for the begining and the end of the frames range." + ) + raise _FunctionError(msg) if isinstance(frames, str): if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - frames_for_analysis.append(frame) + for frame in range(self.no_of_frames): # type: ignore[attr-defined] + frames_for_analysis.append(frame) # noqa: PERF402 + else: - raise _FunctionError( - "Didn't recognise the keyword. (see manual)" - ) + msg = "Didn't recognise the keyword. (see manual)" + raise _FunctionError(msg) # The override keyword by default is False. So we check if any of the # frames were already analysed and if so we delete them from the list. # However, if the override is set to True, then we just proceed. if override is False: frames_for_analysis_new = [] for frame in frames_for_analysis: - if frame not in self.analysis_output.keys(): - frames_for_analysis_new.append(frame) + if frame not in self.analysis_output: + frames_for_analysis_new.append(frame) # noqa: PERF401 frames_for_analysis = frames_for_analysis_new + if ncpus == 1: for frame in frames_for_analysis: - analysed_frame = self._analysis_serial(frame, _ncpus, **kwargs) + analysed_frame = self._analysis_serial( + frame=frame, + ncpus_analysis=ncpus_analysis, + rebuild=rebuild, + modular=modular, + forcefield=forcefield, + swap_atoms=swap_atoms, + ) self.analysis_output[frame] = analysed_frame + if ncpus > 1: - self._analysis_parallel(frames_for_analysis, ncpus, **kwargs) + self._analysis_parallel( + frames=frames_for_analysis, + ncpus=ncpus, + ncpus_analysis=ncpus_analysis, + rebuild=rebuild, + modular=modular, + forcefield=forcefield, + swap_atoms=swap_atoms, + ) - def _analysis_serial(self, frame, _ncpus, **kwargs): - settings = { - "rebuild": False, - "modular": False, - } - settings.update(kwargs) + def _analysis_serial( # noqa: PLR0913 + self, + frame: int, + ncpus_analysis: int = 1, + rebuild: bool = False, # noqa: FBT001, FBT002 + modular: bool = False, # noqa: FBT001, FBT002 + swap_atoms: dict | None = None, # type: ignore[type-arg] + forcefield: str | None = None, + ) -> dict: # type: ignore[type-arg] molecular_system = self._get_frame( - self.trajectory_map[frame], frame, extract_data=True, **kwargs + frame_coordinates=self.trajectory_map[frame], # type: ignore[attr-defined] + frame_no=frame, + extract_data=True, + swap_atoms=swap_atoms, + forcefield=forcefield, ) - if settings["modular"] is True: - molecular_system.make_modular(rebuild=settings["rebuild"]) + if modular is True: + molecular_system.make_modular(rebuild=rebuild) molecules = molecular_system.molecules else: molecules = {"0": molecular_system.system_to_molecule()} + results = {} for molecule in molecules: mol = molecules[molecule] - if "molsize" in settings: - molsize = settings["molsize"] - if isinstance(molsize, int): - if mol.no_of_atoms == molsize: - results[molecule] = mol.full_analysis( - _ncpus=_ncpus, **kwargs - ) - if isinstance(molsize, tuple) and isinstance(molsize[0], str): - if molsize[0] in ["bigger", "greater", "larger", "more"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis( - _ncpus=_ncpus, **kwargs - ) - if molsize[0] in ["smaller", "less"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis( - _ncpus=_ncpus, **kwargs - ) - if molsize[0] in ["not", "isnot", "notequal", "different"]: - if mol.no_of_atoms != molsize[1]: - results[molecule] = mol.full_analysis( - _ncpus=_ncpus, **kwargs - ) - if molsize[0] in ["is", "equal", "exactly"]: - if mol.no_of_atoms == molsize[1]: - results[molecule] = mol.full_analysis( - _ncpus=_ncpus, **kwargs - ) - if molsize[0] in ["between", "inbetween"]: - if molsize[1] < mol.no_of_atoms < molsize[2]: - results[molecule] = mol.full_analysis( - _ncpus=_ncpus, **kwargs - ) - else: - results[molecule] = mol.full_analysis(_ncpus=_ncpus, **kwargs) + results[molecule] = mol.full_analysis(ncpus=ncpus_analysis) return results - def _analysis_parallel_execute(self, frame, **kwargs): - settings = { - "rebuild": False, - "modular": False, - } + def _analysis_parallel_execute( # type: ignore[no-untyped-def] + self, + frame: int, + # Using kwargs here for parallel execution. + **kwargs, # noqa: ANN003 + ) -> tuple[int, dict]: # type: ignore[type-arg] + settings = {"rebuild": False, "modular": False} settings.update(kwargs) + molecular_system = self._get_frame( - self.trajectory_map[frame], frame, extract_data=True, **kwargs + frame_coordinates=self.trajectory_map[frame], # type: ignore[attr-defined] + frame_no=frame, # type: ignore[arg-type] + extract_data=True, + swap_atoms=settings["swap_atoms"], # type: ignore[arg-type] + forcefield=settings["forcefield"], # type: ignore[arg-type] ) if settings["modular"] is True: molecular_system.make_modular(rebuild=settings["rebuild"]) @@ -550,203 +545,295 @@ def _analysis_parallel_execute(self, frame, **kwargs): results = {} for molecule in molecules: mol = molecules[molecule] - if "molsize" in settings: - molsize = settings["molsize"] - if isinstance(molsize, int): - if mol.no_of_atoms == molsize: - results[molecule] = mol.full_analysis(**kwargs) - if isinstance(molsize, tuple) and isinstance(molsize[0], str): - if molsize[0] in ["bigger", "greater", "larger", "more"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["smaller", "less"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["not", "isnot", "notequal", "different"]: - if mol.no_of_atoms != molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["is", "equal", "exactly"]: - if mol.no_of_atoms == molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["between", "inbetween"]: - if molsize[1] < mol.no_of_atoms < molsize[2]: - results[molecule] = mol.full_analysis(**kwargs) - else: - results[molecule] = mol.full_analysis(**kwargs) + results[molecule] = mol.full_analysis( + ncpus=settings["ncpus_analysis"] + ) return frame, results - def _analysis_parallel(self, frames, ncpus, **kwargs): + def _analysis_parallel( # noqa: PLR0913 + self, + frames: list, # type: ignore[type-arg] + ncpus: int, + ncpus_analysis: int, + rebuild: bool = False, # noqa: FBT001, FBT002 + modular: bool = False, # noqa: FBT001, FBT002 + swap_atoms: dict | None = None, # type: ignore[type-arg] + forcefield: str | None = None, + ) -> None: try: pool = Pool(processes=ncpus) parallel = [ pool.apply_async( - self._analysis_parallel_execute, args=(frame,), kwds=kwargs + self._analysis_parallel_execute, + args=(frame,), + kwds={ + "swap_atoms": swap_atoms, + "rebuild": rebuild, + "forcefield": forcefield, + "modular": modular, + "ncpus_analysis": ncpus_analysis, + }, ) for frame in frames ] results = [p.get() for p in parallel if p.get()] pool.terminate() for i in results: - self.analysis_output[i[0]] = i[1] + self.analysis_output[i[0]] = i[1] # type: ignore[index, attr-defined] except TypeError: pool.terminate() - raise _ParallelAnalysisError("Parallel analysis failed.") + msg = "Parallel analysis failed." + raise _ParallelAnalysisError(msg) from None - def _check_HISTORY(self): - """ """ - self.check_log = "" - line = 0 - binary_step = 0 - timestep = 0 - timestep_flag = "timestep" - progress = 0 - warning_1 = "No comment line is present as the file header.\n" - warning_2 = " ".join( - ( - "Second header line is missing from the file", - "that contains information on the system's periodicity", - "and the type of the trajectory file.\n", - ) - ) - warning_3 = " ".join( - ( - "Comment line encountered in the middle of", - "the trajectory file.\n", - ) - ) +class DLPOLY(Trajectory): + """A container for a DL_POLY_C type trajectory (HISTORY). - error_1 = "The trajectory is discontinous.\n" - error_2 = "The file contains an empty line.\n" + This function takes a DL_POLY_C trajectory file and maps it for the + binary points in the file where each frame starts/ends. This way the + process is fast, as it not require loading the trajectory into computer + memory. When a frame is being extracted, it is only this frame that gets + loaded to the memory. - with open(self.filepath) as trajectory_file: - # We open the HISTORY trajectory file - with closing( - mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) - ) as file_binary_map: - # We use this binary mapping feature that instead of loading - # the full file into memory beforehand it only - # maps the content. Especially useful with enormous files - while binary_step < len(file_binary_map): - line += 1 - binary_line = file_binary_map.readline() - binary_step = binary_step + len(binary_line) - progress_old = progress - progress = round( - binary_step * 100 / len(file_binary_map), 0 - ) - string_line = ( - binary_line.decode("utf-8").strip("\n").split() - ) + Frames can be accessed individually and loaded as an unmodified string, + returned as a :class:`pywindow.MolecularSystem` (and analysed), + dumped as PDB or XYZ or JSON (if dumped as a + :attr:`pywindow.MolecularSystem.system`) - # Warning 1 - if line == 1: - if string_line[0] != "DLFIELD": - self.check_log = " ".join( - (self.check_log, f"Line {line}:", warning_1) - ) - - # Warning 2 - if line == 2: - if len(string_line) != 3: - self.check_log = " ".join( - (self.check_log, f"Line {line}:", warning_2) - ) - - # Error 1 - if string_line: - if string_line[0] == timestep_flag: - old_timestep = timestep - timestep = int(string_line[1]) - if old_timestep > timestep: - error = " ".join(f"Line {line}:", error_1) - raise _TrajectoryError(error) - - # Error 2 - if len(string_line) == 0: - error = " ".join(f"Line {line}:", error_2) - raise _TrajectoryError(error) + Attributes: + filepath : :class:`str` + The filepath. - def save_analysis(self, filepath=None, **kwargs): - """Dump the content of :attr:`analysis_output` as JSON dictionary. + system_id : :class:`str` + The system id inherited from the filename. - Parameters - ---------- - filepath : :class:`str` - The filepath for the JSON file. + frames : :class:`dict` + A dictionary that is populated, on the fly, with the extracted + frames. - Returns: - ------- - None : :class:`NoneType` - """ - # We pass a copy of the analysis attribute dictionary. - dict_obj = deepcopy(self.analysis_output) - # If no filepath is provided we create one. - if filepath is None: - filepath = "_".join((str(self.system_id), "pywindow_analysis")) - filepath = "/".join((os.getcwd(), filepath)) - # Dump the dictionary to json file. - Output().dump2json(dict_obj, filepath, default=to_list, **kwargs) - - def save_frames(self, frames, filepath=None, filetype="pdb", **kwargs): - settings = { - "pdb": Output()._save_pdb, - "xyz": Output()._save_xyz, - "decipher": True, - "forcefield": None, + analysis_output : :class:`dict` + A dictionary that is populated, on the fly, with the analysis + output. + + """ + + def __init__(self, filepath: pathlib.Path | str) -> None: + # Image conventions - periodic boundary key. + self._imcon = { + 0: "nonperiodic", + 1: "cubic", + 2: "orthorhombic", + 3: "parallelepiped", + 4: "truncated octahedral", + 5: "rhombic dodecahedral", + 6: "x-y parallelogram", + 7: "hexagonal prism", } - settings.update(kwargs) - if filetype.lower() not in settings: - raise _FormatError( - f"The '{filetype}' file format is not supported" - ) - frames_to_get = [] - if isinstance(frames, int): - frames_to_get.append(frames) - if isinstance(frames, list): - frames_to_get = frames - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - frames_to_get.append(frame) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - frames_to_get.append(frame) - for frame in frames_to_get: - if frame not in self.frames.keys(): - _ = self.get_frames(frame) - # If no filepath is provided we create one. - if filepath is None: - filepath = "/".join((os.getcwd(), str(self.system_id))) - for frame in frames_to_get: - frame_molsys = self.frames[frame] - if ( - settings["decipher"] is True - and settings["forcefield"] is not None - ): - if "swap_atoms" in settings: - if isinstance(settings["swap_atoms"], dict): - frame_molsys.swap_atom_keys(settings["swap_atoms"]) - else: - raise _FunctionError( - "The swap_atom_keys function only accepts " - "'swap_atoms' argument in form of a dictionary." + # Trajectory key - content type. + self._keytrj = { + 0: "coordinates", + 1: "coordinates and velocities", + 2: "coordinates, velocities and forces", + } + self.filepath = pathlib.Path(filepath) + self.system_id = self.filepath.name.split(".")[0] + self.frames = {} # type: ignore[var-annotated] + self.analysis_output = {} # type: ignore[var-annotated] + # Check the history file at init, if no errors, proceed to mapping. + self._check_history() + # Map the trajectory file at init. + self._map_history() + + def _map_history(self) -> None: + """Map HISTORY file.""" + self.trajectory_map: dict[str | int, Any] = {} + with self.filepath.open() as trajectory_file: + with closing( + mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) + ) as mapped_file: + progress = 0 + line = 0 + frame = 0 + + # We need to first process trajectory file's header. + header_flag = True + while progress <= len(mapped_file): + line = line + 1 + # We read a binary data from a mapped file. + bline = mapped_file.readline() + # If the bline length equals zero we terminate. + # We reached end of the file but still add the last frame! + if len(bline) == 0: + self.trajectory_map[frame] = [frame_start, progress] # noqa: F821 + frame = frame + 1 + break + # We need to decode byte line into an utf-8 string. + sline = bline.decode("utf-8").strip("\n").split() + # We extract map's byte coordinates for each frame + if header_flag is False and sline[0] == "timestep": + self.trajectory_map[frame] = [ + frame_start, # noqa: F821 + progress, + ] + frame_start: int = progress + frame = frame + 1 + # Here we extract the map's byte coordinates for the header + # And also the periodic system type needed for later. + if header_flag is True and sline[0] == "timestep": + self.trajectory_map["header"] = self._decode_head( + [0, progress] ) - frame_molsys.decipher_atom_keys(settings["forcefield"]) - ffilepath = "_".join((filepath, str(frame))) - if "elements" not in frame_molsys.system.keys(): - raise _FunctionError( - "The frame (MolecularSystem object) needs to have " - "'elements' attribute within the system dictionary. " - "It is, therefore, neccessary that you set a decipher " - "keyword to True. (see manual)" - ) - settings[filetype.lower()]( - frame_molsys.system, ffilepath, **kwargs + frame_start = progress # noqa: F841 + header_flag = False + progress = progress + len(bline) + self.no_of_frames = frame + + def _decode_head( + self, + header_coordinates: list[int], + ) -> list[list[str]]: + start, end = header_coordinates + with ( + self.filepath.open() as trajectory_file, + closing( + mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) + ) as mapped_file, + ): + header = [ + i.split() + for i in mapped_file[start:end].decode("utf-8").split("\n") + ] + header = [int(i) for i in header[1]] # type:ignore[misc] + self.periodic_boundary = self._imcon[header[1]] # type:ignore[index] + self.content_type = self._keytrj[header[0]] # type:ignore[index] + self.no_of_atoms = header[2] # type:ignore[index] + return header + + def _decode_frame(self, frame: list) -> dict: # type:ignore[type-arg] # noqa: C901, PLR0912 + frame_data = { + "frame_info": { + "nstep": int(frame[0][1]), + "natms": int(frame[0][2]), + "keytrj": int(frame[0][3]), + "imcon": int(frame[0][4]), + "tstep": float(frame[0][5]), + } + } + start_line = 1 + if frame_data["frame_info"]["imcon"] in [1, 2, 3]: + frame_data["lattice"] = np.array(frame[1:4], dtype=float).T # type:ignore[assignment] + frame_data["unit_cell"] = lattice_array_to_unit_cell( # type:ignore[assignment] + frame_data["lattice"] # type:ignore[arg-type] ) + start_line = 4 + + # Depending on what the trajectory key is (see __init__) we need + # to extract every second/ third/ fourth line for elements and coor. + elements = [] + coordinates = [] + velocities = [] + forces = [] + for i in range(len(frame[start_line:])): + i_ = i + start_line + if frame_data["frame_info"]["keytrj"] == 0: + if i % 2 == 0: + elements.append(frame[i_][0]) + if i % 2 == 1: + coordinates.append(frame[i_]) + if frame_data["frame_info"]["keytrj"] == 1: + if i % 3 == 0: + elements.append(frame[i_][0]) + if i % 3 == 1: + coordinates.append(frame[i_]) + if i % 3 == 2: # noqa: PLR2004 + velocities.append(frame[i_]) + if frame_data["frame_info"]["keytrj"] == 2: # noqa: PLR2004 + if i % 4 == 0: + elements.append(frame[i_][0]) + if i % 4 == 1: + coordinates.append(frame[i_]) + if i % 4 == 2: # noqa: PLR2004 + velocities.append(frame[i_]) + if i % 4 == 3: # noqa: PLR2004 + forces.append(frame[i_]) + + frame_data["atom_ids"] = np.array(elements) # type:ignore[assignment] + frame_data["coordinates"] = np.array(coordinates, dtype=float) # type:ignore[assignment] + if velocities: + frame_data["velocities"] = np.array(velocities, dtype=float) # type:ignore[assignment] + if forces: + frame_data["forces"] = np.array(forces, dtype=float) # type:ignore[assignment] + return frame_data + + def _check_history(self) -> None: + self.check_log = "" + line = 0 + binary_step = 0 + timestep = 0 + timestep_flag = "timestep" + + warning_1 = "No comment line is present as the file header.\n" + warning_2 = ( + "Second header line is missing from the file that contains" + " information on the system's periodicity and the type of the " + "trajectory file.\n" + ) + + error_1 = "The trajectory is discontinous.\n" + error_2 = "The file contains an empty line.\n" + + # We open the HISTORY trajectory file + with ( + self.filepath.open() as trajectory_file, + closing( + mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) + ) as file_binary_map, + ): + # We use this binary mapping feature that instead of loading + # the full file into memory beforehand it only + # maps the content. Especially useful with enormous files + while binary_step < len(file_binary_map): + line += 1 + binary_line = file_binary_map.readline() + binary_step = binary_step + len(binary_line) + + string_line = binary_line.decode("utf-8").strip("\n").split() + + # Warning 1 + if line == 1 and string_line[0] != "DLFIELD": + self.check_log = " ".join( + ( + self.check_log, + f"Line {line}:", + warning_1, + ) + ) + # Warning 2 + if line == 2 and len(string_line) != 3: # noqa: PLR2004 + self.check_log = " ".join( + ( + self.check_log, + f"Line {line}:", + warning_2, + ) + ) -class XYZ: + # Error 1 + if string_line and string_line[0] == timestep_flag: + old_timestep = timestep + timestep = int(string_line[1]) + if old_timestep > timestep: + error = " ".join((f"Line {line}:", error_1)) + raise _TrajectoryError(error) + + # Error 2 + if len(string_line) == 0: + error = " ".join((f"Line {line}:", error_2)) + raise _TrajectoryError(error) + + +class XYZ(Trajectory): """A container for an XYZ type trajectory. This function takes an XYZ trajectory file and maps it for the @@ -756,42 +843,43 @@ class XYZ: loaded to the memory. Frames can be accessed individually and loaded as an unmodified string, - returned as a :class:`pywindow.molecular.MolecularSystem` (and analysed), + returned as a :class:`pywindow.MolecularSystem` (and analysed), dumped as PDB or XYZ or JSON (if dumped as a - :attr:`pywindow.molecular.MolecularSystem.system`) + :attr:`pywindow.MolecularSystem.system`) Attributes: - ---------- - filepath : :class:`str` - The filepath. + filepath : :class:`str` + The filepath. - filename : :class:`str` - The filename. + filename : :class:`str` + The filename. - system_id : :class:`str` - The system id inherited from the filename. + system_id : :class:`str` + The system id inherited from the filename. - frames : :class:`dict` - A dictionary that is populated, on the fly, with the extracted frames. + frames : :class:`dict` + A dictionary that is populated, on the fly, with the extracted + frames. - analysis_output : :class:`dict` - A dictionary that is populated, on the fly, with the analysis output. + analysis_output : :class:`dict` + A dictionary that is populated, on the fly, with the analysis + output. """ - def __init__(self, filepath): - self.filepath = filepath - self.filename = os.path.basename(filepath) + def __init__(self, filepath: pathlib.Path | str) -> None: + self.filepath = pathlib.Path(filepath) + self.filename = self.filepath.name self.system_id = self.filename.split(".")[0] - self.frames = {} - self.analysis_output = {} + self.frames = {} # type: ignore[var-annotated] + self.analysis_output = {} # type: ignore[var-annotated] # Map the trajectory file at init. self._map_trajectory() - def _map_trajectory(self): - """Return filepath as a class attribute""" + def _map_trajectory(self) -> None: + """Map xyz trajectory.""" self.trajectory_map = {} - with open(self.filepath) as trajectory_file: + with self.filepath.open() as trajectory_file: with closing( mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) ) as mapped_file: @@ -825,106 +913,7 @@ def _map_trajectory(self): progress = progress + len(bline) self.no_of_frames = frame + 1 - def get_frames(self, frames="all", override=False, **kwargs): - """Extract frames from the trajectory file. - - Depending on the passed parameters a frame, a list of particular - frames, a range of frames (from, to), or all frames can be extracted - with this function. - - Parameters - ---------- - frames : :class:`int` or :class:`list` or :class:`touple` or :class:`str` - Specified frame (:class:`int`), or frames (:class:`list`), or - range (:class:`touple`), or `all`/`everything` (:class:`str`). - (default=`all`) - - override : :class:`bool` - If True, a frame already storred in :attr:`frames` can be override. - (default=False) - - extract_data : :class:`bool`, optional - If False, a frame is returned as a :class:`str` block as in the - trajectory file. Ohterwise, it is extracted and returned as - :class:`pywindow.molecular.MolecularSystem`. (default=True) - - swap_atoms : :class:`dict`, optional - If this kwarg is passed with an appropriate dictionary a - :func:`pywindow.molecular.MolecularSystem.swap_atom_keys()` will - be applied to the extracted frame. - - forcefield : :class:`str`, optional - If this kwarg is passed with appropriate forcefield keyword a - :func:`pywindow.molecular.MolecularSystem.decipher_atom_keys()` - will be applied to the extracted frame. - - Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` - If a single frame is extracted. - - None : :class:`NoneType` - If more than one frame is extracted, the frames are returned to - :attr:`frames` - - """ - if override is True: - self.frames = {} - if isinstance(frames, int): - frame = self._get_frame( - self.trajectory_map[frames], frames, **kwargs - ) - if frames not in self.frames.keys(): - self.frames[frames] = frame - return frame - if isinstance(frames, list): - for frame in frames: - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) - - def _get_frame(self, frame_coordinates, frame_no, **kwargs): - kwargs_ = { - "extract_data": True, - } - kwargs_.update(kwargs) - start, end = frame_coordinates - with open(self.filepath) as trajectory_file: - with closing( - mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) - ) as mapped_file: - if kwargs_["extract_data"] is False: - return mapped_file[start:end].decode("utf-8") - # [:-1] because the split results in last list empty. - frame = [ - i.split() - for i in mapped_file[start:end].decode("utf-8").split("\n") - ][:-1] - decoded_frame = self._decode_frame(frame) - molsys = MolecularSystem.load_system( - decoded_frame, "_".join([self.system_id, str(frame_no)]) - ) - if "swap_atoms" in kwargs: - molsys.swap_atom_keys(kwargs["swap_atoms"]) - if "forcefield" in kwargs: - molsys.decipher_atom_keys(kwargs["forcefield"]) - return molsys - - def _decode_frame(self, frame): + def _decode_frame(self, frame: list) -> dict: # type: ignore[type-arg] frame_data = { "frame_info": { "natms": int(frame[0][0]), @@ -937,338 +926,57 @@ def _decode_frame(self, frame): for i in range(start_line, len(frame)): elements.append(frame[i][0]) coordinates.append(frame[i][1:]) - frame_data["atom_ids"] = np.array(elements) - frame_data["coordinates"] = np.array(coordinates, dtype=float) + frame_data["atom_ids"] = np.array(elements) # type: ignore[assignment] + frame_data["coordinates"] = np.array(coordinates, dtype=float) # type: ignore[assignment] return frame_data - def analysis(self, frames="all", ncpus=1, override=False, **kwargs): - """Perform structural analysis on a frame/ set of frames. - - Depending on the passed parameters a frame, a list of particular - frames, a range of frames (from, to), or all frames can be analysed - with this function. - - The analysis is performed on each frame and each discrete molecule in - that frame separately. The steps are as follows: - 1. A frame is extracted and returned as a :class:`MolecularSystem`. - 2. If `swap_atoms` is set the atom ids are swapped. - 3. If `forcefield` is set the atom ids are deciphered. - 4. If `rebuild` is set the molecules in the system are rebuild. - 5. Each discrete molecule is extracted as :class:`Molecule` - 6. Each molecule is analysed with :func:`Molecule.full_analysis()` - 7. Analysis output populates the :attr:`analysis_output` dictionary. - - As the analysis of trajectories often have to be unique, many options - are conditional. - - A side effect of this function is that the analysed frames are also - returned to the :attr:`frames` mimicking the behaviour of the - :func:`get_frames()`. - - Parameters - ---------- - frames : :class:`int` or :class:`list` or :class:`touple` or :class:`str` - Specified frame (:class:`int`), or frames (:class:`list`), or - range (:class:`touple`), or `all`/`everything` (:class:`str`). - (default='all') - - override : :class:`bool` - If True, an output already storred in :attr:`analysis_output` can - be override. (default=False) - - swap_atoms : :class:`dict`, optional - If this kwarg is passed with an appropriate dictionary a - :func:`pywindow.molecular.MolecularSystem.swap_atom_keys()` will - be applied to the extracted frame. - - forcefield : :class:`str`, optional - If this kwarg is passed with appropriate forcefield keyword a - :func:`pywindow.molecular.MolecularSystem.decipher_atom_keys()` - will be applied to the extracted frame. - - modular : :class:`bool`, optional - If this kwarg is passed a - :func:`pywindow.molecular.MolecularSystem.make_modular()` - will be applied to the extracted frame. (default=False) - - rebuild : :class:`bool`, optional - If this kwarg is passed a `rebuild=True` is passed to - :func:`pywindow.molecular.MolecularSystem.make_modular()` that - will be applied to the extracted frame. (default=False) - - ncpus : :class:`int`, optional - If ncpus > 1, then the analysis is performed in parallel for the - specified number of parallel jobs. Otherwise, it runs in serial. - (default=1) - - Returns: - ------- - None : :class:`NoneType` - The function returns `None`, the analysis output is - returned to :attr:`analysis_output` dictionary. - - """ - if override is True: - self.analysis_output = {} - if isinstance(frames, int): - analysed_frame = self._analysis_serial(frames, ncpus, **kwargs) - if frames not in self.analysis_output.keys(): - self.analysis_output[frames] = analysed_frame - return analysed_frame - frames_for_analysis = [] - if isinstance(frames, list): - for frame in frames: - if frame not in self.analysis_output.keys(): - frames_for_analysis.append(frame) - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - if frame not in self.analysis_output.keys(): - frames_for_analysis.append(frame) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - if frame not in self.analysis_output.keys(): - frames_for_analysis.append(frame) - self._analysis_parallel(frames_for_analysis, ncpus, **kwargs) - - def _analysis_serial(self, frame, ncpus, **kwargs): - settings = { - "rebuild": False, - "modular": False, - } - settings.update(kwargs) - molecular_system = self._get_frame( - self.trajectory_map[frame], frame, extract_data=True, **kwargs - ) - if settings["modular"] is True: - molecular_system.make_modular(rebuild=settings["rebuild"]) - molecules = molecular_system.molecules - else: - molecules = {"0": molecular_system.system_to_molecule()} - results = {} - for molecule in molecules: - mol = molecules[molecule] - if "molsize" in settings: - molsize = settings["molsize"] - if isinstance(molsize, int): - if mol.no_of_atoms == molsize: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if isinstance(molsize, tuple) and isinstance(molsize[0], str): - if molsize[0] in ["bigger", "greater", "larger", "more"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["smaller", "less"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["not", "isnot", "notequal", "different"]: - if mol.no_of_atoms != molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["is", "equal", "exactly"]: - if mol.no_of_atoms == molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["between", "inbetween"]: - if molsize[1] < mol.no_of_atoms < molsize[2]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - else: - results[molecule] = mol.full_analysis(ncpus=ncpus, **kwargs) - return results - - def _analysis_parallel_execute(self, frame, **kwargs): - settings = { - "rebuild": False, - "modular": False, - } - settings.update(kwargs) - molecular_system = self._get_frame( - self.trajectory_map[frame], frame, extract_data=True, **kwargs - ) - if settings["modular"] is True: - molecular_system.make_modular(rebuild=settings["rebuild"]) - molecules = molecular_system.molecules - else: - molecules = {"0": molecular_system.system_to_molecule()} - results = {} - for molecule in molecules: - mol = molecules[molecule] - if "molsize" in settings: - molsize = settings["molsize"] - if isinstance(molsize, int): - if mol.no_of_atoms == molsize: - results[molecule] = mol.full_analysis(**kwargs) - if isinstance(molsize, tuple) and isinstance(molsize[0], str): - if molsize[0] in ["bigger", "greater", "larger", "more"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["smaller", "less"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["not", "isnot", "notequal", "different"]: - if mol.no_of_atoms != molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["is", "equal", "exactly"]: - if mol.no_of_atoms == molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["between", "inbetween"]: - if molsize[1] < mol.no_of_atoms < molsize[2]: - results[molecule] = mol.full_analysis(**kwargs) - else: - results[molecule] = mol.full_analysis(**kwargs) - return frame, results - - def _analysis_parallel(self, frames, ncpus, **kwargs): - try: - pool = Pool(processes=ncpus) - parallel = [ - pool.apply_async( - self._analysis_parallel_execute, args=(frame,), kwds=kwargs - ) - for frame in frames - ] - results = [p.get() for p in parallel if p.get()[1] is not None] - pool.terminate() - for i in results: - self.analysis_output[i[0]] = i[1] - except TypeError: - pool.terminate() - raise _ParallelAnalysisError("Parallel analysis failed.") - - def save_analysis(self, filepath=None, **kwargs): - """Dump the content of :attr:`analysis_output` as JSON dictionary. - - Parameters - ---------- - filepath : :class:`str` - The filepath for the JSON file. - - Returns: - ------- - None : :class:`NoneType` - """ - # We pass a copy of the analysis attribute dictionary. - dict_obj = deepcopy(self.analysis_output) - # If no filepath is provided we create one. - if filepath is None: - filepath = "_".join((str(self.system_id), "pywindow_analysis")) - filepath = "/".join((os.getcwd(), filepath)) - # Dump the dictionary to json file. - Output().dump2json(dict_obj, filepath, default=to_list, **kwargs) - - def save_frames(self, frames, filepath=None, filetype="pdb", **kwargs): - settings = { - "pdb": Output()._save_pdb, - "xyz": Output()._save_xyz, - "decipher": True, - "forcefield": None, - } - settings.update(kwargs) - if filetype.lower() not in settings: - raise _FormatError( - f"The '{filetype}' file format is not supported" - ) - frames_to_get = [] - if isinstance(frames, int): - frames_to_get.append(frames) - if isinstance(frames, list): - frames_to_get = frames - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - frames_to_get.append(frame) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - frames_to_get.append(frame) - for frame in frames_to_get: - if frame not in self.frames.keys(): - _ = self.get_frames(frame) - # If no filepath is provided we create one. - if filepath is None: - filepath = "/".join((os.getcwd(), str(self.system_id))) - for frame in frames_to_get: - frame_molsys = self.frames[frame] - if ( - settings["decipher"] is True - and settings["forcefield"] is not None - ): - if "swap_atoms" in settings: - if isinstance(settings["swap_atoms"], dict): - frame_molsys.swap_atom_keys(settings["swap_atoms"]) - else: - raise _FunctionError( - "The swap_atom_keys function only accepts " - "'swap_atoms' argument in form of a dictionary." - ) - frame_molsys.decipher_atom_keys(settings["forcefield"]) - ffilepath = "_".join((filepath, str(frame))) - if "elements" not in frame_molsys.system.keys(): - raise _FunctionError( - "The frame (MolecularSystem object) needs to have " - "'elements' attribute within the system dictionary. " - "It is, therefore, neccessary that you set a decipher " - "keyword to True. (see manual)" - ) - settings[filetype.lower()]( - frame_molsys.system, ffilepath, **kwargs - ) - - -class PDB: - def __init__(self, filepath): +class PDB(Trajectory): + def __init__(self, filepath: pathlib.Path | str) -> None: """A container for an PDB type trajectory. This function takes an PDB trajectory file and maps it for the binary points in the file where each frame starts/ends. This way the process is fast, as it not require loading the trajectory into computer - memory. When a frame is being extracted, it is only this frame that gets - loaded to the memory. + memory. When a frame is being extracted, it is only this frame that + gets loaded to the memory. Frames can be accessed individually and loaded as an unmodified string, - returned as a :class:`pywindow.molecular.MolecularSystem` (and analysed), - dumped as PDB or XYZ or JSON (if dumped as a - :attr:`pywindow.molecular.MolecularSystem.system`) + returned as a :class:`pywindow.MolecularSystem` + (and analysed), dumped as PDB or XYZ or JSON (if dumped as a + :attr:`pywindow.MolecularSystem.system`) Attributes: - ---------- - filepath : :class:`str` - The filepath. + filepath: + The filepath. - filename : :class:`str` - The filename. + filename: + The filename. - system_id : :class:`str` - The system id inherited from the filename. + system_id: + The system id inherited from the filename. - frames : :class:`dict` - A dictionary that is populated, on the fly, with the extracted frames. + frames: + A dictionary that is populated, on the fly, with the extracted + frames. - analysis_output : :class:`dict` - A dictionary that is populated, on the fly, with the analysis output. + analysis_output: + A dictionary that is populated, on the fly, with the analysis + output. """ - self.filepath = filepath - self.filename = os.path.basename(filepath) + self.filepath = pathlib.Path(filepath) + self.filename = self.filepath.name self.system_id = self.filename.split(".")[0] - self.frames = {} - self.analysis_output = {} + self.frames: dict = {} # type: ignore[type-arg] + self.analysis_output: dict = {} # type: ignore[type-arg] # Map the trajectory file at init. self._map_trajectory() - def _map_trajectory(self): - """Return filepath as a class attribute""" + def _map_trajectory(self) -> None: + """Map pdb trajectory.""" self.trajectory_map = {} - with open(self.filepath) as trajectory_file: + with self.filepath.open() as trajectory_file: with closing( mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) ) as mapped_file: @@ -1284,7 +992,7 @@ def _map_trajectory(self): # We reached end of the file but still add the last frame! if len(bline) == 0: frame = frame + 1 - if progress - frame_start > 10: + if progress - frame_start > 10: # noqa: PLR2004 self.trajectory_map[frame] = [ frame_start, progress, @@ -1302,109 +1010,15 @@ def _map_trajectory(self): progress = progress + len(bline) self.no_of_frames = frame - def get_frames(self, frames="all", override=False, **kwargs): - """Extract frames from the trajectory file. - - Depending on the passed parameters a frame, a list of particular - frames, a range of frames (from, to), or all frames can be extracted - with this function. - - Parameters - ---------- - frames : :class:`int` or :class:`list` or :class:`touple` or :class:`str` - Specified frame (:class:`int`), or frames (:class:`list`), or - range (:class:`touple`), or `all`/`everything` (:class:`str`). - (default=`all`) - - override : :class:`bool` - If True, a frame already storred in :attr:`frames` can be override. - (default=False) - - extract_data : :class:`bool`, optional - If False, a frame is returned as a :class:`str` block as in the - trajectory file. Ohterwise, it is extracted and returned as - :class:`pywindow.molecular.MolecularSystem`. (default=True) - - swap_atoms : :class:`dict`, optional - If this kwarg is passed with an appropriate dictionary a - :func:`pywindow.molecular.MolecularSystem.swap_atom_keys()` will - be applied to the extracted frame. - - forcefield : :class:`str`, optional - If this kwarg is passed with appropriate forcefield keyword a - :func:`pywindow.molecular.MolecularSystem.decipher_atom_keys()` - will be applied to the extracted frame. - - Returns: - ------- - :class:`pywindow.molecular.MolecularSystem` - If a single frame is extracted. - - None : :class:`NoneType` - If more than one frame is extracted, the frames are returned to - :attr:`frames` - - """ - if override is True: - self.frames = {} - if isinstance(frames, int): - frame = self._get_frame( - self.trajectory_map[frames], frames, **kwargs - ) - if frames not in self.frames.keys(): - self.frames[frames] = frame - return frame - if isinstance(frames, list): - for frame in frames: - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - if frame not in self.frames.keys(): - self.frames[frame] = self._get_frame( - self.trajectory_map[frame], frame, **kwargs - ) - - def _get_frame(self, frame_coordinates, frame_no, **kwargs): - kwargs_ = {"extract_data": True} - kwargs_.update(kwargs) - start, end = frame_coordinates - with open(self.filepath) as trajectory_file: - with closing( - mmap(trajectory_file.fileno(), 0, access=ACCESS_READ) - ) as mapped_file: - if kwargs_["extract_data"] is False: - return mapped_file[start:end].decode("utf-8") - # In case of PDB we do not split lines! - frame = mapped_file[start:end].decode("utf-8").split("\n") - decoded_frame = self._decode_frame(frame) - molsys = MolecularSystem.load_system( - decoded_frame, "_".join([self.system_id, str(frame_no)]) - ) - if "swap_atoms" in kwargs: - molsys.swap_atom_keys(kwargs["swap_atoms"]) - if "forcefield" in kwargs: - molsys.decipher_atom_keys(kwargs["forcefield"]) - return molsys - - def _decode_frame(self, frame): - frame_data = {} + def _decode_frame(self, frame: list) -> dict: # type: ignore[type-arg] + frame_data = {} # type: ignore[var-annotated] elements = [] coordinates = [] for i in range(len(frame)): if frame[i][:6] == "REMARK": if "REMARKS" not in frame_data: - frame_data["REMARKS"] = [] - frame_data["REMARKS"].append(frame[i][6:]) + frame_data["REMARKS"] = [] # type: ignore[assignment] + frame_data["REMARKS"].append(frame[i][6:]) # type: ignore[attr-defined] if frame[i][:6] == "CRYST1": cryst = np.array( [ @@ -1429,285 +1043,3 @@ def _decode_frame(self, frame): frame_data["atom_ids"] = np.array(elements, dtype=" 1, then the analysis is performed in parallel for the - specified number of parallel jobs. Otherwise, it runs in serial. - (default=1) - - Returns: - ------- - None : :class:`NoneType` - The function returns `None`, the analysis output is - returned to :attr:`analysis_output` dictionary. - - """ - if override is True: - self.analysis_output = {} - if isinstance(frames, int): - analysed_frame = self._analysis_serial(frames, ncpus, **kwargs) - if frames not in self.analysis_output.keys(): - self.analysis_output[frames] = analysed_frame - return analysed_frame - frames_for_analysis = [] - if isinstance(frames, list): - for frame in frames: - if frame not in self.analysis_output.keys(): - frames_for_analysis.append(frame) - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - if frame not in self.analysis_output.keys(): - frames_for_analysis.append(frame) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - if frame not in self.analysis_output.keys(): - frames_for_analysis.append(frame) - self._analysis_parallel(frames_for_analysis, ncpus, **kwargs) - - def _analysis_serial(self, frame, ncpus, **kwargs): - settings = { - "rebuild": False, - "modular": False, - } - settings.update(kwargs) - molecular_system = self._get_frame( - self.trajectory_map[frame], frame, extract_data=True, **kwargs - ) - if settings["modular"] is True: - molecular_system.make_modular(rebuild=settings["rebuild"]) - molecules = molecular_system.molecules - else: - molecules = {"0": molecular_system.system_to_molecule()} - results = {} - for molecule in molecules: - mol = molecules[molecule] - if "molsize" in settings: - molsize = settings["molsize"] - if isinstance(molsize, int): - if mol.no_of_atoms == molsize: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if isinstance(molsize, tuple) and isinstance(molsize[0], str): - if molsize[0] in ["bigger", "greater", "larger", "more"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["smaller", "less"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["not", "isnot", "notequal", "different"]: - if mol.no_of_atoms != molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["is", "equal", "exactly"]: - if mol.no_of_atoms == molsize[1]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - if molsize[0] in ["between", "inbetween"]: - if molsize[1] < mol.no_of_atoms < molsize[2]: - results[molecule] = mol.full_analysis( - ncpus=ncpus, **kwargs - ) - else: - results[molecule] = mol.full_analysis(ncpus=ncpus, **kwargs) - return results - - def _analysis_parallel_execute(self, frame, **kwargs): - settings = { - "rebuild": False, - "modular": False, - } - settings.update(kwargs) - molecular_system = self._get_frame( - self.trajectory_map[frame], frame, extract_data=True, **kwargs - ) - if settings["modular"] is True: - molecular_system.make_modular(rebuild=settings["rebuild"]) - molecules = molecular_system.molecules - else: - molecules = {"0": molecular_system.system_to_molecule()} - results = {} - for molecule in molecules: - mol = molecules[molecule] - if "molsize" in settings: - molsize = settings["molsize"] - if isinstance(molsize, int): - if mol.no_of_atoms == molsize: - results[molecule] = mol.full_analysis(**kwargs) - if isinstance(molsize, tuple) and isinstance(molsize[0], str): - if molsize[0] in ["bigger", "greater", "larger", "more"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["smaller", "less"]: - if mol.no_of_atoms > molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["not", "isnot", "notequal", "different"]: - if mol.no_of_atoms != molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["is", "equal", "exactly"]: - if mol.no_of_atoms == molsize[1]: - results[molecule] = mol.full_analysis(**kwargs) - if molsize[0] in ["between", "inbetween"]: - if molsize[1] < mol.no_of_atoms < molsize[2]: - results[molecule] = mol.full_analysis(**kwargs) - else: - results[molecule] = mol.full_analysis(**kwargs) - return frame, results - - def _analysis_parallel(self, frames, ncpus, **kwargs): - try: - pool = Pool(processes=ncpus) - parallel = [ - pool.apply_async( - self._analysis_parallel_execute, args=(frame,), kwds=kwargs - ) - for frame in frames - ] - results = [p.get() for p in parallel if p.get()[1] is not None] - pool.terminate() - for i in results: - self.analysis_output[i[0]] = i[1] - except TypeError: - pool.terminate() - raise _ParallelAnalysisError("Parallel analysis failed.") - - def save_analysis(self, filepath=None, **kwargs): - """Dump the content of :attr:`analysis_output` as JSON dictionary. - - Parameters - ---------- - filepath : :class:`str` - The filepath for the JSON file. - - Returns: - ------- - None : :class:`NoneType` - """ - # We pass a copy of the analysis attribute dictionary. - dict_obj = deepcopy(self.analysis_output) - # If no filepath is provided we create one. - if filepath is None: - filepath = "_".join((str(self.system_id), "pywindow_analysis")) - filepath = "/".join((os.getcwd(), filepath)) - # Dump the dictionary to json file. - Output().dump2json(dict_obj, filepath, default=to_list, **kwargs) - - def save_frames(self, frames, filepath=None, filetype="pdb", **kwargs): - settings = { - "pdb": Output()._save_pdb, - "xyz": Output()._save_xyz, - "decipher": True, - "forcefield": None, - } - settings.update(kwargs) - if filetype.lower() not in settings: - raise _FormatError( - f"The '{filetype}' file format is not supported" - ) - frames_to_get = [] - if isinstance(frames, int): - frames_to_get.append(frames) - if isinstance(frames, list): - frames_to_get = frames - if isinstance(frames, tuple): - for frame in range(frames[0], frames[1]): - frames_to_get.append(frame) - if isinstance(frames, str): - if frames in ["all", "everything"]: - for frame in range(self.no_of_frames): - frames_to_get.append(frame) - for frame in frames_to_get: - if frame not in self.frames.keys(): - _ = self.get_frames(frame) - # If no filepath is provided we create one. - if filepath is None: - filepath = "/".join((os.getcwd(), str(self.system_id))) - for frame in frames_to_get: - frame_molsys = self.frames[frame] - if ( - settings["decipher"] is True - and settings["forcefield"] is not None - ): - if "swap_atoms" in settings: - if isinstance(settings["swap_atoms"], dict): - frame_molsys.swap_atom_keys(settings["swap_atoms"]) - else: - raise _FunctionError( - "The swap_atom_keys function only accepts " - "'swap_atoms' argument in form of a dictionary." - ) - frame_molsys.decipher_atom_keys(settings["forcefield"]) - ffilepath = "_".join((filepath, str(frame))) - if "elements" not in frame_molsys.system.keys(): - raise _FunctionError( - "The frame (MolecularSystem object) needs to have " - "'elements' attribute within the system dictionary. " - "It is, therefore, neccessary that you set a decipher " - "keyword to True. (see manual)" - ) - settings[filetype.lower()]( - frame_molsys.system, ffilepath, **kwargs - ) diff --git a/src/pywindow/_internal/utilities.py b/src/pywindow/_internal/utilities.py index e3bd782..b4bfc96 100644 --- a/src/pywindow/_internal/utilities.py +++ b/src/pywindow/_internal/utilities.py @@ -2,10 +2,13 @@ from __future__ import annotations +import contextlib from copy import deepcopy from multiprocessing import Pool import numpy as np +import numpy.typing as npt +from rdkit.Chem.inchi import logger from scipy.optimize import brute, fmin, minimize from sklearn.cluster import DBSCAN from sklearn.metrics.pairwise import euclidean_distances @@ -20,56 +23,42 @@ class _AtomKeyError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message -class _AtomKeyConflict(Exception): - def __init__(self, message): +class _AtomKeyConflictError(Exception): + def __init__(self, message: str) -> None: self.message = message class _ForceFieldError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message class _FunctionError(Exception): - def __init__(self, message): + def __init__(self, message: str) -> None: self.message = message -def is_number(number): - """Return True if an object is a number - can be converted into a float. - - Parameters - ---------- - number : any - - Returns: - ------- - bool - True if input is a float convertable (a number), False otherwise. - - """ +def is_number(number: str) -> bool: + """Return True if an object is a number - can be converted into a float.""" try: float(number) - return True except ValueError: return False + return True -def unique(input_list): +def unique(input_list: list) -> list: # type:ignore[type-arg] """Return a list of unique items (similar to set functionality). - Parameters - ---------- - input_list : list - A list containg some items that can occur more than once. + Parameters: + input_list : list + A list containg some items that can occur more than once. Returns: - ------- - list A list with only unique occurances of an item. """ @@ -80,60 +69,54 @@ def unique(input_list): return output -def to_list(obj): - """ """ - if isinstance(obj, np.ndarray): - return obj.tolist() - raise TypeError("Not serializable") +def to_list(obj: npt.NDArray[np.float64]) -> list[float]: + """Serialize np.array.""" + if isinstance(obj, np.ndarray): # type:ignore[type-arg] + return obj.tolist() # type:ignore[return-value] + msg = "Not serializable" # type:ignore[unreachable] + raise TypeError(msg) -def distance(a, b): +def distance(a: npt.NDArray[np.float64], b: npt.NDArray[np.float64]) -> float: """Return the distance between two vectors (points) a and b. - Parameters - ---------- - a : numpy.ndarray - First vector. - b : numpy.ndarray - Second vector. + Parameters: + a: + First vector. + b: + Second vector. Returns: - ------- - numpy.float64 A distance between two vectors (points). """ - return (np.sum((a - b) ** 2)) ** 0.5 + return float((np.sum((a - b) ** 2)) ** 0.5) -def molecular_weight(elements): +def molecular_weight(elements: npt.NDArray[np.str_]) -> float: """Return molecular weight of a molecule. - Parameters - ---------- - elements : numpy.ndarray - An array of all elements (type: str) in a molecule. + Parameters: + elements: + An array of all elements (type: str) in a molecule. Returns: - ------- - numpy.float64 A molecular weight of a molecule. """ - return np.array([atomic_mass[i.upper()] for i in elements]).sum() + return float(np.array([atomic_mass[i.upper()] for i in elements]).sum()) -def center_of_coor(coordinates): +def center_of_coor( + coordinates: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return the centre of coordinates. - Parameters - ---------- - coordinates : numpy.ndarray - An array containing molecule's coordinates. + Parameters: + coordinates: + An array containing molecule's coordinates. Returns: - ------- - numpy.ndarray An 1d array with coordinates of the centre of coordinates excluding elements' masses. @@ -141,20 +124,20 @@ def center_of_coor(coordinates): return np.sum(coordinates, axis=0) / coordinates.shape[0] -def center_of_mass(elements, coordinates): +def center_of_mass( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return the centre of mass (COM). - Parameters - ---------- - elements : numpy.ndarray - An array of all elements (type: str) in a molecule. + Parameters: + elements: + An array of all elements (type: str) in a molecule. - coordinates : numpy.ndarray - An array containing molecule's coordinates. + coordinates: + An array containing molecule's coordinates. Returns: - ------- - numpy.ndarray An 1d array with coordinates of the centre of mass including elements' masses. @@ -165,7 +148,10 @@ def center_of_mass(elements, coordinates): return np.sum(mass_coordinates, axis=0) / np.array([mass, mass, mass]) -def compose_atom_list(*args): +def compose_atom_list( + *args: tuple[list[str], list[npt.NDArray[np.float64]]] + | tuple[list[str], list[npt.NDArray[np.float64]], list[int]], +) -> list: # type:ignore[type-arg] """Return an `atom list` from elements and/or atom ids and coordinates. An `atom list` is a special object that some pywindowfunctions uses. @@ -178,30 +164,27 @@ def compose_atom_list(*args): They work better for molecular re-building than two separate arrays for elements and coordinates do. - Parameters - ---------- - elements : :class:`numpy.ndarray` - An array of all elements (type: str) in a molecule. + Parameters: + elements : :class:`numpy.ndarray` + An array of all elements (type: str) in a molecule. - coordinates : :class:`numpy.ndarray` - An array containing molecule's coordinates. + coordinates : :class:`numpy.ndarray` + An array containing molecule's coordinates. - atom_ids : :class:`numpy.ndarray`, optional - An array of all forcfield dependent atom keys (type:str) in a molecule. + atom_ids : :class:`numpy.ndarray`, optional + An array of all forcfield dependent atom keys (type:str) in a + molecule. Returns: - ------- - list Version 1 or version 2 atom list depending on input parameters. Raises: - ------ - _FunctionError : :class:`Exception` - Raised when wrong number of parameters is passed to the function. + _FunctionError : :class:`Exception` + Raised when wrong number of parameters is passed to the function. """ - if len(args) == 2: + if len(args) == 2: # noqa: PLR2004 atom_list = [ [ i[0], @@ -209,9 +192,9 @@ def compose_atom_list(*args): round(float(i[2]), 8), round(float(i[3]), 8), ] - for i in np.concatenate((args[0].reshape(-1, 1), args[1]), axis=1) + for i in np.concatenate((args[0].reshape(-1, 1), args[1]), axis=1) # type:ignore[union-attr, arg-type] ] - elif len(args) == 3: + elif len(args) == 3: # noqa: PLR2004 atom_list = [ [ i[0], @@ -221,9 +204,9 @@ def compose_atom_list(*args): round(float(i[4]), 8), ] for i in np.concatenate( - ( + ( # type:ignore[arg-type] np.concatenate( - (args[0].reshape(-1, 1), args[1].reshape(-1, 1)), + (args[0].reshape(-1, 1), args[1].reshape(-1, 1)), # type:ignore[union-attr] axis=1, ), args[2], @@ -232,13 +215,12 @@ def compose_atom_list(*args): ) ] else: - raise _FunctionError( - "The compose_atom_list() function accepts only 2 or 3 arguments." - ) + msg = "The compose_atom_list() function accepts only 2 or 3 arguments." + raise _FunctionError(msg) return atom_list -def decompose_atom_list(atom_list): +def decompose_atom_list(atom_list: list) -> tuple: # type:ignore[type-arg] """Return elements and/or atom ids and coordinates from an `atom list`. Depending on input type of an atom list (version 1 or 2) @@ -248,20 +230,17 @@ def decompose_atom_list(atom_list): the function reverses what pywindow.utilities.compose_atom_list() do. - Parameters - ---------- - atom_list : list - A nested list of lists (version 1 or 2) + Parameters: + atom_list: + A nested list of lists (version 1 or 2) Returns: - ------- - touple - A touple of elements and coordinates arrays, or if input contained + A tuple of elements and coordinates arrays, or if input contained atom ideas, also atom ids array. """ - transpose = list(zip(*atom_list)) - if len(transpose) == 4: + transpose = list(zip(*atom_list, strict=False)) + if len(transpose) == 4: # noqa: PLR2004 elements = np.array(transpose[0]) array_a = np.array(transpose[1]).reshape(-1, 1) array_b = np.array(transpose[2]).reshape(-1, 1) @@ -269,7 +248,7 @@ def decompose_atom_list(atom_list): array_ab = np.concatenate((array_a, array_b), axis=1) coordinates = np.concatenate((array_ab, array_c), axis=1) return elements, coordinates - if len(transpose) == 5: + if len(transpose) == 5: # noqa: PLR2004 elements = np.array(transpose[0]) atom_ids = np.array(transpose[1]) array_a = np.array(transpose[2]).reshape(-1, 1) @@ -278,13 +257,14 @@ def decompose_atom_list(atom_list): array_ab = np.concatenate((array_a, array_b), axis=1) coordinates = np.concatenate((array_ab, array_c), axis=1) return elements, atom_ids, coordinates - raise _FunctionError( + msg = ( "The decompose_atom_list() function accepts only list of lists " " with only 4 or 5 items per sublist." ) + raise _FunctionError(msg) -def dlf_notation(atom_key): +def dlf_notation(atom_key: str) -> str: """Return element for atom key using DL_F notation.""" split = list(atom_key) element = "" @@ -302,47 +282,43 @@ def dlf_notation(atom_key): # will not affect the functionality towards it. # EDIT2: also the '?' atoms, you can delete them manually or somewhere else element = "".join(i for i in element if not is_number(i)) - element = "".join(i for i in element if i != "?") - return element + return "".join(i for i in element if i != "?") -def opls_notation(atom_key): +def opls_notation(atom_key: str) -> str: """Return element for OPLS forcefield atom key.""" # warning for Ne, He, Na types overlap - conflicts = ["ne", "he", "na"] + conflicts = ("ne", "he", "na") if atom_key in conflicts: - raise _AtomKeyConflict( + msg = ( "One of the OPLS conflicting " f"atom_keys has occured '{atom_key}'. " "For how to solve this issue see the manual or " "MolecularSystem._atom_key_swap() doc string." ) + raise _AtomKeyConflictError(msg) for element in opls_atom_keys: if atom_key in opls_atom_keys[element]: return element # In case if atom_key was not found in the OPLS keys dictionary - raise _AtomKeyError( - f"OPLS atom key {atom_key} was not found in OPLS keys dictionary." - ) + msg = f"OPLS atom key {atom_key} was not found in OPLS keys dictionary." + raise _AtomKeyError(msg) -def decipher_atom_key(atom_key, forcefield): +def decipher_atom_key(atom_key: str, forcefield: str) -> str: """Return element for deciphered atom key. This functions checks if the forcfield specified by user is supported and passes the atom key to the appropriate function for deciphering. - Parameters - ---------- - atom_key : str - The atom key which is to be deciphered. + Parameters: + atom_key: + The atom key which is to be deciphered. - forcefield : str - The forcefield to which the atom key belongs to. + forcefield: + The forcefield to which the atom key belongs to. Returns: - ------- - str A string that is the periodic table element equvalent of forcefield atom key. @@ -357,52 +333,30 @@ def decipher_atom_key(atom_key, forcefield): } if forcefield.upper() in load_funcs: return load_funcs[forcefield.upper()](atom_key) - raise _ForceFieldError( - f"Unfortunetely, '{forcefield}' forcefield is not supported by pyWINDOW." - " For list of supported forcefields see User's Manual or " + msg = ( + f"Unfortunetely, '{forcefield}' forcefield is not supported by" + " pyWINDOW. For list of supported forcefields see User's Manual or " "MolecularSystem._decipher_atom_keys() function doc string." ) + raise _ForceFieldError(msg) -def shift_com(elements, coordinates, com_adjust=np.zeros(3)): - """Return coordinates translated by some vector. - - Parameters - ---------- - elements : numpy.ndarray - An array of all elements (type: str) in a molecule. - - coordinates : numpy.ndarray - An array containing molecule's coordinates. - - com_adjust : numpy.ndarray (default = [0, 0, 0]) - - Returns: - ------- - numpy.ndarray - Translated array of molecule's coordinates. - - """ +def shift_com( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], + com_adjust: npt.NDArray[np.float64] = np.zeros(3), # noqa: B008 +) -> np.ndarray: # type:ignore[type-arg] + """Return coordinates translated by some vector.""" com = center_of_mass(elements, coordinates) com = np.array([com - com_adjust] * coordinates.shape[0]) return coordinates - com -def max_dim(elements, coordinates): - """Return the maximum diameter of a molecule. - - Parameters - ---------- - elements : numpy.ndarray - An array of all elements (type: str) in a molecule. - - coordinates : numpy.ndarray - An array containing molecule's coordinates. - - Returns: - ------- - - """ +def max_dim( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> tuple[int, int, float]: + """Return the maximum diameter of a molecule.""" atom_vdw_vertical = np.matrix( [[atomic_vdw_radius[i.upper()]] for i in elements] ) @@ -415,10 +369,14 @@ def max_dim(elements, coordinates): final_matrix = np.triu(re_dist_matrix) i1, i2 = np.unravel_index(final_matrix.argmax(), final_matrix.shape) maxdim = final_matrix[i1, i2] - return i1, i2, maxdim + return int(i1), int(i2), float(maxdim) -def pore_diameter(elements, coordinates, com=None): +def pore_diameter( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], + com: npt.NDArray[np.float64] | None = None, +) -> tuple[float, int]: """Return pore diameter of a molecule.""" if com is None: com = center_of_mass(elements, coordinates) @@ -427,16 +385,27 @@ def pore_diameter(elements, coordinates, com=None): re_dist_matrix = dist_matrix - atom_vdw index = np.argmin(re_dist_matrix) pored = re_dist_matrix[index][0] * 2 - return (pored, index) + return (float(pored), int(index)) -def correct_pore_diameter(com, *params): +def correct_pore_diameter( + com: npt.NDArray[np.float64], + *params: tuple[list[str], npt.NDArray[np.float64]], +) -> float: """Return negative of a pore diameter. (optimisation function).""" elements, coordinates = params - return -pore_diameter(elements, coordinates, com)[0] - - -def opt_pore_diameter(elements, coordinates, bounds=None, com=None, **kwargs): + return -pore_diameter(elements, coordinates, com)[0] # type:ignore[arg-type] + + +def opt_pore_diameter( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], + bounds: None + | tuple[ + tuple[float, float], tuple[float, float], tuple[float, float] + ] = None, + com: npt.NDArray[np.float64] | None = None, +) -> tuple[float, int, npt.NDArray[np.float64]]: """Return optimised pore diameter and it's COM.""" args = elements, coordinates if com is not None: @@ -457,32 +426,42 @@ def opt_pore_diameter(elements, coordinates, bounds=None, com=None, **kwargs): return (pored[0], pored[1], minimisation.x) -def sphere_volume(sphere_radius): +def sphere_volume(sphere_radius: float) -> float: """Return volume of a sphere.""" - return 4 / 3 * np.pi * sphere_radius**3 + return float(4 / 3 * np.pi * sphere_radius**3) -def asphericity(S): - return S[0] - (S[1] + S[2]) / 2 +def asphericity(shap: npt.NDArray[np.float64]) -> float: + return shap[0] - (shap[1] + shap[2]) / 2 -def acylidricity(S): - return S[1] - S[2] +def acylidricity(shap: npt.NDArray[np.float64]) -> float: + return shap[1] - shap[2] -def relative_shape_anisotropy(S): +def relative_shape_anisotropy(shap: npt.NDArray[np.float64]) -> float: return 1 - 3 * ( - (S[0] * S[1] + S[0] * S[2] + S[1] * S[2]) / (np.sum(S)) ** 2 + (shap[0] * shap[1] + shap[0] * shap[2] + shap[1] * shap[2]) + / (np.sum(shap)) ** 2 ) -def get_tensor_eigenvalues(T, sort=False): +def get_tensor_eigenvalues( + arr: npt.NDArray[np.float64], + sort: bool = False, # noqa: FBT001, FBT002 +) -> np.ndarray: # type:ignore[type-arg] if sort: - return sorted(np.linalg.eigvals(T), reverse=True) - return np.linalg.eigvals(T) + return np.array( + sorted(np.linalg.eigvals(arr), reverse=True), # type:ignore[type-var] + dtype=np.float64, + ) + return np.linalg.eigvals(arr) # type:ignore[return-value] -def get_gyration_tensor(elements, coordinates): +def get_gyration_tensor( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return the gyration tensor of a molecule. The gyration tensor should be invariant to the molecule's position. @@ -490,22 +469,19 @@ def get_gyration_tensor(elements, coordinates): centre of mass of the molecule, therefore, the coordinates are first corrected for the centre of mass and essentially shifted to the origin. - Parameters - ---------- - elements : numpy.ndarray - The array containing the molecule's elemental data. + Parameters: + elements: + The array containing the molecule's elemental data. - coordinates : numpy.ndarray - The array containing the Cartesian coordinates of the molecule. + coordinates: + The array containing the Cartesian coordinates of the molecule. Returns: - ------- - numpy.ndarray The gyration tensor of a molecule invariant to the molecule's position. """ # First calculate COM for correction. - com = centre_of_mass(elements, coordinates) + com = center_of_mass(elements, coordinates) # Correct the coordinates for the COM. coordinates = coordinates - com # Calculate diagonal and then other values of the matrix. @@ -513,27 +489,26 @@ def get_gyration_tensor(elements, coordinates): xy = np.sum(coordinates[:, 0] * coordinates[:, 1]) xz = np.sum(coordinates[:, 0] * coordinates[:, 2]) yz = np.sum(coordinates[:, 1] * coordinates[:, 2]) - S = ( + return ( np.array([[diag[0], xy, xz], [xy, diag[1], yz], [xz, yz, diag[2]]]) / coordinates.shape[0] ) - return S -def get_inertia_tensor(elements, coordinates): +def get_inertia_tensor( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return the tensor of inertia a molecule. - Parameters - ---------- - elements : numpy.ndarray - The array containing the molecule's elemental data. + Parameters: + elements: + The array containing the molecule's elemental data. - coordinates : numpy.ndarray - The array containing the Cartesian coordinates of the molecule. + coordinates: + The array containing the Cartesian coordinates of the molecule. Returns: - ------- - numpy.ndarray The tensor of inertia of a molecule. """ @@ -548,30 +523,31 @@ def get_inertia_tensor(elements, coordinates): mxz = np.sum(-molecular_weight * coordinates[:, 0] * coordinates[:, 2]) myz = np.sum(-molecular_weight * coordinates[:, 1] * coordinates[:, 2]) - inertia_tensor = ( + return ( np.array([[diag_1, mxy, mxz], [mxy, diag_2, myz], [mxz, myz, diag_3]]) / coordinates.shape[0] ) - return inertia_tensor -def principal_axes(elements, coordinates): +def principal_axes( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] return np.linalg.eig(get_inertia_tensor(elements, coordinates))[1].T -def normalize_vector(vector): +def normalize_vector( + vector: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Normalize a vector. A new vector is returned, the original vector is not modified. - Parameters - ---------- - vector : np.array - The vector to be normalized. + Parameters: + vector: + The vector to be normalized. Returns: - ------- - np.array The normalized vector. """ @@ -579,21 +555,21 @@ def normalize_vector(vector): return np.round(v, decimals=4) -def rotation_matrix_arbitrary_axis(angle, axis): +def rotation_matrix_arbitrary_axis( + angle: float, + axis: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return a rotation matrix of `angle` radians about `axis`. - Parameters - ---------- - angle : int or float - The size of the rotation in radians. + Parameters: + angle: + The size of the rotation in radians. - axis : numpy.array - A 3 element aray which represents a vector. The vector is the - axis about which the rotation is carried out. + axis: + A 3 element aray which represents a vector. The vector is the + axis about which the rotation is carried out. Returns: - ------- - numpy.array A 3x3 array representing a rotation matrix. """ @@ -617,12 +593,16 @@ def rotation_matrix_arbitrary_axis(angle, axis): return np.array([[e11, e12, e13], [e21, e22, e23], [e31, e32, e33]]) -def align_principal_ax(elements, coordinates): - """ """ +def align_principal_ax( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> tuple[npt.NDArray[np.float64], list[np.matrix]]: # type: ignore[type-arg] coor = deepcopy(coordinates) new_coor = [] rot = [] - for i, j in zip([2, 1, 0], [[1, 0, 0], [0, 1, 0], [0, 0, 1]]): + for i, j in zip( + [2, 1, 0], [[1, 0, 0], [0, 1, 0], [0, 0, 1]], strict=False + ): p_axes = principal_axes(elements, coordinates) r_vec = np.cross(p_axes[i], np.array(j)) @@ -630,37 +610,49 @@ def align_principal_ax(elements, coordinates): cos = np.dot(p_axes[i], np.array(j)) ang = np.arctan2(sin, cos) - R_mat = np.matrix(rotation_matrix_arbitrary_axis(ang, r_vec)) - rot.append(R_mat) + r_mat = np.matrix(rotation_matrix_arbitrary_axis(ang, r_vec)) + rot.append(r_mat) - for i in coor: - new_coord = R_mat * i.reshape(-1, 1) + for i in coor: # noqa: PLW2901 + new_coord = r_mat * i.reshape(-1, 1) # type:ignore[attr-defined] new_coor.append(np.array(new_coord.reshape(1, -1))[0]) - new_coor = np.array(new_coor) - coor = new_coor + new_coor = np.array(new_coor) # type:ignore[assignment] + coor = new_coor # type:ignore[assignment] new_coor = [] + # What is matrix in numpy typing? return (coor, rot) -def calc_asphericity(elements, coordinates): +def calc_asphericity( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> float: inertia_tensor = get_inertia_tensor(elements, coordinates) tensor_eigenvalues = get_tensor_eigenvalues(inertia_tensor, sort=True) return asphericity(tensor_eigenvalues) -def calc_acylidricity(elements, coordinates): +def calc_acylidricity( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> float: inertia_tensor = get_inertia_tensor(elements, coordinates) tensor_eigenvalues = get_tensor_eigenvalues(inertia_tensor, sort=True) return acylidricity(tensor_eigenvalues) -def calc_relative_shape_anisotropy(elements, coordinates): +def calc_relative_shape_anisotropy( + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], +) -> float: inertia_tensor = get_inertia_tensor(elements, coordinates) tensor_eigenvalues = get_tensor_eigenvalues(inertia_tensor, sort=True) return relative_shape_anisotropy(tensor_eigenvalues) -def unit_cell_to_lattice_array(cryst): +def unit_cell_to_lattice_array( + cryst: list[float] | npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return parallelpiped unit cell lattice matrix.""" a_, b_, c_, alpha, beta, gamma = cryst # Convert angles from degrees to radians. @@ -695,13 +687,12 @@ def unit_cell_to_lattice_array(cryst): c_x = 0 c_y = 0 c_z = volume / (a_ * b_ * np.sin(r_gamma)) - lattice_array = np.array( - [[a_x, a_y, a_z], [b_x, b_y, b_z], [c_x, c_y, c_z]] - ) - return lattice_array + return np.array([[a_x, a_y, a_z], [b_x, b_y, b_z], [c_x, c_y, c_z]]) -def lattice_array_to_unit_cell(lattice_array): +def lattice_array_to_unit_cell( + lattice_array: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return crystallographic param. from unit cell lattice matrix.""" cell_lengths = np.sqrt(np.sum(lattice_array**2, axis=0)) gamma_r = np.arccos(lattice_array[0][1] / cell_lengths[1]) @@ -718,31 +709,40 @@ def lattice_array_to_unit_cell(lattice_array): return np.append(cell_lengths, cell_angles) -def volume_from_lattice_array(lattice_array): +def volume_from_lattice_array(lattice_array: npt.NDArray[np.float64]) -> float: """Return unit cell's volume from lattice matrix.""" return np.linalg.det(lattice_array) -def volume_from_cell_parameters(cryst): +def volume_from_cell_parameters(cryst: list[float]) -> float: """Return unit cell's volume from crystallographic parameters.""" return volume_from_lattice_array(unit_cell_to_lattice_array(cryst)) -def fractional_from_cartesian(coordinate, lattice_array): +def fractional_from_cartesian( + coordinate: npt.NDArray[np.float64], + lattice_array: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return a fractional coordinate from a cartesian one.""" - deorthogonalisation_M = np.matrix(np.linalg.inv(lattice_array)) - fractional = deorthogonalisation_M * coordinate.reshape(-1, 1) + deorthogonalisation_m = np.matrix(np.linalg.inv(lattice_array)) + fractional = deorthogonalisation_m * coordinate.reshape(-1, 1) return np.array(fractional.reshape(1, -1)) -def cartisian_from_fractional(coordinate, lattice_array): +def cartisian_from_fractional( + coordinate: npt.NDArray[np.float64], + lattice_array: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Return cartesian coordinate from a fractional one.""" - orthogonalisation_M = np.matrix(lattice_array) - orthogonal = orthogonalisation_M * coordinate.reshape(-1, 1) + orthogonalisation_m = np.matrix(lattice_array) + orthogonal = orthogonalisation_m * coordinate.reshape(-1, 1) return np.array(orthogonal.reshape(1, -1)) -def cart2frac_all(coordinates, lattice_array): +def cart2frac_all( + coordinates: npt.NDArray[np.float64], + lattice_array: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Convert all cartesian coordinates to fractional.""" frac_coordinates = deepcopy(coordinates) for coord in range(frac_coordinates.shape[0]): @@ -752,7 +752,10 @@ def cart2frac_all(coordinates, lattice_array): return frac_coordinates -def frac2cart_all(frac_coordinates, lattice_array): +def frac2cart_all( + frac_coordinates: npt.NDArray[np.float64], + lattice_array: npt.NDArray[np.float64], +) -> np.ndarray: # type:ignore[type-arg] """Convert all fractional coordinates to cartesian.""" coordinates = deepcopy(frac_coordinates) for coord in range(coordinates.shape[0]): @@ -762,17 +765,22 @@ def frac2cart_all(frac_coordinates, lattice_array): return coordinates -def create_supercell(system, supercell=[[-1, 1], [-1, 1], [-1, 1]]): +def create_supercell( + system: dict, # type: ignore[type-arg] + supercell: list[list[float]] | None = None, +) -> dict: # type:ignore[type-arg] """Create a supercell.""" - if "lattice" not in system.keys(): + if supercell is None: + supercell = [[-1, 1], [-1, 1], [-1, 1]] + if "lattice" not in system: matrix = unit_cell_to_lattice_array(system["unit_cell"]) else: matrix = system["lattice"] coordinates = deepcopy(system["coordinates"]) multiplication_matrices = [] - for a_ in range(supercell[0][0], supercell[0][1] + 1): - for b_ in range(supercell[1][0], supercell[1][1] + 1): - for c_ in range(supercell[2][0], supercell[2][1] + 1): + for a_ in range(supercell[0][0], supercell[0][1] + 1): # type:ignore[call-overload] + for b_ in range(supercell[1][0], supercell[1][1] + 1): # type:ignore[call-overload] + for c_ in range(supercell[2][0], supercell[2][1] + 1): # type:ignore[call-overload] mult_matrix = np.array([[a_, b_, c_]]) mult_matrix = np.repeat( mult_matrix, coordinates.shape[0], axis=0 @@ -789,43 +797,31 @@ def create_supercell(system, supercell=[[-1, 1], [-1, 1], [-1, 1]]): # elements array so that it maches new_elements = deepcopy(system["elements"]) new_ids = deepcopy(system["atom_ids"]) - for i in range(len(updated_coordinates) - 1): + for _i in range(len(updated_coordinates) - 1): new_elements = np.concatenate((new_elements, system["elements"])) new_ids = np.concatenate((new_ids, system["atom_ids"])) cryst = lattice_array_to_unit_cell(matrix) - supercell_system = { + return { "elements": new_elements, "atom_ids": new_ids, "coordinates": supercell_coordinates, "unit_cell": cryst, "lattice": matrix, } - return supercell_system -def is_inside_polyhedron(point, polyhedron): - if polyhedron.shape == (1, 6): - matrix = unit_cell_to_lattice_array(polyhedron) - if polyhedron.shape == (3, 3): - matrix = polyhedron - - frac_coord = pw.utilities.fractional_from_cartesian(point, matrix)[0] - - if ( - 0 <= frac_coord[0] <= 1.000 - and 0 <= frac_coord[1] <= 1.000 - and 0 <= frac_coord[2] <= 1.000 - ): - return True - return False - - -def normal_vector(origin, vectors): +def normal_vector( + origin: npt.NDArray[np.float64], vectors: npt.NDArray[np.float64] +) -> np.ndarray: # type:ignore[type-arg] """Return normal vector for two vectors with same origin.""" return np.cross(vectors[0] - origin, vectors[1] - origin) -def discrete_molecules(system, rebuild=None, tol=0.4): +def discrete_molecules( # noqa: C901, PLR0912, PLR0915 + system: dict, # type: ignore[type-arg] + rebuild: None | dict = None, # type: ignore[type-arg] + tol: float = 0.4, +) -> list[dict]: # type: ignore[type-arg] """Decompose molecular system into individual discreet molecules. Note: @@ -847,16 +843,10 @@ def discrete_molecules(system, rebuild=None, tol=0.4): # 3) Periodic Molecular system with rebuilding (supercell provided). if rebuild is not None: mode = 3 - elif "unit_cell" in system.keys(): - if system["unit_cell"].shape == (6,): - mode = 2 - else: - mode = 1 - elif "lattice" in system.keys(): - if system["lattice"].shape == (3, 3): - mode = 2 - else: - mode = 1 + elif "unit_cell" in system: + mode = 2 if system["unit_cell"].shape == (6,) else 1 + elif "lattice" in system: + mode = 2 if system["lattice"].shape == (3, 3) else 1 else: mode = 1 # We create a list containing all atoms, theirs periodic elements and @@ -866,18 +856,19 @@ def discrete_molecules(system, rebuild=None, tol=0.4): elements = system["elements"] coordinates = system["coordinates"] except KeyError: - raise _FunctionError( + msg = ( "The 'elements' key is missing in the 'system' dictionary " "attribute of the MolecularSystem object. Which means, you need to" " decipher the forcefield based atom keys first (see manual)." ) + raise _FunctionError(msg) from None coordinates = system["coordinates"] args = (elements, coordinates) adj = 0 # If there are forcefield 'atom ids' as well we will retain them. - if "atom_ids" in system.keys(): + if "atom_ids" in system: atom_ids = system["atom_ids"] - args = (elements, atom_ids, coordinates) + args = (elements, atom_ids, coordinates) # type:ignore[assignment] adj = 1 atom_list = compose_atom_list(*args) atom_coor = decompose_atom_list(atom_list)[1 + adj] @@ -897,10 +888,10 @@ def discrete_molecules(system, rebuild=None, tol=0.4): # be random from a set of equally far choices - bug found in the testing # this way rebuild system should always look the same from the same input # and on different machines. - if mode == 2 or mode == 3: + if mode in (2, 3): # Scenarios 2 or 3. origin = np.array([0.01, 0.0, 0.0]) - if "lattice" not in system.keys(): + if "lattice" not in system: matrix = unit_cell_to_lattice_array(system["unit_cell"]) else: matrix = system["lattice"] @@ -967,6 +958,7 @@ def discrete_molecules(system, rebuild=None, tol=0.4): dist_matrix = euclidean_distances( inside_atoms_coord_heavy, pseudo_origin.reshape(1, -1) ) + atom_index_x, _ = np.unravel_index( dist_matrix.argmin(), dist_matrix.shape ) @@ -979,7 +971,7 @@ def discrete_molecules(system, rebuild=None, tol=0.4): dist_matrix = euclidean_distances( atom_coor, pot_arr.reshape(1, -1) ) - idx = (dist_matrix > 0.1) * (dist_matrix < max_dist) + idx = (dist_matrix > 0.1) * (dist_matrix < max_dist) # noqa: PLR2004 if len(idx) < 1: pass else: @@ -1005,7 +997,7 @@ def discrete_molecules(system, rebuild=None, tol=0.4): dist_matrix = euclidean_distances( atom_coor, i_arr.reshape(1, -1) ) - idx = (dist_matrix > 0.1) * (dist_matrix < max_dist) + idx = (dist_matrix > 0.1) * (dist_matrix < max_dist) # noqa: PLR2004 neighbours_indexes = np.where(idx)[0] for j in neighbours_indexes: j_arr = np.array(atom_coor[j]) @@ -1022,7 +1014,8 @@ def discrete_molecules(system, rebuild=None, tol=0.4): sdist_matrix = euclidean_distances( satom_coor, i_arr.reshape(1, -1) ) - sidx = (sdist_matrix > 0.1) * (sdist_matrix < max_dist) + + sidx = (sdist_matrix > 0.1) * (sdist_matrix < max_dist) # noqa: PLR2004 sneighbours_indexes = np.where(sidx)[0] for j in sneighbours_indexes: if satom_list[j] in atom_list: @@ -1042,15 +1035,15 @@ def discrete_molecules(system, rebuild=None, tol=0.4): else: final_molecule.append(i) for i in working_list: - try: + with contextlib.suppress(ValueError): atom_list.remove(i) - except ValueError: - pass # We empty the working list as all the items were analysed # and moved to the final_molecule list. working_list = [] # We make sure there are no duplicates in the working_list_temp. + working_list_temp = unique(working_list_temp) + # Now we move the entries from the temporary working list # to the working list for looping analysys. for i in working_list_temp: @@ -1058,6 +1051,7 @@ def discrete_molecules(system, rebuild=None, tol=0.4): # being transfered. if i not in final_molecule: working_list.append(i) + final_molecule_dict = {} final_molecule_dict["elements"] = np.array( [x[0] for x in final_molecule], dtype="str" @@ -1091,17 +1085,24 @@ def discrete_molecules(system, rebuild=None, tol=0.4): return molecules -def angle_between_vectors(x, y): +def angle_between_vectors( + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], +) -> float: """Calculate the angle between two vectors x and y.""" first_step = abs(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]) / ( np.sqrt(x[0] ** 2 + x[1] ** 2 + x[2] ** 2) * np.sqrt(y[0] ** 2 + y[1] ** 2 + y[2] ** 2) ) - second_step = np.arccos(first_step) - return second_step + return np.arccos(first_step) -def vector_analysis(vector, coordinates, elements_vdw, increment=1.0): +def vector_analysis( + vector: npt.NDArray[np.float64], + coordinates: npt.NDArray[np.float64], + elements_vdw: npt.NDArray[np.float64], + increment: float = 1.0, +) -> np.ndarray | None: # type:ignore[type-arg] """Analyse a sampling vector's path for window analysis purpose.""" # Calculate number of chunks if vector length is divided by increment. chunks = int(np.linalg.norm(vector) // increment) @@ -1125,15 +1126,21 @@ def vector_analysis(vector, coordinates, elements_vdw, increment=1.0): return np.array( [dist, analysed_vector[pos] * 2, *chunk * pos, *vector] ) + return None -def vector_preanalysis(vector, coordinates, elements_vdw, increment=1.0): +def vector_preanalysis( + vector: npt.NDArray[np.float64], + coordinates: npt.NDArray[np.float64], + elements_vdw: npt.NDArray[np.float64], + increment: float = 1.0, +) -> np.ndarray | None: # type:ignore[type-arg] norm_vec = vector / np.linalg.norm(vector) intersections = [] origin = center_of_coor(coordinates) - L = coordinates - origin - t_ca = np.dot(L, norm_vec) - d = np.sqrt(np.einsum("ij,ij->i", L, L) - t_ca**2) + length = coordinates - origin + t_ca = np.dot(length, norm_vec) + d = np.sqrt(np.einsum("ij,ij->i", length, length) - t_ca**2) under_sqrt = elements_vdw**2 - d**2 diag = under_sqrt.diagonal() positions = np.argwhere(diag > 0) @@ -1142,42 +1149,55 @@ def vector_preanalysis(vector, coordinates, elements_vdw, increment=1.0): t_0 = t_ca[pos][0] - t_hc t_1 = t_ca[pos][0] + t_hc - P_0 = origin + np.dot(t_0, norm_vec) - P_1 = origin + np.dot(t_1, norm_vec) - # print(np.linalg.norm(P_0), np.linalg.norm(P_1)) - if np.linalg.norm(P_0) < np.linalg.norm(P_1): + p_0 = origin + np.dot(t_0, norm_vec) + p_1 = origin + np.dot(t_1, norm_vec) + + if np.linalg.norm(p_0) < np.linalg.norm(p_1): intersections.append(1) else: intersections.append(0) if sum(intersections) == 0: return vector_analysis(vector, coordinates, elements_vdw, increment) + return None -def optimise_xy(xy, *args): +def optimise_xy( + xy: npt.NDArray[np.float64], + *args: tuple[npt.NDArray[np.float64], list[str], npt.NDArray[np.float64]], +) -> float: """Return negative pore diameter for x and y coordinates optimisation.""" z, elements, coordinates = args window_com = np.array([xy[0], xy[1], z]) - return -pore_diameter(elements, coordinates, com=window_com)[0] - - -def optimise_z(z, *args): + return -pore_diameter(elements, coordinates, com=window_com)[0] # type: ignore[arg-type] + + +def optimise_z( + z: npt.NDArray[np.float64], + *args: tuple[ + npt.NDArray[np.float64], + npt.NDArray[np.float64], + list[str], + npt.NDArray[np.float64], + ], +) -> float: """Return pore diameter for coordinates optimisation in z direction.""" x, y, elements, coordinates = args - window_com = np.array([x, y, z]) - return pore_diameter(elements, coordinates, com=window_com)[0] - - -def window_analysis( - window, - elements, - coordinates, - elements_vdw, - increment2=0.1, - z_bounds=[None, None], - lb_z=True, - z_second_mini=False, - **kwargs, -): + + window_com = np.array([x, y, z[0]]) + + return pore_diameter(elements, coordinates, com=window_com)[0] # type: ignore[arg-type] + + +def window_analysis( # noqa: C901, PLR0913, PLR0915 + window: npt.NDArray[np.float64], + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], + elements_vdw: npt.NDArray[np.float64], + increment2: float = 0.1, + z_bounds: None | list = None, # type:ignore[type-arg] + lb_z: bool = True, # noqa: FBT001, FBT002 + z_second_mini: bool = False, # noqa: FBT001, FBT002 +) -> tuple[float, npt.NDArray[np.float64]] | None: """Return window diameter and window's centre. Parameters @@ -1194,6 +1214,8 @@ def window_analysis( """ # Copy the coordinates as we will manipulate them. + if z_bounds is None: + z_bounds = [None, None] coordinates = deepcopy(coordinates) # Find the vector with the largest window sampling diameter from the pool. vector_ = window[window.argmax(axis=0)[1]][5:8] @@ -1201,15 +1223,13 @@ def window_analysis( vector_, coordinates, elements_vdw, increment=increment2 ) # A safety check, if the refined analysis give None we end the function. - if vector_analysed is not None: - pass - else: + if vector_analysed is None: return None vector = vector_analysed[5:8] # Unit vectors. - vec_a = [1, 0, 0] - vec_b = [0, 1, 0] - vec_c = [0, 0, 1] + vec_a = np.array([1, 0, 0]) + + vec_c = np.array([0, 0, 1]) # Angles needed for rotation (in radians) to rotate and translate the # molecule for the vector to become the Z-axis. angle_1 = angle_between_vectors(np.array([vector[0], vector[1], 0]), vec_a) @@ -1221,9 +1241,9 @@ def window_analysis( angle_2 = -angle_2 if vector[0] < 0 and vector[1] >= 0 and vector[2] >= 0: angle_1 = np.pi * 2 + angle_1 - angle_2 = angle_2 + angle_2 = angle_2 # noqa: PLW0127 if vector[0] >= 0 and vector[1] < 0 and vector[2] >= 0: - angle_1 = angle_1 + angle_1 = angle_1 # noqa: PLW0127 angle_2 = -angle_2 if vector[0] < 0 and vector[1] < 0 and vector[2] >= 0: angle_1 = np.pi * 2 - angle_1 @@ -1341,21 +1361,19 @@ def window_analysis( return (window_diameter, window_com) -def find_windows( - elements, - coordinates, - processes=None, - mol_size=None, - adjust=1, - pore_opt=True, - increment=1.0, - **kwargs, -): +def find_windows( # noqa: PLR0913, PLR0915 + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], + processes: int | None = None, + adjust: float = 1, + pore_opt: bool = True, # noqa: FBT001, FBT002 + increment: float = 1.0, +) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]] | None: """Return windows diameters and center of masses for a molecule.""" # Copy the coordinates as will perform many opertaions on them coordinates = deepcopy(coordinates) # Center of our cartesian system is always at origin - origin = np.array([0, 0, 0]) + # Initial center of mass to reverse translation at the end initial_com = center_of_mass(elements, coordinates) # Shift the cage to the origin using either the standard center of mass @@ -1367,14 +1385,12 @@ def find_windows( # is at the origin of the system and not the center of the not # optimised one, we need to adjust the shift. We also have to update # the initial com. - com_adjust = ( - initial_com - opt_pore_diameter(elements, coordinates, **kwargs)[2] - ) + com_adjust = initial_com - opt_pore_diameter(elements, coordinates)[2] initial_com = initial_com - com_adjust - coordinates = shift_com(elements, coordinates, com_adjust=com_adjust) + coordinates = shift_com(elements, coordinates, com_adjust=com_adjust) # type:ignore[assignment] else: # Otherwise, we just shift the cage to the origin. - coordinates = shift_com(elements, coordinates) + coordinates = shift_com(elements, coordinates) # type:ignore[assignment] # We create an array of vdw radii of elements. elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) # We calculate maximum diameter of a molecule to determine the radius @@ -1422,7 +1438,7 @@ def find_windows( # included sphere, coordinates for this narrow channel point. vectors # that find molecule on theirs path are return as NoneType object. # Parralel analysis on user's defined number of CPUs. - if processes: + if processes is not None and processes > 1: pool = Pool(processes=processes) parallel = [ pool.apply_async( @@ -1435,16 +1451,20 @@ def find_windows( results = [p.get() for p in parallel if p.get() is not None] pool.terminate() # Dataset is an array of sampling points coordinates. - dataset = np.array([x[5:8] for x in results]) + dataset = np.array([x[5:8] for x in results]) # type:ignore[index] + else: results = [ vector_preanalysis( - point, coordinates, elements_vdw, increment=increment + point, + coordinates, + elements_vdw, + increment=increment, ) for point in points ] results = [x for x in results if x is not None] - dataset = np.array([x[5:8] for x in results]) + dataset = np.array([x[5:8] for x in results]) # type:ignore[index] # If not a single vector was returned from the analysis it mean that # no molecular channels (what we call windows here) connects the # molecule's interior with the surroungsings (exterior space). @@ -1454,16 +1474,17 @@ def find_windows( return None # Perfomr DBSCAN to cluster the sampling points vectors. # the n_jobs will be developed later. - # db = DBSCAN(eps=eps, n_jobs=_ncpus).fit(dataset) + db = DBSCAN(eps=eps).fit(dataset) core_samples_mask = np.zeros_like(db.labels_, dtype=bool) core_samples_mask[db.core_sample_indices_] = True labels = set(db.labels_) # Assing cluster label to a sampling point. clusters = [[i, j] for i, j in zip(results, db.labels_)] - clustered_results = {label: [] for label in labels} + clustered_results = {label: [] for label in labels} # type:ignore[var-annotated] # Create a dictionary of clusters with points listed. - [clustered_results[i[1]].append(i[0]) for i in clusters] + for i in clusters: # type:ignore[assignment] + clustered_results[i[1]].append(i[0]) # No for the sampling point vector in each cluster that had # the widest channel's 'neck' is assumed to pass the closest # to the window's center and therefore will be passed to @@ -1471,32 +1492,31 @@ def find_windows( # We also pass user defined settings for window analysis. # Again either in serlia or in parallel. # Noisy points get a cluster label -1, therefore we have to exclude it. - if processes: + if processes is not None and processes > 1: pool = Pool(processes=processes) parallel = [ pool.apply_async( - window_analysis, + window_analysis, # type:ignore[arg-type] args=( np.array(clustered_results[cluster]), elements, coordinates, elements_vdw, ), - kwds=kwargs, ) for cluster in clustered_results if cluster != -1 ] window_results = [p.get() for p in parallel if p.get() is not None] pool.terminate() + else: window_results = [ - window_analysis( + window_analysis( # type:ignore[misc] np.array(clustered_results[cluster]), elements, coordinates, elements_vdw, - **kwargs, ) for cluster in clustered_results if cluster != -1 @@ -1517,358 +1537,33 @@ def find_windows( # should be raised. for result in window_results: if result is None: - msg_ = " ".join( - [ - "Warning. One of the analysed windows has", - "returned as None. See manual.", - ] - ) - # print(msg_) - elif result[0] < 0: - msg_ = " ".join( - [ - "Warning. One of the analysed windows has a vdW", - "corrected diameter smaller than 0. See manual.", - ] + msg_ = ( + "Warning. One of the analysed windows has returned as None. " + "See manual." ) - # print(msg_) - return (windows, windows_coms) - - -def window_shape( - window, - elements, - coordinates, - increment2=0.1, - z_bounds=[None, None], - lb_z=True, - z_second_mini=False, - **kwargs, -): - """Return window diameter and window's centre. - - Parameters - ---------- - widnow: list - - elements: numpy.array - - coordinates: numpy.array - - elements_vdw: numpy.array - - step: float + logger.warning(msg_) - """ - # Copy the coordinates as we will manipulate them. - coordinates = deepcopy(coordinates) - # We create an array of vdw radii of elements. - elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) - # Find the vector with the largest window sampling diameter from the pool. - vector_ = window[window.argmax(axis=0)[1]][5:8] - vector_analysed = vector_analysis( - vector_, coordinates, elements_vdw, increment=increment2 - ) - # A safety check, if the refined analysis give None we end the function. - if vector_analysed is not None: - pass - else: - return None - vector = vector_analysed[5:8] - # Unit vectors. - vec_a = [1, 0, 0] - vec_b = [0, 1, 0] - vec_c = [0, 0, 1] - # Angles needed for rotation (in radians) to rotate and translate the - # molecule for the vector to become the Z-axis. - angle_1 = angle_between_vectors(np.array([vector[0], vector[1], 0]), vec_a) - angle_2 = angle_between_vectors(vector, vec_c) - # Depending in which cartesian coordinate system area the vector is - # We need a rotation into a different direction and by different value. - if vector[0] >= 0 and vector[1] >= 0 and vector[2] >= 0: - angle_1 = -angle_1 - angle_2 = -angle_2 - if vector[0] < 0 and vector[1] >= 0 and vector[2] >= 0: - angle_1 = np.pi * 2 + angle_1 - angle_2 = angle_2 - if vector[0] >= 0 and vector[1] < 0 and vector[2] >= 0: - angle_1 = angle_1 - angle_2 = -angle_2 - if vector[0] < 0 and vector[1] < 0 and vector[2] >= 0: - angle_1 = np.pi * 2 - angle_1 - if vector[0] >= 0 and vector[1] >= 0 and vector[2] < 0: - angle_1 = -angle_1 - angle_2 = np.pi + angle_2 - if vector[0] < 0 and vector[1] >= 0 and vector[2] < 0: - angle_2 = np.pi - angle_2 - if vector[0] >= 0 and vector[1] < 0 and vector[2] < 0: - angle_2 = angle_2 + np.pi - if vector[0] < 0 and vector[1] < 0 and vector[2] < 0: - angle_1 = -angle_1 - angle_2 = np.pi - angle_2 - # Rotation matrix for rotation around Z-axis with angle_1. - rotation_around_z = np.array( - [ - [np.cos(angle_1), -np.sin(angle_1), 0], - [np.sin(angle_1), np.cos(angle_1), 0], - [0, 0, 1], - ] - ) - # Rotate the whole molecule around with rotation_around_z. - coordinates = np.array([np.dot(rotation_around_z, i) for i in coordinates]) - # Rotation matrix for rotation around Y-axis with angle_2 - rotation_around_y = np.array( - [ - [np.cos(angle_2), 0, np.sin(angle_2)], - [0, 1, 0], - [-np.sin(angle_2), 0, np.cos(angle_2)], - ] - ) - # Rotate the whole molecule around with rotation_around_y. - coordinates = np.array([np.dot(rotation_around_y, i) for i in coordinates]) - # Third step is translation. We are now at [0, 0, -z]. - # We shift the molecule so that center of the window is at the origin. - # The `z` is from original vector analysis. It is the point on the vector - # where the largest sampling sphere was (vector_analysed[0]). - new_z = vector_analysed[0] - # Translate the whole molecule to shift window's center to origin. - coordinates = coordinates - np.array( - [[0, 0, new_z]] * coordinates.shape[0] - ) - # !!!Here the window center (xy and z) optimisation take place!!! - window_com = np.array([0, 0, 0], dtype=float) - # The lb_z parameter is 'lower bound equal to z' which means, - # that we set the lower bound for the z optimisation to be equal - # to the -new_z as in some cages it's the COM - pore that is the - # limiting diameter. But, no lower than new_z because we don't want to - # move into the other direction. - if lb_z: - z_bounds[0] = -new_z - window_diameter, _ = pore_diameter(elements, coordinates, com=window_com) - # SciPy minimisation on z coordinate. - z_args = (window_com[0], window_com[1], elements, coordinates) - z_optimisation = minimize( - optimise_z, x0=window_com[2], args=z_args, bounds=[z_bounds] - ) - # Substitute the z coordinate for a minimised one. - window_com[2] = z_optimisation.x[0] - # SciPy brute optimisation on x and y coordinates in window plane. - xy_args = (window_com[2], elements, coordinates) - xy_bounds = ( - (-window_diameter / 2, window_diameter / 2), - (-window_diameter / 2, window_diameter / 2), - ) - xy_optimisation = brute( - optimise_xy, xy_bounds, args=xy_args, full_output=True, finish=fmin - ) - # Substitute the x and y coordinates for the optimised ones. - window_com[0] = xy_optimisation[0][0] - window_com[1] = xy_optimisation[0][1] - # Additional SciPy minimisation on z coordinate. Added on 18 May 2017. - # We can argue which aproach is best. Whether z opt and then xy opt - # or like now z opt -> xy opt -> additional z opt etc. I have also tested - # a loop of optimisations until some convergence and optimisation of - # xyz coordinates at the same time by optimising these two optimisations. - # In the end. I think this approach is best for cages. - # Update 20 October 2017: I made this optional and turned off by default - # In many cases that worsen the quality of the results and should be used - # with caution. - if z_second_mini is not False: - z_args = (window_com[0], window_com[1], elements, coordinates) - # The z_bounds should be passed in kwargs. - z_optimisation = minimize( - optimise_z, x0=window_com[2], args=z_args, bounds=[z_bounds] - ) - # Substitute the z coordinate for a minimised one. - window_com[2] = z_optimisation.x[0] - # Getting the 2D plane crosssection of a window in XY plain. (10-04-18) - # First translation around Z axis. - vectors_translated = [ - [ - np.dot(rotation_around_z, i[5:])[0], - np.dot(rotation_around_z, i[5:])[1], - np.dot(rotation_around_z, i[5:])[2], - ] - for i in window - ] - # Second rotation around Y axis. - vectors_translated = [ - [ - np.dot(rotation_around_y, i)[0], - np.dot(rotation_around_y, i)[1], - np.dot(rotation_around_y, i)[2], - ] - for i in vectors_translated - ] - ref_distance = (new_z - window_com[2]) / np.linalg.norm(vector) - # Cutting the XY plane. - XY_plane = np.array( - [ - [i[0] * ref_distance, i[1] * ref_distance] - for i in vectors_translated - ] - ) - return XY_plane - - -def find_windows_new( - elements, - coordinates, - processes=None, - mol_size=None, - adjust=1, - pore_opt=True, - increment=1.0, - **kwargs, -): - """Return windows diameters and center of masses for a molecule.""" - # Copy the coordinates as will perform many opertaions on them - coordinates = deepcopy(coordinates) - # Center of our cartesian system is always at origin - origin = np.array([0, 0, 0]) - # Initial center of mass to reverse translation at the end - initial_com = center_of_mass(elements, coordinates) - # Shift the cage to the origin using either the standard center of mass - # or if pore_opt flag is True, the optimised pore center as center of mass - if pore_opt is True: - # Normally the pore is calculated from the COM of a molecule. - # So, esentially the molecule's COM is the pore center. - # To shift the molecule so that the center of the optimised pore - # is at the origin of the system and not the center of the not - # optimised one, we need to adjust the shift. We also have to update - # the initial com. - com_adjust = ( - initial_com - opt_pore_diameter(elements, coordinates, **kwargs)[2] - ) - initial_com = initial_com - com_adjust - coordinates = shift_com(elements, coordinates, com_adjust=com_adjust) - else: - # Otherwise, we just shift the cage to the origin. - coordinates = shift_com(elements, coordinates) - # We create an array of vdw radii of elements. - elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) - # We calculate maximum diameter of a molecule to determine the radius - # of a sampling sphere neccessary to enclose the whole molecule. - shpere_radius = max_dim(elements, coordinates)[2] / 2 - sphere_surface_area = 4 * np.pi * shpere_radius**2 - # Here we determine the number of sampling points necessary for a fine - # sampling. Smaller molecules require more finner density of sampling - # points on the sampling sphere's surface, whereas largen require less. - # This formula was created so that larger molecule do not take much longer - # to analyse, as number_sampling_points*length_of_sampling_vectors - # results in quadratic increase of sampling time. The 250 factor was - # specificly determined to produce close to 1 sampling point /Angstrom^2 - # for a sphere of radius ~ 24 Angstrom. We can adjust how fine is the - # sampling by changing the adjust factor. - number_of_points = int(np.log10(sphere_surface_area) * 250 * adjust) - # Here I use code by Alexandre Devert for spreading points on a sphere: - # http://blog.marmakoide.org/?p=1 - golden_angle = np.pi * (3 - np.sqrt(5)) - theta = golden_angle * np.arange(number_of_points) - z = np.linspace( - 1 - 1.0 / number_of_points, - 1.0 / number_of_points - 1.0, - number_of_points, - ) - radius = np.sqrt(1 - z * z) - points = np.zeros((number_of_points, 3)) - points[:, 0] = radius * np.cos(theta) * shpere_radius - points[:, 1] = radius * np.sin(theta) * shpere_radius - points[:, 2] = z * shpere_radius - # Here we will compute the eps parameter for the sklearn.cluster.DBSCAN - # (3-dimensional spatial clustering algorithm) which is the mean distance - # to the closest point of all points. - values = [] - tree = KDTree(points) - for i in points: - dist, ind = tree.query(i.reshape(1, -1), k=10) - values.extend(dist) - mean_distance = np.mean(values) - # The best eps is parametrized when adding the mean distance and it's root. - eps = mean_distance + mean_distance**0.5 - # Here we either run the sampling points vectors analysis in serial - # or parallel. The vectors that go through molecular pores return - # as analysed list with the increment at vector's path with largest - # included sphere, coordinates for this narrow channel point. vectors - # that find molecule on theirs path are return as NoneType object. - # Parralel analysis on user's defined number of CPUs. - if processes: - pool = Pool(processes=processes) - parallel = [ - pool.apply_async( - vector_preanalysis, - args=(point, coordinates, elements_vdw), - kwds={"increment": increment}, - ) - for point in points - ] - results = [p.get() for p in parallel if p.get() is not None] - pool.terminate() - # Dataset is an array of sampling points coordinates. - dataset = np.array([x[5:8] for x in results]) - else: - results = [ - vector_preanalysis( - point, coordinates, elements_vdw, increment=increment + elif result[0] < 0: + msg_ = ( + "Warning. One of the analysed windows has a vdW corrected " + "diameter smaller than 0. See manual." ) - for point in points - ] - results = [x for x in results if x is not None] - dataset = np.array([x[5:8] for x in results]) - # If not a single vector was returned from the analysis it mean that - # no molecular channels (what we call windows here) connects the - # molecule's interior with the surroungsings (exterior space). - # The number of windows in that case equals zero and zero is returned. - # Otherwise we continue our search for windows. - if len(results) == 0: - return None - # Perfomr DBSCAN to cluster the sampling points vectors. - # the n_jobs will be developed later. - # db = DBSCAN(eps=eps, n_jobs=_ncpus).fit(dataset) - db = DBSCAN(eps=eps).fit(dataset) - core_samples_mask = np.zeros_like(db.labels_, dtype=bool) - core_samples_mask[db.core_sample_indices_] = True - labels = set(db.labels_) - # Assing cluster label to a sampling point. - clusters = [[i, j] for i, j in zip(results, db.labels_)] - clustered_results = {label: [] for label in labels} - # Create a dictionary of clusters with points listed. - [clustered_results[i[1]].append(i[0]) for i in clusters] - return clustered_results, elements, coordinates, initial_com - - -def calculate_window_diameter(window, elements, coordinates, **kwargs): - elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) - window_results = window_analysis( - np.array(window), elements, coordinates, elements_vdw, **kwargs - ) - # The function returns two numpy arrays, one with windows diameters - # in Angstrom, second with corresponding windows center's coordinates - if window_results: - return window_results[0] - return None + logger.warning(msg_) - -def get_window_com(window, elements, coordinates, initial_com, **kwargs): - elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) - window_results = window_analysis( - np.array(window), elements, coordinates, elements_vdw, **kwargs - ) - # The function returns two numpy arrays, one with windows diameters - # in Angstrom, second with corresponding windows center's coordinates - if window_results: - # I correct the COM of window for the initial COM of the cage - return np.add(window_results[1], initial_com) - return None + return (windows, windows_coms) -def vector_analysis_reversed(vector, coordinates, elements_vdw): +def vector_analysis_reversed( + vector: npt.NDArray[np.float64], + coordinates: npt.NDArray[np.float64], + elements_vdw: npt.NDArray[np.float64], +) -> list[float] | None: norm_vec = vector / np.linalg.norm(vector) intersections = [] origin = center_of_coor(coordinates) - L = coordinates - origin - t_ca = np.dot(L, norm_vec) - d = np.sqrt(np.einsum("ij,ij->i", L, L) - t_ca**2) + length = coordinates - origin + t_ca = np.dot(length, norm_vec) + d = np.sqrt(np.einsum("ij,ij->i", length, length) - t_ca**2) under_sqrt = elements_vdw**2 - d**2 diag = under_sqrt.diagonal() positions = np.argwhere(diag > 0) @@ -1877,28 +1572,32 @@ def vector_analysis_reversed(vector, coordinates, elements_vdw): t_0 = t_ca[pos][0] - t_hc t_1 = t_ca[pos][0] + t_hc - P_0 = origin + np.dot(t_0, norm_vec) - P_1 = origin + np.dot(t_1, norm_vec) - if np.linalg.norm(P_0) < np.linalg.norm(P_1): - intersections.append([np.linalg.norm(P_1), P_1]) + p_0 = origin + np.dot(t_0, norm_vec) + p_1 = origin + np.dot(t_1, norm_vec) + if np.linalg.norm(p_0) < np.linalg.norm(p_1): + intersections.append([np.linalg.norm(p_1), p_1]) if intersections: intersection = sorted(intersections, reverse=True)[0][1] dist_origin = np.linalg.norm(intersection) - return [dist_origin, intersection] + return [float(dist_origin), intersection] + return None def find_average_diameter( - elements, coordinates, adjust=1, increment=0.1, processes=None, **kwargs -): + elements: npt.NDArray[np.str_], + coordinates: npt.NDArray[np.float64], + adjust: float = 1, + processes: int | None = None, +) -> float: """Return average diameter for a molecule.""" # Copy the coordinates as will perform many opertaions on them coordinates = deepcopy(coordinates) # Center of our cartesian system is always at origin - origin = np.array([0, 0, 0]) + origin = np.array([0, 0, 0]) # noqa: F841 # Initial center of mass to reverse translation at the end - initial_com = center_of_mass(elements, coordinates) + initial_com = center_of_mass(elements, coordinates) # noqa: F841 # We just shift the cage to the origin. - coordinates = shift_com(elements, coordinates) + coordinates = shift_com(elements, coordinates) # type:ignore[assignment] # We create an array of vdw radii of elements. elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) # We calculate maximum diameter of a molecule to determine the radius @@ -1948,132 +1647,46 @@ def find_average_diameter( for point in points ] results_cleaned = [x[0] for x in results if x is not None] - return np.mean(results_cleaned) * 2 - - -def vector_analysis_pore_shape(vector, coordinates, elements_vdw): - norm_vec = vector / np.linalg.norm(vector) - intersections = [] - origin = center_of_coor(coordinates) - L = coordinates - origin - t_ca = np.dot(L, norm_vec) - d = np.sqrt(np.einsum("ij,ij->i", L, L) - t_ca**2) - under_sqrt = elements_vdw**2 - d**2 - diag = under_sqrt.diagonal() - positions = np.argwhere(diag > 0) - for pos in positions: - t_hc = np.sqrt(diag[pos[0]]) - t_0 = t_ca[pos][0] - t_hc - t_1 = t_ca[pos][0] + t_hc - - P_0 = origin + np.dot(t_0, norm_vec) - P_1 = origin + np.dot(t_1, norm_vec) - # print(np.linalg.norm(P_0), np.linalg.norm(P_1)) - if np.linalg.norm(P_0) < np.linalg.norm(P_1): - intersections.append([np.linalg.norm(P_0), P_0]) - if intersections: - return sorted(intersections)[0][1] - - -def calculate_pore_shape( - elements, coordinates, adjust=1, increment=0.1, **kwargs -): - """Return average diameter for a molecule.""" - # Copy the coordinates as will perform many opertaions on them - coordinates = deepcopy(coordinates) - # Center of our cartesian system is always at origin - origin = np.array([0, 0, 0]) - # Initial center of mass to reverse translation at the end - initial_com = center_of_mass(elements, coordinates) - # We just shift the cage to the origin. - coordinates = shift_com(elements, coordinates) - # We create an array of vdw radii of elements. - elements_vdw = np.array([[atomic_vdw_radius[x.upper()]] for x in elements]) - # We calculate maximum diameter of a molecule to determine the radius - # of a sampling sphere neccessary to enclose the whole molecule. - shpere_radius = max_dim(elements, coordinates)[2] / 2 - sphere_surface_area = 4 * np.pi * shpere_radius**2 - # Here we determine the number of sampling points necessary for a fine - # sampling. Smaller molecules require more finner density of sampling - # points on the sampling sphere's surface, whereas largen require less. - # This formula was created so that larger molecule do not take much longer - # to analyse, as number_sampling_points*length_of_sampling_vectors - # results in quadratic increase of sampling time. The 250 factor was - # specificly determined to produce close to 1 sampling point /Angstrom^2 - # for a sphere of radius ~ 24 Angstrom. We can adjust how fine is the - # sampling by changing the adjust factor. - number_of_points = int(np.log10(sphere_surface_area) * 250 * adjust) - # Here I use code by Alexandre Devert for spreading points on a sphere: - # http://blog.marmakoide.org/?p=1 - golden_angle = np.pi * (3 - np.sqrt(5)) - theta = golden_angle * np.arange(number_of_points) - z = np.linspace( - 1 - 1.0 / number_of_points, - 1.0 / number_of_points - 1.0, - number_of_points, - ) - radius = np.sqrt(1 - z * z) - points = np.zeros((number_of_points, 3)) - points[:, 0] = radius * np.cos(theta) * shpere_radius - points[:, 1] = radius * np.sin(theta) * shpere_radius - points[:, 2] = z * shpere_radius - # Here we will compute the eps parameter for the sklearn.cluster.DBSCAN - # (3-dimensional spatial clustering algorithm) which is the mean distance - # to the closest point of all points. - values = [] - tree = KDTree(points) - for i in points: - dist, ind = tree.query(i.reshape(1, -1), k=10) - values.extend(dist) - mean_distance = np.mean(values) - # The best eps is parametrized when adding the mean distance and it's root. - eps = mean_distance + mean_distance**0.5 - # Here we either run the sampling points vectors analysis in serial - # or parallel. The vectors that go through molecular voids return - # as analysed list with the increment at vector's path with largest - # included sphere, coordinates for this narrow channel point. vectors - # that find molecule on theirs path are return as NoneType object. - results = [ - vector_analysis_pore_shape(point, coordinates, elements_vdw) - for point in points - ] - results_cleaned = [x for x in results if x is not None] - ele = np.array(["X"] * len(results_cleaned)) - coor = np.array(results_cleaned) - return coor + return float(np.mean(results_cleaned) * 2) -def circumcircle_window(coordinates, atom_set): +def circumcircle_window( + coordinates: npt.NDArray[np.float64], + atom_set: list, # type:ignore[type-arg] +) -> tuple[float, npt.NDArray[np.float64]]: # Calculating circumcircle - A = np.array(coordinates[int(atom_set[0])]) - B = np.array(coordinates[int(atom_set[1])]) - C = np.array(coordinates[int(atom_set[2])]) - a = np.linalg.norm(C - B) - b = np.linalg.norm(C - A) - c = np.linalg.norm(B - A) + cap_a = np.array(coordinates[int(atom_set[0])]) + cap_b = np.array(coordinates[int(atom_set[1])]) + cap_c = np.array(coordinates[int(atom_set[2])]) + a = np.linalg.norm(cap_c - cap_b) + b = np.linalg.norm(cap_c - cap_a) + c = np.linalg.norm(cap_b - cap_a) s = (a + b + c) / 2 # Holden et al. method is intended to only work with triads of carbons, # therefore I substract the vdW radii for a carbon. # These equation calculaties the window's radius. - R = a * b * c / 4 / np.sqrt(s * (s - a) * (s - b) * (s - c)) - 1.70 + r = a * b * c / 4 / np.sqrt(s * (s - a) * (s - b) * (s - c)) - 1.70 # This steps are used to calculate the window's COM. b1 = a * a * (b * b + c * c - a * a) b2 = b * b * (a * a + c * c - b * b) b3 = c * c * (a * a + b * b - c * c) - COM = np.column_stack((A, B, C)).dot(np.hstack((b1, b2, b3))) + com = np.column_stack((cap_a, cap_b, cap_c)).dot(np.hstack((b1, b2, b3))) # The window's COM. - COM /= b1 + b2 + b3 - return R, COM + com /= b1 + b2 + b3 + return r, com -def circumcircle(coordinates, atom_sets): +def circumcircle( + coordinates: npt.NDArray[np.float64], + atom_sets: list, # type:ignore[type-arg] +) -> tuple[list[float], list[npt.NDArray[np.float64]]]: pld_diameter_list = [] pld_com_list = [] iter_ = 0 while iter_ < len(atom_sets): - R, COM = circumcircle_window(coordinates, atom_sets[iter_]) - pld_diameter_list.append(R * 2) - pld_com_list.append(COM) + r, com = circumcircle_window(coordinates, atom_sets[iter_]) + pld_diameter_list.append(r * 2) + pld_com_list.append(com) iter_ += 1 return pld_diameter_list, pld_com_list diff --git a/tests/data/mol_system.pdb b/tests/data/mol_system.pdb new file mode 100644 index 0000000..81f0aaf --- /dev/null +++ b/tests/data/mol_system.pdb @@ -0,0 +1,104 @@ +REMARK File generated using pyWINDOW. +ATOM 1 C6 MOL A 1 9.439 5.984 6.904 C +ATOM 2 C6 MOL A 1 9.439 6.416 5.496 C +ATOM 3 C5 MOL A 1 10.679 5.144 7.177 C +ATOM 4 H6 MOL A 1 8.640 5.466 7.090 H +ATOM 5 H7 MOL A 1 9.434 6.763 7.485 H +ATOM 6 C5 MOL A 1 10.679 7.256 5.223 C +ATOM 7 H6 MOL A 1 8.640 6.934 5.310 H +ATOM 8 H7 MOL A 1 9.434 5.637 4.915 H +ATOM 9 C4 MOL A 1 11.939 5.952 6.907 C +ATOM 10 H4 MOL A 1 10.674 4.848 8.102 H +ATOM 11 H5 MOL A 1 10.669 4.357 6.609 H +ATOM 12 C4 MOL A 1 11.939 6.448 5.493 C +ATOM 13 H4 MOL A 1 10.674 7.552 4.298 H +ATOM 14 H5 MOL A 1 10.669 8.043 5.791 H +ATOM 15 N1 MOL A 1 13.090 5.085 7.104 N +ATOM 16 H3 MOL A 1 11.986 6.711 7.524 H +ATOM 17 N1 MOL A 1 13.090 7.315 5.296 N +ATOM 18 H3 MOL A 1 11.986 5.689 4.876 H +ATOM 19 C3 MOL A 1 13.915 5.388 7.973 C +ATOM 20 C3 MOL A 1 13.915 7.012 4.427 C +ATOM 21 C2 MOL A 1 15.085 4.573 8.296 C +ATOM 22 H2 MOL A 1 13.786 6.178 8.447 H +ATOM 23 C2 MOL A 1 15.085 7.827 4.104 C +ATOM 24 H2 MOL A 1 13.786 6.222 3.953 H +ATOM 25 C1 MOL A 1 15.867 4.869 9.379 C +ATOM 26 C1 MOL A 1 15.421 3.467 7.531 C +ATOM 27 C1 MOL A 1 15.867 7.531 3.021 C +ATOM 28 C1 MOL A 1 15.421 8.933 4.869 C +ATOM 29 C2 MOL A 1 16.973 4.104 9.715 C +ATOM 30 H1 MOL A 1 15.649 5.605 9.905 H +ATOM 31 H1 MOL A 1 14.895 3.249 6.795 H +ATOM 32 C2 MOL A 1 16.504 2.685 7.827 C +ATOM 33 C2 MOL A 1 16.973 8.296 2.685 C +ATOM 34 H1 MOL A 1 15.649 6.795 2.495 H +ATOM 35 H1 MOL A 1 14.895 9.151 5.605 H +ATOM 36 C2 MOL A 1 16.504 9.715 4.573 C +ATOM 37 C3 MOL A 1 17.788 4.427 10.885 C +ATOM 38 C1 MOL A 1 17.269 3.021 8.933 C +ATOM 39 C3 MOL A 1 16.827 1.515 7.012 C +ATOM 40 C3 MOL A 1 17.788 7.973 1.515 C +ATOM 41 C1 MOL A 1 17.269 9.379 3.467 C +ATOM 42 C3 MOL A 1 16.827 10.885 5.388 C +ATOM 43 N1 MOL A 1 17.485 5.296 11.710 N +ATOM 44 H2 MOL A 1 18.578 3.953 11.014 H +ATOM 45 H1 MOL A 1 18.005 2.495 9.151 H +ATOM 46 N1 MOL A 1 17.696 0.690 7.315 N +ATOM 47 H2 MOL A 1 16.353 1.386 6.222 H +ATOM 48 N1 MOL A 1 17.485 7.104 0.690 N +ATOM 49 H2 MOL A 1 18.578 8.447 1.386 H +ATOM 50 H1 MOL A 1 18.005 9.905 3.249 H +ATOM 51 N1 MOL A 1 17.696 11.710 5.085 N +ATOM 52 H2 MOL A 1 16.353 11.014 6.178 H +ATOM 53 C4 MOL A 1 18.352 5.493 12.861 C +ATOM 54 C4 MOL A 1 17.893 12.861 5.952 C +ATOM 55 C5 MOL A 1 17.544 5.223 14.121 C +ATOM 56 H3 MOL A 1 19.111 4.876 12.814 H +ATOM 57 C4 MOL A 1 18.848 6.907 12.861 C +ATOM 58 C5 MOL A 1 17.623 14.121 5.144 C +ATOM 59 H3 MOL A 1 17.276 12.814 6.711 H +ATOM 60 C4 MOL A 1 19.307 12.861 6.448 C +ATOM 61 C6 MOL A 1 18.384 5.496 15.361 C +ATOM 62 H4 MOL A 1 17.248 4.298 14.126 H +ATOM 63 H5 MOL A 1 16.757 5.791 14.131 H +ATOM 64 N1 MOL A 1 19.715 7.104 11.710 N +ATOM 65 C5 MOL A 1 19.656 7.177 14.121 C +ATOM 66 H3 MOL A 1 18.089 7.524 12.814 H +ATOM 67 C6 MOL A 1 17.896 15.361 5.984 C +ATOM 68 H4 MOL A 1 16.698 14.126 4.848 H +ATOM 69 H5 MOL A 1 18.191 14.131 4.357 H +ATOM 70 N1 MOL A 1 19.504 11.710 7.315 N +ATOM 71 C5 MOL A 1 19.577 14.121 7.256 C +ATOM 72 H3 MOL A 1 19.924 12.814 5.689 H +ATOM 73 H6 MOL A 1 17.866 5.310 16.160 H +ATOM 74 H7 MOL A 1 19.163 4.915 15.366 H +ATOM 75 C6 MOL A 1 18.816 6.904 15.361 C +ATOM 76 C3 MOL A 1 19.412 7.973 10.885 C +ATOM 77 H4 MOL A 1 19.952 8.102 14.126 H +ATOM 78 H5 MOL A 1 20.443 6.609 14.131 H +ATOM 79 H6 MOL A 1 17.710 16.160 5.466 H +ATOM 80 H7 MOL A 1 17.315 15.366 6.763 H +ATOM 81 C6 MOL A 1 19.304 15.361 6.416 C +ATOM 82 C3 MOL A 1 20.373 10.885 7.012 C +ATOM 83 H4 MOL A 1 20.502 14.126 7.552 H +ATOM 84 H5 MOL A 1 19.009 14.131 8.043 H +ATOM 85 H6 MOL A 1 19.334 7.090 16.160 H +ATOM 86 H7 MOL A 1 18.037 7.485 15.366 H +ATOM 87 C2 MOL A 1 20.227 8.296 9.715 C +ATOM 88 H2 MOL A 1 18.622 8.447 11.014 H +ATOM 89 H6 MOL A 1 19.490 16.160 6.934 H +ATOM 90 H7 MOL A 1 19.885 15.366 5.637 H +ATOM 91 C2 MOL A 1 20.696 9.715 7.827 C +ATOM 92 H2 MOL A 1 20.847 11.014 6.222 H +ATOM 93 C1 MOL A 1 21.333 7.531 9.379 C +ATOM 94 C1 MOL A 1 19.931 9.379 8.933 C +ATOM 95 C1 MOL A 1 21.779 8.933 7.531 C +ATOM 96 H1 MOL A 1 21.551 6.795 9.905 H +ATOM 97 C2 MOL A 1 22.115 7.827 8.296 C +ATOM 98 H1 MOL A 1 19.195 9.905 9.151 H +ATOM 99 H1 MOL A 1 22.305 9.151 6.795 H +ATOM 100 C3 MOL A 1 23.285 7.012 7.973 C +ATOM 101 N1 MOL A 1 24.110 7.315 7.104 N +ATOM 102 H2 MOL A 1 23.414 6.222 8.447 H +END \ No newline at end of file diff --git a/tests/data/mol_system_rebuild.pdb b/tests/data/mol_system_rebuild.pdb new file mode 100644 index 0000000..166612f --- /dev/null +++ b/tests/data/mol_system_rebuild.pdb @@ -0,0 +1,170 @@ +REMARK File generated using pyWINDOW. +ATOM 1 C6 MOL A 1 9.439 5.984 6.904 C +ATOM 2 C6 MOL A 1 9.439 6.416 5.496 C +ATOM 3 C5 MOL A 1 10.679 5.144 7.177 C +ATOM 4 H6 MOL A 1 8.640 5.466 7.090 H +ATOM 5 H7 MOL A 1 9.434 6.763 7.485 H +ATOM 6 C5 MOL A 1 10.679 7.256 5.223 C +ATOM 7 H6 MOL A 1 8.640 6.934 5.310 H +ATOM 8 H7 MOL A 1 9.434 5.637 4.915 H +ATOM 9 C4 MOL A 1 11.939 5.952 6.907 C +ATOM 10 H4 MOL A 1 10.674 4.848 8.102 H +ATOM 11 H5 MOL A 1 10.669 4.357 6.609 H +ATOM 12 C4 MOL A 1 11.939 6.448 5.493 C +ATOM 13 H4 MOL A 1 10.674 7.552 4.298 H +ATOM 14 H5 MOL A 1 10.669 8.043 5.791 H +ATOM 15 N1 MOL A 1 13.090 5.085 7.104 N +ATOM 16 H3 MOL A 1 11.986 6.711 7.524 H +ATOM 17 N1 MOL A 1 13.090 7.315 5.296 N +ATOM 18 H3 MOL A 1 11.986 5.689 4.876 H +ATOM 19 C3 MOL A 1 13.915 5.388 7.973 C +ATOM 20 C3 MOL A 1 13.915 7.012 4.427 C +ATOM 21 C2 MOL A 1 15.085 4.573 8.296 C +ATOM 22 H2 MOL A 1 13.786 6.178 8.447 H +ATOM 23 C2 MOL A 1 15.085 7.827 4.104 C +ATOM 24 H2 MOL A 1 13.786 6.222 3.953 H +ATOM 25 C1 MOL A 1 15.867 4.869 9.379 C +ATOM 26 C1 MOL A 1 15.421 3.467 7.531 C +ATOM 27 C1 MOL A 1 15.867 7.531 3.021 C +ATOM 28 C1 MOL A 1 15.421 8.933 4.869 C +ATOM 29 C2 MOL A 1 16.973 4.104 9.715 C +ATOM 30 H1 MOL A 1 15.649 5.605 9.905 H +ATOM 31 H1 MOL A 1 14.895 3.249 6.795 H +ATOM 32 C2 MOL A 1 16.504 2.685 7.827 C +ATOM 33 C2 MOL A 1 16.973 8.296 2.685 C +ATOM 34 H1 MOL A 1 15.649 6.795 2.495 H +ATOM 35 H1 MOL A 1 14.895 9.151 5.605 H +ATOM 36 C2 MOL A 1 16.504 9.715 4.573 C +ATOM 37 C3 MOL A 1 17.788 4.427 10.885 C +ATOM 38 C1 MOL A 1 17.269 3.021 8.933 C +ATOM 39 C3 MOL A 1 16.827 1.515 7.012 C +ATOM 40 C3 MOL A 1 17.788 7.973 1.515 C +ATOM 41 C1 MOL A 1 17.269 9.379 3.467 C +ATOM 42 C3 MOL A 1 16.827 10.885 5.388 C +ATOM 43 N1 MOL A 1 17.485 5.296 11.710 N +ATOM 44 H2 MOL A 1 18.578 3.953 11.014 H +ATOM 45 H1 MOL A 1 18.005 2.495 9.151 H +ATOM 46 N1 MOL A 1 17.696 0.690 7.315 N +ATOM 47 H2 MOL A 1 16.353 1.386 6.222 H +ATOM 48 N1 MOL A 1 17.485 7.104 0.690 N +ATOM 49 H2 MOL A 1 18.578 8.447 1.386 H +ATOM 50 H1 MOL A 1 18.005 9.905 3.249 H +ATOM 51 N1 MOL A 1 17.696 11.710 5.085 N +ATOM 52 H2 MOL A 1 16.353 11.014 6.178 H +ATOM 53 C4 MOL A 1 18.352 5.493 12.861 C +ATOM 54 C4 MOL A 1 17.893 -0.461 6.448 C +ATOM 55 C4 MOL A 1 18.352 6.907 -0.461 C +ATOM 56 C4 MOL A 1 17.893 12.861 5.952 C +ATOM 57 C5 MOL A 1 17.544 5.223 14.121 C +ATOM 58 H3 MOL A 1 19.111 4.876 12.814 H +ATOM 59 C4 MOL A 1 18.848 6.907 12.861 C +ATOM 60 C5 MOL A 1 17.623 -1.721 7.256 C +ATOM 61 H3 MOL A 1 17.276 -0.414 5.689 H +ATOM 62 C4 MOL A 1 19.307 -0.461 5.952 C +ATOM 63 C4 MOL A 1 18.848 5.493 -0.461 C +ATOM 64 C5 MOL A 1 17.544 7.177 -1.721 C +ATOM 65 H3 MOL A 1 19.111 7.524 -0.414 H +ATOM 66 C5 MOL A 1 17.623 14.121 5.144 C +ATOM 67 H3 MOL A 1 17.276 12.814 6.711 H +ATOM 68 C4 MOL A 1 19.307 12.861 6.448 C +ATOM 69 C6 MOL A 1 18.384 5.496 15.361 C +ATOM 70 H4 MOL A 1 17.248 4.298 14.126 H +ATOM 71 H5 MOL A 1 16.757 5.791 14.131 H +ATOM 72 N1 MOL A 1 19.715 7.104 11.710 N +ATOM 73 C5 MOL A 1 19.656 7.177 14.121 C +ATOM 74 H3 MOL A 1 18.089 7.524 12.814 H +ATOM 75 C6 MOL A 1 17.896 -2.961 6.416 C +ATOM 76 H4 MOL A 1 16.698 -1.726 7.552 H +ATOM 77 H5 MOL A 1 18.191 -1.731 8.043 H +ATOM 78 N1 MOL A 1 19.504 0.690 5.085 N +ATOM 79 C5 MOL A 1 19.577 -1.721 5.144 C +ATOM 80 H3 MOL A 1 19.924 -0.414 6.711 H +ATOM 81 N1 MOL A 1 19.715 5.296 0.690 N +ATOM 82 C5 MOL A 1 19.656 5.223 -1.721 C +ATOM 83 H3 MOL A 1 18.089 4.876 -0.414 H +ATOM 84 C6 MOL A 1 18.384 6.904 -2.961 C +ATOM 85 H4 MOL A 1 17.248 8.102 -1.726 H +ATOM 86 H5 MOL A 1 16.757 6.609 -1.731 H +ATOM 87 C6 MOL A 1 17.896 15.361 5.984 C +ATOM 88 H4 MOL A 1 16.698 14.126 4.848 H +ATOM 89 H5 MOL A 1 18.191 14.131 4.357 H +ATOM 90 N1 MOL A 1 19.504 11.710 7.315 N +ATOM 91 C5 MOL A 1 19.577 14.121 7.256 C +ATOM 92 H3 MOL A 1 19.924 12.814 5.689 H +ATOM 93 H6 MOL A 1 17.866 5.310 16.160 H +ATOM 94 H7 MOL A 1 19.163 4.915 15.366 H +ATOM 95 C6 MOL A 1 18.816 6.904 15.361 C +ATOM 96 C3 MOL A 1 19.412 7.973 10.885 C +ATOM 97 H4 MOL A 1 19.952 8.102 14.126 H +ATOM 98 H5 MOL A 1 20.443 6.609 14.131 H +ATOM 99 H6 MOL A 1 17.710 -3.760 6.934 H +ATOM 100 H7 MOL A 1 17.315 -2.966 5.637 H +ATOM 101 C6 MOL A 1 19.304 -2.961 5.984 C +ATOM 102 C3 MOL A 1 20.373 1.515 5.388 C +ATOM 103 H4 MOL A 1 20.502 -1.726 4.848 H +ATOM 104 H5 MOL A 1 19.009 -1.731 4.357 H +ATOM 105 C3 MOL A 1 19.412 4.427 1.515 C +ATOM 106 C6 MOL A 1 18.816 5.496 -2.961 C +ATOM 107 H4 MOL A 1 19.952 4.298 -1.726 H +ATOM 108 H5 MOL A 1 20.443 5.791 -1.731 H +ATOM 109 H6 MOL A 1 17.866 7.090 -3.760 H +ATOM 110 H7 MOL A 1 19.163 7.485 -2.966 H +ATOM 111 H6 MOL A 1 17.710 16.160 5.466 H +ATOM 112 H7 MOL A 1 17.315 15.366 6.763 H +ATOM 113 C6 MOL A 1 19.304 15.361 6.416 C +ATOM 114 C3 MOL A 1 20.373 10.885 7.012 C +ATOM 115 H4 MOL A 1 20.502 14.126 7.552 H +ATOM 116 H5 MOL A 1 19.009 14.131 8.043 H +ATOM 117 H6 MOL A 1 19.334 7.090 16.160 H +ATOM 118 H7 MOL A 1 18.037 7.485 15.366 H +ATOM 119 C2 MOL A 1 20.227 8.296 9.715 C +ATOM 120 H2 MOL A 1 18.622 8.447 11.014 H +ATOM 121 H6 MOL A 1 19.490 -3.760 5.466 H +ATOM 122 H7 MOL A 1 19.885 -2.966 6.763 H +ATOM 123 C2 MOL A 1 20.696 2.685 4.573 C +ATOM 124 H2 MOL A 1 20.847 1.386 6.178 H +ATOM 125 C2 MOL A 1 20.227 4.104 2.685 C +ATOM 126 H2 MOL A 1 18.622 3.953 1.386 H +ATOM 127 H6 MOL A 1 19.334 5.310 -3.760 H +ATOM 128 H7 MOL A 1 18.037 4.915 -2.966 H +ATOM 129 H6 MOL A 1 19.490 16.160 6.934 H +ATOM 130 H7 MOL A 1 19.885 15.366 5.637 H +ATOM 131 C2 MOL A 1 20.696 9.715 7.827 C +ATOM 132 H2 MOL A 1 20.847 11.014 6.222 H +ATOM 133 C1 MOL A 1 21.333 7.531 9.379 C +ATOM 134 C1 MOL A 1 19.931 9.379 8.933 C +ATOM 135 C1 MOL A 1 21.779 3.467 4.869 C +ATOM 136 C1 MOL A 1 19.931 3.021 3.467 C +ATOM 137 C1 MOL A 1 21.333 4.869 3.021 C +ATOM 138 C1 MOL A 1 21.779 8.933 7.531 C +ATOM 139 H1 MOL A 1 21.551 6.795 9.905 H +ATOM 140 C2 MOL A 1 22.115 7.827 8.296 C +ATOM 141 H1 MOL A 1 19.195 9.905 9.151 H +ATOM 142 C2 MOL A 1 22.115 4.573 4.104 C +ATOM 143 H1 MOL A 1 22.305 3.249 5.605 H +ATOM 144 H1 MOL A 1 19.195 2.495 3.249 H +ATOM 145 H1 MOL A 1 21.551 5.605 2.495 H +ATOM 146 H1 MOL A 1 22.305 9.151 6.795 H +ATOM 147 C3 MOL A 1 23.285 7.012 7.973 C +ATOM 148 C3 MOL A 1 23.285 5.388 4.427 C +ATOM 149 N1 MOL A 1 24.110 7.315 7.104 N +ATOM 150 H2 MOL A 1 23.414 6.222 8.447 H +ATOM 151 N1 MOL A 1 24.110 5.085 5.296 N +ATOM 152 H2 MOL A 1 23.414 6.178 3.953 H +ATOM 153 C4 MOL A 1 25.261 6.448 6.907 C +ATOM 154 C4 MOL A 1 25.261 5.952 5.493 C +ATOM 155 C5 MOL A 1 26.521 7.256 7.177 C +ATOM 156 H3 MOL A 1 25.214 5.689 7.524 H +ATOM 157 C5 MOL A 1 26.521 5.144 5.223 C +ATOM 158 H3 MOL A 1 25.214 6.711 4.876 H +ATOM 159 C6 MOL A 1 27.761 6.416 6.904 C +ATOM 160 H4 MOL A 1 26.526 7.552 8.102 H +ATOM 161 H5 MOL A 1 26.531 8.043 6.609 H +ATOM 162 C6 MOL A 1 27.761 5.984 5.496 C +ATOM 163 H4 MOL A 1 26.526 4.848 4.298 H +ATOM 164 H5 MOL A 1 26.531 4.357 5.791 H +ATOM 165 H6 MOL A 1 28.560 6.934 7.090 H +ATOM 166 H7 MOL A 1 27.766 5.637 7.485 H +ATOM 167 H6 MOL A 1 28.560 5.466 5.310 H +ATOM 168 H7 MOL A 1 27.766 6.763 4.915 H +END \ No newline at end of file diff --git a/tests/data/system.pdb b/tests/data/system.pdb new file mode 100644 index 0000000..0449aec --- /dev/null +++ b/tests/data/system.pdb @@ -0,0 +1,170 @@ +REMARK File generated using pyWINDOW. +ATOM 1 N MOL A 1 11.496 13.515 17.910 N +ATOM 2 C MOL A 1 11.069 15.133 15.579 C +ATOM 3 C MOL A 1 10.304 14.027 15.915 C +ATOM 4 C MOL A 1 10.627 13.212 17.085 C +ATOM 5 C MOL A 1 11.693 12.648 19.061 C +ATOM 6 C MOL A 1 11.423 13.456 20.321 C +ATOM 7 C MOL A 1 11.696 12.616 21.561 C +ATOM 8 H MOL A 1 11.805 15.351 16.105 H +ATOM 9 H MOL A 1 10.153 12.422 17.214 H +ATOM 10 H MOL A 1 11.076 11.889 19.014 H +ATOM 11 H MOL A 1 10.498 13.752 20.326 H +ATOM 12 H MOL A 1 11.991 14.243 20.331 H +ATOM 13 H MOL A 1 11.510 13.134 22.360 H +ATOM 14 H MOL A 1 11.115 11.837 21.566 H +ATOM 15 N MOL A 1 13.304 11.285 17.910 N +ATOM 16 C MOL A 1 13.731 9.667 15.579 C +ATOM 17 C MOL A 1 14.496 10.773 15.915 C +ATOM 18 C MOL A 1 14.173 11.588 17.085 C +ATOM 19 C MOL A 1 13.107 12.152 19.061 C +ATOM 20 C MOL A 1 13.377 11.344 20.321 C +ATOM 21 C MOL A 1 13.104 12.184 21.561 C +ATOM 22 H MOL A 1 12.995 9.449 16.105 H +ATOM 23 H MOL A 1 14.647 12.378 17.214 H +ATOM 24 H MOL A 1 13.724 12.911 19.014 H +ATOM 25 H MOL A 1 14.302 11.048 20.326 H +ATOM 26 H MOL A 1 12.809 10.557 20.331 H +ATOM 27 H MOL A 1 13.290 11.666 22.360 H +ATOM 28 H MOL A 1 13.685 12.963 21.566 H +ATOM 29 N MOL A 1 11.496 11.285 6.890 N +ATOM 30 C MOL A 1 11.069 9.667 9.221 C +ATOM 31 C MOL A 1 10.304 10.773 8.885 C +ATOM 32 C MOL A 1 10.627 11.588 7.715 C +ATOM 33 C MOL A 1 11.693 12.152 5.739 C +ATOM 34 C MOL A 1 11.423 11.344 4.479 C +ATOM 35 C MOL A 1 11.696 12.184 3.239 C +ATOM 36 H MOL A 1 11.805 9.449 8.695 H +ATOM 37 H MOL A 1 10.153 12.378 7.586 H +ATOM 38 H MOL A 1 11.076 12.911 5.786 H +ATOM 39 H MOL A 1 10.498 11.048 4.474 H +ATOM 40 H MOL A 1 11.991 10.557 4.469 H +ATOM 41 H MOL A 1 11.510 11.666 2.440 H +ATOM 42 H MOL A 1 11.115 12.963 3.234 H +ATOM 43 N MOL A 1 13.304 13.515 6.890 N +ATOM 44 C MOL A 1 13.731 15.133 9.221 C +ATOM 45 C MOL A 1 14.496 14.027 8.885 C +ATOM 46 C MOL A 1 14.173 13.212 7.715 C +ATOM 47 C MOL A 1 13.107 12.648 5.739 C +ATOM 48 C MOL A 1 13.377 13.456 4.479 C +ATOM 49 C MOL A 1 13.104 12.616 3.239 C +ATOM 50 H MOL A 1 12.995 15.351 8.695 H +ATOM 51 H MOL A 1 14.647 12.422 7.586 H +ATOM 52 H MOL A 1 13.724 11.889 5.786 H +ATOM 53 H MOL A 1 14.302 13.752 4.474 H +ATOM 54 H MOL A 1 12.809 14.243 4.469 H +ATOM 55 H MOL A 1 13.290 13.134 2.440 H +ATOM 56 H MOL A 1 13.685 11.837 3.234 H +ATOM 57 N MOL A 1 13.515 6.890 13.304 N +ATOM 58 C MOL A 1 15.133 9.221 13.731 C +ATOM 59 C MOL A 1 14.027 8.885 14.496 C +ATOM 60 C MOL A 1 13.212 7.715 14.173 C +ATOM 61 C MOL A 1 12.648 5.739 13.107 C +ATOM 62 C MOL A 1 13.456 4.479 13.377 C +ATOM 63 C MOL A 1 12.616 3.239 13.104 C +ATOM 64 H MOL A 1 15.351 8.695 12.995 H +ATOM 65 H MOL A 1 12.422 7.586 14.647 H +ATOM 66 H MOL A 1 11.889 5.786 13.724 H +ATOM 67 H MOL A 1 13.752 4.474 14.302 H +ATOM 68 H MOL A 1 14.243 4.469 12.809 H +ATOM 69 H MOL A 1 13.134 2.440 13.290 H +ATOM 70 H MOL A 1 11.837 3.234 13.685 H +ATOM 71 N MOL A 1 11.285 6.890 11.496 N +ATOM 72 C MOL A 1 9.667 9.221 11.069 C +ATOM 73 C MOL A 1 10.773 8.885 10.304 C +ATOM 74 C MOL A 1 11.588 7.715 10.627 C +ATOM 75 C MOL A 1 12.152 5.739 11.693 C +ATOM 76 C MOL A 1 11.344 4.479 11.423 C +ATOM 77 C MOL A 1 12.184 3.239 11.696 C +ATOM 78 H MOL A 1 9.449 8.695 11.805 H +ATOM 79 H MOL A 1 12.378 7.586 10.153 H +ATOM 80 H MOL A 1 12.911 5.786 11.076 H +ATOM 81 H MOL A 1 11.048 4.474 10.498 H +ATOM 82 H MOL A 1 10.557 4.469 11.991 H +ATOM 83 H MOL A 1 11.666 2.440 11.510 H +ATOM 84 H MOL A 1 12.963 3.234 11.115 H +ATOM 85 N MOL A 1 11.285 17.910 13.304 N +ATOM 86 C MOL A 1 9.667 15.579 13.731 C +ATOM 87 C MOL A 1 10.773 15.915 14.496 C +ATOM 88 C MOL A 1 11.588 17.085 14.173 C +ATOM 89 C MOL A 1 12.152 19.061 13.107 C +ATOM 90 C MOL A 1 11.344 20.321 13.377 C +ATOM 91 C MOL A 1 12.184 21.561 13.104 C +ATOM 92 H MOL A 1 9.449 16.105 12.995 H +ATOM 93 H MOL A 1 12.378 17.214 14.647 H +ATOM 94 H MOL A 1 12.911 19.014 13.724 H +ATOM 95 H MOL A 1 11.048 20.326 14.302 H +ATOM 96 H MOL A 1 10.557 20.331 12.809 H +ATOM 97 H MOL A 1 11.666 22.360 13.290 H +ATOM 98 H MOL A 1 12.963 21.566 13.685 H +ATOM 99 N MOL A 1 13.515 17.910 11.496 N +ATOM 100 C MOL A 1 15.133 15.579 11.069 C +ATOM 101 C MOL A 1 14.027 15.915 10.304 C +ATOM 102 C MOL A 1 13.212 17.085 10.627 C +ATOM 103 C MOL A 1 12.648 19.061 11.693 C +ATOM 104 C MOL A 1 13.456 20.321 11.423 C +ATOM 105 C MOL A 1 12.616 21.561 11.696 C +ATOM 106 H MOL A 1 15.351 16.105 11.805 H +ATOM 107 H MOL A 1 12.422 17.214 10.153 H +ATOM 108 H MOL A 1 11.889 19.014 11.076 H +ATOM 109 H MOL A 1 13.752 20.326 10.498 H +ATOM 110 H MOL A 1 14.243 20.331 11.991 H +ATOM 111 H MOL A 1 13.134 22.360 11.510 H +ATOM 112 H MOL A 1 11.837 21.566 11.115 H +ATOM 113 N MOL A 1 6.890 11.496 11.285 N +ATOM 114 C MOL A 1 9.221 11.069 9.667 C +ATOM 115 C MOL A 1 8.885 10.304 10.773 C +ATOM 116 C MOL A 1 7.715 10.627 11.588 C +ATOM 117 C MOL A 1 5.739 11.693 12.152 C +ATOM 118 C MOL A 1 4.479 11.423 11.344 C +ATOM 119 C MOL A 1 3.239 11.696 12.184 C +ATOM 120 H MOL A 1 8.695 11.805 9.449 H +ATOM 121 H MOL A 1 7.586 10.153 12.378 H +ATOM 122 H MOL A 1 5.786 11.076 12.911 H +ATOM 123 H MOL A 1 4.474 10.498 11.048 H +ATOM 124 H MOL A 1 4.469 11.991 10.557 H +ATOM 125 H MOL A 1 2.440 11.510 11.666 H +ATOM 126 H MOL A 1 3.234 11.115 12.963 H +ATOM 127 N MOL A 1 6.890 13.304 13.515 N +ATOM 128 C MOL A 1 9.221 13.731 15.133 C +ATOM 129 C MOL A 1 8.885 14.496 14.027 C +ATOM 130 C MOL A 1 7.715 14.173 13.212 C +ATOM 131 C MOL A 1 5.739 13.107 12.648 C +ATOM 132 C MOL A 1 4.479 13.377 13.456 C +ATOM 133 C MOL A 1 3.239 13.104 12.616 C +ATOM 134 H MOL A 1 8.695 12.995 15.351 H +ATOM 135 H MOL A 1 7.586 14.647 12.422 H +ATOM 136 H MOL A 1 5.786 13.724 11.889 H +ATOM 137 H MOL A 1 4.474 14.302 13.752 H +ATOM 138 H MOL A 1 4.469 12.809 14.243 H +ATOM 139 H MOL A 1 2.440 13.290 13.134 H +ATOM 140 H MOL A 1 3.234 13.685 11.837 H +ATOM 141 N MOL A 1 17.910 11.496 13.515 N +ATOM 142 C MOL A 1 15.579 11.069 15.133 C +ATOM 143 C MOL A 1 15.915 10.304 14.027 C +ATOM 144 C MOL A 1 17.085 10.627 13.212 C +ATOM 145 C MOL A 1 19.061 11.693 12.648 C +ATOM 146 C MOL A 1 20.321 11.423 13.456 C +ATOM 147 C MOL A 1 21.561 11.696 12.616 C +ATOM 148 H MOL A 1 16.105 11.805 15.351 H +ATOM 149 H MOL A 1 17.214 10.153 12.422 H +ATOM 150 H MOL A 1 19.014 11.076 11.889 H +ATOM 151 H MOL A 1 20.326 10.498 13.752 H +ATOM 152 H MOL A 1 20.331 11.991 14.243 H +ATOM 153 H MOL A 1 22.360 11.510 13.134 H +ATOM 154 H MOL A 1 21.566 11.115 11.837 H +ATOM 155 N MOL A 1 17.910 13.304 11.285 N +ATOM 156 C MOL A 1 15.579 13.731 9.667 C +ATOM 157 C MOL A 1 15.915 14.496 10.773 C +ATOM 158 C MOL A 1 17.085 14.173 11.588 C +ATOM 159 C MOL A 1 19.061 13.107 12.152 C +ATOM 160 C MOL A 1 20.321 13.377 11.344 C +ATOM 161 C MOL A 1 21.561 13.104 12.184 C +ATOM 162 H MOL A 1 16.105 12.995 9.449 H +ATOM 163 H MOL A 1 17.214 14.647 12.378 H +ATOM 164 H MOL A 1 19.014 13.724 12.911 H +ATOM 165 H MOL A 1 20.326 14.302 11.048 H +ATOM 166 H MOL A 1 20.331 12.809 10.557 H +ATOM 167 H MOL A 1 22.360 13.290 11.666 H +ATOM 168 H MOL A 1 21.566 13.685 12.963 H +END \ No newline at end of file diff --git a/tests/data/system_periodic.pdb b/tests/data/system_periodic.pdb new file mode 100644 index 0000000..b14c8cd --- /dev/null +++ b/tests/data/system_periodic.pdb @@ -0,0 +1,1348 @@ +REMARK Materials Studio PDB file +REMARK Created: Wed Jul 26 11:23:20 GMT Standard Time 2017 +CRYST1 24.800 24.800 24.800 90.00 90.00 90.00 P1 +ATOM 1 N1 MOL A 1 19.715 5.296 0.690 N +ATOM 2 C1 MOL A 1 21.333 4.869 3.021 C +ATOM 3 C2 MOL A 1 20.227 4.104 2.685 C +ATOM 4 C3 MOL A 1 19.412 4.427 1.515 C +ATOM 5 C4 MOL A 1 18.848 5.493 24.339 C +ATOM 6 C5 MOL A 1 19.656 5.223 23.079 C +ATOM 7 C6 MOL A 1 18.816 5.496 21.839 C +ATOM 8 H1 MOL A 1 21.551 5.605 2.495 H +ATOM 9 H2 MOL A 1 18.622 3.953 1.386 H +ATOM 10 H3 MOL A 1 18.089 4.876 24.386 H +ATOM 11 H4 MOL A 1 19.952 4.298 23.074 H +ATOM 12 H5 MOL A 1 20.443 5.791 23.069 H +ATOM 13 H6 MOL A 1 19.334 5.310 21.040 H +ATOM 14 H7 MOL A 1 18.037 4.915 21.834 H +ATOM 15 N1 MOL A 1 19.715 17.696 13.090 N +ATOM 16 C1 MOL A 1 21.333 17.269 15.421 C +ATOM 17 C2 MOL A 1 20.227 16.504 15.085 C +ATOM 18 C3 MOL A 1 19.412 16.827 13.915 C +ATOM 19 C4 MOL A 1 18.848 17.893 11.939 C +ATOM 20 C5 MOL A 1 19.656 17.623 10.679 C +ATOM 21 C6 MOL A 1 18.816 17.896 9.439 C +ATOM 22 H1 MOL A 1 21.551 18.005 14.895 H +ATOM 23 H2 MOL A 1 18.622 16.353 13.786 H +ATOM 24 H3 MOL A 1 18.089 17.276 11.986 H +ATOM 25 H4 MOL A 1 19.952 16.698 10.674 H +ATOM 26 H5 MOL A 1 20.443 18.191 10.669 H +ATOM 27 H6 MOL A 1 19.334 17.710 8.640 H +ATOM 28 H7 MOL A 1 18.037 17.315 9.434 H +ATOM 29 N1 MOL A 1 7.315 5.296 13.090 N +ATOM 30 C1 MOL A 1 8.933 4.869 15.421 C +ATOM 31 C2 MOL A 1 7.827 4.104 15.085 C +ATOM 32 C3 MOL A 1 7.012 4.427 13.915 C +ATOM 33 C4 MOL A 1 6.448 5.493 11.939 C +ATOM 34 C5 MOL A 1 7.256 5.223 10.679 C +ATOM 35 C6 MOL A 1 6.416 5.496 9.439 C +ATOM 36 H1 MOL A 1 9.151 5.605 14.895 H +ATOM 37 H2 MOL A 1 6.222 3.953 13.786 H +ATOM 38 H3 MOL A 1 5.689 4.876 11.986 H +ATOM 39 H4 MOL A 1 7.552 4.298 10.674 H +ATOM 40 H5 MOL A 1 8.043 5.791 10.669 H +ATOM 41 H6 MOL A 1 6.934 5.310 8.640 H +ATOM 42 H7 MOL A 1 5.637 4.915 9.434 H +ATOM 43 N1 MOL A 1 7.315 17.696 0.690 N +ATOM 44 C1 MOL A 1 8.933 17.269 3.021 C +ATOM 45 C2 MOL A 1 7.827 16.504 2.685 C +ATOM 46 C3 MOL A 1 7.012 16.827 1.515 C +ATOM 47 C4 MOL A 1 6.448 17.893 24.339 C +ATOM 48 C5 MOL A 1 7.256 17.623 23.079 C +ATOM 49 C6 MOL A 1 6.416 17.896 21.839 C +ATOM 50 H1 MOL A 1 9.151 18.005 2.495 H +ATOM 51 H2 MOL A 1 6.222 16.353 1.386 H +ATOM 52 H3 MOL A 1 5.689 17.276 24.386 H +ATOM 53 H4 MOL A 1 7.552 16.698 23.074 H +ATOM 54 H5 MOL A 1 8.043 18.191 23.069 H +ATOM 55 H6 MOL A 1 6.934 17.710 21.040 H +ATOM 56 H7 MOL A 1 5.637 17.315 21.834 H +ATOM 57 N1 MOL A 1 5.085 7.104 13.090 N +ATOM 58 C1 MOL A 1 3.467 7.531 15.421 C +ATOM 59 C2 MOL A 1 4.573 8.296 15.085 C +ATOM 60 C3 MOL A 1 5.388 7.973 13.915 C +ATOM 61 C4 MOL A 1 5.952 6.907 11.939 C +ATOM 62 C5 MOL A 1 5.144 7.177 10.679 C +ATOM 63 C6 MOL A 1 5.984 6.904 9.439 C +ATOM 64 H1 MOL A 1 3.249 6.795 14.895 H +ATOM 65 H2 MOL A 1 6.178 8.447 13.786 H +ATOM 66 H3 MOL A 1 6.711 7.524 11.986 H +ATOM 67 H4 MOL A 1 4.848 8.102 10.674 H +ATOM 68 H5 MOL A 1 4.357 6.609 10.669 H +ATOM 69 H6 MOL A 1 5.466 7.090 8.640 H +ATOM 70 H7 MOL A 1 6.763 7.485 9.434 H +ATOM 71 N1 MOL A 1 5.085 19.504 0.690 N +ATOM 72 C1 MOL A 1 3.467 19.931 3.021 C +ATOM 73 C2 MOL A 1 4.573 20.696 2.685 C +ATOM 74 C3 MOL A 1 5.388 20.373 1.515 C +ATOM 75 C4 MOL A 1 5.952 19.307 24.339 C +ATOM 76 C5 MOL A 1 5.144 19.577 23.079 C +ATOM 77 C6 MOL A 1 5.984 19.304 21.839 C +ATOM 78 H1 MOL A 1 3.249 19.195 2.495 H +ATOM 79 H2 MOL A 1 6.178 20.847 1.386 H +ATOM 80 H3 MOL A 1 6.711 19.924 24.386 H +ATOM 81 H4 MOL A 1 4.848 20.502 23.074 H +ATOM 82 H5 MOL A 1 4.357 19.009 23.069 H +ATOM 83 H6 MOL A 1 5.466 19.490 21.040 H +ATOM 84 H7 MOL A 1 6.763 19.885 21.834 H +ATOM 85 N1 MOL A 1 17.485 7.104 0.690 N +ATOM 86 C1 MOL A 1 15.867 7.531 3.021 C +ATOM 87 C2 MOL A 1 16.973 8.296 2.685 C +ATOM 88 C3 MOL A 1 17.788 7.973 1.515 C +ATOM 89 C4 MOL A 1 18.352 6.907 24.339 C +ATOM 90 C5 MOL A 1 17.544 7.177 23.079 C +ATOM 91 C6 MOL A 1 18.384 6.904 21.839 C +ATOM 92 H1 MOL A 1 15.649 6.795 2.495 H +ATOM 93 H2 MOL A 1 18.578 8.447 1.386 H +ATOM 94 H3 MOL A 1 19.111 7.524 24.386 H +ATOM 95 H4 MOL A 1 17.248 8.102 23.074 H +ATOM 96 H5 MOL A 1 16.757 6.609 23.069 H +ATOM 97 H6 MOL A 1 17.866 7.090 21.040 H +ATOM 98 H7 MOL A 1 19.163 7.485 21.834 H +ATOM 99 N1 MOL A 1 17.485 19.504 13.090 N +ATOM 100 C1 MOL A 1 15.867 19.931 15.421 C +ATOM 101 C2 MOL A 1 16.973 20.696 15.085 C +ATOM 102 C3 MOL A 1 17.788 20.373 13.915 C +ATOM 103 C4 MOL A 1 18.352 19.307 11.939 C +ATOM 104 C5 MOL A 1 17.544 19.577 10.679 C +ATOM 105 C6 MOL A 1 18.384 19.304 9.439 C +ATOM 106 H1 MOL A 1 15.649 19.195 14.895 H +ATOM 107 H2 MOL A 1 18.578 20.847 13.786 H +ATOM 108 H3 MOL A 1 19.111 19.924 11.986 H +ATOM 109 H4 MOL A 1 17.248 20.502 10.674 H +ATOM 110 H5 MOL A 1 16.757 19.009 10.669 H +ATOM 111 H6 MOL A 1 17.866 19.490 8.640 H +ATOM 112 H7 MOL A 1 19.163 19.885 9.434 H +ATOM 113 N1 MOL A 1 17.485 17.696 24.110 N +ATOM 114 C1 MOL A 1 15.867 17.269 21.779 C +ATOM 115 C2 MOL A 1 16.973 16.504 22.115 C +ATOM 116 C3 MOL A 1 17.788 16.827 23.285 C +ATOM 117 C4 MOL A 1 18.352 17.893 0.461 C +ATOM 118 C5 MOL A 1 17.544 17.623 1.721 C +ATOM 119 C6 MOL A 1 18.384 17.896 2.961 C +ATOM 120 H1 MOL A 1 15.649 18.005 22.305 H +ATOM 121 H2 MOL A 1 18.578 16.353 23.414 H +ATOM 122 H3 MOL A 1 19.111 17.276 0.414 H +ATOM 123 H4 MOL A 1 17.248 16.698 1.726 H +ATOM 124 H5 MOL A 1 16.757 18.191 1.731 H +ATOM 125 H6 MOL A 1 17.866 17.710 3.760 H +ATOM 126 H7 MOL A 1 19.163 17.315 2.966 H +ATOM 127 N1 MOL A 1 17.485 5.296 11.710 N +ATOM 128 C1 MOL A 1 15.867 4.869 9.379 C +ATOM 129 C2 MOL A 1 16.973 4.104 9.715 C +ATOM 130 C3 MOL A 1 17.788 4.427 10.885 C +ATOM 131 C4 MOL A 1 18.352 5.493 12.861 C +ATOM 132 C5 MOL A 1 17.544 5.223 14.121 C +ATOM 133 C6 MOL A 1 18.384 5.496 15.361 C +ATOM 134 H1 MOL A 1 15.649 5.605 9.905 H +ATOM 135 H2 MOL A 1 18.578 3.953 11.014 H +ATOM 136 H3 MOL A 1 19.111 4.876 12.814 H +ATOM 137 H4 MOL A 1 17.248 4.298 14.126 H +ATOM 138 H5 MOL A 1 16.757 5.791 14.131 H +ATOM 139 H6 MOL A 1 17.866 5.310 16.160 H +ATOM 140 H7 MOL A 1 19.163 4.915 15.366 H +ATOM 141 N1 MOL A 1 5.085 17.696 11.710 N +ATOM 142 C1 MOL A 1 3.467 17.269 9.379 C +ATOM 143 C2 MOL A 1 4.573 16.504 9.715 C +ATOM 144 C3 MOL A 1 5.388 16.827 10.885 C +ATOM 145 C4 MOL A 1 5.952 17.893 12.861 C +ATOM 146 C5 MOL A 1 5.144 17.623 14.121 C +ATOM 147 C6 MOL A 1 5.984 17.896 15.361 C +ATOM 148 H1 MOL A 1 3.249 18.005 9.905 H +ATOM 149 H2 MOL A 1 6.178 16.353 11.014 H +ATOM 150 H3 MOL A 1 6.711 17.276 12.814 H +ATOM 151 H4 MOL A 1 4.848 16.698 14.126 H +ATOM 152 H5 MOL A 1 4.357 18.191 14.131 H +ATOM 153 H6 MOL A 1 5.466 17.710 16.160 H +ATOM 154 H7 MOL A 1 6.763 17.315 15.366 H +ATOM 155 N1 MOL A 1 5.085 5.296 24.110 N +ATOM 156 C1 MOL A 1 3.467 4.869 21.779 C +ATOM 157 C2 MOL A 1 4.573 4.104 22.115 C +ATOM 158 C3 MOL A 1 5.388 4.427 23.285 C +ATOM 159 C4 MOL A 1 5.952 5.493 0.461 C +ATOM 160 C5 MOL A 1 5.144 5.223 1.721 C +ATOM 161 C6 MOL A 1 5.984 5.496 2.961 C +ATOM 162 H1 MOL A 1 3.249 5.605 22.305 H +ATOM 163 H2 MOL A 1 6.178 3.953 23.414 H +ATOM 164 H3 MOL A 1 6.711 4.876 0.414 H +ATOM 165 H4 MOL A 1 4.848 4.298 1.726 H +ATOM 166 H5 MOL A 1 4.357 5.791 1.731 H +ATOM 167 H6 MOL A 1 5.466 5.310 3.760 H +ATOM 168 H7 MOL A 1 6.763 4.915 2.966 H +ATOM 169 N1 MOL A 1 7.315 19.504 11.710 N +ATOM 170 C1 MOL A 1 8.933 19.931 9.379 C +ATOM 171 C2 MOL A 1 7.827 20.696 9.715 C +ATOM 172 C3 MOL A 1 7.012 20.373 10.885 C +ATOM 173 C4 MOL A 1 6.448 19.307 12.861 C +ATOM 174 C5 MOL A 1 7.256 19.577 14.121 C +ATOM 175 C6 MOL A 1 6.416 19.304 15.361 C +ATOM 176 H1 MOL A 1 9.151 19.195 9.905 H +ATOM 177 H2 MOL A 1 6.222 20.847 11.014 H +ATOM 178 H3 MOL A 1 5.689 19.924 12.814 H +ATOM 179 H4 MOL A 1 7.552 20.502 14.126 H +ATOM 180 H5 MOL A 1 8.043 19.009 14.131 H +ATOM 181 H6 MOL A 1 6.934 19.490 16.160 H +ATOM 182 H7 MOL A 1 5.637 19.885 15.366 H +ATOM 183 N1 MOL A 1 7.315 7.104 24.110 N +ATOM 184 C1 MOL A 1 8.933 7.531 21.779 C +ATOM 185 C2 MOL A 1 7.827 8.296 22.115 C +ATOM 186 C3 MOL A 1 7.012 7.973 23.285 C +ATOM 187 C4 MOL A 1 6.448 6.907 0.461 C +ATOM 188 C5 MOL A 1 7.256 7.177 1.721 C +ATOM 189 C6 MOL A 1 6.416 6.904 2.961 C +ATOM 190 H1 MOL A 1 9.151 6.795 22.305 H +ATOM 191 H2 MOL A 1 6.222 8.447 23.414 H +ATOM 192 H3 MOL A 1 5.689 7.524 0.414 H +ATOM 193 H4 MOL A 1 7.552 8.102 1.726 H +ATOM 194 H5 MOL A 1 8.043 6.609 1.731 H +ATOM 195 H6 MOL A 1 6.934 7.090 3.760 H +ATOM 196 H7 MOL A 1 5.637 7.485 2.966 H +ATOM 197 N1 MOL A 1 19.715 19.504 24.110 N +ATOM 198 C1 MOL A 1 21.333 19.931 21.779 C +ATOM 199 C2 MOL A 1 20.227 20.696 22.115 C +ATOM 200 C3 MOL A 1 19.412 20.373 23.285 C +ATOM 201 C4 MOL A 1 18.848 19.307 0.461 C +ATOM 202 C5 MOL A 1 19.656 19.577 1.721 C +ATOM 203 C6 MOL A 1 18.816 19.304 2.961 C +ATOM 204 H1 MOL A 1 21.551 19.195 22.305 H +ATOM 205 H2 MOL A 1 18.622 20.847 23.414 H +ATOM 206 H3 MOL A 1 18.089 19.924 0.414 H +ATOM 207 H4 MOL A 1 19.952 20.502 1.726 H +ATOM 208 H5 MOL A 1 20.443 19.009 1.731 H +ATOM 209 H6 MOL A 1 19.334 19.490 3.760 H +ATOM 210 H7 MOL A 1 18.037 19.885 2.966 H +ATOM 211 N1 MOL A 1 19.715 7.104 11.710 N +ATOM 212 C1 MOL A 1 21.333 7.531 9.379 C +ATOM 213 C2 MOL A 1 20.227 8.296 9.715 C +ATOM 214 C3 MOL A 1 19.412 7.973 10.885 C +ATOM 215 C4 MOL A 1 18.848 6.907 12.861 C +ATOM 216 C5 MOL A 1 19.656 7.177 14.121 C +ATOM 217 C6 MOL A 1 18.816 6.904 15.361 C +ATOM 218 H1 MOL A 1 21.551 6.795 9.905 H +ATOM 219 H2 MOL A 1 18.622 8.447 11.014 H +ATOM 220 H3 MOL A 1 18.089 7.524 12.814 H +ATOM 221 H4 MOL A 1 19.952 8.102 14.126 H +ATOM 222 H5 MOL A 1 20.443 6.609 14.131 H +ATOM 223 H6 MOL A 1 19.334 7.090 16.160 H +ATOM 224 H7 MOL A 1 18.037 7.485 15.366 H +ATOM 225 N1 MOL A 1 0.690 19.715 5.296 N +ATOM 226 C1 MOL A 1 3.021 21.333 4.869 C +ATOM 227 C2 MOL A 1 2.685 20.227 4.104 C +ATOM 228 C3 MOL A 1 1.515 19.412 4.427 C +ATOM 229 C4 MOL A 1 24.339 18.848 5.493 C +ATOM 230 C5 MOL A 1 23.079 19.656 5.223 C +ATOM 231 C6 MOL A 1 21.839 18.816 5.496 C +ATOM 232 H1 MOL A 1 2.495 21.551 5.605 H +ATOM 233 H2 MOL A 1 1.386 18.622 3.953 H +ATOM 234 H3 MOL A 1 24.386 18.089 4.876 H +ATOM 235 H4 MOL A 1 23.074 19.952 4.298 H +ATOM 236 H5 MOL A 1 23.069 20.443 5.791 H +ATOM 237 H6 MOL A 1 21.040 19.334 5.310 H +ATOM 238 H7 MOL A 1 21.834 18.037 4.915 H +ATOM 239 N1 MOL A 1 0.690 7.315 17.696 N +ATOM 240 C1 MOL A 1 3.021 8.933 17.269 C +ATOM 241 C2 MOL A 1 2.685 7.827 16.504 C +ATOM 242 C3 MOL A 1 1.515 7.012 16.827 C +ATOM 243 C4 MOL A 1 24.339 6.448 17.893 C +ATOM 244 C5 MOL A 1 23.079 7.256 17.623 C +ATOM 245 C6 MOL A 1 21.839 6.416 17.896 C +ATOM 246 H1 MOL A 1 2.495 9.151 18.005 H +ATOM 247 H2 MOL A 1 1.386 6.222 16.353 H +ATOM 248 H3 MOL A 1 24.386 5.689 17.276 H +ATOM 249 H4 MOL A 1 23.074 7.552 16.698 H +ATOM 250 H5 MOL A 1 23.069 8.043 18.191 H +ATOM 251 H6 MOL A 1 21.040 6.934 17.710 H +ATOM 252 H7 MOL A 1 21.834 5.637 17.315 H +ATOM 253 N1 MOL A 1 13.090 19.715 17.696 N +ATOM 254 C1 MOL A 1 15.421 21.333 17.269 C +ATOM 255 C2 MOL A 1 15.085 20.227 16.504 C +ATOM 256 C3 MOL A 1 13.915 19.412 16.827 C +ATOM 257 C4 MOL A 1 11.939 18.848 17.893 C +ATOM 258 C5 MOL A 1 10.679 19.656 17.623 C +ATOM 259 C6 MOL A 1 9.439 18.816 17.896 C +ATOM 260 H1 MOL A 1 14.895 21.551 18.005 H +ATOM 261 H2 MOL A 1 13.786 18.622 16.353 H +ATOM 262 H3 MOL A 1 11.986 18.089 17.276 H +ATOM 263 H4 MOL A 1 10.674 19.952 16.698 H +ATOM 264 H5 MOL A 1 10.669 20.443 18.191 H +ATOM 265 H6 MOL A 1 8.640 19.334 17.710 H +ATOM 266 H7 MOL A 1 9.434 18.037 17.315 H +ATOM 267 N1 MOL A 1 13.090 7.315 5.296 N +ATOM 268 C1 MOL A 1 15.421 8.933 4.869 C +ATOM 269 C2 MOL A 1 15.085 7.827 4.104 C +ATOM 270 C3 MOL A 1 13.915 7.012 4.427 C +ATOM 271 C4 MOL A 1 11.939 6.448 5.493 C +ATOM 272 C5 MOL A 1 10.679 7.256 5.223 C +ATOM 273 C6 MOL A 1 9.439 6.416 5.496 C +ATOM 274 H1 MOL A 1 14.895 9.151 5.605 H +ATOM 275 H2 MOL A 1 13.786 6.222 3.953 H +ATOM 276 H3 MOL A 1 11.986 5.689 4.876 H +ATOM 277 H4 MOL A 1 10.674 7.552 4.298 H +ATOM 278 H5 MOL A 1 10.669 8.043 5.791 H +ATOM 279 H6 MOL A 1 8.640 6.934 5.310 H +ATOM 280 H7 MOL A 1 9.434 5.637 4.915 H +ATOM 281 N1 MOL A 1 13.090 5.085 7.104 N +ATOM 282 C1 MOL A 1 15.421 3.467 7.531 C +ATOM 283 C2 MOL A 1 15.085 4.573 8.296 C +ATOM 284 C3 MOL A 1 13.915 5.388 7.973 C +ATOM 285 C4 MOL A 1 11.939 5.952 6.907 C +ATOM 286 C5 MOL A 1 10.679 5.144 7.177 C +ATOM 287 C6 MOL A 1 9.439 5.984 6.904 C +ATOM 288 H1 MOL A 1 14.895 3.249 6.795 H +ATOM 289 H2 MOL A 1 13.786 6.178 8.447 H +ATOM 290 H3 MOL A 1 11.986 6.711 7.524 H +ATOM 291 H4 MOL A 1 10.674 4.848 8.102 H +ATOM 292 H5 MOL A 1 10.669 4.357 6.609 H +ATOM 293 H6 MOL A 1 8.640 5.466 7.090 H +ATOM 294 H7 MOL A 1 9.434 6.763 7.485 H +ATOM 295 N1 MOL A 1 13.090 17.485 19.504 N +ATOM 296 C1 MOL A 1 15.421 15.867 19.931 C +ATOM 297 C2 MOL A 1 15.085 16.973 20.696 C +ATOM 298 C3 MOL A 1 13.915 17.788 20.373 C +ATOM 299 C4 MOL A 1 11.939 18.352 19.307 C +ATOM 300 C5 MOL A 1 10.679 17.544 19.577 C +ATOM 301 C6 MOL A 1 9.439 18.384 19.304 C +ATOM 302 H1 MOL A 1 14.895 15.649 19.195 H +ATOM 303 H2 MOL A 1 13.786 18.578 20.847 H +ATOM 304 H3 MOL A 1 11.986 19.111 19.924 H +ATOM 305 H4 MOL A 1 10.674 17.248 20.502 H +ATOM 306 H5 MOL A 1 10.669 16.757 19.009 H +ATOM 307 H6 MOL A 1 8.640 17.866 19.490 H +ATOM 308 H7 MOL A 1 9.434 19.163 19.885 H +ATOM 309 N1 MOL A 1 0.690 5.085 19.504 N +ATOM 310 C1 MOL A 1 3.021 3.467 19.931 C +ATOM 311 C2 MOL A 1 2.685 4.573 20.696 C +ATOM 312 C3 MOL A 1 1.515 5.388 20.373 C +ATOM 313 C4 MOL A 1 24.339 5.952 19.307 C +ATOM 314 C5 MOL A 1 23.079 5.144 19.577 C +ATOM 315 C6 MOL A 1 21.839 5.984 19.304 C +ATOM 316 H1 MOL A 1 2.495 3.249 19.195 H +ATOM 317 H2 MOL A 1 1.386 6.178 20.847 H +ATOM 318 H3 MOL A 1 24.386 6.711 19.924 H +ATOM 319 H4 MOL A 1 23.074 4.848 20.502 H +ATOM 320 H5 MOL A 1 23.069 4.357 19.009 H +ATOM 321 H6 MOL A 1 21.040 5.466 19.490 H +ATOM 322 H7 MOL A 1 21.834 6.763 19.885 H +ATOM 323 N1 MOL A 1 0.690 17.485 7.104 N +ATOM 324 C1 MOL A 1 3.021 15.867 7.531 C +ATOM 325 C2 MOL A 1 2.685 16.973 8.296 C +ATOM 326 C3 MOL A 1 1.515 17.788 7.973 C +ATOM 327 C4 MOL A 1 24.339 18.352 6.907 C +ATOM 328 C5 MOL A 1 23.079 17.544 7.177 C +ATOM 329 C6 MOL A 1 21.839 18.384 6.904 C +ATOM 330 H1 MOL A 1 2.495 15.649 6.795 H +ATOM 331 H2 MOL A 1 1.386 18.578 8.447 H +ATOM 332 H3 MOL A 1 24.386 19.111 7.524 H +ATOM 333 H4 MOL A 1 23.074 17.248 8.102 H +ATOM 334 H5 MOL A 1 23.069 16.757 6.609 H +ATOM 335 H6 MOL A 1 21.040 17.866 7.090 H +ATOM 336 H7 MOL A 1 21.834 19.163 7.485 H +ATOM 337 N1 MOL A 1 24.110 17.485 17.696 N +ATOM 338 C1 MOL A 1 21.779 15.867 17.269 C +ATOM 339 C2 MOL A 1 22.115 16.973 16.504 C +ATOM 340 C3 MOL A 1 23.285 17.788 16.827 C +ATOM 341 C4 MOL A 1 0.461 18.352 17.893 C +ATOM 342 C5 MOL A 1 1.721 17.544 17.623 C +ATOM 343 C6 MOL A 1 2.961 18.384 17.896 C +ATOM 344 H1 MOL A 1 22.305 15.649 18.005 H +ATOM 345 H2 MOL A 1 23.414 18.578 16.353 H +ATOM 346 H3 MOL A 1 0.414 19.111 17.276 H +ATOM 347 H4 MOL A 1 1.726 17.248 16.698 H +ATOM 348 H5 MOL A 1 1.731 16.757 18.191 H +ATOM 349 H6 MOL A 1 3.760 17.866 17.710 H +ATOM 350 H7 MOL A 1 2.966 19.163 17.315 H +ATOM 351 N1 MOL A 1 24.110 5.085 5.296 N +ATOM 352 C1 MOL A 1 21.779 3.467 4.869 C +ATOM 353 C2 MOL A 1 22.115 4.573 4.104 C +ATOM 354 C3 MOL A 1 23.285 5.388 4.427 C +ATOM 355 C4 MOL A 1 0.461 5.952 5.493 C +ATOM 356 C5 MOL A 1 1.721 5.144 5.223 C +ATOM 357 C6 MOL A 1 2.961 5.984 5.496 C +ATOM 358 H1 MOL A 1 22.305 3.249 5.605 H +ATOM 359 H2 MOL A 1 23.414 6.178 3.953 H +ATOM 360 H3 MOL A 1 0.414 6.711 4.876 H +ATOM 361 H4 MOL A 1 1.726 4.848 4.298 H +ATOM 362 H5 MOL A 1 1.731 4.357 5.791 H +ATOM 363 H6 MOL A 1 3.760 5.466 5.310 H +ATOM 364 H7 MOL A 1 2.966 6.763 4.915 H +ATOM 365 N1 MOL A 1 11.710 17.485 5.296 N +ATOM 366 C1 MOL A 1 9.379 15.867 4.869 C +ATOM 367 C2 MOL A 1 9.715 16.973 4.104 C +ATOM 368 C3 MOL A 1 10.885 17.788 4.427 C +ATOM 369 C4 MOL A 1 12.861 18.352 5.493 C +ATOM 370 C5 MOL A 1 14.121 17.544 5.223 C +ATOM 371 C6 MOL A 1 15.361 18.384 5.496 C +ATOM 372 H1 MOL A 1 9.905 15.649 5.605 H +ATOM 373 H2 MOL A 1 11.014 18.578 3.953 H +ATOM 374 H3 MOL A 1 12.814 19.111 4.876 H +ATOM 375 H4 MOL A 1 14.126 17.248 4.298 H +ATOM 376 H5 MOL A 1 14.131 16.757 5.791 H +ATOM 377 H6 MOL A 1 16.160 17.866 5.310 H +ATOM 378 H7 MOL A 1 15.366 19.163 4.915 H +ATOM 379 N1 MOL A 1 11.710 5.085 17.696 N +ATOM 380 C1 MOL A 1 9.379 3.467 17.269 C +ATOM 381 C2 MOL A 1 9.715 4.573 16.504 C +ATOM 382 C3 MOL A 1 10.885 5.388 16.827 C +ATOM 383 C4 MOL A 1 12.861 5.952 17.893 C +ATOM 384 C5 MOL A 1 14.121 5.144 17.623 C +ATOM 385 C6 MOL A 1 15.361 5.984 17.896 C +ATOM 386 H1 MOL A 1 9.905 3.249 18.005 H +ATOM 387 H2 MOL A 1 11.014 6.178 16.353 H +ATOM 388 H3 MOL A 1 12.814 6.711 17.276 H +ATOM 389 H4 MOL A 1 14.126 4.848 16.698 H +ATOM 390 H5 MOL A 1 14.131 4.357 18.191 H +ATOM 391 H6 MOL A 1 16.160 5.466 17.710 H +ATOM 392 H7 MOL A 1 15.366 6.763 17.315 H +ATOM 393 N1 MOL A 1 11.710 7.315 19.504 N +ATOM 394 C1 MOL A 1 9.379 8.933 19.931 C +ATOM 395 C2 MOL A 1 9.715 7.827 20.696 C +ATOM 396 C3 MOL A 1 10.885 7.012 20.373 C +ATOM 397 C4 MOL A 1 12.861 6.448 19.307 C +ATOM 398 C5 MOL A 1 14.121 7.256 19.577 C +ATOM 399 C6 MOL A 1 15.361 6.416 19.304 C +ATOM 400 H1 MOL A 1 9.905 9.151 19.195 H +ATOM 401 H2 MOL A 1 11.014 6.222 20.847 H +ATOM 402 H3 MOL A 1 12.814 5.689 19.924 H +ATOM 403 H4 MOL A 1 14.126 7.552 20.502 H +ATOM 404 H5 MOL A 1 14.131 8.043 19.009 H +ATOM 405 H6 MOL A 1 16.160 6.934 19.490 H +ATOM 406 H7 MOL A 1 15.366 5.637 19.885 H +ATOM 407 N1 MOL A 1 11.710 19.715 7.104 N +ATOM 408 C1 MOL A 1 9.379 21.333 7.531 C +ATOM 409 C2 MOL A 1 9.715 20.227 8.296 C +ATOM 410 C3 MOL A 1 10.885 19.412 7.973 C +ATOM 411 C4 MOL A 1 12.861 18.848 6.907 C +ATOM 412 C5 MOL A 1 14.121 19.656 7.177 C +ATOM 413 C6 MOL A 1 15.361 18.816 6.904 C +ATOM 414 H1 MOL A 1 9.905 21.551 6.795 H +ATOM 415 H2 MOL A 1 11.014 18.622 8.447 H +ATOM 416 H3 MOL A 1 12.814 18.089 7.524 H +ATOM 417 H4 MOL A 1 14.126 19.952 8.102 H +ATOM 418 H5 MOL A 1 14.131 20.443 6.609 H +ATOM 419 H6 MOL A 1 16.160 19.334 7.090 H +ATOM 420 H7 MOL A 1 15.366 18.037 7.485 H +ATOM 421 N1 MOL A 1 24.110 7.315 7.104 N +ATOM 422 C1 MOL A 1 21.779 8.933 7.531 C +ATOM 423 C2 MOL A 1 22.115 7.827 8.296 C +ATOM 424 C3 MOL A 1 23.285 7.012 7.973 C +ATOM 425 C4 MOL A 1 0.461 6.448 6.907 C +ATOM 426 C5 MOL A 1 1.721 7.256 7.177 C +ATOM 427 C6 MOL A 1 2.961 6.416 6.904 C +ATOM 428 H1 MOL A 1 22.305 9.151 6.795 H +ATOM 429 H2 MOL A 1 23.414 6.222 8.447 H +ATOM 430 H3 MOL A 1 0.414 5.689 7.524 H +ATOM 431 H4 MOL A 1 1.726 7.552 8.102 H +ATOM 432 H5 MOL A 1 1.731 8.043 6.609 H +ATOM 433 H6 MOL A 1 3.760 6.934 7.090 H +ATOM 434 H7 MOL A 1 2.966 5.637 7.485 H +ATOM 435 N1 MOL A 1 24.110 19.715 19.504 N +ATOM 436 C1 MOL A 1 21.779 21.333 19.931 C +ATOM 437 C2 MOL A 1 22.115 20.227 20.696 C +ATOM 438 C3 MOL A 1 23.285 19.412 20.373 C +ATOM 439 C4 MOL A 1 0.461 18.848 19.307 C +ATOM 440 C5 MOL A 1 1.721 19.656 19.577 C +ATOM 441 C6 MOL A 1 2.961 18.816 19.304 C +ATOM 442 H1 MOL A 1 22.305 21.551 19.195 H +ATOM 443 H2 MOL A 1 23.414 18.622 20.847 H +ATOM 444 H3 MOL A 1 0.414 18.089 19.924 H +ATOM 445 H4 MOL A 1 1.726 19.952 20.502 H +ATOM 446 H5 MOL A 1 1.731 20.443 19.009 H +ATOM 447 H6 MOL A 1 3.760 19.334 19.490 H +ATOM 448 H7 MOL A 1 2.966 18.037 19.885 H +ATOM 449 N1 MOL A 1 5.296 0.690 19.715 N +ATOM 450 C1 MOL A 1 4.869 3.021 21.333 C +ATOM 451 C2 MOL A 1 4.104 2.685 20.227 C +ATOM 452 C3 MOL A 1 4.427 1.515 19.412 C +ATOM 453 C4 MOL A 1 5.493 24.339 18.848 C +ATOM 454 C5 MOL A 1 5.223 23.079 19.656 C +ATOM 455 C6 MOL A 1 5.496 21.839 18.816 C +ATOM 456 H1 MOL A 1 5.605 2.495 21.551 H +ATOM 457 H2 MOL A 1 3.953 1.386 18.622 H +ATOM 458 H3 MOL A 1 4.876 24.386 18.089 H +ATOM 459 H4 MOL A 1 4.298 23.074 19.952 H +ATOM 460 H5 MOL A 1 5.791 23.069 20.443 H +ATOM 461 H6 MOL A 1 5.310 21.040 19.334 H +ATOM 462 H7 MOL A 1 4.915 21.834 18.037 H +ATOM 463 N1 MOL A 1 5.296 13.090 7.315 N +ATOM 464 C1 MOL A 1 4.869 15.421 8.933 C +ATOM 465 C2 MOL A 1 4.104 15.085 7.827 C +ATOM 466 C3 MOL A 1 4.427 13.915 7.012 C +ATOM 467 C4 MOL A 1 5.493 11.939 6.448 C +ATOM 468 C5 MOL A 1 5.223 10.679 7.256 C +ATOM 469 C6 MOL A 1 5.496 9.439 6.416 C +ATOM 470 H1 MOL A 1 5.605 14.895 9.151 H +ATOM 471 H2 MOL A 1 3.953 13.786 6.222 H +ATOM 472 H3 MOL A 1 4.876 11.986 5.689 H +ATOM 473 H4 MOL A 1 4.298 10.674 7.552 H +ATOM 474 H5 MOL A 1 5.791 10.669 8.043 H +ATOM 475 H6 MOL A 1 5.310 8.640 6.934 H +ATOM 476 H7 MOL A 1 4.915 9.434 5.637 H +ATOM 477 N1 MOL A 1 17.696 0.690 7.315 N +ATOM 478 C1 MOL A 1 17.269 3.021 8.933 C +ATOM 479 C2 MOL A 1 16.504 2.685 7.827 C +ATOM 480 C3 MOL A 1 16.827 1.515 7.012 C +ATOM 481 C4 MOL A 1 17.893 24.339 6.448 C +ATOM 482 C5 MOL A 1 17.623 23.079 7.256 C +ATOM 483 C6 MOL A 1 17.896 21.839 6.416 C +ATOM 484 H1 MOL A 1 18.005 2.495 9.151 H +ATOM 485 H2 MOL A 1 16.353 1.386 6.222 H +ATOM 486 H3 MOL A 1 17.276 24.386 5.689 H +ATOM 487 H4 MOL A 1 16.698 23.074 7.552 H +ATOM 488 H5 MOL A 1 18.191 23.069 8.043 H +ATOM 489 H6 MOL A 1 17.710 21.040 6.934 H +ATOM 490 H7 MOL A 1 17.315 21.834 5.637 H +ATOM 491 N1 MOL A 1 17.696 13.090 19.715 N +ATOM 492 C1 MOL A 1 17.269 15.421 21.333 C +ATOM 493 C2 MOL A 1 16.504 15.085 20.227 C +ATOM 494 C3 MOL A 1 16.827 13.915 19.412 C +ATOM 495 C4 MOL A 1 17.893 11.939 18.848 C +ATOM 496 C5 MOL A 1 17.623 10.679 19.656 C +ATOM 497 C6 MOL A 1 17.896 9.439 18.816 C +ATOM 498 H1 MOL A 1 18.005 14.895 21.551 H +ATOM 499 H2 MOL A 1 16.353 13.786 18.622 H +ATOM 500 H3 MOL A 1 17.276 11.986 18.089 H +ATOM 501 H4 MOL A 1 16.698 10.674 19.952 H +ATOM 502 H5 MOL A 1 18.191 10.669 20.443 H +ATOM 503 H6 MOL A 1 17.710 8.640 19.334 H +ATOM 504 H7 MOL A 1 17.315 9.434 18.037 H +ATOM 505 N1 MOL A 1 7.104 13.090 5.085 N +ATOM 506 C1 MOL A 1 7.531 15.421 3.467 C +ATOM 507 C2 MOL A 1 8.296 15.085 4.573 C +ATOM 508 C3 MOL A 1 7.973 13.915 5.388 C +ATOM 509 C4 MOL A 1 6.907 11.939 5.952 C +ATOM 510 C5 MOL A 1 7.177 10.679 5.144 C +ATOM 511 C6 MOL A 1 6.904 9.439 5.984 C +ATOM 512 H1 MOL A 1 6.795 14.895 3.249 H +ATOM 513 H2 MOL A 1 8.447 13.786 6.178 H +ATOM 514 H3 MOL A 1 7.524 11.986 6.711 H +ATOM 515 H4 MOL A 1 8.102 10.674 4.848 H +ATOM 516 H5 MOL A 1 6.609 10.669 4.357 H +ATOM 517 H6 MOL A 1 7.090 8.640 5.466 H +ATOM 518 H7 MOL A 1 7.485 9.434 6.763 H +ATOM 519 N1 MOL A 1 7.104 0.690 17.485 N +ATOM 520 C1 MOL A 1 7.531 3.021 15.867 C +ATOM 521 C2 MOL A 1 8.296 2.685 16.973 C +ATOM 522 C3 MOL A 1 7.973 1.515 17.788 C +ATOM 523 C4 MOL A 1 6.907 24.339 18.352 C +ATOM 524 C5 MOL A 1 7.177 23.079 17.544 C +ATOM 525 C6 MOL A 1 6.904 21.839 18.384 C +ATOM 526 H1 MOL A 1 6.795 2.495 15.649 H +ATOM 527 H2 MOL A 1 8.447 1.386 18.578 H +ATOM 528 H3 MOL A 1 7.524 24.386 19.111 H +ATOM 529 H4 MOL A 1 8.102 23.074 17.248 H +ATOM 530 H5 MOL A 1 6.609 23.069 16.757 H +ATOM 531 H6 MOL A 1 7.090 21.040 17.866 H +ATOM 532 H7 MOL A 1 7.485 21.834 19.163 H +ATOM 533 N1 MOL A 1 19.504 13.090 17.485 N +ATOM 534 C1 MOL A 1 19.931 15.421 15.867 C +ATOM 535 C2 MOL A 1 20.696 15.085 16.973 C +ATOM 536 C3 MOL A 1 20.373 13.915 17.788 C +ATOM 537 C4 MOL A 1 19.307 11.939 18.352 C +ATOM 538 C5 MOL A 1 19.577 10.679 17.544 C +ATOM 539 C6 MOL A 1 19.304 9.439 18.384 C +ATOM 540 H1 MOL A 1 19.195 14.895 15.649 H +ATOM 541 H2 MOL A 1 20.847 13.786 18.578 H +ATOM 542 H3 MOL A 1 19.924 11.986 19.111 H +ATOM 543 H4 MOL A 1 20.502 10.674 17.248 H +ATOM 544 H5 MOL A 1 19.009 10.669 16.757 H +ATOM 545 H6 MOL A 1 19.490 8.640 17.866 H +ATOM 546 H7 MOL A 1 19.885 9.434 19.163 H +ATOM 547 N1 MOL A 1 19.504 0.690 5.085 N +ATOM 548 C1 MOL A 1 19.931 3.021 3.467 C +ATOM 549 C2 MOL A 1 20.696 2.685 4.573 C +ATOM 550 C3 MOL A 1 20.373 1.515 5.388 C +ATOM 551 C4 MOL A 1 19.307 24.339 5.952 C +ATOM 552 C5 MOL A 1 19.577 23.079 5.144 C +ATOM 553 C6 MOL A 1 19.304 21.839 5.984 C +ATOM 554 H1 MOL A 1 19.195 2.495 3.249 H +ATOM 555 H2 MOL A 1 20.847 1.386 6.178 H +ATOM 556 H3 MOL A 1 19.924 24.386 6.711 H +ATOM 557 H4 MOL A 1 20.502 23.074 4.848 H +ATOM 558 H5 MOL A 1 19.009 23.069 4.357 H +ATOM 559 H6 MOL A 1 19.490 21.040 5.466 H +ATOM 560 H7 MOL A 1 19.885 21.834 6.763 H +ATOM 561 N1 MOL A 1 17.696 24.110 17.485 N +ATOM 562 C1 MOL A 1 17.269 21.779 15.867 C +ATOM 563 C2 MOL A 1 16.504 22.115 16.973 C +ATOM 564 C3 MOL A 1 16.827 23.285 17.788 C +ATOM 565 C4 MOL A 1 17.893 0.461 18.352 C +ATOM 566 C5 MOL A 1 17.623 1.721 17.544 C +ATOM 567 C6 MOL A 1 17.896 2.961 18.384 C +ATOM 568 H1 MOL A 1 18.005 22.305 15.649 H +ATOM 569 H2 MOL A 1 16.353 23.414 18.578 H +ATOM 570 H3 MOL A 1 17.276 0.414 19.111 H +ATOM 571 H4 MOL A 1 16.698 1.726 17.248 H +ATOM 572 H5 MOL A 1 18.191 1.731 16.757 H +ATOM 573 H6 MOL A 1 17.710 3.760 17.866 H +ATOM 574 H7 MOL A 1 17.315 2.966 19.163 H +ATOM 575 N1 MOL A 1 17.696 11.710 5.085 N +ATOM 576 C1 MOL A 1 17.269 9.379 3.467 C +ATOM 577 C2 MOL A 1 16.504 9.715 4.573 C +ATOM 578 C3 MOL A 1 16.827 10.885 5.388 C +ATOM 579 C4 MOL A 1 17.893 12.861 5.952 C +ATOM 580 C5 MOL A 1 17.623 14.121 5.144 C +ATOM 581 C6 MOL A 1 17.896 15.361 5.984 C +ATOM 582 H1 MOL A 1 18.005 9.905 3.249 H +ATOM 583 H2 MOL A 1 16.353 11.014 6.178 H +ATOM 584 H3 MOL A 1 17.276 12.814 6.711 H +ATOM 585 H4 MOL A 1 16.698 14.126 4.848 H +ATOM 586 H5 MOL A 1 18.191 14.131 4.357 H +ATOM 587 H6 MOL A 1 17.710 16.160 5.466 H +ATOM 588 H7 MOL A 1 17.315 15.366 6.763 H +ATOM 589 N1 MOL A 1 5.296 24.110 5.085 N +ATOM 590 C1 MOL A 1 4.869 21.779 3.467 C +ATOM 591 C2 MOL A 1 4.104 22.115 4.573 C +ATOM 592 C3 MOL A 1 4.427 23.285 5.388 C +ATOM 593 C4 MOL A 1 5.493 0.461 5.952 C +ATOM 594 C5 MOL A 1 5.223 1.721 5.144 C +ATOM 595 C6 MOL A 1 5.496 2.961 5.984 C +ATOM 596 H1 MOL A 1 5.605 22.305 3.249 H +ATOM 597 H2 MOL A 1 3.953 23.414 6.178 H +ATOM 598 H3 MOL A 1 4.876 0.414 6.711 H +ATOM 599 H4 MOL A 1 4.298 1.726 4.848 H +ATOM 600 H5 MOL A 1 5.791 1.731 4.357 H +ATOM 601 H6 MOL A 1 5.310 3.760 5.466 H +ATOM 602 H7 MOL A 1 4.915 2.966 6.763 H +ATOM 603 N1 MOL A 1 5.296 11.710 17.485 N +ATOM 604 C1 MOL A 1 4.869 9.379 15.867 C +ATOM 605 C2 MOL A 1 4.104 9.715 16.973 C +ATOM 606 C3 MOL A 1 4.427 10.885 17.788 C +ATOM 607 C4 MOL A 1 5.493 12.861 18.352 C +ATOM 608 C5 MOL A 1 5.223 14.121 17.544 C +ATOM 609 C6 MOL A 1 5.496 15.361 18.384 C +ATOM 610 H1 MOL A 1 5.605 9.905 15.649 H +ATOM 611 H2 MOL A 1 3.953 11.014 18.578 H +ATOM 612 H3 MOL A 1 4.876 12.814 19.111 H +ATOM 613 H4 MOL A 1 4.298 14.126 17.248 H +ATOM 614 H5 MOL A 1 5.791 14.131 16.757 H +ATOM 615 H6 MOL A 1 5.310 16.160 17.866 H +ATOM 616 H7 MOL A 1 4.915 15.366 19.163 H +ATOM 617 N1 MOL A 1 19.504 11.710 7.315 N +ATOM 618 C1 MOL A 1 19.931 9.379 8.933 C +ATOM 619 C2 MOL A 1 20.696 9.715 7.827 C +ATOM 620 C3 MOL A 1 20.373 10.885 7.012 C +ATOM 621 C4 MOL A 1 19.307 12.861 6.448 C +ATOM 622 C5 MOL A 1 19.577 14.121 7.256 C +ATOM 623 C6 MOL A 1 19.304 15.361 6.416 C +ATOM 624 H1 MOL A 1 19.195 9.905 9.151 H +ATOM 625 H2 MOL A 1 20.847 11.014 6.222 H +ATOM 626 H3 MOL A 1 19.924 12.814 5.689 H +ATOM 627 H4 MOL A 1 20.502 14.126 7.552 H +ATOM 628 H5 MOL A 1 19.009 14.131 8.043 H +ATOM 629 H6 MOL A 1 19.490 16.160 6.934 H +ATOM 630 H7 MOL A 1 19.885 15.366 5.637 H +ATOM 631 N1 MOL A 1 19.504 24.110 19.715 N +ATOM 632 C1 MOL A 1 19.931 21.779 21.333 C +ATOM 633 C2 MOL A 1 20.696 22.115 20.227 C +ATOM 634 C3 MOL A 1 20.373 23.285 19.412 C +ATOM 635 C4 MOL A 1 19.307 0.461 18.848 C +ATOM 636 C5 MOL A 1 19.577 1.721 19.656 C +ATOM 637 C6 MOL A 1 19.304 2.961 18.816 C +ATOM 638 H1 MOL A 1 19.195 22.305 21.551 H +ATOM 639 H2 MOL A 1 20.847 23.414 18.622 H +ATOM 640 H3 MOL A 1 19.924 0.414 18.089 H +ATOM 641 H4 MOL A 1 20.502 1.726 19.952 H +ATOM 642 H5 MOL A 1 19.009 1.731 20.443 H +ATOM 643 H6 MOL A 1 19.490 3.760 19.334 H +ATOM 644 H7 MOL A 1 19.885 2.966 18.037 H +ATOM 645 N1 MOL A 1 7.104 11.710 19.715 N +ATOM 646 C1 MOL A 1 7.531 9.379 21.333 C +ATOM 647 C2 MOL A 1 8.296 9.715 20.227 C +ATOM 648 C3 MOL A 1 7.973 10.885 19.412 C +ATOM 649 C4 MOL A 1 6.907 12.861 18.848 C +ATOM 650 C5 MOL A 1 7.177 14.121 19.656 C +ATOM 651 C6 MOL A 1 6.904 15.361 18.816 C +ATOM 652 H1 MOL A 1 6.795 9.905 21.551 H +ATOM 653 H2 MOL A 1 8.447 11.014 18.622 H +ATOM 654 H3 MOL A 1 7.524 12.814 18.089 H +ATOM 655 H4 MOL A 1 8.102 14.126 19.952 H +ATOM 656 H5 MOL A 1 6.609 14.131 20.443 H +ATOM 657 H6 MOL A 1 7.090 16.160 19.334 H +ATOM 658 H7 MOL A 1 7.485 15.366 18.037 H +ATOM 659 N1 MOL A 1 7.104 24.110 7.315 N +ATOM 660 C1 MOL A 1 7.531 21.779 8.933 C +ATOM 661 C2 MOL A 1 8.296 22.115 7.827 C +ATOM 662 C3 MOL A 1 7.973 23.285 7.012 C +ATOM 663 C4 MOL A 1 6.907 0.461 6.448 C +ATOM 664 C5 MOL A 1 7.177 1.721 7.256 C +ATOM 665 C6 MOL A 1 6.904 2.961 6.416 C +ATOM 666 H1 MOL A 1 6.795 22.305 9.151 H +ATOM 667 H2 MOL A 1 8.447 23.414 6.222 H +ATOM 668 H3 MOL A 1 7.524 0.414 5.689 H +ATOM 669 H4 MOL A 1 8.102 1.726 7.552 H +ATOM 670 H5 MOL A 1 6.609 1.731 8.043 H +ATOM 671 H6 MOL A 1 7.090 3.760 6.934 H +ATOM 672 H7 MOL A 1 7.485 2.966 5.637 H +ATOM 673 N1 MOL A 1 23.896 1.115 17.910 N +ATOM 674 C1 MOL A 1 23.469 2.733 15.579 C +ATOM 675 C2 MOL A 1 22.704 1.627 15.915 C +ATOM 676 C3 MOL A 1 23.027 0.812 17.085 C +ATOM 677 C4 MOL A 1 24.093 0.248 19.061 C +ATOM 678 C5 MOL A 1 23.823 1.056 20.321 C +ATOM 679 C6 MOL A 1 24.096 0.216 21.561 C +ATOM 680 H1 MOL A 1 24.205 2.951 16.105 H +ATOM 681 H2 MOL A 1 22.553 0.022 17.214 H +ATOM 682 H3 MOL A 1 23.476 24.289 19.014 H +ATOM 683 H4 MOL A 1 22.898 1.352 20.326 H +ATOM 684 H5 MOL A 1 24.391 1.843 20.331 H +ATOM 685 H6 MOL A 1 23.910 0.734 22.360 H +ATOM 686 H7 MOL A 1 23.515 24.237 21.566 H +ATOM 687 N1 MOL A 1 23.896 13.515 5.510 N +ATOM 688 C1 MOL A 1 23.469 15.133 3.179 C +ATOM 689 C2 MOL A 1 22.704 14.027 3.515 C +ATOM 690 C3 MOL A 1 23.027 13.212 4.685 C +ATOM 691 C4 MOL A 1 24.093 12.648 6.661 C +ATOM 692 C5 MOL A 1 23.823 13.456 7.921 C +ATOM 693 C6 MOL A 1 24.096 12.616 9.161 C +ATOM 694 H1 MOL A 1 24.205 15.351 3.705 H +ATOM 695 H2 MOL A 1 22.553 12.422 4.814 H +ATOM 696 H3 MOL A 1 23.476 11.889 6.614 H +ATOM 697 H4 MOL A 1 22.898 13.752 7.926 H +ATOM 698 H5 MOL A 1 24.391 14.243 7.931 H +ATOM 699 H6 MOL A 1 23.910 13.134 9.960 H +ATOM 700 H7 MOL A 1 23.515 11.837 9.166 H +ATOM 701 N1 MOL A 1 11.496 1.115 5.510 N +ATOM 702 C1 MOL A 1 11.069 2.733 3.179 C +ATOM 703 C2 MOL A 1 10.304 1.627 3.515 C +ATOM 704 C3 MOL A 1 10.627 0.812 4.685 C +ATOM 705 C4 MOL A 1 11.693 0.248 6.661 C +ATOM 706 C5 MOL A 1 11.423 1.056 7.921 C +ATOM 707 C6 MOL A 1 11.696 0.216 9.161 C +ATOM 708 H1 MOL A 1 11.805 2.951 3.705 H +ATOM 709 H2 MOL A 1 10.153 0.022 4.814 H +ATOM 710 H3 MOL A 1 11.076 24.289 6.614 H +ATOM 711 H4 MOL A 1 10.498 1.352 7.926 H +ATOM 712 H5 MOL A 1 11.991 1.843 7.931 H +ATOM 713 H6 MOL A 1 11.510 0.734 9.960 H +ATOM 714 H7 MOL A 1 11.115 24.237 9.166 H +ATOM 715 N1 MOL A 1 11.496 13.515 17.910 N +ATOM 716 C1 MOL A 1 11.069 15.133 15.579 C +ATOM 717 C2 MOL A 1 10.304 14.027 15.915 C +ATOM 718 C3 MOL A 1 10.627 13.212 17.085 C +ATOM 719 C4 MOL A 1 11.693 12.648 19.061 C +ATOM 720 C5 MOL A 1 11.423 13.456 20.321 C +ATOM 721 C6 MOL A 1 11.696 12.616 21.561 C +ATOM 722 H1 MOL A 1 11.805 15.351 16.105 H +ATOM 723 H2 MOL A 1 10.153 12.422 17.214 H +ATOM 724 H3 MOL A 1 11.076 11.889 19.014 H +ATOM 725 H4 MOL A 1 10.498 13.752 20.326 H +ATOM 726 H5 MOL A 1 11.991 14.243 20.331 H +ATOM 727 H6 MOL A 1 11.510 13.134 22.360 H +ATOM 728 H7 MOL A 1 11.115 11.837 21.566 H +ATOM 729 N1 MOL A 1 0.904 11.285 5.510 N +ATOM 730 C1 MOL A 1 1.331 9.667 3.179 C +ATOM 731 C2 MOL A 1 2.096 10.773 3.515 C +ATOM 732 C3 MOL A 1 1.773 11.588 4.685 C +ATOM 733 C4 MOL A 1 0.707 12.152 6.661 C +ATOM 734 C5 MOL A 1 0.977 11.344 7.921 C +ATOM 735 C6 MOL A 1 0.704 12.184 9.161 C +ATOM 736 H1 MOL A 1 0.595 9.449 3.705 H +ATOM 737 H2 MOL A 1 2.247 12.378 4.814 H +ATOM 738 H3 MOL A 1 1.324 12.911 6.614 H +ATOM 739 H4 MOL A 1 1.902 11.048 7.926 H +ATOM 740 H5 MOL A 1 0.409 10.557 7.931 H +ATOM 741 H6 MOL A 1 0.890 11.666 9.960 H +ATOM 742 H7 MOL A 1 1.285 12.963 9.166 H +ATOM 743 N1 MOL A 1 0.904 23.685 17.910 N +ATOM 744 C1 MOL A 1 1.331 22.067 15.579 C +ATOM 745 C2 MOL A 1 2.096 23.173 15.915 C +ATOM 746 C3 MOL A 1 1.773 23.988 17.085 C +ATOM 747 C4 MOL A 1 0.707 24.552 19.061 C +ATOM 748 C5 MOL A 1 0.977 23.744 20.321 C +ATOM 749 C6 MOL A 1 0.704 24.584 21.561 C +ATOM 750 H1 MOL A 1 0.595 21.849 16.105 H +ATOM 751 H2 MOL A 1 2.247 24.778 17.214 H +ATOM 752 H3 MOL A 1 1.324 0.511 19.014 H +ATOM 753 H4 MOL A 1 1.902 23.448 20.326 H +ATOM 754 H5 MOL A 1 0.409 22.957 20.331 H +ATOM 755 H6 MOL A 1 0.890 24.066 22.360 H +ATOM 756 H7 MOL A 1 1.285 0.563 21.566 H +ATOM 757 N1 MOL A 1 13.304 11.285 17.910 N +ATOM 758 C1 MOL A 1 13.731 9.667 15.579 C +ATOM 759 C2 MOL A 1 14.496 10.773 15.915 C +ATOM 760 C3 MOL A 1 14.173 11.588 17.085 C +ATOM 761 C4 MOL A 1 13.107 12.152 19.061 C +ATOM 762 C5 MOL A 1 13.377 11.344 20.321 C +ATOM 763 C6 MOL A 1 13.104 12.184 21.561 C +ATOM 764 H1 MOL A 1 12.995 9.449 16.105 H +ATOM 765 H2 MOL A 1 14.647 12.378 17.214 H +ATOM 766 H3 MOL A 1 13.724 12.911 19.014 H +ATOM 767 H4 MOL A 1 14.302 11.048 20.326 H +ATOM 768 H5 MOL A 1 12.809 10.557 20.331 H +ATOM 769 H6 MOL A 1 13.290 11.666 22.360 H +ATOM 770 H7 MOL A 1 13.685 12.963 21.566 H +ATOM 771 N1 MOL A 1 13.304 23.685 5.510 N +ATOM 772 C1 MOL A 1 13.731 22.067 3.179 C +ATOM 773 C2 MOL A 1 14.496 23.173 3.515 C +ATOM 774 C3 MOL A 1 14.173 23.988 4.685 C +ATOM 775 C4 MOL A 1 13.107 24.552 6.661 C +ATOM 776 C5 MOL A 1 13.377 23.744 7.921 C +ATOM 777 C6 MOL A 1 13.104 24.584 9.161 C +ATOM 778 H1 MOL A 1 12.995 21.849 3.705 H +ATOM 779 H2 MOL A 1 14.647 24.778 4.814 H +ATOM 780 H3 MOL A 1 13.724 0.511 6.614 H +ATOM 781 H4 MOL A 1 14.302 23.448 7.926 H +ATOM 782 H5 MOL A 1 12.809 22.957 7.931 H +ATOM 783 H6 MOL A 1 13.290 24.066 9.960 H +ATOM 784 H7 MOL A 1 13.685 0.563 9.166 H +ATOM 785 N1 MOL A 1 11.496 23.685 19.290 N +ATOM 786 C1 MOL A 1 11.069 22.067 21.621 C +ATOM 787 C2 MOL A 1 10.304 23.173 21.285 C +ATOM 788 C3 MOL A 1 10.627 23.988 20.115 C +ATOM 789 C4 MOL A 1 11.693 24.552 18.139 C +ATOM 790 C5 MOL A 1 11.423 23.744 16.879 C +ATOM 791 C6 MOL A 1 11.696 24.584 15.639 C +ATOM 792 H1 MOL A 1 11.805 21.849 21.095 H +ATOM 793 H2 MOL A 1 10.153 24.778 19.986 H +ATOM 794 H3 MOL A 1 11.076 0.511 18.186 H +ATOM 795 H4 MOL A 1 10.498 23.448 16.874 H +ATOM 796 H5 MOL A 1 11.991 22.957 16.869 H +ATOM 797 H6 MOL A 1 11.510 24.066 14.840 H +ATOM 798 H7 MOL A 1 11.115 0.563 15.634 H +ATOM 799 N1 MOL A 1 11.496 11.285 6.890 N +ATOM 800 C1 MOL A 1 11.069 9.667 9.221 C +ATOM 801 C2 MOL A 1 10.304 10.773 8.885 C +ATOM 802 C3 MOL A 1 10.627 11.588 7.715 C +ATOM 803 C4 MOL A 1 11.693 12.152 5.739 C +ATOM 804 C5 MOL A 1 11.423 11.344 4.479 C +ATOM 805 C6 MOL A 1 11.696 12.184 3.239 C +ATOM 806 H1 MOL A 1 11.805 9.449 8.695 H +ATOM 807 H2 MOL A 1 10.153 12.378 7.586 H +ATOM 808 H3 MOL A 1 11.076 12.911 5.786 H +ATOM 809 H4 MOL A 1 10.498 11.048 4.474 H +ATOM 810 H5 MOL A 1 11.991 10.557 4.469 H +ATOM 811 H6 MOL A 1 11.510 11.666 2.440 H +ATOM 812 H7 MOL A 1 11.115 12.963 3.234 H +ATOM 813 N1 MOL A 1 23.896 23.685 6.890 N +ATOM 814 C1 MOL A 1 23.469 22.067 9.221 C +ATOM 815 C2 MOL A 1 22.704 23.173 8.885 C +ATOM 816 C3 MOL A 1 23.027 23.988 7.715 C +ATOM 817 C4 MOL A 1 24.093 24.552 5.739 C +ATOM 818 C5 MOL A 1 23.823 23.744 4.479 C +ATOM 819 C6 MOL A 1 24.096 24.584 3.239 C +ATOM 820 H1 MOL A 1 24.205 21.849 8.695 H +ATOM 821 H2 MOL A 1 22.553 24.778 7.586 H +ATOM 822 H3 MOL A 1 23.476 0.511 5.786 H +ATOM 823 H4 MOL A 1 22.898 23.448 4.474 H +ATOM 824 H5 MOL A 1 24.391 22.957 4.469 H +ATOM 825 H6 MOL A 1 23.910 24.066 2.440 H +ATOM 826 H7 MOL A 1 23.515 0.563 3.234 H +ATOM 827 N1 MOL A 1 23.896 11.285 19.290 N +ATOM 828 C1 MOL A 1 23.469 9.667 21.621 C +ATOM 829 C2 MOL A 1 22.704 10.773 21.285 C +ATOM 830 C3 MOL A 1 23.027 11.588 20.115 C +ATOM 831 C4 MOL A 1 24.093 12.152 18.139 C +ATOM 832 C5 MOL A 1 23.823 11.344 16.879 C +ATOM 833 C6 MOL A 1 24.096 12.184 15.639 C +ATOM 834 H1 MOL A 1 24.205 9.449 21.095 H +ATOM 835 H2 MOL A 1 22.553 12.378 19.986 H +ATOM 836 H3 MOL A 1 23.476 12.911 18.186 H +ATOM 837 H4 MOL A 1 22.898 11.048 16.874 H +ATOM 838 H5 MOL A 1 24.391 10.557 16.869 H +ATOM 839 H6 MOL A 1 23.910 11.666 14.840 H +ATOM 840 H7 MOL A 1 23.515 12.963 15.634 H +ATOM 841 N1 MOL A 1 13.304 13.515 6.890 N +ATOM 842 C1 MOL A 1 13.731 15.133 9.221 C +ATOM 843 C2 MOL A 1 14.496 14.027 8.885 C +ATOM 844 C3 MOL A 1 14.173 13.212 7.715 C +ATOM 845 C4 MOL A 1 13.107 12.648 5.739 C +ATOM 846 C5 MOL A 1 13.377 13.456 4.479 C +ATOM 847 C6 MOL A 1 13.104 12.616 3.239 C +ATOM 848 H1 MOL A 1 12.995 15.351 8.695 H +ATOM 849 H2 MOL A 1 14.647 12.422 7.586 H +ATOM 850 H3 MOL A 1 13.724 11.889 5.786 H +ATOM 851 H4 MOL A 1 14.302 13.752 4.474 H +ATOM 852 H5 MOL A 1 12.809 14.243 4.469 H +ATOM 853 H6 MOL A 1 13.290 13.134 2.440 H +ATOM 854 H7 MOL A 1 13.685 11.837 3.234 H +ATOM 855 N1 MOL A 1 13.304 1.115 19.290 N +ATOM 856 C1 MOL A 1 13.731 2.733 21.621 C +ATOM 857 C2 MOL A 1 14.496 1.627 21.285 C +ATOM 858 C3 MOL A 1 14.173 0.812 20.115 C +ATOM 859 C4 MOL A 1 13.107 0.248 18.139 C +ATOM 860 C5 MOL A 1 13.377 1.056 16.879 C +ATOM 861 C6 MOL A 1 13.104 0.216 15.639 C +ATOM 862 H1 MOL A 1 12.995 2.951 21.095 H +ATOM 863 H2 MOL A 1 14.647 0.022 19.986 H +ATOM 864 H3 MOL A 1 13.724 24.289 18.186 H +ATOM 865 H4 MOL A 1 14.302 1.352 16.874 H +ATOM 866 H5 MOL A 1 12.809 1.843 16.869 H +ATOM 867 H6 MOL A 1 13.290 0.734 14.840 H +ATOM 868 H7 MOL A 1 13.685 24.237 15.634 H +ATOM 869 N1 MOL A 1 0.904 13.515 19.290 N +ATOM 870 C1 MOL A 1 1.331 15.133 21.621 C +ATOM 871 C2 MOL A 1 2.096 14.027 21.285 C +ATOM 872 C3 MOL A 1 1.773 13.212 20.115 C +ATOM 873 C4 MOL A 1 0.707 12.648 18.139 C +ATOM 874 C5 MOL A 1 0.977 13.456 16.879 C +ATOM 875 C6 MOL A 1 0.704 12.616 15.639 C +ATOM 876 H1 MOL A 1 0.595 15.351 21.095 H +ATOM 877 H2 MOL A 1 2.247 12.422 19.986 H +ATOM 878 H3 MOL A 1 1.324 11.889 18.186 H +ATOM 879 H4 MOL A 1 1.902 13.752 16.874 H +ATOM 880 H5 MOL A 1 0.409 14.243 16.869 H +ATOM 881 H6 MOL A 1 0.890 13.134 14.840 H +ATOM 882 H7 MOL A 1 1.285 11.837 15.634 H +ATOM 883 N1 MOL A 1 0.904 1.115 6.890 N +ATOM 884 C1 MOL A 1 1.331 2.733 9.221 C +ATOM 885 C2 MOL A 1 2.096 1.627 8.885 C +ATOM 886 C3 MOL A 1 1.773 0.812 7.715 C +ATOM 887 C4 MOL A 1 0.707 0.248 5.739 C +ATOM 888 C5 MOL A 1 0.977 1.056 4.479 C +ATOM 889 C6 MOL A 1 0.704 0.216 3.239 C +ATOM 890 H1 MOL A 1 0.595 2.951 8.695 H +ATOM 891 H2 MOL A 1 2.247 0.022 7.586 H +ATOM 892 H3 MOL A 1 1.324 24.289 5.786 H +ATOM 893 H4 MOL A 1 1.902 1.352 4.474 H +ATOM 894 H5 MOL A 1 0.409 1.843 4.469 H +ATOM 895 H6 MOL A 1 0.890 0.734 2.440 H +ATOM 896 H7 MOL A 1 1.285 24.237 3.234 H +ATOM 897 N1 MOL A 1 13.515 6.890 13.304 N +ATOM 898 C1 MOL A 1 15.133 9.221 13.731 C +ATOM 899 C2 MOL A 1 14.027 8.885 14.496 C +ATOM 900 C3 MOL A 1 13.212 7.715 14.173 C +ATOM 901 C4 MOL A 1 12.648 5.739 13.107 C +ATOM 902 C5 MOL A 1 13.456 4.479 13.377 C +ATOM 903 C6 MOL A 1 12.616 3.239 13.104 C +ATOM 904 H1 MOL A 1 15.351 8.695 12.995 H +ATOM 905 H2 MOL A 1 12.422 7.586 14.647 H +ATOM 906 H3 MOL A 1 11.889 5.786 13.724 H +ATOM 907 H4 MOL A 1 13.752 4.474 14.302 H +ATOM 908 H5 MOL A 1 14.243 4.469 12.809 H +ATOM 909 H6 MOL A 1 13.134 2.440 13.290 H +ATOM 910 H7 MOL A 1 11.837 3.234 13.685 H +ATOM 911 N1 MOL A 1 13.515 19.290 0.904 N +ATOM 912 C1 MOL A 1 15.133 21.621 1.331 C +ATOM 913 C2 MOL A 1 14.027 21.285 2.096 C +ATOM 914 C3 MOL A 1 13.212 20.115 1.773 C +ATOM 915 C4 MOL A 1 12.648 18.139 0.707 C +ATOM 916 C5 MOL A 1 13.456 16.879 0.977 C +ATOM 917 C6 MOL A 1 12.616 15.639 0.704 C +ATOM 918 H1 MOL A 1 15.351 21.095 0.595 H +ATOM 919 H2 MOL A 1 12.422 19.986 2.247 H +ATOM 920 H3 MOL A 1 11.889 18.186 1.324 H +ATOM 921 H4 MOL A 1 13.752 16.874 1.902 H +ATOM 922 H5 MOL A 1 14.243 16.869 0.409 H +ATOM 923 H6 MOL A 1 13.134 14.840 0.890 H +ATOM 924 H7 MOL A 1 11.837 15.634 1.285 H +ATOM 925 N1 MOL A 1 1.115 6.890 0.904 N +ATOM 926 C1 MOL A 1 2.733 9.221 1.331 C +ATOM 927 C2 MOL A 1 1.627 8.885 2.096 C +ATOM 928 C3 MOL A 1 0.812 7.715 1.773 C +ATOM 929 C4 MOL A 1 0.248 5.739 0.707 C +ATOM 930 C5 MOL A 1 1.056 4.479 0.977 C +ATOM 931 C6 MOL A 1 0.216 3.239 0.704 C +ATOM 932 H1 MOL A 1 2.951 8.695 0.595 H +ATOM 933 H2 MOL A 1 0.022 7.586 2.247 H +ATOM 934 H3 MOL A 1 24.289 5.786 1.324 H +ATOM 935 H4 MOL A 1 1.352 4.474 1.902 H +ATOM 936 H5 MOL A 1 1.843 4.469 0.409 H +ATOM 937 H6 MOL A 1 0.734 2.440 0.890 H +ATOM 938 H7 MOL A 1 24.237 3.234 1.285 H +ATOM 939 N1 MOL A 1 1.115 19.290 13.304 N +ATOM 940 C1 MOL A 1 2.733 21.621 13.731 C +ATOM 941 C2 MOL A 1 1.627 21.285 14.496 C +ATOM 942 C3 MOL A 1 0.812 20.115 14.173 C +ATOM 943 C4 MOL A 1 0.248 18.139 13.107 C +ATOM 944 C5 MOL A 1 1.056 16.879 13.377 C +ATOM 945 C6 MOL A 1 0.216 15.639 13.104 C +ATOM 946 H1 MOL A 1 2.951 21.095 12.995 H +ATOM 947 H2 MOL A 1 0.022 19.986 14.647 H +ATOM 948 H3 MOL A 1 24.289 18.186 13.724 H +ATOM 949 H4 MOL A 1 1.352 16.874 14.302 H +ATOM 950 H5 MOL A 1 1.843 16.869 12.809 H +ATOM 951 H6 MOL A 1 0.734 14.840 13.290 H +ATOM 952 H7 MOL A 1 24.237 15.634 13.685 H +ATOM 953 N1 MOL A 1 23.685 19.290 11.496 N +ATOM 954 C1 MOL A 1 22.067 21.621 11.069 C +ATOM 955 C2 MOL A 1 23.173 21.285 10.304 C +ATOM 956 C3 MOL A 1 23.988 20.115 10.627 C +ATOM 957 C4 MOL A 1 24.552 18.139 11.693 C +ATOM 958 C5 MOL A 1 23.744 16.879 11.423 C +ATOM 959 C6 MOL A 1 24.584 15.639 11.696 C +ATOM 960 H1 MOL A 1 21.849 21.095 11.805 H +ATOM 961 H2 MOL A 1 24.778 19.986 10.153 H +ATOM 962 H3 MOL A 1 0.511 18.186 11.076 H +ATOM 963 H4 MOL A 1 23.448 16.874 10.498 H +ATOM 964 H5 MOL A 1 22.957 16.869 11.991 H +ATOM 965 H6 MOL A 1 24.066 14.840 11.510 H +ATOM 966 H7 MOL A 1 0.563 15.634 11.115 H +ATOM 967 N1 MOL A 1 23.685 6.890 23.896 N +ATOM 968 C1 MOL A 1 22.067 9.221 23.469 C +ATOM 969 C2 MOL A 1 23.173 8.885 22.704 C +ATOM 970 C3 MOL A 1 23.988 7.715 23.027 C +ATOM 971 C4 MOL A 1 24.552 5.739 24.093 C +ATOM 972 C5 MOL A 1 23.744 4.479 23.823 C +ATOM 973 C6 MOL A 1 24.584 3.239 24.096 C +ATOM 974 H1 MOL A 1 21.849 8.695 24.205 H +ATOM 975 H2 MOL A 1 24.778 7.586 22.553 H +ATOM 976 H3 MOL A 1 0.511 5.786 23.476 H +ATOM 977 H4 MOL A 1 23.448 4.474 22.898 H +ATOM 978 H5 MOL A 1 22.957 4.469 24.391 H +ATOM 979 H6 MOL A 1 24.066 2.440 23.910 H +ATOM 980 H7 MOL A 1 0.563 3.234 23.515 H +ATOM 981 N1 MOL A 1 11.285 19.290 23.896 N +ATOM 982 C1 MOL A 1 9.667 21.621 23.469 C +ATOM 983 C2 MOL A 1 10.773 21.285 22.704 C +ATOM 984 C3 MOL A 1 11.588 20.115 23.027 C +ATOM 985 C4 MOL A 1 12.152 18.139 24.093 C +ATOM 986 C5 MOL A 1 11.344 16.879 23.823 C +ATOM 987 C6 MOL A 1 12.184 15.639 24.096 C +ATOM 988 H1 MOL A 1 9.449 21.095 24.205 H +ATOM 989 H2 MOL A 1 12.378 19.986 22.553 H +ATOM 990 H3 MOL A 1 12.911 18.186 23.476 H +ATOM 991 H4 MOL A 1 11.048 16.874 22.898 H +ATOM 992 H5 MOL A 1 10.557 16.869 24.391 H +ATOM 993 H6 MOL A 1 11.666 14.840 23.910 H +ATOM 994 H7 MOL A 1 12.963 15.634 23.515 H +ATOM 995 N1 MOL A 1 11.285 6.890 11.496 N +ATOM 996 C1 MOL A 1 9.667 9.221 11.069 C +ATOM 997 C2 MOL A 1 10.773 8.885 10.304 C +ATOM 998 C3 MOL A 1 11.588 7.715 10.627 C +ATOM 999 C4 MOL A 1 12.152 5.739 11.693 C +ATOM 1000 C5 MOL A 1 11.344 4.479 11.423 C +ATOM 1001 C6 MOL A 1 12.184 3.239 11.696 C +ATOM 1002 H1 MOL A 1 9.449 8.695 11.805 H +ATOM 1003 H2 MOL A 1 12.378 7.586 10.153 H +ATOM 1004 H3 MOL A 1 12.911 5.786 11.076 H +ATOM 1005 H4 MOL A 1 11.048 4.474 10.498 H +ATOM 1006 H5 MOL A 1 10.557 4.469 11.991 H +ATOM 1007 H6 MOL A 1 11.666 2.440 11.510 H +ATOM 1008 H7 MOL A 1 12.963 3.234 11.115 H +ATOM 1009 N1 MOL A 1 11.285 5.510 0.904 N +ATOM 1010 C1 MOL A 1 9.667 3.179 1.331 C +ATOM 1011 C2 MOL A 1 10.773 3.515 2.096 C +ATOM 1012 C3 MOL A 1 11.588 4.685 1.773 C +ATOM 1013 C4 MOL A 1 12.152 6.661 0.707 C +ATOM 1014 C5 MOL A 1 11.344 7.921 0.977 C +ATOM 1015 C6 MOL A 1 12.184 9.161 0.704 C +ATOM 1016 H1 MOL A 1 9.449 3.705 0.595 H +ATOM 1017 H2 MOL A 1 12.378 4.814 2.247 H +ATOM 1018 H3 MOL A 1 12.911 6.614 1.324 H +ATOM 1019 H4 MOL A 1 11.048 7.926 1.902 H +ATOM 1020 H5 MOL A 1 10.557 7.931 0.409 H +ATOM 1021 H6 MOL A 1 11.666 9.960 0.890 H +ATOM 1022 H7 MOL A 1 12.963 9.166 1.285 H +ATOM 1023 N1 MOL A 1 11.285 17.910 13.304 N +ATOM 1024 C1 MOL A 1 9.667 15.579 13.731 C +ATOM 1025 C2 MOL A 1 10.773 15.915 14.496 C +ATOM 1026 C3 MOL A 1 11.588 17.085 14.173 C +ATOM 1027 C4 MOL A 1 12.152 19.061 13.107 C +ATOM 1028 C5 MOL A 1 11.344 20.321 13.377 C +ATOM 1029 C6 MOL A 1 12.184 21.561 13.104 C +ATOM 1030 H1 MOL A 1 9.449 16.105 12.995 H +ATOM 1031 H2 MOL A 1 12.378 17.214 14.647 H +ATOM 1032 H3 MOL A 1 12.911 19.014 13.724 H +ATOM 1033 H4 MOL A 1 11.048 20.326 14.302 H +ATOM 1034 H5 MOL A 1 10.557 20.331 12.809 H +ATOM 1035 H6 MOL A 1 11.666 22.360 13.290 H +ATOM 1036 H7 MOL A 1 12.963 21.566 13.685 H +ATOM 1037 N1 MOL A 1 23.685 5.510 13.304 N +ATOM 1038 C1 MOL A 1 22.067 3.179 13.731 C +ATOM 1039 C2 MOL A 1 23.173 3.515 14.496 C +ATOM 1040 C3 MOL A 1 23.988 4.685 14.173 C +ATOM 1041 C4 MOL A 1 24.552 6.661 13.107 C +ATOM 1042 C5 MOL A 1 23.744 7.921 13.377 C +ATOM 1043 C6 MOL A 1 24.584 9.161 13.104 C +ATOM 1044 H1 MOL A 1 21.849 3.705 12.995 H +ATOM 1045 H2 MOL A 1 24.778 4.814 14.647 H +ATOM 1046 H3 MOL A 1 0.511 6.614 13.724 H +ATOM 1047 H4 MOL A 1 23.448 7.926 14.302 H +ATOM 1048 H5 MOL A 1 22.957 7.931 12.809 H +ATOM 1049 H6 MOL A 1 24.066 9.960 13.290 H +ATOM 1050 H7 MOL A 1 0.563 9.166 13.685 H +ATOM 1051 N1 MOL A 1 23.685 17.910 0.904 N +ATOM 1052 C1 MOL A 1 22.067 15.579 1.331 C +ATOM 1053 C2 MOL A 1 23.173 15.915 2.096 C +ATOM 1054 C3 MOL A 1 23.988 17.085 1.773 C +ATOM 1055 C4 MOL A 1 24.552 19.061 0.707 C +ATOM 1056 C5 MOL A 1 23.744 20.321 0.977 C +ATOM 1057 C6 MOL A 1 24.584 21.561 0.704 C +ATOM 1058 H1 MOL A 1 21.849 16.105 0.595 H +ATOM 1059 H2 MOL A 1 24.778 17.214 2.247 H +ATOM 1060 H3 MOL A 1 0.511 19.014 1.324 H +ATOM 1061 H4 MOL A 1 23.448 20.326 1.902 H +ATOM 1062 H5 MOL A 1 22.957 20.331 0.409 H +ATOM 1063 H6 MOL A 1 24.066 22.360 0.890 H +ATOM 1064 H7 MOL A 1 0.563 21.566 1.285 H +ATOM 1065 N1 MOL A 1 1.115 17.910 23.896 N +ATOM 1066 C1 MOL A 1 2.733 15.579 23.469 C +ATOM 1067 C2 MOL A 1 1.627 15.915 22.704 C +ATOM 1068 C3 MOL A 1 0.812 17.085 23.027 C +ATOM 1069 C4 MOL A 1 0.248 19.061 24.093 C +ATOM 1070 C5 MOL A 1 1.056 20.321 23.823 C +ATOM 1071 C6 MOL A 1 0.216 21.561 24.096 C +ATOM 1072 H1 MOL A 1 2.951 16.105 24.205 H +ATOM 1073 H2 MOL A 1 0.022 17.214 22.553 H +ATOM 1074 H3 MOL A 1 24.289 19.014 23.476 H +ATOM 1075 H4 MOL A 1 1.352 20.326 22.898 H +ATOM 1076 H5 MOL A 1 1.843 20.331 24.391 H +ATOM 1077 H6 MOL A 1 0.734 22.360 23.910 H +ATOM 1078 H7 MOL A 1 24.237 21.566 23.515 H +ATOM 1079 N1 MOL A 1 1.115 5.510 11.496 N +ATOM 1080 C1 MOL A 1 2.733 3.179 11.069 C +ATOM 1081 C2 MOL A 1 1.627 3.515 10.304 C +ATOM 1082 C3 MOL A 1 0.812 4.685 10.627 C +ATOM 1083 C4 MOL A 1 0.248 6.661 11.693 C +ATOM 1084 C5 MOL A 1 1.056 7.921 11.423 C +ATOM 1085 C6 MOL A 1 0.216 9.161 11.696 C +ATOM 1086 H1 MOL A 1 2.951 3.705 11.805 H +ATOM 1087 H2 MOL A 1 0.022 4.814 10.153 H +ATOM 1088 H3 MOL A 1 24.289 6.614 11.076 H +ATOM 1089 H4 MOL A 1 1.352 7.926 10.498 H +ATOM 1090 H5 MOL A 1 1.843 7.931 11.991 H +ATOM 1091 H6 MOL A 1 0.734 9.960 11.510 H +ATOM 1092 H7 MOL A 1 24.237 9.166 11.115 H +ATOM 1093 N1 MOL A 1 13.515 17.910 11.496 N +ATOM 1094 C1 MOL A 1 15.133 15.579 11.069 C +ATOM 1095 C2 MOL A 1 14.027 15.915 10.304 C +ATOM 1096 C3 MOL A 1 13.212 17.085 10.627 C +ATOM 1097 C4 MOL A 1 12.648 19.061 11.693 C +ATOM 1098 C5 MOL A 1 13.456 20.321 11.423 C +ATOM 1099 C6 MOL A 1 12.616 21.561 11.696 C +ATOM 1100 H1 MOL A 1 15.351 16.105 11.805 H +ATOM 1101 H2 MOL A 1 12.422 17.214 10.153 H +ATOM 1102 H3 MOL A 1 11.889 19.014 11.076 H +ATOM 1103 H4 MOL A 1 13.752 20.326 10.498 H +ATOM 1104 H5 MOL A 1 14.243 20.331 11.991 H +ATOM 1105 H6 MOL A 1 13.134 22.360 11.510 H +ATOM 1106 H7 MOL A 1 11.837 21.566 11.115 H +ATOM 1107 N1 MOL A 1 13.515 5.510 23.896 N +ATOM 1108 C1 MOL A 1 15.133 3.179 23.469 C +ATOM 1109 C2 MOL A 1 14.027 3.515 22.704 C +ATOM 1110 C3 MOL A 1 13.212 4.685 23.027 C +ATOM 1111 C4 MOL A 1 12.648 6.661 24.093 C +ATOM 1112 C5 MOL A 1 13.456 7.921 23.823 C +ATOM 1113 C6 MOL A 1 12.616 9.161 24.096 C +ATOM 1114 H1 MOL A 1 15.351 3.705 24.205 H +ATOM 1115 H2 MOL A 1 12.422 4.814 22.553 H +ATOM 1116 H3 MOL A 1 11.889 6.614 23.476 H +ATOM 1117 H4 MOL A 1 13.752 7.926 22.898 H +ATOM 1118 H5 MOL A 1 14.243 7.931 24.391 H +ATOM 1119 H6 MOL A 1 13.134 9.960 23.910 H +ATOM 1120 H7 MOL A 1 11.837 9.166 23.515 H +ATOM 1121 N1 MOL A 1 19.290 11.496 23.685 N +ATOM 1122 C1 MOL A 1 21.621 11.069 22.067 C +ATOM 1123 C2 MOL A 1 21.285 10.304 23.173 C +ATOM 1124 C3 MOL A 1 20.115 10.627 23.988 C +ATOM 1125 C4 MOL A 1 18.139 11.693 24.552 C +ATOM 1126 C5 MOL A 1 16.879 11.423 23.744 C +ATOM 1127 C6 MOL A 1 15.639 11.696 24.584 C +ATOM 1128 H1 MOL A 1 21.095 11.805 21.849 H +ATOM 1129 H2 MOL A 1 19.986 10.153 24.778 H +ATOM 1130 H3 MOL A 1 18.186 11.076 0.511 H +ATOM 1131 H4 MOL A 1 16.874 10.498 23.448 H +ATOM 1132 H5 MOL A 1 16.869 11.991 22.957 H +ATOM 1133 H6 MOL A 1 14.840 11.510 24.066 H +ATOM 1134 H7 MOL A 1 15.634 11.115 0.563 H +ATOM 1135 N1 MOL A 1 19.290 23.896 11.285 N +ATOM 1136 C1 MOL A 1 21.621 23.469 9.667 C +ATOM 1137 C2 MOL A 1 21.285 22.704 10.773 C +ATOM 1138 C3 MOL A 1 20.115 23.027 11.588 C +ATOM 1139 C4 MOL A 1 18.139 24.093 12.152 C +ATOM 1140 C5 MOL A 1 16.879 23.823 11.344 C +ATOM 1141 C6 MOL A 1 15.639 24.096 12.184 C +ATOM 1142 H1 MOL A 1 21.095 24.205 9.449 H +ATOM 1143 H2 MOL A 1 19.986 22.553 12.378 H +ATOM 1144 H3 MOL A 1 18.186 23.476 12.911 H +ATOM 1145 H4 MOL A 1 16.874 22.898 11.048 H +ATOM 1146 H5 MOL A 1 16.869 24.391 10.557 H +ATOM 1147 H6 MOL A 1 14.840 23.910 11.666 H +ATOM 1148 H7 MOL A 1 15.634 23.515 12.963 H +ATOM 1149 N1 MOL A 1 6.890 11.496 11.285 N +ATOM 1150 C1 MOL A 1 9.221 11.069 9.667 C +ATOM 1151 C2 MOL A 1 8.885 10.304 10.773 C +ATOM 1152 C3 MOL A 1 7.715 10.627 11.588 C +ATOM 1153 C4 MOL A 1 5.739 11.693 12.152 C +ATOM 1154 C5 MOL A 1 4.479 11.423 11.344 C +ATOM 1155 C6 MOL A 1 3.239 11.696 12.184 C +ATOM 1156 H1 MOL A 1 8.695 11.805 9.449 H +ATOM 1157 H2 MOL A 1 7.586 10.153 12.378 H +ATOM 1158 H3 MOL A 1 5.786 11.076 12.911 H +ATOM 1159 H4 MOL A 1 4.474 10.498 11.048 H +ATOM 1160 H5 MOL A 1 4.469 11.991 10.557 H +ATOM 1161 H6 MOL A 1 2.440 11.510 11.666 H +ATOM 1162 H7 MOL A 1 3.234 11.115 12.963 H +ATOM 1163 N1 MOL A 1 6.890 23.896 23.685 N +ATOM 1164 C1 MOL A 1 9.221 23.469 22.067 C +ATOM 1165 C2 MOL A 1 8.885 22.704 23.173 C +ATOM 1166 C3 MOL A 1 7.715 23.027 23.988 C +ATOM 1167 C4 MOL A 1 5.739 24.093 24.552 C +ATOM 1168 C5 MOL A 1 4.479 23.823 23.744 C +ATOM 1169 C6 MOL A 1 3.239 24.096 24.584 C +ATOM 1170 H1 MOL A 1 8.695 24.205 21.849 H +ATOM 1171 H2 MOL A 1 7.586 22.553 24.778 H +ATOM 1172 H3 MOL A 1 5.786 23.476 0.511 H +ATOM 1173 H4 MOL A 1 4.474 22.898 23.448 H +ATOM 1174 H5 MOL A 1 4.469 24.391 22.957 H +ATOM 1175 H6 MOL A 1 2.440 23.910 24.066 H +ATOM 1176 H7 MOL A 1 3.234 23.515 0.563 H +ATOM 1177 N1 MOL A 1 6.890 13.304 13.515 N +ATOM 1178 C1 MOL A 1 9.221 13.731 15.133 C +ATOM 1179 C2 MOL A 1 8.885 14.496 14.027 C +ATOM 1180 C3 MOL A 1 7.715 14.173 13.212 C +ATOM 1181 C4 MOL A 1 5.739 13.107 12.648 C +ATOM 1182 C5 MOL A 1 4.479 13.377 13.456 C +ATOM 1183 C6 MOL A 1 3.239 13.104 12.616 C +ATOM 1184 H1 MOL A 1 8.695 12.995 15.351 H +ATOM 1185 H2 MOL A 1 7.586 14.647 12.422 H +ATOM 1186 H3 MOL A 1 5.786 13.724 11.889 H +ATOM 1187 H4 MOL A 1 4.474 14.302 13.752 H +ATOM 1188 H5 MOL A 1 4.469 12.809 14.243 H +ATOM 1189 H6 MOL A 1 2.440 13.290 13.134 H +ATOM 1190 H7 MOL A 1 3.234 13.685 11.837 H +ATOM 1191 N1 MOL A 1 6.890 0.904 1.115 N +ATOM 1192 C1 MOL A 1 9.221 1.331 2.733 C +ATOM 1193 C2 MOL A 1 8.885 2.096 1.627 C +ATOM 1194 C3 MOL A 1 7.715 1.773 0.812 C +ATOM 1195 C4 MOL A 1 5.739 0.707 0.248 C +ATOM 1196 C5 MOL A 1 4.479 0.977 1.056 C +ATOM 1197 C6 MOL A 1 3.239 0.704 0.216 C +ATOM 1198 H1 MOL A 1 8.695 0.595 2.951 H +ATOM 1199 H2 MOL A 1 7.586 2.247 0.022 H +ATOM 1200 H3 MOL A 1 5.786 1.324 24.289 H +ATOM 1201 H4 MOL A 1 4.474 1.902 1.352 H +ATOM 1202 H5 MOL A 1 4.469 0.409 1.843 H +ATOM 1203 H6 MOL A 1 2.440 0.890 0.734 H +ATOM 1204 H7 MOL A 1 3.234 1.285 24.237 H +ATOM 1205 N1 MOL A 1 19.290 13.304 1.115 N +ATOM 1206 C1 MOL A 1 21.621 13.731 2.733 C +ATOM 1207 C2 MOL A 1 21.285 14.496 1.627 C +ATOM 1208 C3 MOL A 1 20.115 14.173 0.812 C +ATOM 1209 C4 MOL A 1 18.139 13.107 0.248 C +ATOM 1210 C5 MOL A 1 16.879 13.377 1.056 C +ATOM 1211 C6 MOL A 1 15.639 13.104 0.216 C +ATOM 1212 H1 MOL A 1 21.095 12.995 2.951 H +ATOM 1213 H2 MOL A 1 19.986 14.647 0.022 H +ATOM 1214 H3 MOL A 1 18.186 13.724 24.289 H +ATOM 1215 H4 MOL A 1 16.874 14.302 1.352 H +ATOM 1216 H5 MOL A 1 16.869 12.809 1.843 H +ATOM 1217 H6 MOL A 1 14.840 13.290 0.734 H +ATOM 1218 H7 MOL A 1 15.634 13.685 24.237 H +ATOM 1219 N1 MOL A 1 19.290 0.904 13.515 N +ATOM 1220 C1 MOL A 1 21.621 1.331 15.133 C +ATOM 1221 C2 MOL A 1 21.285 2.096 14.027 C +ATOM 1222 C3 MOL A 1 20.115 1.773 13.212 C +ATOM 1223 C4 MOL A 1 18.139 0.707 12.648 C +ATOM 1224 C5 MOL A 1 16.879 0.977 13.456 C +ATOM 1225 C6 MOL A 1 15.639 0.704 12.616 C +ATOM 1226 H1 MOL A 1 21.095 0.595 15.351 H +ATOM 1227 H2 MOL A 1 19.986 2.247 12.422 H +ATOM 1228 H3 MOL A 1 18.186 1.324 11.889 H +ATOM 1229 H4 MOL A 1 16.874 1.902 13.752 H +ATOM 1230 H5 MOL A 1 16.869 0.409 14.243 H +ATOM 1231 H6 MOL A 1 14.840 0.890 13.134 H +ATOM 1232 H7 MOL A 1 15.634 1.285 11.837 H +ATOM 1233 N1 MOL A 1 17.910 23.896 1.115 N +ATOM 1234 C1 MOL A 1 15.579 23.469 2.733 C +ATOM 1235 C2 MOL A 1 15.915 22.704 1.627 C +ATOM 1236 C3 MOL A 1 17.085 23.027 0.812 C +ATOM 1237 C4 MOL A 1 19.061 24.093 0.248 C +ATOM 1238 C5 MOL A 1 20.321 23.823 1.056 C +ATOM 1239 C6 MOL A 1 21.561 24.096 0.216 C +ATOM 1240 H1 MOL A 1 16.105 24.205 2.951 H +ATOM 1241 H2 MOL A 1 17.214 22.553 0.022 H +ATOM 1242 H3 MOL A 1 19.014 23.476 24.289 H +ATOM 1243 H4 MOL A 1 20.326 22.898 1.352 H +ATOM 1244 H5 MOL A 1 20.331 24.391 1.843 H +ATOM 1245 H6 MOL A 1 22.360 23.910 0.734 H +ATOM 1246 H7 MOL A 1 21.566 23.515 24.237 H +ATOM 1247 N1 MOL A 1 17.910 11.496 13.515 N +ATOM 1248 C1 MOL A 1 15.579 11.069 15.133 C +ATOM 1249 C2 MOL A 1 15.915 10.304 14.027 C +ATOM 1250 C3 MOL A 1 17.085 10.627 13.212 C +ATOM 1251 C4 MOL A 1 19.061 11.693 12.648 C +ATOM 1252 C5 MOL A 1 20.321 11.423 13.456 C +ATOM 1253 C6 MOL A 1 21.561 11.696 12.616 C +ATOM 1254 H1 MOL A 1 16.105 11.805 15.351 H +ATOM 1255 H2 MOL A 1 17.214 10.153 12.422 H +ATOM 1256 H3 MOL A 1 19.014 11.076 11.889 H +ATOM 1257 H4 MOL A 1 20.326 10.498 13.752 H +ATOM 1258 H5 MOL A 1 20.331 11.991 14.243 H +ATOM 1259 H6 MOL A 1 22.360 11.510 13.134 H +ATOM 1260 H7 MOL A 1 21.566 11.115 11.837 H +ATOM 1261 N1 MOL A 1 5.510 23.896 13.515 N +ATOM 1262 C1 MOL A 1 3.179 23.469 15.133 C +ATOM 1263 C2 MOL A 1 3.515 22.704 14.027 C +ATOM 1264 C3 MOL A 1 4.685 23.027 13.212 C +ATOM 1265 C4 MOL A 1 6.661 24.093 12.648 C +ATOM 1266 C5 MOL A 1 7.921 23.823 13.456 C +ATOM 1267 C6 MOL A 1 9.161 24.096 12.616 C +ATOM 1268 H1 MOL A 1 3.705 24.205 15.351 H +ATOM 1269 H2 MOL A 1 4.814 22.553 12.422 H +ATOM 1270 H3 MOL A 1 6.614 23.476 11.889 H +ATOM 1271 H4 MOL A 1 7.926 22.898 13.752 H +ATOM 1272 H5 MOL A 1 7.931 24.391 14.243 H +ATOM 1273 H6 MOL A 1 9.960 23.910 13.134 H +ATOM 1274 H7 MOL A 1 9.166 23.515 11.837 H +ATOM 1275 N1 MOL A 1 5.510 11.496 1.115 N +ATOM 1276 C1 MOL A 1 3.179 11.069 2.733 C +ATOM 1277 C2 MOL A 1 3.515 10.304 1.627 C +ATOM 1278 C3 MOL A 1 4.685 10.627 0.812 C +ATOM 1279 C4 MOL A 1 6.661 11.693 0.248 C +ATOM 1280 C5 MOL A 1 7.921 11.423 1.056 C +ATOM 1281 C6 MOL A 1 9.161 11.696 0.216 C +ATOM 1282 H1 MOL A 1 3.705 11.805 2.951 H +ATOM 1283 H2 MOL A 1 4.814 10.153 0.022 H +ATOM 1284 H3 MOL A 1 6.614 11.076 24.289 H +ATOM 1285 H4 MOL A 1 7.926 10.498 1.352 H +ATOM 1286 H5 MOL A 1 7.931 11.991 1.843 H +ATOM 1287 H6 MOL A 1 9.960 11.510 0.734 H +ATOM 1288 H7 MOL A 1 9.166 11.115 24.237 H +ATOM 1289 N1 MOL A 1 5.510 0.904 11.285 N +ATOM 1290 C1 MOL A 1 3.179 1.331 9.667 C +ATOM 1291 C2 MOL A 1 3.515 2.096 10.773 C +ATOM 1292 C3 MOL A 1 4.685 1.773 11.588 C +ATOM 1293 C4 MOL A 1 6.661 0.707 12.152 C +ATOM 1294 C5 MOL A 1 7.921 0.977 11.344 C +ATOM 1295 C6 MOL A 1 9.161 0.704 12.184 C +ATOM 1296 H1 MOL A 1 3.705 0.595 9.449 H +ATOM 1297 H2 MOL A 1 4.814 2.247 12.378 H +ATOM 1298 H3 MOL A 1 6.614 1.324 12.911 H +ATOM 1299 H4 MOL A 1 7.926 1.902 11.048 H +ATOM 1300 H5 MOL A 1 7.931 0.409 10.557 H +ATOM 1301 H6 MOL A 1 9.960 0.890 11.666 H +ATOM 1302 H7 MOL A 1 9.166 1.285 12.963 H +ATOM 1303 N1 MOL A 1 5.510 13.304 23.685 N +ATOM 1304 C1 MOL A 1 3.179 13.731 22.067 C +ATOM 1305 C2 MOL A 1 3.515 14.496 23.173 C +ATOM 1306 C3 MOL A 1 4.685 14.173 23.988 C +ATOM 1307 C4 MOL A 1 6.661 13.107 24.552 C +ATOM 1308 C5 MOL A 1 7.921 13.377 23.744 C +ATOM 1309 C6 MOL A 1 9.161 13.104 24.584 C +ATOM 1310 H1 MOL A 1 3.705 12.995 21.849 H +ATOM 1311 H2 MOL A 1 4.814 14.647 24.778 H +ATOM 1312 H3 MOL A 1 6.614 13.724 0.511 H +ATOM 1313 H4 MOL A 1 7.926 14.302 23.448 H +ATOM 1314 H5 MOL A 1 7.931 12.809 22.957 H +ATOM 1315 H6 MOL A 1 9.960 13.290 24.066 H +ATOM 1316 H7 MOL A 1 9.166 13.685 0.563 H +ATOM 1317 N1 MOL A 1 17.910 0.904 23.685 N +ATOM 1318 C1 MOL A 1 15.579 1.331 22.067 C +ATOM 1319 C2 MOL A 1 15.915 2.096 23.173 C +ATOM 1320 C3 MOL A 1 17.085 1.773 23.988 C +ATOM 1321 C4 MOL A 1 19.061 0.707 24.552 C +ATOM 1322 C5 MOL A 1 20.321 0.977 23.744 C +ATOM 1323 C6 MOL A 1 21.561 0.704 24.584 C +ATOM 1324 H1 MOL A 1 16.105 0.595 21.849 H +ATOM 1325 H2 MOL A 1 17.214 2.247 24.778 H +ATOM 1326 H3 MOL A 1 19.014 1.324 0.511 H +ATOM 1327 H4 MOL A 1 20.326 1.902 23.448 H +ATOM 1328 H5 MOL A 1 20.331 0.409 22.957 H +ATOM 1329 H6 MOL A 1 22.360 0.890 24.066 H +ATOM 1330 H7 MOL A 1 21.566 1.285 0.563 H +ATOM 1331 N1 MOL A 1 17.910 13.304 11.285 N +ATOM 1332 C1 MOL A 1 15.579 13.731 9.667 C +ATOM 1333 C2 MOL A 1 15.915 14.496 10.773 C +ATOM 1334 C3 MOL A 1 17.085 14.173 11.588 C +ATOM 1335 C4 MOL A 1 19.061 13.107 12.152 C +ATOM 1336 C5 MOL A 1 20.321 13.377 11.344 C +ATOM 1337 C6 MOL A 1 21.561 13.104 12.184 C +ATOM 1338 H1 MOL A 1 16.105 12.995 9.449 H +ATOM 1339 H2 MOL A 1 17.214 14.647 12.378 H +ATOM 1340 H3 MOL A 1 19.014 13.724 12.911 H +ATOM 1341 H4 MOL A 1 20.326 14.302 11.048 H +ATOM 1342 H5 MOL A 1 20.331 12.809 10.557 H +ATOM 1343 H6 MOL A 1 22.360 13.290 11.666 H +ATOM 1344 H7 MOL A 1 21.566 13.685 12.963 H +END diff --git a/tests/data/system_periodic_rebuild.pdb b/tests/data/system_periodic_rebuild.pdb new file mode 100644 index 0000000..022184c --- /dev/null +++ b/tests/data/system_periodic_rebuild.pdb @@ -0,0 +1,1346 @@ +REMARK File generated using pyWINDOW. +ATOM 1 C6 MOL A 1 9.439 5.984 6.904 C +ATOM 2 C6 MOL A 1 9.439 6.416 5.496 C +ATOM 3 C5 MOL A 1 10.679 5.144 7.177 C +ATOM 4 H6 MOL A 1 8.640 5.466 7.090 H +ATOM 5 H7 MOL A 1 9.434 6.763 7.485 H +ATOM 6 C5 MOL A 1 10.679 7.256 5.223 C +ATOM 7 H6 MOL A 1 8.640 6.934 5.310 H +ATOM 8 H7 MOL A 1 9.434 5.637 4.915 H +ATOM 9 C4 MOL A 1 11.939 5.952 6.907 C +ATOM 10 H4 MOL A 1 10.674 4.848 8.102 H +ATOM 11 H5 MOL A 1 10.669 4.357 6.609 H +ATOM 12 C4 MOL A 1 11.939 6.448 5.493 C +ATOM 13 H4 MOL A 1 10.674 7.552 4.298 H +ATOM 14 H5 MOL A 1 10.669 8.043 5.791 H +ATOM 15 N1 MOL A 1 13.090 5.085 7.104 N +ATOM 16 H3 MOL A 1 11.986 6.711 7.524 H +ATOM 17 N1 MOL A 1 13.090 7.315 5.296 N +ATOM 18 H3 MOL A 1 11.986 5.689 4.876 H +ATOM 19 C3 MOL A 1 13.915 5.388 7.973 C +ATOM 20 C3 MOL A 1 13.915 7.012 4.427 C +ATOM 21 C2 MOL A 1 15.085 4.573 8.296 C +ATOM 22 H2 MOL A 1 13.786 6.178 8.447 H +ATOM 23 C2 MOL A 1 15.085 7.827 4.104 C +ATOM 24 H2 MOL A 1 13.786 6.222 3.953 H +ATOM 25 C1 MOL A 1 15.867 4.869 9.379 C +ATOM 26 C1 MOL A 1 15.421 3.467 7.531 C +ATOM 27 C1 MOL A 1 15.867 7.531 3.021 C +ATOM 28 C1 MOL A 1 15.421 8.933 4.869 C +ATOM 29 C2 MOL A 1 16.973 4.104 9.715 C +ATOM 30 H1 MOL A 1 15.649 5.605 9.905 H +ATOM 31 H1 MOL A 1 14.895 3.249 6.795 H +ATOM 32 C2 MOL A 1 16.504 2.685 7.827 C +ATOM 33 C2 MOL A 1 16.973 8.296 2.685 C +ATOM 34 H1 MOL A 1 15.649 6.795 2.495 H +ATOM 35 H1 MOL A 1 14.895 9.151 5.605 H +ATOM 36 C2 MOL A 1 16.504 9.715 4.573 C +ATOM 37 C3 MOL A 1 17.788 4.427 10.885 C +ATOM 38 C1 MOL A 1 17.269 3.021 8.933 C +ATOM 39 C3 MOL A 1 16.827 1.515 7.012 C +ATOM 40 C3 MOL A 1 17.788 7.973 1.515 C +ATOM 41 C1 MOL A 1 17.269 9.379 3.467 C +ATOM 42 C3 MOL A 1 16.827 10.885 5.388 C +ATOM 43 N1 MOL A 1 17.485 5.296 11.710 N +ATOM 44 H2 MOL A 1 18.578 3.953 11.014 H +ATOM 45 H1 MOL A 1 18.005 2.495 9.151 H +ATOM 46 N1 MOL A 1 17.696 0.690 7.315 N +ATOM 47 H2 MOL A 1 16.353 1.386 6.222 H +ATOM 48 N1 MOL A 1 17.485 7.104 0.690 N +ATOM 49 H2 MOL A 1 18.578 8.447 1.386 H +ATOM 50 H1 MOL A 1 18.005 9.905 3.249 H +ATOM 51 N1 MOL A 1 17.696 11.710 5.085 N +ATOM 52 H2 MOL A 1 16.353 11.014 6.178 H +ATOM 53 C4 MOL A 1 18.352 5.493 12.861 C +ATOM 54 C4 MOL A 1 17.893 -0.461 6.448 C +ATOM 55 C4 MOL A 1 18.352 6.907 -0.461 C +ATOM 56 C4 MOL A 1 17.893 12.861 5.952 C +ATOM 57 C5 MOL A 1 17.544 5.223 14.121 C +ATOM 58 H3 MOL A 1 19.111 4.876 12.814 H +ATOM 59 C4 MOL A 1 18.848 6.907 12.861 C +ATOM 60 C5 MOL A 1 17.623 -1.721 7.256 C +ATOM 61 H3 MOL A 1 17.276 -0.414 5.689 H +ATOM 62 C4 MOL A 1 19.307 -0.461 5.952 C +ATOM 63 C4 MOL A 1 18.848 5.493 -0.461 C +ATOM 64 C5 MOL A 1 17.544 7.177 -1.721 C +ATOM 65 H3 MOL A 1 19.111 7.524 -0.414 H +ATOM 66 C5 MOL A 1 17.623 14.121 5.144 C +ATOM 67 H3 MOL A 1 17.276 12.814 6.711 H +ATOM 68 C4 MOL A 1 19.307 12.861 6.448 C +ATOM 69 C6 MOL A 1 18.384 5.496 15.361 C +ATOM 70 H4 MOL A 1 17.248 4.298 14.126 H +ATOM 71 H5 MOL A 1 16.757 5.791 14.131 H +ATOM 72 N1 MOL A 1 19.715 7.104 11.710 N +ATOM 73 C5 MOL A 1 19.656 7.177 14.121 C +ATOM 74 H3 MOL A 1 18.089 7.524 12.814 H +ATOM 75 C6 MOL A 1 17.896 -2.961 6.416 C +ATOM 76 H4 MOL A 1 16.698 -1.726 7.552 H +ATOM 77 H5 MOL A 1 18.191 -1.731 8.043 H +ATOM 78 N1 MOL A 1 19.504 0.690 5.085 N +ATOM 79 C5 MOL A 1 19.577 -1.721 5.144 C +ATOM 80 H3 MOL A 1 19.924 -0.414 6.711 H +ATOM 81 N1 MOL A 1 19.715 5.296 0.690 N +ATOM 82 C5 MOL A 1 19.656 5.223 -1.721 C +ATOM 83 H3 MOL A 1 18.089 4.876 -0.414 H +ATOM 84 C6 MOL A 1 18.384 6.904 -2.961 C +ATOM 85 H4 MOL A 1 17.248 8.102 -1.726 H +ATOM 86 H5 MOL A 1 16.757 6.609 -1.731 H +ATOM 87 C6 MOL A 1 17.896 15.361 5.984 C +ATOM 88 H4 MOL A 1 16.698 14.126 4.848 H +ATOM 89 H5 MOL A 1 18.191 14.131 4.357 H +ATOM 90 N1 MOL A 1 19.504 11.710 7.315 N +ATOM 91 C5 MOL A 1 19.577 14.121 7.256 C +ATOM 92 H3 MOL A 1 19.924 12.814 5.689 H +ATOM 93 H6 MOL A 1 17.866 5.310 16.160 H +ATOM 94 H7 MOL A 1 19.163 4.915 15.366 H +ATOM 95 C6 MOL A 1 18.816 6.904 15.361 C +ATOM 96 C3 MOL A 1 19.412 7.973 10.885 C +ATOM 97 H4 MOL A 1 19.952 8.102 14.126 H +ATOM 98 H5 MOL A 1 20.443 6.609 14.131 H +ATOM 99 H6 MOL A 1 17.710 -3.760 6.934 H +ATOM 100 H7 MOL A 1 17.315 -2.966 5.637 H +ATOM 101 C6 MOL A 1 19.304 -2.961 5.984 C +ATOM 102 C3 MOL A 1 20.373 1.515 5.388 C +ATOM 103 H4 MOL A 1 20.502 -1.726 4.848 H +ATOM 104 H5 MOL A 1 19.009 -1.731 4.357 H +ATOM 105 C3 MOL A 1 19.412 4.427 1.515 C +ATOM 106 C6 MOL A 1 18.816 5.496 -2.961 C +ATOM 107 H4 MOL A 1 19.952 4.298 -1.726 H +ATOM 108 H5 MOL A 1 20.443 5.791 -1.731 H +ATOM 109 H6 MOL A 1 17.866 7.090 -3.760 H +ATOM 110 H7 MOL A 1 19.163 7.485 -2.966 H +ATOM 111 H6 MOL A 1 17.710 16.160 5.466 H +ATOM 112 H7 MOL A 1 17.315 15.366 6.763 H +ATOM 113 C6 MOL A 1 19.304 15.361 6.416 C +ATOM 114 C3 MOL A 1 20.373 10.885 7.012 C +ATOM 115 H4 MOL A 1 20.502 14.126 7.552 H +ATOM 116 H5 MOL A 1 19.009 14.131 8.043 H +ATOM 117 H6 MOL A 1 19.334 7.090 16.160 H +ATOM 118 H7 MOL A 1 18.037 7.485 15.366 H +ATOM 119 C2 MOL A 1 20.227 8.296 9.715 C +ATOM 120 H2 MOL A 1 18.622 8.447 11.014 H +ATOM 121 H6 MOL A 1 19.490 -3.760 5.466 H +ATOM 122 H7 MOL A 1 19.885 -2.966 6.763 H +ATOM 123 C2 MOL A 1 20.696 2.685 4.573 C +ATOM 124 H2 MOL A 1 20.847 1.386 6.178 H +ATOM 125 C2 MOL A 1 20.227 4.104 2.685 C +ATOM 126 H2 MOL A 1 18.622 3.953 1.386 H +ATOM 127 H6 MOL A 1 19.334 5.310 -3.760 H +ATOM 128 H7 MOL A 1 18.037 4.915 -2.966 H +ATOM 129 H6 MOL A 1 19.490 16.160 6.934 H +ATOM 130 H7 MOL A 1 19.885 15.366 5.637 H +ATOM 131 C2 MOL A 1 20.696 9.715 7.827 C +ATOM 132 H2 MOL A 1 20.847 11.014 6.222 H +ATOM 133 C1 MOL A 1 21.333 7.531 9.379 C +ATOM 134 C1 MOL A 1 19.931 9.379 8.933 C +ATOM 135 C1 MOL A 1 21.779 3.467 4.869 C +ATOM 136 C1 MOL A 1 19.931 3.021 3.467 C +ATOM 137 C1 MOL A 1 21.333 4.869 3.021 C +ATOM 138 C1 MOL A 1 21.779 8.933 7.531 C +ATOM 139 H1 MOL A 1 21.551 6.795 9.905 H +ATOM 140 C2 MOL A 1 22.115 7.827 8.296 C +ATOM 141 H1 MOL A 1 19.195 9.905 9.151 H +ATOM 142 C2 MOL A 1 22.115 4.573 4.104 C +ATOM 143 H1 MOL A 1 22.305 3.249 5.605 H +ATOM 144 H1 MOL A 1 19.195 2.495 3.249 H +ATOM 145 H1 MOL A 1 21.551 5.605 2.495 H +ATOM 146 H1 MOL A 1 22.305 9.151 6.795 H +ATOM 147 C3 MOL A 1 23.285 7.012 7.973 C +ATOM 148 C3 MOL A 1 23.285 5.388 4.427 C +ATOM 149 N1 MOL A 1 24.110 7.315 7.104 N +ATOM 150 H2 MOL A 1 23.414 6.222 8.447 H +ATOM 151 N1 MOL A 1 24.110 5.085 5.296 N +ATOM 152 H2 MOL A 1 23.414 6.178 3.953 H +ATOM 153 C4 MOL A 1 25.261 6.448 6.907 C +ATOM 154 C4 MOL A 1 25.261 5.952 5.493 C +ATOM 155 C5 MOL A 1 26.521 7.256 7.177 C +ATOM 156 H3 MOL A 1 25.214 5.689 7.524 H +ATOM 157 C5 MOL A 1 26.521 5.144 5.223 C +ATOM 158 H3 MOL A 1 25.214 6.711 4.876 H +ATOM 159 C6 MOL A 1 27.761 6.416 6.904 C +ATOM 160 H4 MOL A 1 26.526 7.552 8.102 H +ATOM 161 H5 MOL A 1 26.531 8.043 6.609 H +ATOM 162 C6 MOL A 1 27.761 5.984 5.496 C +ATOM 163 H4 MOL A 1 26.526 4.848 4.298 H +ATOM 164 H5 MOL A 1 26.531 4.357 5.791 H +ATOM 165 H6 MOL A 1 28.560 6.934 7.090 H +ATOM 166 H7 MOL A 1 27.766 5.637 7.485 H +ATOM 167 H6 MOL A 1 28.560 5.466 5.310 H +ATOM 168 H7 MOL A 1 27.766 6.763 4.915 H +ATOM 169 C6 MOL A 1 6.904 9.439 5.984 C +ATOM 170 C6 MOL A 1 5.496 9.439 6.416 C +ATOM 171 C5 MOL A 1 7.177 10.679 5.144 C +ATOM 172 H6 MOL A 1 7.090 8.640 5.466 H +ATOM 173 H7 MOL A 1 7.485 9.434 6.763 H +ATOM 174 C5 MOL A 1 5.223 10.679 7.256 C +ATOM 175 H6 MOL A 1 5.310 8.640 6.934 H +ATOM 176 H7 MOL A 1 4.915 9.434 5.637 H +ATOM 177 C4 MOL A 1 6.907 11.939 5.952 C +ATOM 178 H4 MOL A 1 8.102 10.674 4.848 H +ATOM 179 H5 MOL A 1 6.609 10.669 4.357 H +ATOM 180 C4 MOL A 1 5.493 11.939 6.448 C +ATOM 181 H4 MOL A 1 4.298 10.674 7.552 H +ATOM 182 H5 MOL A 1 5.791 10.669 8.043 H +ATOM 183 N1 MOL A 1 7.104 13.090 5.085 N +ATOM 184 H3 MOL A 1 7.524 11.986 6.711 H +ATOM 185 N1 MOL A 1 5.296 13.090 7.315 N +ATOM 186 H3 MOL A 1 4.876 11.986 5.689 H +ATOM 187 C3 MOL A 1 7.973 13.915 5.388 C +ATOM 188 C3 MOL A 1 4.427 13.915 7.012 C +ATOM 189 C2 MOL A 1 8.296 15.085 4.573 C +ATOM 190 H2 MOL A 1 8.447 13.786 6.178 H +ATOM 191 C2 MOL A 1 4.104 15.085 7.827 C +ATOM 192 H2 MOL A 1 3.953 13.786 6.222 H +ATOM 193 C1 MOL A 1 9.379 15.867 4.869 C +ATOM 194 C1 MOL A 1 7.531 15.421 3.467 C +ATOM 195 C1 MOL A 1 3.021 15.867 7.531 C +ATOM 196 C1 MOL A 1 4.869 15.421 8.933 C +ATOM 197 C2 MOL A 1 9.715 16.973 4.104 C +ATOM 198 H1 MOL A 1 9.905 15.649 5.605 H +ATOM 199 C2 MOL A 1 7.827 16.504 2.685 C +ATOM 200 H1 MOL A 1 6.795 14.895 3.249 H +ATOM 201 C2 MOL A 1 2.685 16.973 8.296 C +ATOM 202 H1 MOL A 1 2.495 15.649 6.795 H +ATOM 203 C2 MOL A 1 4.573 16.504 9.715 C +ATOM 204 H1 MOL A 1 5.605 14.895 9.151 H +ATOM 205 C1 MOL A 1 8.933 17.269 3.021 C +ATOM 206 C3 MOL A 1 10.885 17.788 4.427 C +ATOM 207 C3 MOL A 1 7.012 16.827 1.515 C +ATOM 208 C1 MOL A 1 3.467 17.269 9.379 C +ATOM 209 C3 MOL A 1 1.515 17.788 7.973 C +ATOM 210 C3 MOL A 1 5.388 16.827 10.885 C +ATOM 211 H1 MOL A 1 9.151 18.005 2.495 H +ATOM 212 N1 MOL A 1 11.710 17.485 5.296 N +ATOM 213 H2 MOL A 1 11.014 18.578 3.953 H +ATOM 214 N1 MOL A 1 7.315 17.696 0.690 N +ATOM 215 H2 MOL A 1 6.222 16.353 1.386 H +ATOM 216 H1 MOL A 1 3.249 18.005 9.905 H +ATOM 217 N1 MOL A 1 0.690 17.485 7.104 N +ATOM 218 H2 MOL A 1 1.386 18.578 8.447 H +ATOM 219 N1 MOL A 1 5.085 17.696 11.710 N +ATOM 220 H2 MOL A 1 6.178 16.353 11.014 H +ATOM 221 C4 MOL A 1 12.861 18.352 5.493 C +ATOM 222 C4 MOL A 1 6.448 17.893 -0.461 C +ATOM 223 C4 MOL A 1 -0.461 18.352 6.907 C +ATOM 224 C4 MOL A 1 5.952 17.893 12.861 C +ATOM 225 C5 MOL A 1 14.121 17.544 5.223 C +ATOM 226 H3 MOL A 1 12.814 19.111 4.876 H +ATOM 227 C4 MOL A 1 12.861 18.848 6.907 C +ATOM 228 C5 MOL A 1 7.256 17.623 -1.721 C +ATOM 229 H3 MOL A 1 5.689 17.276 -0.414 H +ATOM 230 C4 MOL A 1 5.952 19.307 -0.461 C +ATOM 231 C4 MOL A 1 -0.461 18.848 5.493 C +ATOM 232 C5 MOL A 1 -1.721 17.544 7.177 C +ATOM 233 H3 MOL A 1 -0.414 19.111 7.524 H +ATOM 234 C5 MOL A 1 5.144 17.623 14.121 C +ATOM 235 H3 MOL A 1 6.711 17.276 12.814 H +ATOM 236 C4 MOL A 1 6.448 19.307 12.861 C +ATOM 237 C6 MOL A 1 15.361 18.384 5.496 C +ATOM 238 H4 MOL A 1 14.126 17.248 4.298 H +ATOM 239 H5 MOL A 1 14.131 16.757 5.791 H +ATOM 240 N1 MOL A 1 11.710 19.715 7.104 N +ATOM 241 C5 MOL A 1 14.121 19.656 7.177 C +ATOM 242 H3 MOL A 1 12.814 18.089 7.524 H +ATOM 243 C6 MOL A 1 6.416 17.896 -2.961 C +ATOM 244 H4 MOL A 1 7.552 16.698 -1.726 H +ATOM 245 H5 MOL A 1 8.043 18.191 -1.731 H +ATOM 246 N1 MOL A 1 5.085 19.504 0.690 N +ATOM 247 C5 MOL A 1 5.144 19.577 -1.721 C +ATOM 248 H3 MOL A 1 6.711 19.924 -0.414 H +ATOM 249 N1 MOL A 1 0.690 19.715 5.296 N +ATOM 250 C5 MOL A 1 -1.721 19.656 5.223 C +ATOM 251 H3 MOL A 1 -0.414 18.089 4.876 H +ATOM 252 C6 MOL A 1 -2.961 18.384 6.904 C +ATOM 253 H4 MOL A 1 -1.726 17.248 8.102 H +ATOM 254 H5 MOL A 1 -1.731 16.757 6.609 H +ATOM 255 C6 MOL A 1 5.984 17.896 15.361 C +ATOM 256 H4 MOL A 1 4.848 16.698 14.126 H +ATOM 257 H5 MOL A 1 4.357 18.191 14.131 H +ATOM 258 N1 MOL A 1 7.315 19.504 11.710 N +ATOM 259 C5 MOL A 1 7.256 19.577 14.121 C +ATOM 260 H3 MOL A 1 5.689 19.924 12.814 H +ATOM 261 H6 MOL A 1 16.160 17.866 5.310 H +ATOM 262 H7 MOL A 1 15.366 19.163 4.915 H +ATOM 263 C6 MOL A 1 15.361 18.816 6.904 C +ATOM 264 C3 MOL A 1 10.885 19.412 7.973 C +ATOM 265 H4 MOL A 1 14.126 19.952 8.102 H +ATOM 266 H5 MOL A 1 14.131 20.443 6.609 H +ATOM 267 H6 MOL A 1 6.934 17.710 -3.760 H +ATOM 268 H7 MOL A 1 5.637 17.315 -2.966 H +ATOM 269 C6 MOL A 1 5.984 19.304 -2.961 C +ATOM 270 C3 MOL A 1 5.388 20.373 1.515 C +ATOM 271 H4 MOL A 1 4.848 20.502 -1.726 H +ATOM 272 H5 MOL A 1 4.357 19.009 -1.731 H +ATOM 273 C3 MOL A 1 1.515 19.412 4.427 C +ATOM 274 C6 MOL A 1 -2.961 18.816 5.496 C +ATOM 275 H4 MOL A 1 -1.726 19.952 4.298 H +ATOM 276 H5 MOL A 1 -1.731 20.443 5.791 H +ATOM 277 H6 MOL A 1 -3.760 17.866 7.090 H +ATOM 278 H7 MOL A 1 -2.966 19.163 7.485 H +ATOM 279 H6 MOL A 1 5.466 17.710 16.160 H +ATOM 280 H7 MOL A 1 6.763 17.315 15.366 H +ATOM 281 C6 MOL A 1 6.416 19.304 15.361 C +ATOM 282 C3 MOL A 1 7.012 20.373 10.885 C +ATOM 283 H4 MOL A 1 7.552 20.502 14.126 H +ATOM 284 H5 MOL A 1 8.043 19.009 14.131 H +ATOM 285 H6 MOL A 1 16.160 19.334 7.090 H +ATOM 286 H7 MOL A 1 15.366 18.037 7.485 H +ATOM 287 C2 MOL A 1 9.715 20.227 8.296 C +ATOM 288 H2 MOL A 1 11.014 18.622 8.447 H +ATOM 289 H6 MOL A 1 5.466 19.490 -3.760 H +ATOM 290 H7 MOL A 1 6.763 19.885 -2.966 H +ATOM 291 C2 MOL A 1 4.573 20.696 2.685 C +ATOM 292 H2 MOL A 1 6.178 20.847 1.386 H +ATOM 293 C2 MOL A 1 2.685 20.227 4.104 C +ATOM 294 H2 MOL A 1 1.386 18.622 3.953 H +ATOM 295 H6 MOL A 1 -3.760 19.334 5.310 H +ATOM 296 H7 MOL A 1 -2.966 18.037 4.915 H +ATOM 297 H6 MOL A 1 6.934 19.490 16.160 H +ATOM 298 H7 MOL A 1 5.637 19.885 15.366 H +ATOM 299 C2 MOL A 1 7.827 20.696 9.715 C +ATOM 300 H2 MOL A 1 6.222 20.847 11.014 H +ATOM 301 C1 MOL A 1 8.933 19.931 9.379 C +ATOM 302 C1 MOL A 1 9.379 21.333 7.531 C +ATOM 303 C1 MOL A 1 3.467 19.931 3.021 C +ATOM 304 C1 MOL A 1 4.869 21.779 3.467 C +ATOM 305 C1 MOL A 1 3.021 21.333 4.869 C +ATOM 306 C1 MOL A 1 7.531 21.779 8.933 C +ATOM 307 H1 MOL A 1 9.151 19.195 9.905 H +ATOM 308 H1 MOL A 1 9.905 21.551 6.795 H +ATOM 309 C2 MOL A 1 8.296 22.115 7.827 C +ATOM 310 H1 MOL A 1 3.249 19.195 2.495 H +ATOM 311 C2 MOL A 1 4.104 22.115 4.573 C +ATOM 312 H1 MOL A 1 5.605 22.305 3.249 H +ATOM 313 H1 MOL A 1 2.495 21.551 5.605 H +ATOM 314 H1 MOL A 1 6.795 22.305 9.151 H +ATOM 315 C3 MOL A 1 7.973 23.285 7.012 C +ATOM 316 C3 MOL A 1 4.427 23.285 5.388 C +ATOM 317 N1 MOL A 1 7.104 24.110 7.315 N +ATOM 318 H2 MOL A 1 8.447 23.414 6.222 H +ATOM 319 N1 MOL A 1 5.296 24.110 5.085 N +ATOM 320 H2 MOL A 1 3.953 23.414 6.178 H +ATOM 321 C4 MOL A 1 6.907 25.261 6.448 C +ATOM 322 C4 MOL A 1 5.493 25.261 5.952 C +ATOM 323 C5 MOL A 1 7.177 26.521 7.256 C +ATOM 324 H3 MOL A 1 7.524 25.214 5.689 H +ATOM 325 C5 MOL A 1 5.223 26.521 5.144 C +ATOM 326 H3 MOL A 1 4.876 25.214 6.711 H +ATOM 327 C6 MOL A 1 6.904 27.761 6.416 C +ATOM 328 H4 MOL A 1 8.102 26.526 7.552 H +ATOM 329 H5 MOL A 1 6.609 26.531 8.043 H +ATOM 330 C6 MOL A 1 5.496 27.761 5.984 C +ATOM 331 H4 MOL A 1 4.298 26.526 4.848 H +ATOM 332 H5 MOL A 1 5.791 26.531 4.357 H +ATOM 333 H6 MOL A 1 7.090 28.560 6.934 H +ATOM 334 H7 MOL A 1 7.485 27.766 5.637 H +ATOM 335 H6 MOL A 1 5.310 28.560 5.466 H +ATOM 336 H7 MOL A 1 4.915 27.766 6.763 H +ATOM 337 C6 MOL A 1 6.416 5.496 9.439 C +ATOM 338 C5 MOL A 1 7.256 5.223 10.679 C +ATOM 339 H6 MOL A 1 6.934 5.310 8.640 H +ATOM 340 H7 MOL A 1 5.637 4.915 9.434 H +ATOM 341 C6 MOL A 1 5.984 6.904 9.439 C +ATOM 342 C4 MOL A 1 6.448 5.493 11.939 C +ATOM 343 H4 MOL A 1 7.552 4.298 10.674 H +ATOM 344 H5 MOL A 1 8.043 5.791 10.669 H +ATOM 345 C5 MOL A 1 5.144 7.177 10.679 C +ATOM 346 H6 MOL A 1 5.466 7.090 8.640 H +ATOM 347 H7 MOL A 1 6.763 7.485 9.434 H +ATOM 348 N1 MOL A 1 7.315 5.296 13.090 N +ATOM 349 H3 MOL A 1 5.689 4.876 11.986 H +ATOM 350 C4 MOL A 1 5.952 6.907 11.939 C +ATOM 351 H4 MOL A 1 4.848 8.102 10.674 H +ATOM 352 H5 MOL A 1 4.357 6.609 10.669 H +ATOM 353 C3 MOL A 1 7.012 4.427 13.915 C +ATOM 354 N1 MOL A 1 5.085 7.104 13.090 N +ATOM 355 H3 MOL A 1 6.711 7.524 11.986 H +ATOM 356 C2 MOL A 1 7.827 4.104 15.085 C +ATOM 357 H2 MOL A 1 6.222 3.953 13.786 H +ATOM 358 C3 MOL A 1 5.388 7.973 13.915 C +ATOM 359 C1 MOL A 1 8.933 4.869 15.421 C +ATOM 360 C1 MOL A 1 7.531 3.021 15.867 C +ATOM 361 C2 MOL A 1 4.573 8.296 15.085 C +ATOM 362 H2 MOL A 1 6.178 8.447 13.786 H +ATOM 363 H1 MOL A 1 9.151 5.605 14.895 H +ATOM 364 C2 MOL A 1 9.715 4.573 16.504 C +ATOM 365 C2 MOL A 1 8.296 2.685 16.973 C +ATOM 366 H1 MOL A 1 6.795 2.495 15.649 H +ATOM 367 C1 MOL A 1 3.467 7.531 15.421 C +ATOM 368 C1 MOL A 1 4.869 9.379 15.867 C +ATOM 369 C1 MOL A 1 9.379 3.467 17.269 C +ATOM 370 C3 MOL A 1 10.885 5.388 16.827 C +ATOM 371 C3 MOL A 1 7.973 1.515 17.788 C +ATOM 372 H1 MOL A 1 3.249 6.795 14.895 H +ATOM 373 C2 MOL A 1 2.685 7.827 16.504 C +ATOM 374 C2 MOL A 1 4.104 9.715 16.973 C +ATOM 375 H1 MOL A 1 5.605 9.905 15.649 H +ATOM 376 H1 MOL A 1 9.905 3.249 18.005 H +ATOM 377 N1 MOL A 1 11.710 5.085 17.696 N +ATOM 378 H2 MOL A 1 11.014 6.178 16.353 H +ATOM 379 N1 MOL A 1 7.104 0.690 17.485 N +ATOM 380 H2 MOL A 1 8.447 1.386 18.578 H +ATOM 381 C1 MOL A 1 3.021 8.933 17.269 C +ATOM 382 C3 MOL A 1 1.515 7.012 16.827 C +ATOM 383 C3 MOL A 1 4.427 10.885 17.788 C +ATOM 384 C4 MOL A 1 12.861 5.952 17.893 C +ATOM 385 C4 MOL A 1 6.907 -0.461 18.352 C +ATOM 386 H1 MOL A 1 2.495 9.151 18.005 H +ATOM 387 N1 MOL A 1 0.690 7.315 17.696 N +ATOM 388 H2 MOL A 1 1.386 6.222 16.353 H +ATOM 389 N1 MOL A 1 5.296 11.710 17.485 N +ATOM 390 H2 MOL A 1 3.953 11.014 18.578 H +ATOM 391 C5 MOL A 1 14.121 5.144 17.623 C +ATOM 392 H3 MOL A 1 12.814 6.711 17.276 H +ATOM 393 C4 MOL A 1 12.861 6.448 19.307 C +ATOM 394 C4 MOL A 1 5.493 -0.461 18.848 C +ATOM 395 C5 MOL A 1 7.177 -1.721 17.544 C +ATOM 396 H3 MOL A 1 7.524 -0.414 19.111 H +ATOM 397 C4 MOL A 1 -0.461 6.448 17.893 C +ATOM 398 C4 MOL A 1 5.493 12.861 18.352 C +ATOM 399 C6 MOL A 1 15.361 5.984 17.896 C +ATOM 400 H4 MOL A 1 14.126 4.848 16.698 H +ATOM 401 H5 MOL A 1 14.131 4.357 18.191 H +ATOM 402 N1 MOL A 1 11.710 7.315 19.504 N +ATOM 403 C5 MOL A 1 14.121 7.256 19.577 C +ATOM 404 H3 MOL A 1 12.814 5.689 19.924 H +ATOM 405 N1 MOL A 1 5.296 0.690 19.715 N +ATOM 406 C5 MOL A 1 5.223 -1.721 19.656 C +ATOM 407 H3 MOL A 1 4.876 -0.414 18.089 H +ATOM 408 C6 MOL A 1 6.904 -2.961 18.384 C +ATOM 409 H4 MOL A 1 8.102 -1.726 17.248 H +ATOM 410 H5 MOL A 1 6.609 -1.731 16.757 H +ATOM 411 C5 MOL A 1 -1.721 7.256 17.623 C +ATOM 412 H3 MOL A 1 -0.414 5.689 17.276 H +ATOM 413 C4 MOL A 1 -0.461 5.952 19.307 C +ATOM 414 C5 MOL A 1 5.223 14.121 17.544 C +ATOM 415 H3 MOL A 1 4.876 12.814 19.111 H +ATOM 416 C4 MOL A 1 6.907 12.861 18.848 C +ATOM 417 H6 MOL A 1 16.160 5.466 17.710 H +ATOM 418 H7 MOL A 1 15.366 6.763 17.315 H +ATOM 419 C6 MOL A 1 15.361 6.416 19.304 C +ATOM 420 C3 MOL A 1 10.885 7.012 20.373 C +ATOM 421 H4 MOL A 1 14.126 7.552 20.502 H +ATOM 422 H5 MOL A 1 14.131 8.043 19.009 H +ATOM 423 C3 MOL A 1 4.427 1.515 19.412 C +ATOM 424 C6 MOL A 1 5.496 -2.961 18.816 C +ATOM 425 H4 MOL A 1 4.298 -1.726 19.952 H +ATOM 426 H5 MOL A 1 5.791 -1.731 20.443 H +ATOM 427 H6 MOL A 1 7.090 -3.760 17.866 H +ATOM 428 H7 MOL A 1 7.485 -2.966 19.163 H +ATOM 429 C6 MOL A 1 -2.961 6.416 17.896 C +ATOM 430 H4 MOL A 1 -1.726 7.552 16.698 H +ATOM 431 H5 MOL A 1 -1.731 8.043 18.191 H +ATOM 432 N1 MOL A 1 0.690 5.085 19.504 N +ATOM 433 C5 MOL A 1 -1.721 5.144 19.577 C +ATOM 434 H3 MOL A 1 -0.414 6.711 19.924 H +ATOM 435 C6 MOL A 1 5.496 15.361 18.384 C +ATOM 436 H4 MOL A 1 4.298 14.126 17.248 H +ATOM 437 H5 MOL A 1 5.791 14.131 16.757 H +ATOM 438 N1 MOL A 1 7.104 11.710 19.715 N +ATOM 439 C5 MOL A 1 7.177 14.121 19.656 C +ATOM 440 H3 MOL A 1 7.524 12.814 18.089 H +ATOM 441 H6 MOL A 1 16.160 6.934 19.490 H +ATOM 442 H7 MOL A 1 15.366 5.637 19.885 H +ATOM 443 C2 MOL A 1 9.715 7.827 20.696 C +ATOM 444 H2 MOL A 1 11.014 6.222 20.847 H +ATOM 445 C2 MOL A 1 4.104 2.685 20.227 C +ATOM 446 H2 MOL A 1 3.953 1.386 18.622 H +ATOM 447 H6 MOL A 1 5.310 -3.760 19.334 H +ATOM 448 H7 MOL A 1 4.915 -2.966 18.037 H +ATOM 449 H6 MOL A 1 -3.760 6.934 17.710 H +ATOM 450 H7 MOL A 1 -2.966 5.637 17.315 H +ATOM 451 C6 MOL A 1 -2.961 5.984 19.304 C +ATOM 452 C3 MOL A 1 1.515 5.388 20.373 C +ATOM 453 H4 MOL A 1 -1.726 4.848 20.502 H +ATOM 454 H5 MOL A 1 -1.731 4.357 19.009 H +ATOM 455 H6 MOL A 1 5.310 16.160 17.866 H +ATOM 456 H7 MOL A 1 4.915 15.366 19.163 H +ATOM 457 C6 MOL A 1 6.904 15.361 18.816 C +ATOM 458 C3 MOL A 1 7.973 10.885 19.412 C +ATOM 459 H4 MOL A 1 8.102 14.126 19.952 H +ATOM 460 H5 MOL A 1 6.609 14.131 20.443 H +ATOM 461 C1 MOL A 1 8.933 7.531 21.779 C +ATOM 462 C1 MOL A 1 9.379 8.933 19.931 C +ATOM 463 C1 MOL A 1 3.021 3.467 19.931 C +ATOM 464 C1 MOL A 1 4.869 3.021 21.333 C +ATOM 465 H6 MOL A 1 -3.760 5.466 19.490 H +ATOM 466 H7 MOL A 1 -2.966 6.763 19.885 H +ATOM 467 C2 MOL A 1 2.685 4.573 20.696 C +ATOM 468 H2 MOL A 1 1.386 6.178 20.847 H +ATOM 469 H6 MOL A 1 7.090 16.160 19.334 H +ATOM 470 H7 MOL A 1 7.485 15.366 18.037 H +ATOM 471 C2 MOL A 1 8.296 9.715 20.227 C +ATOM 472 H2 MOL A 1 8.447 11.014 18.622 H +ATOM 473 C2 MOL A 1 7.827 8.296 22.115 C +ATOM 474 H1 MOL A 1 9.151 6.795 22.305 H +ATOM 475 H1 MOL A 1 9.905 9.151 19.195 H +ATOM 476 H1 MOL A 1 2.495 3.249 19.195 H +ATOM 477 C2 MOL A 1 4.573 4.104 22.115 C +ATOM 478 H1 MOL A 1 5.605 2.495 21.551 H +ATOM 479 C1 MOL A 1 3.467 4.869 21.779 C +ATOM 480 C1 MOL A 1 7.531 9.379 21.333 C +ATOM 481 C3 MOL A 1 7.012 7.973 23.285 C +ATOM 482 C3 MOL A 1 5.388 4.427 23.285 C +ATOM 483 H1 MOL A 1 3.249 5.605 22.305 H +ATOM 484 H1 MOL A 1 6.795 9.905 21.551 H +ATOM 485 N1 MOL A 1 7.315 7.104 24.110 N +ATOM 486 H2 MOL A 1 6.222 8.447 23.414 H +ATOM 487 N1 MOL A 1 5.085 5.296 24.110 N +ATOM 488 H2 MOL A 1 6.178 3.953 23.414 H +ATOM 489 C4 MOL A 1 6.448 6.907 25.261 C +ATOM 490 C4 MOL A 1 5.952 5.493 25.261 C +ATOM 491 C5 MOL A 1 7.256 7.177 26.521 C +ATOM 492 H3 MOL A 1 5.689 7.524 25.214 H +ATOM 493 C5 MOL A 1 5.144 5.223 26.521 C +ATOM 494 H3 MOL A 1 6.711 4.876 25.214 H +ATOM 495 C6 MOL A 1 6.416 6.904 27.761 C +ATOM 496 H4 MOL A 1 7.552 8.102 26.526 H +ATOM 497 H5 MOL A 1 8.043 6.609 26.531 H +ATOM 498 C6 MOL A 1 5.984 5.496 27.761 C +ATOM 499 H4 MOL A 1 4.848 4.298 26.526 H +ATOM 500 H5 MOL A 1 4.357 5.791 26.531 H +ATOM 501 H6 MOL A 1 6.934 7.090 28.560 H +ATOM 502 H7 MOL A 1 5.637 7.485 27.766 H +ATOM 503 H6 MOL A 1 5.466 5.310 28.560 H +ATOM 504 H7 MOL A 1 6.763 4.915 27.766 H +ATOM 505 C1 MOL A 1 11.069 2.733 3.179 C +ATOM 506 C2 MOL A 1 10.304 1.627 3.515 C +ATOM 507 H1 MOL A 1 11.805 2.951 3.705 H +ATOM 508 C2 MOL A 1 10.773 3.515 2.096 C +ATOM 509 C3 MOL A 1 10.627 0.812 4.685 C +ATOM 510 C1 MOL A 1 9.221 1.331 2.733 C +ATOM 511 C1 MOL A 1 9.667 3.179 1.331 C +ATOM 512 C3 MOL A 1 11.588 4.685 1.773 C +ATOM 513 N1 MOL A 1 11.496 1.115 5.510 N +ATOM 514 H2 MOL A 1 10.153 0.022 4.814 H +ATOM 515 C2 MOL A 1 8.885 2.096 1.627 C +ATOM 516 H1 MOL A 1 8.695 0.595 2.951 H +ATOM 517 H1 MOL A 1 9.449 3.705 0.595 H +ATOM 518 N1 MOL A 1 11.285 5.510 0.904 N +ATOM 519 H2 MOL A 1 12.378 4.814 2.247 H +ATOM 520 C4 MOL A 1 11.693 0.248 6.661 C +ATOM 521 C3 MOL A 1 7.715 1.773 0.812 C +ATOM 522 C4 MOL A 1 12.152 6.661 0.707 C +ATOM 523 C5 MOL A 1 11.423 1.056 7.921 C +ATOM 524 H3 MOL A 1 11.076 -0.511 6.614 H +ATOM 525 C4 MOL A 1 13.107 -0.248 6.661 C +ATOM 526 N1 MOL A 1 6.890 0.904 1.115 N +ATOM 527 H2 MOL A 1 7.586 2.247 0.022 H +ATOM 528 C5 MOL A 1 11.344 7.921 0.977 C +ATOM 529 H3 MOL A 1 12.911 6.614 1.324 H +ATOM 530 C4 MOL A 1 12.648 6.661 -0.707 C +ATOM 531 C6 MOL A 1 11.696 0.216 9.161 C +ATOM 532 H4 MOL A 1 10.498 1.352 7.926 H +ATOM 533 H5 MOL A 1 11.991 1.843 7.931 H +ATOM 534 H3 MOL A 1 13.724 0.511 6.614 H +ATOM 535 N1 MOL A 1 13.304 -1.115 5.510 N +ATOM 536 C5 MOL A 1 13.377 -1.056 7.921 C +ATOM 537 C4 MOL A 1 5.739 0.707 0.248 C +ATOM 538 C6 MOL A 1 12.184 9.161 0.704 C +ATOM 539 H4 MOL A 1 11.048 7.926 1.902 H +ATOM 540 H5 MOL A 1 10.557 7.931 0.409 H +ATOM 541 N1 MOL A 1 13.515 5.510 -0.904 N +ATOM 542 C5 MOL A 1 13.456 7.921 -0.977 C +ATOM 543 H3 MOL A 1 11.889 6.614 -1.324 H +ATOM 544 H6 MOL A 1 11.510 0.734 9.960 H +ATOM 545 H7 MOL A 1 11.115 -0.563 9.166 H +ATOM 546 C6 MOL A 1 13.104 -0.216 9.161 C +ATOM 547 C3 MOL A 1 14.173 -0.812 4.685 C +ATOM 548 H4 MOL A 1 14.302 -1.352 7.926 H +ATOM 549 H5 MOL A 1 12.809 -1.843 7.931 H +ATOM 550 C5 MOL A 1 4.479 0.977 1.056 C +ATOM 551 C4 MOL A 1 5.739 -0.707 -0.248 C +ATOM 552 H3 MOL A 1 5.786 1.324 -0.511 H +ATOM 553 H6 MOL A 1 11.666 9.960 0.890 H +ATOM 554 H7 MOL A 1 12.963 9.166 1.285 H +ATOM 555 C6 MOL A 1 12.616 9.161 -0.704 C +ATOM 556 C3 MOL A 1 13.212 4.685 -1.773 C +ATOM 557 H4 MOL A 1 13.752 7.926 -1.902 H +ATOM 558 H5 MOL A 1 14.243 7.931 -0.409 H +ATOM 559 H7 MOL A 1 13.685 0.563 9.166 H +ATOM 560 H6 MOL A 1 13.290 -0.734 9.960 H +ATOM 561 C2 MOL A 1 14.496 -1.627 3.515 C +ATOM 562 H2 MOL A 1 14.647 -0.022 4.814 H +ATOM 563 C6 MOL A 1 3.239 0.704 0.216 C +ATOM 564 H4 MOL A 1 4.474 1.902 1.352 H +ATOM 565 H5 MOL A 1 4.469 0.409 1.843 H +ATOM 566 N1 MOL A 1 6.890 -0.904 -1.115 N +ATOM 567 C5 MOL A 1 4.479 -0.977 -1.056 C +ATOM 568 H3 MOL A 1 5.786 -1.324 0.511 H +ATOM 569 H6 MOL A 1 13.134 9.960 -0.890 H +ATOM 570 H7 MOL A 1 11.837 9.166 -1.285 H +ATOM 571 C2 MOL A 1 14.027 3.515 -2.096 C +ATOM 572 H2 MOL A 1 12.422 4.814 -2.247 H +ATOM 573 C1 MOL A 1 13.731 -2.733 3.179 C +ATOM 574 C1 MOL A 1 15.579 -1.331 2.733 C +ATOM 575 H6 MOL A 1 2.440 0.890 0.734 H +ATOM 576 C6 MOL A 1 3.239 -0.704 -0.216 C +ATOM 577 H7 MOL A 1 3.234 1.285 -0.563 H +ATOM 578 C3 MOL A 1 7.715 -1.773 -0.812 C +ATOM 579 H4 MOL A 1 4.474 -1.902 -1.352 H +ATOM 580 H5 MOL A 1 4.469 -0.409 -1.843 H +ATOM 581 C1 MOL A 1 13.731 2.733 -3.179 C +ATOM 582 C1 MOL A 1 15.133 3.179 -1.331 C +ATOM 583 H1 MOL A 1 12.995 -2.951 3.705 H +ATOM 584 C2 MOL A 1 14.027 -3.515 2.096 C +ATOM 585 C2 MOL A 1 15.915 -2.096 1.627 C +ATOM 586 H1 MOL A 1 16.105 -0.595 2.951 H +ATOM 587 H6 MOL A 1 2.440 -0.890 -0.734 H +ATOM 588 H7 MOL A 1 3.234 -1.285 0.563 H +ATOM 589 C2 MOL A 1 8.885 -2.096 -1.627 C +ATOM 590 H2 MOL A 1 7.586 -2.247 -0.022 H +ATOM 591 C2 MOL A 1 14.496 1.627 -3.515 C +ATOM 592 H1 MOL A 1 12.995 2.951 -3.705 H +ATOM 593 H1 MOL A 1 15.351 3.705 -0.595 H +ATOM 594 C2 MOL A 1 15.915 2.096 -1.627 C +ATOM 595 C1 MOL A 1 15.133 -3.179 1.331 C +ATOM 596 C3 MOL A 1 13.212 -4.685 1.773 C +ATOM 597 C3 MOL A 1 17.085 -1.773 0.812 C +ATOM 598 C1 MOL A 1 9.667 -3.179 -1.331 C +ATOM 599 C1 MOL A 1 9.221 -1.331 -2.733 C +ATOM 600 C3 MOL A 1 14.173 0.812 -4.685 C +ATOM 601 C1 MOL A 1 15.579 1.331 -2.733 C +ATOM 602 C3 MOL A 1 17.085 1.773 -0.812 C +ATOM 603 H1 MOL A 1 15.351 -3.705 0.595 H +ATOM 604 N1 MOL A 1 13.515 -5.510 0.904 N +ATOM 605 H2 MOL A 1 12.422 -4.814 2.247 H +ATOM 606 N1 MOL A 1 17.910 -0.904 1.115 N +ATOM 607 H2 MOL A 1 17.214 -2.247 0.022 H +ATOM 608 C2 MOL A 1 10.773 -3.515 -2.096 C +ATOM 609 H1 MOL A 1 9.449 -3.705 -0.595 H +ATOM 610 C2 MOL A 1 10.304 -1.627 -3.515 C +ATOM 611 H1 MOL A 1 8.695 -0.595 -2.951 H +ATOM 612 N1 MOL A 1 13.304 1.115 -5.510 N +ATOM 613 H2 MOL A 1 14.647 0.022 -4.814 H +ATOM 614 H1 MOL A 1 16.105 0.595 -2.951 H +ATOM 615 N1 MOL A 1 17.910 0.904 -1.115 N +ATOM 616 H2 MOL A 1 17.214 2.247 -0.022 H +ATOM 617 C4 MOL A 1 12.648 -6.661 0.707 C +ATOM 618 C4 MOL A 1 19.061 -0.707 0.248 C +ATOM 619 C1 MOL A 1 11.069 -2.733 -3.179 C +ATOM 620 C3 MOL A 1 11.588 -4.685 -1.773 C +ATOM 621 C3 MOL A 1 10.627 -0.812 -4.685 C +ATOM 622 C4 MOL A 1 13.107 0.248 -6.661 C +ATOM 623 C4 MOL A 1 19.061 0.707 -0.248 C +ATOM 624 C4 MOL A 1 12.152 -6.661 -0.707 C +ATOM 625 C5 MOL A 1 13.456 -7.921 0.977 C +ATOM 626 H3 MOL A 1 11.889 -6.614 1.324 H +ATOM 627 H3 MOL A 1 19.014 -1.324 -0.511 H +ATOM 628 C5 MOL A 1 20.321 -0.977 1.056 C +ATOM 629 H1 MOL A 1 11.805 -2.951 -3.705 H +ATOM 630 N1 MOL A 1 11.285 -5.510 -0.904 N +ATOM 631 H2 MOL A 1 12.378 -4.814 -2.247 H +ATOM 632 N1 MOL A 1 11.496 -1.115 -5.510 N +ATOM 633 H2 MOL A 1 10.153 -0.022 -4.814 H +ATOM 634 C4 MOL A 1 11.693 -0.248 -6.661 C +ATOM 635 H3 MOL A 1 13.724 -0.511 -6.614 H +ATOM 636 C5 MOL A 1 13.377 1.056 -7.921 C +ATOM 637 H3 MOL A 1 19.014 1.324 0.511 H +ATOM 638 C5 MOL A 1 20.321 0.977 -1.056 C +ATOM 639 C5 MOL A 1 11.344 -7.921 -0.977 C +ATOM 640 H3 MOL A 1 12.911 -6.614 -1.324 H +ATOM 641 C6 MOL A 1 12.616 -9.161 0.704 C +ATOM 642 H4 MOL A 1 13.752 -7.926 1.902 H +ATOM 643 H5 MOL A 1 14.243 -7.931 0.409 H +ATOM 644 C6 MOL A 1 21.561 -0.704 0.216 C +ATOM 645 H4 MOL A 1 20.326 -1.902 1.352 H +ATOM 646 H5 MOL A 1 20.331 -0.409 1.843 H +ATOM 647 C5 MOL A 1 11.423 -1.056 -7.921 C +ATOM 648 H3 MOL A 1 11.076 0.511 -6.614 H +ATOM 649 C6 MOL A 1 13.104 0.216 -9.161 C +ATOM 650 H4 MOL A 1 14.302 1.352 -7.926 H +ATOM 651 H5 MOL A 1 12.809 1.843 -7.931 H +ATOM 652 C6 MOL A 1 21.561 0.704 -0.216 C +ATOM 653 H4 MOL A 1 20.326 1.902 -1.352 H +ATOM 654 H5 MOL A 1 20.331 0.409 -1.843 H +ATOM 655 C6 MOL A 1 12.184 -9.161 -0.704 C +ATOM 656 H4 MOL A 1 11.048 -7.926 -1.902 H +ATOM 657 H5 MOL A 1 10.557 -7.931 -0.409 H +ATOM 658 H6 MOL A 1 13.134 -9.960 0.890 H +ATOM 659 H7 MOL A 1 11.837 -9.166 1.285 H +ATOM 660 H7 MOL A 1 21.566 -1.285 -0.563 H +ATOM 661 H6 MOL A 1 22.360 -0.890 0.734 H +ATOM 662 C6 MOL A 1 11.696 -0.216 -9.161 C +ATOM 663 H4 MOL A 1 10.498 -1.352 -7.926 H +ATOM 664 H5 MOL A 1 11.991 -1.843 -7.931 H +ATOM 665 H7 MOL A 1 13.685 -0.563 -9.166 H +ATOM 666 H6 MOL A 1 13.290 0.734 -9.960 H +ATOM 667 H7 MOL A 1 21.566 1.285 0.563 H +ATOM 668 H6 MOL A 1 22.360 0.890 -0.734 H +ATOM 669 H6 MOL A 1 11.666 -9.960 -0.890 H +ATOM 670 H7 MOL A 1 12.963 -9.166 -1.285 H +ATOM 671 H6 MOL A 1 11.510 -0.734 -9.960 H +ATOM 672 H7 MOL A 1 11.115 0.563 -9.166 H +ATOM 673 C1 MOL A 1 11.069 9.667 9.221 C +ATOM 674 C2 MOL A 1 10.304 10.773 8.885 C +ATOM 675 H1 MOL A 1 11.805 9.449 8.695 H +ATOM 676 C2 MOL A 1 10.773 8.885 10.304 C +ATOM 677 C3 MOL A 1 10.627 11.588 7.715 C +ATOM 678 C1 MOL A 1 9.221 11.069 9.667 C +ATOM 679 C1 MOL A 1 9.667 9.221 11.069 C +ATOM 680 C3 MOL A 1 11.588 7.715 10.627 C +ATOM 681 N1 MOL A 1 11.496 11.285 6.890 N +ATOM 682 H2 MOL A 1 10.153 12.378 7.586 H +ATOM 683 C2 MOL A 1 8.885 10.304 10.773 C +ATOM 684 H1 MOL A 1 8.695 11.805 9.449 H +ATOM 685 H1 MOL A 1 9.449 8.695 11.805 H +ATOM 686 N1 MOL A 1 11.285 6.890 11.496 N +ATOM 687 H2 MOL A 1 12.378 7.586 10.153 H +ATOM 688 C4 MOL A 1 11.693 12.152 5.739 C +ATOM 689 C3 MOL A 1 7.715 10.627 11.588 C +ATOM 690 C4 MOL A 1 12.152 5.739 11.693 C +ATOM 691 C5 MOL A 1 11.423 11.344 4.479 C +ATOM 692 H3 MOL A 1 11.076 12.911 5.786 H +ATOM 693 C4 MOL A 1 13.107 12.648 5.739 C +ATOM 694 N1 MOL A 1 6.890 11.496 11.285 N +ATOM 695 H2 MOL A 1 7.586 10.153 12.378 H +ATOM 696 C4 MOL A 1 12.648 5.739 13.107 C +ATOM 697 C5 MOL A 1 11.344 4.479 11.423 C +ATOM 698 H3 MOL A 1 12.911 5.786 11.076 H +ATOM 699 C6 MOL A 1 11.696 12.184 3.239 C +ATOM 700 H4 MOL A 1 10.498 11.048 4.474 H +ATOM 701 H5 MOL A 1 11.991 10.557 4.469 H +ATOM 702 N1 MOL A 1 13.304 13.515 6.890 N +ATOM 703 C5 MOL A 1 13.377 13.456 4.479 C +ATOM 704 H3 MOL A 1 13.724 11.889 5.786 H +ATOM 705 C4 MOL A 1 5.739 11.693 12.152 C +ATOM 706 N1 MOL A 1 13.515 6.890 13.304 N +ATOM 707 C5 MOL A 1 13.456 4.479 13.377 C +ATOM 708 H3 MOL A 1 11.889 5.786 13.724 H +ATOM 709 C6 MOL A 1 12.184 3.239 11.696 C +ATOM 710 H4 MOL A 1 11.048 4.474 10.498 H +ATOM 711 H5 MOL A 1 10.557 4.469 11.991 H +ATOM 712 H6 MOL A 1 11.510 11.666 2.440 H +ATOM 713 H7 MOL A 1 11.115 12.963 3.234 H +ATOM 714 C6 MOL A 1 13.104 12.616 3.239 C +ATOM 715 C3 MOL A 1 14.173 13.212 7.715 C +ATOM 716 H4 MOL A 1 14.302 13.752 4.474 H +ATOM 717 H5 MOL A 1 12.809 14.243 4.469 H +ATOM 718 C5 MOL A 1 4.479 11.423 11.344 C +ATOM 719 H3 MOL A 1 5.786 11.076 12.911 H +ATOM 720 C4 MOL A 1 5.739 13.107 12.648 C +ATOM 721 C3 MOL A 1 13.212 7.715 14.173 C +ATOM 722 C6 MOL A 1 12.616 3.239 13.104 C +ATOM 723 H4 MOL A 1 13.752 4.474 14.302 H +ATOM 724 H5 MOL A 1 14.243 4.469 12.809 H +ATOM 725 H6 MOL A 1 11.666 2.440 11.510 H +ATOM 726 H7 MOL A 1 12.963 3.234 11.115 H +ATOM 727 H6 MOL A 1 13.290 13.134 2.440 H +ATOM 728 H7 MOL A 1 13.685 11.837 3.234 H +ATOM 729 C2 MOL A 1 14.496 14.027 8.885 C +ATOM 730 H2 MOL A 1 14.647 12.422 7.586 H +ATOM 731 C6 MOL A 1 3.239 11.696 12.184 C +ATOM 732 H4 MOL A 1 4.474 10.498 11.048 H +ATOM 733 H5 MOL A 1 4.469 11.991 10.557 H +ATOM 734 N1 MOL A 1 6.890 13.304 13.515 N +ATOM 735 C5 MOL A 1 4.479 13.377 13.456 C +ATOM 736 H3 MOL A 1 5.786 13.724 11.889 H +ATOM 737 C2 MOL A 1 14.027 8.885 14.496 C +ATOM 738 H2 MOL A 1 12.422 7.586 14.647 H +ATOM 739 H6 MOL A 1 13.134 2.440 13.290 H +ATOM 740 H7 MOL A 1 11.837 3.234 13.685 H +ATOM 741 C1 MOL A 1 13.731 15.133 9.221 C +ATOM 742 C1 MOL A 1 15.579 13.731 9.667 C +ATOM 743 H6 MOL A 1 2.440 11.510 11.666 H +ATOM 744 H7 MOL A 1 3.234 11.115 12.963 H +ATOM 745 C6 MOL A 1 3.239 13.104 12.616 C +ATOM 746 C3 MOL A 1 7.715 14.173 13.212 C +ATOM 747 H4 MOL A 1 4.474 14.302 13.752 H +ATOM 748 H5 MOL A 1 4.469 12.809 14.243 H +ATOM 749 C1 MOL A 1 13.731 9.667 15.579 C +ATOM 750 C1 MOL A 1 15.133 9.221 13.731 C +ATOM 751 H1 MOL A 1 12.995 15.351 8.695 H +ATOM 752 C2 MOL A 1 14.027 15.915 10.304 C +ATOM 753 C2 MOL A 1 15.915 14.496 10.773 C +ATOM 754 H1 MOL A 1 16.105 12.995 9.449 H +ATOM 755 H6 MOL A 1 2.440 13.290 13.134 H +ATOM 756 H7 MOL A 1 3.234 13.685 11.837 H +ATOM 757 C2 MOL A 1 8.885 14.496 14.027 C +ATOM 758 H2 MOL A 1 7.586 14.647 12.422 H +ATOM 759 C2 MOL A 1 14.496 10.773 15.915 C +ATOM 760 H1 MOL A 1 12.995 9.449 16.105 H +ATOM 761 H1 MOL A 1 15.351 8.695 12.995 H +ATOM 762 C2 MOL A 1 15.915 10.304 14.027 C +ATOM 763 C1 MOL A 1 15.133 15.579 11.069 C +ATOM 764 C3 MOL A 1 13.212 17.085 10.627 C +ATOM 765 C3 MOL A 1 17.085 14.173 11.588 C +ATOM 766 C1 MOL A 1 9.667 15.579 13.731 C +ATOM 767 C1 MOL A 1 9.221 13.731 15.133 C +ATOM 768 C3 MOL A 1 14.173 11.588 17.085 C +ATOM 769 C1 MOL A 1 15.579 11.069 15.133 C +ATOM 770 C3 MOL A 1 17.085 10.627 13.212 C +ATOM 771 H1 MOL A 1 15.351 16.105 11.805 H +ATOM 772 N1 MOL A 1 13.515 17.910 11.496 N +ATOM 773 H2 MOL A 1 12.422 17.214 10.153 H +ATOM 774 N1 MOL A 1 17.910 13.304 11.285 N +ATOM 775 H2 MOL A 1 17.214 14.647 12.378 H +ATOM 776 C2 MOL A 1 10.773 15.915 14.496 C +ATOM 777 H1 MOL A 1 9.449 16.105 12.995 H +ATOM 778 C2 MOL A 1 10.304 14.027 15.915 C +ATOM 779 H1 MOL A 1 8.695 12.995 15.351 H +ATOM 780 N1 MOL A 1 13.304 11.285 17.910 N +ATOM 781 H2 MOL A 1 14.647 12.378 17.214 H +ATOM 782 H1 MOL A 1 16.105 11.805 15.351 H +ATOM 783 N1 MOL A 1 17.910 11.496 13.515 N +ATOM 784 H2 MOL A 1 17.214 10.153 12.422 H +ATOM 785 C4 MOL A 1 12.648 19.061 11.693 C +ATOM 786 C4 MOL A 1 19.061 13.107 12.152 C +ATOM 787 C1 MOL A 1 11.069 15.133 15.579 C +ATOM 788 C3 MOL A 1 11.588 17.085 14.173 C +ATOM 789 C3 MOL A 1 10.627 13.212 17.085 C +ATOM 790 C4 MOL A 1 13.107 12.152 19.061 C +ATOM 791 C4 MOL A 1 19.061 11.693 12.648 C +ATOM 792 C4 MOL A 1 12.152 19.061 13.107 C +ATOM 793 C5 MOL A 1 13.456 20.321 11.423 C +ATOM 794 H3 MOL A 1 11.889 19.014 11.076 H +ATOM 795 C5 MOL A 1 20.321 13.377 11.344 C +ATOM 796 H3 MOL A 1 19.014 13.724 12.911 H +ATOM 797 H1 MOL A 1 11.805 15.351 16.105 H +ATOM 798 N1 MOL A 1 11.285 17.910 13.304 N +ATOM 799 H2 MOL A 1 12.378 17.214 14.647 H +ATOM 800 N1 MOL A 1 11.496 13.515 17.910 N +ATOM 801 H2 MOL A 1 10.153 12.422 17.214 H +ATOM 802 C4 MOL A 1 11.693 12.648 19.061 C +ATOM 803 C5 MOL A 1 13.377 11.344 20.321 C +ATOM 804 H3 MOL A 1 13.724 12.911 19.014 H +ATOM 805 C5 MOL A 1 20.321 11.423 13.456 C +ATOM 806 H3 MOL A 1 19.014 11.076 11.889 H +ATOM 807 C5 MOL A 1 11.344 20.321 13.377 C +ATOM 808 H3 MOL A 1 12.911 19.014 13.724 H +ATOM 809 C6 MOL A 1 12.616 21.561 11.696 C +ATOM 810 H4 MOL A 1 13.752 20.326 10.498 H +ATOM 811 H5 MOL A 1 14.243 20.331 11.991 H +ATOM 812 C6 MOL A 1 21.561 13.104 12.184 C +ATOM 813 H4 MOL A 1 20.326 14.302 11.048 H +ATOM 814 H5 MOL A 1 20.331 12.809 10.557 H +ATOM 815 C5 MOL A 1 11.423 13.456 20.321 C +ATOM 816 H3 MOL A 1 11.076 11.889 19.014 H +ATOM 817 C6 MOL A 1 13.104 12.184 21.561 C +ATOM 818 H4 MOL A 1 14.302 11.048 20.326 H +ATOM 819 H5 MOL A 1 12.809 10.557 20.331 H +ATOM 820 C6 MOL A 1 21.561 11.696 12.616 C +ATOM 821 H4 MOL A 1 20.326 10.498 13.752 H +ATOM 822 H5 MOL A 1 20.331 11.991 14.243 H +ATOM 823 C6 MOL A 1 12.184 21.561 13.104 C +ATOM 824 H4 MOL A 1 11.048 20.326 14.302 H +ATOM 825 H5 MOL A 1 10.557 20.331 12.809 H +ATOM 826 H6 MOL A 1 13.134 22.360 11.510 H +ATOM 827 H7 MOL A 1 11.837 21.566 11.115 H +ATOM 828 H6 MOL A 1 22.360 13.290 11.666 H +ATOM 829 H7 MOL A 1 21.566 13.685 12.963 H +ATOM 830 C6 MOL A 1 11.696 12.616 21.561 C +ATOM 831 H4 MOL A 1 10.498 13.752 20.326 H +ATOM 832 H5 MOL A 1 11.991 14.243 20.331 H +ATOM 833 H6 MOL A 1 13.290 11.666 22.360 H +ATOM 834 H7 MOL A 1 13.685 12.963 21.566 H +ATOM 835 H6 MOL A 1 22.360 11.510 13.134 H +ATOM 836 H7 MOL A 1 21.566 11.115 11.837 H +ATOM 837 H6 MOL A 1 11.666 22.360 13.290 H +ATOM 838 H7 MOL A 1 12.963 21.566 13.685 H +ATOM 839 H6 MOL A 1 11.510 13.134 22.360 H +ATOM 840 H7 MOL A 1 11.115 11.837 21.566 H +ATOM 841 C2 MOL A 1 3.515 2.096 10.773 C +ATOM 842 C1 MOL A 1 2.733 3.179 11.069 C +ATOM 843 C1 MOL A 1 3.179 1.331 9.667 C +ATOM 844 C3 MOL A 1 4.685 1.773 11.588 C +ATOM 845 C2 MOL A 1 1.627 3.515 10.304 C +ATOM 846 H1 MOL A 1 2.951 3.705 11.805 H +ATOM 847 C2 MOL A 1 2.096 1.627 8.885 C +ATOM 848 H1 MOL A 1 3.705 0.595 9.449 H +ATOM 849 N1 MOL A 1 5.510 0.904 11.285 N +ATOM 850 H2 MOL A 1 4.814 2.247 12.378 H +ATOM 851 C1 MOL A 1 1.331 2.733 9.221 C +ATOM 852 C3 MOL A 1 0.812 4.685 10.627 C +ATOM 853 C3 MOL A 1 1.773 0.812 7.715 C +ATOM 854 C4 MOL A 1 6.661 0.707 12.152 C +ATOM 855 H1 MOL A 1 0.595 2.951 8.695 H +ATOM 856 N1 MOL A 1 1.115 5.510 11.496 N +ATOM 857 H2 MOL A 1 0.022 4.814 10.153 H +ATOM 858 N1 MOL A 1 0.904 1.115 6.890 N +ATOM 859 H2 MOL A 1 2.247 0.022 7.586 H +ATOM 860 C5 MOL A 1 7.921 0.977 11.344 C +ATOM 861 H3 MOL A 1 6.614 1.324 12.911 H +ATOM 862 C4 MOL A 1 6.661 -0.707 12.648 C +ATOM 863 C4 MOL A 1 0.248 6.661 11.693 C +ATOM 864 C4 MOL A 1 0.707 0.248 5.739 C +ATOM 865 C6 MOL A 1 9.161 0.704 12.184 C +ATOM 866 H4 MOL A 1 7.926 1.902 11.048 H +ATOM 867 H5 MOL A 1 7.931 0.409 10.557 H +ATOM 868 N1 MOL A 1 5.510 -0.904 13.515 N +ATOM 869 C5 MOL A 1 7.921 -0.977 13.456 C +ATOM 870 H3 MOL A 1 6.614 -1.324 11.889 H +ATOM 871 C5 MOL A 1 1.056 7.921 11.423 C +ATOM 872 C4 MOL A 1 -0.248 6.661 13.107 C +ATOM 873 H3 MOL A 1 -0.511 6.614 11.076 H +ATOM 874 C5 MOL A 1 0.977 1.056 4.479 C +ATOM 875 C4 MOL A 1 -0.707 -0.248 5.739 C +ATOM 876 H3 MOL A 1 1.324 -0.511 5.786 H +ATOM 877 H6 MOL A 1 9.960 0.890 11.666 H +ATOM 878 H7 MOL A 1 9.166 1.285 12.963 H +ATOM 879 C6 MOL A 1 9.161 -0.704 12.616 C +ATOM 880 C3 MOL A 1 4.685 -1.773 13.212 C +ATOM 881 H4 MOL A 1 7.926 -1.902 13.752 H +ATOM 882 H5 MOL A 1 7.931 -0.409 14.243 H +ATOM 883 C6 MOL A 1 0.216 9.161 11.696 C +ATOM 884 H4 MOL A 1 1.352 7.926 10.498 H +ATOM 885 H5 MOL A 1 1.843 7.931 11.991 H +ATOM 886 H3 MOL A 1 0.511 6.614 13.724 H +ATOM 887 N1 MOL A 1 -1.115 5.510 13.304 N +ATOM 888 C5 MOL A 1 -1.056 7.921 13.377 C +ATOM 889 C6 MOL A 1 0.704 0.216 3.239 C +ATOM 890 H4 MOL A 1 1.902 1.352 4.474 H +ATOM 891 H5 MOL A 1 0.409 1.843 4.469 H +ATOM 892 N1 MOL A 1 -0.904 -1.115 6.890 N +ATOM 893 C5 MOL A 1 -0.977 -1.056 4.479 C +ATOM 894 H3 MOL A 1 -1.324 0.511 5.786 H +ATOM 895 H6 MOL A 1 9.960 -0.890 13.134 H +ATOM 896 H7 MOL A 1 9.166 -1.285 11.837 H +ATOM 897 C2 MOL A 1 3.515 -2.096 14.027 C +ATOM 898 H2 MOL A 1 4.814 -2.247 12.422 H +ATOM 899 H6 MOL A 1 0.734 9.960 11.510 H +ATOM 900 C6 MOL A 1 -0.216 9.161 13.104 C +ATOM 901 H7 MOL A 1 -0.563 9.166 11.115 H +ATOM 902 C3 MOL A 1 -0.812 4.685 14.173 C +ATOM 903 H4 MOL A 1 -1.352 7.926 14.302 H +ATOM 904 H5 MOL A 1 -1.843 7.931 12.809 H +ATOM 905 H6 MOL A 1 0.890 0.734 2.440 H +ATOM 906 C6 MOL A 1 -0.704 -0.216 3.239 C +ATOM 907 H7 MOL A 1 1.285 -0.563 3.234 H +ATOM 908 C3 MOL A 1 -1.773 -0.812 7.715 C +ATOM 909 H4 MOL A 1 -1.902 -1.352 4.474 H +ATOM 910 H5 MOL A 1 -0.409 -1.843 4.469 H +ATOM 911 C1 MOL A 1 2.733 -3.179 13.731 C +ATOM 912 C1 MOL A 1 3.179 -1.331 15.133 C +ATOM 913 H7 MOL A 1 0.563 9.166 13.685 H +ATOM 914 H6 MOL A 1 -0.734 9.960 13.290 H +ATOM 915 C2 MOL A 1 -1.627 3.515 14.496 C +ATOM 916 H2 MOL A 1 -0.022 4.814 14.647 H +ATOM 917 H6 MOL A 1 -0.890 -0.734 2.440 H +ATOM 918 H7 MOL A 1 -1.285 0.563 3.234 H +ATOM 919 C2 MOL A 1 -2.096 -1.627 8.885 C +ATOM 920 H2 MOL A 1 -2.247 -0.022 7.586 H +ATOM 921 C2 MOL A 1 1.627 -3.515 14.496 C +ATOM 922 H1 MOL A 1 2.951 -3.705 12.995 H +ATOM 923 C2 MOL A 1 2.096 -1.627 15.915 C +ATOM 924 H1 MOL A 1 3.705 -0.595 15.351 H +ATOM 925 C1 MOL A 1 -1.331 2.733 15.579 C +ATOM 926 C1 MOL A 1 -2.733 3.179 13.731 C +ATOM 927 C1 MOL A 1 -1.331 -2.733 9.221 C +ATOM 928 C1 MOL A 1 -3.179 -1.331 9.667 C +ATOM 929 C1 MOL A 1 1.331 -2.733 15.579 C +ATOM 930 C3 MOL A 1 0.812 -4.685 14.173 C +ATOM 931 C3 MOL A 1 1.773 -0.812 17.085 C +ATOM 932 C2 MOL A 1 -2.096 1.627 15.915 C +ATOM 933 H1 MOL A 1 -0.595 2.951 16.105 H +ATOM 934 H1 MOL A 1 -2.951 3.705 12.995 H +ATOM 935 C2 MOL A 1 -3.515 2.096 14.027 C +ATOM 936 H1 MOL A 1 -0.595 -2.951 8.695 H +ATOM 937 C2 MOL A 1 -1.627 -3.515 10.304 C +ATOM 938 C2 MOL A 1 -3.515 -2.096 10.773 C +ATOM 939 H1 MOL A 1 -3.705 -0.595 9.449 H +ATOM 940 H1 MOL A 1 0.595 -2.951 16.105 H +ATOM 941 N1 MOL A 1 1.115 -5.510 13.304 N +ATOM 942 H2 MOL A 1 0.022 -4.814 14.647 H +ATOM 943 N1 MOL A 1 0.904 -1.115 17.910 N +ATOM 944 H2 MOL A 1 2.247 -0.022 17.214 H +ATOM 945 C3 MOL A 1 -1.773 0.812 17.085 C +ATOM 946 C1 MOL A 1 -3.179 1.331 15.133 C +ATOM 947 C3 MOL A 1 -4.685 1.773 13.212 C +ATOM 948 C1 MOL A 1 -2.733 -3.179 11.069 C +ATOM 949 C3 MOL A 1 -0.812 -4.685 10.627 C +ATOM 950 C3 MOL A 1 -4.685 -1.773 11.588 C +ATOM 951 C4 MOL A 1 0.248 -6.661 13.107 C +ATOM 952 C4 MOL A 1 0.707 -0.248 19.061 C +ATOM 953 N1 MOL A 1 -0.904 1.115 17.910 N +ATOM 954 H2 MOL A 1 -2.247 0.022 17.214 H +ATOM 955 H1 MOL A 1 -3.705 0.595 15.351 H +ATOM 956 N1 MOL A 1 -5.510 0.904 13.515 N +ATOM 957 H2 MOL A 1 -4.814 2.247 12.422 H +ATOM 958 H1 MOL A 1 -2.951 -3.705 11.805 H +ATOM 959 N1 MOL A 1 -1.115 -5.510 11.496 N +ATOM 960 H2 MOL A 1 -0.022 -4.814 10.153 H +ATOM 961 N1 MOL A 1 -5.510 -0.904 11.285 N +ATOM 962 H2 MOL A 1 -4.814 -2.247 12.378 H +ATOM 963 H3 MOL A 1 -0.511 -6.614 13.724 H +ATOM 964 C4 MOL A 1 -0.248 -6.661 11.693 C +ATOM 965 C5 MOL A 1 1.056 -7.921 13.377 C +ATOM 966 H3 MOL A 1 1.324 0.511 19.014 H +ATOM 967 C4 MOL A 1 -0.707 0.248 19.061 C +ATOM 968 C5 MOL A 1 0.977 -1.056 20.321 C +ATOM 969 C4 MOL A 1 -6.661 0.707 12.648 C +ATOM 970 C4 MOL A 1 -6.661 -0.707 12.152 C +ATOM 971 C5 MOL A 1 -1.056 -7.921 11.423 C +ATOM 972 H3 MOL A 1 0.511 -6.614 11.076 H +ATOM 973 C6 MOL A 1 0.216 -9.161 13.104 C +ATOM 974 H4 MOL A 1 1.352 -7.926 14.302 H +ATOM 975 H5 MOL A 1 1.843 -7.931 12.809 H +ATOM 976 H3 MOL A 1 -1.324 -0.511 19.014 H +ATOM 977 C5 MOL A 1 -0.977 1.056 20.321 C +ATOM 978 C6 MOL A 1 0.704 -0.216 21.561 C +ATOM 979 H4 MOL A 1 1.902 -1.352 20.326 H +ATOM 980 H5 MOL A 1 0.409 -1.843 20.331 H +ATOM 981 C5 MOL A 1 -7.921 0.977 13.456 C +ATOM 982 H3 MOL A 1 -6.614 1.324 11.889 H +ATOM 983 C5 MOL A 1 -7.921 -0.977 11.344 C +ATOM 984 H3 MOL A 1 -6.614 -1.324 12.911 H +ATOM 985 C6 MOL A 1 -0.216 -9.161 11.696 C +ATOM 986 H4 MOL A 1 -1.352 -7.926 10.498 H +ATOM 987 H5 MOL A 1 -1.843 -7.931 11.991 H +ATOM 988 H7 MOL A 1 -0.563 -9.166 13.685 H +ATOM 989 H6 MOL A 1 0.734 -9.960 13.290 H +ATOM 990 C6 MOL A 1 -0.704 0.216 21.561 C +ATOM 991 H4 MOL A 1 -1.902 1.352 20.326 H +ATOM 992 H5 MOL A 1 -0.409 1.843 20.331 H +ATOM 993 H7 MOL A 1 1.285 0.563 21.566 H +ATOM 994 H6 MOL A 1 0.890 -0.734 22.360 H +ATOM 995 C6 MOL A 1 -9.161 0.704 12.616 C +ATOM 996 H4 MOL A 1 -7.926 1.902 13.752 H +ATOM 997 H5 MOL A 1 -7.931 0.409 14.243 H +ATOM 998 C6 MOL A 1 -9.161 -0.704 12.184 C +ATOM 999 H4 MOL A 1 -7.926 -1.902 11.048 H +ATOM 1000 H5 MOL A 1 -7.931 -0.409 10.557 H +ATOM 1001 H6 MOL A 1 -0.734 -9.960 11.510 H +ATOM 1002 H7 MOL A 1 0.563 -9.166 11.115 H +ATOM 1003 H7 MOL A 1 -1.285 -0.563 21.566 H +ATOM 1004 H6 MOL A 1 -0.890 0.734 22.360 H +ATOM 1005 H6 MOL A 1 -9.960 0.890 13.134 H +ATOM 1006 H7 MOL A 1 -9.166 1.285 11.837 H +ATOM 1007 H6 MOL A 1 -9.960 -0.890 11.666 H +ATOM 1008 H7 MOL A 1 -9.166 -1.285 12.963 H +ATOM 1009 C2 MOL A 1 3.515 10.304 1.627 C +ATOM 1010 C1 MOL A 1 2.733 9.221 1.331 C +ATOM 1011 C1 MOL A 1 3.179 11.069 2.733 C +ATOM 1012 C3 MOL A 1 4.685 10.627 0.812 C +ATOM 1013 C2 MOL A 1 1.627 8.885 2.096 C +ATOM 1014 H1 MOL A 1 2.951 8.695 0.595 H +ATOM 1015 C2 MOL A 1 2.096 10.773 3.515 C +ATOM 1016 H1 MOL A 1 3.705 11.805 2.951 H +ATOM 1017 N1 MOL A 1 5.510 11.496 1.115 N +ATOM 1018 H2 MOL A 1 4.814 10.153 0.022 H +ATOM 1019 C1 MOL A 1 1.331 9.667 3.179 C +ATOM 1020 C3 MOL A 1 0.812 7.715 1.773 C +ATOM 1021 C3 MOL A 1 1.773 11.588 4.685 C +ATOM 1022 C4 MOL A 1 6.661 11.693 0.248 C +ATOM 1023 H1 MOL A 1 0.595 9.449 3.705 H +ATOM 1024 N1 MOL A 1 1.115 6.890 0.904 N +ATOM 1025 H2 MOL A 1 0.022 7.586 2.247 H +ATOM 1026 N1 MOL A 1 0.904 11.285 5.510 N +ATOM 1027 H2 MOL A 1 2.247 12.378 4.814 H +ATOM 1028 C5 MOL A 1 7.921 11.423 1.056 C +ATOM 1029 H3 MOL A 1 6.614 11.076 -0.511 H +ATOM 1030 C4 MOL A 1 6.661 13.107 -0.248 C +ATOM 1031 C4 MOL A 1 0.248 5.739 0.707 C +ATOM 1032 C4 MOL A 1 0.707 12.152 6.661 C +ATOM 1033 C6 MOL A 1 9.161 11.696 0.216 C +ATOM 1034 H4 MOL A 1 7.926 10.498 1.352 H +ATOM 1035 H5 MOL A 1 7.931 11.991 1.843 H +ATOM 1036 H3 MOL A 1 6.614 13.724 0.511 H +ATOM 1037 N1 MOL A 1 5.510 13.304 -1.115 N +ATOM 1038 C5 MOL A 1 7.921 13.377 -1.056 C +ATOM 1039 C5 MOL A 1 1.056 4.479 0.977 C +ATOM 1040 C4 MOL A 1 -0.248 5.739 -0.707 C +ATOM 1041 H3 MOL A 1 -0.511 5.786 1.324 H +ATOM 1042 C5 MOL A 1 0.977 11.344 7.921 C +ATOM 1043 H3 MOL A 1 1.324 12.911 6.614 H +ATOM 1044 C4 MOL A 1 -0.707 12.648 6.661 C +ATOM 1045 H6 MOL A 1 9.960 11.510 0.734 H +ATOM 1046 H7 MOL A 1 9.166 11.115 -0.563 H +ATOM 1047 C6 MOL A 1 9.161 13.104 -0.216 C +ATOM 1048 C3 MOL A 1 4.685 14.173 -0.812 C +ATOM 1049 H4 MOL A 1 7.926 14.302 -1.352 H +ATOM 1050 H5 MOL A 1 7.931 12.809 -1.843 H +ATOM 1051 C6 MOL A 1 0.216 3.239 0.704 C +ATOM 1052 H4 MOL A 1 1.352 4.474 1.902 H +ATOM 1053 H5 MOL A 1 1.843 4.469 0.409 H +ATOM 1054 N1 MOL A 1 -1.115 6.890 -0.904 N +ATOM 1055 C5 MOL A 1 -1.056 4.479 -0.977 C +ATOM 1056 H3 MOL A 1 0.511 5.786 -1.324 H +ATOM 1057 C6 MOL A 1 0.704 12.184 9.161 C +ATOM 1058 H4 MOL A 1 1.902 11.048 7.926 H +ATOM 1059 H5 MOL A 1 0.409 10.557 7.931 H +ATOM 1060 N1 MOL A 1 -0.904 13.515 5.510 N +ATOM 1061 C5 MOL A 1 -0.977 13.456 7.921 C +ATOM 1062 H3 MOL A 1 -1.324 11.889 6.614 H +ATOM 1063 H7 MOL A 1 9.166 13.685 0.563 H +ATOM 1064 H6 MOL A 1 9.960 13.290 -0.734 H +ATOM 1065 C2 MOL A 1 3.515 14.496 -1.627 C +ATOM 1066 H2 MOL A 1 4.814 14.647 -0.022 H +ATOM 1067 H6 MOL A 1 0.734 2.440 0.890 H +ATOM 1068 C6 MOL A 1 -0.216 3.239 -0.704 C +ATOM 1069 H7 MOL A 1 -0.563 3.234 1.285 H +ATOM 1070 C3 MOL A 1 -0.812 7.715 -1.773 C +ATOM 1071 H4 MOL A 1 -1.352 4.474 -1.902 H +ATOM 1072 H5 MOL A 1 -1.843 4.469 -0.409 H +ATOM 1073 H6 MOL A 1 0.890 11.666 9.960 H +ATOM 1074 H7 MOL A 1 1.285 12.963 9.166 H +ATOM 1075 C6 MOL A 1 -0.704 12.616 9.161 C +ATOM 1076 C3 MOL A 1 -1.773 13.212 4.685 C +ATOM 1077 H4 MOL A 1 -1.902 13.752 7.926 H +ATOM 1078 H5 MOL A 1 -0.409 14.243 7.931 H +ATOM 1079 C1 MOL A 1 2.733 15.579 -1.331 C +ATOM 1080 C1 MOL A 1 3.179 13.731 -2.733 C +ATOM 1081 H6 MOL A 1 -0.734 2.440 -0.890 H +ATOM 1082 H7 MOL A 1 0.563 3.234 -1.285 H +ATOM 1083 C2 MOL A 1 -1.627 8.885 -2.096 C +ATOM 1084 H2 MOL A 1 -0.022 7.586 -2.247 H +ATOM 1085 H6 MOL A 1 -0.890 13.134 9.960 H +ATOM 1086 H7 MOL A 1 -1.285 11.837 9.166 H +ATOM 1087 C2 MOL A 1 -2.096 14.027 3.515 C +ATOM 1088 H2 MOL A 1 -2.247 12.422 4.814 H +ATOM 1089 C2 MOL A 1 1.627 15.915 -2.096 C +ATOM 1090 H1 MOL A 1 2.951 16.105 -0.595 H +ATOM 1091 C2 MOL A 1 2.096 14.027 -3.515 C +ATOM 1092 H1 MOL A 1 3.705 12.995 -2.951 H +ATOM 1093 C1 MOL A 1 -1.331 9.667 -3.179 C +ATOM 1094 C1 MOL A 1 -2.733 9.221 -1.331 C +ATOM 1095 C1 MOL A 1 -1.331 15.133 3.179 C +ATOM 1096 C1 MOL A 1 -3.179 13.731 2.733 C +ATOM 1097 C1 MOL A 1 1.331 15.133 -3.179 C +ATOM 1098 C3 MOL A 1 0.812 17.085 -1.773 C +ATOM 1099 C3 MOL A 1 1.773 13.212 -4.685 C +ATOM 1100 C2 MOL A 1 -2.096 10.773 -3.515 C +ATOM 1101 H1 MOL A 1 -0.595 9.449 -3.705 H +ATOM 1102 H1 MOL A 1 -2.951 8.695 -0.595 H +ATOM 1103 C2 MOL A 1 -3.515 10.304 -1.627 C +ATOM 1104 H1 MOL A 1 -0.595 15.351 3.705 H +ATOM 1105 C2 MOL A 1 -1.627 15.915 2.096 C +ATOM 1106 C2 MOL A 1 -3.515 14.496 1.627 C +ATOM 1107 H1 MOL A 1 -3.705 12.995 2.951 H +ATOM 1108 H1 MOL A 1 0.595 15.351 -3.705 H +ATOM 1109 N1 MOL A 1 1.115 17.910 -0.904 N +ATOM 1110 H2 MOL A 1 0.022 17.214 -2.247 H +ATOM 1111 N1 MOL A 1 0.904 13.515 -5.510 N +ATOM 1112 H2 MOL A 1 2.247 12.422 -4.814 H +ATOM 1113 C3 MOL A 1 -1.773 11.588 -4.685 C +ATOM 1114 C1 MOL A 1 -3.179 11.069 -2.733 C +ATOM 1115 C3 MOL A 1 -4.685 10.627 -0.812 C +ATOM 1116 C1 MOL A 1 -2.733 15.579 1.331 C +ATOM 1117 C3 MOL A 1 -0.812 17.085 1.773 C +ATOM 1118 C3 MOL A 1 -4.685 14.173 0.812 C +ATOM 1119 C4 MOL A 1 0.248 19.061 -0.707 C +ATOM 1120 C4 MOL A 1 0.707 12.648 -6.661 C +ATOM 1121 N1 MOL A 1 -0.904 11.285 -5.510 N +ATOM 1122 H2 MOL A 1 -2.247 12.378 -4.814 H +ATOM 1123 H1 MOL A 1 -3.705 11.805 -2.951 H +ATOM 1124 N1 MOL A 1 -5.510 11.496 -1.115 N +ATOM 1125 H2 MOL A 1 -4.814 10.153 -0.022 H +ATOM 1126 H1 MOL A 1 -2.951 16.105 0.595 H +ATOM 1127 N1 MOL A 1 -1.115 17.910 0.904 N +ATOM 1128 H2 MOL A 1 -0.022 17.214 2.247 H +ATOM 1129 N1 MOL A 1 -5.510 13.304 1.115 N +ATOM 1130 H2 MOL A 1 -4.814 14.647 0.022 H +ATOM 1131 H3 MOL A 1 -0.511 19.014 -1.324 H +ATOM 1132 C4 MOL A 1 -0.248 19.061 0.707 C +ATOM 1133 C5 MOL A 1 1.056 20.321 -0.977 C +ATOM 1134 C4 MOL A 1 -0.707 12.152 -6.661 C +ATOM 1135 C5 MOL A 1 0.977 13.456 -7.921 C +ATOM 1136 H3 MOL A 1 1.324 11.889 -6.614 H +ATOM 1137 C4 MOL A 1 -6.661 11.693 -0.248 C +ATOM 1138 C4 MOL A 1 -6.661 13.107 0.248 C +ATOM 1139 H3 MOL A 1 0.511 19.014 1.324 H +ATOM 1140 C5 MOL A 1 -1.056 20.321 0.977 C +ATOM 1141 C6 MOL A 1 0.216 21.561 -0.704 C +ATOM 1142 H4 MOL A 1 1.352 20.326 -1.902 H +ATOM 1143 H5 MOL A 1 1.843 20.331 -0.409 H +ATOM 1144 C5 MOL A 1 -0.977 11.344 -7.921 C +ATOM 1145 H3 MOL A 1 -1.324 12.911 -6.614 H +ATOM 1146 C6 MOL A 1 0.704 12.616 -9.161 C +ATOM 1147 H4 MOL A 1 1.902 13.752 -7.926 H +ATOM 1148 H5 MOL A 1 0.409 14.243 -7.931 H +ATOM 1149 C5 MOL A 1 -7.921 11.423 -1.056 C +ATOM 1150 H3 MOL A 1 -6.614 11.076 0.511 H +ATOM 1151 H3 MOL A 1 -6.614 13.724 -0.511 H +ATOM 1152 C5 MOL A 1 -7.921 13.377 1.056 C +ATOM 1153 C6 MOL A 1 -0.216 21.561 0.704 C +ATOM 1154 H4 MOL A 1 -1.352 20.326 1.902 H +ATOM 1155 H5 MOL A 1 -1.843 20.331 0.409 H +ATOM 1156 H7 MOL A 1 -0.563 21.566 -1.285 H +ATOM 1157 H6 MOL A 1 0.734 22.360 -0.890 H +ATOM 1158 C6 MOL A 1 -0.704 12.184 -9.161 C +ATOM 1159 H4 MOL A 1 -1.902 11.048 -7.926 H +ATOM 1160 H5 MOL A 1 -0.409 10.557 -7.931 H +ATOM 1161 H6 MOL A 1 0.890 13.134 -9.960 H +ATOM 1162 H7 MOL A 1 1.285 11.837 -9.166 H +ATOM 1163 C6 MOL A 1 -9.161 11.696 -0.216 C +ATOM 1164 H4 MOL A 1 -7.926 10.498 -1.352 H +ATOM 1165 H5 MOL A 1 -7.931 11.991 -1.843 H +ATOM 1166 C6 MOL A 1 -9.161 13.104 0.216 C +ATOM 1167 H4 MOL A 1 -7.926 14.302 1.352 H +ATOM 1168 H5 MOL A 1 -7.931 12.809 1.843 H +ATOM 1169 H7 MOL A 1 0.563 21.566 1.285 H +ATOM 1170 H6 MOL A 1 -0.734 22.360 0.890 H +ATOM 1171 H6 MOL A 1 -0.890 11.666 -9.960 H +ATOM 1172 H7 MOL A 1 -1.285 12.963 -9.166 H +ATOM 1173 H6 MOL A 1 -9.960 11.510 -0.734 H +ATOM 1174 H7 MOL A 1 -9.166 11.115 0.563 H +ATOM 1175 H7 MOL A 1 -9.166 13.685 -0.563 H +ATOM 1176 H6 MOL A 1 -9.960 13.290 0.734 H +ATOM 1177 C6 MOL A 1 18.816 17.896 9.439 C +ATOM 1178 C5 MOL A 1 19.656 17.623 10.679 C +ATOM 1179 H6 MOL A 1 19.334 17.710 8.640 H +ATOM 1180 H7 MOL A 1 18.037 17.315 9.434 H +ATOM 1181 C6 MOL A 1 18.384 19.304 9.439 C +ATOM 1182 C4 MOL A 1 18.848 17.893 11.939 C +ATOM 1183 H4 MOL A 1 19.952 16.698 10.674 H +ATOM 1184 H5 MOL A 1 20.443 18.191 10.669 H +ATOM 1185 C5 MOL A 1 17.544 19.577 10.679 C +ATOM 1186 H6 MOL A 1 17.866 19.490 8.640 H +ATOM 1187 H7 MOL A 1 19.163 19.885 9.434 H +ATOM 1188 N1 MOL A 1 19.715 17.696 13.090 N +ATOM 1189 H3 MOL A 1 18.089 17.276 11.986 H +ATOM 1190 C4 MOL A 1 18.352 19.307 11.939 C +ATOM 1191 H4 MOL A 1 17.248 20.502 10.674 H +ATOM 1192 H5 MOL A 1 16.757 19.009 10.669 H +ATOM 1193 C3 MOL A 1 19.412 16.827 13.915 C +ATOM 1194 N1 MOL A 1 17.485 19.504 13.090 N +ATOM 1195 H3 MOL A 1 19.111 19.924 11.986 H +ATOM 1196 C2 MOL A 1 20.227 16.504 15.085 C +ATOM 1197 H2 MOL A 1 18.622 16.353 13.786 H +ATOM 1198 C3 MOL A 1 17.788 20.373 13.915 C +ATOM 1199 C1 MOL A 1 21.333 17.269 15.421 C +ATOM 1200 C1 MOL A 1 19.931 15.421 15.867 C +ATOM 1201 C2 MOL A 1 16.973 20.696 15.085 C +ATOM 1202 H2 MOL A 1 18.578 20.847 13.786 H +ATOM 1203 H1 MOL A 1 21.551 18.005 14.895 H +ATOM 1204 C2 MOL A 1 22.115 16.973 16.504 C +ATOM 1205 C2 MOL A 1 20.696 15.085 16.973 C +ATOM 1206 H1 MOL A 1 19.195 14.895 15.649 H +ATOM 1207 C1 MOL A 1 15.867 19.931 15.421 C +ATOM 1208 C1 MOL A 1 17.269 21.779 15.867 C +ATOM 1209 C1 MOL A 1 21.779 15.867 17.269 C +ATOM 1210 C3 MOL A 1 23.285 17.788 16.827 C +ATOM 1211 C3 MOL A 1 20.373 13.915 17.788 C +ATOM 1212 H1 MOL A 1 15.649 19.195 14.895 H +ATOM 1213 C2 MOL A 1 15.085 20.227 16.504 C +ATOM 1214 C2 MOL A 1 16.504 22.115 16.973 C +ATOM 1215 H1 MOL A 1 18.005 22.305 15.649 H +ATOM 1216 H1 MOL A 1 22.305 15.649 18.005 H +ATOM 1217 N1 MOL A 1 24.110 17.485 17.696 N +ATOM 1218 H2 MOL A 1 23.414 18.578 16.353 H +ATOM 1219 N1 MOL A 1 19.504 13.090 17.485 N +ATOM 1220 H2 MOL A 1 20.847 13.786 18.578 H +ATOM 1221 C1 MOL A 1 15.421 21.333 17.269 C +ATOM 1222 C3 MOL A 1 13.915 19.412 16.827 C +ATOM 1223 C3 MOL A 1 16.827 23.285 17.788 C +ATOM 1224 C4 MOL A 1 25.261 18.352 17.893 C +ATOM 1225 C4 MOL A 1 19.307 11.939 18.352 C +ATOM 1226 H1 MOL A 1 14.895 21.551 18.005 H +ATOM 1227 N1 MOL A 1 13.090 19.715 17.696 N +ATOM 1228 H2 MOL A 1 13.786 18.622 16.353 H +ATOM 1229 N1 MOL A 1 17.696 24.110 17.485 N +ATOM 1230 H2 MOL A 1 16.353 23.414 18.578 H +ATOM 1231 C5 MOL A 1 26.521 17.544 17.623 C +ATOM 1232 H3 MOL A 1 25.214 19.111 17.276 H +ATOM 1233 C4 MOL A 1 25.261 18.848 19.307 C +ATOM 1234 C4 MOL A 1 17.893 11.939 18.848 C +ATOM 1235 C5 MOL A 1 19.577 10.679 17.544 C +ATOM 1236 H3 MOL A 1 19.924 11.986 19.111 H +ATOM 1237 C4 MOL A 1 11.939 18.848 17.893 C +ATOM 1238 C4 MOL A 1 17.893 25.261 18.352 C +ATOM 1239 C6 MOL A 1 27.761 18.384 17.896 C +ATOM 1240 H4 MOL A 1 26.526 17.248 16.698 H +ATOM 1241 H5 MOL A 1 26.531 16.757 18.191 H +ATOM 1242 N1 MOL A 1 24.110 19.715 19.504 N +ATOM 1243 C5 MOL A 1 26.521 19.656 19.577 C +ATOM 1244 H3 MOL A 1 25.214 18.089 19.924 H +ATOM 1245 N1 MOL A 1 17.696 13.090 19.715 N +ATOM 1246 C5 MOL A 1 17.623 10.679 19.656 C +ATOM 1247 H3 MOL A 1 17.276 11.986 18.089 H +ATOM 1248 C6 MOL A 1 19.304 9.439 18.384 C +ATOM 1249 H4 MOL A 1 20.502 10.674 17.248 H +ATOM 1250 H5 MOL A 1 19.009 10.669 16.757 H +ATOM 1251 C5 MOL A 1 10.679 19.656 17.623 C +ATOM 1252 H3 MOL A 1 11.986 18.089 17.276 H +ATOM 1253 C4 MOL A 1 11.939 18.352 19.307 C +ATOM 1254 C5 MOL A 1 17.623 26.521 17.544 C +ATOM 1255 H3 MOL A 1 17.276 25.214 19.111 H +ATOM 1256 C4 MOL A 1 19.307 25.261 18.848 C +ATOM 1257 H6 MOL A 1 28.560 17.866 17.710 H +ATOM 1258 H7 MOL A 1 27.766 19.163 17.315 H +ATOM 1259 C6 MOL A 1 27.761 18.816 19.304 C +ATOM 1260 C3 MOL A 1 23.285 19.412 20.373 C +ATOM 1261 H4 MOL A 1 26.526 19.952 20.502 H +ATOM 1262 H5 MOL A 1 26.531 20.443 19.009 H +ATOM 1263 C3 MOL A 1 16.827 13.915 19.412 C +ATOM 1264 C6 MOL A 1 17.896 9.439 18.816 C +ATOM 1265 H4 MOL A 1 16.698 10.674 19.952 H +ATOM 1266 H5 MOL A 1 18.191 10.669 20.443 H +ATOM 1267 H6 MOL A 1 19.490 8.640 17.866 H +ATOM 1268 H7 MOL A 1 19.885 9.434 19.163 H +ATOM 1269 C6 MOL A 1 9.439 18.816 17.896 C +ATOM 1270 H4 MOL A 1 10.674 19.952 16.698 H +ATOM 1271 H5 MOL A 1 10.669 20.443 18.191 H +ATOM 1272 N1 MOL A 1 13.090 17.485 19.504 N +ATOM 1273 C5 MOL A 1 10.679 17.544 19.577 C +ATOM 1274 H3 MOL A 1 11.986 19.111 19.924 H +ATOM 1275 C6 MOL A 1 17.896 27.761 18.384 C +ATOM 1276 H4 MOL A 1 16.698 26.526 17.248 H +ATOM 1277 H5 MOL A 1 18.191 26.531 16.757 H +ATOM 1278 N1 MOL A 1 19.504 24.110 19.715 N +ATOM 1279 C5 MOL A 1 19.577 26.521 19.656 C +ATOM 1280 H3 MOL A 1 19.924 25.214 18.089 H +ATOM 1281 H6 MOL A 1 28.560 19.334 19.490 H +ATOM 1282 H7 MOL A 1 27.766 18.037 19.885 H +ATOM 1283 C2 MOL A 1 22.115 20.227 20.696 C +ATOM 1284 H2 MOL A 1 23.414 18.622 20.847 H +ATOM 1285 C2 MOL A 1 16.504 15.085 20.227 C +ATOM 1286 H2 MOL A 1 16.353 13.786 18.622 H +ATOM 1287 H6 MOL A 1 17.710 8.640 19.334 H +ATOM 1288 H7 MOL A 1 17.315 9.434 18.037 H +ATOM 1289 H6 MOL A 1 8.640 19.334 17.710 H +ATOM 1290 H7 MOL A 1 9.434 18.037 17.315 H +ATOM 1291 C6 MOL A 1 9.439 18.384 19.304 C +ATOM 1292 C3 MOL A 1 13.915 17.788 20.373 C +ATOM 1293 H4 MOL A 1 10.674 17.248 20.502 H +ATOM 1294 H5 MOL A 1 10.669 16.757 19.009 H +ATOM 1295 H6 MOL A 1 17.710 28.560 17.866 H +ATOM 1296 H7 MOL A 1 17.315 27.766 19.163 H +ATOM 1297 C6 MOL A 1 19.304 27.761 18.816 C +ATOM 1298 C3 MOL A 1 20.373 23.285 19.412 C +ATOM 1299 H4 MOL A 1 20.502 26.526 19.952 H +ATOM 1300 H5 MOL A 1 19.009 26.531 20.443 H +ATOM 1301 C1 MOL A 1 21.333 19.931 21.779 C +ATOM 1302 C1 MOL A 1 21.779 21.333 19.931 C +ATOM 1303 C1 MOL A 1 15.421 15.867 19.931 C +ATOM 1304 C1 MOL A 1 17.269 15.421 21.333 C +ATOM 1305 H6 MOL A 1 8.640 17.866 19.490 H +ATOM 1306 H7 MOL A 1 9.434 19.163 19.885 H +ATOM 1307 C2 MOL A 1 15.085 16.973 20.696 C +ATOM 1308 H2 MOL A 1 13.786 18.578 20.847 H +ATOM 1309 H6 MOL A 1 19.490 28.560 19.334 H +ATOM 1310 H7 MOL A 1 19.885 27.766 18.037 H +ATOM 1311 C2 MOL A 1 20.696 22.115 20.227 C +ATOM 1312 H2 MOL A 1 20.847 23.414 18.622 H +ATOM 1313 C2 MOL A 1 20.227 20.696 22.115 C +ATOM 1314 H1 MOL A 1 21.551 19.195 22.305 H +ATOM 1315 H1 MOL A 1 22.305 21.551 19.195 H +ATOM 1316 H1 MOL A 1 14.895 15.649 19.195 H +ATOM 1317 C2 MOL A 1 16.973 16.504 22.115 C +ATOM 1318 H1 MOL A 1 18.005 14.895 21.551 H +ATOM 1319 C1 MOL A 1 15.867 17.269 21.779 C +ATOM 1320 C1 MOL A 1 19.931 21.779 21.333 C +ATOM 1321 C3 MOL A 1 19.412 20.373 23.285 C +ATOM 1322 C3 MOL A 1 17.788 16.827 23.285 C +ATOM 1323 H1 MOL A 1 15.649 18.005 22.305 H +ATOM 1324 H1 MOL A 1 19.195 22.305 21.551 H +ATOM 1325 N1 MOL A 1 19.715 19.504 24.110 N +ATOM 1326 H2 MOL A 1 18.622 20.847 23.414 H +ATOM 1327 N1 MOL A 1 17.485 17.696 24.110 N +ATOM 1328 H2 MOL A 1 18.578 16.353 23.414 H +ATOM 1329 C4 MOL A 1 18.848 19.307 25.261 C +ATOM 1330 C4 MOL A 1 18.352 17.893 25.261 C +ATOM 1331 C5 MOL A 1 19.656 19.577 26.521 C +ATOM 1332 H3 MOL A 1 18.089 19.924 25.214 H +ATOM 1333 C5 MOL A 1 17.544 17.623 26.521 C +ATOM 1334 H3 MOL A 1 19.111 17.276 25.214 H +ATOM 1335 C6 MOL A 1 18.816 19.304 27.761 C +ATOM 1336 H4 MOL A 1 19.952 20.502 26.526 H +ATOM 1337 H5 MOL A 1 20.443 19.009 26.531 H +ATOM 1338 C6 MOL A 1 18.384 17.896 27.761 C +ATOM 1339 H4 MOL A 1 17.248 16.698 26.526 H +ATOM 1340 H5 MOL A 1 16.757 18.191 26.531 H +ATOM 1341 H6 MOL A 1 19.334 19.490 28.560 H +ATOM 1342 H7 MOL A 1 18.037 19.885 27.766 H +ATOM 1343 H6 MOL A 1 17.866 17.710 28.560 H +ATOM 1344 H7 MOL A 1 19.163 17.315 27.766 H +END \ No newline at end of file diff --git a/tests/test_molecular.py b/tests/test_molecular.py index 0b75ce2..a258e6d 100644 --- a/tests/test_molecular.py +++ b/tests/test_molecular.py @@ -1,7 +1,12 @@ +import pathlib + import numpy as np import pywindow as pw +current_directory = pathlib.Path(__file__).parent.absolute() +data_directory = current_directory / "data" + system = { "coordinates": np.array( [ @@ -4408,4619 +4413,14 @@ ), } -system_periodic_rebuild = { - "coordinates": np.array( - [ - [9.4390e00, 6.4160e00, 5.4960e00], - [1.0679e01, 7.2560e00, 5.2230e00], - [8.6400e00, 6.9340e00, 5.3100e00], - [9.4340e00, 5.6370e00, 4.9150e00], - [9.4390e00, 5.9840e00, 6.9040e00], - [1.1939e01, 6.4480e00, 5.4930e00], - [1.0674e01, 7.5520e00, 4.2980e00], - [1.0669e01, 8.0430e00, 5.7910e00], - [1.0679e01, 5.1440e00, 7.1770e00], - [8.6400e00, 5.4660e00, 7.0900e00], - [9.4340e00, 6.7630e00, 7.4850e00], - [1.3090e01, 7.3150e00, 5.2960e00], - [1.1986e01, 5.6890e00, 4.8760e00], - [1.1939e01, 5.9520e00, 6.9070e00], - [1.0674e01, 4.8480e00, 8.1020e00], - [1.0669e01, 4.3570e00, 6.6090e00], - [1.3915e01, 7.0120e00, 4.4270e00], - [1.3090e01, 5.0850e00, 7.1040e00], - [1.1986e01, 6.7110e00, 7.5240e00], - [1.5085e01, 7.8270e00, 4.1040e00], - [1.3786e01, 6.2220e00, 3.9530e00], - [1.3915e01, 5.3880e00, 7.9730e00], - [1.5867e01, 7.5310e00, 3.0210e00], - [1.5421e01, 8.9330e00, 4.8690e00], - [1.5085e01, 4.5730e00, 8.2960e00], - [1.3786e01, 6.1780e00, 8.4470e00], - [1.6973e01, 8.2960e00, 2.6850e00], - [1.5649e01, 6.7950e00, 2.4950e00], - [1.4895e01, 9.1510e00, 5.6050e00], - [1.6504e01, 9.7150e00, 4.5730e00], - [1.5867e01, 4.8690e00, 9.3790e00], - [1.5421e01, 3.4670e00, 7.5310e00], - [1.7788e01, 7.9730e00, 1.5150e00], - [1.7269e01, 9.3790e00, 3.4670e00], - [1.6827e01, 1.0885e01, 5.3880e00], - [1.6973e01, 4.1040e00, 9.7150e00], - [1.5649e01, 5.6050e00, 9.9050e00], - [1.4895e01, 3.2490e00, 6.7950e00], - [1.6504e01, 2.6850e00, 7.8270e00], - [1.7485e01, 7.1040e00, 6.9000e-01], - [1.8578e01, 8.4470e00, 1.3860e00], - [1.8005e01, 9.9050e00, 3.2490e00], - [1.7696e01, 1.1710e01, 5.0850e00], - [1.6353e01, 1.1014e01, 6.1780e00], - [1.7788e01, 4.4270e00, 1.0885e01], - [1.7269e01, 3.0210e00, 8.9330e00], - [1.6827e01, 1.5150e00, 7.0120e00], - [1.8352e01, 6.9070e00, -4.6100e-01], - [1.7893e01, 1.2861e01, 5.9520e00], - [1.7485e01, 5.2960e00, 1.1710e01], - [1.8578e01, 3.9530e00, 1.1014e01], - [1.8005e01, 2.4950e00, 9.1510e00], - [1.7696e01, 6.9000e-01, 7.3150e00], - [1.6353e01, 1.3860e00, 6.2220e00], - [1.8848e01, 5.4930e00, -4.6100e-01], - [1.7544e01, 7.1770e00, -1.7210e00], - [1.9111e01, 7.5240e00, -4.1400e-01], - [1.7623e01, 1.4121e01, 5.1440e00], - [1.7276e01, 1.2814e01, 6.7110e00], - [1.9307e01, 1.2861e01, 6.4480e00], - [1.8352e01, 5.4930e00, 1.2861e01], - [1.7893e01, -4.6100e-01, 6.4480e00], - [1.9715e01, 5.2960e00, 6.9000e-01], - [1.9656e01, 5.2230e00, -1.7210e00], - [1.8089e01, 4.8760e00, -4.1400e-01], - [1.8384e01, 6.9040e00, -2.9610e00], - [1.7248e01, 8.1020e00, -1.7260e00], - [1.6757e01, 6.6090e00, -1.7310e00], - [1.7896e01, 1.5361e01, 5.9840e00], - [1.6698e01, 1.4126e01, 4.8480e00], - [1.8191e01, 1.4131e01, 4.3570e00], - [1.9504e01, 1.1710e01, 7.3150e00], - [1.9577e01, 1.4121e01, 7.2560e00], - [1.9924e01, 1.2814e01, 5.6890e00], - [1.7544e01, 5.2230e00, 1.4121e01], - [1.9111e01, 4.8760e00, 1.2814e01], - [1.8848e01, 6.9070e00, 1.2861e01], - [1.7623e01, -1.7210e00, 7.2560e00], - [1.7276e01, -4.1400e-01, 5.6890e00], - [1.9307e01, -4.6100e-01, 5.9520e00], - [1.9412e01, 4.4270e00, 1.5150e00], - [1.8816e01, 5.4960e00, -2.9610e00], - [1.9952e01, 4.2980e00, -1.7260e00], - [2.0443e01, 5.7910e00, -1.7310e00], - [1.7866e01, 7.0900e00, -3.7600e00], - [1.9163e01, 7.4850e00, -2.9660e00], - [1.7710e01, 1.6160e01, 5.4660e00], - [1.7315e01, 1.5366e01, 6.7630e00], - [1.9304e01, 1.5361e01, 6.4160e00], - [2.0373e01, 1.0885e01, 7.0120e00], - [2.0502e01, 1.4126e01, 7.5520e00], - [1.9009e01, 1.4131e01, 8.0430e00], - [1.8384e01, 5.4960e00, 1.5361e01], - [1.7248e01, 4.2980e00, 1.4126e01], - [1.6757e01, 5.7910e00, 1.4131e01], - [1.9715e01, 7.1040e00, 1.1710e01], - [1.9656e01, 7.1770e00, 1.4121e01], - [1.8089e01, 7.5240e00, 1.2814e01], - [1.7896e01, -2.9610e00, 6.4160e00], - [1.6698e01, -1.7260e00, 7.5520e00], - [1.8191e01, -1.7310e00, 8.0430e00], - [1.9504e01, 6.9000e-01, 5.0850e00], - [1.9577e01, -1.7210e00, 5.1440e00], - [1.9924e01, -4.1400e-01, 6.7110e00], - [2.0227e01, 4.1040e00, 2.6850e00], - [1.8622e01, 3.9530e00, 1.3860e00], - [1.9334e01, 5.3100e00, -3.7600e00], - [1.8037e01, 4.9150e00, -2.9660e00], - [1.9490e01, 1.6160e01, 6.9340e00], - [1.9885e01, 1.5366e01, 5.6370e00], - [2.0696e01, 9.7150e00, 7.8270e00], - [2.0847e01, 1.1014e01, 6.2220e00], - [1.7866e01, 5.3100e00, 1.6160e01], - [1.9163e01, 4.9150e00, 1.5366e01], - [1.8816e01, 6.9040e00, 1.5361e01], - [1.9412e01, 7.9730e00, 1.0885e01], - [1.9952e01, 8.1020e00, 1.4126e01], - [2.0443e01, 6.6090e00, 1.4131e01], - [1.7710e01, -3.7600e00, 6.9340e00], - [1.7315e01, -2.9660e00, 5.6370e00], - [1.9304e01, -2.9610e00, 5.9840e00], - [2.0373e01, 1.5150e00, 5.3880e00], - [2.0502e01, -1.7260e00, 4.8480e00], - [1.9009e01, -1.7310e00, 4.3570e00], - [2.1333e01, 4.8690e00, 3.0210e00], - [1.9931e01, 3.0210e00, 3.4670e00], - [2.1779e01, 8.9330e00, 7.5310e00], - [1.9931e01, 9.3790e00, 8.9330e00], - [1.9334e01, 7.0900e00, 1.6160e01], - [1.8037e01, 7.4850e00, 1.5366e01], - [2.0227e01, 8.2960e00, 9.7150e00], - [1.8622e01, 8.4470e00, 1.1014e01], - [1.9490e01, -3.7600e00, 5.4660e00], - [1.9885e01, -2.9660e00, 6.7630e00], - [2.0696e01, 2.6850e00, 4.5730e00], - [2.0847e01, 1.3860e00, 6.1780e00], - [2.1551e01, 5.6050e00, 2.4950e00], - [2.2115e01, 4.5730e00, 4.1040e00], - [1.9195e01, 2.4950e00, 3.2490e00], - [2.2115e01, 7.8270e00, 8.2960e00], - [2.2305e01, 9.1510e00, 6.7950e00], - [1.9195e01, 9.9050e00, 9.1510e00], - [2.1333e01, 7.5310e00, 9.3790e00], - [2.1779e01, 3.4670e00, 4.8690e00], - [2.3285e01, 5.3880e00, 4.4270e00], - [2.3285e01, 7.0120e00, 7.9730e00], - [2.1551e01, 6.7950e00, 9.9050e00], - [2.2305e01, 3.2490e00, 5.6050e00], - [2.4110e01, 5.0850e00, 5.2960e00], - [2.3414e01, 6.1780e00, 3.9530e00], - [2.4110e01, 7.3150e00, 7.1040e00], - [2.3414e01, 6.2220e00, 8.4470e00], - [2.5261e01, 5.9520e00, 5.4930e00], - [2.5261e01, 6.4480e00, 6.9070e00], - [2.6521e01, 5.1440e00, 5.2230e00], - [2.5214e01, 6.7110e00, 4.8760e00], - [2.6521e01, 7.2560e00, 7.1770e00], - [2.5214e01, 5.6890e00, 7.5240e00], - [2.7761e01, 5.9840e00, 5.4960e00], - [2.6526e01, 4.8480e00, 4.2980e00], - [2.6531e01, 4.3570e00, 5.7910e00], - [2.7761e01, 6.4160e00, 6.9040e00], - [2.6526e01, 7.5520e00, 8.1020e00], - [2.6531e01, 8.0430e00, 6.6090e00], - [2.8560e01, 5.4660e00, 5.3100e00], - [2.7766e01, 6.7630e00, 4.9150e00], - [2.8560e01, 6.9340e00, 7.0900e00], - [2.7766e01, 5.6370e00, 7.4850e00], - [6.9040e00, 9.4390e00, 5.9840e00], - [5.4960e00, 9.4390e00, 6.4160e00], - [7.1770e00, 1.0679e01, 5.1440e00], - [7.0900e00, 8.6400e00, 5.4660e00], - [7.4850e00, 9.4340e00, 6.7630e00], - [5.2230e00, 1.0679e01, 7.2560e00], - [5.3100e00, 8.6400e00, 6.9340e00], - [4.9150e00, 9.4340e00, 5.6370e00], - [6.9070e00, 1.1939e01, 5.9520e00], - [8.1020e00, 1.0674e01, 4.8480e00], - [6.6090e00, 1.0669e01, 4.3570e00], - [5.4930e00, 1.1939e01, 6.4480e00], - [4.2980e00, 1.0674e01, 7.5520e00], - [5.7910e00, 1.0669e01, 8.0430e00], - [7.1040e00, 1.3090e01, 5.0850e00], - [7.5240e00, 1.1986e01, 6.7110e00], - [5.2960e00, 1.3090e01, 7.3150e00], - [4.8760e00, 1.1986e01, 5.6890e00], - [7.9730e00, 1.3915e01, 5.3880e00], - [4.4270e00, 1.3915e01, 7.0120e00], - [8.2960e00, 1.5085e01, 4.5730e00], - [8.4470e00, 1.3786e01, 6.1780e00], - [4.1040e00, 1.5085e01, 7.8270e00], - [3.9530e00, 1.3786e01, 6.2220e00], - [9.3790e00, 1.5867e01, 4.8690e00], - [7.5310e00, 1.5421e01, 3.4670e00], - [3.0210e00, 1.5867e01, 7.5310e00], - [4.8690e00, 1.5421e01, 8.9330e00], - [9.7150e00, 1.6973e01, 4.1040e00], - [9.9050e00, 1.5649e01, 5.6050e00], - [7.8270e00, 1.6504e01, 2.6850e00], - [6.7950e00, 1.4895e01, 3.2490e00], - [2.6850e00, 1.6973e01, 8.2960e00], - [2.4950e00, 1.5649e01, 6.7950e00], - [4.5730e00, 1.6504e01, 9.7150e00], - [5.6050e00, 1.4895e01, 9.1510e00], - [8.9330e00, 1.7269e01, 3.0210e00], - [1.0885e01, 1.7788e01, 4.4270e00], - [7.0120e00, 1.6827e01, 1.5150e00], - [3.4670e00, 1.7269e01, 9.3790e00], - [1.5150e00, 1.7788e01, 7.9730e00], - [5.3880e00, 1.6827e01, 1.0885e01], - [9.1510e00, 1.8005e01, 2.4950e00], - [1.1710e01, 1.7485e01, 5.2960e00], - [1.1014e01, 1.8578e01, 3.9530e00], - [7.3150e00, 1.7696e01, 6.9000e-01], - [6.2220e00, 1.6353e01, 1.3860e00], - [3.2490e00, 1.8005e01, 9.9050e00], - [6.9000e-01, 1.7485e01, 7.1040e00], - [1.3860e00, 1.8578e01, 8.4470e00], - [5.0850e00, 1.7696e01, 1.1710e01], - [6.1780e00, 1.6353e01, 1.1014e01], - [1.2861e01, 1.8352e01, 5.4930e00], - [6.4480e00, 1.7893e01, -4.6100e-01], - [-4.6100e-01, 1.8352e01, 6.9070e00], - [5.9520e00, 1.7893e01, 1.2861e01], - [1.4121e01, 1.7544e01, 5.2230e00], - [1.2814e01, 1.9111e01, 4.8760e00], - [1.2861e01, 1.8848e01, 6.9070e00], - [7.2560e00, 1.7623e01, -1.7210e00], - [5.6890e00, 1.7276e01, -4.1400e-01], - [5.9520e00, 1.9307e01, -4.6100e-01], - [-4.6100e-01, 1.8848e01, 5.4930e00], - [-1.7210e00, 1.7544e01, 7.1770e00], - [-4.1400e-01, 1.9111e01, 7.5240e00], - [5.1440e00, 1.7623e01, 1.4121e01], - [6.7110e00, 1.7276e01, 1.2814e01], - [6.4480e00, 1.9307e01, 1.2861e01], - [1.5361e01, 1.8384e01, 5.4960e00], - [1.4126e01, 1.7248e01, 4.2980e00], - [1.4131e01, 1.6757e01, 5.7910e00], - [1.1710e01, 1.9715e01, 7.1040e00], - [1.4121e01, 1.9656e01, 7.1770e00], - [1.2814e01, 1.8089e01, 7.5240e00], - [6.4160e00, 1.7896e01, -2.9610e00], - [7.5520e00, 1.6698e01, -1.7260e00], - [8.0430e00, 1.8191e01, -1.7310e00], - [5.0850e00, 1.9504e01, 6.9000e-01], - [5.1440e00, 1.9577e01, -1.7210e00], - [6.7110e00, 1.9924e01, -4.1400e-01], - [6.9000e-01, 1.9715e01, 5.2960e00], - [-1.7210e00, 1.9656e01, 5.2230e00], - [-4.1400e-01, 1.8089e01, 4.8760e00], - [-2.9610e00, 1.8384e01, 6.9040e00], - [-1.7260e00, 1.7248e01, 8.1020e00], - [-1.7310e00, 1.6757e01, 6.6090e00], - [5.9840e00, 1.7896e01, 1.5361e01], - [4.8480e00, 1.6698e01, 1.4126e01], - [4.3570e00, 1.8191e01, 1.4131e01], - [7.3150e00, 1.9504e01, 1.1710e01], - [7.2560e00, 1.9577e01, 1.4121e01], - [5.6890e00, 1.9924e01, 1.2814e01], - [1.6160e01, 1.7866e01, 5.3100e00], - [1.5366e01, 1.9163e01, 4.9150e00], - [1.5361e01, 1.8816e01, 6.9040e00], - [1.0885e01, 1.9412e01, 7.9730e00], - [1.4126e01, 1.9952e01, 8.1020e00], - [1.4131e01, 2.0443e01, 6.6090e00], - [6.9340e00, 1.7710e01, -3.7600e00], - [5.6370e00, 1.7315e01, -2.9660e00], - [5.9840e00, 1.9304e01, -2.9610e00], - [5.3880e00, 2.0373e01, 1.5150e00], - [4.8480e00, 2.0502e01, -1.7260e00], - [4.3570e00, 1.9009e01, -1.7310e00], - [1.5150e00, 1.9412e01, 4.4270e00], - [-2.9610e00, 1.8816e01, 5.4960e00], - [-1.7260e00, 1.9952e01, 4.2980e00], - [-1.7310e00, 2.0443e01, 5.7910e00], - [-3.7600e00, 1.7866e01, 7.0900e00], - [-2.9660e00, 1.9163e01, 7.4850e00], - [5.4660e00, 1.7710e01, 1.6160e01], - [6.7630e00, 1.7315e01, 1.5366e01], - [6.4160e00, 1.9304e01, 1.5361e01], - [7.0120e00, 2.0373e01, 1.0885e01], - [7.5520e00, 2.0502e01, 1.4126e01], - [8.0430e00, 1.9009e01, 1.4131e01], - [1.6160e01, 1.9334e01, 7.0900e00], - [1.5366e01, 1.8037e01, 7.4850e00], - [9.7150e00, 2.0227e01, 8.2960e00], - [1.1014e01, 1.8622e01, 8.4470e00], - [5.4660e00, 1.9490e01, -3.7600e00], - [6.7630e00, 1.9885e01, -2.9660e00], - [4.5730e00, 2.0696e01, 2.6850e00], - [6.1780e00, 2.0847e01, 1.3860e00], - [2.6850e00, 2.0227e01, 4.1040e00], - [1.3860e00, 1.8622e01, 3.9530e00], - [-3.7600e00, 1.9334e01, 5.3100e00], - [-2.9660e00, 1.8037e01, 4.9150e00], - [6.9340e00, 1.9490e01, 1.6160e01], - [5.6370e00, 1.9885e01, 1.5366e01], - [7.8270e00, 2.0696e01, 9.7150e00], - [6.2220e00, 2.0847e01, 1.1014e01], - [8.9330e00, 1.9931e01, 9.3790e00], - [9.3790e00, 2.1333e01, 7.5310e00], - [3.4670e00, 1.9931e01, 3.0210e00], - [4.8690e00, 2.1779e01, 3.4670e00], - [3.0210e00, 2.1333e01, 4.8690e00], - [7.5310e00, 2.1779e01, 8.9330e00], - [9.1510e00, 1.9195e01, 9.9050e00], - [9.9050e00, 2.1551e01, 6.7950e00], - [8.2960e00, 2.2115e01, 7.8270e00], - [3.2490e00, 1.9195e01, 2.4950e00], - [4.1040e00, 2.2115e01, 4.5730e00], - [5.6050e00, 2.2305e01, 3.2490e00], - [2.4950e00, 2.1551e01, 5.6050e00], - [6.7950e00, 2.2305e01, 9.1510e00], - [7.9730e00, 2.3285e01, 7.0120e00], - [4.4270e00, 2.3285e01, 5.3880e00], - [7.1040e00, 2.4110e01, 7.3150e00], - [8.4470e00, 2.3414e01, 6.2220e00], - [5.2960e00, 2.4110e01, 5.0850e00], - [3.9530e00, 2.3414e01, 6.1780e00], - [6.9070e00, 2.5261e01, 6.4480e00], - [5.4930e00, 2.5261e01, 5.9520e00], - [7.1770e00, 2.6521e01, 7.2560e00], - [7.5240e00, 2.5214e01, 5.6890e00], - [5.2230e00, 2.6521e01, 5.1440e00], - [4.8760e00, 2.5214e01, 6.7110e00], - [6.9040e00, 2.7761e01, 6.4160e00], - [8.1020e00, 2.6526e01, 7.5520e00], - [6.6090e00, 2.6531e01, 8.0430e00], - [5.4960e00, 2.7761e01, 5.9840e00], - [4.2980e00, 2.6526e01, 4.8480e00], - [5.7910e00, 2.6531e01, 4.3570e00], - [7.0900e00, 2.8560e01, 6.9340e00], - [7.4850e00, 2.7766e01, 5.6370e00], - [5.3100e00, 2.8560e01, 5.4660e00], - [4.9150e00, 2.7766e01, 6.7630e00], - [6.4160e00, 5.4960e00, 9.4390e00], - [7.2560e00, 5.2230e00, 1.0679e01], - [6.9340e00, 5.3100e00, 8.6400e00], - [5.6370e00, 4.9150e00, 9.4340e00], - [5.9840e00, 6.9040e00, 9.4390e00], - [6.4480e00, 5.4930e00, 1.1939e01], - [7.5520e00, 4.2980e00, 1.0674e01], - [8.0430e00, 5.7910e00, 1.0669e01], - [5.1440e00, 7.1770e00, 1.0679e01], - [5.4660e00, 7.0900e00, 8.6400e00], - [6.7630e00, 7.4850e00, 9.4340e00], - [7.3150e00, 5.2960e00, 1.3090e01], - [5.6890e00, 4.8760e00, 1.1986e01], - [5.9520e00, 6.9070e00, 1.1939e01], - [4.8480e00, 8.1020e00, 1.0674e01], - [4.3570e00, 6.6090e00, 1.0669e01], - [7.0120e00, 4.4270e00, 1.3915e01], - [5.0850e00, 7.1040e00, 1.3090e01], - [6.7110e00, 7.5240e00, 1.1986e01], - [7.8270e00, 4.1040e00, 1.5085e01], - [6.2220e00, 3.9530e00, 1.3786e01], - [5.3880e00, 7.9730e00, 1.3915e01], - [8.9330e00, 4.8690e00, 1.5421e01], - [7.5310e00, 3.0210e00, 1.5867e01], - [4.5730e00, 8.2960e00, 1.5085e01], - [6.1780e00, 8.4470e00, 1.3786e01], - [9.1510e00, 5.6050e00, 1.4895e01], - [9.7150e00, 4.5730e00, 1.6504e01], - [8.2960e00, 2.6850e00, 1.6973e01], - [6.7950e00, 2.4950e00, 1.5649e01], - [3.4670e00, 7.5310e00, 1.5421e01], - [4.8690e00, 9.3790e00, 1.5867e01], - [9.3790e00, 3.4670e00, 1.7269e01], - [1.0885e01, 5.3880e00, 1.6827e01], - [7.9730e00, 1.5150e00, 1.7788e01], - [3.2490e00, 6.7950e00, 1.4895e01], - [2.6850e00, 7.8270e00, 1.6504e01], - [4.1040e00, 9.7150e00, 1.6973e01], - [5.6050e00, 9.9050e00, 1.5649e01], - [9.9050e00, 3.2490e00, 1.8005e01], - [1.1710e01, 5.0850e00, 1.7696e01], - [1.1014e01, 6.1780e00, 1.6353e01], - [7.1040e00, 6.9000e-01, 1.7485e01], - [8.4470e00, 1.3860e00, 1.8578e01], - [3.0210e00, 8.9330e00, 1.7269e01], - [1.5150e00, 7.0120e00, 1.6827e01], - [4.4270e00, 1.0885e01, 1.7788e01], - [1.2861e01, 5.9520e00, 1.7893e01], - [6.9070e00, -4.6100e-01, 1.8352e01], - [2.4950e00, 9.1510e00, 1.8005e01], - [6.9000e-01, 7.3150e00, 1.7696e01], - [1.3860e00, 6.2220e00, 1.6353e01], - [5.2960e00, 1.1710e01, 1.7485e01], - [3.9530e00, 1.1014e01, 1.8578e01], - [1.4121e01, 5.1440e00, 1.7623e01], - [1.2814e01, 6.7110e00, 1.7276e01], - [1.2861e01, 6.4480e00, 1.9307e01], - [5.4930e00, -4.6100e-01, 1.8848e01], - [7.1770e00, -1.7210e00, 1.7544e01], - [7.5240e00, -4.1400e-01, 1.9111e01], - [-4.6100e-01, 6.4480e00, 1.7893e01], - [5.4930e00, 1.2861e01, 1.8352e01], - [1.5361e01, 5.9840e00, 1.7896e01], - [1.4126e01, 4.8480e00, 1.6698e01], - [1.4131e01, 4.3570e00, 1.8191e01], - [1.1710e01, 7.3150e00, 1.9504e01], - [1.4121e01, 7.2560e00, 1.9577e01], - [1.2814e01, 5.6890e00, 1.9924e01], - [5.2960e00, 6.9000e-01, 1.9715e01], - [5.2230e00, -1.7210e00, 1.9656e01], - [4.8760e00, -4.1400e-01, 1.8089e01], - [6.9040e00, -2.9610e00, 1.8384e01], - [8.1020e00, -1.7260e00, 1.7248e01], - [6.6090e00, -1.7310e00, 1.6757e01], - [-1.7210e00, 7.2560e00, 1.7623e01], - [-4.1400e-01, 5.6890e00, 1.7276e01], - [-4.6100e-01, 5.9520e00, 1.9307e01], - [5.2230e00, 1.4121e01, 1.7544e01], - [4.8760e00, 1.2814e01, 1.9111e01], - [6.9070e00, 1.2861e01, 1.8848e01], - [1.6160e01, 5.4660e00, 1.7710e01], - [1.5366e01, 6.7630e00, 1.7315e01], - [1.5361e01, 6.4160e00, 1.9304e01], - [1.0885e01, 7.0120e00, 2.0373e01], - [1.4126e01, 7.5520e00, 2.0502e01], - [1.4131e01, 8.0430e00, 1.9009e01], - [4.4270e00, 1.5150e00, 1.9412e01], - [5.4960e00, -2.9610e00, 1.8816e01], - [4.2980e00, -1.7260e00, 1.9952e01], - [5.7910e00, -1.7310e00, 2.0443e01], - [7.0900e00, -3.7600e00, 1.7866e01], - [7.4850e00, -2.9660e00, 1.9163e01], - [-2.9610e00, 6.4160e00, 1.7896e01], - [-1.7260e00, 7.5520e00, 1.6698e01], - [-1.7310e00, 8.0430e00, 1.8191e01], - [6.9000e-01, 5.0850e00, 1.9504e01], - [-1.7210e00, 5.1440e00, 1.9577e01], - [-4.1400e-01, 6.7110e00, 1.9924e01], - [5.4960e00, 1.5361e01, 1.8384e01], - [4.2980e00, 1.4126e01, 1.7248e01], - [5.7910e00, 1.4131e01, 1.6757e01], - [7.1040e00, 1.1710e01, 1.9715e01], - [7.1770e00, 1.4121e01, 1.9656e01], - [7.5240e00, 1.2814e01, 1.8089e01], - [1.6160e01, 6.9340e00, 1.9490e01], - [1.5366e01, 5.6370e00, 1.9885e01], - [9.7150e00, 7.8270e00, 2.0696e01], - [1.1014e01, 6.2220e00, 2.0847e01], - [4.1040e00, 2.6850e00, 2.0227e01], - [3.9530e00, 1.3860e00, 1.8622e01], - [5.3100e00, -3.7600e00, 1.9334e01], - [4.9150e00, -2.9660e00, 1.8037e01], - [-3.7600e00, 6.9340e00, 1.7710e01], - [-2.9660e00, 5.6370e00, 1.7315e01], - [-2.9610e00, 5.9840e00, 1.9304e01], - [1.5150e00, 5.3880e00, 2.0373e01], - [-1.7260e00, 4.8480e00, 2.0502e01], - [-1.7310e00, 4.3570e00, 1.9009e01], - [5.3100e00, 1.6160e01, 1.7866e01], - [4.9150e00, 1.5366e01, 1.9163e01], - [6.9040e00, 1.5361e01, 1.8816e01], - [7.9730e00, 1.0885e01, 1.9412e01], - [8.1020e00, 1.4126e01, 1.9952e01], - [6.6090e00, 1.4131e01, 2.0443e01], - [8.9330e00, 7.5310e00, 2.1779e01], - [9.3790e00, 8.9330e00, 1.9931e01], - [3.0210e00, 3.4670e00, 1.9931e01], - [4.8690e00, 3.0210e00, 2.1333e01], - [-3.7600e00, 5.4660e00, 1.9490e01], - [-2.9660e00, 6.7630e00, 1.9885e01], - [2.6850e00, 4.5730e00, 2.0696e01], - [1.3860e00, 6.1780e00, 2.0847e01], - [7.0900e00, 1.6160e01, 1.9334e01], - [7.4850e00, 1.5366e01, 1.8037e01], - [8.2960e00, 9.7150e00, 2.0227e01], - [8.4470e00, 1.1014e01, 1.8622e01], - [7.8270e00, 8.2960e00, 2.2115e01], - [9.1510e00, 6.7950e00, 2.2305e01], - [9.9050e00, 9.1510e00, 1.9195e01], - [2.4950e00, 3.2490e00, 1.9195e01], - [4.5730e00, 4.1040e00, 2.2115e01], - [5.6050e00, 2.4950e00, 2.1551e01], - [3.4670e00, 4.8690e00, 2.1779e01], - [7.5310e00, 9.3790e00, 2.1333e01], - [7.0120e00, 7.9730e00, 2.3285e01], - [5.3880e00, 4.4270e00, 2.3285e01], - [3.2490e00, 5.6050e00, 2.2305e01], - [6.7950e00, 9.9050e00, 2.1551e01], - [7.3150e00, 7.1040e00, 2.4110e01], - [6.2220e00, 8.4470e00, 2.3414e01], - [5.0850e00, 5.2960e00, 2.4110e01], - [6.1780e00, 3.9530e00, 2.3414e01], - [6.4480e00, 6.9070e00, 2.5261e01], - [5.9520e00, 5.4930e00, 2.5261e01], - [7.2560e00, 7.1770e00, 2.6521e01], - [5.6890e00, 7.5240e00, 2.5214e01], - [5.1440e00, 5.2230e00, 2.6521e01], - [6.7110e00, 4.8760e00, 2.5214e01], - [6.4160e00, 6.9040e00, 2.7761e01], - [7.5520e00, 8.1020e00, 2.6526e01], - [8.0430e00, 6.6090e00, 2.6531e01], - [5.9840e00, 5.4960e00, 2.7761e01], - [4.8480e00, 4.2980e00, 2.6526e01], - [4.3570e00, 5.7910e00, 2.6531e01], - [6.9340e00, 7.0900e00, 2.8560e01], - [5.6370e00, 7.4850e00, 2.7766e01], - [5.4660e00, 5.3100e00, 2.8560e01], - [6.7630e00, 4.9150e00, 2.7766e01], - [1.1069e01, 2.7330e00, 3.1790e00], - [1.0304e01, 1.6270e00, 3.5150e00], - [1.1805e01, 2.9510e00, 3.7050e00], - [1.0773e01, 3.5150e00, 2.0960e00], - [1.0627e01, 8.1200e-01, 4.6850e00], - [9.2210e00, 1.3310e00, 2.7330e00], - [9.6670e00, 3.1790e00, 1.3310e00], - [1.1588e01, 4.6850e00, 1.7730e00], - [1.1496e01, 1.1150e00, 5.5100e00], - [1.0153e01, 2.2000e-02, 4.8140e00], - [8.8850e00, 2.0960e00, 1.6270e00], - [8.6950e00, 5.9500e-01, 2.9510e00], - [9.4490e00, 3.7050e00, 5.9500e-01], - [1.1285e01, 5.5100e00, 9.0400e-01], - [1.2378e01, 4.8140e00, 2.2470e00], - [1.1693e01, 2.4800e-01, 6.6610e00], - [7.7150e00, 1.7730e00, 8.1200e-01], - [1.2152e01, 6.6610e00, 7.0700e-01], - [1.1423e01, 1.0560e00, 7.9210e00], - [1.1076e01, -5.1100e-01, 6.6140e00], - [1.3107e01, -2.4800e-01, 6.6610e00], - [6.8900e00, 9.0400e-01, 1.1150e00], - [7.5860e00, 2.2470e00, 2.2000e-02], - [1.1344e01, 7.9210e00, 9.7700e-01], - [1.2911e01, 6.6140e00, 1.3240e00], - [1.2648e01, 6.6610e00, -7.0700e-01], - [1.1696e01, 2.1600e-01, 9.1610e00], - [1.0498e01, 1.3520e00, 7.9260e00], - [1.1991e01, 1.8430e00, 7.9310e00], - [1.3724e01, 5.1100e-01, 6.6140e00], - [1.3304e01, -1.1150e00, 5.5100e00], - [1.3377e01, -1.0560e00, 7.9210e00], - [5.7390e00, 7.0700e-01, 2.4800e-01], - [1.2184e01, 9.1610e00, 7.0400e-01], - [1.1048e01, 7.9260e00, 1.9020e00], - [1.0557e01, 7.9310e00, 4.0900e-01], - [1.3515e01, 5.5100e00, -9.0400e-01], - [1.3456e01, 7.9210e00, -9.7700e-01], - [1.1889e01, 6.6140e00, -1.3240e00], - [1.1510e01, 7.3400e-01, 9.9600e00], - [1.1115e01, -5.6300e-01, 9.1660e00], - [1.3104e01, -2.1600e-01, 9.1610e00], - [1.4173e01, -8.1200e-01, 4.6850e00], - [1.4302e01, -1.3520e00, 7.9260e00], - [1.2809e01, -1.8430e00, 7.9310e00], - [4.4790e00, 9.7700e-01, 1.0560e00], - [5.7390e00, -7.0700e-01, -2.4800e-01], - [5.7860e00, 1.3240e00, -5.1100e-01], - [1.1666e01, 9.9600e00, 8.9000e-01], - [1.2963e01, 9.1660e00, 1.2850e00], - [1.2616e01, 9.1610e00, -7.0400e-01], - [1.3212e01, 4.6850e00, -1.7730e00], - [1.3752e01, 7.9260e00, -1.9020e00], - [1.4243e01, 7.9310e00, -4.0900e-01], - [1.3685e01, 5.6300e-01, 9.1660e00], - [1.3290e01, -7.3400e-01, 9.9600e00], - [1.4496e01, -1.6270e00, 3.5150e00], - [1.4647e01, -2.2000e-02, 4.8140e00], - [3.2390e00, 7.0400e-01, 2.1600e-01], - [4.4740e00, 1.9020e00, 1.3520e00], - [4.4690e00, 4.0900e-01, 1.8430e00], - [6.8900e00, -9.0400e-01, -1.1150e00], - [4.4790e00, -9.7700e-01, -1.0560e00], - [5.7860e00, -1.3240e00, 5.1100e-01], - [1.3134e01, 9.9600e00, -8.9000e-01], - [1.1837e01, 9.1660e00, -1.2850e00], - [1.4027e01, 3.5150e00, -2.0960e00], - [1.2422e01, 4.8140e00, -2.2470e00], - [1.3731e01, -2.7330e00, 3.1790e00], - [1.5579e01, -1.3310e00, 2.7330e00], - [2.4400e00, 8.9000e-01, 7.3400e-01], - [3.2390e00, -7.0400e-01, -2.1600e-01], - [3.2340e00, 1.2850e00, -5.6300e-01], - [7.7150e00, -1.7730e00, -8.1200e-01], - [4.4740e00, -1.9020e00, -1.3520e00], - [4.4690e00, -4.0900e-01, -1.8430e00], - [1.3731e01, 2.7330e00, -3.1790e00], - [1.5133e01, 3.1790e00, -1.3310e00], - [1.2995e01, -2.9510e00, 3.7050e00], - [1.4027e01, -3.5150e00, 2.0960e00], - [1.5915e01, -2.0960e00, 1.6270e00], - [1.6105e01, -5.9500e-01, 2.9510e00], - [2.4400e00, -8.9000e-01, -7.3400e-01], - [3.2340e00, -1.2850e00, 5.6300e-01], - [8.8850e00, -2.0960e00, -1.6270e00], - [7.5860e00, -2.2470e00, -2.2000e-02], - [1.4496e01, 1.6270e00, -3.5150e00], - [1.2995e01, 2.9510e00, -3.7050e00], - [1.5351e01, 3.7050e00, -5.9500e-01], - [1.5915e01, 2.0960e00, -1.6270e00], - [1.5133e01, -3.1790e00, 1.3310e00], - [1.3212e01, -4.6850e00, 1.7730e00], - [1.7085e01, -1.7730e00, 8.1200e-01], - [9.6670e00, -3.1790e00, -1.3310e00], - [9.2210e00, -1.3310e00, -2.7330e00], - [1.4173e01, 8.1200e-01, -4.6850e00], - [1.5579e01, 1.3310e00, -2.7330e00], - [1.7085e01, 1.7730e00, -8.1200e-01], - [1.5351e01, -3.7050e00, 5.9500e-01], - [1.3515e01, -5.5100e00, 9.0400e-01], - [1.2422e01, -4.8140e00, 2.2470e00], - [1.7910e01, -9.0400e-01, 1.1150e00], - [1.7214e01, -2.2470e00, 2.2000e-02], - [1.0773e01, -3.5150e00, -2.0960e00], - [9.4490e00, -3.7050e00, -5.9500e-01], - [1.0304e01, -1.6270e00, -3.5150e00], - [8.6950e00, -5.9500e-01, -2.9510e00], - [1.3304e01, 1.1150e00, -5.5100e00], - [1.4647e01, 2.2000e-02, -4.8140e00], - [1.6105e01, 5.9500e-01, -2.9510e00], - [1.7910e01, 9.0400e-01, -1.1150e00], - [1.7214e01, 2.2470e00, -2.2000e-02], - [1.2648e01, -6.6610e00, 7.0700e-01], - [1.9061e01, -7.0700e-01, 2.4800e-01], - [1.1069e01, -2.7330e00, -3.1790e00], - [1.1588e01, -4.6850e00, -1.7730e00], - [1.0627e01, -8.1200e-01, -4.6850e00], - [1.3107e01, 2.4800e-01, -6.6610e00], - [1.9061e01, 7.0700e-01, -2.4800e-01], - [1.2152e01, -6.6610e00, -7.0700e-01], - [1.3456e01, -7.9210e00, 9.7700e-01], - [1.1889e01, -6.6140e00, 1.3240e00], - [1.9014e01, -1.3240e00, -5.1100e-01], - [2.0321e01, -9.7700e-01, 1.0560e00], - [1.1805e01, -2.9510e00, -3.7050e00], - [1.1285e01, -5.5100e00, -9.0400e-01], - [1.2378e01, -4.8140e00, -2.2470e00], - [1.1496e01, -1.1150e00, -5.5100e00], - [1.0153e01, -2.2000e-02, -4.8140e00], - [1.1693e01, -2.4800e-01, -6.6610e00], - [1.3724e01, -5.1100e-01, -6.6140e00], - [1.3377e01, 1.0560e00, -7.9210e00], - [1.9014e01, 1.3240e00, 5.1100e-01], - [2.0321e01, 9.7700e-01, -1.0560e00], - [1.1344e01, -7.9210e00, -9.7700e-01], - [1.2911e01, -6.6140e00, -1.3240e00], - [1.2616e01, -9.1610e00, 7.0400e-01], - [1.3752e01, -7.9260e00, 1.9020e00], - [1.4243e01, -7.9310e00, 4.0900e-01], - [2.1561e01, -7.0400e-01, 2.1600e-01], - [2.0326e01, -1.9020e00, 1.3520e00], - [2.0331e01, -4.0900e-01, 1.8430e00], - [1.1423e01, -1.0560e00, -7.9210e00], - [1.1076e01, 5.1100e-01, -6.6140e00], - [1.3104e01, 2.1600e-01, -9.1610e00], - [1.4302e01, 1.3520e00, -7.9260e00], - [1.2809e01, 1.8430e00, -7.9310e00], - [2.1561e01, 7.0400e-01, -2.1600e-01], - [2.0326e01, 1.9020e00, -1.3520e00], - [2.0331e01, 4.0900e-01, -1.8430e00], - [1.2184e01, -9.1610e00, -7.0400e-01], - [1.1048e01, -7.9260e00, -1.9020e00], - [1.0557e01, -7.9310e00, -4.0900e-01], - [1.3134e01, -9.9600e00, 8.9000e-01], - [1.1837e01, -9.1660e00, 1.2850e00], - [2.1566e01, -1.2850e00, -5.6300e-01], - [2.2360e01, -8.9000e-01, 7.3400e-01], - [1.1696e01, -2.1600e-01, -9.1610e00], - [1.0498e01, -1.3520e00, -7.9260e00], - [1.1991e01, -1.8430e00, -7.9310e00], - [1.3685e01, -5.6300e-01, -9.1660e00], - [1.3290e01, 7.3400e-01, -9.9600e00], - [2.1566e01, 1.2850e00, 5.6300e-01], - [2.2360e01, 8.9000e-01, -7.3400e-01], - [1.1666e01, -9.9600e00, -8.9000e-01], - [1.2963e01, -9.1660e00, -1.2850e00], - [1.1510e01, -7.3400e-01, -9.9600e00], - [1.1115e01, 5.6300e-01, -9.1660e00], - [1.1069e01, 9.6670e00, 9.2210e00], - [1.0304e01, 1.0773e01, 8.8850e00], - [1.1805e01, 9.4490e00, 8.6950e00], - [1.0773e01, 8.8850e00, 1.0304e01], - [1.0627e01, 1.1588e01, 7.7150e00], - [9.2210e00, 1.1069e01, 9.6670e00], - [9.6670e00, 9.2210e00, 1.1069e01], - [1.1588e01, 7.7150e00, 1.0627e01], - [1.1496e01, 1.1285e01, 6.8900e00], - [1.0153e01, 1.2378e01, 7.5860e00], - [8.8850e00, 1.0304e01, 1.0773e01], - [8.6950e00, 1.1805e01, 9.4490e00], - [9.4490e00, 8.6950e00, 1.1805e01], - [1.1285e01, 6.8900e00, 1.1496e01], - [1.2378e01, 7.5860e00, 1.0153e01], - [1.1693e01, 1.2152e01, 5.7390e00], - [7.7150e00, 1.0627e01, 1.1588e01], - [1.2152e01, 5.7390e00, 1.1693e01], - [1.1423e01, 1.1344e01, 4.4790e00], - [1.1076e01, 1.2911e01, 5.7860e00], - [1.3107e01, 1.2648e01, 5.7390e00], - [6.8900e00, 1.1496e01, 1.1285e01], - [7.5860e00, 1.0153e01, 1.2378e01], - [1.2648e01, 5.7390e00, 1.3107e01], - [1.1344e01, 4.4790e00, 1.1423e01], - [1.2911e01, 5.7860e00, 1.1076e01], - [1.1696e01, 1.2184e01, 3.2390e00], - [1.0498e01, 1.1048e01, 4.4740e00], - [1.1991e01, 1.0557e01, 4.4690e00], - [1.3304e01, 1.3515e01, 6.8900e00], - [1.3377e01, 1.3456e01, 4.4790e00], - [1.3724e01, 1.1889e01, 5.7860e00], - [5.7390e00, 1.1693e01, 1.2152e01], - [1.3515e01, 6.8900e00, 1.3304e01], - [1.3456e01, 4.4790e00, 1.3377e01], - [1.1889e01, 5.7860e00, 1.3724e01], - [1.2184e01, 3.2390e00, 1.1696e01], - [1.1048e01, 4.4740e00, 1.0498e01], - [1.0557e01, 4.4690e00, 1.1991e01], - [1.1510e01, 1.1666e01, 2.4400e00], - [1.1115e01, 1.2963e01, 3.2340e00], - [1.3104e01, 1.2616e01, 3.2390e00], - [1.4173e01, 1.3212e01, 7.7150e00], - [1.4302e01, 1.3752e01, 4.4740e00], - [1.2809e01, 1.4243e01, 4.4690e00], - [4.4790e00, 1.1423e01, 1.1344e01], - [5.7860e00, 1.1076e01, 1.2911e01], - [5.7390e00, 1.3107e01, 1.2648e01], - [1.3212e01, 7.7150e00, 1.4173e01], - [1.2616e01, 3.2390e00, 1.3104e01], - [1.3752e01, 4.4740e00, 1.4302e01], - [1.4243e01, 4.4690e00, 1.2809e01], - [1.1666e01, 2.4400e00, 1.1510e01], - [1.2963e01, 3.2340e00, 1.1115e01], - [1.3290e01, 1.3134e01, 2.4400e00], - [1.3685e01, 1.1837e01, 3.2340e00], - [1.4496e01, 1.4027e01, 8.8850e00], - [1.4647e01, 1.2422e01, 7.5860e00], - [3.2390e00, 1.1696e01, 1.2184e01], - [4.4740e00, 1.0498e01, 1.1048e01], - [4.4690e00, 1.1991e01, 1.0557e01], - [6.8900e00, 1.3304e01, 1.3515e01], - [4.4790e00, 1.3377e01, 1.3456e01], - [5.7860e00, 1.3724e01, 1.1889e01], - [1.4027e01, 8.8850e00, 1.4496e01], - [1.2422e01, 7.5860e00, 1.4647e01], - [1.3134e01, 2.4400e00, 1.3290e01], - [1.1837e01, 3.2340e00, 1.3685e01], - [1.3731e01, 1.5133e01, 9.2210e00], - [1.5579e01, 1.3731e01, 9.6670e00], - [2.4400e00, 1.1510e01, 1.1666e01], - [3.2340e00, 1.1115e01, 1.2963e01], - [3.2390e00, 1.3104e01, 1.2616e01], - [7.7150e00, 1.4173e01, 1.3212e01], - [4.4740e00, 1.4302e01, 1.3752e01], - [4.4690e00, 1.2809e01, 1.4243e01], - [1.3731e01, 9.6670e00, 1.5579e01], - [1.5133e01, 9.2210e00, 1.3731e01], - [1.2995e01, 1.5351e01, 8.6950e00], - [1.4027e01, 1.5915e01, 1.0304e01], - [1.5915e01, 1.4496e01, 1.0773e01], - [1.6105e01, 1.2995e01, 9.4490e00], - [2.4400e00, 1.3290e01, 1.3134e01], - [3.2340e00, 1.3685e01, 1.1837e01], - [8.8850e00, 1.4496e01, 1.4027e01], - [7.5860e00, 1.4647e01, 1.2422e01], - [1.4496e01, 1.0773e01, 1.5915e01], - [1.2995e01, 9.4490e00, 1.6105e01], - [1.5351e01, 8.6950e00, 1.2995e01], - [1.5915e01, 1.0304e01, 1.4027e01], - [1.5133e01, 1.5579e01, 1.1069e01], - [1.3212e01, 1.7085e01, 1.0627e01], - [1.7085e01, 1.4173e01, 1.1588e01], - [9.6670e00, 1.5579e01, 1.3731e01], - [9.2210e00, 1.3731e01, 1.5133e01], - [1.4173e01, 1.1588e01, 1.7085e01], - [1.5579e01, 1.1069e01, 1.5133e01], - [1.7085e01, 1.0627e01, 1.3212e01], - [1.5351e01, 1.6105e01, 1.1805e01], - [1.3515e01, 1.7910e01, 1.1496e01], - [1.2422e01, 1.7214e01, 1.0153e01], - [1.7910e01, 1.3304e01, 1.1285e01], - [1.7214e01, 1.4647e01, 1.2378e01], - [1.0773e01, 1.5915e01, 1.4496e01], - [9.4490e00, 1.6105e01, 1.2995e01], - [1.0304e01, 1.4027e01, 1.5915e01], - [8.6950e00, 1.2995e01, 1.5351e01], - [1.3304e01, 1.1285e01, 1.7910e01], - [1.4647e01, 1.2378e01, 1.7214e01], - [1.6105e01, 1.1805e01, 1.5351e01], - [1.7910e01, 1.1496e01, 1.3515e01], - [1.7214e01, 1.0153e01, 1.2422e01], - [1.2648e01, 1.9061e01, 1.1693e01], - [1.9061e01, 1.3107e01, 1.2152e01], - [1.1069e01, 1.5133e01, 1.5579e01], - [1.1588e01, 1.7085e01, 1.4173e01], - [1.0627e01, 1.3212e01, 1.7085e01], - [1.3107e01, 1.2152e01, 1.9061e01], - [1.9061e01, 1.1693e01, 1.2648e01], - [1.2152e01, 1.9061e01, 1.3107e01], - [1.3456e01, 2.0321e01, 1.1423e01], - [1.1889e01, 1.9014e01, 1.1076e01], - [2.0321e01, 1.3377e01, 1.1344e01], - [1.9014e01, 1.3724e01, 1.2911e01], - [1.1805e01, 1.5351e01, 1.6105e01], - [1.1285e01, 1.7910e01, 1.3304e01], - [1.2378e01, 1.7214e01, 1.4647e01], - [1.1496e01, 1.3515e01, 1.7910e01], - [1.0153e01, 1.2422e01, 1.7214e01], - [1.1693e01, 1.2648e01, 1.9061e01], - [1.3377e01, 1.1344e01, 2.0321e01], - [1.3724e01, 1.2911e01, 1.9014e01], - [2.0321e01, 1.1423e01, 1.3456e01], - [1.9014e01, 1.1076e01, 1.1889e01], - [1.1344e01, 2.0321e01, 1.3377e01], - [1.2911e01, 1.9014e01, 1.3724e01], - [1.2616e01, 2.1561e01, 1.1696e01], - [1.3752e01, 2.0326e01, 1.0498e01], - [1.4243e01, 2.0331e01, 1.1991e01], - [2.1561e01, 1.3104e01, 1.2184e01], - [2.0326e01, 1.4302e01, 1.1048e01], - [2.0331e01, 1.2809e01, 1.0557e01], - [1.1423e01, 1.3456e01, 2.0321e01], - [1.1076e01, 1.1889e01, 1.9014e01], - [1.3104e01, 1.2184e01, 2.1561e01], - [1.4302e01, 1.1048e01, 2.0326e01], - [1.2809e01, 1.0557e01, 2.0331e01], - [2.1561e01, 1.1696e01, 1.2616e01], - [2.0326e01, 1.0498e01, 1.3752e01], - [2.0331e01, 1.1991e01, 1.4243e01], - [1.2184e01, 2.1561e01, 1.3104e01], - [1.1048e01, 2.0326e01, 1.4302e01], - [1.0557e01, 2.0331e01, 1.2809e01], - [1.3134e01, 2.2360e01, 1.1510e01], - [1.1837e01, 2.1566e01, 1.1115e01], - [2.2360e01, 1.3290e01, 1.1666e01], - [2.1566e01, 1.3685e01, 1.2963e01], - [1.1696e01, 1.2616e01, 2.1561e01], - [1.0498e01, 1.3752e01, 2.0326e01], - [1.1991e01, 1.4243e01, 2.0331e01], - [1.3290e01, 1.1666e01, 2.2360e01], - [1.3685e01, 1.2963e01, 2.1566e01], - [2.2360e01, 1.1510e01, 1.3134e01], - [2.1566e01, 1.1115e01, 1.1837e01], - [1.1666e01, 2.2360e01, 1.3290e01], - [1.2963e01, 2.1566e01, 1.3685e01], - [1.1510e01, 1.3134e01, 2.2360e01], - [1.1115e01, 1.1837e01, 2.1566e01], - [3.5150e00, 2.0960e00, 1.0773e01], - [2.7330e00, 3.1790e00, 1.1069e01], - [3.1790e00, 1.3310e00, 9.6670e00], - [4.6850e00, 1.7730e00, 1.1588e01], - [1.6270e00, 3.5150e00, 1.0304e01], - [2.9510e00, 3.7050e00, 1.1805e01], - [2.0960e00, 1.6270e00, 8.8850e00], - [3.7050e00, 5.9500e-01, 9.4490e00], - [5.5100e00, 9.0400e-01, 1.1285e01], - [4.8140e00, 2.2470e00, 1.2378e01], - [1.3310e00, 2.7330e00, 9.2210e00], - [8.1200e-01, 4.6850e00, 1.0627e01], - [1.7730e00, 8.1200e-01, 7.7150e00], - [6.6610e00, 7.0700e-01, 1.2152e01], - [5.9500e-01, 2.9510e00, 8.6950e00], - [1.1150e00, 5.5100e00, 1.1496e01], - [2.2000e-02, 4.8140e00, 1.0153e01], - [9.0400e-01, 1.1150e00, 6.8900e00], - [2.2470e00, 2.2000e-02, 7.5860e00], - [7.9210e00, 9.7700e-01, 1.1344e01], - [6.6140e00, 1.3240e00, 1.2911e01], - [6.6610e00, -7.0700e-01, 1.2648e01], - [2.4800e-01, 6.6610e00, 1.1693e01], - [7.0700e-01, 2.4800e-01, 5.7390e00], - [9.1610e00, 7.0400e-01, 1.2184e01], - [7.9260e00, 1.9020e00, 1.1048e01], - [7.9310e00, 4.0900e-01, 1.0557e01], - [5.5100e00, -9.0400e-01, 1.3515e01], - [7.9210e00, -9.7700e-01, 1.3456e01], - [6.6140e00, -1.3240e00, 1.1889e01], - [1.0560e00, 7.9210e00, 1.1423e01], - [-2.4800e-01, 6.6610e00, 1.3107e01], - [-5.1100e-01, 6.6140e00, 1.1076e01], - [9.7700e-01, 1.0560e00, 4.4790e00], - [-7.0700e-01, -2.4800e-01, 5.7390e00], - [1.3240e00, -5.1100e-01, 5.7860e00], - [9.9600e00, 8.9000e-01, 1.1666e01], - [9.1660e00, 1.2850e00, 1.2963e01], - [9.1610e00, -7.0400e-01, 1.2616e01], - [4.6850e00, -1.7730e00, 1.3212e01], - [7.9260e00, -1.9020e00, 1.3752e01], - [7.9310e00, -4.0900e-01, 1.4243e01], - [2.1600e-01, 9.1610e00, 1.1696e01], - [1.3520e00, 7.9260e00, 1.0498e01], - [1.8430e00, 7.9310e00, 1.1991e01], - [5.1100e-01, 6.6140e00, 1.3724e01], - [-1.1150e00, 5.5100e00, 1.3304e01], - [-1.0560e00, 7.9210e00, 1.3377e01], - [7.0400e-01, 2.1600e-01, 3.2390e00], - [1.9020e00, 1.3520e00, 4.4740e00], - [4.0900e-01, 1.8430e00, 4.4690e00], - [-9.0400e-01, -1.1150e00, 6.8900e00], - [-9.7700e-01, -1.0560e00, 4.4790e00], - [-1.3240e00, 5.1100e-01, 5.7860e00], - [9.9600e00, -8.9000e-01, 1.3134e01], - [9.1660e00, -1.2850e00, 1.1837e01], - [3.5150e00, -2.0960e00, 1.4027e01], - [4.8140e00, -2.2470e00, 1.2422e01], - [7.3400e-01, 9.9600e00, 1.1510e01], - [-2.1600e-01, 9.1610e00, 1.3104e01], - [-5.6300e-01, 9.1660e00, 1.1115e01], - [-8.1200e-01, 4.6850e00, 1.4173e01], - [-1.3520e00, 7.9260e00, 1.4302e01], - [-1.8430e00, 7.9310e00, 1.2809e01], - [8.9000e-01, 7.3400e-01, 2.4400e00], - [-7.0400e-01, -2.1600e-01, 3.2390e00], - [1.2850e00, -5.6300e-01, 3.2340e00], - [-1.7730e00, -8.1200e-01, 7.7150e00], - [-1.9020e00, -1.3520e00, 4.4740e00], - [-4.0900e-01, -1.8430e00, 4.4690e00], - [2.7330e00, -3.1790e00, 1.3731e01], - [3.1790e00, -1.3310e00, 1.5133e01], - [5.6300e-01, 9.1660e00, 1.3685e01], - [-7.3400e-01, 9.9600e00, 1.3290e01], - [-1.6270e00, 3.5150e00, 1.4496e01], - [-2.2000e-02, 4.8140e00, 1.4647e01], - [-8.9000e-01, -7.3400e-01, 2.4400e00], - [-1.2850e00, 5.6300e-01, 3.2340e00], - [-2.0960e00, -1.6270e00, 8.8850e00], - [-2.2470e00, -2.2000e-02, 7.5860e00], - [1.6270e00, -3.5150e00, 1.4496e01], - [2.9510e00, -3.7050e00, 1.2995e01], - [2.0960e00, -1.6270e00, 1.5915e01], - [3.7050e00, -5.9500e-01, 1.5351e01], - [-1.3310e00, 2.7330e00, 1.5579e01], - [-2.7330e00, 3.1790e00, 1.3731e01], - [-1.3310e00, -2.7330e00, 9.2210e00], - [-3.1790e00, -1.3310e00, 9.6670e00], - [1.3310e00, -2.7330e00, 1.5579e01], - [8.1200e-01, -4.6850e00, 1.4173e01], - [1.7730e00, -8.1200e-01, 1.7085e01], - [-2.0960e00, 1.6270e00, 1.5915e01], - [-5.9500e-01, 2.9510e00, 1.6105e01], - [-2.9510e00, 3.7050e00, 1.2995e01], - [-3.5150e00, 2.0960e00, 1.4027e01], - [-5.9500e-01, -2.9510e00, 8.6950e00], - [-1.6270e00, -3.5150e00, 1.0304e01], - [-3.5150e00, -2.0960e00, 1.0773e01], - [-3.7050e00, -5.9500e-01, 9.4490e00], - [5.9500e-01, -2.9510e00, 1.6105e01], - [1.1150e00, -5.5100e00, 1.3304e01], - [2.2000e-02, -4.8140e00, 1.4647e01], - [9.0400e-01, -1.1150e00, 1.7910e01], - [2.2470e00, -2.2000e-02, 1.7214e01], - [-1.7730e00, 8.1200e-01, 1.7085e01], - [-3.1790e00, 1.3310e00, 1.5133e01], - [-4.6850e00, 1.7730e00, 1.3212e01], - [-2.7330e00, -3.1790e00, 1.1069e01], - [-8.1200e-01, -4.6850e00, 1.0627e01], - [-4.6850e00, -1.7730e00, 1.1588e01], - [2.4800e-01, -6.6610e00, 1.3107e01], - [7.0700e-01, -2.4800e-01, 1.9061e01], - [-9.0400e-01, 1.1150e00, 1.7910e01], - [-2.2470e00, 2.2000e-02, 1.7214e01], - [-3.7050e00, 5.9500e-01, 1.5351e01], - [-5.5100e00, 9.0400e-01, 1.3515e01], - [-4.8140e00, 2.2470e00, 1.2422e01], - [-2.9510e00, -3.7050e00, 1.1805e01], - [-1.1150e00, -5.5100e00, 1.1496e01], - [-2.2000e-02, -4.8140e00, 1.0153e01], - [-5.5100e00, -9.0400e-01, 1.1285e01], - [-4.8140e00, -2.2470e00, 1.2378e01], - [-5.1100e-01, -6.6140e00, 1.3724e01], - [-2.4800e-01, -6.6610e00, 1.1693e01], - [1.0560e00, -7.9210e00, 1.3377e01], - [1.3240e00, 5.1100e-01, 1.9014e01], - [-7.0700e-01, 2.4800e-01, 1.9061e01], - [9.7700e-01, -1.0560e00, 2.0321e01], - [-6.6610e00, 7.0700e-01, 1.2648e01], - [-6.6610e00, -7.0700e-01, 1.2152e01], - [-1.0560e00, -7.9210e00, 1.1423e01], - [5.1100e-01, -6.6140e00, 1.1076e01], - [2.1600e-01, -9.1610e00, 1.3104e01], - [1.3520e00, -7.9260e00, 1.4302e01], - [1.8430e00, -7.9310e00, 1.2809e01], - [-1.3240e00, -5.1100e-01, 1.9014e01], - [-9.7700e-01, 1.0560e00, 2.0321e01], - [7.0400e-01, -2.1600e-01, 2.1561e01], - [1.9020e00, -1.3520e00, 2.0326e01], - [4.0900e-01, -1.8430e00, 2.0331e01], - [-7.9210e00, 9.7700e-01, 1.3456e01], - [-6.6140e00, 1.3240e00, 1.1889e01], - [-7.9210e00, -9.7700e-01, 1.1344e01], - [-6.6140e00, -1.3240e00, 1.2911e01], - [-2.1600e-01, -9.1610e00, 1.1696e01], - [-1.3520e00, -7.9260e00, 1.0498e01], - [-1.8430e00, -7.9310e00, 1.1991e01], - [-5.6300e-01, -9.1660e00, 1.3685e01], - [7.3400e-01, -9.9600e00, 1.3290e01], - [-7.0400e-01, 2.1600e-01, 2.1561e01], - [-1.9020e00, 1.3520e00, 2.0326e01], - [-4.0900e-01, 1.8430e00, 2.0331e01], - [1.2850e00, 5.6300e-01, 2.1566e01], - [8.9000e-01, -7.3400e-01, 2.2360e01], - [-9.1610e00, 7.0400e-01, 1.2616e01], - [-7.9260e00, 1.9020e00, 1.3752e01], - [-7.9310e00, 4.0900e-01, 1.4243e01], - [-9.1610e00, -7.0400e-01, 1.2184e01], - [-7.9260e00, -1.9020e00, 1.1048e01], - [-7.9310e00, -4.0900e-01, 1.0557e01], - [-7.3400e-01, -9.9600e00, 1.1510e01], - [5.6300e-01, -9.1660e00, 1.1115e01], - [-1.2850e00, -5.6300e-01, 2.1566e01], - [-8.9000e-01, 7.3400e-01, 2.2360e01], - [-9.9600e00, 8.9000e-01, 1.3134e01], - [-9.1660e00, 1.2850e00, 1.1837e01], - [-9.9600e00, -8.9000e-01, 1.1666e01], - [-9.1660e00, -1.2850e00, 1.2963e01], - [3.5150e00, 1.0304e01, 1.6270e00], - [2.7330e00, 9.2210e00, 1.3310e00], - [3.1790e00, 1.1069e01, 2.7330e00], - [4.6850e00, 1.0627e01, 8.1200e-01], - [1.6270e00, 8.8850e00, 2.0960e00], - [2.9510e00, 8.6950e00, 5.9500e-01], - [2.0960e00, 1.0773e01, 3.5150e00], - [3.7050e00, 1.1805e01, 2.9510e00], - [5.5100e00, 1.1496e01, 1.1150e00], - [4.8140e00, 1.0153e01, 2.2000e-02], - [1.3310e00, 9.6670e00, 3.1790e00], - [8.1200e-01, 7.7150e00, 1.7730e00], - [1.7730e00, 1.1588e01, 4.6850e00], - [6.6610e00, 1.1693e01, 2.4800e-01], - [5.9500e-01, 9.4490e00, 3.7050e00], - [1.1150e00, 6.8900e00, 9.0400e-01], - [2.2000e-02, 7.5860e00, 2.2470e00], - [9.0400e-01, 1.1285e01, 5.5100e00], - [2.2470e00, 1.2378e01, 4.8140e00], - [7.9210e00, 1.1423e01, 1.0560e00], - [6.6140e00, 1.1076e01, -5.1100e-01], - [6.6610e00, 1.3107e01, -2.4800e-01], - [2.4800e-01, 5.7390e00, 7.0700e-01], - [7.0700e-01, 1.2152e01, 6.6610e00], - [9.1610e00, 1.1696e01, 2.1600e-01], - [7.9260e00, 1.0498e01, 1.3520e00], - [7.9310e00, 1.1991e01, 1.8430e00], - [6.6140e00, 1.3724e01, 5.1100e-01], - [5.5100e00, 1.3304e01, -1.1150e00], - [7.9210e00, 1.3377e01, -1.0560e00], - [1.0560e00, 4.4790e00, 9.7700e-01], - [-2.4800e-01, 5.7390e00, -7.0700e-01], - [-5.1100e-01, 5.7860e00, 1.3240e00], - [9.7700e-01, 1.1344e01, 7.9210e00], - [1.3240e00, 1.2911e01, 6.6140e00], - [-7.0700e-01, 1.2648e01, 6.6610e00], - [9.9600e00, 1.1510e01, 7.3400e-01], - [9.1660e00, 1.1115e01, -5.6300e-01], - [9.1610e00, 1.3104e01, -2.1600e-01], - [4.6850e00, 1.4173e01, -8.1200e-01], - [7.9260e00, 1.4302e01, -1.3520e00], - [7.9310e00, 1.2809e01, -1.8430e00], - [2.1600e-01, 3.2390e00, 7.0400e-01], - [1.3520e00, 4.4740e00, 1.9020e00], - [1.8430e00, 4.4690e00, 4.0900e-01], - [-1.1150e00, 6.8900e00, -9.0400e-01], - [-1.0560e00, 4.4790e00, -9.7700e-01], - [5.1100e-01, 5.7860e00, -1.3240e00], - [7.0400e-01, 1.2184e01, 9.1610e00], - [1.9020e00, 1.1048e01, 7.9260e00], - [4.0900e-01, 1.0557e01, 7.9310e00], - [-9.0400e-01, 1.3515e01, 5.5100e00], - [-9.7700e-01, 1.3456e01, 7.9210e00], - [-1.3240e00, 1.1889e01, 6.6140e00], - [9.1660e00, 1.3685e01, 5.6300e-01], - [9.9600e00, 1.3290e01, -7.3400e-01], - [3.5150e00, 1.4496e01, -1.6270e00], - [4.8140e00, 1.4647e01, -2.2000e-02], - [7.3400e-01, 2.4400e00, 8.9000e-01], - [-2.1600e-01, 3.2390e00, -7.0400e-01], - [-5.6300e-01, 3.2340e00, 1.2850e00], - [-8.1200e-01, 7.7150e00, -1.7730e00], - [-1.3520e00, 4.4740e00, -1.9020e00], - [-1.8430e00, 4.4690e00, -4.0900e-01], - [8.9000e-01, 1.1666e01, 9.9600e00], - [1.2850e00, 1.2963e01, 9.1660e00], - [-7.0400e-01, 1.2616e01, 9.1610e00], - [-1.7730e00, 1.3212e01, 4.6850e00], - [-1.9020e00, 1.3752e01, 7.9260e00], - [-4.0900e-01, 1.4243e01, 7.9310e00], - [2.7330e00, 1.5579e01, -1.3310e00], - [3.1790e00, 1.3731e01, -2.7330e00], - [-7.3400e-01, 2.4400e00, -8.9000e-01], - [5.6300e-01, 3.2340e00, -1.2850e00], - [-1.6270e00, 8.8850e00, -2.0960e00], - [-2.2000e-02, 7.5860e00, -2.2470e00], - [-8.9000e-01, 1.3134e01, 9.9600e00], - [-1.2850e00, 1.1837e01, 9.1660e00], - [-2.0960e00, 1.4027e01, 3.5150e00], - [-2.2470e00, 1.2422e01, 4.8140e00], - [1.6270e00, 1.5915e01, -2.0960e00], - [2.9510e00, 1.6105e01, -5.9500e-01], - [2.0960e00, 1.4027e01, -3.5150e00], - [3.7050e00, 1.2995e01, -2.9510e00], - [-1.3310e00, 9.6670e00, -3.1790e00], - [-2.7330e00, 9.2210e00, -1.3310e00], - [-1.3310e00, 1.5133e01, 3.1790e00], - [-3.1790e00, 1.3731e01, 2.7330e00], - [1.3310e00, 1.5133e01, -3.1790e00], - [8.1200e-01, 1.7085e01, -1.7730e00], - [1.7730e00, 1.3212e01, -4.6850e00], - [-2.0960e00, 1.0773e01, -3.5150e00], - [-5.9500e-01, 9.4490e00, -3.7050e00], - [-2.9510e00, 8.6950e00, -5.9500e-01], - [-3.5150e00, 1.0304e01, -1.6270e00], - [-5.9500e-01, 1.5351e01, 3.7050e00], - [-1.6270e00, 1.5915e01, 2.0960e00], - [-3.5150e00, 1.4496e01, 1.6270e00], - [-3.7050e00, 1.2995e01, 2.9510e00], - [5.9500e-01, 1.5351e01, -3.7050e00], - [1.1150e00, 1.7910e01, -9.0400e-01], - [2.2000e-02, 1.7214e01, -2.2470e00], - [9.0400e-01, 1.3515e01, -5.5100e00], - [2.2470e00, 1.2422e01, -4.8140e00], - [-1.7730e00, 1.1588e01, -4.6850e00], - [-3.1790e00, 1.1069e01, -2.7330e00], - [-4.6850e00, 1.0627e01, -8.1200e-01], - [-2.7330e00, 1.5579e01, 1.3310e00], - [-8.1200e-01, 1.7085e01, 1.7730e00], - [-4.6850e00, 1.4173e01, 8.1200e-01], - [2.4800e-01, 1.9061e01, -7.0700e-01], - [7.0700e-01, 1.2648e01, -6.6610e00], - [-9.0400e-01, 1.1285e01, -5.5100e00], - [-2.2470e00, 1.2378e01, -4.8140e00], - [-3.7050e00, 1.1805e01, -2.9510e00], - [-5.5100e00, 1.1496e01, -1.1150e00], - [-4.8140e00, 1.0153e01, -2.2000e-02], - [-2.9510e00, 1.6105e01, 5.9500e-01], - [-1.1150e00, 1.7910e01, 9.0400e-01], - [-2.2000e-02, 1.7214e01, 2.2470e00], - [-5.5100e00, 1.3304e01, 1.1150e00], - [-4.8140e00, 1.4647e01, 2.2000e-02], - [-5.1100e-01, 1.9014e01, -1.3240e00], - [-2.4800e-01, 1.9061e01, 7.0700e-01], - [1.0560e00, 2.0321e01, -9.7700e-01], - [-7.0700e-01, 1.2152e01, -6.6610e00], - [9.7700e-01, 1.3456e01, -7.9210e00], - [1.3240e00, 1.1889e01, -6.6140e00], - [-6.6610e00, 1.1693e01, -2.4800e-01], - [-6.6610e00, 1.3107e01, 2.4800e-01], - [5.1100e-01, 1.9014e01, 1.3240e00], - [-1.0560e00, 2.0321e01, 9.7700e-01], - [2.1600e-01, 2.1561e01, -7.0400e-01], - [1.3520e00, 2.0326e01, -1.9020e00], - [1.8430e00, 2.0331e01, -4.0900e-01], - [-9.7700e-01, 1.1344e01, -7.9210e00], - [-1.3240e00, 1.2911e01, -6.6140e00], - [7.0400e-01, 1.2616e01, -9.1610e00], - [1.9020e00, 1.3752e01, -7.9260e00], - [4.0900e-01, 1.4243e01, -7.9310e00], - [-7.9210e00, 1.1423e01, -1.0560e00], - [-6.6140e00, 1.1076e01, 5.1100e-01], - [-6.6140e00, 1.3724e01, -5.1100e-01], - [-7.9210e00, 1.3377e01, 1.0560e00], - [-2.1600e-01, 2.1561e01, 7.0400e-01], - [-1.3520e00, 2.0326e01, 1.9020e00], - [-1.8430e00, 2.0331e01, 4.0900e-01], - [-5.6300e-01, 2.1566e01, -1.2850e00], - [7.3400e-01, 2.2360e01, -8.9000e-01], - [-7.0400e-01, 1.2184e01, -9.1610e00], - [-1.9020e00, 1.1048e01, -7.9260e00], - [-4.0900e-01, 1.0557e01, -7.9310e00], - [8.9000e-01, 1.3134e01, -9.9600e00], - [1.2850e00, 1.1837e01, -9.1660e00], - [-9.1610e00, 1.1696e01, -2.1600e-01], - [-7.9260e00, 1.0498e01, -1.3520e00], - [-7.9310e00, 1.1991e01, -1.8430e00], - [-9.1610e00, 1.3104e01, 2.1600e-01], - [-7.9260e00, 1.4302e01, 1.3520e00], - [-7.9310e00, 1.2809e01, 1.8430e00], - [5.6300e-01, 2.1566e01, 1.2850e00], - [-7.3400e-01, 2.2360e01, 8.9000e-01], - [-8.9000e-01, 1.1666e01, -9.9600e00], - [-1.2850e00, 1.2963e01, -9.1660e00], - [-9.9600e00, 1.1510e01, -7.3400e-01], - [-9.1660e00, 1.1115e01, 5.6300e-01], - [-9.1660e00, 1.3685e01, -5.6300e-01], - [-9.9600e00, 1.3290e01, 7.3400e-01], - [1.8816e01, 1.7896e01, 9.4390e00], - [1.9656e01, 1.7623e01, 1.0679e01], - [1.9334e01, 1.7710e01, 8.6400e00], - [1.8037e01, 1.7315e01, 9.4340e00], - [1.8384e01, 1.9304e01, 9.4390e00], - [1.8848e01, 1.7893e01, 1.1939e01], - [1.9952e01, 1.6698e01, 1.0674e01], - [2.0443e01, 1.8191e01, 1.0669e01], - [1.7544e01, 1.9577e01, 1.0679e01], - [1.7866e01, 1.9490e01, 8.6400e00], - [1.9163e01, 1.9885e01, 9.4340e00], - [1.9715e01, 1.7696e01, 1.3090e01], - [1.8089e01, 1.7276e01, 1.1986e01], - [1.8352e01, 1.9307e01, 1.1939e01], - [1.7248e01, 2.0502e01, 1.0674e01], - [1.6757e01, 1.9009e01, 1.0669e01], - [1.9412e01, 1.6827e01, 1.3915e01], - [1.7485e01, 1.9504e01, 1.3090e01], - [1.9111e01, 1.9924e01, 1.1986e01], - [2.0227e01, 1.6504e01, 1.5085e01], - [1.8622e01, 1.6353e01, 1.3786e01], - [1.7788e01, 2.0373e01, 1.3915e01], - [2.1333e01, 1.7269e01, 1.5421e01], - [1.9931e01, 1.5421e01, 1.5867e01], - [1.6973e01, 2.0696e01, 1.5085e01], - [1.8578e01, 2.0847e01, 1.3786e01], - [2.1551e01, 1.8005e01, 1.4895e01], - [2.2115e01, 1.6973e01, 1.6504e01], - [2.0696e01, 1.5085e01, 1.6973e01], - [1.9195e01, 1.4895e01, 1.5649e01], - [1.5867e01, 1.9931e01, 1.5421e01], - [1.7269e01, 2.1779e01, 1.5867e01], - [2.1779e01, 1.5867e01, 1.7269e01], - [2.3285e01, 1.7788e01, 1.6827e01], - [2.0373e01, 1.3915e01, 1.7788e01], - [1.5649e01, 1.9195e01, 1.4895e01], - [1.5085e01, 2.0227e01, 1.6504e01], - [1.6504e01, 2.2115e01, 1.6973e01], - [1.8005e01, 2.2305e01, 1.5649e01], - [2.2305e01, 1.5649e01, 1.8005e01], - [2.4110e01, 1.7485e01, 1.7696e01], - [2.3414e01, 1.8578e01, 1.6353e01], - [1.9504e01, 1.3090e01, 1.7485e01], - [2.0847e01, 1.3786e01, 1.8578e01], - [1.5421e01, 2.1333e01, 1.7269e01], - [1.3915e01, 1.9412e01, 1.6827e01], - [1.6827e01, 2.3285e01, 1.7788e01], - [2.5261e01, 1.8352e01, 1.7893e01], - [1.9307e01, 1.1939e01, 1.8352e01], - [1.4895e01, 2.1551e01, 1.8005e01], - [1.3090e01, 1.9715e01, 1.7696e01], - [1.3786e01, 1.8622e01, 1.6353e01], - [1.7696e01, 2.4110e01, 1.7485e01], - [1.6353e01, 2.3414e01, 1.8578e01], - [2.6521e01, 1.7544e01, 1.7623e01], - [2.5214e01, 1.9111e01, 1.7276e01], - [2.5261e01, 1.8848e01, 1.9307e01], - [1.7893e01, 1.1939e01, 1.8848e01], - [1.9577e01, 1.0679e01, 1.7544e01], - [1.9924e01, 1.1986e01, 1.9111e01], - [1.1939e01, 1.8848e01, 1.7893e01], - [1.7893e01, 2.5261e01, 1.8352e01], - [2.7761e01, 1.8384e01, 1.7896e01], - [2.6526e01, 1.7248e01, 1.6698e01], - [2.6531e01, 1.6757e01, 1.8191e01], - [2.4110e01, 1.9715e01, 1.9504e01], - [2.6521e01, 1.9656e01, 1.9577e01], - [2.5214e01, 1.8089e01, 1.9924e01], - [1.7696e01, 1.3090e01, 1.9715e01], - [1.7623e01, 1.0679e01, 1.9656e01], - [1.7276e01, 1.1986e01, 1.8089e01], - [1.9304e01, 9.4390e00, 1.8384e01], - [2.0502e01, 1.0674e01, 1.7248e01], - [1.9009e01, 1.0669e01, 1.6757e01], - [1.0679e01, 1.9656e01, 1.7623e01], - [1.1986e01, 1.8089e01, 1.7276e01], - [1.1939e01, 1.8352e01, 1.9307e01], - [1.7623e01, 2.6521e01, 1.7544e01], - [1.7276e01, 2.5214e01, 1.9111e01], - [1.9307e01, 2.5261e01, 1.8848e01], - [2.8560e01, 1.7866e01, 1.7710e01], - [2.7766e01, 1.9163e01, 1.7315e01], - [2.7761e01, 1.8816e01, 1.9304e01], - [2.3285e01, 1.9412e01, 2.0373e01], - [2.6526e01, 1.9952e01, 2.0502e01], - [2.6531e01, 2.0443e01, 1.9009e01], - [1.6827e01, 1.3915e01, 1.9412e01], - [1.7896e01, 9.4390e00, 1.8816e01], - [1.6698e01, 1.0674e01, 1.9952e01], - [1.8191e01, 1.0669e01, 2.0443e01], - [1.9490e01, 8.6400e00, 1.7866e01], - [1.9885e01, 9.4340e00, 1.9163e01], - [9.4390e00, 1.8816e01, 1.7896e01], - [1.0674e01, 1.9952e01, 1.6698e01], - [1.0669e01, 2.0443e01, 1.8191e01], - [1.3090e01, 1.7485e01, 1.9504e01], - [1.0679e01, 1.7544e01, 1.9577e01], - [1.1986e01, 1.9111e01, 1.9924e01], - [1.7896e01, 2.7761e01, 1.8384e01], - [1.6698e01, 2.6526e01, 1.7248e01], - [1.8191e01, 2.6531e01, 1.6757e01], - [1.9504e01, 2.4110e01, 1.9715e01], - [1.9577e01, 2.6521e01, 1.9656e01], - [1.9924e01, 2.5214e01, 1.8089e01], - [2.8560e01, 1.9334e01, 1.9490e01], - [2.7766e01, 1.8037e01, 1.9885e01], - [2.2115e01, 2.0227e01, 2.0696e01], - [2.3414e01, 1.8622e01, 2.0847e01], - [1.6504e01, 1.5085e01, 2.0227e01], - [1.6353e01, 1.3786e01, 1.8622e01], - [1.7710e01, 8.6400e00, 1.9334e01], - [1.7315e01, 9.4340e00, 1.8037e01], - [8.6400e00, 1.9334e01, 1.7710e01], - [9.4340e00, 1.8037e01, 1.7315e01], - [9.4390e00, 1.8384e01, 1.9304e01], - [1.3915e01, 1.7788e01, 2.0373e01], - [1.0674e01, 1.7248e01, 2.0502e01], - [1.0669e01, 1.6757e01, 1.9009e01], - [1.7710e01, 2.8560e01, 1.7866e01], - [1.7315e01, 2.7766e01, 1.9163e01], - [1.9304e01, 2.7761e01, 1.8816e01], - [2.0373e01, 2.3285e01, 1.9412e01], - [2.0502e01, 2.6526e01, 1.9952e01], - [1.9009e01, 2.6531e01, 2.0443e01], - [2.1333e01, 1.9931e01, 2.1779e01], - [2.1779e01, 2.1333e01, 1.9931e01], - [1.5421e01, 1.5867e01, 1.9931e01], - [1.7269e01, 1.5421e01, 2.1333e01], - [8.6400e00, 1.7866e01, 1.9490e01], - [9.4340e00, 1.9163e01, 1.9885e01], - [1.5085e01, 1.6973e01, 2.0696e01], - [1.3786e01, 1.8578e01, 2.0847e01], - [1.9490e01, 2.8560e01, 1.9334e01], - [1.9885e01, 2.7766e01, 1.8037e01], - [2.0696e01, 2.2115e01, 2.0227e01], - [2.0847e01, 2.3414e01, 1.8622e01], - [2.0227e01, 2.0696e01, 2.2115e01], - [2.1551e01, 1.9195e01, 2.2305e01], - [2.2305e01, 2.1551e01, 1.9195e01], - [1.4895e01, 1.5649e01, 1.9195e01], - [1.6973e01, 1.6504e01, 2.2115e01], - [1.8005e01, 1.4895e01, 2.1551e01], - [1.5867e01, 1.7269e01, 2.1779e01], - [1.9931e01, 2.1779e01, 2.1333e01], - [1.9412e01, 2.0373e01, 2.3285e01], - [1.7788e01, 1.6827e01, 2.3285e01], - [1.5649e01, 1.8005e01, 2.2305e01], - [1.9195e01, 2.2305e01, 2.1551e01], - [1.9715e01, 1.9504e01, 2.4110e01], - [1.8622e01, 2.0847e01, 2.3414e01], - [1.7485e01, 1.7696e01, 2.4110e01], - [1.8578e01, 1.6353e01, 2.3414e01], - [1.8848e01, 1.9307e01, 2.5261e01], - [1.8352e01, 1.7893e01, 2.5261e01], - [1.9656e01, 1.9577e01, 2.6521e01], - [1.8089e01, 1.9924e01, 2.5214e01], - [1.7544e01, 1.7623e01, 2.6521e01], - [1.9111e01, 1.7276e01, 2.5214e01], - [1.8816e01, 1.9304e01, 2.7761e01], - [1.9952e01, 2.0502e01, 2.6526e01], - [2.0443e01, 1.9009e01, 2.6531e01], - [1.8384e01, 1.7896e01, 2.7761e01], - [1.7248e01, 1.6698e01, 2.6526e01], - [1.6757e01, 1.8191e01, 2.6531e01], - [1.9334e01, 1.9490e01, 2.8560e01], - [1.8037e01, 1.9885e01, 2.7766e01], - [1.7866e01, 1.7710e01, 2.8560e01], - [1.9163e01, 1.7315e01, 2.7766e01], - ] - ), - "elements": np.array( - [ - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "H", - "H", - "C", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "H", - "C", - "H", - "C", - "C", - "C", - "N", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "C", - "C", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "H", - "H", - "C", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "H", - "C", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "N", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "H", - "C", - "N", - "H", - "C", - "H", - "C", - "C", - "H", - "H", - "H", - "N", - "C", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "H", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "H", - "C", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "N", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "H", - "C", - "N", - "H", - "C", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "N", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "C", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "H", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "C", - "H", - "C", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "N", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "N", - "H", - "H", - "N", - "H", - "H", - "N", - "H", - "N", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "H", - "N", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "N", - "H", - "H", - "N", - "H", - "H", - "N", - "H", - "N", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "C", - "C", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "H", - "H", - "C", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "H", - "N", - "H", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "H", - "C", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - ] - ), - "atom_ids": np.array( - [ - "C6", - "C5", - "H6", - "H7", - "C6", - "C4", - "H4", - "H5", - "C5", - "H6", - "H7", - "N1", - "H3", - "C4", - "H4", - "H5", - "C3", - "N1", - "H3", - "C2", - "H2", - "C3", - "C1", - "C1", - "C2", - "H2", - "C2", - "H1", - "H1", - "C2", - "C1", - "C1", - "C3", - "C1", - "C3", - "C2", - "H1", - "H1", - "C2", - "N1", - "H2", - "H1", - "N1", - "H2", - "C3", - "C1", - "C3", - "C4", - "C4", - "N1", - "H2", - "H1", - "N1", - "H2", - "C4", - "C5", - "H3", - "C5", - "H3", - "C4", - "C4", - "C4", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C5", - "H3", - "C4", - "C5", - "H3", - "C4", - "C3", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C2", - "H2", - "H6", - "H7", - "H6", - "H7", - "C2", - "H2", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C1", - "C1", - "C1", - "C1", - "H6", - "H7", - "C2", - "H2", - "H6", - "H7", - "C2", - "H2", - "H1", - "C2", - "H1", - "C2", - "H1", - "H1", - "C1", - "C1", - "C3", - "C3", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C4", - "C4", - "C5", - "H3", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C6", - "C6", - "C5", - "H6", - "H7", - "C5", - "H6", - "H7", - "C4", - "H4", - "H5", - "C4", - "H4", - "H5", - "N1", - "H3", - "N1", - "H3", - "C3", - "C3", - "C2", - "H2", - "C2", - "H2", - "C1", - "C1", - "C1", - "C1", - "C2", - "H1", - "C2", - "H1", - "C2", - "H1", - "C2", - "H1", - "C1", - "C3", - "C3", - "C1", - "C3", - "C3", - "H1", - "N1", - "H2", - "N1", - "H2", - "H1", - "N1", - "H2", - "N1", - "H2", - "C4", - "C4", - "C4", - "C4", - "C5", - "H3", - "C4", - "C5", - "H3", - "C4", - "C4", - "C5", - "H3", - "C5", - "H3", - "C4", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C3", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "H6", - "H7", - "C2", - "H2", - "H6", - "H7", - "C2", - "H2", - "C2", - "H2", - "H6", - "H7", - "H6", - "H7", - "C2", - "H2", - "C1", - "C1", - "C1", - "C1", - "C1", - "C1", - "H1", - "H1", - "C2", - "H1", - "C2", - "H1", - "H1", - "H1", - "C3", - "C3", - "N1", - "H2", - "N1", - "H2", - "C4", - "C4", - "C5", - "H3", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C6", - "C5", - "H6", - "H7", - "C6", - "C4", - "H4", - "H5", - "C5", - "H6", - "H7", - "N1", - "H3", - "C4", - "H4", - "H5", - "C3", - "N1", - "H3", - "C2", - "H2", - "C3", - "C1", - "C1", - "C2", - "H2", - "H1", - "C2", - "C2", - "H1", - "C1", - "C1", - "C1", - "C3", - "C3", - "H1", - "C2", - "C2", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C1", - "C3", - "C3", - "C4", - "C4", - "H1", - "N1", - "H2", - "N1", - "H2", - "C5", - "H3", - "C4", - "C4", - "C5", - "H3", - "C4", - "C4", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "C5", - "H3", - "C4", - "C5", - "H3", - "C4", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C3", - "C6", - "H4", - "H5", - "H6", - "H7", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H6", - "H7", - "C2", - "H2", - "C2", - "H2", - "H6", - "H7", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C1", - "C1", - "C1", - "C1", - "H6", - "H7", - "C2", - "H2", - "H6", - "H7", - "C2", - "H2", - "C2", - "H1", - "H1", - "H1", - "C2", - "H1", - "C1", - "C1", - "C3", - "C3", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C4", - "C4", - "C5", - "H3", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C1", - "C2", - "H1", - "C2", - "C3", - "C1", - "C1", - "C3", - "N1", - "H2", - "C2", - "H1", - "H1", - "N1", - "H2", - "C4", - "C3", - "C4", - "C5", - "H3", - "C4", - "N1", - "H2", - "C5", - "H3", - "C4", - "C6", - "H4", - "H5", - "H3", - "N1", - "C5", - "C4", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C5", - "C4", - "H3", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "H7", - "H6", - "C2", - "H2", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H6", - "H7", - "C2", - "H2", - "C1", - "C1", - "H6", - "C6", - "H7", - "C3", - "H4", - "H5", - "C1", - "C1", - "H1", - "C2", - "C2", - "H1", - "H6", - "H7", - "C2", - "H2", - "C2", - "H1", - "H1", - "C2", - "C1", - "C3", - "C3", - "C1", - "C1", - "C3", - "C1", - "C3", - "H1", - "N1", - "H2", - "N1", - "H2", - "C2", - "H1", - "C2", - "H1", - "N1", - "H2", - "H1", - "N1", - "H2", - "C4", - "C4", - "C1", - "C3", - "C3", - "C4", - "C4", - "C4", - "C5", - "H3", - "H3", - "C5", - "H1", - "N1", - "H2", - "N1", - "H2", - "C4", - "H3", - "C5", - "H3", - "C5", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H7", - "H6", - "C6", - "H4", - "H5", - "H7", - "H6", - "H7", - "H6", - "H6", - "H7", - "H6", - "H7", - "C1", - "C2", - "H1", - "C2", - "C3", - "C1", - "C1", - "C3", - "N1", - "H2", - "C2", - "H1", - "H1", - "N1", - "H2", - "C4", - "C3", - "C4", - "C5", - "H3", - "C4", - "N1", - "H2", - "C4", - "C5", - "H3", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C4", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C5", - "H3", - "C4", - "C3", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C2", - "H2", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C2", - "H2", - "H6", - "H7", - "C1", - "C1", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C1", - "C1", - "H1", - "C2", - "C2", - "H1", - "H6", - "H7", - "C2", - "H2", - "C2", - "H1", - "H1", - "C2", - "C1", - "C3", - "C3", - "C1", - "C1", - "C3", - "C1", - "C3", - "H1", - "N1", - "H2", - "N1", - "H2", - "C2", - "H1", - "C2", - "H1", - "N1", - "H2", - "H1", - "N1", - "H2", - "C4", - "C4", - "C1", - "C3", - "C3", - "C4", - "C4", - "C4", - "C5", - "H3", - "C5", - "H3", - "H1", - "N1", - "H2", - "N1", - "H2", - "C4", - "C5", - "H3", - "C5", - "H3", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - "H6", - "H7", - "H6", - "H7", - "C2", - "C1", - "C1", - "C3", - "C2", - "H1", - "C2", - "H1", - "N1", - "H2", - "C1", - "C3", - "C3", - "C4", - "H1", - "N1", - "H2", - "N1", - "H2", - "C5", - "H3", - "C4", - "C4", - "C4", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C5", - "C4", - "H3", - "C5", - "C4", - "H3", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C6", - "H4", - "H5", - "H3", - "N1", - "C5", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H6", - "H7", - "C2", - "H2", - "H6", - "C6", - "H7", - "C3", - "H4", - "H5", - "H6", - "C6", - "H7", - "C3", - "H4", - "H5", - "C1", - "C1", - "H7", - "H6", - "C2", - "H2", - "H6", - "H7", - "C2", - "H2", - "C2", - "H1", - "C2", - "H1", - "C1", - "C1", - "C1", - "C1", - "C1", - "C3", - "C3", - "C2", - "H1", - "H1", - "C2", - "H1", - "C2", - "C2", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C3", - "C1", - "C3", - "C1", - "C3", - "C3", - "C4", - "C4", - "N1", - "H2", - "H1", - "N1", - "H2", - "H1", - "N1", - "H2", - "N1", - "H2", - "H3", - "C4", - "C5", - "H3", - "C4", - "C5", - "C4", - "C4", - "C5", - "H3", - "C6", - "H4", - "H5", - "H3", - "C5", - "C6", - "H4", - "H5", - "C5", - "H3", - "C5", - "H3", - "C6", - "H4", - "H5", - "H7", - "H6", - "C6", - "H4", - "H5", - "H7", - "H6", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H7", - "H6", - "H6", - "H7", - "H6", - "H7", - "C2", - "C1", - "C1", - "C3", - "C2", - "H1", - "C2", - "H1", - "N1", - "H2", - "C1", - "C3", - "C3", - "C4", - "H1", - "N1", - "H2", - "N1", - "H2", - "C5", - "H3", - "C4", - "C4", - "C4", - "C6", - "H4", - "H5", - "H3", - "N1", - "C5", - "C5", - "C4", - "H3", - "C5", - "H3", - "C4", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H7", - "H6", - "C2", - "H2", - "H6", - "C6", - "H7", - "C3", - "H4", - "H5", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C1", - "C1", - "H6", - "H7", - "C2", - "H2", - "H6", - "H7", - "C2", - "H2", - "C2", - "H1", - "C2", - "H1", - "C1", - "C1", - "C1", - "C1", - "C1", - "C3", - "C3", - "C2", - "H1", - "H1", - "C2", - "H1", - "C2", - "C2", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C3", - "C1", - "C3", - "C1", - "C3", - "C3", - "C4", - "C4", - "N1", - "H2", - "H1", - "N1", - "H2", - "H1", - "N1", - "H2", - "N1", - "H2", - "H3", - "C4", - "C5", - "C4", - "C5", - "H3", - "C4", - "C4", - "H3", - "C5", - "C6", - "H4", - "H5", - "C5", - "H3", - "C6", - "H4", - "H5", - "C5", - "H3", - "H3", - "C5", - "C6", - "H4", - "H5", - "H7", - "H6", - "C6", - "H4", - "H5", - "H6", - "H7", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H7", - "H6", - "H6", - "H7", - "H6", - "H7", - "H7", - "H6", - "C6", - "C5", - "H6", - "H7", - "C6", - "C4", - "H4", - "H5", - "C5", - "H6", - "H7", - "N1", - "H3", - "C4", - "H4", - "H5", - "C3", - "N1", - "H3", - "C2", - "H2", - "C3", - "C1", - "C1", - "C2", - "H2", - "H1", - "C2", - "C2", - "H1", - "C1", - "C1", - "C1", - "C3", - "C3", - "H1", - "C2", - "C2", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C1", - "C3", - "C3", - "C4", - "C4", - "H1", - "N1", - "H2", - "N1", - "H2", - "C5", - "H3", - "C4", - "C4", - "C5", - "H3", - "C4", - "C4", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "C5", - "H3", - "C4", - "C5", - "H3", - "C4", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C3", - "C6", - "H4", - "H5", - "H6", - "H7", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "C6", - "H4", - "H5", - "N1", - "C5", - "H3", - "H6", - "H7", - "C2", - "H2", - "C2", - "H2", - "H6", - "H7", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "H6", - "H7", - "C6", - "C3", - "H4", - "H5", - "C1", - "C1", - "C1", - "C1", - "H6", - "H7", - "C2", - "H2", - "H6", - "H7", - "C2", - "H2", - "C2", - "H1", - "H1", - "H1", - "C2", - "H1", - "C1", - "C1", - "C3", - "C3", - "H1", - "H1", - "N1", - "H2", - "N1", - "H2", - "C4", - "C4", - "C5", - "H3", - "C5", - "H3", - "C6", - "H4", - "H5", - "C6", - "H4", - "H5", - "H6", - "H7", - "H6", - "H7", - ] - ), -} - -mol_system = { - "coordinates": np.array( - [ - [9.439, 6.416, 5.496], - [10.679, 7.256, 5.223], - [8.64, 6.934, 5.31], - [9.434, 5.637, 4.915], - [9.439, 5.984, 6.904], - [11.939, 6.448, 5.493], - [10.674, 7.552, 4.298], - [10.669, 8.043, 5.791], - [10.679, 5.144, 7.177], - [8.64, 5.466, 7.09], - [9.434, 6.763, 7.485], - [13.09, 7.315, 5.296], - [11.986, 5.689, 4.876], - [11.939, 5.952, 6.907], - [10.674, 4.848, 8.102], - [10.669, 4.357, 6.609], - [13.915, 7.012, 4.427], - [13.09, 5.085, 7.104], - [11.986, 6.711, 7.524], - [15.085, 7.827, 4.104], - [13.786, 6.222, 3.953], - [13.915, 5.388, 7.973], - [15.867, 7.531, 3.021], - [15.421, 8.933, 4.869], - [15.085, 4.573, 8.296], - [13.786, 6.178, 8.447], - [16.973, 8.296, 2.685], - [15.649, 6.795, 2.495], - [14.895, 9.151, 5.605], - [16.504, 9.715, 4.573], - [15.867, 4.869, 9.379], - [15.421, 3.467, 7.531], - [17.788, 7.973, 1.515], - [17.269, 9.379, 3.467], - [16.827, 10.885, 5.388], - [16.973, 4.104, 9.715], - [15.649, 5.605, 9.905], - [14.895, 3.249, 6.795], - [16.504, 2.685, 7.827], - [17.485, 7.104, 0.69], - [18.578, 8.447, 1.386], - [18.005, 9.905, 3.249], - [17.696, 11.71, 5.085], - [16.353, 11.014, 6.178], - [17.788, 4.427, 10.885], - [17.269, 3.021, 8.933], - [16.827, 1.515, 7.012], - [17.893, 12.861, 5.952], - [17.485, 5.296, 11.71], - [18.578, 3.953, 11.014], - [18.005, 2.495, 9.151], - [17.696, 0.69, 7.315], - [16.353, 1.386, 6.222], - [17.623, 14.121, 5.144], - [17.276, 12.814, 6.711], - [19.307, 12.861, 6.448], - [18.352, 5.493, 12.861], - [17.896, 15.361, 5.984], - [16.698, 14.126, 4.848], - [18.191, 14.131, 4.357], - [19.504, 11.71, 7.315], - [19.577, 14.121, 7.256], - [19.924, 12.814, 5.689], - [17.544, 5.223, 14.121], - [19.111, 4.876, 12.814], - [18.848, 6.907, 12.861], - [17.71, 16.16, 5.466], - [17.315, 15.366, 6.763], - [19.304, 15.361, 6.416], - [20.373, 10.885, 7.012], - [20.502, 14.126, 7.552], - [19.009, 14.131, 8.043], - [18.384, 5.496, 15.361], - [17.248, 4.298, 14.126], - [16.757, 5.791, 14.131], - [19.715, 7.104, 11.71], - [19.656, 7.177, 14.121], - [18.089, 7.524, 12.814], - [19.49, 16.16, 6.934], - [19.885, 15.366, 5.637], - [20.696, 9.715, 7.827], - [20.847, 11.014, 6.222], - [17.866, 5.31, 16.16], - [19.163, 4.915, 15.366], - [18.816, 6.904, 15.361], - [19.412, 7.973, 10.885], - [19.952, 8.102, 14.126], - [20.443, 6.609, 14.131], - [21.779, 8.933, 7.531], - [19.931, 9.379, 8.933], - [19.334, 7.09, 16.16], - [18.037, 7.485, 15.366], - [20.227, 8.296, 9.715], - [18.622, 8.447, 11.014], - [22.115, 7.827, 8.296], - [22.305, 9.151, 6.795], - [19.195, 9.905, 9.151], - [21.333, 7.531, 9.379], - [23.285, 7.012, 7.973], - [21.551, 6.795, 9.905], - [24.11, 7.315, 7.104], - [23.414, 6.222, 8.447], - ] - ), - "elements": np.array( - [ - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "H", - "H", - "C", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "N", - "H", - "H", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "H", - "N", - "H", - ] - ), -} - -mol_system_r = { - "coordinates": np.array( - [ - [9.439, 6.416, 5.496], - [10.679, 7.256, 5.223], - [8.64, 6.934, 5.31], - [9.434, 5.637, 4.915], - [9.439, 5.984, 6.904], - [11.939, 6.448, 5.493], - [10.674, 7.552, 4.298], - [10.669, 8.043, 5.791], - [10.679, 5.144, 7.177], - [8.64, 5.466, 7.09], - [9.434, 6.763, 7.485], - [13.09, 7.315, 5.296], - [11.986, 5.689, 4.876], - [11.939, 5.952, 6.907], - [10.674, 4.848, 8.102], - [10.669, 4.357, 6.609], - [13.915, 7.012, 4.427], - [13.09, 5.085, 7.104], - [11.986, 6.711, 7.524], - [15.085, 7.827, 4.104], - [13.786, 6.222, 3.953], - [13.915, 5.388, 7.973], - [15.867, 7.531, 3.021], - [15.421, 8.933, 4.869], - [15.085, 4.573, 8.296], - [13.786, 6.178, 8.447], - [16.973, 8.296, 2.685], - [15.649, 6.795, 2.495], - [14.895, 9.151, 5.605], - [16.504, 9.715, 4.573], - [15.867, 4.869, 9.379], - [15.421, 3.467, 7.531], - [17.788, 7.973, 1.515], - [17.269, 9.379, 3.467], - [16.827, 10.885, 5.388], - [16.973, 4.104, 9.715], - [15.649, 5.605, 9.905], - [14.895, 3.249, 6.795], - [16.504, 2.685, 7.827], - [17.485, 7.104, 0.69], - [18.578, 8.447, 1.386], - [18.005, 9.905, 3.249], - [17.696, 11.71, 5.085], - [16.353, 11.014, 6.178], - [17.788, 4.427, 10.885], - [17.269, 3.021, 8.933], - [16.827, 1.515, 7.012], - [18.352, 6.907, -0.461], - [17.893, 12.861, 5.952], - [17.485, 5.296, 11.71], - [18.578, 3.953, 11.014], - [18.005, 2.495, 9.151], - [17.696, 0.69, 7.315], - [16.353, 1.386, 6.222], - [18.848, 5.493, -0.461], - [17.544, 7.177, -1.721], - [19.111, 7.524, -0.414], - [17.623, 14.121, 5.144], - [17.276, 12.814, 6.711], - [19.307, 12.861, 6.448], - [18.352, 5.493, 12.861], - [17.893, -0.461, 6.448], - [19.715, 5.296, 0.69], - [19.656, 5.223, -1.721], - [18.089, 4.876, -0.414], - [18.384, 6.904, -2.961], - [17.248, 8.102, -1.726], - [16.757, 6.609, -1.731], - [17.896, 15.361, 5.984], - [16.698, 14.126, 4.848], - [18.191, 14.131, 4.357], - [19.504, 11.71, 7.315], - [19.577, 14.121, 7.256], - [19.924, 12.814, 5.689], - [17.544, 5.223, 14.121], - [19.111, 4.876, 12.814], - [18.848, 6.907, 12.861], - [17.623, -1.721, 7.256], - [17.276, -0.414, 5.689], - [19.307, -0.461, 5.952], - [19.412, 4.427, 1.515], - [18.816, 5.496, -2.961], - [19.952, 4.298, -1.726], - [20.443, 5.791, -1.731], - [17.866, 7.09, -3.76], - [19.163, 7.485, -2.966], - [17.71, 16.16, 5.466], - [17.315, 15.366, 6.763], - [19.304, 15.361, 6.416], - [20.373, 10.885, 7.012], - [20.502, 14.126, 7.552], - [19.009, 14.131, 8.043], - [18.384, 5.496, 15.361], - [17.248, 4.298, 14.126], - [16.757, 5.791, 14.131], - [19.715, 7.104, 11.71], - [19.656, 7.177, 14.121], - [18.089, 7.524, 12.814], - [17.896, -2.961, 6.416], - [16.698, -1.726, 7.552], - [18.191, -1.731, 8.043], - [19.504, 0.69, 5.085], - [19.577, -1.721, 5.144], - [19.924, -0.414, 6.711], - [20.227, 4.104, 2.685], - [18.622, 3.953, 1.386], - [19.334, 5.31, -3.76], - [18.037, 4.915, -2.966], - [19.49, 16.16, 6.934], - [19.885, 15.366, 5.637], - [20.696, 9.715, 7.827], - [20.847, 11.014, 6.222], - [17.866, 5.31, 16.16], - [19.163, 4.915, 15.366], - [18.816, 6.904, 15.361], - [19.412, 7.973, 10.885], - [19.952, 8.102, 14.126], - [20.443, 6.609, 14.131], - [17.71, -3.76, 6.934], - [17.315, -2.966, 5.637], - [19.304, -2.961, 5.984], - [20.373, 1.515, 5.388], - [20.502, -1.726, 4.848], - [19.009, -1.731, 4.357], - [21.333, 4.869, 3.021], - [19.931, 3.021, 3.467], - [21.779, 8.933, 7.531], - [19.931, 9.379, 8.933], - [19.334, 7.09, 16.16], - [18.037, 7.485, 15.366], - [20.227, 8.296, 9.715], - [18.622, 8.447, 11.014], - [19.49, -3.76, 5.466], - [19.885, -2.966, 6.763], - [20.696, 2.685, 4.573], - [20.847, 1.386, 6.178], - [21.551, 5.605, 2.495], - [22.115, 4.573, 4.104], - [19.195, 2.495, 3.249], - [22.115, 7.827, 8.296], - [22.305, 9.151, 6.795], - [19.195, 9.905, 9.151], - [21.333, 7.531, 9.379], - [21.779, 3.467, 4.869], - [23.285, 5.388, 4.427], - [23.285, 7.012, 7.973], - [21.551, 6.795, 9.905], - [22.305, 3.249, 5.605], - [24.11, 5.085, 5.296], - [23.414, 6.178, 3.953], - [24.11, 7.315, 7.104], - [23.414, 6.222, 8.447], - [25.261, 5.952, 5.493], - [25.261, 6.448, 6.907], - [26.521, 5.144, 5.223], - [25.214, 6.711, 4.876], - [26.521, 7.256, 7.177], - [25.214, 5.689, 7.524], - [27.761, 5.984, 5.496], - [26.526, 4.848, 4.298], - [26.531, 4.357, 5.791], - [27.761, 6.416, 6.904], - [26.526, 7.552, 8.102], - [26.531, 8.043, 6.609], - [28.56, 5.466, 5.31], - [27.766, 6.763, 4.915], - [28.56, 6.934, 7.09], - [27.766, 5.637, 7.485], - ] - ), - "elements": np.array( - [ - "C", - "C", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "H", - "C", - "H", - "H", - "C", - "N", - "H", - "C", - "H", - "C", - "C", - "C", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "C", - "C", - "C", - "N", - "H", - "H", - "N", - "H", - "C", - "C", - "H", - "C", - "H", - "C", - "C", - "C", - "N", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "C", - "C", - "H", - "C", - "C", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "N", - "C", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "H", - "H", - "C", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "C", - "H", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "C", - "C", - "C", - "H", - "H", - "N", - "H", - "N", - "H", - "C", - "C", - "C", - "H", - "C", - "H", - "C", - "H", - "H", - "C", - "H", - "H", - "H", - "H", - "H", - "H", - ] - ), -} - def test_loadmolsys() -> None: - molsys = pw.MolecularSystem.load_system(system, "test") - assert molsys.system_id == "test" + input_path = data_directory / "system.pdb" + if not input_path.exists(): + msg = f"{input_path} does not exist" + raise FileNotFoundError(msg) + molsys = pw.MolecularSystem.load_file(input_path) + assert molsys.system_id == "system" np.testing.assert_equal(molsys.system["elements"], system["elements"]) np.testing.assert_equal( @@ -9030,8 +4430,12 @@ def test_loadmolsys() -> None: def test_periodic_loadmolsys() -> None: - molsys = pw.MolecularSystem.load_system(system_periodic, "periodic") - assert molsys.system_id == "periodic" + input_path = data_directory / "system_periodic.pdb" + if not input_path.exists(): + msg = f"{input_path} does not exist" + raise FileNotFoundError(msg) + molsys = pw.MolecularSystem.load_file(input_path) + assert molsys.system_id == "system_periodic" np.testing.assert_equal( molsys.system["remarks"], @@ -9061,21 +4465,41 @@ def test_periodic_loadmolsys() -> None: def test_periodic_rebuild() -> None: - molsys = pw.MolecularSystem.load_system(system_periodic, "periodic") + input_path = data_directory / "system_periodic.pdb" + if not input_path.exists(): + msg = f"{input_path} does not exist" + raise FileNotFoundError(msg) + molsys = pw.MolecularSystem.load_file(input_path) + + output_path = data_directory / "system_periodic_rebuild.pdb" + tmp_path = data_directory / "temp_system_periodic_rebuild.pdb" + if not output_path.exists(): + msg = f"{output_path} does not exist" + raise FileNotFoundError(msg) + output_molsys = pw.MolecularSystem.load_file(output_path) + molsys_rebuild = molsys.rebuild_system() + # For visualisation. + molsys_rebuild.dump_system(tmp_path) + molsys_rebuild.make_modular() + assert len(molsys_rebuild.molecules.items()) == 8 # noqa: PLR2004 + for mol in molsys_rebuild.molecules.values(): + # Check num atoms. + assert mol.no_of_atoms == 168 # noqa: PLR2004 np.testing.assert_equal( molsys_rebuild.system["atom_ids"], - system_periodic_rebuild["atom_ids"], + output_molsys.system["atom_ids"], ) np.testing.assert_equal( molsys_rebuild.system["elements"], - system_periodic_rebuild["elements"], + output_molsys.system["elements"], ) np.testing.assert_almost_equal( molsys_rebuild.system["coordinates"], - system_periodic_rebuild["coordinates"], + output_molsys.system["coordinates"], ) + tmp_path.unlink() def test_periodic_makemodular() -> None: @@ -9088,10 +4512,19 @@ def test_periodic_makemodular() -> None: mol = molsys.molecules[0] + output_path = data_directory / "mol_system.pdb" + if not output_path.exists(): + msg = f"{output_path} does not exist" + raise FileNotFoundError(msg) + output_mol = pw.MolecularSystem.load_file(output_path).system_to_molecule() + tmp_path = data_directory / "temp_mol_system.pdb" + mol.dump_molecule(tmp_path) + assert mol assert isinstance(mol, pw.Molecule) - np.testing.assert_equal(mol.elements, mol_system["elements"]) - np.testing.assert_almost_equal(mol.coordinates, mol_system["coordinates"]) + np.testing.assert_equal(mol.elements, output_mol.elements) + np.testing.assert_almost_equal(mol.coordinates, output_mol.coordinates) + tmp_path.unlink() def test_periodic_makemodular_rebuild() -> None: @@ -9104,12 +4537,16 @@ def test_periodic_makemodular_rebuild() -> None: mol = molsys.molecules[0] + output_path = data_directory / "mol_system_rebuild.pdb" + if not output_path.exists(): + msg = f"{output_path} does not exist" + raise FileNotFoundError(msg) + output_mol = pw.MolecularSystem.load_file(output_path).system_to_molecule() + assert mol assert isinstance(mol, pw.Molecule) - np.testing.assert_equal(mol.elements, mol_system_r["elements"]) - np.testing.assert_almost_equal( - mol.coordinates, mol_system_r["coordinates"] - ) + np.testing.assert_equal(mol.elements, output_mol.elements) + np.testing.assert_almost_equal(mol.coordinates, output_mol.coordinates) for molecule in molsys.molecules.values(): assert len(molecule.coordinates) == 168 # noqa: PLR2004