diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index dc03b36..fbe3047 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -16,13 +16,14 @@ env: CIBW_TEST_COMMAND: >- python -c "import importlib.util, XpongeCPP, Xponge, XpongeCPP.io_bundle, XpongeCPP.metal_assignment; - assert XpongeCPP.__version__ == '0.2.0'; + assert XpongeCPP.__version__ == '0.2.6'; assert not hasattr(XpongeCPP, 'MC' + 'PB'); assert importlib.util.find_spec('XpongeCPP.' + ('MC' + 'PB').lower()) is None" CIBW_BEFORE_ALL_LINUX: >- if command -v dnf >/dev/null 2>&1; then dnf install -y hdf5-devel; elif command -v yum >/dev/null 2>&1; then yum install -y hdf5-devel; else apt-get update && apt-get install -y libhdf5-dev; fi + CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel repair -w {dest_dir} {wheel}" CIBW_BEFORE_BUILD_WINDOWS: "python -m pip install delvewheel" CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -w {dest_dir} {wheel}" @@ -118,10 +119,10 @@ jobs: tests/test_bundle_protocol.py tests/test_bundle_native.py - - name: Run Xponge-origin 1.7b8 parity cohorts + - name: Run Xponge-origin compatibility parity cohorts run: >- python -m pytest -q - tests/test_release_020.py + tests/test_release_025.py tests/test_origin_resp_linear_constraints.py tests/test_origin_io_bundle.py tests/test_origin_io_bundle_reverse.py diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 9b99d77..1ee7f61 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -12,13 +12,14 @@ env: CIBW_TEST_COMMAND: >- python -c "import importlib.util, XpongeCPP, Xponge, XpongeCPP.io_bundle, XpongeCPP.metal_assignment; - assert XpongeCPP.__version__ == '0.2.0'; + assert XpongeCPP.__version__ == '0.2.6'; assert not hasattr(XpongeCPP, 'MC' + 'PB'); assert importlib.util.find_spec('XpongeCPP.' + ('MC' + 'PB').lower()) is None" CIBW_BEFORE_ALL_LINUX: >- if command -v dnf >/dev/null 2>&1; then dnf install -y hdf5-devel; elif command -v yum >/dev/null 2>&1; then yum install -y hdf5-devel; else apt-get update && apt-get install -y libhdf5-dev; fi + CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel repair -w {dest_dir} {wheel}" CIBW_BEFORE_BUILD_WINDOWS: "python -m pip install delvewheel" CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -w {dest_dir} {wheel}" diff --git a/CMakeLists.txt b/CMakeLists.txt index e0319af..58e8d86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,14 @@ endif() target_compile_options(_core PRIVATE $<$:-Wall -Wextra -Wpedantic> ) +if(UNIX AND NOT APPLE) + set_target_properties(_core PROPERTIES + BUILD_RPATH_USE_ORIGIN TRUE + INSTALL_RPATH "$ORIGIN" + INSTALL_RPATH_USE_LINK_PATH FALSE + INSTALL_REMOVE_ENVIRONMENT_RPATH TRUE + ) +endif() option(XPONGECPP_SANITIZE "Build with AddressSanitizer and UndefinedBehaviorSanitizer" OFF) if (XPONGECPP_SANITIZE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") @@ -95,3 +103,9 @@ if (XPONGECPP_SANITIZE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") endif() install(TARGETS _core DESTINATION XpongeCPP) +install( + DIRECTORY third_party/xponge_reference_forcefield/ + DESTINATION XpongeCPP/data/reference_forcefield + PATTERN "__pycache__" EXCLUDE + PATTERN "*.pyc" EXCLUDE +) diff --git a/README.md b/README.md index c1b36e5..0b3790f 100644 --- a/README.md +++ b/README.md @@ -143,10 +143,10 @@ XpongeCPP.save_sponge_input_raw(molecule, "system", "inputs") XpongeCPP.save_sponge_input_bundle(molecule, "system", "inputs") ``` -RESP supports a multi-backend strategy: +RESP automatically selects the first available backend: -- default backend: `PySCF` -- optional backend: `Psi4` +- preferred backend: `PySCF` +- fallback backend: `Psi4` - shared dispatch layer: `XpongeCPP.qm` Example: @@ -161,7 +161,8 @@ qm.run_scf(assign, backend="pyscf") qm.optimize_geometry(assign, backend="pyscf") ``` -For Windows RESP workflows, install `Psi4` separately and select it explicitly: +Windows does not install PySCF automatically. If a compatible PySCF is +available, it is selected; otherwise install Psi4 separately as the fallback: ```bash conda install -c conda-forge psi4 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9e0259a..2a45954 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,124 @@ +# XpongeCPP 0.2.6 + +Compatibility target: Xponge-origin 1.7b10. + +This parity release changes QM backend selection from an operating-system rule +to runtime capability detection. XpongeCPP now prefers an installed PySCF +backend, falls back to Psi4 when PySCF is absent, and reports a clear error +when neither backend is available. Windows packaging continues to skip PySCF; +users may supply a compatible PySCF installation or install Psi4 separately. + +Regression coverage verifies PySCF preference, Psi4 fallback, and the +no-backend error path. Windows wheel CI remains a packaging smoke test; it does +not claim native Windows PySCF support. + +# XpongeCPP 0.2.5 + +Compatibility target: Xponge-origin 1.7b9. + +This patch preserves source-atom identity when raw SPONGE export reorders +noncontiguous linked residue components. The native layer now reports the +saved atom permutation before serialization, and the compatibility layer +applies the same permutation to caller-provided source IDs. This keeps Mokda +trajectory topology and atom-order mappings aligned for proteins, ligands, +metals, solvent, and repeated solvent molecules without matching atoms by +name or coordinates. + +Focused release validation covers covalent and coordination-driven residue +reordering, source-ID mapping, and the complete native bundle regression +cohort. The complete repository suite passes with 716 tests, 10 optional +skips, and 1 expected xfail. The change adds one linear residue/atom +permutation pass before raw save and does not move force-field assignment back +to Python. + +# XpongeCPP 0.2.4 + +Compatibility target: Xponge-origin 1.7b9. + +This compatibility patch preserves residue-link bonds in public MOL2 exports, +keeps mixed standard/GAFF systems intact when invoking GAFF or GAFF2 +parameterization, and aligns the legacy MDAnalysis raw-SPONGE reader with the +format hints exposed by Xponge. These fixes cover the Mokda SPONGE-input path +without moving force-field assignment back to Python. + +Release validation includes the focused MOL2, mixed-force-field, and +MDAnalysis compatibility regressions. The complete repository suite passes +with 715 tests, 10 optional skips, and 1 expected xfail. A CPython 3.11 wheel +was built and imported from an isolated environment under the Mokda resource +gate with `OOMKillDelta=0`. + +# XpongeCPP 0.2.3 + +Compatibility target: Xponge-origin 1.7b9. + +This release completes the Mokda-used same-script compatibility surface and +adds scientific-output comparison for real systems. It preserves native +template bonds when an mmCIF residue also supplies explicit covalent bonds, +including model pseudo-bonds such as the TIP3P H-H distance constraint, while +still honoring explicit Mokda edit deletions. It also synchronizes temporary +legacy residue-link overrides with the native registry and canonicalizes CMAP +grid identities independently of force-field declaration order. The legacy +MDAnalysis raw-SPONGE reader now advertises the `SPONGE_MASS` format and +recognizes `_mass.txt`, matching the Xponge interface used by Mokda H5MD +analysis. + +Linux x86_64 release-candidate evidence: + +- XpongeCPP repository suite under the coherent managed 0.2.3 runtime after the + raw-reader compatibility fix: 717 passed, 7 optional skips, 1 expected + xfail; +- Xponge-origin 1.7b9 tests through the installed compatibility namespace: + 36/36 passed; +- Mokda auto-discovered Xponge consumer matrix: 327 passed, 14 conditional + skips, and 12 subtests under both providers; +- real 3GOU/4EWL Life Modeling under the isolated XpongeCPP 0.2.3 managed + runtime completed in 205.656 s with a 1.09 GiB peak and + `OOMKillDelta=0`; +- complete Mokda Lipid21/1BL8 tier: 8/8 files passed, with a 1.995 GiB peak + and `OOMKillDelta=0`; +- provider-neutral scientific manifests match for repaired 1EMA, 1KV2+B96, + 8RYK, 1BNA, 1GYA, and 1BL8; the existing 3GOU/4EWL four-quadrant metal + acceptance also passes under both managed providers; +- provider-neutral 1KV2 benchmark remains 42,600 atoms in both + implementations; XpongeCPP median 0.0588 s versus Xponge 12.47 s, and the + measured XpongeCPP pre/post change is +2.57%, within the 5% release + tolerance. + +# XpongeCPP 0.2.2 + +Compatibility target: Xponge-origin 1.7b9. + +This compatibility release closes the Mokda-used Xponge surface under the +same-script `import Xponge` contract. It synchronizes legacy atom-type and +residue-link state with the native registries, aligns GAFF/GAFF2, PDB/link, +Lipid17/Lipid21 and non-Amber behavior with the current reference, and ships +the non-Amber reference force-field data inside wheels. The release also adds +a fail-closed machine-readable capability manifest and validates both source +and installed-wheel execution. + +Linux x86_64 release-candidate evidence: + +- installed CPython 3.12 wheel: 701 passed, 7 optional skips, 1 expected + unsupported legacy-frcmod workflow; +- Xponge-origin 1.7b9 suite through the compatibility namespace: 36/36 passed; +- Mokda auto-discovered Xponge consumer matrix: 324 passed, 13 conditional + skips and 12 subtests; +- provider-neutral 1KV2 benchmark: 42,600 atoms from both implementations; + XpongeCPP median 0.0588 s versus Xponge 12.47 s; +- pre/post XpongeCPP micro-benchmark change: +2.57% total, within the 5% + release tolerance; no assignment hot path was moved back to Python. + +# XpongeCPP 0.2.1 + +Compatibility target: Xponge-origin 1.7b9. + +This patch release corrects GLYCAM terminal-zero residue metadata across the +native template registry, bundled Python data, and the pinned reference +force-field copy. Terminal-zero names such as `0MA`, `0aA`, `0AD`, and `0aD` +now carry no synthetic `O0`/`C0` head attachment. The release adds parity and +standalone PDB-export regression coverage for all four pyranose/furanose and +D/L representative families. + # XpongeCPP 0.2.0 Compatibility target: Xponge-origin 1.7b8. diff --git a/benchmarks/bench_same_script_1kv2.py b/benchmarks/bench_same_script_1kv2.py new file mode 100644 index 0000000..4d8e414 --- /dev/null +++ b/benchmarks/bench_same_script_1kv2.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +"""Provider-neutral 1KV2 assembly benchmark used by release parity gates.""" + +from __future__ import annotations + +import argparse +import json +import statistics +import tempfile +import time +from pathlib import Path + +import Xponge +import Xponge.forcefield.amber.ff14sb # noqa: F401 +import Xponge.forcefield.amber.tip3p # noqa: F401 + + +def _median(values): + return statistics.median(values) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("pdb", type=Path) + parser.add_argument("--repeat", type=int, default=5) + parser.add_argument("--n-solvent", type=int, default=0) + args = parser.parse_args() + + timings = {"load_pdb": [], "solvate": [], "save_sponge_input": [], "total": []} + atom_counts = [] + water = Xponge.get_template_molecule("WAT") + for _ in range(args.repeat): + total_start = time.perf_counter() + start = time.perf_counter() + molecule = Xponge.load_pdb(str(args.pdb)) + timings["load_pdb"].append(time.perf_counter() - start) + + start = time.perf_counter() + solvent_options = {"tolerance": 2.5} + if args.n_solvent > 0: + solvent_options["n_solvent"] = args.n_solvent + Xponge.Add_Solvent_Box(molecule, water, 8.0, **solvent_options) + timings["solvate"].append(time.perf_counter() - start) + + with tempfile.TemporaryDirectory(prefix="xponge-parity-bench-") as output: + start = time.perf_counter() + Xponge.Save_SPONGE_Input(molecule, prefix="input", dirname=output) + timings["save_sponge_input"].append(time.perf_counter() - start) + timings["total"].append(time.perf_counter() - total_start) + atom_counts.append(len(molecule.atoms)) + + if len(set(atom_counts)) != 1: + raise RuntimeError(f"non-deterministic atom counts: {atom_counts}") + print(json.dumps({ + "implementation": str(getattr(Xponge, "__mokda_backend__", "xponge") or "xponge"), + "version": str(getattr(Xponge, "__version__", "")), + "atom_count": atom_counts[0], + "repeat": args.repeat, + "median_seconds": {key: _median(values) for key, values in timings.items()}, + }, sort_keys=True)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/cpp/assign/resp.cpp b/cpp/assign/resp.cpp index 0326f0d..4ddb9bb 100644 --- a/cpp/assign/resp.cpp +++ b/cpp/assign/resp.cpp @@ -26,15 +26,16 @@ std::vector> fibonacci_grid(int npoints, const std::array< return out; } out.reserve(static_cast(npoints)); - const double golden_angle = kPi * (3.0 - std::sqrt(5.0)); + const double golden_angle = kPi * (std::sqrt(5.0) - 1.0); for (int i = 0; i < npoints; ++i) { - const double y = 1.0 - (2.0 * i + 1.0) / static_cast(npoints); - const double r = std::sqrt(std::max(1.0 - y * y, 0.0)); - const double theta = golden_angle * static_cast(i); + const double index = static_cast(i + 1); + const double z = (2.0 * index - 1.0) / static_cast(npoints) - 1.0; + const double planar_radius = std::sqrt(std::max(1.0 - z * z, 0.0)); + const double theta = golden_angle * index; out.push_back({ - center[0] + radius * std::cos(theta) * r, - center[1] + radius * y, - center[2] + radius * std::sin(theta) * r, + center[0] + radius * planar_radius * std::cos(theta), + center[1] + radius * planar_radius * std::sin(theta), + center[2] + radius * z, }); } return out; diff --git a/cpp/core.hpp b/cpp/core.hpp index 327dce8..9e8338d 100644 --- a/cpp/core.hpp +++ b/cpp/core.hpp @@ -579,6 +579,7 @@ void add_solvent_box(Molecule& molecule, const Molecule& solvent, const std::arr double tolerance, std::int64_t n_solvent, std::uint64_t seed = 0); void add_ions(Molecule& molecule, const std::unordered_map& counts, std::uint64_t seed = 0, const std::string& solvent_residue = "WAT"); +std::vector prepare_sponge_atom_order(Molecule& molecule); std::unordered_map save_sponge_input(Molecule& molecule, const std::string& prefix, const std::filesystem::path& dirname); @@ -662,6 +663,9 @@ Molecule merge_force_field(const Molecule& molecule_a, const Molecule& molecule_ const std::unordered_map& specific_lambda); void register_residue_templates_from_mol2_text(const std::string& text); void register_residue_templates_from_mol2_file(const std::filesystem::path& filename); +void register_new_residue_templates_from_mol2_text(const std::string& text); +void register_new_residue_templates_from_mol2_file(const std::filesystem::path& filename); +void register_residue_type_template(const ResidueType& residue_type); void register_template_molecule_from_mol2_file(const std::filesystem::path& filename); void register_template_virtual_atom2(const std::string& template_name, const std::string& virtual_atom, const std::string& atom0, const std::string& atom1, const std::string& atom2, diff --git a/cpp/core/template_ops.cpp b/cpp/core/template_ops.cpp index a9c465c..f2645f0 100644 --- a/cpp/core/template_ops.cpp +++ b/cpp/core/template_ops.cpp @@ -27,6 +27,30 @@ void append_internal_structures(Molecule& target, const Molecule& source, AtomId for (const auto& link : source.residue_links) { target.residue_links.push_back({link.atom1 + atom_offset, link.atom2 + atom_offset}); } + target.coordination_bonds.reserve( + target.coordination_bonds.size() + source.coordination_bonds.size()); + for (const auto& bond : source.coordination_bonds) { + target.coordination_bonds.push_back( + {bond.atom1 + atom_offset, bond.atom2 + atom_offset}); + } + target.bond_parameter_overrides.reserve( + target.bond_parameter_overrides.size() + source.bond_parameter_overrides.size()); + for (const auto& term : source.bond_parameter_overrides) { + target.bond_parameter_overrides.push_back( + {term.atom1 + atom_offset, term.atom2 + atom_offset, + term.k, term.length, term.source}); + } + target.angle_parameter_overrides.reserve( + target.angle_parameter_overrides.size() + source.angle_parameter_overrides.size()); + for (const auto& term : source.angle_parameter_overrides) { + target.angle_parameter_overrides.push_back( + {term.atom1 + atom_offset, term.atom2 + atom_offset, + term.atom3 + atom_offset, term.k, term.theta, term.source}); + } + target.lj_parameter_overrides.insert( + target.lj_parameter_overrides.end(), + source.lj_parameter_overrides.begin(), + source.lj_parameter_overrides.end()); target.virtual_atoms.reserve(target.virtual_atoms.size() + source.virtual_atoms.size()); for (const auto& vatom : source.virtual_atoms) { target.virtual_atoms.push_back({vatom.virtual_atom + atom_offset, vatom.atom0 + atom_offset, @@ -103,6 +127,41 @@ void remap_internal_structures(const Molecule& source, Molecule& target, const s } target.residue_links.push_back({atom1, atom2}); } + target.coordination_bonds.reserve( + target.coordination_bonds.size() + source.coordination_bonds.size()); + for (const auto& bond : source.coordination_bonds) { + const AtomId atom1 = remap_atom_id(old_to_new_atom, bond.atom1); + const AtomId atom2 = remap_atom_id(old_to_new_atom, bond.atom2); + if (atom1 == invalid_atom_id || atom2 == invalid_atom_id) { + continue; + } + target.coordination_bonds.push_back({atom1, atom2}); + } + target.bond_parameter_overrides.reserve( + target.bond_parameter_overrides.size() + source.bond_parameter_overrides.size()); + for (const auto& term : source.bond_parameter_overrides) { + const AtomId atom1 = remap_atom_id(old_to_new_atom, term.atom1); + const AtomId atom2 = remap_atom_id(old_to_new_atom, term.atom2); + if (atom1 == invalid_atom_id || atom2 == invalid_atom_id) { + continue; + } + target.bond_parameter_overrides.push_back( + {atom1, atom2, term.k, term.length, term.source}); + } + target.angle_parameter_overrides.reserve( + target.angle_parameter_overrides.size() + source.angle_parameter_overrides.size()); + for (const auto& term : source.angle_parameter_overrides) { + const AtomId atom1 = remap_atom_id(old_to_new_atom, term.atom1); + const AtomId atom2 = remap_atom_id(old_to_new_atom, term.atom2); + const AtomId atom3 = remap_atom_id(old_to_new_atom, term.atom3); + if (atom1 == invalid_atom_id || atom2 == invalid_atom_id || + atom3 == invalid_atom_id) { + continue; + } + target.angle_parameter_overrides.push_back( + {atom1, atom2, atom3, term.k, term.theta, term.source}); + } + target.lj_parameter_overrides = source.lj_parameter_overrides; target.virtual_atoms.reserve(target.virtual_atoms.size() + source.virtual_atoms.size()); for (const auto& vatom : source.virtual_atoms) { const AtomId virtual_atom = remap_atom_id(old_to_new_atom, vatom.virtual_atom); @@ -205,12 +264,16 @@ void Molecule::replace_residues(const std::unordered_map& r Molecule rebuilt(name); rebuilt.box_length = box_length; + rebuilt.box_origin = box_origin; rebuilt.box_angle = box_angle; rebuilt.has_box = has_box; + rebuilt.has_box_origin = has_box_origin; rebuilt.has_gb_parameters = has_gb_parameters; rebuilt.write_min_bonded_parameters = write_min_bonded_parameters; rebuilt.write_subsys_division = write_subsys_division; rebuilt.write_lj_soft_core = write_lj_soft_core; + rebuilt.ignore_missing_atoms = ignore_missing_atoms; + rebuilt.listed_force_definitions = listed_force_definitions; rebuilt.sw_parameters = sw_parameters; rebuilt.edip_parameters = edip_parameters; @@ -298,12 +361,15 @@ void Molecule::reorder_atoms_by_template(const Molecule& template_molecule) { Molecule rebuilt(name); rebuilt.box_length = box_length; + rebuilt.box_origin = box_origin; rebuilt.box_angle = box_angle; rebuilt.has_box = has_box; + rebuilt.has_box_origin = has_box_origin; rebuilt.has_gb_parameters = has_gb_parameters; rebuilt.write_min_bonded_parameters = write_min_bonded_parameters; rebuilt.write_subsys_division = write_subsys_division; rebuilt.write_lj_soft_core = write_lj_soft_core; + rebuilt.ignore_missing_atoms = ignore_missing_atoms; std::vector old_to_new_atom(atoms.size(), invalid_atom_id); rebuilt.residues.reserve(residues.size()); diff --git a/cpp/forcefield/amber_templates.cpp b/cpp/forcefield/amber_templates.cpp index d0d6a97..5bed749 100644 --- a/cpp/forcefield/amber_templates.cpp +++ b/cpp/forcefield/amber_templates.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace xpongecpp { @@ -25,14 +26,22 @@ ResidueType residue_type_from_molecule_residue(const Molecule& molecule, const R return residue_type; } -void register_residue_templates_from_mol2_text(const std::string& text) { +namespace { + +void register_residue_templates_from_mol2_text_impl(const std::string& text, bool preserve_existing) { const auto molecule = load_mol2_text(text); std::vector> residue_types; residue_types.reserve(molecule.residues.size()); std::unordered_map residue_to_type; + std::unordered_set newly_registered_names; for (ResidueId residue_id = 0; residue_id < molecule.residues.size(); ++residue_id) { const auto& residue = molecule.residues[residue_id]; + if ((preserve_existing && has_template(residue.name)) || + newly_registered_names.find(residue.name) != newly_registered_names.end()) { + continue; + } + newly_registered_names.insert(residue.name); residue_to_type[residue_id] = residue_types.size(); residue_types.emplace_back(residue_id, ResidueType(residue.name)); auto& residue_type = residue_types.back().second; @@ -45,13 +54,36 @@ void register_residue_templates_from_mol2_text(const std::string& text) { for (const auto& bond : molecule.explicit_bonds) { const auto res1 = molecule.atoms[bond.atom1].residue; const auto res2 = molecule.atoms[bond.atom2].residue; - if (res1 != res2) { + if (res1 == res2) { + const auto type_it = residue_to_type.find(res1); + if (type_it == residue_to_type.end()) { + continue; + } + auto& residue_type = residue_types[type_it->second].second; + try { + residue_type.add_connectivity(molecule.atoms[bond.atom1].name, molecule.atoms[bond.atom2].name); + } catch (const std::exception&) { + } continue; } - auto& residue_type = residue_types[residue_to_type.at(res1)].second; - try { - residue_type.add_connectivity(molecule.atoms[bond.atom1].name, molecule.atoms[bond.atom2].name); - } catch (const std::exception&) { + if (res1 + 1 == res2) { + const auto left_it = residue_to_type.find(res1); + if (left_it != residue_to_type.end()) { + residue_types[left_it->second].second.set_tail(molecule.atoms[bond.atom1].name); + } + const auto right_it = residue_to_type.find(res2); + if (right_it != residue_to_type.end()) { + residue_types[right_it->second].second.set_head(molecule.atoms[bond.atom2].name); + } + } else if (res2 + 1 == res1) { + const auto left_it = residue_to_type.find(res2); + if (left_it != residue_to_type.end()) { + residue_types[left_it->second].second.set_tail(molecule.atoms[bond.atom2].name); + } + const auto right_it = residue_to_type.find(res1); + if (right_it != residue_to_type.end()) { + residue_types[right_it->second].second.set_head(molecule.atoms[bond.atom1].name); + } } } @@ -60,14 +92,36 @@ void register_residue_templates_from_mol2_text(const std::string& text) { } } -void register_residue_templates_from_mol2_file(const std::filesystem::path& filename) { +std::string read_mol2_template_file(const std::filesystem::path& filename) { std::ifstream input(filename); if (!input) { throw std::runtime_error("failed to open mol2 template file: " + filename.string()); } std::ostringstream buffer; buffer << input.rdbuf(); - register_residue_templates_from_mol2_text(buffer.str()); + return buffer.str(); +} + +} // namespace + +void register_residue_templates_from_mol2_text(const std::string& text) { + register_residue_templates_from_mol2_text_impl(text, false); +} + +void register_residue_templates_from_mol2_file(const std::filesystem::path& filename) { + register_residue_templates_from_mol2_text(read_mol2_template_file(filename)); +} + +void register_new_residue_templates_from_mol2_text(const std::string& text) { + register_residue_templates_from_mol2_text_impl(text, true); +} + +void register_new_residue_templates_from_mol2_file(const std::filesystem::path& filename) { + register_new_residue_templates_from_mol2_text(read_mol2_template_file(filename)); +} + +void register_residue_type_template(const ResidueType& residue_type) { + put_template(residue_type); } void register_template_molecule_from_mol2_file(const std::filesystem::path& filename) { diff --git a/cpp/io/mol2.cpp b/cpp/io/mol2.cpp index 88db4f6..c36bb83 100644 --- a/cpp/io/mol2.cpp +++ b/cpp/io/mol2.cpp @@ -28,6 +28,25 @@ std::vector split_ws(const std::string& line) { return out; } +std::vector> mol2_bond_pairs(const Molecule& molecule) { + std::vector> bonds; + bonds.reserve(molecule.explicit_bonds.size() + molecule.residue_links.size()); + const auto append = [&bonds](const ResidueLink& bond) { + const auto atom1 = std::min(bond.atom1, bond.atom2); + const auto atom2 = std::max(bond.atom1, bond.atom2); + bonds.emplace_back(atom1, atom2); + }; + for (const auto& bond : molecule.explicit_bonds) { + append(bond); + } + for (const auto& link : molecule.residue_links) { + append(link); + } + std::sort(bonds.begin(), bonds.end()); + bonds.erase(std::unique(bonds.begin(), bonds.end()), bonds.end()); + return bonds; +} + } // namespace Molecule load_mol2_text(const std::string& text) { @@ -116,9 +135,10 @@ void save_mol2(const Molecule& molecule, const std::filesystem::path& filename) if (!out) { throw std::runtime_error("failed to open MOL2 output: " + filename.string()); } + const auto bond_pairs = mol2_bond_pairs(molecule); out << "@MOLECULE\n"; out << molecule.name << "\n"; - out << std::setw(6) << molecule.atoms.size() << std::setw(6) << molecule.explicit_bonds.size() + out << std::setw(6) << molecule.atoms.size() << std::setw(6) << bond_pairs.size() << std::setw(6) << molecule.residues.size() << " 0 1\n"; out << "SMALL\nUSER_CHARGES\n"; out << "@ATOM\n"; @@ -140,9 +160,9 @@ void save_mol2(const Molecule& molecule, const std::filesystem::path& filename) << "\n"; } out << "@BOND\n"; - for (std::size_t i = 0; i < molecule.explicit_bonds.size(); ++i) { - const auto& bond = molecule.explicit_bonds[i]; - out << std::setw(6) << i + 1 << std::setw(6) << bond.atom1 + 1 << std::setw(6) << bond.atom2 + 1 + for (std::size_t i = 0; i < bond_pairs.size(); ++i) { + const auto& bond = bond_pairs[i]; + out << std::setw(6) << i + 1 << std::setw(6) << bond.first + 1 << std::setw(6) << bond.second + 1 << " 1\n"; } out << "@SUBSTRUCTURE\n"; diff --git a/cpp/io/pdb.cpp b/cpp/io/pdb.cpp index 88a5770..5e406cb 100644 --- a/cpp/io/pdb.cpp +++ b/cpp/io/pdb.cpp @@ -248,6 +248,8 @@ void apply_template_atom_properties(Molecule& molecule, bool ignore_unknown_name const ResidueType* residue_type = nullptr; if (has_template(residue.name)) { residue_type = &get_residue_template(residue.name); + residue.name = residue_type->name(); + residue.type_name = residue.name; } for (std::uint32_t local = 0; local < residue.atom_count; ++local) { auto atom = molecule.atoms[residue.atom_begin + local]; diff --git a/cpp/io/pdb_reader.cpp b/cpp/io/pdb_reader.cpp index 16c9dc6..8e4e081 100644 --- a/cpp/io/pdb_reader.cpp +++ b/cpp/io/pdb_reader.cpp @@ -903,6 +903,25 @@ Molecule load_mmcif_text(const std::string& text, const MmcifLoadOptions& option if (it == chem_comp_bonds.end()) { continue; } + // A Chemcore/self-contained mmCIF describes ordinary covalent bonds in + // _chem_comp_bond, while a registered force-field template may also + // contain model-defining pseudo-bonds (TIP3P H1-H2 is the canonical + // example). Once a residue has any explicit bond, build_topology() + // deliberately treats that explicit graph as authoritative. Seed the + // graph with the complete registered template before overlaying the + // mmCIF bonds so an otherwise complete covalent loop does not silently + // discard those force-field terms. Later _mokda_edit_operation rows + // still run last and can remove an explicitly deleted bond. + if (has_template(residue.name)) { + const auto& residue_type = get_residue_template(residue.name); + for (const auto& bond : residue_type.bonds()) { + const AtomId atom1 = find_atom( + molecule, residue, residue_type.atoms()[bond.atom1].name); + const AtomId atom2 = find_atom( + molecule, residue, residue_type.atoms()[bond.atom2].name); + mmcif_add_connection(molecule, atom1, atom2); + } + } for (const auto& [atom1_name, atom2_name] : it->second) { const AtomId atom1 = find_atom(molecule, residue, atom1_name); const AtomId atom2 = find_atom(molecule, residue, atom2_name); diff --git a/cpp/io/psf.cpp b/cpp/io/psf.cpp index 054a4ef..c891e98 100644 --- a/cpp/io/psf.cpp +++ b/cpp/io/psf.cpp @@ -129,16 +129,16 @@ void update_psf_residue_type(Molecule& molecule, Residue& residue, const std::st signatures.push_back({residue.type_name, std::move(new_signature)}); } -void append_psf_atom(Molecule& molecule, std::unordered_map& residue_by_key, +void append_psf_atom(Molecule& molecule, std::string& current_residue_key, + ResidueId& current_residue_id, const std::string& segid, const std::string& resnr, const std::string& resname, const std::string& atom_name, const std::string& atom_type, double charge, double mass, std::unordered_map>>& signatures_by_resname) { const auto key = residue_key(segid, resnr, resname); - auto it = residue_by_key.find(key); - if (it == residue_by_key.end()) { - const ResidueId residue_id = static_cast(molecule.residues.size()); - it = residue_by_key.emplace(key, residue_id).first; + if (key != current_residue_key) { + current_residue_key = key; + current_residue_id = static_cast(molecule.residues.size()); Residue residue; residue.name = resname; residue.type_name = resname; @@ -148,12 +148,12 @@ void append_psf_atom(Molecule& molecule, std::unordered_map(molecule.atoms.size()); molecule.residues.push_back(std::move(residue)); } - auto& residue = molecule.residues[it->second]; + auto& residue = molecule.residues[current_residue_id]; update_psf_residue_type(molecule, residue, atom_name, atom_type, charge, signatures_by_resname); Atom atom; atom.name = atom_name; atom.type = atom_type; - atom.residue = it->second; + atom.residue = current_residue_id; atom.charge = charge; atom.mass = mass; atom.element = atom.mass > 0.0 ? guess_element_from_mass(atom.mass) : guess_element(atom_name, ""); @@ -202,6 +202,20 @@ void split_residues_by_connectivity(Molecule& molecule) { push_whole_residue(); continue; } + bool has_internal_bond = false; + for (std::uint32_t local = 0; local < residue.atom_count && !has_internal_bond; ++local) { + const AtomId atom = residue.atom_begin + local; + for (const AtomId next : graph[atom]) { + if (molecule.atoms[next].residue == molecule.atoms[atom].residue) { + has_internal_bond = true; + break; + } + } + } + if (!has_internal_bond) { + push_whole_residue(); + continue; + } std::vector seen(residue.atom_count, false); std::vector> components; for (std::uint32_t local = 0; local < residue.atom_count; ++local) { @@ -296,24 +310,23 @@ std::unordered_map split_molecules_by_connectivity(const std::unordered_map out; std::vector> atom_maps(static_cast(component_count + 1)); - for (int comp = 1; comp <= component_count; ++comp) { - out.emplace(molecule.name + "_" + std::to_string(comp), Molecule(molecule.name + "_" + std::to_string(comp))); - } for (const auto& residue : molecule.residues) { if (residue.atom_count == 0) { continue; } const int comp = component[residue.atom_begin]; - auto& target = out.at(molecule.name + "_" + std::to_string(comp)); + const std::string component_name = molecule.name + "_" + std::to_string(comp); + auto target_it = out.find(component_name); + if (target_it == out.end()) { + target_it = out.emplace(component_name, Molecule(component_name)).first; + } + auto& target = target_it->second; Residue new_residue = residue; new_residue.atom_begin = static_cast(target.atoms.size()); new_residue.atom_count = 0; const ResidueId new_residue_id = static_cast(target.residues.size()); for (std::uint32_t local = 0; local < residue.atom_count; ++local) { const AtomId old_atom = residue.atom_begin + local; - if (component[old_atom] != comp) { - continue; - } Atom atom = molecule.atoms[old_atom]; atom.residue = new_residue_id; atom_maps[comp][old_atom] = static_cast(target.atoms.size()); @@ -342,7 +355,8 @@ PsfData load_molpsf_text(const std::string& text, const std::string& split_by) { } Molecule molecule("psf"); std::unordered_map atom_by_psf_index; - std::unordered_map residue_by_key; + std::string current_residue_key; + ResidueId current_residue_id = std::numeric_limits::max(); std::unordered_map>> signatures_by_resname; while (std::getline(input, line)) { @@ -365,7 +379,8 @@ PsfData load_molpsf_text(const std::string& text, const std::string& split_by) { if (atom_words.size() < 8) { throw std::runtime_error("bad PSF atom line"); } - append_psf_atom(molecule, residue_by_key, atom_words[1], atom_words[2], atom_words[3], + append_psf_atom(molecule, current_residue_key, current_residue_id, + atom_words[1], atom_words[2], atom_words[3], atom_words[4], atom_words[5], std::stod(atom_words[6]), std::stod(atom_words[7]), signatures_by_resname); atom_by_psf_index[std::stoi(atom_words[0])] = static_cast(molecule.atoms.size() - 1); diff --git a/cpp/io/sponge.cpp b/cpp/io/sponge.cpp index 22e7932..775cd20 100644 --- a/cpp/io/sponge.cpp +++ b/cpp/io/sponge.cpp @@ -209,17 +209,42 @@ std::vector real_lj_types(const std::vector& lj_types, return real; } -bool reorder_residues_by_linked_components(Molecule& molecule) { - if (molecule.residues.size() < 2 || molecule.residue_links.empty()) { - return false; +std::vector reorder_residues_by_linked_components(Molecule& molecule) { + std::vector new_to_old_atom_order(molecule.atoms.size()); + for (AtomId atom_id = 0; atom_id < molecule.atoms.size(); ++atom_id) { + new_to_old_atom_order[atom_id] = atom_id; + } + if (molecule.residues.size() < 2 || + (molecule.residue_links.empty() && + molecule.coordination_bonds.empty() && + molecule.explicit_bonds.empty() && + molecule.bond_parameter_overrides.empty())) { + return new_to_old_atom_order; } IndexDisjointSet components(molecule.residues.size()); + const auto unite_link = [&](AtomId atom1, AtomId atom2) { + if (atom1 >= molecule.atoms.size() || atom2 >= molecule.atoms.size()) { + throw std::invalid_argument("component link atom index out of range"); + } + components.unite( + molecule.atoms[atom1].residue, + molecule.atoms[atom2].residue + ); + }; for (const auto& link : molecule.residue_links) { - if (link.atom1 >= molecule.atoms.size() || link.atom2 >= molecule.atoms.size()) { - throw std::invalid_argument("residue link atom index out of range"); + unite_link(link.atom1, link.atom2); + } + for (const auto& link : molecule.coordination_bonds) { + unite_link(link.atom1, link.atom2); + } + for (const auto& link : molecule.explicit_bonds) { + unite_link(link.atom1, link.atom2); + } + for (const auto& parameter_override : molecule.bond_parameter_overrides) { + if (parameter_override.k != 0.0) { + unite_link(parameter_override.atom1, parameter_override.atom2); } - components.unite(molecule.atoms[link.atom1].residue, molecule.atoms[link.atom2].residue); } std::unordered_map root_to_sort_key; @@ -242,11 +267,27 @@ bool reorder_residues_by_linked_components(Molecule& molecule) { previous_key = key; } if (already_contiguous) { - return false; + return new_to_old_atom_order; } + std::vector residue_order(molecule.residues.size()); + for (ResidueId residue_id = 0; residue_id < molecule.residues.size(); ++residue_id) { + residue_order[residue_id] = residue_id; + } + std::stable_sort(residue_order.begin(), residue_order.end(), + [&](ResidueId lhs, ResidueId rhs) { + return residue_sort_keys[lhs] < residue_sort_keys[rhs]; + }); + new_to_old_atom_order.clear(); + new_to_old_atom_order.reserve(molecule.atoms.size()); + for (const ResidueId old_residue_id : residue_order) { + const auto& residue = molecule.residues[old_residue_id]; + for (std::uint32_t local = 0; local < residue.atom_count; ++local) { + new_to_old_atom_order.push_back(residue.atom_begin + local); + } + } molecule.replace_residues({}, residue_sort_keys, true); - return true; + return new_to_old_atom_order; } void check_sponge_atom_components_are_contiguous(const Molecule& molecule, const Topology& topology) { @@ -280,17 +321,24 @@ void check_sponge_atom_components_are_contiguous(const Molecule& molecule, const if (static_cast(range.max_atom - range.min_atom + 1) != range.count) { throw std::runtime_error( "Atoms in the same molecule must be continuous for SPONGE input; " - "please reorder residues or atoms before export."); + "connected component spans atom indices " + std::to_string(range.min_atom) + + ".." + std::to_string(range.max_atom) + " but contains " + + std::to_string(range.count) + + " atoms. Please reorder residues or atoms before export."); } } } } // namespace +std::vector prepare_sponge_atom_order(Molecule& molecule) { + return reorder_residues_by_linked_components(molecule); +} + std::unordered_map save_sponge_input(Molecule& input_molecule, const std::string& prefix, const std::filesystem::path& dirname) { - reorder_residues_by_linked_components(input_molecule); + prepare_sponge_atom_order(input_molecule); std::optional molecule_with_generated_cmaps; if (input_molecule.cmaps.empty() && has_amber_cmap_parameters()) { molecule_with_generated_cmaps = input_molecule; diff --git a/cpp/python/bindings_core.cpp b/cpp/python/bindings_core.cpp index a19211b..88451a4 100644 --- a/cpp/python/bindings_core.cpp +++ b/cpp/python/bindings_core.cpp @@ -29,6 +29,12 @@ void replace_residues_object(const std::shared_ptr& molecule, molecule->replace_residues(copied_replacements, residue_sort_keys, sort); } +std::vector prepare_sponge_atom_order_object( + const std::shared_ptr& molecule +) { + return prepare_sponge_atom_order(*molecule); +} + void reorder_atoms_by_template_object(const std::shared_ptr& molecule, const std::shared_ptr& template_molecule) { molecule->reorder_atoms_by_template(*template_molecule); @@ -435,6 +441,7 @@ void bind_core_module(py::module_& m) { .def("add_coordination_bond", &Molecule::add_coordination_bond, py::arg("atom1"), py::arg("atom2")) .def("add_residue_link", &Molecule::add_residue_link, py::arg("atom1"), py::arg("atom2")) .def("Add_Residue_Link", &Molecule::add_residue_link, py::arg("atom1"), py::arg("atom2")) + .def("clear_residue_links", [](Molecule& self) { self.residue_links.clear(); }) .def( "_set_bond_parameter_override", &Molecule::set_bond_parameter_override, py::arg("atom1"), py::arg("atom2"), py::arg("k"), @@ -566,6 +573,7 @@ void bind_core_module(py::module_& m) { m.def("add_molecule", &add_molecule_object, py::arg("molecule"), py::arg("other")); m.def("replace_residues", &replace_residues_object, py::arg("molecule"), py::arg("replacements"), py::arg("residue_sort_keys") = std::vector{}, py::arg("sort") = true); + m.def("prepare_sponge_atom_order", &prepare_sponge_atom_order_object, py::arg("molecule")); m.def("reorder_atoms_by_template", &reorder_atoms_by_template_object, py::arg("molecule"), py::arg("template_molecule")); m.def("set_box_padding", &set_box_padding_object, py::arg("molecule"), py::arg("padding") = 0.5, diff --git a/cpp/python/bindings_forcefield.cpp b/cpp/python/bindings_forcefield.cpp index 80b3e6c..b338778 100644 --- a/cpp/python/bindings_forcefield.cpp +++ b/cpp/python/bindings_forcefield.cpp @@ -194,6 +194,14 @@ void bind_forcefield_module(py::module_& m) { m.def("register_amber_frcmod_file", [](const std::string& filename) { register_amber_frcmod_file(filename); }); m.def("register_amber_lj_parameter", ®ister_amber_lj_parameter, py::arg("atom_type"), py::arg("lj_type"), py::arg("epsilon"), py::arg("rmin")); + m.def("_find_amber_lj_type", &find_amber_lj_type, py::arg("atom_type")); + m.def("_find_amber_lj_parameter", [](const std::string& lj_type) -> py::object { + const auto parameter = find_amber_lj_parameter(lj_type); + if (!parameter) { + return py::none(); + } + return py::make_tuple(parameter->first, parameter->second); + }, py::arg("lj_type")); m.def("register_amber_bond_parameter", ®ister_amber_bond_parameter, py::arg("atom_type1"), py::arg("atom_type2"), py::arg("k"), py::arg("length")); m.def("register_amber_angle_parameter", ®ister_amber_angle_parameter, py::arg("atom_types"), @@ -217,6 +225,12 @@ void bind_forcefield_module(py::module_& m) { py::arg("text")); m.def("register_residue_templates_from_mol2_file", [](const std::string& filename) { register_residue_templates_from_mol2_file(filename); }); + m.def("register_new_residue_templates_from_mol2_text", + ®ister_new_residue_templates_from_mol2_text, py::arg("text")); + m.def("register_new_residue_templates_from_mol2_file", + [](const std::string& filename) { register_new_residue_templates_from_mol2_file(filename); }); + m.def("register_residue_type_template", ®ister_residue_type_template, + py::arg("residue_type")); m.def("register_template_molecule_from_mol2_file", [](const std::string& filename) { register_template_molecule_from_mol2_file(filename); }); m.def("register_template_virtual_atom2", ®ister_template_virtual_atom2, py::arg("template_name"), diff --git a/docs/installation.md b/docs/installation.md index 196a418..b8753b2 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -55,15 +55,16 @@ python -c "import Xponge.forcefield.amber.ff19sb; from Xponge.forcefield.special ## RESP 后端说明 -当前 RESP 电荷计算支持多后端策略: +当前 RESP 电荷计算会自动选择第一个可用的后端: -- 默认后端:`PySCF` -- 可选后端:`Psi4` +- 优先后端:`PySCF` +- 回退后端:`Psi4` 推荐使用方式: -- Linux / macOS:默认直接使用 `PySCF` -- Windows:安装 `Psi4`,并在 RESP 调用时显式指定 `backend="psi4"` +- 所有平台:若已安装可用的 `PySCF`,则优先使用它 +- PySCF 不可用时:自动回退到 `Psi4` +- 两者都不可用时:在开始 QM 前给出明确错误 示例: @@ -72,7 +73,7 @@ assign.calculate_charge("resp", backend="pyscf") assign.calculate_charge("resp", backend="psi4") ``` -如果是在 Windows 上做 RESP,推荐安装顺序是: +Windows 不会自动安装 PySCF;如果没有自行提供兼容的 PySCF,推荐安装 Psi4: ```bash conda install -c conda-forge psi4 diff --git a/docs/installation.zh-CN.md b/docs/installation.zh-CN.md index 717864a..4ab489e 100644 --- a/docs/installation.zh-CN.md +++ b/docs/installation.zh-CN.md @@ -68,15 +68,16 @@ python -c "import Xponge.forcefield.amber.ff19sb; from Xponge.forcefield.special ## RESP 后端说明 -当前 RESP 电荷计算采用多后端策略: +当前 RESP 电荷计算会自动选择第一个可用的后端: -- 默认后端:`PySCF` -- 可选后端:`Psi4` +- 优先后端:`PySCF` +- 回退后端:`Psi4` 推荐用法: -- Linux / macOS:默认直接使用 `PySCF` -- Windows:安装 `Psi4`,并在 RESP 调用时显式指定 `backend="psi4"` +- 所有平台:若已安装可用的 `PySCF`,则优先使用它 +- PySCF 不可用时:自动回退到 `Psi4` +- 两者都不可用时:在开始 QM 前给出明确错误 示例: @@ -85,7 +86,7 @@ assign.calculate_charge("resp", backend="pyscf") assign.calculate_charge("resp", backend="psi4") ``` -如果你是在 Windows 上使用 RESP,推荐安装方式是: +Windows 不会自动安装 PySCF;如果没有自行提供兼容的 PySCF,推荐安装 Psi4: ```bash conda install -c conda-forge psi4 diff --git a/docs/xponge-vs-xpongecpp-architecture-status.md b/docs/xponge-vs-xpongecpp-architecture-status.md index 201def5..ec4b3af 100644 --- a/docs/xponge-vs-xpongecpp-architecture-status.md +++ b/docs/xponge-vs-xpongecpp-architecture-status.md @@ -110,7 +110,7 @@ XpongeCPP | `AssignRule` custom Python registry | Supported | User custom rules run in Python and do not affect built-in C++ hot paths. | | TPACM4 | Supported | C++ implementation with regression tests. | | Gasteiger | Supported with optional dependency | Uses RDKit when installed. | -| RESP | Partial | `PySCF` remains the default backend; optional `Psi4` routing, Windows-facing install hints, and Python/C++ RESP-core parity tests exist. Real-fixture regressions pass under `PySCF`, while `Psi4` coverage is currently guarded by optional-dependency tests rather than mandatory CI. Full large-case and all-parameter Xponge parity is not complete. | +| RESP | Partial | The QM scheduler prefers an available `PySCF` backend and falls back to `Psi4`; Windows packaging still does not install PySCF automatically. Python/C++ RESP-core parity tests exist. Real-fixture regressions pass under `PySCF`, while `Psi4` coverage is currently guarded by optional-dependency tests rather than mandatory CI. Full large-case and all-parameter Xponge parity is not complete. | | pH model | Partial | Common phenol/carboxyl/alcohol behavior exists, including reference-backed typing checks and protonation/deprotonation coverage in both directions for the current supported chemistry classes. Full original edge coverage is not complete. | | PubChem real network behavior | Partial | Signature and dependency behavior are present; live network regression is opt-in. | | CIF symmetry/crystal expansion | Partial | Basic cell/fractional coordinate support exists, including reference-backed fractional-coordinate cases plus richer non-orthogonal symmetry-basis coverage. Full original CIF crystallographic behavior is not complete. | diff --git a/pixi.toml b/pixi.toml index 1a8f2eb..eb1155a 100644 --- a/pixi.toml +++ b/pixi.toml @@ -28,4 +28,4 @@ pubchempy = "*" install-dev = "python -m pip install -e . --force-reinstall --no-cache-dir" test = { cmd = "pytest -q", depends-on = ["install-dev"] } test-assign-full = { cmd = "pytest tests/test_assign_charge_models.py tests/test_gaff_assign_migration.py tests/test_amber_fep_workflow.py::test_merge_dual_topology_can_derive_match_map_from_assign_when_rdkit_is_available -q", depends-on = ["install-dev"] } -test-resp = { cmd = "pytest tests/test_assign_charge_models.py::test_resp_uses_pyscf_backend_or_reports_missing_dependency -q", depends-on = ["install-dev"] } +test-resp = { cmd = "pytest tests/test_assign_charge_models.py::test_resp_uses_available_backend_or_reports_missing_dependency -q", depends-on = ["install-dev"] } diff --git a/pyproject.toml b/pyproject.toml index b818477..12a664d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,13 @@ build-backend = "scikit_build_core.build" [project] name = "XpongeCPP" -version = "0.2.0" -description = "C++ core rewrite of Xponge workflows, compatible with Xponge-origin 1.7b8" +version = "0.2.6" +description = "C++ core rewrite of Xponge workflows, compatible with Xponge-origin 1.7b10" readme = "README.md" requires-python = ">=3.10,<3.13" authors = [{ name = "The XpongeCPP contributors" }] license = { text = "Apache License 2.0" } -keywords = ["molecular-dynamics", "molecular-mechanics", "Xponge-origin-1.7b8"] +keywords = ["molecular-dynamics", "molecular-mechanics", "Xponge-origin-1.7b10"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", diff --git a/src/Xponge/__init__.py b/src/Xponge/__init__.py index 2f0d145..bd2a528 100644 --- a/src/Xponge/__init__.py +++ b/src/Xponge/__init__.py @@ -6,6 +6,10 @@ from XpongeCPP import * # noqa: F401,F403 +__version__ = _XpongeCPP.__version__ +__mokda_backend__ = "xpongecpp" +__implementation_version__ = _XpongeCPP.__version__ + _SHIM_SUBPACKAGES = { "analysis", "assign", diff --git a/src/Xponge/assign/resp.py b/src/Xponge/assign/resp.py new file mode 100644 index 0000000..3cd726b --- /dev/null +++ b/src/Xponge/assign/resp.py @@ -0,0 +1,3 @@ +"""Legacy RESP module backed by the XpongeCPP implementation.""" + +from XpongeCPP.assign.resp import * # noqa: F401,F403 diff --git a/src/Xponge/build.py b/src/Xponge/build.py index 6d01a5d..9b8fbe4 100644 --- a/src/Xponge/build.py +++ b/src/Xponge/build.py @@ -1,3 +1,4 @@ """Legacy Xponge.build shim.""" from XpongeCPP.build import * # noqa: F401,F403 +from XpongeCPP.build import _pdb_guess_element diff --git a/src/Xponge/forcefield/amber/_forcefield_family.py b/src/Xponge/forcefield/amber/_forcefield_family.py new file mode 100644 index 0000000..d4e3bfc --- /dev/null +++ b/src/Xponge/forcefield/amber/_forcefield_family.py @@ -0,0 +1,3 @@ +"""Share Amber force-field family state with XpongeCPP.""" + +from XpongeCPP.forcefield.amber._forcefield_family import * # noqa: F401,F403 diff --git a/src/Xponge/forcefield/amber/_lipid_common.py b/src/Xponge/forcefield/amber/_lipid_common.py new file mode 100644 index 0000000..76c58a3 --- /dev/null +++ b/src/Xponge/forcefield/amber/_lipid_common.py @@ -0,0 +1,3 @@ +"""Legacy lipid helpers backed by XpongeCPP.""" + +from XpongeCPP.forcefield.amber._lipid_common import * # noqa: F401,F403 diff --git a/src/Xponge/forcefield/amber/_lipid_ext.py b/src/Xponge/forcefield/amber/_lipid_ext.py new file mode 100644 index 0000000..3bc9cb5 --- /dev/null +++ b/src/Xponge/forcefield/amber/_lipid_ext.py @@ -0,0 +1,3 @@ +"""Legacy lipid extension helpers backed by XpongeCPP.""" + +from XpongeCPP.forcefield.amber._lipid_ext import * # noqa: F401,F403 diff --git a/src/Xponge/forcefield/amber/lipid17.py b/src/Xponge/forcefield/amber/lipid17.py new file mode 100644 index 0000000..d2d420d --- /dev/null +++ b/src/Xponge/forcefield/amber/lipid17.py @@ -0,0 +1,3 @@ +"""Legacy Lipid17 loader backed by XpongeCPP.""" + +from XpongeCPP.forcefield.amber.lipid17 import * # noqa: F401,F403 diff --git a/src/Xponge/forcefield/amber/lipid21.mol2 b/src/Xponge/forcefield/amber/lipid21.mol2 new file mode 100644 index 0000000..c3db9a1 --- /dev/null +++ b/src/Xponge/forcefield/amber/lipid21.mol2 @@ -0,0 +1,1330 @@ +@MOLECULE +LIPID21 + 659 647 16 0 1 +SMALL +USER_CHARGES +@ATOM + 1 C116 -3.542000 1.263000 -0.507000 cD 1 AR 0.039100 + 2 H16R -4.373000 1.525000 0.147000 hL 1 AR 0.028848 + 3 H16S -2.920000 0.574000 0.053000 hL 1 AR 0.028848 + 4 C115 -4.106000 0.611000 -1.743000 cB 1 AR -0.244149 + 5 H15R -4.793000 1.231000 -2.299000 hB 1 AR 0.132793 + 6 C114 -3.871000 -0.600000 -2.218000 cB 1 AR -0.224769 + 7 H14R -4.393000 -0.888000 -3.118000 hB 1 AR 0.129616 + 8 C113 -2.969000 -1.670000 -1.649000 cD 1 AR 0.058197 + 9 H13R -2.270000 -1.252000 -0.937000 hL 1 AR 0.061350 + 10 H13S -2.374000 -2.080000 -2.465000 hL 1 AR 0.061350 + 11 C112 -3.766000 -2.788000 -1.011000 cB 1 AR -0.220164 + 12 H12R -4.712000 -3.005000 -1.481000 hB 1 AR 0.131986 + 13 C111 -3.426000 -3.504000 0.046000 cB 1 AR -0.228704 + 14 H11R -4.122000 -4.252000 0.390000 hB 1 AR 0.131341 + 15 C110 -2.146000 -3.387000 0.847000 cD 1 AR 0.095406 + 16 H10R -1.326000 -3.099000 0.203000 hL 1 AR 0.051140 + 17 H10S -1.897000 -4.375000 1.231000 hL 1 AR 0.051140 + 18 C19 -2.272000 -2.426000 2.011000 cB 1 AR -0.228694 + 19 H9R -3.242000 -2.408000 2.482000 hB 1 AR 0.132167 + 20 C18 -1.340000 -1.630000 2.505000 cB 1 AR -0.228527 + 21 H8R -1.611000 -1.007000 3.344000 hB 1 AR 0.134735 + 22 C17 0.097000 -1.490000 2.057000 cD 1 AR 0.055784 + 23 H7R 0.316000 -2.162000 1.240000 hL 1 AR 0.062775 + 24 H7S 0.737000 -1.797000 2.884000 hL 1 AR 0.062775 + 25 C16 0.442000 -0.063000 1.702000 cB 1 AR -0.206786 + 26 H6R 0.227000 0.652000 2.481000 hB 1 AR 0.129858 + 27 C15 0.966000 0.404000 0.581000 cB 1 AR -0.267890 + 28 H5R 1.145000 1.467000 0.528000 hB 1 AR 0.143577 + 29 C14 1.363000 -0.350000 -0.663000 cD 1 AR 0.031382 + 30 H4R 0.783000 0.037000 -1.499000 hL 1 AR 0.038708 + 31 H4S 1.119000 -1.403000 -0.583000 hL 1 AR 0.038708 + 32 C13 2.852000 -0.196000 -1.008000 cD 1 AR 0.025626 + 33 H3R 3.101000 0.857000 -1.091000 hL 1 AR 0.025117 + 34 H3S 3.031000 -0.640000 -1.984000 hL 1 AR 0.025117 + 35 C12 3.775000 -0.860000 0.024000 cD 1 AR -0.123935 + 36 H2R 3.551000 -1.915000 0.111000 hL 1 AR 0.024535 + 37 H2S 3.634000 -0.397000 0.994000 hL 1 AR 0.024535 + 38 C117 -2.747000 2.535000 -0.828000 cD 1 AR -0.028398 + 39 H17R -1.894000 2.273000 -1.450000 hL 1 AR 0.019581 + 40 H17S -3.364000 3.205000 -1.425000 hL 1 AR 0.019581 + 41 C118 -2.265000 3.270000 0.423000 cD 1 AR -0.019772 + 42 H18R -3.125000 3.537000 1.037000 hL 1 AR 0.014218 + 43 H18S -1.659000 2.595000 1.024000 hL 1 AR 0.014218 + 44 C119 -1.459000 4.532000 0.111000 cD 1 AR 0.024957 + 45 H19R -0.599000 4.267000 -0.501000 hL 1 AR 0.005426 + 46 H19S -2.064000 5.207000 -0.492000 hL 1 AR 0.005426 + 47 C120 -0.981000 5.263000 1.365000 cD 1 AR -0.109302 + 48 H20R -0.412000 6.152000 1.111000 hL 1 AR 0.023723 + 49 H20S -0.345000 4.625000 1.972000 hL 1 AR 0.023723 + 50 H20T -1.821000 5.573000 1.982000 hL 1 AR 0.023723 + 51 C1 4.697000 -1.469000 -0.739000 cA 2 CHL -0.247736 + 52 H11 4.428000 -1.214000 -1.762000 hA 2 CHL 0.048772 + 53 H12 4.303000 -2.462000 -0.556000 hA 2 CHL 0.048772 + 54 C2 6.224000 -1.517000 -0.642000 cA 2 CHL -0.061498 + 55 H21 6.547000 -1.874000 0.331000 hA 2 CHL 0.048128 + 56 H22 6.617000 -2.214000 -1.376000 hA 2 CHL 0.048128 + 57 C3 6.830000 -0.145000 -0.877000 cA 2 CHL 0.400362 + 58 H31 6.590000 0.176000 -1.891000 hE 2 CHL -0.008510 + 59 C4 6.246000 0.863000 0.111000 cA 2 CHL -0.237134 + 60 H41 6.601000 0.589000 1.102000 hA 2 CHL 0.100619 + 61 H42 6.636000 1.856000 -0.095000 hA 2 CHL 0.100619 + 62 C5 4.731000 0.895000 0.070000 cB 2 CHL -0.257515 + 63 C6 4.091000 2.041000 -0.088000 cB 2 CHL -0.243730 + 64 H61 4.668000 2.946000 -0.204000 hB 2 CHL 0.148607 + 65 C7 2.599000 2.206000 -0.119000 cA 2 CHL -0.075453 + 66 H71 2.323000 3.070000 0.480000 hA 2 CHL 0.051297 + 67 H72 2.290000 2.443000 -1.137000 hA 2 CHL 0.051297 + 68 C8 1.853000 0.964000 0.375000 cA 2 CHL 0.017835 + 69 H81 1.922000 0.946000 1.460000 hA 2 CHL 0.028120 + 70 C9 2.514000 -0.306000 -0.204000 cA 2 CHL -0.029839 + 71 H91 2.518000 -0.165000 -1.285000 hA 2 CHL -0.003361 + 72 C10 4.012000 -0.452000 0.214000 cA 2 CHL 0.546470 + 73 C11 1.671000 -1.566000 0.076000 cA 2 CHL -0.127715 + 74 H111 2.085000 -2.410000 -0.467000 hA 2 CHL 0.040257 + 75 H112 1.730000 -1.829000 1.125000 hA 2 CHL 0.040257 + 76 C12 0.190000 -1.429000 -0.312000 cA 2 CHL -0.158054 + 77 H121 0.108000 -1.322000 -1.392000 hA 2 CHL 0.007687 + 78 H122 -0.312000 -2.355000 -0.056000 hA 2 CHL 0.007687 + 79 C13 -0.469000 -0.212000 0.358000 cA 2 CHL 0.583692 + 80 C14 0.381000 1.015000 -0.041000 cA 2 CHL 0.013753 + 81 H141 0.381000 1.020000 -1.132000 hA 2 CHL 0.004469 + 82 C15 -0.462000 2.215000 0.391000 cA 2 CHL -0.185047 + 83 H151 -0.304000 2.443000 1.442000 hA 2 CHL 0.041228 + 84 H152 -0.217000 3.115000 -0.163000 hA 2 CHL 0.041228 + 85 C16 -1.913000 1.751000 0.131000 cA 2 CHL -0.082919 + 86 H161 -2.537000 1.930000 1.001000 hA 2 CHL 0.027639 + 87 H162 -2.357000 2.309000 -0.684000 hA 2 CHL 0.027639 + 88 C17 -1.859000 0.228000 -0.203000 cA 2 CHL -0.051767 + 89 H171 -1.794000 0.127000 -1.286000 hA 2 CHL -0.030436 + 90 C18 -0.546000 -0.407000 1.886000 cA 2 CHL -0.536004 + 91 H181 -1.062000 0.412000 2.374000 hA 2 CHL 0.103623 + 92 H182 0.431000 -0.485000 2.344000 hA 2 CHL 0.103623 + 93 H183 -1.086000 -1.316000 2.130000 hA 2 CHL 0.103623 + 94 C19 4.156000 -0.937000 1.675000 cA 2 CHL -0.352218 + 95 H191 3.579000 -0.319000 2.354000 hA 2 CHL 0.072469 + 96 H192 5.185000 -0.898000 2.008000 hA 2 CHL 0.072469 + 97 H193 3.826000 -1.963000 1.788000 hA 2 CHL 0.072469 + 98 C20 -3.141000 -0.519000 0.237000 cD 2 CHL 0.178752 + 99 H201 -3.267000 -0.372000 1.309000 hL 2 CHL -0.016015 + 100 C21 -3.080000 -2.029000 -0.029000 cD 2 CHL -0.427968 + 101 H211 -2.330000 -2.520000 0.577000 hL 2 CHL 0.099219 + 102 H212 -2.851000 -2.232000 -1.072000 hL 2 CHL 0.099219 + 103 H213 -4.025000 -2.508000 0.198000 hL 2 CHL 0.099219 + 104 C22 -4.375000 0.093000 -0.461000 cD 2 CHL -0.050256 + 105 H221 -4.324000 1.175000 -0.403000 hL 2 CHL 0.009445 + 106 H222 -4.337000 -0.153000 -1.522000 hL 2 CHL 0.009445 + 107 C23 -5.732000 -0.335000 0.111000 cD 2 CHL 0.078665 + 108 H231 -5.862000 -1.406000 0.010000 hL 2 CHL -0.007957 + 109 H232 -5.752000 -0.121000 1.179000 hL 2 CHL -0.007957 + 110 C24 -6.898000 0.389000 -0.569000 cD 2 CHL -0.282133 + 111 H241 -6.718000 1.461000 -0.516000 hL 2 CHL 0.062972 + 112 H242 -6.910000 0.137000 -1.629000 hL 2 CHL 0.062972 + 113 C25 -8.286000 0.104000 0.028000 cD 2 CHL 0.450601 + 114 H251 -8.244000 0.333000 1.092000 hL 2 CHL -0.049128 + 115 C26 -8.705000 -1.362000 -0.122000 cD 2 CHL -0.449300 + 116 H261 -8.034000 -2.035000 0.400000 hL 2 CHL 0.099869 + 117 H262 -8.723000 -1.655000 -1.169000 hL 2 CHL 0.099869 + 118 H263 -9.702000 -1.521000 0.280000 hL 2 CHL 0.099869 + 119 C27 -9.336000 1.023000 -0.605000 cD 2 CHL -0.449300 + 120 H271 -9.079000 2.069000 -0.470000 hL 2 CHL 0.099869 + 121 H272 -10.316000 0.862000 -0.166000 hL 2 CHL 0.099869 + 122 H273 -9.420000 0.839000 -1.674000 hL 2 CHL 0.099869 + 123 O1 8.224000 -0.262000 -0.734000 oH 2 CHL -0.766581 + 124 HO1 8.633000 0.570000 -0.924000 hO 2 CHL 0.442970 + 125 C116 6.186000 0.815000 -0.603000 cB 3 DHA -0.233897 + 126 H16R 5.772000 1.811000 -0.619000 hB 3 DHA 0.133812 + 127 C115 5.152000 -0.282000 -0.706000 cD 3 DHA 0.069215 + 128 H15R 5.627000 -1.257000 -0.734000 hL 3 DHA 0.058341 + 129 H15S 4.618000 -0.174000 -1.644000 hL 3 DHA 0.058341 + 130 C114 4.194000 -0.242000 0.462000 cB 3 DHA -0.240419 + 131 H14R 4.661000 -0.419000 1.419000 hB 3 DHA 0.138337 + 132 C113 2.893000 -0.010000 0.455000 cB 3 DHA -0.218668 + 133 H13R 2.380000 -0.028000 1.404000 hB 3 DHA 0.131575 + 134 C112 1.993000 0.270000 -0.727000 cD 3 DHA 0.085245 + 135 H12R 2.572000 0.350000 -1.640000 hL 3 DHA 0.053422 + 136 H12S 1.515000 1.232000 -0.581000 hL 3 DHA 0.053422 + 137 C111 0.961000 -0.820000 -0.898000 cB 3 DHA -0.241205 + 138 H11R 1.380000 -1.795000 -1.094000 hB 3 DHA 0.136308 + 139 C110 -0.357000 -0.729000 -0.828000 cB 3 DHA -0.221433 + 140 H10R -0.925000 -1.634000 -0.972000 hB 3 DHA 0.133628 + 141 C19 -1.204000 0.493000 -0.557000 cD 3 DHA 0.089043 + 142 H9R -1.860000 0.659000 -1.404000 hL 3 DHA 0.054255 + 143 H9S -0.584000 1.379000 -0.470000 hL 3 DHA 0.054255 + 144 C18 -2.001000 0.333000 0.716000 cB 3 DHA -0.226254 + 145 H8R -1.397000 0.236000 1.605000 hB 3 DHA 0.128147 + 146 C17 -3.314000 0.284000 0.867000 cB 3 DHA -0.220895 + 147 H7R -3.695000 0.166000 1.869000 hB 3 DHA 0.139863 + 148 C16 -4.387000 0.387000 -0.193000 cD 3 DHA 0.060337 + 149 H6R -4.997000 -0.509000 -0.162000 hL 3 DHA 0.063515 + 150 H6S -3.948000 0.424000 -1.183000 hL 3 DHA 0.063515 + 151 C15 -5.236000 1.620000 0.008000 cB 3 DHA -0.214845 + 152 H5R -4.695000 2.548000 -0.092000 hB 3 DHA 0.132504 + 153 C14 -6.524000 1.695000 0.297000 cB 3 DHA -0.287059 + 154 H4R -6.951000 2.681000 0.401000 hB 3 DHA 0.154038 + 155 C13 -7.505000 0.570000 0.499000 cD 3 DHA 0.120999 + 156 H3R -7.983000 0.686000 1.467000 hL 3 DHA 0.026097 + 157 H3S -7.007000 -0.392000 0.505000 hL 3 DHA 0.026097 + 158 C12 -8.592000 0.571000 -0.593000 cD 3 DHA -0.142937 + 159 H2R -8.148000 0.420000 -1.567000 hL 3 DHA 0.037544 + 160 H2S -9.110000 1.525000 -0.592000 hL 3 DHA 0.037544 + 161 C117 7.499000 0.703000 -0.489000 cB 3 DHA -0.216499 + 162 H17R 8.069000 1.616000 -0.419000 hB 3 DHA 0.132121 + 163 C118 8.338000 -0.552000 -0.428000 cD 3 DHA 0.092718 + 164 H18R 7.719000 -1.435000 -0.548000 hL 3 DHA 0.053227 + 165 H18S 9.032000 -0.549000 -1.261000 hL 3 DHA 0.053227 + 166 C119 9.079000 -0.651000 0.885000 cB 3 DHA -0.246833 + 167 H19R 8.435000 -0.701000 1.750000 hB 3 DHA 0.136323 + 168 C120 10.384000 -0.673000 1.094000 cB 3 DHA -0.240216 + 169 H20R 10.715000 -0.743000 2.120000 hB 3 DHA 0.133048 + 170 C121 11.504000 -0.603000 0.088000 cD 3 DHA 0.122022 + 171 H21R 12.102000 -1.509000 0.169000 hL 3 DHA 0.010042 + 172 H21S 11.121000 -0.579000 -0.925000 hL 3 DHA 0.010042 + 173 C122 12.411000 0.611000 0.320000 cD 3 DHA -0.108913 + 174 H22R 13.235000 0.621000 -0.387000 hL 3 DHA 0.025968 + 175 H22S 12.834000 0.599000 1.320000 hL 3 DHA 0.025968 + 176 H22T 11.857000 1.537000 0.206000 hL 3 DHA 0.025968 + 177 H12T 72.456000 10.844000 19.346000 hL 4 LAL 0.025809 + 178 C112 71.871000 10.231000 18.815000 cD 4 LAL -0.118534 + 179 H12R 71.178000 9.870000 19.578000 hL 4 LAL 0.025809 + 180 H12S 72.578000 9.424000 18.604000 hL 4 LAL 0.025809 + 181 C111 71.063000 10.566000 17.542000 cD 4 LAL 0.023320 + 182 H11R 71.736000 10.898000 16.748000 hL 4 LAL 0.008276 + 183 H11S 70.381000 11.389000 17.765000 hL 4 LAL 0.008276 + 184 C110 70.248000 9.346000 17.062000 cD 4 LAL -0.019575 + 185 H10R 69.657000 8.960000 17.896000 hL 4 LAL 0.015163 + 186 H10S 70.930000 8.552000 16.748000 hL 4 LAL 0.015163 + 187 C19 69.295000 9.709000 15.900000 cD 4 LAL -0.021975 + 188 H9R 69.867000 10.082000 15.047000 hL 4 LAL 0.005869 + 189 H9S 68.620000 10.502000 16.225000 hL 4 LAL 0.005869 + 190 C18 68.458000 8.485000 15.479000 cD 4 LAL -0.020879 + 191 H8R 67.960000 8.078000 16.362000 hL 4 LAL 0.010385 + 192 H8S 69.123000 7.713000 15.091000 hL 4 LAL 0.010385 + 193 C17 67.396000 8.833000 14.413000 cD 4 LAL -0.019279 + 194 H7R 67.887000 9.155000 13.492000 hL 4 LAL 0.011207 + 195 H7S 66.788000 9.669000 14.765000 hL 4 LAL 0.011207 + 196 C16 66.494000 7.608000 14.129000 cD 4 LAL -0.019631 + 197 H6R 66.260000 7.108000 15.071000 hL 4 LAL 0.010236 + 198 H6S 67.042000 6.887000 13.518000 hL 4 LAL 0.010236 + 199 C15 65.152000 7.963000 13.447000 cD 4 LAL -0.015735 + 200 H5R 64.552000 8.556000 14.137000 hL 4 LAL 0.009551 + 201 H5S 64.602000 7.038000 13.264000 hL 4 LAL 0.009551 + 202 C14 65.314000 8.740000 12.120000 cD 4 LAL -0.024078 + 203 H4R 66.094000 8.276000 11.515000 hL 4 LAL 0.020580 + 204 H4S 65.638000 9.759000 12.335000 hL 4 LAL 0.020580 + 205 C13 64.012000 8.783000 11.285000 cD 4 LAL 0.001510 + 206 H3R 63.755000 7.770000 10.968000 hL 4 LAL 0.019108 + 207 H3S 64.207000 9.367000 10.384000 hL 4 LAL 0.019108 + 208 C12 62.815000 9.404000 12.036000 cD 4 LAL -0.172159 + 209 H2R 63.101000 10.354000 12.488000 hL 4 LAL 0.054419 + 210 H2S 62.489000 8.734000 12.830000 hL 4 LAL 0.054419 + 211 H14T 72.992000 10.982000 21.559000 hL 5 MY 0.025511 + 212 C114 73.387000 11.208000 20.669000 cD 5 MY -0.111712 + 213 H14R 74.081000 10.373000 20.543000 hL 5 MY 0.025511 + 214 H14S 73.988000 12.092000 20.900000 hL 5 MY 0.025511 + 215 C113 72.635000 11.469000 19.341000 cD 5 MY 0.017463 + 216 H13R 73.359000 11.785000 18.585000 hL 5 MY 0.007531 + 217 H13S 71.940000 12.299000 19.482000 hL 5 MY 0.007531 + 218 C112 71.871000 10.231000 18.815000 cD 5 MY -0.028094 + 219 H12R 71.178000 9.870000 19.578000 hL 5 MY 0.017208 + 220 H12S 72.578000 9.424000 18.604000 hL 5 MY 0.017208 + 221 C111 71.063000 10.566000 17.542000 cD 5 MY -0.031787 + 222 H11R 71.736000 10.898000 16.748000 hL 5 MY 0.012677 + 223 H11S 70.381000 11.389000 17.765000 hL 5 MY 0.012677 + 224 C110 70.248000 9.346000 17.062000 cD 5 MY -0.021025 + 225 H10R 69.657000 8.960000 17.896000 hL 5 MY 0.010037 + 226 H10S 70.930000 8.552000 16.748000 hL 5 MY 0.010037 + 227 C19 69.295000 9.709000 15.900000 cD 5 MY -0.014653 + 228 H9R 69.867000 10.082000 15.047000 hL 5 MY 0.010172 + 229 H9S 68.620000 10.502000 16.225000 hL 5 MY 0.010172 + 230 C18 68.458000 8.485000 15.479000 cD 5 MY -0.026451 + 231 H8R 67.960000 8.078000 16.362000 hL 5 MY 0.011241 + 232 H8S 69.123000 7.713000 15.091000 hL 5 MY 0.011241 + 233 C17 67.396000 8.833000 14.413000 cD 5 MY -0.004386 + 234 H7R 67.887000 9.155000 13.492000 hL 5 MY 0.006833 + 235 H7S 66.788000 9.669000 14.765000 hL 5 MY 0.006833 + 236 C16 66.494000 7.608000 14.129000 cD 5 MY -0.027812 + 237 H6R 66.260000 7.108000 15.071000 hL 5 MY 0.011511 + 238 H6S 67.042000 6.887000 13.518000 hL 5 MY 0.011511 + 239 C15 65.152000 7.963000 13.447000 cD 5 MY -0.016521 + 240 H5R 64.552000 8.556000 14.137000 hL 5 MY 0.010573 + 241 H5S 64.602000 7.038000 13.264000 hL 5 MY 0.010573 + 242 C14 65.314000 8.740000 12.120000 cD 5 MY -0.026954 + 243 H4R 66.094000 8.276000 11.515000 hL 5 MY 0.020431 + 244 H4S 65.638000 9.759000 12.335000 hL 5 MY 0.020431 + 245 C13 64.012000 8.783000 11.285000 cD 5 MY -0.002435 + 246 H3R 63.755000 7.770000 10.968000 hL 5 MY 0.018859 + 247 H3S 64.207000 9.367000 10.384000 hL 5 MY 0.018859 + 248 C12 62.815000 9.404000 12.036000 cD 5 MY -0.164200 + 249 H2R 63.101000 10.354000 12.488000 hL 5 MY 0.053944 + 250 H2S 62.489000 8.734000 12.830000 hL 5 MY 0.053944 + 251 C12 6.166000 -0.064000 0.159000 cD 6 OL -0.143418 + 252 H2R 5.945000 -0.958000 0.733000 hL 6 OL 0.042861 + 253 H2S 5.869000 0.773000 0.786000 hL 6 OL 0.042861 + 254 C13 5.422000 -0.043000 -1.175000 cD 6 OL 0.001619 + 255 H3R 5.748000 0.824000 -1.739000 hL 6 OL 0.019529 + 256 H3S 5.713000 -0.909000 -1.761000 hL 6 OL 0.019529 + 257 C14 3.897000 -0.002000 -1.029000 cD 6 OL -0.022960 + 258 H4R 3.618000 0.876000 -0.452000 hL 6 OL 0.018134 + 259 H4S 3.467000 0.136000 -2.018000 hL 6 OL 0.018134 + 260 C15 3.285000 -1.260000 -0.401000 cD 6 OL -0.016692 + 261 H5R 3.676000 -2.132000 -0.922000 hL 6 OL 0.008690 + 262 H5S 3.604000 -1.356000 0.634000 hL 6 OL 0.008690 + 263 C16 1.753000 -1.313000 -0.454000 cD 6 OL -0.023789 + 264 H6R 1.427000 -1.233000 -1.489000 hL 6 OL 0.009266 + 265 H6S 1.431000 -2.294000 -0.110000 hL 6 OL 0.009266 + 266 C17 1.047000 -0.244000 0.385000 cD 6 OL -0.017495 + 267 H7R 1.408000 -0.296000 1.411000 hL 6 OL 0.019598 + 268 H7S 1.297000 0.749000 0.022000 hL 6 OL 0.019598 + 269 C18 -0.480000 -0.400000 0.376000 cD 6 OL 0.031775 + 270 H8R -0.842000 -0.344000 -0.644000 hL 6 OL 0.032685 + 271 H8S -0.733000 -1.396000 0.737000 hL 6 OL 0.032685 + 272 C19 -1.164000 0.618000 1.252000 cB 6 OL -0.244228 + 273 H9R -0.917000 0.539000 2.300000 hB 6 OL 0.131512 + 274 C110 -2.000000 1.581000 0.901000 cB 6 OL -0.239284 + 275 H10R -2.380000 2.214000 1.690000 hB 6 OL 0.126878 + 276 C111 -2.510000 1.937000 -0.472000 cD 6 OL 0.029059 + 277 H11R -2.194000 2.954000 -0.698000 hL 6 OL 0.033531 + 278 H11S -2.066000 1.305000 -1.233000 hL 6 OL 0.033531 + 279 C112 -4.042000 1.873000 -0.585000 cD 6 OL -0.026353 + 280 H12R -4.484000 2.503000 0.186000 hL 6 OL 0.019717 + 281 H12S -4.337000 2.308000 -1.538000 hL 6 OL 0.019717 + 282 C113 -4.615000 0.459000 -0.479000 cD 6 OL -0.018257 + 283 H13R -4.172000 -0.164000 -1.256000 hL 6 OL 0.013800 + 284 H13S -4.321000 0.017000 0.469000 hL 6 OL 0.013800 + 285 C114 -6.139000 0.419000 -0.609000 cD 6 OL -0.024849 + 286 H14R -6.575000 1.054000 0.159000 hL 6 OL 0.008572 + 287 H14S -6.433000 0.851000 -1.564000 hL 6 OL 0.008572 + 288 C115 -6.708000 -0.999000 -0.500000 cD 6 OL -0.023247 + 289 H15R -6.207000 -1.632000 -1.230000 hL 6 OL 0.010403 + 290 H15S -6.458000 -1.413000 0.473000 hL 6 OL 0.010403 + 291 C116 -8.220000 -1.104000 -0.743000 cD 6 OL -0.012488 + 292 H16R -8.435000 -0.751000 -1.750000 hL 6 OL 0.013659 + 293 H16S -8.499000 -2.156000 -0.726000 hL 6 OL 0.013659 + 294 C117 -9.120000 -0.346000 0.242000 cD 6 OL 0.008684 + 295 H17R -8.919000 0.721000 0.187000 hL 6 OL 0.010026 + 296 H17S -10.151000 -0.470000 -0.082000 hL 6 OL 0.010026 + 297 C118 -9.002000 -0.812000 1.694000 cD 6 OL -0.117290 + 298 H18R -9.724000 -0.300000 2.323000 hL 6 OL 0.026627 + 299 H18S -8.017000 -0.616000 2.104000 hL 6 OL 0.026627 + 300 H18T -9.188000 -1.879000 1.778000 hL 6 OL 0.026627 + 301 C116 -10.262000 -0.302000 -0.549000 cD 7 PA -0.125447 + 302 H16R -10.644000 -0.891000 -1.377000 hL 7 PA 0.029047 + 303 H16S -10.859000 0.603000 -0.483000 hL 7 PA 0.029047 + 304 H16T -10.424000 -0.870000 0.363000 hL 7 PA 0.029047 + 305 C115 -8.781000 0.025000 -0.737000 cD 7 PA 0.013975 + 306 H15R -8.648000 0.570000 -1.670000 hL 7 PA 0.009292 + 307 H15S -8.224000 -0.902000 -0.843000 hL 7 PA 0.009292 + 308 C114 -8.209000 0.854000 0.416000 cD 7 PA -0.020086 + 309 H14R -8.302000 0.290000 1.344000 hL 7 PA 0.015929 + 310 H14S -8.824000 1.743000 0.541000 hL 7 PA 0.015929 + 311 C113 -6.751000 1.293000 0.235000 cD 7 PA -0.033096 + 312 H13R -6.500000 1.986000 1.035000 hL 7 PA 0.014621 + 313 H13S -6.660000 1.857000 -0.692000 hL 7 PA 0.014621 + 314 C112 -5.730000 0.153000 0.237000 cD 7 PA -0.027633 + 315 H12R -5.920000 -0.519000 -0.596000 hL 7 PA 0.011368 + 316 H12S -5.856000 -0.439000 1.142000 hL 7 PA 0.011368 + 317 C111 -4.284000 0.648000 0.155000 cD 7 PA -0.025206 + 318 H11R -4.084000 1.312000 0.994000 hL 7 PA 0.014334 + 319 H11S -4.160000 1.248000 -0.744000 hL 7 PA 0.014334 + 320 C110 -3.256000 -0.485000 0.151000 cD 7 PA -0.028831 + 321 H10R -3.455000 -1.148000 -0.689000 hL 7 PA 0.014691 + 322 H10S -3.381000 -1.087000 1.050000 hL 7 PA 0.014691 + 323 C19 -1.811000 0.010000 0.072000 cD 7 PA -0.030472 + 324 H9R -1.612000 0.673000 0.913000 hL 7 PA 0.013897 + 325 H9S -1.685000 0.612000 -0.826000 hL 7 PA 0.013897 + 326 C18 -0.782000 -1.123000 0.068000 cD 7 PA -0.015793 + 327 H8R -0.983000 -1.787000 -0.770000 hL 7 PA 0.009067 + 328 H8S -0.906000 -1.724000 0.968000 hL 7 PA 0.009067 + 329 C17 0.663000 -0.628000 -0.013000 cD 7 PA -0.019630 + 330 H7R 0.854000 0.045000 0.820000 hL 7 PA 0.011041 + 331 H7S 0.790000 -0.036000 -0.919000 hL 7 PA 0.011041 + 332 C16 1.685000 -1.769000 -0.010000 cD 7 PA -0.024427 + 333 H6R 1.433000 -2.463000 -0.809000 hL 7 PA 0.013334 + 334 H6S 1.595000 -2.331000 0.918000 hL 7 PA 0.013334 + 335 C15 3.142000 -1.328000 -0.195000 cD 7 PA -0.029387 + 336 H5R 3.227000 -0.783000 -1.132000 hL 7 PA 0.016763 + 337 H5S 3.759000 -2.218000 -0.304000 hL 7 PA 0.016763 + 338 C14 3.698000 -0.485000 0.958000 cD 7 PA -0.030099 + 339 H4R 3.490000 -0.997000 1.896000 hL 7 PA 0.020877 + 340 H4S 3.179000 0.468000 1.010000 hL 7 PA 0.020877 + 341 C13 5.207000 -0.229000 0.884000 cD 7 PA -0.004882 + 342 H3R 5.739000 -1.174000 0.848000 hL 7 PA 0.019007 + 343 H3S 5.519000 0.273000 1.796000 hL 7 PA 0.019007 + 344 C12 5.627000 0.634000 -0.318000 cD 7 PA -0.149259 + 345 H2R 5.083000 1.570000 -0.321000 hL 7 PA 0.047345 + 346 H2S 5.426000 0.112000 -1.246000 hL 7 PA 0.047345 + 347 C11 4.694000 -2.109000 0.405000 cC 8 PC 0.910403 + 348 O12 4.576000 -2.896000 -0.477000 oC 8 PC -0.671566 + 349 O11 3.902000 -1.060000 0.566000 oS 8 PC -0.575489 + 350 C1 2.854000 -0.874000 -0.377000 cA 8 PC 0.196939 + 351 HR 2.157000 -1.696000 -0.314000 hE 8 PC 0.070469 + 352 HS 3.266000 -0.836000 -1.375000 hE 8 PC 0.070469 + 353 C2 2.165000 0.425000 -0.026000 cA 8 PC 0.281242 + 354 HX 1.911000 0.438000 1.021000 hE 8 PC 0.063253 + 355 C3 0.919000 0.667000 -0.863000 cA 8 PC 0.017459 + 356 HA 1.151000 0.638000 -1.919000 hE 8 PC 0.095591 + 357 HB 0.516000 1.643000 -0.623000 hE 8 PC 0.095591 + 358 O31 -0.006000 -0.339000 -0.535000 oT 8 PC -0.509480 + 359 P31 -1.430000 -0.403000 -1.277000 pA 8 PC 1.339721 + 360 O32 -2.179000 0.795000 -0.393000 oT 8 PC -0.508176 + 361 C31 -3.461000 1.133000 -0.789000 cA 8 PC 0.166801 + 362 H1A -3.812000 0.531000 -1.617000 hE 8 PC 0.078534 + 363 H1B -3.484000 2.165000 -1.127000 hE 8 PC 0.078534 + 364 C32 -4.434000 1.074000 0.381000 cA 8 PC -0.170824 + 365 H2A -5.396000 1.448000 0.054000 hX 8 PC 0.136415 + 366 H2B -4.072000 1.701000 1.183000 hX 8 PC 0.136415 + 367 N31 -4.708000 -0.280000 1.003000 nA 8 PC 0.245262 + 368 C33 -5.092000 -1.293000 -0.033000 cA 8 PC -0.338973 + 369 H3A -5.889000 -0.883000 -0.638000 hX 8 PC 0.172230 + 370 H3B -5.442000 -2.177000 0.479000 hX 8 PC 0.172230 + 371 H3C -4.222000 -1.537000 -0.624000 hX 8 PC 0.172230 + 372 C34 -3.521000 -0.799000 1.770000 cA 8 PC -0.338973 + 373 H4A -3.178000 -0.023000 2.437000 hX 8 PC 0.172230 + 374 H4B -2.753000 -1.088000 1.075000 hX 8 PC 0.172230 + 375 H4C -3.853000 -1.656000 2.338000 hX 8 PC 0.172230 + 376 C35 -5.839000 -0.102000 1.952000 cA 8 PC -0.338973 + 377 H5A -5.570000 0.638000 2.691000 hX 8 PC 0.172230 + 378 H5B -6.044000 -1.043000 2.440000 hX 8 PC 0.172230 + 379 H5C -6.716000 0.223000 1.411000 hX 8 PC 0.172230 + 380 O33 -2.106000 -1.653000 -0.869000 oP 8 PC -0.875812 + 381 O34 -1.344000 0.050000 -2.666000 oP 8 PC -0.875812 + 382 O21 3.096000 1.472000 -0.298000 oS 8 PC -0.552948 + 383 C21 3.110000 2.550000 0.475000 cC 8 PC 0.897613 + 384 O22 2.361000 2.734000 1.379000 oC 8 PC -0.673755 + 385 C11 2.180000 2.916000 -0.064000 cC 9 PE 0.888359 + 386 O12 1.200000 3.445000 0.353000 oC 9 PE -0.650802 + 387 O11 2.300000 1.607000 -0.216000 oS 9 PE -0.593826 + 388 C1 1.186000 0.802000 0.148000 cA 9 PE 0.273776 + 389 HR 0.303000 1.147000 -0.363000 hE 9 PE 0.044574 + 390 HS 1.024000 0.875000 1.214000 hE 9 PE 0.044574 + 391 C2 1.505000 -0.620000 -0.256000 cA 9 PE 0.339004 + 392 HX 1.807000 -0.650000 -1.291000 hE 9 PE 0.032843 + 393 C3 0.330000 -1.562000 -0.031000 cA 9 PE 0.040967 + 394 HA 0.041000 -1.559000 1.011000 hE 9 PE 0.090994 + 395 HB 0.613000 -2.568000 -0.305000 hE 9 PE 0.090994 + 396 O31 -0.732000 -1.142000 -0.860000 oT 9 PE -0.546623 + 397 P31 -2.233000 -1.108000 -0.332000 pA 9 PE 1.373656 + 398 O32 -2.136000 0.266000 0.585000 oT 9 PE -0.514542 + 399 C31 -3.161000 0.573000 1.479000 cA 9 PE 0.075159 + 400 H1A -2.877000 1.497000 1.967000 hE 9 PE 0.091516 + 401 H1B -3.275000 -0.198000 2.230000 hE 9 PE 0.091516 + 402 C32 -4.503000 0.755000 0.756000 cA 9 PE 0.077319 + 403 H2A -4.980000 -0.196000 0.574000 hX 9 PE 0.091630 + 404 H2B -5.171000 1.387000 1.325000 hX 9 PE 0.091630 + 405 N31 -4.264000 1.356000 -0.588000 nA 9 PE -0.368132 + 406 HN1A -3.660000 2.160000 -0.543000 hN 9 PE 0.348549 + 407 HN1B -3.765000 0.574000 -1.162000 hN 9 PE 0.348549 + 408 HN1C -5.121000 1.620000 -1.043000 hN 9 PE 0.348549 + 409 O33 -2.580000 -2.225000 0.542000 oP 9 PE -0.877447 + 410 O34 -3.100000 -0.702000 -1.484000 oP 9 PE -0.877447 + 411 O21 2.581000 -1.061000 0.567000 oS 9 PE -0.575480 + 412 C21 3.515000 -1.854000 0.049000 cC 9 PE 0.869340 + 413 O22 3.494000 -2.265000 -1.064000 oC 9 PE -0.649199 + 414 C11 -4.477000 -1.887000 -0.726000 cC 10 PGR 0.877006 + 415 O12 -4.371000 -2.868000 -0.063000 oC 10 PGR -0.649265 + 416 O11 -3.639000 -0.870000 -0.694000 oS 10 PGR -0.585165 + 417 C1 -2.503000 -0.948000 0.169000 cA 10 PGR 0.295119 + 418 HR -1.828000 -1.711000 -0.185000 hE 10 PGR 0.033797 + 419 HS -2.829000 -1.195000 1.169000 hE 10 PGR 0.033797 + 420 C2 -1.828000 0.404000 0.138000 cA 10 PGR 0.353807 + 421 HX -1.630000 0.695000 -0.880000 hE 10 PGR 0.037488 + 422 C3 -0.548000 0.426000 0.959000 cA 10 PGR 0.043713 + 423 HA -0.757000 0.182000 1.993000 hE 10 PGR 0.091041 + 424 HB -0.133000 1.429000 0.931000 hE 10 PGR 0.091041 + 425 O31 0.324000 -0.498000 0.392000 oT 10 PGR -0.546098 + 426 P31 1.792000 -0.746000 1.103000 pA 10 PGR 1.380464 + 427 O32 2.555000 0.619000 0.624000 oT 10 PGR -0.534308 + 428 C31 2.986000 0.770000 -0.700000 cA 10 PGR -0.056706 + 429 H1A 2.623000 1.721000 -1.076000 hE 10 PGR 0.093354 + 430 H1B 2.604000 -0.014000 -1.340000 hE 10 PGR 0.093354 + 431 C32 4.505000 0.786000 -0.761000 cA 10 PGR 0.336816 + 432 H2A 4.873000 1.541000 -0.068000 hE 10 PGR 0.030042 + 433 O35 4.862000 1.134000 -2.080000 oH 10 PGR -0.726192 + 434 HO5A 5.785000 0.936000 -2.177000 hO 10 PGR 0.439523 + 435 C33 5.129000 -0.545000 -0.390000 cA 10 PGR 0.193597 + 436 H3A 4.915000 -0.793000 0.640000 hE 10 PGR 0.034715 + 437 H3B 4.728000 -1.331000 -1.018000 hE 10 PGR 0.034715 + 438 O33 2.390000 -1.892000 0.403000 oP 10 PGR -0.873444 + 439 O34 1.622000 -0.640000 2.557000 oP 10 PGR -0.873444 + 440 O21 -2.727000 1.350000 0.732000 oS 10 PGR -0.599131 + 441 C21 -3.217000 2.354000 0.028000 cC 10 PGR 0.883669 + 442 O22 -2.963000 2.587000 -1.110000 oC 10 PGR -0.655762 + 443 O36 6.529000 -0.405000 -0.601000 oH 10 PGR -0.700871 + 444 HO6A 6.945000 -1.239000 -0.440000 hO 10 PGR 0.423328 + 445 C11 -4.694000 -1.417000 0.240000 cC 11 PGS 0.877006 + 446 O12 -4.509000 -2.326000 0.983000 oC 11 PGS -0.649265 + 447 O11 -3.752000 -0.596000 -0.184000 oS 11 PGS -0.585165 + 448 C1 -2.409000 -0.821000 0.246000 cA 11 PGS 0.295119 + 449 HR -2.038000 -1.739000 -0.181000 hE 11 PGS 0.033797 + 450 HS -2.383000 -0.893000 1.323000 hE 11 PGS 0.033797 + 451 C2 -1.588000 0.353000 -0.240000 cA 11 PGS 0.353807 + 452 HX -1.724000 0.488000 -1.299000 hE 11 PGS 0.037488 + 453 C3 -0.111000 0.199000 0.091000 cA 11 PGS 0.043713 + 454 HA 0.027000 0.102000 1.161000 hE 11 PGS 0.091041 + 455 HB 0.417000 1.085000 -0.244000 hE 11 PGS 0.091041 + 456 O31 0.348000 -0.934000 -0.576000 oT 11 PGS -0.546098 + 457 P31 1.837000 -1.519000 -0.273000 pA 11 PGS 1.380464 + 458 O32 2.681000 -0.306000 -0.969000 oT 11 PGS -0.534308 + 459 C31 4.081000 -0.360000 -0.920000 cA 11 PGS -0.056706 + 460 H1A 4.460000 -0.364000 -1.935000 hE 11 PGS 0.093354 + 461 H1B 4.422000 -1.266000 -0.434000 hE 11 PGS 0.093354 + 462 C32 4.680000 0.829000 -0.187000 cA 11 PGS 0.336816 + 463 H2A 5.745000 0.618000 -0.068000 hE 11 PGS 0.030042 + 464 O35 4.513000 1.978000 -0.993000 oH 11 PGS -0.726192 + 465 HO5A 4.845000 2.731000 -0.522000 hO 11 PGS 0.439523 + 466 C33 4.080000 1.063000 1.197000 cA 11 PGS 0.193597 + 467 H3A 4.575000 1.928000 1.641000 hE 11 PGS 0.034715 + 468 H3B 3.031000 1.312000 1.083000 hE 11 PGS 0.034715 + 469 O33 2.005000 -2.765000 -1.022000 oP 11 PGS -0.873444 + 470 O34 2.084000 -1.434000 1.191000 oP 11 PGS -0.873444 + 471 O21 -2.046000 1.522000 0.450000 oS 11 PGS -0.599131 + 472 C21 -2.640000 2.506000 -0.204000 cC 11 PGS 0.883669 + 473 O22 -2.822000 2.540000 -1.377000 oC 11 PGS -0.655762 + 474 O36 4.267000 -0.017000 2.049000 oH 11 PGS -0.700871 + 475 HO6A 3.542000 -0.633000 1.892000 hO 11 PGS 0.423328 + 476 C11 -3.044000 -2.013000 0.046000 cC 12 PH- 0.888207 + 477 O12 -2.728000 -2.874000 0.802000 oC 12 PH- -0.671142 + 478 O11 -2.283000 -0.988000 -0.281000 oS 12 PH- -0.547824 + 479 C1 -0.971000 -0.903000 0.280000 cA 12 PH- 0.185299 + 480 HR -0.353000 -1.692000 -0.118000 hE 12 PH- 0.067676 + 481 HS -1.034000 -1.005000 1.353000 hE 12 PH- 0.067676 + 482 C2 -0.409000 0.446000 -0.105000 cA 12 PH- 0.283546 + 483 HX -0.481000 0.586000 -1.171000 hE 12 PH- 0.063862 + 484 C3 1.029000 0.623000 0.360000 cA 12 PH- 0.081528 + 485 HA 1.091000 0.533000 1.438000 hE 12 PH- 0.083099 + 486 HB 1.360000 1.622000 0.090000 hE 12 PH- 0.083099 + 487 O31 1.789000 -0.352000 -0.272000 oT 12 PH- -0.594197 + 488 P31 3.414000 -0.414000 0.038000 pA 12 PH- 1.456663 + 489 O32 3.909000 0.868000 -0.850000 oH 12 PH- -0.706197 + 490 HO2A 4.131000 0.544000 -1.712000 hO 12 PH- 0.415628 + 491 O33 3.901000 -1.629000 -0.630000 oP 12 PH- -0.914158 + 492 O34 3.601000 -0.081000 1.456000 oP 12 PH- -0.914158 + 493 O21 -1.197000 1.447000 0.555000 oS 12 PH- -0.554487 + 494 C21 -1.896000 2.327000 -0.137000 cC 12 PH- 0.897502 + 495 O22 -1.933000 2.399000 -1.324000 oC 12 PH- -0.671622 + 496 C11 -4.858000 -1.850000 -0.410000 cC 13 PS 0.887549 + 497 O12 -4.698000 -2.763000 0.333000 oC 13 PS -0.663331 + 498 O11 -4.019000 -0.838000 -0.535000 oS 13 PS -0.579073 + 499 C1 -2.831000 -0.844000 0.255000 cA 13 PS 0.271173 + 500 HR -2.200000 -1.666000 -0.042000 hE 13 PS 0.037454 + 501 HS -3.092000 -0.954000 1.297000 hE 13 PS 0.037454 + 502 C2 -2.131000 0.474000 0.008000 cA 13 PS 0.440650 + 503 HX -1.992000 0.627000 -1.049000 hE 13 PS 0.002473 + 504 C3 -0.799000 0.566000 0.736000 cA 13 PS 0.012366 + 505 HA -0.935000 0.434000 1.801000 hE 13 PS 0.097347 + 506 HB -0.371000 1.548000 0.565000 hE 13 PS 0.097347 + 507 O31 0.031000 -0.431000 0.214000 oT 13 PS -0.556992 + 508 P31 1.459000 -0.736000 0.918000 pA 13 PS 1.380208 + 509 O32 2.273000 0.544000 0.314000 oT 13 PS -0.520128 + 510 C31 3.667000 0.633000 0.494000 cA 13 PS 0.060375 + 511 H1A 3.999000 -0.001000 1.309000 hE 13 PS 0.093484 + 512 H1B 3.918000 1.652000 0.742000 hE 13 PS 0.093484 + 513 C32 4.399000 0.283000 -0.793000 cA 13 PS 0.039448 + 514 H2A 4.021000 0.911000 -1.586000 hX 13 PS 0.090549 + 515 N31 4.144000 -1.146000 -1.167000 nA 13 PS -0.414327 + 516 HN1A 5.037000 -1.599000 -0.965000 hN 13 PS 0.353866 + 517 HN1B 3.345000 -1.571000 -0.652000 hN 13 PS 0.353866 + 518 HN1C 3.974000 -1.245000 -2.151000 hN 13 PS 0.353866 + 519 C33 5.947000 0.464000 -0.664000 cC 13 PS 0.809867 + 520 O33 2.019000 -1.944000 0.253000 oP 13 PS -0.877922 + 521 O34 1.341000 -0.631000 2.375000 oP 13 PS -0.877922 + 522 O21 -2.961000 1.514000 0.532000 oS 13 PS -0.634381 + 523 C21 -3.475000 2.435000 -0.269000 cC 13 PS 0.891897 + 524 O22 -3.284000 2.507000 -1.439000 oC 13 PS -0.650291 + 525 O35 6.589000 -0.587000 -0.792000 oO 13 PS -0.815178 + 526 O36 6.300000 1.609000 -0.448000 oO 13 PS -0.815178 + 527 C116 9.152000 -1.077000 0.697000 cD 14 SA -0.199999 + 528 H16R 10.204000 -1.219000 0.564000 hL 14 SA 0.049471 + 529 H16S 8.914000 -0.040000 0.579000 hL 14 SA 0.049471 + 530 H16T 8.620000 -1.650000 -0.033000 hL 14 SA 0.049471 + 531 C115 8.749000 -1.537000 2.100000 cD 14 SA -0.046781 + 532 H15R 8.998000 -2.571000 2.214000 hL 14 SA 0.026484 + 533 H15S 7.696000 -1.389000 2.217000 hL 14 SA 0.026484 + 534 C114 9.476000 -0.727000 3.175000 cD 14 SA 0.044648 + 535 H14R 9.150000 0.290000 3.104000 hL 14 SA 0.010970 + 536 H14S 10.523000 -0.848000 2.988000 hL 14 SA 0.010970 + 537 C113 9.235000 -1.205000 4.608000 cD 14 SA -0.119225 + 538 H13R 9.328000 -2.270000 4.640000 hL 14 SA 0.040330 + 539 H13S 8.253000 -0.901000 4.904000 hL 14 SA 0.040330 + 540 C112 10.244000 -0.588000 5.579000 cD 14 SA 0.001048 + 541 H12R 10.085000 0.465000 5.680000 hL 14 SA 0.016935 + 542 H12S 11.258000 -0.696000 5.255000 hL 14 SA 0.016935 + 543 C111 9.953000 -1.315000 6.894000 cD 14 SA -0.079417 + 544 H11R 10.536000 -2.210000 6.950000 hL 14 SA 0.023502 + 545 H11S 8.917000 -1.578000 6.950000 hL 14 SA 0.023502 + 546 C110 10.325000 -0.382000 8.047000 cD 14 SA -0.066372 + 547 H10R 9.732000 0.507000 7.999000 hL 14 SA 0.021723 + 548 H10S 11.358000 -0.109000 7.982000 hL 14 SA 0.021723 + 549 C19 10.054000 -1.114000 9.363000 cD 14 SA 0.053352 + 550 H9R 10.960000 -1.558000 9.719000 hL 14 SA 0.020200 + 551 H9S 9.324000 -1.880000 9.205000 hL 14 SA 0.020200 + 552 C18 9.534000 -0.113000 10.397000 cD 14 SA -0.187889 + 553 H8R 8.612000 0.297000 10.041000 hL 14 SA 0.046909 + 554 H8S 10.285000 0.639000 10.520000 hL 14 SA 0.046909 + 555 C17 9.289000 -0.743000 11.770000 cD 14 SA 0.049288 + 556 H7R 8.953000 -1.749000 11.629000 hL 14 SA 0.006045 + 557 H7S 8.557000 -0.145000 12.271000 hL 14 SA 0.006045 + 558 C16 10.542000 -0.765000 12.648000 cD 14 SA -0.012997 + 559 H6R 10.872000 0.244000 12.784000 hL 14 SA 0.003223 + 560 H6S 11.259000 -1.375000 12.139000 hL 14 SA 0.003223 + 561 C15 10.340000 -1.392000 14.029000 cD 14 SA 0.093171 + 562 H5R 9.875000 -0.666000 14.663000 hL 14 SA -0.011690 + 563 H5S 11.308000 -1.686000 14.378000 hL 14 SA -0.011690 + 564 C14 9.472000 -2.651000 14.023000 cD 14 SA -0.258138 + 565 H4R 10.007000 -3.387000 13.461000 hL 14 SA 0.076843 + 566 H4S 8.542000 -2.295000 13.631000 hL 14 SA 0.076843 + 567 C13 9.061000 -3.309000 15.307000 cB 14 SA 0.028290 + 568 H3R 8.616000 -4.240000 15.290000 hB 14 SA 0.116281 + 569 C12 9.271000 -2.689000 16.476000 cB 14 SA -0.341889 + 570 H2R 9.747000 -1.773000 16.480000 hB 14 SA 0.145550 + 571 C2 -41.583000 54.249000 135.723000 cA 15 SPM 0.012739 + 572 HX -42.533000 53.708000 135.697000 hE 15 SPM 0.087455 + 573 C3 -40.999000 53.884000 137.051000 cA 15 SPM 0.176625 + 574 HA -40.811000 52.812000 137.148000 hE 15 SPM 0.051622 + 575 HB -41.752000 54.112000 137.810000 hE 15 SPM 0.051622 + 576 O31 -39.815000 54.716000 137.276000 oT 15 SPM -0.533356 + 577 P31 -39.293000 55.046000 138.706000 pA 15 SPM 1.324762 + 578 O32 -38.408000 53.823000 139.126000 oT 15 SPM -0.459308 + 579 C31 -39.007000 52.753000 139.780000 cA 15 SPM 0.282447 + 580 H1A -39.703000 52.245000 139.107000 hE 15 SPM 0.049886 + 581 H1B -39.513000 53.055000 140.700000 hE 15 SPM 0.049886 + 582 C32 -37.924000 51.780000 140.007000 cA 15 SPM -0.493665 + 583 H2A -37.321000 51.694000 139.101000 hX 15 SPM 0.233840 + 584 H2B -38.386000 50.810000 140.197000 hX 15 SPM 0.233840 + 585 N31 -36.964000 52.047000 141.081000 nA 15 SPM 0.245275 + 586 C33 -36.033000 53.154000 140.832000 cA 15 SPM -0.386611 + 587 H3A -35.716000 52.950000 139.809000 hX 15 SPM 0.191569 + 588 H3B -36.582000 54.084000 140.986000 hX 15 SPM 0.191569 + 589 H3C -35.184000 53.174000 141.517000 hX 15 SPM 0.191569 + 590 C34 -37.627000 52.236000 142.409000 cA 15 SPM -0.386611 + 591 H4A -36.897000 52.122000 143.212000 hX 15 SPM 0.191569 + 592 H4B -37.859000 53.302000 142.403000 hX 15 SPM 0.191569 + 593 H4C -38.452000 51.526000 142.332000 hX 15 SPM 0.191569 + 594 C35 -36.268000 50.708000 141.208000 cA 15 SPM -0.386611 + 595 H5A -35.199000 50.867000 141.358000 hX 15 SPM 0.191569 + 596 H5B -36.826000 50.065000 141.889000 hX 15 SPM 0.191569 + 597 H5C -36.280000 50.262000 140.212000 hX 15 SPM 0.191569 + 598 O33 -40.354000 55.264000 139.710000 oP 15 SPM -0.884789 + 599 O34 -38.275000 56.136000 138.639000 oP 15 SPM -0.884789 + 600 N11 -40.692000 54.026000 134.611000 nN 15 SPM -0.388410 + 601 H11 -39.968000 54.718000 134.492000 hN 15 SPM 0.273592 + 602 C11 -40.660000 52.864000 133.849000 cC 15 SPM 0.617231 + 603 O12 -41.427000 51.930000 133.938000 oC 15 SPM -0.645303 + 604 C1 -42.202000 55.632000 135.867000 cA 15 SPM 0.323092 + 605 HR -41.432000 56.273000 136.304000 hE 15 SPM 0.069208 + 606 O22 -43.465000 55.672000 136.573000 oH 15 SPM -0.723033 + 607 H22 -44.064000 56.048000 135.903000 hO 15 SPM 0.434964 + 608 C118 12.346000 0.172000 0.239000 cD 16 ST -0.120069 + 609 H18R 13.222000 0.143000 -0.403000 hL 16 ST 0.027938 + 610 H18S 12.424000 -0.652000 0.943000 hL 16 ST 0.027938 + 611 H18T 12.385000 1.096000 0.809000 hL 16 ST 0.027938 + 612 C117 11.057000 0.081000 -0.577000 cD 16 ST 0.020665 + 613 H17R 11.064000 -0.836000 -1.161000 hL 16 ST 0.008483 + 614 H17S 11.026000 0.899000 -1.294000 hL 16 ST 0.008483 + 615 C116 9.797000 0.120000 0.290000 cD 16 ST -0.027654 + 616 H16R 9.792000 1.038000 0.875000 hL 16 ST 0.015627 + 617 H16S 9.831000 -0.698000 1.008000 hL 16 ST 0.015627 + 618 C115 8.502000 0.029000 -0.520000 cD 16 ST -0.032444 + 619 H15R 8.507000 -0.889000 -1.105000 hL 16 ST 0.010253 + 620 H15S 8.469000 0.847000 -1.238000 hL 16 ST 0.010253 + 621 C114 7.242000 0.068000 0.348000 cD 16 ST -0.013489 + 622 H14R 7.236000 0.986000 0.933000 hL 16 ST 0.010073 + 623 H14S 7.275000 -0.750000 1.066000 hL 16 ST 0.010073 + 624 C113 5.947000 -0.023000 -0.462000 cD 16 ST -0.011590 + 625 H13R 5.952000 -0.941000 -1.047000 hL 16 ST 0.006022 + 626 H13S 5.914000 0.795000 -1.180000 hL 16 ST 0.006022 + 627 C112 4.687000 0.016000 0.405000 cD 16 ST -0.019153 + 628 H12R 4.681000 0.934000 0.990000 hL 16 ST 0.008198 + 629 H12S 4.720000 -0.802000 1.123000 hL 16 ST 0.008198 + 630 C111 3.392000 -0.075000 -0.404000 cD 16 ST -0.017093 + 631 H11R 3.397000 -0.993000 -0.989000 hL 16 ST 0.010206 + 632 H11S 3.359000 0.743000 -1.122000 hL 16 ST 0.010206 + 633 C110 2.132000 -0.036000 0.463000 cD 16 ST -0.026418 + 634 H10R 2.126000 0.882000 1.048000 hL 16 ST 0.010825 + 635 H10S 2.165000 -0.854000 1.181000 hL 16 ST 0.010825 + 636 C19 0.837000 -0.127000 -0.347000 cD 16 ST -0.017997 + 637 H9R 0.842000 -1.045000 -0.932000 hL 16 ST 0.009595 + 638 H9S 0.804000 0.691000 -1.065000 hL 16 ST 0.009595 + 639 C18 -0.423000 -0.089000 0.521000 cD 16 ST -0.014623 + 640 H8R -0.429000 0.830000 1.106000 hL 16 ST 0.007326 + 641 H8S -0.390000 -0.906000 1.239000 hL 16 ST 0.007326 + 642 C17 -1.718000 -0.180000 -0.289000 cD 16 ST -0.019469 + 643 H7R -1.712000 -1.098000 -0.874000 hL 16 ST 0.009292 + 644 H7S -1.751000 0.638000 -1.007000 hL 16 ST 0.009292 + 645 C16 -2.977000 -0.141000 0.578000 cD 16 ST -0.037627 + 646 H6R -2.984000 0.777000 1.163000 hL 16 ST 0.017740 + 647 H6S -2.944000 -0.959000 1.297000 hL 16 ST 0.017740 + 648 C15 -4.272000 -0.234000 -0.232000 cD 16 ST -0.013443 + 649 H5R -4.267000 -1.152000 -0.815000 hL 16 ST 0.008191 + 650 H5S -4.306000 0.584000 -0.950000 hL 16 ST 0.008191 + 651 C14 -5.531000 -0.196000 0.636000 cD 16 ST -0.059792 + 652 H4R -5.539000 0.724000 1.220000 hL 16 ST 0.024241 + 653 H4S -5.498000 -1.012000 1.355000 hL 16 ST 0.024241 + 654 C13 -6.822000 -0.294000 -0.177000 cD 16 ST -0.000128 + 655 H3R -6.828000 -1.215000 -0.752000 hL 16 ST 0.013886 + 656 H3S -6.861000 0.522000 -0.896000 hL 16 ST 0.013886 + 657 C12 -8.079000 -0.265000 0.706000 cD 16 ST -0.117020 + 658 H2R -8.110000 0.652000 1.284000 hL 16 ST 0.051807 + 659 H2S -8.050000 -1.094000 1.403000 hL 16 ST 0.051807 +@BOND + 1 1 2 1 + 2 1 3 1 + 3 1 4 1 + 4 1 38 1 + 5 4 5 1 + 6 4 6 2 + 7 6 7 1 + 8 6 8 1 + 9 8 9 1 + 10 8 10 1 + 11 8 11 1 + 12 11 12 1 + 13 11 13 2 + 14 13 14 1 + 15 13 15 1 + 16 15 16 1 + 17 15 17 1 + 18 15 18 1 + 19 18 19 1 + 20 18 20 2 + 21 20 21 1 + 22 20 22 1 + 23 22 23 1 + 24 22 24 1 + 25 22 25 1 + 26 25 26 1 + 27 25 27 2 + 28 27 28 1 + 29 27 29 1 + 30 29 30 1 + 31 29 31 1 + 32 29 32 1 + 33 32 33 1 + 34 32 34 1 + 35 32 35 1 + 36 35 36 1 + 37 35 37 1 + 38 38 39 1 + 39 38 40 1 + 40 38 41 1 + 41 41 42 1 + 42 41 43 1 + 43 41 44 1 + 44 44 45 1 + 45 44 46 1 + 46 44 47 1 + 47 47 48 1 + 48 47 49 1 + 49 47 50 1 + 50 51 52 1 + 51 51 53 1 + 52 51 54 1 + 53 51 72 1 + 54 54 55 1 + 55 54 56 1 + 56 54 57 1 + 57 57 58 1 + 58 57 59 1 + 59 57 123 1 + 60 59 60 1 + 61 59 61 1 + 62 59 62 1 + 63 62 63 2 + 64 62 72 1 + 65 63 64 1 + 66 63 65 1 + 67 65 66 1 + 68 65 67 1 + 69 65 68 1 + 70 68 69 1 + 71 68 70 1 + 72 68 80 1 + 73 70 71 1 + 74 70 72 1 + 75 70 73 1 + 76 72 94 1 + 77 73 74 1 + 78 73 75 1 + 79 73 76 1 + 80 76 77 1 + 81 76 78 1 + 82 76 79 1 + 83 79 80 1 + 84 79 88 1 + 85 79 90 1 + 86 80 81 1 + 87 80 82 1 + 88 82 83 1 + 89 82 84 1 + 90 82 85 1 + 91 85 86 1 + 92 85 87 1 + 93 85 88 1 + 94 88 89 1 + 95 88 98 1 + 96 90 91 1 + 97 90 92 1 + 98 90 93 1 + 99 94 95 1 + 100 94 96 1 + 101 94 97 1 + 102 98 99 1 + 103 98 100 1 + 104 98 104 1 + 105 100 101 1 + 106 100 102 1 + 107 100 103 1 + 108 104 105 1 + 109 104 106 1 + 110 104 107 1 + 111 107 108 1 + 112 107 109 1 + 113 107 110 1 + 114 110 111 1 + 115 110 112 1 + 116 110 113 1 + 117 113 114 1 + 118 113 115 1 + 119 113 119 1 + 120 115 116 1 + 121 115 117 1 + 122 115 118 1 + 123 119 120 1 + 124 119 121 1 + 125 119 122 1 + 126 123 124 1 + 127 125 126 1 + 128 125 127 1 + 129 125 161 2 + 130 127 128 1 + 131 127 129 1 + 132 127 130 1 + 133 130 131 1 + 134 130 132 2 + 135 132 133 1 + 136 132 134 1 + 137 134 135 1 + 138 134 136 1 + 139 134 137 1 + 140 137 138 1 + 141 137 139 2 + 142 139 140 1 + 143 139 141 1 + 144 141 142 1 + 145 141 143 1 + 146 141 144 1 + 147 144 145 1 + 148 144 146 2 + 149 146 147 1 + 150 146 148 1 + 151 148 149 1 + 152 148 150 1 + 153 148 151 1 + 154 151 152 1 + 155 151 153 2 + 156 153 154 1 + 157 153 155 1 + 158 155 156 1 + 159 155 157 1 + 160 155 158 1 + 161 158 159 1 + 162 158 160 1 + 163 161 162 1 + 164 161 163 1 + 165 163 164 1 + 166 163 165 1 + 167 163 166 1 + 168 166 167 1 + 169 166 168 2 + 170 168 169 1 + 171 168 170 1 + 172 170 171 1 + 173 170 172 1 + 174 170 173 1 + 175 173 174 1 + 176 173 175 1 + 177 173 176 1 + 178 177 178 1 + 179 178 179 1 + 180 178 180 1 + 181 178 181 1 + 182 181 184 1 + 183 181 183 1 + 184 181 182 1 + 185 184 187 1 + 186 184 186 1 + 187 184 185 1 + 188 187 190 1 + 189 187 189 1 + 190 187 188 1 + 191 190 193 1 + 192 190 192 1 + 193 190 191 1 + 194 193 196 1 + 195 193 195 1 + 196 193 194 1 + 197 196 199 1 + 198 196 198 1 + 199 196 197 1 + 200 199 202 1 + 201 199 201 1 + 202 199 200 1 + 203 202 205 1 + 204 202 204 1 + 205 202 203 1 + 206 205 208 1 + 207 205 206 1 + 208 205 207 1 + 209 208 210 1 + 210 208 209 1 + 211 211 212 1 + 212 212 215 1 + 213 212 213 1 + 214 212 214 1 + 215 215 218 1 + 216 215 216 1 + 217 215 217 1 + 218 218 221 1 + 219 218 220 1 + 220 218 219 1 + 221 221 224 1 + 222 221 222 1 + 223 221 223 1 + 224 224 227 1 + 225 224 226 1 + 226 224 225 1 + 227 227 230 1 + 228 227 228 1 + 229 227 229 1 + 230 230 233 1 + 231 230 232 1 + 232 230 231 1 + 233 233 236 1 + 234 233 234 1 + 235 233 235 1 + 236 236 239 1 + 237 236 237 1 + 238 236 238 1 + 239 239 242 1 + 240 239 240 1 + 241 239 241 1 + 242 242 245 1 + 243 242 244 1 + 244 242 243 1 + 245 245 248 1 + 246 245 247 1 + 247 245 246 1 + 248 248 250 1 + 249 248 249 1 + 250 251 252 1 + 251 251 253 1 + 252 251 254 1 + 253 254 255 1 + 254 254 256 1 + 255 254 257 1 + 256 257 258 1 + 257 257 259 1 + 258 257 260 1 + 259 260 261 1 + 260 260 262 1 + 261 260 263 1 + 262 263 264 1 + 263 263 265 1 + 264 263 266 1 + 265 266 267 1 + 266 266 268 1 + 267 266 269 1 + 268 269 270 1 + 269 269 271 1 + 270 269 272 1 + 271 272 273 1 + 272 272 274 2 + 273 274 275 1 + 274 274 276 1 + 275 276 277 1 + 276 276 278 1 + 277 276 279 1 + 278 279 280 1 + 279 279 281 1 + 280 279 282 1 + 281 282 283 1 + 282 282 284 1 + 283 282 285 1 + 284 285 286 1 + 285 285 287 1 + 286 285 288 1 + 287 288 289 1 + 288 288 290 1 + 289 288 291 1 + 290 291 292 1 + 291 291 293 1 + 292 291 294 1 + 293 294 295 1 + 294 294 296 1 + 295 294 297 1 + 296 297 298 1 + 297 297 299 1 + 298 297 300 1 + 299 301 302 1 + 300 301 303 1 + 301 301 304 1 + 302 301 305 1 + 303 305 306 1 + 304 305 307 1 + 305 305 308 1 + 306 308 309 1 + 307 308 310 1 + 308 308 311 1 + 309 311 312 1 + 310 311 313 1 + 311 311 314 1 + 312 314 315 1 + 313 314 316 1 + 314 314 317 1 + 315 317 318 1 + 316 317 319 1 + 317 317 320 1 + 318 320 321 1 + 319 320 322 1 + 320 320 323 1 + 321 323 324 1 + 322 323 325 1 + 323 323 326 1 + 324 326 327 1 + 325 326 328 1 + 326 326 329 1 + 327 329 330 1 + 328 329 331 1 + 329 329 332 1 + 330 332 333 1 + 331 332 334 1 + 332 332 335 1 + 333 335 336 1 + 334 335 337 1 + 335 335 338 1 + 336 338 339 1 + 337 338 340 1 + 338 338 341 1 + 339 341 342 1 + 340 341 343 1 + 341 341 344 1 + 342 344 345 1 + 343 344 346 1 + 344 347 348 2 + 345 347 349 1 + 346 349 350 1 + 347 350 351 1 + 348 350 352 1 + 349 350 353 1 + 350 353 354 1 + 351 353 355 1 + 352 353 382 1 + 353 355 356 1 + 354 355 357 1 + 355 355 358 1 + 356 358 359 1 + 357 359 360 1 + 358 359 380 1 + 359 359 381 1 + 360 360 361 1 + 361 361 362 1 + 362 361 363 1 + 363 361 364 1 + 364 364 365 1 + 365 364 366 1 + 366 364 367 1 + 367 367 368 1 + 368 367 372 1 + 369 367 376 1 + 370 368 369 1 + 371 368 370 1 + 372 368 371 1 + 373 372 373 1 + 374 372 374 1 + 375 372 375 1 + 376 376 377 1 + 377 376 378 1 + 378 376 379 1 + 379 382 383 1 + 380 383 384 2 + 381 385 386 2 + 382 385 387 1 + 383 387 388 1 + 384 388 389 1 + 385 388 390 1 + 386 388 391 1 + 387 391 392 1 + 388 391 393 1 + 389 391 411 1 + 390 393 394 1 + 391 393 395 1 + 392 393 396 1 + 393 396 397 1 + 394 397 398 1 + 395 397 409 1 + 396 397 410 1 + 397 398 399 1 + 398 399 400 1 + 399 399 401 1 + 400 399 402 1 + 401 402 403 1 + 402 402 404 1 + 403 402 405 1 + 404 405 406 1 + 405 405 407 1 + 406 405 408 1 + 407 411 412 1 + 408 412 413 2 + 409 414 415 2 + 410 414 416 1 + 411 416 417 1 + 412 417 418 1 + 413 417 419 1 + 414 417 420 1 + 415 420 421 1 + 416 420 422 1 + 417 420 440 1 + 418 422 423 1 + 419 422 424 1 + 420 422 425 1 + 421 425 426 1 + 422 426 427 1 + 423 426 438 1 + 424 426 439 1 + 425 427 428 1 + 426 428 429 1 + 427 428 430 1 + 428 428 431 1 + 429 431 432 1 + 430 431 433 1 + 431 431 435 1 + 432 433 434 1 + 433 435 436 1 + 434 435 437 1 + 435 435 443 1 + 436 440 441 1 + 437 441 442 2 + 438 443 444 1 + 439 445 446 2 + 440 445 447 1 + 441 447 448 1 + 442 448 449 1 + 443 448 450 1 + 444 448 451 1 + 445 451 452 1 + 446 451 453 1 + 447 451 471 1 + 448 453 454 1 + 449 453 455 1 + 450 453 456 1 + 451 456 457 1 + 452 457 458 1 + 453 457 469 1 + 454 457 470 1 + 455 458 459 1 + 456 459 460 1 + 457 459 461 1 + 458 459 462 1 + 459 462 463 1 + 460 462 464 1 + 461 462 466 1 + 462 464 465 1 + 463 466 467 1 + 464 466 468 1 + 465 466 474 1 + 466 471 472 1 + 467 472 473 2 + 468 474 475 1 + 469 476 477 2 + 470 476 478 1 + 471 478 479 1 + 472 479 480 1 + 473 479 481 1 + 474 479 482 1 + 475 482 483 1 + 476 482 484 1 + 477 482 493 1 + 478 484 485 1 + 479 484 486 1 + 480 484 487 1 + 481 487 488 1 + 482 488 489 1 + 483 488 491 1 + 484 488 492 1 + 485 489 490 1 + 486 493 494 1 + 487 494 495 2 + 488 496 497 2 + 489 496 498 1 + 490 498 499 1 + 491 499 500 1 + 492 499 501 1 + 493 499 502 1 + 494 502 503 1 + 495 502 504 1 + 496 502 522 1 + 497 504 505 1 + 498 504 506 1 + 499 504 507 1 + 500 507 508 1 + 501 508 509 1 + 502 508 520 1 + 503 508 521 1 + 504 509 510 1 + 505 510 511 1 + 506 510 512 1 + 507 510 513 1 + 508 513 514 1 + 509 513 515 1 + 510 513 519 1 + 511 515 516 1 + 512 515 517 1 + 513 515 518 1 + 514 519 525 1 + 515 519 526 1 + 516 522 523 1 + 517 523 524 2 + 518 527 531 1 + 519 527 529 1 + 520 527 528 1 + 521 527 530 1 + 522 531 534 1 + 523 531 533 1 + 524 531 532 1 + 525 534 537 1 + 526 534 535 1 + 527 534 536 1 + 528 537 540 1 + 529 537 539 1 + 530 537 538 1 + 531 540 543 1 + 532 540 542 1 + 533 540 541 1 + 534 543 546 1 + 535 543 545 1 + 536 543 544 1 + 537 546 549 1 + 538 546 547 1 + 539 546 548 1 + 540 549 552 1 + 541 549 550 1 + 542 549 551 1 + 543 552 555 1 + 544 552 554 1 + 545 552 553 1 + 546 555 558 1 + 547 555 557 1 + 548 555 556 1 + 549 558 561 1 + 550 558 559 1 + 551 558 560 1 + 552 561 564 1 + 553 561 563 1 + 554 561 562 1 + 555 564 567 1 + 556 564 565 1 + 557 564 566 1 + 558 567 569 1 + 559 567 568 1 + 560 569 570 1 + 561 571 600 1 + 562 571 573 1 + 563 571 572 1 + 564 571 604 1 + 565 573 576 1 + 566 573 575 1 + 567 573 574 1 + 568 576 577 1 + 569 577 578 1 + 570 577 598 1 + 571 577 599 1 + 572 578 579 1 + 573 579 582 1 + 574 579 581 1 + 575 579 580 1 + 576 582 585 1 + 577 582 583 1 + 578 582 584 1 + 579 585 590 1 + 580 585 594 1 + 581 585 586 1 + 582 586 587 1 + 583 586 588 1 + 584 586 589 1 + 585 590 593 1 + 586 590 592 1 + 587 590 591 1 + 588 594 597 1 + 589 594 595 1 + 590 594 596 1 + 591 600 602 1 + 592 600 601 1 + 593 602 603 1 + 594 604 605 1 + 595 604 606 1 + 596 606 607 1 + 597 608 612 1 + 598 608 611 1 + 599 608 610 1 + 600 608 609 1 + 601 612 615 1 + 602 612 614 1 + 603 612 613 1 + 604 615 618 1 + 605 615 616 1 + 606 615 617 1 + 607 618 621 1 + 608 618 620 1 + 609 618 619 1 + 610 621 624 1 + 611 621 622 1 + 612 621 623 1 + 613 624 627 1 + 614 624 626 1 + 615 624 625 1 + 616 627 630 1 + 617 627 628 1 + 618 627 629 1 + 619 630 633 1 + 620 630 632 1 + 621 630 631 1 + 622 633 636 1 + 623 633 634 1 + 624 633 635 1 + 625 636 639 1 + 626 636 638 1 + 627 636 637 1 + 628 639 642 1 + 629 639 640 1 + 630 639 641 1 + 631 642 645 1 + 632 642 644 1 + 633 642 643 1 + 634 645 648 1 + 635 645 646 1 + 636 645 647 1 + 637 648 651 1 + 638 648 650 1 + 639 648 649 1 + 640 651 654 1 + 641 651 652 1 + 642 651 653 1 + 643 654 657 1 + 644 654 656 1 + 645 654 655 1 + 646 657 658 1 + 647 657 659 1 +@SUBSTRUCTURE + 1 AR 1 **** 0 **** **** + 2 CHL 51 **** 0 **** **** + 3 DHA 125 **** 0 **** **** + 4 LAL 177 **** 0 **** **** + 5 MY 211 **** 0 **** **** + 6 OL 251 **** 0 **** **** + 7 PA 301 **** 0 **** **** + 8 PC 347 **** 0 **** **** + 9 PE 385 **** 0 **** **** + 10 PGR 414 **** 0 **** **** + 11 PGS 445 **** 0 **** **** + 12 PH- 476 **** 0 **** **** + 13 PS 496 **** 0 **** **** + 14 SA 527 **** 0 **** **** + 15 SPM 571 **** 0 **** **** + 16 ST 608 **** 0 **** **** diff --git a/src/Xponge/forcefield/amber/lipid21.py b/src/Xponge/forcefield/amber/lipid21.py new file mode 100644 index 0000000..a0fe76c --- /dev/null +++ b/src/Xponge/forcefield/amber/lipid21.py @@ -0,0 +1,3 @@ +"""Legacy Lipid21 loader backed by XpongeCPP.""" + +from XpongeCPP.forcefield.amber.lipid21 import * # noqa: F401,F403 diff --git a/src/Xponge/forcefield/amber/lipid21_manifest.json b/src/Xponge/forcefield/amber/lipid21_manifest.json new file mode 100644 index 0000000..0fa8952 --- /dev/null +++ b/src/Xponge/forcefield/amber/lipid21_manifest.json @@ -0,0 +1,899 @@ +{ + "format_version": 2, + "source": "lipid21.lib", + "source_sha256": "03fab780a94ff7f80f912cf08e80967ef63bae3ae5d9b204bb88bee51f1fae3d", + "source_license": "Public Domain (AmberTools dat/leap)", + "template_count": 16, + "templates": [ + { + "template": "AR", + "source_unit_name": "AR", + "atom_count": 50, + "bond_count": 49, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 35, + 35 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + }, + { + "template": "CHL", + "source_unit_name": "CHL", + "atom_count": 74, + "bond_count": 77, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": null, + "source_connect_indices": [ + 0, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "DHA", + "source_unit_name": "DHA", + "atom_count": 52, + "bond_count": 51, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 34, + 34 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + }, + { + "template": "LAL", + "source_unit_name": "LAL", + "atom_count": 34, + "bond_count": 33, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 32, + 32 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + }, + { + "template": "MY", + "source_unit_name": "MY", + "atom_count": 40, + "bond_count": 39, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 38, + 38 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + }, + { + "template": "OL", + "source_unit_name": "OL", + "atom_count": 50, + "bond_count": 49, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 1, + 1 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + }, + { + "template": "PA", + "source_unit_name": "PA", + "atom_count": 46, + "bond_count": 45, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 44, + 44 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + }, + { + "template": "PC", + "source_unit_name": "PC", + "atom_count": 38, + "bond_count": 37, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 37 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PE", + "source_unit_name": "PE", + "atom_count": 29, + "bond_count": 28, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 28 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PGR", + "source_unit_name": "PGR", + "atom_count": 31, + "bond_count": 30, + "total_charge": -1.0, + "expected_integer_charge": -1, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 28 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PGS", + "source_unit_name": "PGS", + "atom_count": 31, + "bond_count": 30, + "total_charge": -1.0, + "expected_integer_charge": -1, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 28 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PH-", + "source_unit_name": "PH-", + "atom_count": 20, + "bond_count": 19, + "total_charge": -1.0, + "expected_integer_charge": -1, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 19 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PS", + "source_unit_name": "PS", + "atom_count": 31, + "bond_count": 30, + "total_charge": -1.0, + "expected_integer_charge": -1, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 28 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "SA", + "source_unit_name": "SA", + "atom_count": 44, + "bond_count": 43, + "total_charge": -0.069718, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 43, + 43 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2R", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "C13", + "H2R", + "C12" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "explicit_sa_alkene", + "tail_next_atom": "C13", + "tail_reference_atom": "H2R", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "C13", + "H2R", + "C12" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "explicit_sa_alkene" + }, + { + "template": "SPM", + "source_unit_name": "SPM", + "atom_count": 37, + "bond_count": 36, + "total_charge": 0.069721, + "expected_integer_charge": 0, + "head_atom": "C11", + "tail_atom": "C1", + "source_connect_indices": [ + 32, + 34 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "N11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "N11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "N11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "explicit_spm_amide", + "tail_next_atom": "C2", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "C2", + "C1" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "O22", + "C2", + "C1" + ], + "parameter_degrees": -120.0 + } + ], + "tail_rule_source": "explicit_spm_sphingosine" + }, + { + "template": "ST", + "source_unit_name": "ST", + "atom_count": 52, + "bond_count": 51, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C12", + "tail_atom": "C12", + "source_connect_indices": [ + 50, + 50 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "C13", + "head_reference_atom": "H2S", + "head_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": -120.0 + } + ], + "head_rule_source": "standard_chain", + "tail_next_atom": "C13", + "tail_reference_atom": "H2S", + "tail_link_conditions": [ + { + "atoms": [ + "H2R", + "C12" + ], + "parameter_degrees": 109.5 + }, + { + "atoms": [ + "H2S", + "H2R", + "C12" + ], + "parameter_degrees": 120.0 + } + ], + "tail_rule_source": "standard_chain" + } + ] +} diff --git a/src/Xponge/forcefield/amber/lipid_ext.mol2 b/src/Xponge/forcefield/amber/lipid_ext.mol2 new file mode 100644 index 0000000..21472f8 --- /dev/null +++ b/src/Xponge/forcefield/amber/lipid_ext.mol2 @@ -0,0 +1,3735 @@ +@MOLECULE +LIPID_EXT + 1842 1847 38 0 1 +SMALL +USER_CHARGES +@ATOM + 1 C11 -3.575000 3.389000 -1.076000 cC 1 2-A 0.756909 + 2 O12 -4.376000 4.166000 -0.626000 oC 1 2-A -0.710418 + 3 O11 -3.661000 2.086000 -0.861000 oS 1 2-A -0.422409 + 4 C1 -4.454000 1.634000 0.212000 cA 1 2-A 0.326256 + 5 HR -5.506000 1.755000 -0.026000 hE 1 2-A -0.052762 + 6 HS -4.230000 2.224000 1.091000 hE 1 2-A -0.052762 + 7 C2 -4.140000 0.180000 0.497000 cA 1 2-A 0.688729 + 8 HX -4.674000 -0.105000 1.392000 hE 1 2-A -0.102106 + 9 C3 -2.655000 -0.116000 0.678000 cA 1 2-A -0.137488 + 10 HA -2.205000 0.689000 1.247000 hE 1 2-A 0.079052 + 11 HB -2.158000 -0.142000 -0.278000 hE 1 2-A 0.079052 + 12 O31 -2.506000 -1.311000 1.393000 Os 1 2-A -0.397242 + 13 P31 -1.858000 -2.691000 0.766000 P 1 2-A 1.127927 + 14 O32 -0.661000 -2.133000 -0.136000 Os 1 2-A -0.510071 + 15 O33 -2.864000 -3.279000 -0.166000 O2 1 2-A -0.828835 + 16 O34 -1.405000 -3.472000 1.937000 O2 1 2-A -0.828835 + 17 O21 -4.631000 -0.628000 -0.587000 oS 1 2-A -0.532309 + 18 C21 -5.608000 -1.480000 -0.426000 cC 1 2-A 0.695200 + 19 O22 -6.448000 -1.421000 0.431000 oC 1 2-A -0.673764 + 20 C31 0.619000 -1.640000 0.272000 Cp 1 2-A 0.727620 + 21 H1A 0.819000 -1.993000 1.277000 H1 1 2-A -0.045238 + 22 C32 0.661000 -0.107000 0.232000 Cg 1 2-A -0.574564 + 23 H2A -0.006000 0.265000 0.997000 H1 1 2-A 0.272118 + 24 C33 2.049000 0.518000 0.565000 Cp 1 2-A 0.420177 + 25 H3A 2.250000 0.323000 1.617000 H1 1 2-A -0.026325 + 26 C34 3.229000 -0.115000 -0.243000 Cp 1 2-A 0.151615 + 27 H4A 3.195000 0.254000 -1.262000 H1 1 2-A 0.090332 + 28 C35 3.063000 -1.654000 -0.254000 Cg 1 2-A 0.193480 + 29 H5A 3.238000 -1.986000 0.773000 H1 1 2-A 0.024519 + 30 C36 1.680000 -2.167000 -0.666000 Cg 1 2-A -0.036389 + 31 H6A 1.453000 -1.820000 -1.669000 H1 1 2-A 0.106594 + 32 O35 0.213000 0.319000 -1.027000 Oh 1 2-A -0.648348 + 33 HO5A 0.026000 1.262000 -0.891000 Ho 1 2-A 0.478738 + 34 O36 1.985000 1.901000 0.348000 Os 1 2-A -0.590654 + 35 O37 4.452000 0.210000 0.361000 Os 1 2-A -0.583038 + 36 O38 3.952000 -2.322000 -1.110000 Oh 1 2-A -0.681488 + 37 HO8A 4.883000 -2.050000 -0.865000 Ho 1 2-A 0.417336 + 38 O39 1.727000 -3.586000 -0.669000 Oh 1 2-A -0.641153 + 39 HO9A 2.628000 -3.754000 -0.927000 Ho 1 2-A 0.354696 + 40 P36 0.800000 2.950000 0.955000 P 1 2-A 1.588284 + 41 O40 -0.372000 2.743000 -0.037000 O2 1 2-A -1.002944 + 42 O41 1.409000 4.317000 0.845000 O2 1 2-A -1.002944 + 43 O42 0.461000 2.464000 2.340000 O2 1 2-A -1.002944 + 44 P37 6.019000 0.050000 -0.296000 P 1 2-A 1.414391 + 45 O45 6.898000 0.705000 0.735000 O2 1 2-A -0.969332 + 46 O44 6.226000 -1.478000 -0.359000 O2 1 2-A -0.969332 + 47 O43 5.992000 0.681000 -1.662000 O2 1 2-A -0.969332 + 48 C11 4.664000 1.827000 -0.629000 cC 2 2-B 0.894683 + 49 O12 5.757000 2.328000 -0.694000 oC 2 2-B -0.793957 + 50 O11 4.583000 0.610000 -0.112000 oS 2 2-B -0.510163 + 51 C1 3.340000 -0.059000 0.171000 cA 2 2-B -0.052197 + 52 HR 2.647000 -0.009000 -0.649000 hE 2 2-B 0.127514 + 53 HS 2.886000 0.400000 1.036000 hE 2 2-B 0.127514 + 54 C2 3.705000 -1.507000 0.425000 cA 2 2-B 0.704616 + 55 HX 4.078000 -1.962000 -0.475000 hE 2 2-B -0.086048 + 56 C3 2.567000 -2.320000 1.050000 cA 2 2-B 0.235229 + 57 HA 2.536000 -2.066000 2.106000 hE 2 2-B -0.008563 + 58 HB 2.804000 -3.379000 0.969000 hE 2 2-B -0.008563 + 59 O31 1.329000 -2.032000 0.523000 Os 2 2-B -0.599287 + 60 P31 0.902000 -2.646000 -0.957000 P 2 2-B 1.371619 + 61 O32 -0.471000 -1.867000 -1.181000 Os 2 2-B -0.591001 + 62 O33 0.673000 -4.101000 -0.785000 O2 2 2-B -0.892155 + 63 O34 1.951000 -2.218000 -1.919000 O2 2 2-B -0.892155 + 64 O21 4.775000 -1.507000 1.423000 oS 2 2-B -0.587306 + 65 C21 6.025000 -1.686000 1.093000 cC 2 2-B 0.747308 + 66 O22 6.440000 -2.335000 0.180000 oC 2 2-B -0.689617 + 67 C31 -1.188000 -0.875000 -0.402000 Cp 2 2-B 0.309534 + 68 H1A -0.923000 -1.008000 0.638000 H1 2 2-B -0.039157 + 69 C32 -2.690000 -1.130000 -0.612000 Cg 2 2-B 0.350864 + 70 H2A -2.957000 -2.117000 -0.258000 H1 2 2-B -0.050751 + 71 C33 -3.576000 -0.120000 0.160000 Cp 2 2-B 0.251710 + 72 H3A -3.359000 -0.258000 1.219000 H1 2 2-B -0.039278 + 73 C34 -3.172000 1.325000 -0.216000 Cg 2 2-B 0.350031 + 74 H4A -3.477000 1.496000 -1.245000 H1 2 2-B -0.037727 + 75 C35 -1.658000 1.570000 -0.117000 Cp 2 2-B 0.251710 + 76 H5A -1.391000 1.529000 0.938000 H1 2 2-B -0.039278 + 77 C36 -0.809000 0.533000 -0.855000 Cg 2 2-B 0.350864 + 78 H6A -1.022000 0.611000 -1.917000 H1 2 2-B -0.050751 + 79 O35 -2.952000 -1.056000 -2.007000 Oh 2 2-B -0.722166 + 80 HO5A -2.348000 -1.672000 -2.400000 Ho 2 2-B 0.419095 + 81 O36 -4.920000 -0.330000 -0.084000 Os 2 2-B -0.657855 + 82 O37 -3.808000 2.267000 0.620000 Oh 2 2-B -0.687828 + 83 HO7A -3.188000 2.978000 0.768000 Ho 2 2-B 0.375863 + 84 O38 -1.364000 2.843000 -0.635000 Os 2 2-B -0.657855 + 85 O39 0.552000 0.785000 -0.638000 Oh 2 2-B -0.722166 + 86 HO9A 0.648000 1.664000 -0.234000 Ho 2 2-B 0.419095 + 87 P36 -5.879000 -1.506000 0.759000 P 2 2-B 1.447362 + 88 O40 -5.361000 -2.847000 0.282000 O2 2 2-B -0.961025 + 89 O41 -7.271000 -1.162000 0.273000 O2 2 2-B -0.961025 + 90 O42 -5.622000 -1.234000 2.225000 O2 2 2-B -0.961025 + 91 P38 -0.455000 3.982000 0.234000 P 2 2-B 1.447362 + 92 O46 -0.260000 5.103000 -0.750000 O2 2 2-B -0.961025 + 93 O47 -1.301000 4.296000 1.442000 O2 2 2-B -0.961025 + 94 O48 0.830000 3.207000 0.563000 O2 2 2-B -0.961025 + 95 C11 -3.719000 -2.117000 -0.381000 cC 3 2-C 0.830947 + 96 O12 -4.254000 -2.257000 0.683000 oC 3 2-C -0.757575 + 97 O11 -3.342000 -0.943000 -0.866000 oS 3 2-C -0.533136 + 98 C1 -2.497000 -0.070000 -0.101000 cA 3 2-C 0.212874 + 99 HR -1.955000 -0.660000 0.620000 hE 3 2-C 0.013743 + 100 HS -1.790000 0.323000 -0.812000 hE 3 2-C 0.013743 + 101 C2 -3.268000 1.071000 0.526000 cA 3 2-C 0.886634 + 102 HX -4.053000 1.424000 -0.123000 hE 3 2-C -0.148061 + 103 C3 -2.347000 2.227000 0.906000 cA 3 2-C 0.158232 + 104 HA -2.881000 2.895000 1.582000 hE 3 2-C -0.004206 + 105 HB -1.479000 1.852000 1.431000 hE 3 2-C -0.004206 + 106 O31 -2.003000 2.899000 -0.262000 Os 3 2-C -0.611068 + 107 P31 -0.488000 3.551000 -0.412000 P 3 2-C 1.253137 + 108 O32 0.301000 2.149000 -0.524000 Os 3 2-C -0.455451 + 109 O33 -0.502000 4.305000 -1.684000 O2 3 2-C -0.860713 + 110 O34 -0.187000 4.248000 0.862000 O2 3 2-C -0.860713 + 111 O21 -3.875000 0.602000 1.762000 oS 3 2-C -0.683923 + 112 C21 -5.153000 0.428000 1.907000 cC 3 2-C 0.775566 + 113 O22 -6.026000 0.878000 1.217000 oC 3 2-C -0.701626 + 114 C31 1.673000 1.978000 -0.902000 Cp 3 2-C 0.414469 + 115 H1A 2.093000 2.952000 -1.111000 H1 3 2-C -0.066520 + 116 C32 1.779000 1.113000 -2.147000 Cg 3 2-C 0.420038 + 117 H2A 2.842000 1.076000 -2.361000 H1 3 2-C -0.132114 + 118 C33 1.279000 -0.333000 -1.926000 Cg 3 2-C 0.324039 + 119 H3A 1.876000 -0.987000 -2.561000 H1 3 2-C -0.047108 + 120 C34 1.486000 -0.852000 -0.478000 Cp 3 2-C 0.030668 + 121 H4A 0.667000 -0.490000 0.136000 H1 3 2-C 0.062593 + 122 C35 2.813000 -0.206000 0.041000 Cp 3 2-C 0.343054 + 123 H5A 3.574000 -0.339000 -0.725000 H1 3 2-C -0.074266 + 124 C36 2.546000 1.332000 0.206000 Cg 3 2-C 0.622951 + 125 H6A 2.031000 1.456000 1.156000 H1 3 2-C -0.214566 + 126 O35 1.177000 1.681000 -3.287000 Oh 3 2-C -0.770849 + 127 HO5A 0.261000 1.439000 -3.214000 Ho 3 2-C 0.374038 + 128 O36 -0.057000 -0.388000 -2.354000 Oh 3 2-C -0.739050 + 129 HO6A -0.310000 -1.340000 -2.323000 Ho 3 2-C 0.380038 + 130 O37 1.476000 -2.252000 -0.481000 Os 3 2-C -0.466452 + 131 O38 3.294000 -0.725000 1.239000 Os 3 2-C -0.587516 + 132 O39 3.745000 2.058000 0.189000 Oh 3 2-C -0.954095 + 133 HO9A 4.362000 1.632000 0.832000 Ho 3 2-C 0.506810 + 134 P37 0.094000 -3.200000 -0.655000 P 3 2-C 1.285907 + 135 O43 -0.940000 -2.657000 0.313000 O2 3 2-C -0.916989 + 136 O44 0.563000 -4.604000 -0.416000 O2 3 2-C -0.916989 + 137 O45 -0.370000 -2.961000 -2.109000 O2 3 2-C -0.916989 + 138 P38 4.956000 -0.697000 1.672000 P 3 2-C 1.376591 + 139 O46 5.235000 0.794000 1.913000 O2 3 2-C -0.953964 + 140 O47 5.005000 -1.516000 2.933000 O2 3 2-C -0.953964 + 141 O48 5.712000 -1.242000 0.486000 O2 3 2-C -0.953964 + 142 C1 4.621000 -0.885000 -1.316000 cA 4 CAM -0.053421 + 143 H11 4.198000 -0.326000 -2.148000 hA 4 CAM 0.022613 + 144 H12 4.360000 -1.925000 -1.480000 hA 4 CAM 0.022613 + 145 C2 6.144000 -0.740000 -1.365000 cA 4 CAM -0.224512 + 146 H21 6.625000 -1.365000 -0.619000 hA 4 CAM 0.065295 + 147 H22 6.505000 -1.081000 -2.334000 hA 4 CAM 0.065295 + 148 C3 6.566000 0.705000 -1.132000 cA 4 CAM 0.469740 + 149 H31 6.165000 1.325000 -1.934000 hE 4 CAM -0.016690 + 150 C4 6.013000 1.205000 0.194000 cA 4 CAM -0.418389 + 151 H41 6.524000 0.662000 0.986000 hA 4 CAM 0.131060 + 152 H42 6.271000 2.250000 0.320000 hA 4 CAM 0.131060 + 153 C5 4.511000 1.021000 0.295000 cB 4 CAM 0.009022 + 154 C6 3.737000 2.041000 0.624000 cB 4 CAM -0.278205 + 155 H61 4.194000 3.003000 0.797000 hB 4 CAM 0.143219 + 156 C7 2.246000 1.984000 0.784000 cA 4 CAM -0.027352 + 157 H71 1.961000 2.531000 1.680000 hA 4 CAM 0.039581 + 158 H72 1.779000 2.516000 -0.046000 hA 4 CAM 0.039581 + 159 C8 1.708000 0.552000 0.850000 cA 4 CAM -0.010968 + 160 H81 1.923000 0.164000 1.842000 hA 4 CAM 0.047880 + 161 C9 2.417000 -0.320000 -0.209000 cA 4 CAM -0.177806 + 162 H91 2.263000 0.193000 -1.159000 hA 4 CAM 0.056181 + 163 C10 3.964000 -0.381000 -0.002000 cA 4 CAM 0.263540 + 164 C11 1.759000 -1.708000 -0.342000 cA 4 CAM -0.030334 + 165 H111 2.184000 -2.233000 -1.192000 hA 4 CAM 0.032108 + 166 H112 1.988000 -2.314000 0.526000 hA 4 CAM 0.032108 + 167 C12 0.233000 -1.665000 -0.522000 cA 4 CAM -0.193086 + 168 H121 -0.005000 -1.200000 -1.476000 hA 4 CAM 0.026882 + 169 H122 -0.130000 -2.685000 -0.577000 hA 4 CAM 0.026882 + 170 C13 -0.453000 -0.873000 0.603000 cA 4 CAM 0.408453 + 171 C14 0.197000 0.528000 0.610000 cA 4 CAM 0.032190 + 172 H141 0.052000 0.914000 -0.401000 hA 4 CAM 0.011682 + 173 C15 -0.706000 1.363000 1.519000 cA 4 CAM -0.138414 + 174 H151 -0.423000 1.247000 2.562000 hA 4 CAM 0.032497 + 175 H152 -0.648000 2.423000 1.297000 hA 4 CAM 0.032497 + 176 C16 -2.118000 0.790000 1.259000 cA 4 CAM -0.100670 + 177 H161 -2.603000 0.529000 2.195000 hA 4 CAM 0.034016 + 178 H162 -2.758000 1.521000 0.778000 hA 4 CAM 0.034016 + 179 C17 -1.943000 -0.472000 0.364000 cA 4 CAM -0.007233 + 180 H171 -2.000000 -0.153000 -0.675000 hA 4 CAM -0.031847 + 181 C18 -0.303000 -1.606000 1.951000 cA 4 CAM -0.445030 + 182 H181 -0.829000 -1.099000 2.751000 hA 4 CAM 0.092728 + 183 H182 0.730000 -1.700000 2.258000 hA 4 CAM 0.092728 + 184 H183 -0.708000 -2.611000 1.887000 hA 4 CAM 0.092728 + 185 C19 4.352000 -1.322000 1.162000 cA 4 CAM -0.260635 + 186 H191 5.405000 -1.246000 1.401000 hA 4 CAM 0.065558 + 187 H192 4.156000 -2.359000 0.917000 hA 4 CAM 0.065558 + 188 H193 3.803000 -1.077000 2.064000 hA 4 CAM 0.065558 + 189 C20 -3.061000 -1.514000 0.589000 cD 4 CAM 0.200662 + 190 H201 -3.009000 -1.830000 1.629000 hL 4 CAM -0.040076 + 191 C21 -2.909000 -2.777000 -0.272000 cD 4 CAM -0.329365 + 192 H211 -3.805000 -3.388000 -0.213000 hL 4 CAM 0.073634 + 193 H212 -2.083000 -3.393000 0.062000 hL 4 CAM 0.073634 + 194 H213 -2.739000 -2.543000 -1.317000 hL 4 CAM 0.073634 + 195 C22 -4.480000 -0.914000 0.422000 cD 4 CAM -0.025832 + 196 H221 -5.183000 -1.694000 0.699000 hL 4 CAM 0.001234 + 197 H222 -4.616000 -0.124000 1.149000 hL 4 CAM 0.001234 + 198 C23 -4.825000 -0.405000 -0.986000 cD 4 CAM -0.080198 + 199 H231 -4.136000 0.383000 -1.271000 hL 4 CAM 0.016898 + 200 H232 -4.649000 -1.214000 -1.690000 hL 4 CAM 0.016898 + 201 C24 -6.273000 0.084000 -1.241000 cD 4 CAM 0.107119 + 202 C25 -6.625000 1.528000 -0.795000 cD 4 CAM 0.343199 + 203 H251 -7.665000 1.664000 -1.091000 hL 4 CAM -0.060375 + 204 C26 -5.815000 2.583000 -1.558000 cD 4 CAM -0.335745 + 205 H261 -4.767000 2.574000 -1.274000 hL 4 CAM 0.069883 + 206 H262 -6.195000 3.579000 -1.350000 hL 4 CAM 0.069883 + 207 H263 -5.870000 2.427000 -2.632000 hL 4 CAM 0.069883 + 208 C27 -6.559000 1.811000 0.711000 cD 4 CAM -0.335745 + 209 H271 -5.536000 1.858000 1.068000 hL 4 CAM 0.069883 + 210 H272 -7.085000 1.065000 1.297000 hL 4 CAM 0.069883 + 211 H273 -7.017000 2.773000 0.925000 hL 4 CAM 0.069883 + 212 O1 7.965000 0.845000 -1.079000 oH 4 CAM -0.645437 + 213 HO1 8.341000 0.579000 -1.907000 hO 4 CAM 0.360586 + 214 C28 -7.321000 -0.930000 -0.763000 cD 4 CAM -0.266484 + 215 H241 -6.365000 0.111000 -2.325000 hL 4 CAM -0.021943 + 216 H281 -7.374000 -1.003000 0.317000 hL 4 CAM 0.060964 + 217 H282 -7.100000 -1.923000 -1.146000 hL 4 CAM 0.060964 + 218 H283 -8.309000 -0.654000 -1.121000 hL 4 CAM 0.060964 + 219 C11A -7.763000 -0.132000 -1.263000 cC 5 CLI 0.751826 + 220 O12A -8.882000 -0.324000 -0.902000 oC 5 CLI -0.625807 + 221 O11A -7.036000 0.778000 -0.626000 oS 5 CLI -0.425552 + 222 C1A -5.768000 1.228000 -1.071000 cA 5 CLI 0.059653 + 223 HRA -5.937000 2.046000 -1.759000 hE 5 CLI 0.062481 + 224 HSA -5.213000 0.441000 -1.552000 hE 5 CLI 0.062481 + 225 C2A -4.950000 1.726000 0.135000 cA 5 CLI 0.384033 + 226 HXA -4.425000 2.627000 -0.159000 hE 5 CLI 0.022742 + 227 C3A -3.916000 0.723000 0.619000 cA 5 CLI 0.195132 + 228 HAA -3.471000 1.100000 1.534000 hE 5 CLI 0.001849 + 229 HBA -3.138000 0.671000 -0.132000 hE 5 CLI 0.001849 + 230 O31A -4.470000 -0.530000 0.866000 oT 5 CLI -0.526260 + 231 P31A -3.971000 -1.824000 0.005000 pA 5 CLI 1.303462 + 232 O32A -2.406000 -1.785000 0.451000 oT 5 CLI -0.519148 + 233 C31A -1.533000 -2.746000 -0.091000 cA 5 CLI 0.235650 + 234 H1AA -1.770000 -2.901000 -1.140000 hE 5 CLI -0.021290 + 235 H1BA -1.659000 -3.686000 0.433000 hE 5 CLI -0.021290 + 236 CC -0.080000 -2.311000 0.019000 cA 5 CLI 0.496492 + 237 HC 0.142966 -2.265557 1.087900 hE 5 CLI -0.112424 + 238 OC 0.732863 -3.264348 -0.597304 oH 5 CLI -0.728180 + 239 C31B 0.136000 -0.903000 -0.533000 cA 5 CLI 0.235650 + 240 O33A -4.046000 -1.464000 -1.437000 oP 5 CLI -0.799997 + 241 O34A -4.649000 -3.014000 0.530000 oP 5 CLI -0.799997 + 242 O21A -5.792000 2.049000 1.237000 oS 5 CLI -0.481795 + 243 C21A -6.623000 3.063000 1.134000 cC 5 CLI 0.738671 + 244 O22A -6.603000 3.871000 0.256000 oC 5 CLI -0.628388 + 245 O12B 9.476000 2.658000 -1.346000 oC 5 CLI -0.625807 + 246 C11B 9.486000 1.636000 -0.735000 cC 5 CLI 0.751826 + 247 HRB 7.251000 1.450000 -2.108000 hE 5 CLI 0.062481 + 248 O11B 8.431000 0.879000 -0.530000 oS 5 CLI -0.425552 + 249 C1B 7.172000 1.313000 -1.037000 cA 5 CLI 0.059653 + 250 O34B 2.711000 -0.952000 1.205000 oP 5 CLI -0.799997 + 251 HSB 6.916000 2.260000 -0.584000 hE 5 CLI 0.062481 + 252 O31B 3.873000 -0.399000 -0.975000 oT 5 CLI -0.526260 + 253 P31B 2.595000 -0.084000 0.004000 pA 5 CLI 1.303462 + 254 C2B 6.142000 0.256000 -0.701000 cA 5 CLI 0.384033 + 255 HXB 6.481000 -0.711000 -1.038000 hE 5 CLI 0.022742 + 256 C3B 4.787000 0.585000 -1.320000 cA 5 CLI 0.195132 + 257 O32B 1.470000 -0.708000 -0.970000 oT 5 CLI -0.519148 + 258 O21B 5.977000 0.224000 0.704000 oS 5 CLI -0.481795 + 259 HAB 4.896000 0.601000 -2.403000 hE 5 CLI 0.001849 + 260 O33B 2.452000 1.376000 0.135000 oP 5 CLI -0.799997 + 261 C21B 6.206000 -0.901000 1.379000 cC 5 CLI 0.738671 + 262 HBB 4.448000 1.557000 -0.992000 hE 5 CLI 0.001849 + 263 O22B 6.812000 -1.827000 0.940000 oC 5 CLI -0.628388 + 264 H1BB -0.141000 -0.170000 0.214000 hE 5 CLI -0.021290 + 265 H1AB -0.489000 -0.749000 -1.403000 hE 5 CLI -0.021290 + 266 HOC 0.417952 -4.138179 -0.355706 hO 5 CLI 0.403503 + 267 C1 4.962000 -1.432000 -0.579000 cA 6 ERG -0.081575 + 268 H11 4.782000 -1.269000 -1.640000 hA 6 ERG 0.017152 + 269 H12 4.620000 -2.438000 -0.361000 hA 6 ERG 0.017152 + 270 C2 6.472000 -1.354000 -0.343000 cA 6 ERG -0.067913 + 271 H21 6.729000 -1.615000 0.679000 hA 6 ERG 0.025347 + 272 H22 6.982000 -2.065000 -0.985000 hA 6 ERG 0.025347 + 273 C3 6.989000 0.044000 -0.630000 cA 6 ERG 0.402468 + 274 H31 6.786000 0.288000 -1.673000 hE 6 ERG -0.000875 + 275 C4 6.279000 1.052000 0.269000 cA 6 ERG -0.307461 + 276 H41 6.603000 0.849000 1.288000 hA 6 ERG 0.103527 + 277 H42 6.605000 2.063000 0.036000 hA 6 ERG 0.103527 + 278 C5 4.770000 0.975000 0.171000 cB 6 ERG -0.042856 + 279 C6 4.026000 2.071000 0.184000 cE 6 ERG -0.211774 + 280 H61 4.496000 3.040000 0.218000 hB 6 ERG 0.149787 + 281 C7 2.561000 2.033000 0.147000 cE 6 ERG -0.118285 + 282 C8 1.905000 0.912000 -0.116000 cB 6 ERG -0.188495 + 283 C9 2.678000 -0.374000 -0.397000 cA 6 ERG -0.003546 + 284 H91 2.816000 -0.368000 -1.481000 hA 6 ERG 0.049541 + 285 C10 4.117000 -0.411000 0.226000 cA 6 ERG 0.219962 + 286 C11 1.859000 -1.646000 -0.069000 cA 6 ERG -0.039219 + 287 H111 2.318000 -2.498000 -0.559000 hA 6 ERG 0.031400 + 288 H112 1.904000 -1.851000 0.992000 hA 6 ERG 0.031400 + 289 C12 0.377000 -1.593000 -0.471000 cA 6 ERG -0.174576 + 290 H121 0.288000 -1.569000 -1.555000 hA 6 ERG 0.023903 + 291 H122 -0.089000 -2.515000 -0.144000 hA 6 ERG 0.023903 + 292 C13 -0.325000 -0.357000 0.111000 cA 6 ERG 0.390222 + 293 C14 0.435000 0.867000 -0.444000 cA 6 ERG 0.064254 + 294 H141 0.400000 0.743000 -1.530000 hA 6 ERG 0.035094 + 295 C15 -0.460000 2.063000 -0.124000 cA 6 ERG -0.166853 + 296 H151 -0.280000 2.423000 0.883000 hA 6 ERG 0.054918 + 297 H152 -0.284000 2.897000 -0.795000 hA 6 ERG 0.054918 + 298 C16 -1.890000 1.490000 -0.262000 cA 6 ERG -0.100674 + 299 H161 -2.486000 1.727000 0.613000 hA 6 ERG 0.037844 + 300 H162 -2.413000 1.921000 -1.107000 hA 6 ERG 0.037844 + 301 C17 -1.754000 -0.053000 -0.429000 cA 6 ERG -0.044635 + 302 H171 -1.732000 -0.274000 -1.496000 hA 6 ERG -0.003299 + 303 C18 -0.313000 -0.382000 1.651000 cA 6 ERG -0.445797 + 304 H181 -0.710000 -1.319000 2.029000 hA 6 ERG 0.102795 + 305 H182 -0.915000 0.415000 2.071000 hA 6 ERG 0.102795 + 306 H183 0.687000 -0.266000 2.050000 hA 6 ERG 0.102795 + 307 C19 4.095000 -0.810000 1.722000 cA 6 ERG -0.277311 + 308 H191 5.067000 -0.663000 2.176000 hA 6 ERG 0.074538 + 309 H192 3.834000 -1.853000 1.863000 hA 6 ERG 0.074538 + 310 H193 3.386000 -0.200000 2.271000 hA 6 ERG 0.074538 + 311 C20 -2.971000 -0.805000 0.158000 cD 6 ERG 0.230774 + 312 H201 -3.043000 -0.576000 1.218000 hL 6 ERG -0.021041 + 313 C21 -2.894000 -2.333000 0.007000 cD 6 ERG -0.311021 + 314 H211 -2.093000 -2.761000 0.595000 hL 6 ERG 0.072874 + 315 H212 -2.738000 -2.620000 -1.030000 hL 6 ERG 0.072874 + 316 H213 -3.822000 -2.787000 0.338000 hL 6 ERG 0.072874 + 317 C22 -4.240000 -0.317000 -0.506000 cB 6 ERG -0.222886 + 318 C23 -5.274000 0.227000 0.111000 cB 6 ERG -0.227366 + 319 C24 -6.536000 0.716000 -0.563000 cD 6 ERG 0.116726 + 320 C25 -7.799000 -0.100000 -0.183000 cD 6 ERG 0.340891 + 321 H251 -8.635000 0.394000 -0.676000 hL 6 ERG -0.058856 + 322 C26 -8.106000 -0.122000 1.320000 cD 6 ERG -0.326183 + 323 H261 -7.341000 -0.655000 1.875000 hL 6 ERG 0.069369 + 324 H262 -9.049000 -0.628000 1.502000 hL 6 ERG 0.069369 + 325 H263 -8.189000 0.876000 1.737000 hL 6 ERG 0.069369 + 326 C27 -7.731000 -1.529000 -0.730000 cD 6 ERG -0.326183 + 327 H271 -6.924000 -2.091000 -0.270000 hL 6 ERG 0.069369 + 328 H272 -7.567000 -1.533000 -1.804000 hL 6 ERG 0.069369 + 329 H273 -8.658000 -2.061000 -0.536000 hL 6 ERG 0.069369 + 330 O1 8.377000 0.043000 -0.405000 oH 6 ERG -0.652907 + 331 HO1 8.734000 0.895000 -0.619000 hO 6 ERG 0.366836 + 332 H71 2.036000 2.965000 0.261000 hB 6 ERG 0.117272 + 333 H221 -4.284000 -0.454000 -1.578000 hB 6 ERG 0.120810 + 334 H231 -5.223000 0.369000 1.181000 hB 6 ERG 0.134174 + 335 C28 -6.720000 2.219000 -0.304000 cD 6 ERG -0.270112 + 336 H241 -6.404000 0.590000 -1.635000 hL 6 ERG -0.000617 + 337 H281 -6.778000 2.445000 0.756000 hL 6 ERG 0.066164 + 338 H282 -7.628000 2.588000 -0.773000 hL 6 ERG 0.066164 + 339 H283 -5.882000 2.778000 -0.710000 hL 6 ERG 0.066164 + 340 C11 7.355000 1.664000 -0.214000 cC 7 H2A 0.762061 + 341 O12 8.107000 1.213000 -1.022000 oC 7 H2A -0.651078 + 342 O11 6.260000 1.080000 0.207000 oS 7 H2A -0.445956 + 343 C1 5.852000 -0.152000 -0.402000 cA 7 H2A 0.194712 + 344 HR 6.656000 -0.866000 -0.322000 hE 7 H2A 0.023328 + 345 HS 5.624000 0.027000 -1.441000 hE 7 H2A 0.023328 + 346 C2 4.604000 -0.641000 0.300000 cA 7 H2A 0.550570 + 347 HX 4.298000 -1.569000 -0.156000 hE 7 H2A 0.003879 + 348 C3 3.443000 0.348000 0.256000 cA 7 H2A 0.207087 + 349 HA 3.720000 1.252000 0.783000 hE 7 H2A 0.020165 + 350 HB 2.591000 -0.087000 0.759000 hE 7 H2A 0.020165 + 351 O31 3.152000 0.686000 -1.063000 Os 7 H2A -0.629179 + 352 P31 2.015000 -0.183000 -1.870000 P 7 H2A 1.306995 + 353 O32 0.760000 0.243000 -0.952000 Os 7 H2A -0.495977 + 354 O33 2.319000 -1.620000 -1.616000 O2 7 H2A -0.809627 + 355 O34 1.927000 0.360000 -3.231000 O2 7 H2A -0.809627 + 356 O21 4.856000 -0.855000 1.703000 oS 7 H2A -0.638201 + 357 C21 5.492000 -1.925000 2.116000 cC 7 H2A 0.760014 + 358 O22 6.029000 -2.725000 1.414000 oC 7 H2A -0.637626 + 359 C31 -0.598000 -0.084000 -1.190000 Cp 7 H2A 0.144445 + 360 H1A -0.777000 -0.081000 -2.260000 H1 7 H2A 0.048090 + 361 C32 -1.464000 0.985000 -0.531000 Cg 7 H2A 0.305989 + 362 H2A -1.223000 1.944000 -0.983000 H1 7 H2A -0.009978 + 363 C33 -2.948000 0.690000 -0.806000 Cp 7 H2A 0.284594 + 364 H3A -3.048000 0.559000 -1.879000 H1 7 H2A 0.001579 + 365 C34 -3.402000 -0.647000 -0.181000 Cp 7 H2A 0.066970 + 366 H4A -3.338000 -0.628000 0.897000 H1 7 H2A 0.101395 + 367 C35 -2.465000 -1.727000 -0.756000 Cg 7 H2A 0.175272 + 368 H5A -2.684000 -1.782000 -1.823000 H1 7 H2A 0.032149 + 369 C36 -0.965000 -1.447000 -0.617000 Cg 7 H2A 0.188734 + 370 H6A -0.700000 -1.456000 0.434000 H1 7 H2A 0.051149 + 371 O35 -1.149000 1.000000 0.833000 Oh 7 H2A -0.676563 + 372 HO5A -1.626000 1.717000 1.238000 Ho 7 H2A 0.399788 + 373 O36 -3.749000 1.827000 -0.564000 Os 7 H2A -0.567002 + 374 O37 -4.698000 -0.925000 -0.608000 Os 7 H2A -0.502226 + 375 O38 -2.731000 -2.970000 -0.170000 Oh 7 H2A -0.645221 + 376 HO8A -2.085000 -3.564000 -0.527000 Ho 7 H2A 0.399462 + 377 O39 -0.323000 -2.507000 -1.290000 Oh 7 H2A -0.685723 + 378 HO9A 0.625000 -2.359000 -1.318000 Ho 7 H2A 0.416422 + 379 P36 -4.214000 2.666000 0.731000 P 7 H2A 1.324171 + 380 O40 -2.753000 3.220000 1.302000 oH 7 H2A -0.721399 + 381 O41 -4.743000 1.787000 1.788000 O2 7 H2A -0.818967 + 382 O42 -4.911000 3.862000 0.222000 O2 7 H2A -0.818967 + 383 P37 -5.932000 -1.460000 0.364000 P 7 H2A 1.359860 + 384 O43 -6.664000 -0.058000 0.706000 oH 7 H2A -0.759790 + 385 O44 -6.842000 -2.231000 -0.507000 O2 7 H2A -0.845321 + 386 O45 -5.349000 -2.023000 1.600000 O2 7 H2A -0.845321 + 387 HOP6 -2.530000 3.988000 0.793000 hO 7 H2A 0.396559 + 388 HOP7 -6.075000 0.526000 1.188000 hO 7 H2A 0.444819 + 389 C11 5.117000 1.598000 -0.769000 cC 8 H2B 0.745850 + 390 O12 6.314000 1.634000 -0.759000 oC 8 H2B -0.648756 + 391 O11 4.433000 0.481000 -0.589000 oS 8 H2B -0.469375 + 392 C1 5.125000 -0.714000 -0.299000 cA 8 H2B 0.289479 + 393 HR 5.792000 -0.555000 0.538000 hE 8 H2B -0.019218 + 394 HS 5.718000 -1.011000 -1.156000 hE 8 H2B -0.019218 + 395 C2 4.102000 -1.783000 0.036000 cA 8 H2B 0.593490 + 396 HX 4.623000 -2.703000 0.264000 hE 8 H2B -0.132437 + 397 C3 3.095000 -2.012000 -1.081000 cA 8 H2B 0.281008 + 398 HA 3.625000 -2.327000 -1.979000 hE 8 H2B -0.053053 + 399 HB 2.590000 -1.085000 -1.300000 hE 8 H2B -0.053053 + 400 O31 2.199000 -3.002000 -0.682000 Os 8 H2B -0.529853 + 401 P31 0.635000 -2.837000 -1.154000 P 8 H2B 1.170094 + 402 O32 0.277000 -1.576000 -0.190000 Os 8 H2B -0.558200 + 403 O33 -0.097000 -4.023000 -0.665000 O2 8 H2B -0.759801 + 404 O34 0.616000 -2.415000 -2.566000 O2 8 H2B -0.759801 + 405 O21 3.392000 -1.355000 1.182000 oS 8 H2B -0.508422 + 406 C21 3.193000 -2.178000 2.200000 cC 8 H2B 0.680241 + 407 O22 3.871000 -3.134000 2.430000 oC 8 H2B -0.603818 + 408 C31 -0.739000 -0.635000 -0.458000 Cp 8 H2B 0.337572 + 409 H1A -0.895000 -0.579000 -1.530000 H1 8 H2B -0.039689 + 410 C32 -0.281000 0.731000 0.037000 Cg 8 H2B 0.194288 + 411 H2A 0.633000 0.987000 -0.484000 H1 8 H2B 0.077355 + 412 C33 -1.338000 1.801000 -0.270000 Cp 8 H2B 0.108412 + 413 H3A -1.418000 1.923000 -1.344000 H1 8 H2B 0.029228 + 414 C34 -2.713000 1.426000 0.296000 Cg 8 H2B 0.489731 + 415 H4A -2.652000 1.508000 1.377000 H1 8 H2B -0.046081 + 416 C35 -3.124000 -0.014000 -0.036000 Cp 8 H2B 0.108412 + 417 H5A -3.386000 -0.057000 -1.088000 H1 8 H2B 0.029228 + 418 C36 -2.040000 -1.056000 0.216000 Cg 8 H2B 0.194288 + 419 H6A -1.871000 -1.140000 1.284000 H1 8 H2B 0.077355 + 420 O35 -0.033000 0.667000 1.421000 Oh 8 H2B -0.624630 + 421 HO5A 0.411000 1.477000 1.646000 Ho 8 H2B 0.389674 + 422 O36 -0.982000 3.043000 0.310000 Os 8 H2B -0.578798 + 423 O37 -3.665000 2.322000 -0.205000 Oh 8 H2B -0.694473 + 424 HO7A -4.513000 1.882000 -0.300000 Ho 8 H2B 0.400954 + 425 O38 -4.241000 -0.352000 0.758000 Os 8 H2B -0.578798 + 426 O39 -2.516000 -2.278000 -0.294000 Oh 8 H2B -0.624630 + 427 HO9A -1.837000 -2.951000 -0.247000 Ho 8 H2B 0.389674 + 428 P36 0.348000 3.904000 -0.005000 P 8 H2B 1.348962 + 429 O40 1.352000 3.304000 1.185000 oH 8 H2B -0.717514 + 430 O41 0.098000 5.302000 0.392000 O2 8 H2B -0.832452 + 431 O42 0.931000 3.509000 -1.300000 O2 8 H2B -0.832452 + 432 P38 -5.735000 -0.523000 0.119000 P 8 H2B 1.348962 + 433 O46 -5.437000 -1.740000 -0.923000 oH 8 H2B -0.717514 + 434 O47 -6.627000 -0.971000 1.203000 O2 8 H2B -0.832452 + 435 O48 -6.034000 0.699000 -0.671000 O2 8 H2B -0.832452 + 436 HOP8 -4.633000 -2.194000 -0.686000 hO 8 H2B 0.391342 + 437 HOP6 1.270000 3.906000 1.912000 hO 8 H2B 0.391342 + 438 C11 -3.889000 1.445000 1.669000 cC 9 H2C 0.722526 + 439 O12 -4.860000 2.139000 1.797000 oC 9 H2C -0.630666 + 440 O11 -3.931000 0.151000 1.439000 oS 9 H2C -0.381066 + 441 C1 -5.150000 -0.510000 1.191000 cA 9 H2C -0.051403 + 442 HR -5.942000 -0.035000 1.753000 hE 9 H2C 0.088559 + 443 HS -4.994000 -1.523000 1.525000 hE 9 H2C 0.088559 + 444 C2 -5.515000 -0.538000 -0.289000 cA 9 H2C 0.504488 + 445 HX -6.529000 -0.910000 -0.364000 hE 9 H2C -0.026001 + 446 C3 -4.636000 -1.415000 -1.171000 cA 9 H2C 0.152138 + 447 HA -4.945000 -1.249000 -2.201000 hE 9 H2C 0.002847 + 448 HB -4.862000 -2.443000 -0.915000 hE 9 H2C 0.002847 + 449 O31 -3.286000 -1.145000 -1.052000 Os 9 H2C -0.500293 + 450 P31 -2.305000 -2.322000 -0.433000 P 9 H2C 1.172112 + 451 O32 -1.146000 -1.374000 0.172000 Os 9 H2C -0.390615 + 452 O33 -1.781000 -3.131000 -1.549000 O2 9 H2C -0.780357 + 453 O34 -3.048000 -2.942000 0.688000 O2 9 H2C -0.780357 + 454 O21 -5.494000 0.793000 -0.815000 oS 9 H2C -0.439175 + 455 C21 -6.564000 1.551000 -0.733000 cC 9 H2C 0.663588 + 456 O22 -7.642000 1.180000 -0.373000 oC 9 H2C -0.622461 + 457 C31 0.156000 -1.249000 -0.379000 Cp 9 H2C -0.032698 + 458 H1A 0.105000 -1.320000 -1.457000 H1 9 H2C 0.129056 + 459 C32 1.022000 -2.387000 0.185000 Cg 9 H2C 0.271556 + 460 H2A 0.653000 -3.324000 -0.219000 H1 9 H2C 0.032172 + 461 C33 2.468000 -2.208000 -0.244000 Cg 9 H2C 0.108646 + 462 H3A 2.467000 -2.219000 -1.336000 H1 9 H2C 0.047765 + 463 C34 3.070000 -0.869000 0.174000 Cp 9 H2C 0.078396 + 464 H4A 3.154000 -0.810000 1.251000 H1 9 H2C 0.137563 + 465 C35 2.203000 0.278000 -0.336000 Cp 9 H2C 0.164795 + 466 H5A 2.305000 0.331000 -1.414000 H1 9 H2C 0.056283 + 467 C36 0.724000 0.104000 0.034000 Cg 9 H2C 0.201170 + 468 H6A 0.649000 0.178000 1.115000 H1 9 H2C 0.079130 + 469 O35 0.925000 -2.407000 1.589000 Oh 9 H2C -0.699246 + 470 HO5A 0.001000 -2.322000 1.791000 Ho 9 H2C 0.426292 + 471 O36 3.253000 -3.271000 0.223000 Oh 9 H2C -0.598187 + 472 HO6A 4.161000 -2.988000 0.148000 Ho 9 H2C 0.360649 + 473 O37 4.334000 -0.853000 -0.431000 Os 9 H2C -0.524462 + 474 O38 2.567000 1.495000 0.249000 Os 9 H2C -0.531288 + 475 O39 -0.017000 1.140000 -0.562000 Oh 9 H2C -0.653343 + 476 HO9A 0.503000 1.935000 -0.474000 Ho 9 H2C 0.401494 + 477 P37 5.762000 -0.370000 0.219000 P 9 H2C 1.335481 + 478 O44 6.593000 -1.575000 0.427000 O2 9 H2C -0.815044 + 479 O43 6.313000 0.450000 -1.044000 oH 9 H2C -0.762271 + 480 O45 5.476000 0.553000 1.352000 O2 9 H2C -0.815044 + 481 P38 3.395000 2.729000 -0.449000 P 9 H2C 1.398822 + 482 O47 2.446000 3.843000 -0.659000 O2 9 H2C -0.842687 + 483 O48 4.175000 2.182000 -1.594000 O2 9 H2C -0.842687 + 484 O46 4.366000 3.068000 0.780000 oH 9 H2C -0.749404 + 485 HOP7 5.648000 1.099000 -1.318000 hO 9 H2C 0.437834 + 486 HOP8 4.818000 2.258000 1.061000 hO 9 H2C 0.403988 + 487 C11 5.795000 -1.195000 1.390000 cC 10 P2A 0.812147 + 488 O12 6.735000 -1.567000 0.753000 oC 10 P2A -0.702541 + 489 O11 5.043000 -0.165000 1.052000 oS 10 P2A -0.431899 + 490 C1 5.044000 0.264000 -0.299000 cA 10 P2A -0.055051 + 491 HR 5.009000 -0.590000 -0.955000 hE 10 P2A 0.079611 + 492 HS 5.939000 0.841000 -0.501000 hE 10 P2A 0.079611 + 493 C2 3.806000 1.126000 -0.481000 cA 10 P2A 0.528520 + 494 HX 3.818000 1.915000 0.260000 hE 10 P2A -0.007800 + 495 C3 2.504000 0.358000 -0.309000 cA 10 P2A 0.128278 + 496 HA 1.680000 1.004000 -0.572000 hE 10 P2A 0.012840 + 497 HB 2.415000 0.123000 0.742000 hE 10 P2A 0.012840 + 498 O31 2.464000 -0.798000 -1.096000 Os 10 P2A -0.511109 + 499 P31 2.081000 -2.248000 -0.425000 P 10 P2A 1.256118 + 500 O32 0.712000 -1.899000 0.359000 Os 10 P2A -0.405218 + 501 O33 3.091000 -2.558000 0.616000 O2 10 P2A -0.824901 + 502 O34 1.809000 -3.167000 -1.546000 O2 10 P2A -0.824901 + 503 O21 3.969000 1.686000 -1.782000 oS 10 P2A -0.465132 + 504 C21 3.529000 2.884000 -2.158000 cC 10 P2A 0.700521 + 505 O22 3.840000 3.279000 -3.242000 oC 10 P2A -0.647372 + 506 C31 -0.463000 -1.319000 -0.235000 Cp 10 P2A 0.119208 + 507 H1A -0.227000 -0.983000 -1.238000 H1 10 P2A 0.045113 + 508 C32 -0.827000 -0.126000 0.623000 Cg 10 P2A 0.065307 + 509 H2A -0.013000 0.573000 0.584000 H1 10 P2A 0.014445 + 510 C33 -2.081000 0.579000 0.114000 Cp 10 P2A 0.898544 + 511 H3A -1.884000 0.876000 -0.911000 H1 10 P2A -0.167481 + 512 C34 -3.303000 -0.371000 0.101000 Cp 10 P2A 0.333334 + 513 H4A -3.565000 -0.634000 1.120000 H1 10 P2A -0.064227 + 514 C35 -2.924000 -1.673000 -0.685000 Cg 10 P2A 0.327056 + 515 H5A -2.834000 -1.371000 -1.733000 H1 10 P2A -0.054116 + 516 C36 -1.590000 -2.333000 -0.298000 Cg 10 P2A 0.092467 + 517 H6A -1.711000 -2.773000 0.688000 H1 10 P2A 0.030424 + 518 O35 -0.994000 -0.530000 1.977000 Oh 10 P2A -0.764615 + 519 HO5A -0.263000 -1.104000 2.167000 Ho 10 P2A 0.427594 + 520 O36 -2.301000 1.758000 0.873000 Os 10 P2A -0.703320 + 521 O37 -4.359000 0.253000 -0.538000 Os 10 P2A -0.678037 + 522 O38 -3.888000 -2.660000 -0.542000 Oh 10 P2A -0.731915 + 523 HO8A -4.783000 -2.267000 -0.706000 Ho 10 P2A 0.419801 + 524 O39 -1.275000 -3.348000 -1.229000 Oh 10 P2A -0.622424 + 525 HO9A -0.329000 -3.443000 -1.283000 Ho 10 P2A 0.364099 + 526 P36 -1.186000 2.914000 1.109000 P 10 P2A 1.408463 + 527 O41 -0.132000 2.830000 0.051000 O2 10 P2A -0.886444 + 528 O40 -0.537000 2.351000 2.513000 oH 10 P2A -0.769430 + 529 O42 -1.826000 4.209000 1.396000 O2 10 P2A -0.886444 + 530 P37 -6.024000 -0.126000 -0.247000 P 10 P2A 1.290619 + 531 O43 -6.169000 -1.487000 -0.935000 O2 10 P2A -0.893617 + 532 O44 -6.153000 -0.196000 1.248000 O2 10 P2A -0.893617 + 533 O45 -6.741000 0.987000 -0.951000 O2 10 P2A -0.893617 + 534 HOP6 -0.797000 1.443000 2.633000 hO 10 P2A 0.438268 + 535 C11 7.060000 2.352000 -1.144000 cC 11 P2B 0.730545 + 536 O12 6.605000 3.225000 -1.819000 oC 11 P2B -0.660901 + 537 O11 6.414000 1.302000 -0.716000 oS 11 P2B -0.441474 + 538 C1 5.016000 1.147000 -1.017000 cA 11 P2B 0.192044 + 539 HR 4.877000 1.254000 -2.083000 hE 11 P2B 0.042436 + 540 HS 4.465000 1.924000 -0.508000 hE 11 P2B 0.042436 + 541 C2 4.593000 -0.227000 -0.546000 cA 11 P2B 0.410087 + 542 HX 5.244000 -0.976000 -0.970000 hE 11 P2B -0.010511 + 543 C3 3.137000 -0.529000 -0.891000 cA 11 P2B 0.353759 + 544 HA 2.993000 -0.362000 -1.959000 hE 11 P2B -0.054166 + 545 HB 2.490000 0.149000 -0.357000 hE 11 P2B -0.054166 + 546 O31 2.879000 -1.855000 -0.593000 Os 11 P2B -0.567863 + 547 P31 1.596000 -2.285000 0.384000 P 11 P2B 1.155359 + 548 O32 0.426000 -1.516000 -0.412000 Os 11 P2B -0.421547 + 549 O33 1.823000 -1.659000 1.711000 O2 11 P2B -0.796243 + 550 O34 1.522000 -3.746000 0.241000 O2 11 P2B -0.796243 + 551 O21 4.724000 -0.246000 0.868000 oS 11 P2B -0.512011 + 552 C21 5.304000 -1.265000 1.484000 cC 11 P2B 0.674225 + 553 O22 6.159000 -1.944000 0.997000 oC 11 P2B -0.615485 + 554 C31 -0.657000 -0.780000 0.152000 Cp 11 P2B 0.201980 + 555 H1A -0.618000 -0.884000 1.229000 H1 11 P2B 0.075741 + 556 C32 -2.014000 -1.288000 -0.375000 Cg 11 P2B 0.098853 + 557 H2A -2.128000 -2.319000 -0.069000 H1 11 P2B 0.127580 + 558 C33 -3.231000 -0.512000 0.228000 Cp 11 P2B 0.086707 + 559 H3A -3.253000 -0.711000 1.302000 H1 11 P2B 0.001942 + 560 C34 -3.059000 1.016000 0.040000 Cp 11 P2B 0.147422 + 561 H4A -3.241000 1.260000 -0.996000 H1 11 P2B 0.092536 + 562 C35 -1.662000 1.456000 0.470000 Cg 11 P2B 0.184854 + 563 H5A -1.583000 1.287000 1.544000 H1 11 P2B 0.009556 + 564 C36 -0.533000 0.691000 -0.204000 Cg 11 P2B 0.167961 + 565 H6A -0.610000 0.795000 -1.280000 H1 11 P2B 0.039453 + 566 O35 -2.033000 -1.196000 -1.767000 Oh 11 P2B -0.598891 + 567 HO5A -2.789000 -1.771000 -2.015000 Ho 11 P2B 0.355304 + 568 O36 -4.421000 -0.875000 -0.363000 Os 11 P2B -0.454710 + 569 O37 -3.979000 1.737000 0.872000 Os 11 P2B -0.428157 + 570 O38 -1.402000 2.826000 0.216000 Oh 11 P2B -0.659802 + 571 HO8A -2.113000 3.338000 0.596000 Ho 11 P2B 0.391211 + 572 O39 0.693000 1.255000 0.233000 Oh 11 P2B -0.639403 + 573 HO9A 0.515000 2.184000 0.307000 Ho 11 P2B 0.363947 + 574 P36 -4.909000 -2.512000 -0.633000 P 11 P2B 1.272799 + 575 O40 -4.088000 -2.873000 -1.870000 O2 11 P2B -0.908360 + 576 O41 -6.383000 -2.396000 -0.882000 O2 11 P2B -0.908360 + 577 O42 -4.489000 -3.233000 0.620000 O2 11 P2B -0.908360 + 578 P37 -4.845000 3.048000 0.542000 P 11 P2B 1.291905 + 579 O45 -5.166000 3.200000 -0.894000 O2 11 P2B -0.846456 + 580 O44 -5.833000 3.229000 1.619000 O2 11 P2B -0.846456 + 581 O43 -3.683000 4.261000 0.765000 oH 11 P2B -0.774356 + 582 HOP7 -3.620000 4.649000 -0.098000 hO 11 P2B 0.393279 + 583 C11 -4.138000 2.492000 -0.367000 cC 12 P2C 0.795714 + 584 O12 -4.745000 2.452000 -1.396000 oC 12 P2C -0.679312 + 585 O11 -3.819000 1.419000 0.335000 oS 12 P2C -0.554668 + 586 C1 -3.870000 0.135000 -0.275000 cA 12 P2C 0.220587 + 587 HR -3.076000 0.037000 -1.000000 hE 12 P2C 0.015668 + 588 HS -4.820000 -0.011000 -0.766000 hE 12 P2C 0.015668 + 589 C2 -3.649000 -0.869000 0.834000 cA 12 P2C 0.769565 + 590 HX -2.847000 -0.519000 1.461000 hE 12 P2C -0.069719 + 591 C3 -3.268000 -2.270000 0.351000 cA 12 P2C 0.114940 + 592 HA -3.787000 -2.528000 -0.562000 hE 12 P2C -0.014072 + 593 HB -3.557000 -2.991000 1.112000 hE 12 P2C -0.014072 + 594 O31 -1.890000 -2.287000 0.200000 Os 12 P2C -0.524902 + 595 P31 -1.237000 -2.657000 -1.281000 P 12 P2C 1.280648 + 596 O32 0.297000 -2.475000 -0.924000 Os 12 P2C -0.628041 + 597 O33 -1.713000 -1.602000 -2.219000 O2 12 P2C -0.815348 + 598 O34 -1.532000 -4.073000 -1.571000 O2 12 P2C -0.815348 + 599 O21 -4.777000 -0.873000 1.761000 oS 12 P2C -0.564226 + 600 C21 -5.959000 -1.329000 1.457000 cC 12 P2C 0.700137 + 601 O22 -6.285000 -1.857000 0.438000 oC 12 P2C -0.669656 + 602 C31 0.998000 -1.386000 -0.308000 Cp 12 P2C 0.303269 + 603 H1A 0.727000 -1.379000 0.742000 H1 12 P2C -0.091106 + 604 C32 0.628000 -0.027000 -0.936000 Cg 12 P2C 0.367127 + 605 H2A -0.398000 0.213000 -0.676000 H1 12 P2C -0.020342 + 606 C33 1.494000 1.098000 -0.354000 Cp 12 P2C 0.428831 + 607 H3A 1.288000 1.138000 0.712000 H1 12 P2C -0.108613 + 608 C34 2.987000 0.829000 -0.536000 Cg 12 P2C 0.633258 + 609 H4A 3.213000 0.849000 -1.598000 H1 12 P2C -0.095924 + 610 C35 3.366000 -0.532000 0.039000 Cp 12 P2C -0.244410 + 611 H5A 3.247000 -0.461000 1.117000 H1 12 P2C 0.079517 + 612 C36 2.493000 -1.699000 -0.424000 Cg 12 P2C 0.668691 + 613 H6A 2.703000 -1.892000 -1.473000 H1 12 P2C -0.118479 + 614 O35 0.747000 -0.080000 -2.331000 Oh 12 P2C -0.784413 + 615 HO5A -0.023000 -0.556000 -2.632000 Ho 12 P2C 0.433468 + 616 O36 1.144000 2.328000 -0.952000 Os 12 P2C -0.705596 + 617 O37 3.731000 1.831000 0.118000 Oh 12 P2C -0.809675 + 618 O38 4.689000 -0.818000 -0.287000 Os 12 P2C -0.591180 + 619 O39 2.807000 -2.830000 0.344000 Oh 12 P2C -0.805470 + 620 HO9A 3.644000 -2.667000 0.802000 Ho 12 P2C 0.502977 + 621 P36 0.637000 3.635000 -0.124000 P 12 P2C 1.495808 + 622 O40 1.889000 3.849000 0.886000 oH 12 P2C -0.839409 + 623 O41 -0.559000 3.290000 0.697000 O2 12 P2C -0.891525 + 624 O42 0.550000 4.757000 -1.086000 O2 12 P2C -0.891525 + 625 P38 5.786000 -0.922000 1.013000 P 12 P2C 1.429626 + 626 O46 5.641000 0.455000 1.643000 O2 12 P2C -0.946131 + 627 O47 5.194000 -2.054000 1.834000 O2 12 P2C -0.946131 + 628 O48 7.106000 -1.205000 0.359000 O2 12 P2C -0.946131 + 629 HO7A 4.455000 1.418000 0.629000 Ho 12 P2C 0.470030 + 630 HOP6 2.628000 3.279000 0.658000 hO 12 P2C 0.459895 + 631 C11 6.537000 0.428000 1.920000 cC 13 P2D 0.689854 + 632 O12 7.417000 0.801000 1.200000 oC 13 P2D -0.656744 + 633 O11 5.267000 0.387000 1.634000 oS 13 P2D -0.337689 + 634 C1 4.769000 0.766000 0.336000 cA 13 P2D -0.041179 + 635 HR 5.440000 1.489000 -0.099000 hE 13 P2D 0.117964 + 636 HS 3.794000 1.192000 0.498000 hE 13 P2D 0.117964 + 637 C2 4.611000 -0.445000 -0.557000 cA 13 P2D 0.398358 + 638 HX 4.211000 -0.108000 -1.500000 hE 13 P2D 0.063774 + 639 C3 3.735000 -1.551000 0.042000 cA 13 P2D -0.086991 + 640 HA 4.294000 -2.025000 0.843000 hE 13 P2D 0.101881 + 641 HB 3.541000 -2.288000 -0.727000 hE 13 P2D 0.101881 + 642 O31 2.564000 -1.059000 0.581000 Os 13 P2D -0.447681 + 643 P31 1.384000 -0.499000 -0.447000 P 13 P2D 1.356889 + 644 O32 0.189000 -0.694000 0.564000 Os 13 P2D -0.709135 + 645 O33 1.347000 -1.429000 -1.599000 O2 13 P2D -0.836054 + 646 O34 1.691000 0.940000 -0.673000 O2 13 P2D -0.836054 + 647 O21 5.893000 -1.077000 -0.777000 oS 13 P2D -0.578576 + 648 C21 6.744000 -0.585000 -1.648000 cC 13 P2D 0.803819 + 649 O22 6.543000 0.335000 -2.376000 oC 13 P2D -0.680444 + 650 C31 -1.226000 -0.392000 0.508000 Cp 13 P2D 0.427023 + 651 H1A -1.498000 -0.351000 1.554000 H1 13 P2D -0.060079 + 652 C32 -2.005000 -1.512000 -0.169000 Cg 13 P2D 0.163960 + 653 H2A -1.765000 -2.459000 0.305000 H1 13 P2D 0.019814 + 654 C33 -3.498000 -1.258000 0.057000 Cp 13 P2D 0.338739 + 655 H3A -3.638000 -1.264000 1.136000 H1 13 P2D -0.061969 + 656 C34 -3.938000 0.130000 -0.457000 Cg 13 P2D 0.233351 + 657 H4A -3.858000 0.122000 -1.542000 H1 13 P2D 0.003650 + 658 C35 -3.040000 1.285000 0.056000 Cp 13 P2D 0.232932 + 659 H5A -3.245000 1.451000 1.106000 H1 13 P2D 0.009091 + 660 C36 -1.543000 0.962000 -0.123000 Cg 13 P2D 0.482319 + 661 H6A -1.333000 0.926000 -1.186000 H1 13 P2D -0.063673 + 662 O35 -1.694000 -1.566000 -1.542000 Oh 13 P2D -0.789807 + 663 HO5A -0.767000 -1.753000 -1.644000 Ho 13 P2D 0.486650 + 664 O36 -4.250000 -2.259000 -0.527000 Os 13 P2D -0.594776 + 665 O37 -5.254000 0.384000 -0.075000 Oh 13 P2D -0.685544 + 666 O38 -3.344000 2.459000 -0.670000 Os 13 P2D -0.605970 + 667 O39 -0.748000 1.969000 0.472000 Oh 13 P2D -0.853614 + 668 HO9A 0.143000 1.843000 0.150000 Ho 13 P2D 0.508400 + 669 P36 -5.386000 -3.113000 0.451000 P 13 P2D 1.483521 + 670 O40 -5.948000 -4.129000 -0.503000 O2 13 P2D -0.972667 + 671 O41 -6.339000 -1.994000 0.850000 O2 13 P2D -0.972667 + 672 O42 -4.561000 -3.656000 1.592000 O2 13 P2D -0.972667 + 673 P38 -3.423000 3.983000 -0.082000 P 13 P2D 1.423657 + 674 O48 -4.253000 4.793000 -0.999000 O2 13 P2D -0.891826 + 675 O47 -3.684000 3.951000 1.377000 O2 13 P2D -0.891826 + 676 O46 -1.873000 4.458000 -0.324000 oH 13 P2D -0.771853 + 677 HOP8 -1.315000 3.766000 0.023000 hO 13 P2D 0.411346 + 678 HO7A -5.684000 -0.447000 0.198000 Ho 13 P2D 0.422648 + 679 C11 5.341000 -2.414000 -1.019000 cC 14 P2E 0.664437 + 680 O12 6.266000 -2.927000 -0.461000 oC 14 P2E -0.620198 + 681 O11 5.101000 -1.114000 -0.978000 oS 14 P2E -0.417732 + 682 C1 5.666000 -0.349000 0.070000 cA 14 P2E 0.098037 + 683 HR 6.675000 -0.057000 -0.193000 hE 14 P2E 0.024054 + 684 HS 5.690000 -0.938000 0.972000 hE 14 P2E 0.024054 + 685 C2 4.790000 0.864000 0.306000 cA 14 P2E 0.662336 + 686 HX 5.165000 1.382000 1.178000 hE 14 P2E -0.019546 + 687 C3 3.313000 0.523000 0.473000 cA 14 P2E 0.116542 + 688 HA 2.938000 0.124000 -0.458000 hE 14 P2E 0.048468 + 689 HB 2.749000 1.416000 0.707000 hE 14 P2E 0.048468 + 690 O31 3.224000 -0.405000 1.507000 Os 14 P2E -0.575343 + 691 P31 1.931000 -1.435000 1.521000 P 14 P2E 1.422469 + 692 O32 0.828000 -0.338000 1.183000 Os 14 P2E -0.679084 + 693 O33 1.847000 -1.996000 2.879000 O2 14 P2E -0.854854 + 694 O34 2.089000 -2.340000 0.341000 O2 14 P2E -0.854854 + 695 O21 4.852000 1.765000 -0.816000 oS 14 P2E -0.607431 + 696 C21 5.813000 2.643000 -0.928000 cC 14 P2E 0.773366 + 697 O22 6.763000 2.734000 -0.208000 oC 14 P2E -0.689523 + 698 C31 -0.601000 -0.392000 1.228000 Cp 14 P2E 0.292448 + 699 H1A -0.891000 -0.366000 2.273000 H1 14 P2E 0.026790 + 700 C32 -1.119000 -1.676000 0.596000 Cg 14 P2E 0.227578 + 701 H2A -0.832000 -2.522000 1.220000 H1 14 P2E 0.016314 + 702 C33 -2.641000 -1.643000 0.560000 Cg 14 P2E 0.212117 + 703 H3A -2.984000 -1.542000 1.588000 H1 14 P2E -0.042301 + 704 C34 -3.207000 -0.441000 -0.219000 Cp 14 P2E 0.316893 + 705 H4A -2.885000 -0.492000 -1.250000 H1 14 P2E 0.049186 + 706 C35 -2.696000 0.890000 0.399000 Cp 14 P2E -0.148942 + 707 H5A -3.134000 1.000000 1.388000 H1 14 P2E 0.139154 + 708 C36 -1.139000 0.866000 0.542000 Cg 14 P2E 0.161906 + 709 H6A -0.740000 0.877000 -0.473000 H1 14 P2E 0.080961 + 710 O35 -0.612000 -1.872000 -0.697000 Oh 14 P2E -0.679338 + 711 HO5A 0.324000 -2.035000 -0.601000 Ho 14 P2E 0.428284 + 712 O36 -3.117000 -2.893000 0.110000 Oh 14 P2E -0.730092 + 713 O37 -4.627000 -0.493000 -0.176000 Os 14 P2E -0.568427 + 714 O38 -3.064000 1.944000 -0.416000 Os 14 P2E -0.470721 + 715 O39 -0.662000 1.942000 1.276000 Oh 14 P2E -0.676949 + 716 HO9A -1.073000 2.781000 0.939000 Ho 14 P2E 0.460850 + 717 P38 -3.293000 3.568000 0.140000 P 14 P2E 1.439006 + 718 O46 -3.979000 4.224000 -1.020000 O2 14 P2E -0.945105 + 719 O47 -4.067000 3.437000 1.422000 O2 14 P2E -0.945105 + 720 O48 -1.851000 4.042000 0.348000 O2 14 P2E -0.945105 + 721 HO6A -3.369000 -2.812000 -0.815000 Ho 14 P2E 0.408317 + 722 P37 -5.558000 -1.521000 -1.017000 P 14 P2E 1.488794 + 723 O43 -5.934000 -2.605000 0.162000 oH 14 P2E -0.836642 + 724 O44 -6.826000 -0.898000 -1.427000 O2 14 P2E -0.907984 + 725 O45 -4.692000 -2.237000 -2.006000 O2 14 P2E -0.907984 + 726 HOP7 -5.106000 -2.970000 0.459000 hO 14 P2E 0.492432 + 727 C11 5.476000 3.584000 -1.093000 cC 15 P2F 0.803476 + 728 O12 6.500000 3.869000 -0.549000 oC 15 P2F -0.685548 + 729 O11 4.944000 2.384000 -1.094000 oS 15 P2F -0.495454 + 730 C1 5.537000 1.356000 -0.304000 cA 15 P2F 0.105867 + 731 HR 5.543000 1.664000 0.733000 hE 15 P2F 0.074920 + 732 HS 6.555000 1.196000 -0.629000 hE 15 P2F 0.074920 + 733 C2 4.705000 0.098000 -0.494000 cA 15 P2F 0.434756 + 734 HX 4.724000 -0.203000 -1.529000 hE 15 P2F 0.060104 + 735 C3 3.265000 0.222000 -0.012000 cA 15 P2F 0.223271 + 736 HA 2.781000 1.020000 -0.566000 hE 15 P2F -0.002397 + 737 HB 3.248000 0.468000 1.041000 hE 15 P2F -0.002397 + 738 O31 2.608000 -0.971000 -0.258000 Os 15 P2F -0.624798 + 739 P31 2.078000 -1.966000 0.963000 P 15 P2F 1.262631 + 740 O32 0.551000 -2.142000 0.567000 Os 15 P2F -0.420941 + 741 O33 2.228000 -1.208000 2.232000 O2 15 P2F -0.814482 + 742 O34 2.778000 -3.261000 0.793000 O2 15 P2F -0.814482 + 743 O21 5.328000 -0.908000 0.297000 oS 15 P2F -0.542863 + 744 C21 5.916000 -1.947000 -0.275000 cC 15 P2F 0.737851 + 745 O22 6.352000 -1.934000 -1.387000 oC 15 P2F -0.668610 + 746 C31 -0.398000 -1.149000 0.145000 Cp 15 P2F 0.180848 + 747 H1A -0.144000 -0.886000 -0.876000 H1 15 P2F 0.063871 + 748 C32 -0.375000 0.109000 1.016000 Cg 15 P2F 0.039690 + 749 H2A 0.580000 0.612000 0.890000 H1 15 P2F 0.070044 + 750 C33 -1.436000 1.111000 0.548000 Cg 15 P2F 0.552859 + 751 H3A -1.227000 1.292000 -0.515000 H1 15 P2F -0.159075 + 752 C34 -2.870000 0.543000 0.591000 Cp 15 P2F 0.494715 + 753 H4A -3.165000 0.374000 1.620000 H1 15 P2F -0.072591 + 754 C35 -2.882000 -0.782000 -0.196000 Cp 15 P2F 0.623087 + 755 H5A -2.758000 -0.517000 -1.241000 H1 15 P2F -0.052530 + 756 C36 -1.781000 -1.798000 0.151000 Cg 15 P2F -0.118028 + 757 H6A -1.966000 -2.173000 1.153000 H1 15 P2F 0.067150 + 758 O35 -0.531000 -0.226000 2.369000 Oh 15 P2F -0.758340 + 759 HO5A 0.296000 -0.616000 2.636000 Ho 15 P2F 0.467685 + 760 O36 -1.247000 2.281000 1.267000 Oh 15 P2F -0.756481 + 761 O37 -3.776000 1.377000 -0.058000 Os 15 P2F -0.765996 + 762 O38 -4.124000 -1.437000 -0.021000 Os 15 P2F -0.707043 + 763 O39 -1.791000 -2.864000 -0.763000 Oh 15 P2F -0.633978 + 764 HO9A -2.602000 -2.839000 -1.280000 Ho 15 P2F 0.405954 + 765 P38 -5.058000 -1.830000 -1.294000 P 15 P2F 1.583318 + 766 O46 -5.418000 -0.368000 -1.875000 oH 15 P2F -0.813162 + 767 O47 -4.190000 -2.534000 -2.290000 O2 15 P2F -0.933041 + 768 O48 -6.263000 -2.521000 -0.786000 O2 15 P2F -0.933041 + 769 HO6A -1.989000 2.900000 1.064000 Ho 15 P2F 0.392598 + 770 P37 -4.474000 2.819000 0.606000 P 15 P2F 1.345089 + 771 O43 -4.954000 2.434000 1.974000 O2 15 P2F -0.906632 + 772 O44 -3.285000 3.781000 0.618000 O2 15 P2F -0.906632 + 773 O45 -5.514000 3.134000 -0.427000 O2 15 P2F -0.906632 + 774 HOP8 -5.185000 0.351000 -1.280000 hO 15 P2F 0.430470 + 775 C11 -4.471000 2.516000 -1.291000 cC 16 P3- 0.848648 + 776 O12 -5.481000 2.789000 -1.911000 oC 16 P3- -0.870090 + 777 O11 -4.151000 1.262000 -1.117000 oS 16 P3- -0.423996 + 778 C1 -2.980000 0.879000 -0.333000 cA 16 P3- 0.027562 + 779 HR -2.098000 1.326000 -0.777000 hE 16 P3- 0.184001 + 780 HS -3.090000 1.240000 0.678000 hE 16 P3- 0.184001 + 781 C2 -2.864000 -0.634000 -0.288000 cA 16 P3- 0.554084 + 782 HX -2.114000 -0.858000 0.452000 hE 16 P3- -0.127683 + 783 C3 -2.442000 -1.308000 -1.587000 cA 16 P3- 0.309347 + 784 HA -3.294000 -1.354000 -2.265000 hE 16 P3- -0.071957 + 785 HB -1.682000 -0.706000 -2.063000 hE 16 P3- -0.071957 + 786 O31 -1.989000 -2.606000 -1.318000 Os 16 P3- -0.517728 + 787 P31 -0.599000 -3.226000 -1.975000 P 16 P3- 1.249891 + 788 O32 0.575000 -2.717000 -1.018000 Os 16 P3- -0.597556 + 789 O33 -0.725000 -4.701000 -1.810000 O2 16 P3- -0.883254 + 790 O34 -0.500000 -2.668000 -3.352000 O2 16 P3- -0.883254 + 791 O21 -4.149000 -1.194000 0.109000 oS 16 P3- -0.603138 + 792 C21 -4.419000 -1.712000 1.281000 cC 16 P3- 0.829113 + 793 O22 -5.549000 -2.113000 1.484000 oC 16 P3- -0.796197 + 794 C31 0.952000 -1.372000 -0.662000 Cp 16 P3- 0.502419 + 795 H1A 0.304000 -0.689000 -1.189000 H1 16 P3- 0.004943 + 796 C32 2.399000 -1.044000 -1.096000 Cg 16 P3- 0.104639 + 797 H2A 2.369000 -0.880000 -2.174000 H1 16 P3- 0.017978 + 798 C33 2.930000 0.309000 -0.432000 Cp 16 P3- 0.081622 + 799 H3A 3.355000 0.907000 -1.227000 H1 16 P3- 0.104535 + 800 C34 1.735000 1.184000 0.112000 Cp 16 P3- 0.507183 + 801 H4A 2.137000 2.019000 0.666000 H1 16 P3- -0.024494 + 802 C35 0.700000 0.415000 1.034000 Cp 16 P3- 0.081622 + 803 H5A -0.269000 0.709000 0.657000 H1 16 P3- 0.104535 + 804 C36 0.835000 -1.112000 0.847000 Cg 16 P3- 0.104639 + 805 H6A 1.753000 -1.441000 1.324000 H1 16 P3- 0.017978 + 806 O35 3.216000 -2.143000 -0.821000 Oh 16 P3- -0.629010 + 807 HO5A 4.130000 -1.834000 -0.714000 Ho 16 P3- 0.379556 + 808 O36 3.927000 0.070000 0.538000 Os 16 P3- -0.542655 + 809 O37 1.043000 1.623000 -1.046000 Os 16 P3- -0.732459 + 810 O38 0.757000 0.777000 2.402000 Os 16 P3- -0.542655 + 811 O39 -0.253000 -1.804000 1.404000 Oh 16 P3- -0.629010 + 812 HO9A -0.313000 -1.546000 2.340000 Ho 16 P3- 0.379556 + 813 P36 5.609000 -0.005000 0.241000 P 16 P3- 1.470033 + 814 O41 6.022000 1.282000 -0.437000 O2 16 P3- -1.003962 + 815 O40 6.210000 -0.207000 1.618000 O2 16 P3- -1.003962 + 816 O42 5.770000 -1.230000 -0.667000 O2 16 P3- -1.003962 + 817 P37 0.590000 3.163000 -1.616000 P 16 P3- 1.500871 + 818 O43 -0.925000 2.996000 -1.821000 O2 16 P3- -1.015975 + 819 O44 1.312000 3.346000 -2.934000 O2 16 P3- -1.015975 + 820 O45 0.951000 4.172000 -0.554000 O2 16 P3- -1.015975 + 821 P38 -0.508000 0.635000 3.509000 P 16 P3- 1.470033 + 822 O48 -0.506000 -0.844000 3.921000 O2 16 P3- -1.003962 + 823 O47 -1.794000 0.992000 2.772000 O2 16 P3- -1.003962 + 824 O46 -0.147000 1.566000 4.642000 O2 16 P3- -1.003962 + 825 C11 5.102000 -1.061000 -2.193000 cC 17 P3A 0.801165 + 826 O12 5.958000 -1.732000 -2.706000 oC 17 P3A -0.718168 + 827 O11 5.470000 -0.229000 -1.228000 oS 17 P3A -0.491335 + 828 C1 4.619000 0.781000 -0.667000 cA 17 P3A 0.118893 + 829 HR 3.887000 1.118000 -1.377000 hE 17 P3A 0.041293 + 830 HS 5.287000 1.602000 -0.451000 hE 17 P3A 0.041293 + 831 C2 3.934000 0.335000 0.606000 cA 17 P3A 0.371504 + 832 HX 3.390000 -0.584000 0.439000 hE 17 P3A 0.029215 + 833 C3 2.958000 1.407000 1.144000 cA 17 P3A 0.401128 + 834 HA 3.256000 1.639000 2.161000 hE 17 P3A -0.052018 + 835 HB 1.963000 0.997000 1.180000 hE 17 P3A -0.052018 + 836 O31 2.993000 2.620000 0.428000 Os 17 P3A -0.572817 + 837 P31 1.858000 3.076000 -0.666000 P 17 P3A 1.311019 + 838 O32 0.549000 2.519000 0.062000 Os 17 P3A -0.457964 + 839 O33 2.104000 2.331000 -1.938000 O2 17 P3A -0.860904 + 840 O34 1.895000 4.553000 -0.687000 O2 17 P3A -0.860904 + 841 O21 5.003000 0.113000 1.565000 oS 17 P3A -0.507770 + 842 C21 4.963000 -0.811000 2.503000 cC 17 P3A 0.797518 + 843 O22 5.899000 -0.900000 3.258000 oC 17 P3A -0.747431 + 844 C31 -0.567000 1.761000 -0.424000 Cp 17 P3A 0.105770 + 845 H1A -1.016000 2.316000 -1.239000 H1 17 P3A 0.049147 + 846 C32 -1.593000 1.698000 0.708000 Cg 17 P3A 0.202457 + 847 H2A -1.923000 2.708000 0.915000 H1 17 P3A 0.074035 + 848 C33 -2.807000 0.928000 0.175000 Cp 17 P3A 0.170040 + 849 H3A -3.033000 1.309000 -0.816000 H1 17 P3A 0.015285 + 850 C34 -2.480000 -0.560000 0.039000 Cp 17 P3A 0.420737 + 851 H4A -2.362000 -0.997000 1.019000 H1 17 P3A 0.049804 + 852 C35 -1.184000 -0.794000 -0.804000 Cp 17 P3A 0.045385 + 853 H5A -1.547000 -0.972000 -1.807000 H1 17 P3A 0.057600 + 854 C36 -0.162000 0.376000 -0.976000 Cg 17 P3A 0.344498 + 855 H6A 0.744000 0.081000 -0.485000 H1 17 P3A 0.028441 + 856 O35 -1.085000 1.199000 1.906000 Oh 17 P3A -0.771390 + 857 HO5A -0.572000 0.386000 1.790000 Ho 17 P3A 0.462782 + 858 O36 -3.927000 1.128000 1.010000 Os 17 P3A -0.635520 + 859 O37 -3.590000 -1.161000 -0.624000 Os 17 P3A -0.604581 + 860 O38 -0.553000 -1.992000 -0.414000 Os 17 P3A -0.583910 + 861 O39 0.087000 0.489000 -2.368000 Oh 17 P3A -0.698310 + 862 HO9A 0.829000 1.087000 -2.444000 Ho 17 P3A 0.403108 + 863 P36 -5.237000 1.971000 0.530000 P 17 P3A 1.499516 + 864 O41 -6.158000 2.067000 1.689000 O2 17 P3A -0.911779 + 865 O40 -5.845000 0.936000 -0.575000 oH 17 P3A -0.865419 + 866 O42 -4.832000 3.211000 -0.181000 O2 17 P3A -0.911779 + 867 P37 -4.078000 -2.729000 -0.530000 P 17 P3A 1.415340 + 868 O44 -5.208000 -2.856000 -1.482000 O2 17 P3A -0.902105 + 869 O43 -2.815000 -3.509000 -1.182000 oH 17 P3A -0.809989 + 870 O45 -4.240000 -3.125000 0.887000 O2 17 P3A -0.902105 + 871 P38 0.718000 -2.183000 0.693000 P 17 P3A 1.349219 + 872 O46 0.537000 -1.025000 1.666000 O2 17 P3A -0.900727 + 873 O47 0.524000 -3.558000 1.237000 O2 17 P3A -0.900727 + 874 O48 1.995000 -2.010000 -0.126000 O2 17 P3A -0.900727 + 875 HOP6 -5.371000 0.106000 -0.580000 hO 17 P3A 0.532241 + 876 HOP7 -1.989000 -3.288000 -0.746000 hO 17 P3A 0.481963 + 877 C11 -4.729000 -2.166000 2.095000 cC 18 P3B 0.740141 + 878 O12 -5.877000 -1.847000 2.254000 oC 18 P3B -0.686566 + 879 O11 -3.778000 -1.372000 1.694000 oS 18 P3B -0.423924 + 880 C1 -3.995000 -0.046000 1.238000 cA 18 P3B -0.102340 + 881 HR -3.017000 0.298000 0.946000 hE 18 P3B 0.116235 + 882 HS -4.396000 0.552000 2.048000 hE 18 P3B 0.116235 + 883 C2 -4.919000 0.042000 0.023000 cA 18 P3B 0.648671 + 884 HX -5.957000 -0.015000 0.316000 hE 18 P3B -0.089401 + 885 C3 -4.646000 -0.993000 -1.060000 cA 18 P3B 0.236192 + 886 HA -5.316000 -0.753000 -1.890000 hE 18 P3B -0.013784 + 887 HB -4.927000 -1.968000 -0.685000 hE 18 P3B -0.013784 + 888 O31 -3.348000 -0.978000 -1.504000 Os 18 P3B -0.627416 + 889 P31 -2.312000 -2.280000 -1.382000 P 18 P3B 1.432019 + 890 O32 -1.227000 -1.737000 -0.342000 Os 18 P3B -0.623426 + 891 O33 -1.752000 -2.473000 -2.732000 O2 18 P3B -0.870685 + 892 O34 -3.103000 -3.353000 -0.718000 O2 18 P3B -0.870685 + 893 O21 -4.682000 1.337000 -0.553000 oS 18 P3B -0.461876 + 894 C21 -5.268000 2.417000 -0.110000 cC 18 P3B 0.725654 + 895 O22 -6.179000 2.442000 0.671000 oC 18 P3B -0.706793 + 896 C31 -0.046000 -0.979000 -0.629000 Cp 18 P3B 0.395189 + 897 H1A -0.014000 -0.783000 -1.694000 H1 18 P3B -0.054198 + 898 C32 1.202000 -1.757000 -0.228000 Cg 18 P3B 0.380601 + 899 H2A 1.308000 -2.618000 -0.879000 H1 18 P3B -0.083666 + 900 C33 2.505000 -0.925000 -0.350000 Cp 18 P3B 0.244705 + 901 H3A 2.742000 -0.787000 -1.398000 H1 18 P3B -0.088358 + 902 C34 2.456000 0.488000 0.319000 Cp 18 P3B 0.811264 + 903 H4A 2.353000 0.372000 1.392000 H1 18 P3B -0.134835 + 904 C35 1.176000 1.187000 -0.234000 Cp 18 P3B 0.244705 + 905 H5A 1.265000 1.284000 -1.310000 H1 18 P3B -0.088358 + 906 C36 -0.067000 0.340000 0.127000 Cg 18 P3B 0.380601 + 907 H6A -0.035000 0.127000 1.190000 H1 18 P3B -0.083666 + 908 O35 1.065000 -2.194000 1.107000 Oh 18 P3B -0.688843 + 909 HO5A 1.964000 -2.342000 1.390000 Ho 18 P3B 0.361111 + 910 O36 3.484000 -1.723000 0.269000 Os 18 P3B -0.678754 + 911 O37 3.591000 1.206000 0.023000 Os 18 P3B -0.684473 + 912 O38 0.951000 2.494000 0.305000 Os 18 P3B -0.678754 + 913 O39 -1.266000 1.015000 -0.168000 Oh 18 P3B -0.688843 + 914 HO9A -1.156000 1.918000 0.103000 Ho 18 P3B 0.361111 + 915 P36 4.568000 -2.689000 -0.524000 P 18 P3B 1.524427 + 916 O41 4.915000 -3.775000 0.438000 O2 18 P3B -0.912833 + 917 O40 5.777000 -1.683000 -0.739000 oH 18 P3B -0.848533 + 918 O42 3.999000 -3.080000 -1.846000 O2 18 P3B -0.912833 + 919 P37 4.892000 1.478000 1.140000 P 18 P3B 1.417488 + 920 O43 5.355000 2.869000 0.811000 O2 18 P3B -0.958319 + 921 O44 4.276000 1.279000 2.500000 O2 18 P3B -0.958319 + 922 O45 5.918000 0.412000 0.758000 O2 18 P3B -0.958319 + 923 P38 0.596000 3.846000 -0.510000 P 18 P3B 1.524427 + 924 O48 0.748000 5.004000 0.386000 O2 18 P3B -0.912833 + 925 O47 1.084000 3.803000 -1.905000 O2 18 P3B -0.912833 + 926 O46 -1.077000 3.684000 -0.687000 oH 18 P3B -0.848533 + 927 HOP6 5.769000 -0.874000 -0.139000 hO 18 P3B 0.503004 + 928 HOP8 -1.201000 3.178000 -1.480000 hO 18 P3B 0.503004 + 929 C11 3.806000 0.579000 2.423000 cC 19 P3C 0.750013 + 930 O12 4.865000 1.133000 2.541000 oC 19 P3C -0.699285 + 931 O11 3.715000 -0.693000 2.046000 oS 19 P3C -0.408160 + 932 C1 4.864000 -1.334000 1.550000 cA 19 P3C 0.182237 + 933 HR 4.647000 -2.392000 1.606000 hE 19 P3C 0.003555 + 934 HS 5.716000 -1.107000 2.176000 hE 19 P3C 0.003555 + 935 C2 5.164000 -0.906000 0.116000 cA 19 P3C 0.456599 + 936 HX 4.917000 0.130000 -0.001000 hE 19 P3C -0.008599 + 937 C3 4.421000 -1.692000 -0.963000 cA 19 P3C 0.529687 + 938 HA 4.608000 -2.756000 -0.812000 hE 19 P3C -0.099629 + 939 HB 4.847000 -1.423000 -1.926000 hE 19 P3C -0.099629 + 940 O31 3.068000 -1.470000 -0.901000 Os 19 P3C -0.644510 + 941 P31 2.449000 -0.122000 -1.688000 P 19 P3C 1.188346 + 942 O32 1.333000 0.294000 -0.643000 Os 19 P3C -0.457628 + 943 O33 1.930000 -0.542000 -3.000000 O2 19 P3C -0.813804 + 944 O34 3.579000 0.855000 -1.625000 O2 19 P3C -0.813804 + 945 O21 6.584000 -1.120000 -0.076000 oS 19 P3C -0.578888 + 946 C21 7.361000 -0.252000 -0.690000 cC 19 P3C 0.845302 + 947 O22 8.513000 -0.532000 -0.881000 oC 19 P3C -0.758144 + 948 C31 -0.100000 0.225000 -0.738000 Cp 19 P3C 0.499018 + 949 H1A -0.362000 0.060000 -1.775000 H1 19 P3C 0.024830 + 950 C32 -0.686000 1.552000 -0.236000 Cg 19 P3C -0.364111 + 951 H2A -0.326000 2.349000 -0.877000 H1 19 P3C 0.245938 + 952 C33 -2.240000 1.593000 -0.297000 Cp 19 P3C 0.116129 + 953 H3A -2.542000 1.594000 -1.342000 H1 19 P3C 0.083418 + 954 C34 -2.850000 0.345000 0.400000 Cp 19 P3C 0.231003 + 955 H4A -2.678000 0.495000 1.456000 H1 19 P3C 0.080692 + 956 C35 -2.165000 -0.984000 0.029000 Cp 19 P3C 0.308350 + 957 H5A -2.451000 -1.302000 -0.963000 H1 19 P3C 0.036618 + 958 C36 -0.634000 -0.912000 0.117000 Cg 19 P3C 0.064791 + 959 H6A -0.365000 -0.709000 1.147000 H1 19 P3C 0.088283 + 960 O35 -0.242000 1.768000 1.075000 Oh 19 P3C -0.649213 + 961 HO5A -0.463000 2.714000 1.252000 Ho 19 P3C 0.479191 + 962 O36 -2.739000 2.713000 0.361000 Os 19 P3C -0.472867 + 963 O37 -4.264000 0.262000 0.293000 Os 19 P3C -0.584399 + 964 O38 -2.567000 -1.971000 0.981000 Os 19 P3C -0.635867 + 965 O39 -0.069000 -2.133000 -0.288000 Oh 19 P3C -0.655613 + 966 HO9A -0.398000 -2.814000 0.288000 Ho 19 P3C 0.406359 + 967 P36 -2.168000 4.327000 0.248000 P 19 P3C 1.349623 + 968 O40 -1.870000 4.555000 -1.211000 O2 19 P3C -0.952129 + 969 O41 -0.915000 4.289000 1.133000 O2 19 P3C -0.952129 + 970 O42 -3.290000 5.137000 0.838000 O2 19 P3C -0.952129 + 971 P37 -5.271000 -0.259000 -0.859000 P 19 P3C 1.466113 + 972 O43 -5.437000 -1.855000 -0.473000 oH 19 P3C -0.818001 + 973 O44 -6.602000 0.335000 -0.597000 O2 19 P3C -0.898042 + 974 O45 -4.633000 -0.211000 -2.196000 O2 19 P3C -0.898042 + 975 P38 -2.971000 -3.517000 0.750000 P 19 P3C 1.407053 + 976 O48 -3.335000 -3.752000 -0.672000 O2 19 P3C -0.855123 + 977 O47 -1.972000 -4.390000 1.415000 O2 19 P3C -0.855123 + 978 O46 -4.334000 -3.551000 1.643000 oH 19 P3C -0.816657 + 979 HOP8 -4.924000 -2.907000 1.249000 hO 19 P3C 0.455938 + 980 HOP7 -4.750000 -2.382000 -0.883000 hO 19 P3C 0.438884 + 981 C11 -5.181000 -0.532000 -1.983000 cC 20 P3D 0.769265 + 982 O12 -6.324000 -0.168000 -1.870000 oC 20 P3D -0.743527 + 983 O11 -4.127000 0.227000 -1.862000 oS 20 P3D -0.510169 + 984 C1 -4.078000 1.387000 -1.039000 cA 20 P3D 0.412648 + 985 HR -5.012000 1.929000 -1.132000 hE 20 P3D 0.027454 + 986 HS -3.235000 1.964000 -1.398000 hE 20 P3D 0.027454 + 987 C2 -3.805000 1.040000 0.415000 cA 20 P3D 0.092321 + 988 HX -3.833000 1.967000 0.975000 hE 20 P3D 0.072319 + 989 C3 -2.480000 0.336000 0.674000 cA 20 P3D 0.421812 + 990 HA -2.340000 0.237000 1.744000 hE 20 P3D -0.029611 + 991 HB -1.701000 0.964000 0.263000 hE 20 P3D -0.029611 + 992 O31 -2.502000 -0.917000 0.063000 Os 20 P3D -0.571401 + 993 P31 -1.947000 -2.299000 0.749000 P 20 P3D 1.173370 + 994 O32 -0.410000 -2.329000 0.335000 Os 20 P3D -0.584188 + 995 O33 -2.659000 -3.394000 0.034000 O2 20 P3D -0.822053 + 996 O34 -2.169000 -2.157000 2.219000 O2 20 P3D -0.822053 + 997 O21 -4.878000 0.183000 0.877000 oS 20 P3D -0.452957 + 998 C21 -5.191000 0.103000 2.150000 cC 20 P3D 0.681262 + 999 O22 -5.297000 1.041000 2.889000 oC 20 P3D -0.688487 + 1000 C31 0.575000 -1.269000 0.430000 Cp 20 P3D 0.780281 + 1001 H1A 0.359000 -0.683000 1.316000 H1 20 P3D -0.038472 + 1002 C32 0.568000 -0.370000 -0.823000 Cg 20 P3D -0.037982 + 1003 H2A -0.443000 -0.136000 -1.109000 H1 20 P3D 0.067712 + 1004 C33 1.283000 0.935000 -0.457000 Cp 20 P3D 0.062292 + 1005 H3A 0.724000 1.410000 0.334000 H1 20 P3D 0.030088 + 1006 C34 2.712000 0.694000 0.147000 Cp 20 P3D 0.616096 + 1007 H4A 3.446000 1.158000 -0.498000 H1 20 P3D -0.050647 + 1008 C35 3.123000 -0.829000 0.287000 Cp 20 P3D 0.038472 + 1009 H5A 3.746000 -0.853000 1.166000 H1 20 P3D 0.047767 + 1010 C36 1.969000 -1.875000 0.533000 Cg 20 P3D -0.073736 + 1011 H6A 2.037000 -2.587000 -0.277000 H1 20 P3D 0.081016 + 1012 O35 1.116000 -1.017000 -1.948000 Oh 20 P3D -0.632741 + 1013 HO5A 2.062000 -1.121000 -1.852000 Ho 20 P3D 0.354556 + 1014 O36 1.294000 1.797000 -1.593000 Os 20 P3D -0.595066 + 1015 O37 2.767000 1.244000 1.441000 Os 20 P3D -0.643952 + 1016 O38 3.863000 -1.258000 -0.841000 Os 20 P3D -0.515003 + 1017 O39 2.168000 -2.571000 1.739000 Oh 20 P3D -0.778903 + 1018 HO9A 3.037000 -2.960000 1.576000 Ho 20 P3D 0.539426 + 1019 P36 0.207000 2.979000 -1.856000 P 20 P3D 1.711461 + 1020 O41 0.273000 3.366000 -3.296000 O2 20 P3D -0.975696 + 1021 O40 0.772000 4.191000 -0.986000 oH 20 P3D -1.105242 + 1022 O42 -1.139000 2.552000 -1.330000 O2 20 P3D -0.975696 + 1023 P37 3.064000 2.877000 1.824000 P 20 P3D 1.451998 + 1024 O43 4.317000 3.277000 1.088000 O2 20 P3D -0.983005 + 1025 O44 1.810000 3.615000 1.341000 O2 20 P3D -0.983005 + 1026 O45 3.180000 2.852000 3.330000 O2 20 P3D -0.983005 + 1027 P38 4.938000 -2.614000 -0.754000 P 20 P3D 1.443615 + 1028 O48 4.563000 -3.293000 0.562000 O2 20 P3D -0.989068 + 1029 O47 4.594000 -3.417000 -1.987000 O2 20 P3D -0.989068 + 1030 O46 6.337000 -2.042000 -0.761000 O2 20 P3D -0.989068 + 1031 HOP6 1.210000 3.931000 -0.126000 hO 20 P3D 0.690725 + 1032 C11 5.149000 1.033000 -1.321000 cC 21 P3E 0.975211 + 1033 O12 5.706000 0.499000 -2.245000 oC 21 P3E -0.830543 + 1034 O11 4.661000 0.394000 -0.283000 oS 21 P3E -0.600967 + 1035 C1 4.141000 -0.937000 -0.389000 cA 21 P3E 0.372631 + 1036 HR 4.790000 -1.544000 -1.005000 hE 21 P3E -0.016286 + 1037 HS 3.153000 -0.878000 -0.815000 hE 21 P3E -0.016286 + 1038 C2 4.086000 -1.490000 1.024000 cA 21 P3E 0.376163 + 1039 HX 5.089000 -1.595000 1.424000 hE 21 P3E -0.100576 + 1040 C3 3.371000 -2.836000 1.089000 cA 21 P3E 0.593593 + 1041 HA 3.441000 -3.191000 2.121000 hE 21 P3E -0.133323 + 1042 HB 3.909000 -3.536000 0.457000 hE 21 P3E -0.133323 + 1043 O31 2.048000 -2.732000 0.734000 Os 21 P3E -0.493378 + 1044 P31 1.448000 -3.559000 -0.581000 P 21 P3E 1.009715 + 1045 O32 0.288000 -2.579000 -1.038000 Os 21 P3E -0.307001 + 1046 O33 0.949000 -4.864000 -0.075000 O2 21 P3E -0.828506 + 1047 O34 2.549000 -3.595000 -1.586000 O2 21 P3E -0.828506 + 1048 O21 3.365000 -0.586000 1.844000 oS 21 P3E -0.449360 + 1049 C21 3.951000 0.312000 2.600000 cC 21 P3E 0.761896 + 1050 O22 5.114000 0.278000 2.920000 oC 21 P3E -0.738031 + 1051 C31 -0.430000 -1.518000 -0.371000 Cp 21 P3E 0.119645 + 1052 H1A -0.090000 -1.487000 0.656000 H1 21 P3E -0.007525 + 1053 C32 -1.938000 -1.792000 -0.390000 Cg 21 P3E 0.334913 + 1054 H2A -2.119000 -2.699000 0.176000 H1 21 P3E -0.049617 + 1055 C33 -2.752000 -0.662000 0.309000 Cp 21 P3E 0.055646 + 1056 H3A -2.509000 -0.696000 1.373000 H1 21 P3E 0.044697 + 1057 C34 -2.355000 0.762000 -0.203000 Cp 21 P3E 0.372717 + 1058 H4A -2.720000 0.879000 -1.213000 H1 21 P3E 0.025010 + 1059 C35 -0.808000 0.953000 -0.194000 Cp 21 P3E 0.055646 + 1060 H5A -0.454000 0.898000 0.832000 H1 21 P3E 0.044697 + 1061 C36 -0.121000 -0.168000 -1.013000 Cg 21 P3E 0.334913 + 1062 H6A -0.537000 -0.161000 -2.019000 H1 21 P3E -0.049617 + 1063 O35 -2.380000 -1.979000 -1.705000 Oh 21 P3E -0.729289 + 1064 HO5A -3.263000 -2.369000 -1.589000 Ho 21 P3E 0.454905 + 1065 O36 -4.122000 -0.865000 0.133000 Os 21 P3E -0.505635 + 1066 O37 -2.955000 1.745000 0.626000 Os 21 P3E -0.544411 + 1067 O38 -0.480000 2.217000 -0.720000 Os 21 P3E -0.505635 + 1068 O39 1.265000 0.004000 -1.074000 Oh 21 P3E -0.729289 + 1069 HO9A 1.479000 0.919000 -1.308000 Ho 21 P3E 0.454905 + 1070 P36 -4.984000 -2.315000 0.418000 P 21 P3E 1.382442 + 1071 O40 -4.421000 -2.892000 1.697000 O2 21 P3E -0.962831 + 1072 O41 -4.671000 -3.148000 -0.828000 O2 21 P3E -0.962831 + 1073 O42 -6.428000 -1.882000 0.493000 O2 21 P3E -0.962831 + 1074 P37 -3.700000 3.127000 0.183000 P 21 P3E 1.400149 + 1075 O43 -4.699000 3.478000 1.230000 O2 21 P3E -0.917806 + 1076 O44 -2.521000 4.233000 0.360000 oH 21 P3E -0.832135 + 1077 O45 -4.117000 3.074000 -1.244000 O2 21 P3E -0.917806 + 1078 P38 0.901000 3.152000 -0.459000 P 21 P3E 1.382442 + 1079 O48 1.908000 2.614000 -1.491000 O2 21 P3E -0.962831 + 1080 O47 0.419000 4.543000 -0.766000 O2 21 P3E -0.962831 + 1081 O46 1.363000 2.915000 0.961000 O2 21 P3E -0.962831 + 1082 HOP7 -1.719000 4.029000 -0.122000 hO 21 P3E 0.489900 + 1083 C11 -6.175000 -2.047000 -0.922000 cC 22 P3F 0.761453 + 1084 O12 -6.318000 -2.539000 0.159000 oC 22 P3F -0.758622 + 1085 O11 -5.147000 -1.422000 -1.394000 oS 22 P3F -0.512957 + 1086 C1 -3.943000 -1.113000 -0.613000 cA 22 P3F 0.741364 + 1087 HR -3.101000 -1.468000 -1.196000 hE 22 P3F -0.098432 + 1088 HS -3.990000 -1.641000 0.323000 hE 22 P3F -0.098432 + 1089 C2 -3.890000 0.385000 -0.400000 cA 22 P3F -0.017963 + 1090 HX -4.326000 0.902000 -1.244000 hE 22 P3F 0.129801 + 1091 C3 -2.467000 0.844000 -0.157000 cA 22 P3F 0.318055 + 1092 HA -1.892000 0.612000 -1.043000 hE 22 P3F -0.047308 + 1093 HB -2.055000 0.294000 0.677000 hE 22 P3F -0.047308 + 1094 O31 -2.473000 2.219000 0.081000 Os 22 P3F -0.473516 + 1095 P31 -1.164000 2.888000 0.891000 P 22 P3F 1.223592 + 1096 O32 0.020000 2.057000 0.239000 Os 22 P3F -0.516269 + 1097 O33 -1.391000 2.620000 2.335000 O2 22 P3F -0.872399 + 1098 O34 -1.139000 4.298000 0.428000 O2 22 P3F -0.872399 + 1099 O21 -4.687000 0.684000 0.768000 oS 22 P3F -0.517063 + 1100 C21 -5.165000 1.904000 0.958000 cC 22 P3F 0.989113 + 1101 O22 -5.860000 2.477000 0.167000 oC 22 P3F -0.880558 + 1102 C31 1.020000 1.061000 0.619000 Cp 22 P3F 0.477343 + 1103 H1A 1.267000 1.212000 1.659000 H1 22 P3F 0.058586 + 1104 C32 2.268000 1.315000 -0.236000 Cg 22 P3F -0.212133 + 1105 H2A 2.617000 2.320000 -0.021000 H1 22 P3F 0.136582 + 1106 C33 3.419000 0.330000 0.140000 Cp 22 P3F 0.258965 + 1107 H3A 3.895000 0.733000 1.026000 H1 22 P3F 0.053669 + 1108 C34 2.905000 -1.088000 0.575000 Cp 22 P3F 0.386837 + 1109 H4A 3.603000 -1.831000 0.214000 H1 22 P3F -0.001185 + 1110 C35 1.483000 -1.448000 0.081000 Cp 22 P3F 0.095205 + 1111 H5A 1.186000 -2.346000 0.597000 H1 22 P3F 0.160031 + 1112 C36 0.449000 -0.361000 0.455000 Cg 22 P3F -0.144660 + 1113 H6A -0.241000 -0.320000 -0.361000 H1 22 P3F 0.194357 + 1114 O35 1.952000 1.256000 -1.603000 Oh 22 P3F -0.685707 + 1115 HO5A 2.772000 1.527000 -2.056000 Ho 22 P3F 0.511733 + 1116 O36 4.367000 0.230000 -0.887000 Os 22 P3F -0.567725 + 1117 O37 2.864000 -1.077000 1.985000 Os 22 P3F -0.639266 + 1118 O38 1.491000 -1.761000 -1.322000 Os 22 P3F -0.534945 + 1119 O39 -0.284000 -0.737000 1.592000 Oh 22 P3F -0.545512 + 1120 HO9A 0.260000 -1.286000 2.186000 Ho 22 P3F 0.316832 + 1121 P36 5.327000 1.506000 -1.480000 P 22 P3F 1.435932 + 1122 O40 5.755000 2.323000 -0.281000 O2 22 P3F -0.979099 + 1123 O41 4.366000 2.244000 -2.414000 O2 22 P3F -0.979099 + 1124 O42 6.454000 0.803000 -2.203000 O2 22 P3F -0.979099 + 1125 P37 2.680000 -2.412000 3.037000 P 22 P3F 1.404854 + 1126 O43 1.162000 -2.533000 3.159000 O2 22 P3F -0.963067 + 1127 O44 3.339000 -3.589000 2.356000 O2 22 P3F -0.963067 + 1128 O45 3.355000 -1.955000 4.311000 O2 22 P3F -0.963067 + 1129 P38 0.289000 -1.981000 -2.376000 P 22 P3F 1.402270 + 1130 O48 0.704000 -2.984000 -3.396000 O2 22 P3F -0.919056 + 1131 O47 -1.038000 -2.199000 -1.715000 O2 22 P3F -0.919056 + 1132 O46 0.267000 -0.508000 -3.065000 oH 22 P3F -0.809924 + 1133 HOP8 0.873000 0.082000 -2.601000 hO 22 P3F 0.462320 + 1134 C11 -5.853000 -2.625000 0.444000 cC 23 P3H 0.676726 + 1135 O12 -6.563000 -3.074000 -0.405000 oC 23 P3H -0.624236 + 1136 O11 -5.444000 -1.370000 0.470000 oS 23 P3H -0.324227 + 1137 C1 -5.445000 -0.625000 -0.736000 cA 23 P3H -0.044023 + 1138 HR -6.461000 -0.405000 -1.036000 hE 23 P3H 0.081964 + 1139 HS -4.956000 -1.205000 -1.503000 hE 23 P3H 0.081964 + 1140 C2 -4.660000 0.650000 -0.502000 cA 23 P3H 0.483670 + 1141 HX -4.573000 1.166000 -1.447000 hE 23 P3H 0.055517 + 1142 C3 -3.280000 0.426000 0.113000 cA 23 P3H 0.371052 + 1143 HA -3.380000 0.037000 1.113000 hE 23 P3H -0.036072 + 1144 HB -2.745000 1.365000 0.157000 hE 23 P3H -0.036072 + 1145 O31 -2.588000 -0.471000 -0.707000 Os 23 P3H -0.634710 + 1146 P31 -2.102000 -1.963000 -0.201000 P 23 P3H 1.251672 + 1147 O32 -0.553000 -1.883000 -0.655000 Os 23 P3H -0.668951 + 1148 O33 -2.775000 -2.952000 -1.066000 O2 23 P3H -0.793455 + 1149 O34 -2.225000 -2.028000 1.270000 O2 23 P3H -0.793455 + 1150 O21 -5.348000 1.515000 0.423000 oS 23 P3H -0.622089 + 1151 C21 -6.294000 2.321000 0.019000 cC 23 P3H 0.789722 + 1152 O22 -6.772000 2.347000 -1.076000 oC 23 P3H -0.666879 + 1153 C31 0.481000 -1.171000 0.037000 Cp 23 P3H 0.644270 + 1154 H1A 0.372000 -1.350000 1.099000 H1 23 P3H -0.054116 + 1155 C32 0.404000 0.317000 -0.252000 Cg 23 P3H -0.000039 + 1156 H2A -0.466000 0.732000 0.228000 H1 23 P3H 0.134604 + 1157 C33 1.622000 1.049000 0.314000 Cp 23 P3H 0.052518 + 1158 H3A 1.557000 0.975000 1.395000 H1 23 P3H 0.105519 + 1159 C34 2.984000 0.444000 -0.113000 Cp 23 P3H 0.108043 + 1160 H4A 3.133000 0.609000 -1.171000 H1 23 P3H 0.142369 + 1161 C35 3.021000 -1.086000 0.174000 Cp 23 P3H 0.052518 + 1162 H5A 3.021000 -1.249000 1.245000 H1 23 P3H 0.105519 + 1163 C36 1.791000 -1.765000 -0.452000 Cg 23 P3H -0.000039 + 1164 H6A 1.852000 -1.634000 -1.527000 H1 23 P3H 0.134604 + 1165 O35 0.307000 0.530000 -1.650000 Oh 23 P3H -0.655388 + 1166 HO5A -0.453000 0.036000 -1.934000 Ho 23 P3H 0.410661 + 1167 O36 1.591000 2.412000 -0.048000 Os 23 P3H -0.503702 + 1168 O37 4.002000 1.059000 0.617000 Os 23 P3H -0.478410 + 1169 O38 4.181000 -1.641000 -0.386000 Os 23 P3H -0.503702 + 1170 O39 1.769000 -3.149000 -0.156000 Oh 23 P3H -0.655388 + 1171 HO9A 0.919000 -3.462000 -0.441000 Ho 23 P3H 0.410661 + 1172 P36 0.339000 3.453000 0.164000 P 23 P3H 1.420457 + 1173 O41 -0.328000 3.340000 -1.325000 oH 23 P3H -0.778505 + 1174 O40 0.893000 4.810000 0.316000 O2 23 P3H -0.870394 + 1175 O42 -0.606000 2.893000 1.163000 O2 23 P3H -0.870394 + 1176 P37 4.962000 2.287000 0.064000 P 23 P3H 1.391719 + 1177 O43 4.870000 2.321000 -1.413000 O2 23 P3H -0.868077 + 1178 O44 4.192000 3.576000 0.688000 oH 23 P3H -0.778177 + 1179 O45 6.253000 2.209000 0.774000 O2 23 P3H -0.868077 + 1180 P38 5.019000 -2.923000 0.223000 P 23 P3H 1.420457 + 1181 O48 6.415000 -2.844000 -0.241000 O2 23 P3H -0.870394 + 1182 O47 4.660000 -3.090000 1.650000 O2 23 P3H -0.870394 + 1183 O46 4.332000 -4.142000 -0.631000 oH 23 P3H -0.778505 + 1184 H19 3.300000 3.636000 0.360000 hO 23 P3H 0.468351 + 1185 H20 -0.117000 2.484000 -1.688000 hO 23 P3H 0.426657 + 1186 H21 3.395000 -4.097000 -0.471000 hO 23 P3H 0.426657 + 1187 C11 4.694000 -2.109000 0.405000 cC 24 PC1 0.742885 + 1188 O12 4.576000 -2.896000 -0.477000 oC 24 PC1 -0.577293 + 1189 O11 3.902000 -1.060000 0.566000 oS 24 PC1 -0.412240 + 1190 C1 2.854000 -0.874000 -0.377000 cA 24 PC1 -0.025704 + 1191 HR 2.157000 -1.696000 -0.314000 hE 24 PC1 0.087518 + 1192 HS 3.266000 -0.836000 -1.375000 hE 24 PC1 0.087518 + 1193 C2 2.165000 0.425000 -0.026000 cA 24 PC1 0.391894 + 1194 HX 1.911000 0.438000 1.021000 hE 24 PC1 -0.011668 + 1195 C3 0.919000 0.667000 -0.863000 cA 24 PC1 -0.003240 + 1196 HA 1.151000 0.638000 -1.919000 hE 24 PC1 0.068359 + 1197 HB 0.516000 1.643000 -0.623000 hE 24 PC1 0.068359 + 1198 O31 -0.006000 -0.339000 -0.535000 oT 24 PC1 -0.423344 + 1199 P31 -1.430000 -0.403000 -1.277000 pA 24 PC1 1.180843 + 1200 O32 -2.179000 0.795000 -0.393000 oT 24 PC1 -0.458127 + 1201 C31 -3.461000 1.133000 -0.789000 cA 24 PC1 0.223407 + 1202 H1A -3.812000 0.531000 -1.617000 hE 24 PC1 0.026299 + 1203 H1B -3.484000 2.165000 -1.127000 hE 24 PC1 0.026299 + 1204 C32 -4.434000 1.074000 0.381000 cA 24 PC1 0.048208 + 1205 H2A -5.396000 1.448000 0.054000 hX 24 PC1 0.048094 + 1206 H2B -4.072000 1.701000 1.183000 hX 24 PC1 0.048094 + 1207 N31 -4.708000 -0.280000 1.003000 nA 24 PC1 0.103551 + 1208 C33 -5.092000 -1.293000 -0.033000 cA 24 PC1 -0.242785 + 1209 H3A -5.889000 -0.883000 -0.638000 hX 24 PC1 0.134244 + 1210 H3B -5.442000 -2.177000 0.479000 hX 24 PC1 0.134244 + 1211 H3C -4.222000 -1.537000 -0.624000 hX 24 PC1 0.134244 + 1212 C34 -3.521000 -0.799000 1.770000 cA 24 PC1 -0.242785 + 1213 H4A -3.178000 -0.023000 2.437000 hX 24 PC1 0.134244 + 1214 H4B -2.753000 -1.088000 1.075000 hX 24 PC1 0.134244 + 1215 H4C -3.853000 -1.656000 2.338000 hX 24 PC1 0.134244 + 1216 C35 -5.839000 -0.102000 1.952000 cA 24 PC1 -0.242785 + 1217 H5A -5.570000 0.638000 2.691000 hX 24 PC1 0.134244 + 1218 H5B -6.044000 -1.043000 2.440000 hX 24 PC1 0.134244 + 1219 H5C -6.716000 0.223000 1.411000 hX 24 PC1 0.134244 + 1220 O33 -2.106000 -1.653000 -0.869000 oP 24 PC1 -0.727134 + 1221 O34 -1.344000 0.050000 -2.666000 oP 24 PC1 -0.727134 + 1222 O21 3.096000 1.472000 -0.298000 oH 24 PC1 -0.640388 + 1223 H21 2.820000 2.255000 0.247000 hO 24 PC1 0.375103 + 1224 O11 3.902000 -1.060000 0.566000 oH 25 PC2 -0.666461 + 1225 C1 2.854000 -0.874000 -0.377000 cA 25 PC2 0.220846 + 1226 HR 2.157000 -1.696000 -0.314000 hE 25 PC2 0.023639 + 1227 HS 3.266000 -0.836000 -1.375000 hE 25 PC2 0.023639 + 1228 C2 2.165000 0.425000 -0.026000 cA 25 PC2 0.237620 + 1229 HX 1.911000 0.438000 1.021000 hE 25 PC2 0.029872 + 1230 C3 0.919000 0.667000 -0.863000 cA 25 PC2 0.058278 + 1231 HA 1.151000 0.638000 -1.919000 hE 25 PC2 0.052578 + 1232 HB 0.516000 1.643000 -0.623000 hE 25 PC2 0.052578 + 1233 O31 -0.006000 -0.339000 -0.535000 oT 25 PC2 -0.448369 + 1234 P31 -1.430000 -0.403000 -1.277000 pA 25 PC2 1.223464 + 1235 O32 -2.179000 0.795000 -0.393000 oT 25 PC2 -0.454370 + 1236 C31 -3.461000 1.133000 -0.789000 cA 25 PC2 0.214589 + 1237 H1A -3.812000 0.531000 -1.617000 hE 25 PC2 0.030325 + 1238 H1B -3.484000 2.165000 -1.127000 hE 25 PC2 0.030325 + 1239 C32 -4.434000 1.074000 0.381000 cA 25 PC2 0.006032 + 1240 H2A -5.396000 1.448000 0.054000 hX 25 PC2 0.058877 + 1241 H2B -4.072000 1.701000 1.183000 hX 25 PC2 0.058877 + 1242 N31 -4.708000 -0.280000 1.003000 nA 25 PC2 0.110582 + 1243 C33 -5.092000 -1.293000 -0.033000 cA 25 PC2 -0.233051 + 1244 H3A -5.889000 -0.883000 -0.638000 hX 25 PC2 0.132489 + 1245 H3B -5.442000 -2.177000 0.479000 hX 25 PC2 0.132489 + 1246 H3C -4.222000 -1.537000 -0.624000 hX 25 PC2 0.132489 + 1247 C34 -3.521000 -0.799000 1.770000 cA 25 PC2 -0.233051 + 1248 H4A -3.178000 -0.023000 2.437000 hX 25 PC2 0.132489 + 1249 H4B -2.753000 -1.088000 1.075000 hX 25 PC2 0.132489 + 1250 H4C -3.853000 -1.656000 2.338000 hX 25 PC2 0.132489 + 1251 C35 -5.839000 -0.102000 1.952000 cA 25 PC2 -0.233051 + 1252 H5A -5.570000 0.638000 2.691000 hX 25 PC2 0.132489 + 1253 H5B -6.044000 -1.043000 2.440000 hX 25 PC2 0.132489 + 1254 H5C -6.716000 0.223000 1.411000 hX 25 PC2 0.132489 + 1255 O33 -2.106000 -1.653000 -0.869000 oP 25 PC2 -0.745809 + 1256 O34 -1.344000 0.050000 -2.666000 oP 25 PC2 -0.745809 + 1257 O21 3.096000 1.472000 -0.298000 oS 25 PC2 -0.421580 + 1258 C21 3.110000 2.550000 0.475000 cC 25 PC2 0.728661 + 1259 O22 2.361000 2.734000 1.379000 oC 25 PC2 -0.588475 + 1260 H11 4.514000 -1.584000 0.283000 hO 25 PC2 0.416841 + 1261 C11 2.180000 2.916000 -0.064000 cC 26 PE1 0.751933 + 1262 O12 1.200000 3.445000 0.353000 oC 26 PE1 -0.565338 + 1263 O11 2.300000 1.607000 -0.216000 oS 26 PE1 -0.408042 + 1264 C1 1.186000 0.802000 0.148000 cA 26 PE1 -0.046044 + 1265 HR 0.303000 1.147000 -0.363000 hE 26 PE1 0.090184 + 1266 HS 1.024000 0.875000 1.214000 hE 26 PE1 0.090184 + 1267 C2 1.505000 -0.620000 -0.256000 cA 26 PE1 0.392483 + 1268 HX 1.807000 -0.650000 -1.291000 hE 26 PE1 -0.006166 + 1269 C3 0.330000 -1.562000 -0.031000 cA 26 PE1 0.127927 + 1270 HA 0.041000 -1.559000 1.011000 hE 26 PE1 0.043081 + 1271 HB 0.613000 -2.568000 -0.305000 hE 26 PE1 0.043081 + 1272 O31 -0.732000 -1.142000 -0.860000 oT 26 PE1 -0.478925 + 1273 P31 -2.233000 -1.108000 -0.332000 pA 26 PE1 1.271834 + 1274 O32 -2.136000 0.266000 0.585000 oT 26 PE1 -0.308424 + 1275 C31 -3.161000 0.573000 1.479000 cA 26 PE1 -0.361683 + 1276 H1A -2.877000 1.497000 1.967000 hE 26 PE1 0.180576 + 1277 H1B -3.275000 -0.198000 2.230000 hE 26 PE1 0.180576 + 1278 C32 -4.503000 0.755000 0.756000 cA 26 PE1 0.525293 + 1279 H2A -4.980000 -0.196000 0.574000 hX 26 PE1 0.021198 + 1280 H2B -5.171000 1.387000 1.325000 hX 26 PE1 0.021198 + 1281 N31 -4.264000 1.356000 -0.588000 nA 26 PE1 -1.845296 + 1282 HN1A -3.660000 2.160000 -0.543000 hN 26 PE1 0.657678 + 1283 HN1B -3.765000 0.574000 -1.162000 hN 26 PE1 0.657678 + 1284 HN1C -5.121000 1.620000 -1.043000 hN 26 PE1 0.693831 + 1285 O33 -2.580000 -2.225000 0.542000 oP 26 PE1 -0.764298 + 1286 O34 -3.100000 -0.702000 -1.484000 oP 26 PE1 -0.713325 + 1287 O21 2.581000 -1.061000 0.567000 oH 26 PE1 -0.630395 + 1288 H21 3.263000 -1.510000 0.516000 hO 26 PE1 0.379204 + 1289 O11 2.300000 1.607000 -0.216000 oH 27 PE2 -0.582221 + 1290 C1 1.186000 0.802000 0.148000 cA 27 PE2 0.085410 + 1291 HR 0.303000 1.147000 -0.363000 hE 27 PE2 0.048721 + 1292 HS 1.024000 0.875000 1.214000 hE 27 PE2 0.048721 + 1293 C2 1.505000 -0.620000 -0.256000 cA 27 PE2 0.314298 + 1294 HX 1.807000 -0.650000 -1.291000 hE 27 PE2 0.031864 + 1295 C3 0.330000 -1.562000 -0.031000 cA 27 PE2 0.101769 + 1296 HA 0.041000 -1.559000 1.011000 hE 27 PE2 0.049575 + 1297 HB 0.613000 -2.568000 -0.305000 hE 27 PE2 0.049575 + 1298 O31 -0.732000 -1.142000 -0.860000 oT 27 PE2 -0.423364 + 1299 P31 -2.233000 -1.108000 -0.332000 pA 27 PE2 1.215718 + 1300 O32 -2.136000 0.266000 0.585000 oT 27 PE2 -0.403816 + 1301 C31 -3.161000 0.573000 1.479000 cA 27 PE2 -0.089673 + 1302 H1A -2.877000 1.497000 1.967000 hE 27 PE2 0.119067 + 1303 H1B -3.275000 -0.198000 2.230000 hE 27 PE2 0.119067 + 1304 C32 -4.503000 0.755000 0.756000 cA 27 PE2 0.508643 + 1305 H2A -4.980000 -0.196000 0.574000 hX 27 PE2 0.009554 + 1306 H2B -5.171000 1.387000 1.325000 hX 27 PE2 0.009554 + 1307 N31 -4.264000 1.356000 -0.588000 nA 27 PE2 -1.856454 + 1308 HN1A -3.660000 2.160000 -0.543000 hN 27 PE2 0.720944 + 1309 HN1B -3.765000 0.574000 -1.162000 hN 27 PE2 0.658581 + 1310 HN1C -5.121000 1.620000 -1.043000 hN 27 PE2 0.658581 + 1311 O33 -2.580000 -2.225000 0.542000 oP 27 PE2 -0.743439 + 1312 O34 -3.100000 -0.702000 -1.484000 oP 27 PE2 -0.744966 + 1313 O21 2.581000 -1.061000 0.567000 oS 27 PE2 -0.455646 + 1314 C21 3.515000 -1.854000 0.049000 cC 27 PE2 0.713495 + 1315 O22 3.494000 -2.265000 -1.064000 oC 27 PE2 -0.548176 + 1316 H11 2.064000 2.536000 0.040000 hO 27 PE2 0.384617 + 1317 C11 -4.477000 -1.887000 -0.726000 cC 28 PG1 0.731855 + 1318 O12 -4.371000 -2.868000 -0.063000 oC 28 PG1 -0.594566 + 1319 O11 -3.639000 -0.870000 -0.694000 oS 28 PG1 -0.442639 + 1320 C1 -2.503000 -0.948000 0.169000 cA 28 PG1 0.103072 + 1321 HR -1.828000 -1.711000 -0.185000 hE 28 PG1 0.045614 + 1322 HS -2.829000 -1.195000 1.169000 hE 28 PG1 0.045614 + 1323 C2 -1.828000 0.404000 0.138000 cA 28 PG1 0.468682 + 1324 HX -1.630000 0.695000 -0.880000 hE 28 PG1 -0.018057 + 1325 C3 -0.548000 0.426000 0.959000 cA 28 PG1 0.124410 + 1326 HA -0.757000 0.182000 1.993000 hE 28 PG1 0.023730 + 1327 HB -0.133000 1.429000 0.931000 hE 28 PG1 0.023730 + 1328 O31 0.324000 -0.498000 0.392000 oT 28 PG1 -0.527765 + 1329 P31 1.792000 -0.746000 1.103000 pA 28 PG1 1.262400 + 1330 O32 2.555000 0.619000 0.624000 oT 28 PG1 -0.538055 + 1331 C31 2.986000 0.770000 -0.700000 cA 28 PG1 0.229332 + 1332 H1A 2.623000 1.721000 -1.076000 hE 28 PG1 0.003632 + 1333 H1B 2.604000 -0.014000 -1.340000 hE 28 PG1 0.003632 + 1334 C32 4.505000 0.786000 -0.761000 cA 28 PG1 0.261872 + 1335 H2A 4.809724 1.042668 -1.774392 hE 28 PG1 -0.003942 + 1336 O35 4.944181 1.781217 0.136205 oH 28 PG1 -0.667400 + 1337 C33 5.133000 -0.547000 -0.395000 cA 28 PG1 0.235702 + 1338 H3A 4.915000 -0.793000 0.640000 hE 28 PG1 -0.006655 + 1339 H3B 4.728000 -1.331000 -1.018000 hE 28 PG1 -0.006655 + 1340 O33 2.390000 -1.892000 0.403000 oP 28 PG1 -0.773309 + 1341 O34 1.622000 -0.640000 2.557000 oP 28 PG1 -0.773309 + 1342 O21 -2.727000 1.350000 0.732000 oH 28 PG1 -0.729767 + 1343 O36 6.529000 -0.405000 -0.601000 oH 28 PG1 -0.657113 + 1344 H21 -3.311000 1.698000 0.008000 hO 28 PG1 0.386599 + 1345 HO5A 5.047780 2.625020 -0.377257 hO 28 PG1 0.399070 + 1346 HO6A 6.907000 0.005000 0.221000 hO 28 PG1 0.390285 + 1347 O11 -3.639000 -0.870000 -0.694000 oH 29 PG2 -0.649182 + 1348 C1 -2.503000 -0.948000 0.169000 cA 29 PG2 0.228363 + 1349 HR -1.828000 -1.711000 -0.185000 hE 29 PG2 -0.004863 + 1350 HS -2.829000 -1.195000 1.169000 hE 29 PG2 -0.004863 + 1351 C2 -1.828000 0.404000 0.138000 cA 29 PG2 0.335578 + 1352 HX -1.630000 0.695000 -0.880000 hE 29 PG2 -0.017970 + 1353 C3 -0.548000 0.426000 0.959000 cA 29 PG2 0.117451 + 1354 HA -0.757000 0.182000 1.993000 hE 29 PG2 0.022026 + 1355 HB -0.133000 1.429000 0.931000 hE 29 PG2 0.022026 + 1356 O31 0.324000 -0.498000 0.392000 oT 29 PG2 -0.453096 + 1357 P31 1.792000 -0.746000 1.103000 pA 29 PG2 1.193744 + 1358 O32 2.555000 0.619000 0.624000 oT 29 PG2 -0.470382 + 1359 C31 2.986000 0.770000 -0.700000 cA 29 PG2 0.131432 + 1360 H1A 2.623000 1.721000 -1.076000 hE 29 PG2 0.013723 + 1361 H1B 2.604000 -0.014000 -1.340000 hE 29 PG2 0.013723 + 1362 C32 4.505000 0.786000 -0.761000 cA 29 PG2 0.398788 + 1363 H2A 4.809728 1.035181 -1.776258 hE 29 PG2 -0.033747 + 1364 O35 4.943811 1.788025 0.128778 oH 29 PG2 -0.708795 + 1365 HO5A 4.363524 2.530332 0.015690 hO 29 PG2 0.388093 + 1366 C33 5.129000 -0.545000 -0.390000 cA 29 PG2 0.255616 + 1367 H3A 4.915000 -0.793000 0.640000 hE 29 PG2 -0.018391 + 1368 H3B 4.728000 -1.331000 -1.018000 hE 29 PG2 -0.018391 + 1369 O33 2.390000 -1.892000 0.403000 oP 29 PG2 -0.762310 + 1370 O34 1.622000 -0.640000 2.557000 oP 29 PG2 -0.762310 + 1371 O21 -2.727000 1.350000 0.732000 oS 29 PG2 -0.473672 + 1372 C21 -3.217000 2.354000 0.028000 cC 29 PG2 0.731275 + 1373 O22 -2.963000 2.587000 -1.110000 oC 29 PG2 -0.602365 + 1374 O36 6.529000 -0.405000 -0.601000 oH 29 PG2 -0.668922 + 1375 HO6A 6.945000 -1.239000 -0.440000 hO 29 PG2 0.397871 + 1376 H11 -4.061000 -1.768000 -0.674000 hO 29 PG2 0.399552 + 1377 C11 -1.933000 -2.573000 -0.273000 cC 30 PH3 0.690208 + 1378 O12 -2.855000 -3.256000 -0.611000 oC 30 PH3 -0.569694 + 1379 O11 -1.710000 -1.356000 -0.746000 oS 30 PH3 -0.379623 + 1380 C1 -2.605000 -0.800000 -1.684000 cA 30 PH3 0.084766 + 1381 HR -3.066000 -1.594000 -2.252000 hE 30 PH3 0.040791 + 1382 HS -2.004000 -0.190000 -2.345000 hE 30 PH3 0.040791 + 1383 C2 -3.687000 0.069000 -1.049000 cA 30 PH3 0.319370 + 1384 HX -4.431000 0.252000 -1.813000 hE 30 PH3 0.015062 + 1385 C3 -3.247000 1.428000 -0.539000 cA 30 PH3 -0.001115 + 1386 HA -4.115000 1.909000 -0.096000 hE 30 PH3 0.064022 + 1387 HB -2.942000 2.023000 -1.393000 hE 30 PH3 0.064022 + 1388 O31 -2.210000 1.338000 0.381000 Os 30 PH3 -0.380550 + 1389 P31 -1.547000 2.736000 0.938000 P 30 PH3 1.222635 + 1390 O32 -0.045000 2.195000 1.210000 Os 30 PH3 -0.548558 + 1391 O33 -2.136000 3.098000 2.231000 O2 30 PH3 -0.793977 + 1392 O34 -1.521000 3.676000 -0.211000 O2 30 PH3 -0.793977 + 1393 O21 -4.307000 -0.652000 0.013000 oS 30 PH3 -0.428221 + 1394 C21 -5.364000 -1.400000 -0.237000 cC 30 PH3 0.690969 + 1395 O22 -5.944000 -1.432000 -1.279000 oC 30 PH3 -0.585604 + 1396 C31 0.798000 1.602000 0.238000 Cp 30 PH3 0.142703 + 1397 H1A 0.200000 1.174000 -0.558000 H1 30 PH3 0.006997 + 1398 C32 1.530000 0.482000 0.980000 Cg 30 PH3 0.259134 + 1399 H2A 0.797000 -0.265000 1.266000 H1 30 PH3 0.092533 + 1400 C33 2.577000 -0.184000 0.097000 Cp 30 PH3 -0.008190 + 1401 H3A 2.058000 -0.632000 -0.746000 H1 30 PH3 0.062176 + 1402 C34 3.568000 0.851000 -0.421000 Cg 30 PH3 0.326410 + 1403 H4A 4.085000 1.277000 0.433000 H1 30 PH3 0.050007 + 1404 C35 2.838000 1.961000 -1.174000 Cg 30 PH3 -0.067294 + 1405 H5A 2.362000 1.512000 -2.045000 H1 30 PH3 0.090758 + 1406 C36 1.749000 2.649000 -0.360000 Cg 30 PH3 0.482531 + 1407 H6A 2.215000 3.189000 0.460000 H1 30 PH3 -0.024408 + 1408 O35 2.146000 1.004000 2.130000 Oh 30 PH3 -0.673618 + 1409 HO5A 1.492000 1.549000 2.553000 Ho 30 PH3 0.411208 + 1410 O36 3.236000 -1.182000 0.836000 Os 30 PH3 -0.495507 + 1411 O37 4.499000 0.329000 -1.332000 Oh 30 PH3 -0.671035 + 1412 HO7A 4.706000 -0.592000 -1.138000 Ho 30 PH3 0.398902 + 1413 O38 3.778000 2.915000 -1.603000 Oh 30 PH3 -0.623408 + 1414 HO8A 4.500000 2.414000 -1.961000 Ho 30 PH3 0.374560 + 1415 O39 1.079000 3.529000 -1.213000 Oh 30 PH3 -0.661605 + 1416 HO9A 0.208000 3.734000 -0.864000 Ho 30 PH3 0.374213 + 1417 P36 3.587000 -2.620000 0.153000 P 30 PH3 1.316443 + 1418 O40 4.195000 -3.355000 1.465000 oH 30 PH3 -0.714429 + 1419 O41 4.685000 -2.411000 -0.816000 O2 30 PH3 -0.796692 + 1420 O42 2.323000 -3.290000 -0.222000 O2 30 PH3 -0.796692 + 1421 HOP6 3.471000 -3.668000 1.990000 hO 30 PH3 0.392986 + 1422 C11 -5.375000 3.092000 0.369000 cC 31 PH4 0.740794 + 1423 O12 -6.026000 3.065000 1.365000 oC 31 PH4 -0.613261 + 1424 O11 -4.378000 2.277000 0.086000 oS 31 PH4 -0.410303 + 1425 C1 -4.096000 1.160000 0.928000 cA 31 PH4 0.078573 + 1426 HR -4.772000 1.167000 1.766000 hE 31 PH4 0.057937 + 1427 HS -3.078000 1.251000 1.271000 hE 31 PH4 0.057937 + 1428 C2 -4.233000 -0.122000 0.136000 cA 31 PH4 0.352796 + 1429 HX -4.032000 -0.927000 0.823000 hE 31 PH4 0.016055 + 1430 C3 -3.281000 -0.212000 -1.058000 cA 31 PH4 0.121774 + 1431 HA -3.411000 0.659000 -1.686000 hE 31 PH4 0.046393 + 1432 HB -3.524000 -1.094000 -1.637000 hE 31 PH4 0.046393 + 1433 O31 -1.950000 -0.248000 -0.648000 Os 31 PH4 -0.523817 + 1434 P31 -1.440000 -1.540000 0.237000 P 31 PH4 1.259912 + 1435 O32 0.094000 -1.596000 -0.238000 Os 31 PH4 -0.507452 + 1436 O33 -2.149000 -2.732000 -0.260000 O2 31 PH4 -0.779088 + 1437 O34 -1.500000 -1.140000 1.662000 O2 31 PH4 -0.779088 + 1438 O21 -5.573000 -0.193000 -0.347000 oS 31 PH4 -0.518921 + 1439 C21 -6.238000 -1.336000 -0.496000 cC 31 PH4 0.787641 + 1440 O22 -7.295000 -1.317000 -1.043000 oC 31 PH4 -0.634550 + 1441 C31 1.045000 -0.555000 -0.034000 Cp 31 PH4 0.160252 + 1442 H1A 0.532000 0.378000 0.168000 H1 31 PH4 0.050895 + 1443 C32 1.810000 -0.447000 -1.351000 Cg 31 PH4 0.186520 + 1444 H2A 1.123000 -0.095000 -2.117000 H1 31 PH4 0.044192 + 1445 C33 2.948000 0.547000 -1.212000 Cg 31 PH4 0.140594 + 1446 H3A 2.513000 1.508000 -0.934000 H1 31 PH4 0.045548 + 1447 C34 3.901000 0.136000 -0.101000 Cp 31 PH4 0.148925 + 1448 H4A 4.366000 -0.804000 -0.370000 H1 31 PH4 0.087260 + 1449 C35 3.194000 -0.024000 1.245000 Cg 31 PH4 0.140594 + 1450 H5A 2.875000 0.967000 1.565000 H1 31 PH4 0.045548 + 1451 C36 1.941000 -0.906000 1.161000 Cg 31 PH4 0.186520 + 1452 H6A 2.270000 -1.934000 1.035000 H1 31 PH4 0.044192 + 1453 O35 2.320000 -1.703000 -1.716000 Oh 31 PH4 -0.636438 + 1454 HO5A 1.616000 -2.328000 -1.588000 Ho 31 PH4 0.393486 + 1455 O36 3.613000 0.675000 -2.436000 Oh 31 PH4 -0.629193 + 1456 HO6A 4.508000 0.944000 -2.255000 Ho 31 PH4 0.397313 + 1457 O37 4.868000 1.163000 -0.008000 Os 31 PH4 -0.516953 + 1458 O38 4.051000 -0.576000 2.201000 Oh 31 PH4 -0.629193 + 1459 HO8A 4.964000 -0.459000 1.934000 Ho 31 PH4 0.397313 + 1460 O39 1.247000 -0.758000 2.367000 Oh 31 PH4 -0.636438 + 1461 HO9A 0.329000 -1.008000 2.260000 Ho 31 PH4 0.393486 + 1462 P37 6.466000 0.842000 0.060000 P 31 PH4 1.307595 + 1463 O44 6.645000 -0.311000 0.979000 O2 31 PH4 -0.804782 + 1464 O43 6.702000 0.259000 -1.457000 oH 31 PH4 -0.707422 + 1465 O45 7.166000 2.120000 0.192000 O2 31 PH4 -0.804782 + 1466 HOP7 6.721000 -0.688000 -1.412000 hO 31 PH4 0.395243 + 1467 C11 2.847000 1.974000 2.166000 cC 32 PH5 0.739172 + 1468 O12 3.867000 2.541000 1.914000 oC 32 PH5 -0.603343 + 1469 O11 2.629000 0.698000 1.897000 oS 32 PH5 -0.450916 + 1470 C1 3.638000 -0.052000 1.232000 cA 32 PH5 -0.039514 + 1471 HR 3.449000 -1.079000 1.497000 hE 32 PH5 0.100768 + 1472 HS 4.607000 0.265000 1.583000 hE 32 PH5 0.100768 + 1473 C2 3.554000 0.149000 -0.282000 cA 32 PH5 0.456628 + 1474 HX 3.196000 1.140000 -0.505000 hE 32 PH5 -0.011950 + 1475 C3 2.710000 -0.915000 -0.979000 cA 32 PH5 0.201677 + 1476 HA 3.268000 -1.843000 -0.968000 hE 32 PH5 -0.004986 + 1477 HB 2.530000 -0.627000 -2.008000 hE 32 PH5 -0.004986 + 1478 O31 1.497000 -1.048000 -0.304000 Os 32 PH5 -0.450141 + 1479 P31 1.026000 -2.557000 0.166000 P 32 PH5 1.277841 + 1480 O32 -0.126000 -2.123000 1.191000 Os 32 PH5 -0.515918 + 1481 O33 2.136000 -3.147000 0.934000 O2 32 PH5 -0.803135 + 1482 O34 0.455000 -3.254000 -1.011000 O2 32 PH5 -0.803135 + 1483 O21 4.903000 0.029000 -0.770000 oS 32 PH5 -0.501131 + 1484 C21 5.301000 0.734000 -1.810000 cC 32 PH5 0.724785 + 1485 O22 4.620000 1.479000 -2.437000 oC 32 PH5 -0.611955 + 1486 C31 -1.423000 -1.578000 1.019000 Cp 32 PH5 0.048553 + 1487 H1A -1.805000 -1.564000 2.035000 H1 32 PH5 0.029370 + 1488 C32 -2.380000 -2.444000 0.207000 Cg 32 PH5 0.423018 + 1489 H2A -2.358000 -3.454000 0.613000 H1 32 PH5 -0.082735 + 1490 C33 -3.802000 -1.890000 0.348000 Cg 32 PH5 0.248683 + 1491 H3A -4.140000 -2.004000 1.372000 H1 32 PH5 -0.017624 + 1492 C34 -3.885000 -0.403000 -0.017000 Cg 32 PH5 0.249272 + 1493 H4A -3.708000 -0.311000 -1.084000 H1 32 PH5 0.030988 + 1494 C35 -2.826000 0.429000 0.730000 Cp 32 PH5 0.117340 + 1495 H5A -3.055000 0.364000 1.790000 H1 32 PH5 0.009407 + 1496 C36 -1.413000 -0.126000 0.537000 Cg 32 PH5 0.388882 + 1497 H6A -1.135000 -0.059000 -0.507000 H1 32 PH5 -0.007594 + 1498 O35 -2.114000 -2.471000 -1.165000 Oh 32 PH5 -0.724386 + 1499 HO5 -1.221000 -2.807000 -1.304000 Ho 32 PH5 0.451278 + 1500 O36 -4.670000 -2.663000 -0.438000 Oh 32 PH5 -0.647134 + 1501 HO6 -4.247000 -2.745000 -1.285000 Ho 32 PH5 0.365505 + 1502 O37 -5.167000 0.045000 0.309000 Oh 32 PH5 -0.685668 + 1503 HO7 -5.283000 0.891000 -0.134000 Ho 32 PH5 0.404091 + 1504 O38 -2.892000 1.799000 0.437000 Os 32 PH5 -0.514092 + 1505 O39 -0.522000 0.618000 1.327000 Oh 32 PH5 -0.639190 + 1506 HO9 0.341000 0.245000 1.195000 Ho 32 PH5 0.368983 + 1507 P38 -3.311000 2.482000 -0.985000 P 32 PH5 1.301926 + 1508 O46 -2.940000 4.018000 -0.596000 oH 32 PH5 -0.699569 + 1509 O47 -4.783000 2.389000 -1.124000 O2 32 PH5 -0.806827 + 1510 O48 -2.392000 2.032000 -2.046000 O2 32 PH5 -0.806827 + 1511 HOP8 -2.010000 4.127000 -0.740000 hO 32 PH5 0.393820 + 1512 C11 4.983000 1.726000 -0.782000 cC 33 PI 0.727278 + 1513 O12 5.245000 2.097000 0.322000 oC 33 PI -0.594162 + 1514 O11 3.830000 1.212000 -1.150000 oS 33 PI -0.452915 + 1515 C1 2.791000 0.989000 -0.199000 cA 33 PI 0.144555 + 1516 HR 1.874000 1.113000 -0.751000 hE 33 PI 0.067492 + 1517 HS 2.859000 1.720000 0.593000 hE 33 PI 0.067492 + 1518 C2 2.827000 -0.422000 0.358000 cA 33 PI 0.330603 + 1519 HX 2.931000 -1.135000 -0.444000 hE 33 PI 0.080584 + 1520 C3 1.586000 -0.728000 1.200000 cA 33 PI 0.093607 + 1521 HA 1.642000 -0.144000 2.113000 hE 33 PI 0.059405 + 1522 HB 1.594000 -1.778000 1.456000 hE 33 PI 0.059405 + 1523 O31 0.398000 -0.375000 0.560000 Os 33 PI -0.562722 + 1524 P31 -0.167000 -1.259000 -0.740000 P 33 PI 1.322077 + 1525 O32 -1.694000 -1.434000 -0.209000 Os 33 PI -0.471537 + 1526 O33 0.516000 -2.554000 -0.698000 O2 33 PI -0.789774 + 1527 O34 -0.168000 -0.347000 -1.895000 O2 33 PI -0.789774 + 1528 O21 3.909000 -0.583000 1.286000 oS 33 PI -0.534275 + 1529 C21 5.093000 -1.018000 0.901000 cC 33 PI 0.739996 + 1530 O22 5.384000 -1.313000 -0.215000 oC 33 PI -0.585908 + 1531 C31 -2.727000 -0.558000 -0.567000 Cp 33 PI 0.118653 + 1532 H1A -2.776000 -0.467000 -1.645000 H1 33 PI 0.069393 + 1533 C32 -2.467000 0.835000 0.032000 Cg 33 PI 0.119693 + 1534 H2A -1.640000 1.279000 -0.505000 H1 33 PI 0.058812 + 1535 C33 -3.674000 1.759000 -0.067000 Cg 33 PI 0.124089 + 1536 H3A -3.863000 2.003000 -1.107000 H1 33 PI 0.057037 + 1537 C34 -4.918000 1.102000 0.510000 Cg 33 PI 0.236809 + 1538 H4A -4.758000 0.902000 1.566000 H1 33 PI 0.032417 + 1539 C35 -5.196000 -0.202000 -0.205000 Cg 33 PI 0.124089 + 1540 H5A -5.352000 0.004000 -1.263000 H1 33 PI 0.057037 + 1541 C36 -4.030000 -1.172000 -0.063000 Cg 33 PI 0.119693 + 1542 H6A -3.908000 -1.415000 0.989000 H1 33 PI 0.058812 + 1543 O35 -2.152000 0.755000 1.403000 Oh 33 PI -0.597289 + 1544 HO5A -1.313000 0.306000 1.469000 Ho 33 PI 0.397044 + 1545 O36 -3.434000 2.977000 0.596000 Oh 33 PI -0.589294 + 1546 HO6A -2.895000 2.770000 1.352000 Ho 33 PI 0.369765 + 1547 O37 -6.046000 1.933000 0.352000 Oh 33 PI -0.615463 + 1548 HO7A -5.801000 2.800000 0.652000 Ho 33 PI 0.367051 + 1549 O38 -6.339000 -0.836000 0.319000 Oh 33 PI -0.589294 + 1550 HO8A -7.044000 -0.201000 0.326000 Ho 33 PI 0.369765 + 1551 O39 -4.298000 -2.331000 -0.802000 Oh 33 PI -0.597289 + 1552 HO9A -5.120000 -2.685000 -0.490000 Ho 33 PI 0.397044 + 1553 C11 -5.629000 -1.687000 -0.882000 cC 34 PI3 0.788628 + 1554 O12 -6.384000 -0.794000 -1.121000 oC 34 PI3 -0.653419 + 1555 O11 -4.358000 -1.707000 -1.226000 oS 34 PI3 -0.507120 + 1556 C1 -3.731000 -0.505000 -1.666000 cA 34 PI3 0.303262 + 1557 HR -4.412000 0.051000 -2.294000 hE 34 PI3 -0.013102 + 1558 HS -2.879000 -0.833000 -2.244000 hE 34 PI3 -0.013102 + 1559 C2 -3.273000 0.329000 -0.481000 cA 34 PI3 0.451172 + 1560 HX -4.115000 0.598000 0.135000 hE 34 PI3 -0.039972 + 1561 C3 -2.539000 1.588000 -0.923000 cA 34 PI3 0.153433 + 1562 HA -3.149000 2.120000 -1.652000 hE 34 PI3 -0.009489 + 1563 HB -1.615000 1.308000 -1.412000 hE 34 PI3 -0.009489 + 1564 O31 -2.329000 2.387000 0.187000 Os 34 PI3 -0.470821 + 1565 P31 -0.890000 3.154000 0.442000 P 34 PI3 1.202277 + 1566 O32 0.068000 1.908000 0.795000 Os 34 PI3 -0.488480 + 1567 O33 -1.113000 3.992000 1.626000 O2 34 PI3 -0.797757 + 1568 O34 -0.446000 3.718000 -0.864000 O2 34 PI3 -0.797757 + 1569 O21 -2.358000 -0.438000 0.273000 oS 34 PI3 -0.535157 + 1570 C21 -2.705000 -1.007000 1.415000 cC 34 PI3 0.826003 + 1571 O22 -3.837000 -1.063000 1.807000 oC 34 PI3 -0.689138 + 1572 C31 1.081000 1.395000 -0.061000 Cp 34 PI3 0.057965 + 1573 H1A 0.770000 1.541000 -1.089000 H1 34 PI3 0.007584 + 1574 C32 1.271000 -0.106000 0.177000 Cg 34 PI3 0.613553 + 1575 H2A 0.337000 -0.601000 -0.084000 H1 34 PI3 -0.058273 + 1576 C33 2.341000 -0.641000 -0.793000 Cp 34 PI3 0.094053 + 1577 H3A 2.028000 -0.334000 -1.796000 H1 34 PI3 -0.057651 + 1578 C34 3.701000 0.048000 -0.561000 Cg 34 PI3 0.608170 + 1579 H4A 4.034000 -0.143000 0.452000 H1 34 PI3 -0.087007 + 1580 C35 3.502000 1.548000 -0.746000 Cg 34 PI3 0.024872 + 1581 H5A 3.220000 1.720000 -1.787000 H1 34 PI3 0.027045 + 1582 C36 2.399000 2.129000 0.145000 Cg 34 PI3 0.296535 + 1583 H6A 2.691000 2.017000 1.181000 H1 34 PI3 0.007850 + 1584 O35 1.582000 -0.330000 1.515000 Oh 34 PI3 -0.777609 + 1585 HO5A 2.087000 -1.174000 1.592000 Ho 34 PI3 0.453342 + 1586 O36 2.358000 -2.026000 -0.820000 Os 34 PI3 -0.649399 + 1587 O37 4.648000 -0.409000 -1.476000 Oh 34 PI3 -0.818982 + 1588 HO7A 4.811000 -1.331000 -1.198000 Ho 34 PI3 0.476680 + 1589 O38 4.696000 2.260000 -0.486000 Oh 34 PI3 -0.633804 + 1590 HO8A 4.427000 3.168000 -0.431000 Ho 34 PI3 0.344516 + 1591 O39 2.316000 3.518000 -0.131000 Oh 34 PI3 -0.616275 + 1592 HO9A 1.464000 3.724000 -0.518000 Ho 34 PI3 0.357303 + 1593 P36 3.300000 -3.058000 0.167000 P 34 PI3 1.403647 + 1594 O40 4.719000 -2.798000 -0.305000 O2 34 PI3 -0.924696 + 1595 O41 2.744000 -4.408000 -0.145000 O2 34 PI3 -0.924696 + 1596 O42 3.020000 -2.528000 1.566000 O2 34 PI3 -0.924696 + 1597 C11 6.425000 -0.722000 -1.497000 cC 35 PI4 0.664646 + 1598 O12 6.425000 0.177000 -2.285000 oC 35 PI4 -0.604926 + 1599 O11 5.412000 -1.107000 -0.770000 oS 35 PI4 -0.305928 + 1600 C1 4.149000 -0.415000 -0.788000 cA 35 PI4 -0.007522 + 1601 HR 3.397000 -1.181000 -0.822000 hE 35 PI4 0.071082 + 1602 HS 4.101000 0.214000 -1.659000 hE 35 PI4 0.071082 + 1603 C2 3.993000 0.311000 0.537000 cA 35 PI4 0.324833 + 1604 HX 4.166000 -0.435000 1.294000 hE 35 PI4 -0.017911 + 1605 C3 2.600000 0.921000 0.784000 cA 35 PI4 0.492384 + 1606 HA 2.498000 1.871000 0.276000 hE 35 PI4 -0.079552 + 1607 HB 2.496000 1.103000 1.847000 hE 35 PI4 -0.079552 + 1608 O31 1.596000 0.093000 0.313000 Os 35 PI4 -0.538559 + 1609 P31 1.182000 -1.254000 1.202000 P 35 PI4 1.234809 + 1610 O32 -0.168000 -1.634000 0.465000 Os 35 PI4 -0.690227 + 1611 O33 0.954000 -0.792000 2.594000 O2 35 PI4 -0.783731 + 1612 O34 2.212000 -2.276000 0.921000 O2 35 PI4 -0.783731 + 1613 O21 5.043000 1.263000 0.803000 oS 35 PI4 -0.485882 + 1614 C21 5.340000 2.398000 0.190000 cC 35 PI4 0.732377 + 1615 O22 6.179000 3.100000 0.668000 oC 35 PI4 -0.642085 + 1616 C31 -1.297000 -0.818000 0.140000 Cp 35 PI4 0.656500 + 1617 H1A -1.014000 -0.194000 -0.699000 H1 35 PI4 -0.130546 + 1618 C32 -1.748000 0.081000 1.310000 Cg 35 PI4 0.207562 + 1619 H2A -0.987000 0.838000 1.475000 H1 35 PI4 -0.016595 + 1620 C33 -3.046000 0.793000 0.930000 Cg 35 PI4 0.069711 + 1621 H3A -2.855000 1.393000 0.045000 H1 35 PI4 0.047277 + 1622 C34 -4.169000 -0.186000 0.573000 Cp 35 PI4 0.545602 + 1623 H4A -4.296000 -0.874000 1.409000 H1 35 PI4 -0.097692 + 1624 C35 -3.700000 -0.996000 -0.632000 Cg 35 PI4 0.069711 + 1625 H5A -3.496000 -0.306000 -1.446000 H1 35 PI4 0.047277 + 1626 C36 -2.415000 -1.756000 -0.299000 Cg 35 PI4 0.207562 + 1627 H6A -2.613000 -2.444000 0.519000 H1 35 PI4 -0.016595 + 1628 O35 -1.905000 -0.669000 2.484000 Oh 35 PI4 -0.675433 + 1629 HO5A -1.022000 -0.846000 2.800000 Ho 35 PI4 0.391355 + 1630 O36 -3.456000 1.642000 1.971000 Oh 35 PI4 -0.640642 + 1631 HO6A -4.367000 1.823000 1.754000 Ho 35 PI4 0.363272 + 1632 O37 -5.369000 0.497000 0.435000 Os 35 PI4 -0.638409 + 1633 O38 -4.632000 -1.949000 -1.060000 Oh 35 PI4 -0.640642 + 1634 HO8A -5.377000 -1.399000 -1.411000 Ho 35 PI4 0.363272 + 1635 O39 -2.021000 -2.489000 -1.439000 Oh 35 PI4 -0.675433 + 1636 HO9A -2.847000 -2.727000 -1.847000 Ho 35 PI4 0.391355 + 1637 P37 -5.978000 1.145000 -1.053000 P 35 PI4 1.340114 + 1638 O43 -6.307000 -0.120000 -1.842000 O2 35 PI4 -0.913397 + 1639 O44 -7.163000 1.925000 -0.579000 O2 35 PI4 -0.913397 + 1640 O45 -4.815000 1.923000 -1.605000 O2 35 PI4 -0.913397 + 1641 C11 6.509000 -0.596000 -0.970000 cC 36 PI5 0.738302 + 1642 O12 6.288000 -0.029000 -1.997000 oC 36 PI5 -0.625973 + 1643 O11 5.612000 -0.986000 -0.100000 oS 36 PI5 -0.462084 + 1644 C1 4.217000 -0.666000 -0.267000 cA 36 PI5 0.041566 + 1645 HR 3.669000 -1.498000 0.137000 hE 36 PI5 0.112718 + 1646 HS 3.993000 -0.565000 -1.317000 hE 36 PI5 0.112718 + 1647 C2 3.861000 0.600000 0.487000 cA 36 PI5 0.268795 + 1648 HX 4.395000 0.635000 1.423000 hE 36 PI5 0.096255 + 1649 C3 2.361000 0.711000 0.749000 cA 36 PI5 0.013120 + 1650 HA 1.808000 0.590000 -0.173000 hE 36 PI5 0.041551 + 1651 HB 2.150000 1.702000 1.134000 hE 36 PI5 0.041551 + 1652 O31 2.018000 -0.240000 1.702000 Os 36 PI5 -0.488279 + 1653 P31 0.903000 -1.396000 1.344000 P 36 PI5 1.211937 + 1654 O32 -0.317000 -0.414000 1.009000 Os 36 PI5 -0.334696 + 1655 O33 0.704000 -2.200000 2.557000 O2 36 PI5 -0.795106 + 1656 O34 1.360000 -2.030000 0.069000 O2 36 PI5 -0.795106 + 1657 O21 4.219000 1.754000 -0.299000 oS 36 PI5 -0.371925 + 1658 C21 5.365000 2.368000 -0.144000 cC 36 PI5 0.672891 + 1659 O22 6.205000 2.082000 0.657000 oC 36 PI5 -0.615767 + 1660 C31 -1.684000 -0.769000 0.795000 Cp 36 PI5 -0.019611 + 1661 H1A -2.116000 -1.015000 1.760000 H1 36 PI5 0.064350 + 1662 C32 -1.796000 -1.997000 -0.115000 Cg 36 PI5 0.033839 + 1663 H2A -1.397000 -2.858000 0.417000 H1 36 PI5 0.072443 + 1664 C33 -3.244000 -2.320000 -0.493000 Cg 36 PI5 0.293411 + 1665 H3A -3.783000 -2.633000 0.395000 H1 36 PI5 0.021129 + 1666 C34 -3.982000 -1.121000 -1.086000 Cg 36 PI5 0.222519 + 1667 H4A -3.534000 -0.888000 -2.053000 H1 36 PI5 0.011679 + 1668 C35 -3.844000 0.101000 -0.183000 Cp 36 PI5 0.211615 + 1669 H5A -4.389000 -0.123000 0.731000 H1 36 PI5 0.051569 + 1670 C36 -2.415000 0.452000 0.233000 Cg 36 PI5 0.161858 + 1671 H6A -1.868000 0.788000 -0.646000 H1 36 PI5 0.027569 + 1672 O35 -1.073000 -1.838000 -1.315000 Oh 36 PI5 -0.622167 + 1673 HO5A -0.144000 -1.885000 -1.082000 Ho 36 PI5 0.404602 + 1674 O36 -3.232000 -3.438000 -1.359000 Oh 36 PI5 -0.687349 + 1675 HO6A -2.566000 -3.239000 -2.005000 Ho 36 PI5 0.378128 + 1676 O37 -5.333000 -1.441000 -1.254000 Oh 36 PI5 -0.719850 + 1677 HO7A -5.874000 -0.704000 -0.916000 Ho 36 PI5 0.432585 + 1678 O38 -4.399000 1.198000 -0.825000 Os 36 PI5 -0.568921 + 1679 O39 -2.448000 1.467000 1.194000 Oh 36 PI5 -0.575713 + 1680 HO9A -3.345000 1.838000 1.227000 Ho 36 PI5 0.357656 + 1681 P38 -5.772000 1.876000 -0.060000 P 36 PI5 1.350295 + 1682 O46 -5.199000 2.249000 1.295000 O2 36 PI5 -0.921368 + 1683 O47 -6.714000 0.682000 -0.036000 O2 36 PI5 -0.921368 + 1684 O48 -6.165000 3.009000 -0.954000 O2 36 PI5 -0.921368 + 1685 C1 -3.699000 -1.908000 -0.665000 cA 37 SIT -0.027519 + 1686 H11 -3.267000 -2.345000 0.233000 hA 37 SIT 0.019889 + 1687 H12 -3.104000 -2.267000 -1.498000 hA 37 SIT 0.019889 + 1688 C2 -5.128000 -2.435000 -0.815000 cA 37 SIT -0.221198 + 1689 H21 -5.570000 -2.118000 -1.755000 hA 37 SIT 0.058211 + 1690 H22 -5.120000 -3.521000 -0.826000 hA 37 SIT 0.058211 + 1691 C3 -6.011000 -1.951000 0.320000 cA 37 SIT 0.455968 + 1692 H31 -5.627000 -2.350000 1.260000 hE 37 SIT -0.011214 + 1693 C4 -5.990000 -0.425000 0.387000 cA 37 SIT -0.381111 + 1694 H41 -6.488000 -0.054000 -0.505000 hA 37 SIT 0.122013 + 1695 H42 -6.576000 -0.081000 1.236000 hA 37 SIT 0.122013 + 1696 C5 -4.581000 0.125000 0.487000 cB 37 SIT -0.028865 + 1697 C6 -4.264000 0.977000 1.448000 cB 37 SIT -0.277617 + 1698 H61 -5.020000 1.255000 2.166000 hB 37 SIT 0.142082 + 1699 C7 -2.915000 1.609000 1.637000 cA 37 SIT -0.008947 + 1700 H71 -3.044000 2.665000 1.863000 hA 37 SIT 0.035065 + 1701 H72 -2.440000 1.175000 2.518000 hA 37 SIT 0.035065 + 1702 C8 -2.004000 1.440000 0.419000 cA 37 SIT 0.002113 + 1703 H81 -2.338000 2.141000 -0.341000 hA 37 SIT 0.047395 + 1704 C9 -2.123000 -0.003000 -0.123000 cA 37 SIT -0.231270 + 1705 H91 -1.899000 -0.651000 0.724000 hA 37 SIT 0.058964 + 1706 C10 -3.578000 -0.363000 -0.564000 cA 37 SIT 0.313563 + 1707 C11 -1.061000 -0.305000 -1.202000 cA 37 SIT -0.004110 + 1708 H111 -1.083000 -1.362000 -1.448000 hA 37 SIT 0.019859 + 1709 H112 -1.299000 0.220000 -2.119000 hA 37 SIT 0.019859 + 1710 C12 0.372000 0.060000 -0.783000 cA 37 SIT -0.143221 + 1711 H121 0.675000 -0.580000 0.043000 hA 37 SIT 0.014064 + 1712 H122 1.040000 -0.161000 -1.610000 hA 37 SIT 0.014064 + 1713 C13 0.481000 1.528000 -0.349000 cA 37 SIT 0.394580 + 1714 C14 -0.548000 1.735000 0.787000 cA 37 SIT 0.020129 + 1715 H141 -0.286000 1.000000 1.550000 hA 37 SIT 0.017858 + 1716 C15 -0.197000 3.107000 1.372000 cA 37 SIT -0.141875 + 1717 H151 -0.683000 3.903000 0.814000 hA 37 SIT 0.033550 + 1718 H152 -0.516000 3.209000 2.403000 hA 37 SIT 0.033550 + 1719 C16 1.343000 3.187000 1.227000 cA 37 SIT -0.088269 + 1720 H161 1.633000 4.101000 0.723000 hA 37 SIT 0.030413 + 1721 H162 1.837000 3.203000 2.193000 hA 37 SIT 0.030413 + 1722 C17 1.777000 1.928000 0.424000 cA 37 SIT -0.014518 + 1723 H171 1.907000 1.141000 1.162000 hA 37 SIT -0.026417 + 1724 C18 0.208000 2.454000 -1.552000 cA 37 SIT -0.468679 + 1725 H181 0.411000 3.493000 -1.326000 hA 37 SIT 0.100703 + 1726 H182 -0.820000 2.397000 -1.885000 hA 37 SIT 0.100703 + 1727 H183 0.828000 2.177000 -2.397000 hA 37 SIT 0.100703 + 1728 C19 -3.938000 0.273000 -1.927000 cA 37 SIT -0.277370 + 1729 H191 -3.375000 -0.177000 -2.736000 hA 37 SIT 0.066868 + 1730 H192 -3.741000 1.339000 -1.929000 hA 37 SIT 0.066868 + 1731 H193 -4.987000 0.143000 -2.161000 hA 37 SIT 0.066868 + 1732 C20 3.178000 2.089000 -0.226000 cD 37 SIT 0.193853 + 1733 H201 3.800000 2.441000 0.597000 hL 37 SIT -0.030488 + 1734 C21 3.316000 3.144000 -1.336000 cD 37 SIT -0.363341 + 1735 H211 4.367000 3.371000 -1.486000 hL 37 SIT 0.082407 + 1736 H212 2.819000 4.076000 -1.097000 hL 37 SIT 0.082407 + 1737 H213 2.927000 2.794000 -2.284000 hL 37 SIT 0.082407 + 1738 C22 3.825000 0.776000 -0.713000 cD 37 SIT -0.040551 + 1739 H221 3.232000 0.344000 -1.515000 hL 37 SIT 0.006984 + 1740 H222 4.776000 1.041000 -1.165000 hL 37 SIT 0.006984 + 1741 C23 4.068000 -0.291000 0.363000 cD 37 SIT -0.031666 + 1742 H231 4.512000 0.176000 1.241000 hL 37 SIT 0.008997 + 1743 H232 3.116000 -0.691000 0.686000 hL 37 SIT 0.008997 + 1744 C24 4.980000 -1.442000 -0.116000 cD 37 SIT -0.066704 + 1745 C25 4.724000 -2.774000 0.636000 cD 37 SIT 0.386372 + 1746 H251 5.525000 -3.454000 0.359000 hL 37 SIT -0.071024 + 1747 C26 3.419000 -3.443000 0.188000 cD 37 SIT -0.333335 + 1748 H261 2.546000 -2.849000 0.442000 hL 37 SIT 0.068204 + 1749 H262 3.300000 -4.411000 0.667000 hL 37 SIT 0.068204 + 1750 H263 3.408000 -3.604000 -0.886000 hL 37 SIT 0.068204 + 1751 C27 4.756000 -2.644000 2.165000 cD 37 SIT -0.333335 + 1752 H271 4.682000 -3.624000 2.626000 hL 37 SIT 0.068204 + 1753 H272 3.928000 -2.048000 2.535000 hL 37 SIT 0.068204 + 1754 H273 5.675000 -2.188000 2.519000 hL 37 SIT 0.068204 + 1755 O1 -7.309000 -2.441000 0.092000 oH 37 SIT -0.641285 + 1756 HO1 -7.873000 -2.195000 0.813000 hO 37 SIT 0.358123 + 1757 C28 6.463000 -1.019000 -0.071000 cD 37 SIT 0.113910 + 1758 H241 4.737000 -1.631000 -1.162000 hL 37 SIT 0.001714 + 1759 C29 7.401000 -1.870000 -0.929000 cD 37 SIT -0.134162 + 1760 H281 6.813000 -1.020000 0.958000 hL 37 SIT -0.023882 + 1761 H282 6.547000 0.011000 -0.406000 hL 37 SIT -0.023882 + 1762 H291 8.416000 -1.485000 -0.883000 hL 37 SIT 0.027328 + 1763 H292 7.093000 -1.860000 -1.971000 hL 37 SIT 0.027328 + 1764 H293 7.434000 -2.905000 -0.606000 hL 37 SIT 0.027328 + 1765 C1 -5.062000 -1.516000 -0.149000 cA 38 STI -0.053919 + 1766 H11 -5.073000 -1.582000 0.937000 hA 38 STI 0.023792 + 1767 H12 -4.642000 -2.447000 -0.511000 hA 38 STI 0.023792 + 1768 C2 -6.509000 -1.401000 -0.637000 cA 38 STI -0.189319 + 1769 H21 -6.563000 -1.438000 -1.721000 hA 38 STI 0.054674 + 1770 H22 -7.079000 -2.252000 -0.269000 hA 38 STI 0.054674 + 1771 C3 -7.148000 -0.102000 -0.165000 cA 38 STI 0.435218 + 1772 H31 -7.183000 -0.100000 0.925000 hE 38 STI -0.007207 + 1773 C4 -6.320000 1.088000 -0.627000 cA 38 STI -0.393318 + 1774 H41 -6.405000 1.143000 -1.710000 hA 38 STI 0.131931 + 1775 H42 -6.752000 2.001000 -0.236000 hA 38 STI 0.131931 + 1776 C5 -4.867000 0.974000 -0.205000 cB 38 STI -0.033001 + 1777 C6 -4.283000 1.971000 0.436000 cB 38 STI -0.260722 + 1778 H61 -4.864000 2.850000 0.669000 hB 38 STI 0.138059 + 1779 C7 -2.849000 1.995000 0.883000 cA 38 STI -0.019544 + 1780 H71 -2.419000 2.967000 0.655000 hA 38 STI 0.035502 + 1781 H72 -2.814000 1.904000 1.969000 hA 38 STI 0.035502 + 1782 C8 -2.009000 0.889000 0.241000 cA 38 STI -0.007755 + 1783 H81 -1.797000 1.185000 -0.782000 hA 38 STI 0.045297 + 1784 C9 -2.806000 -0.437000 0.242000 cA 38 STI -0.157432 + 1785 H91 -3.093000 -0.601000 1.281000 hA 38 STI 0.045422 + 1786 C10 -4.144000 -0.332000 -0.558000 cA 38 STI 0.276869 + 1787 C11 -1.939000 -1.648000 -0.171000 cA 38 STI -0.013502 + 1788 H111 -2.494000 -2.565000 0.000000 hA 38 STI 0.023520 + 1789 H112 -1.735000 -1.617000 -1.234000 hA 38 STI 0.023520 + 1790 C12 -0.603000 -1.745000 0.584000 cA 38 STI -0.164660 + 1791 H121 -0.798000 -1.953000 1.634000 hA 38 STI 0.020578 + 1792 H122 -0.041000 -2.593000 0.199000 hA 38 STI 0.020578 + 1793 C13 0.200000 -0.444000 0.472000 cA 38 STI 0.351756 + 1794 C14 -0.695000 0.693000 1.001000 cA 38 STI 0.025882 + 1795 H141 -0.983000 0.388000 2.008000 hA 38 STI 0.017882 + 1796 C15 0.265000 1.878000 1.172000 cA 38 STI -0.121866 + 1797 H151 0.371000 2.431000 0.243000 hA 38 STI 0.031227 + 1798 H152 -0.085000 2.585000 1.916000 hA 38 STI 0.031227 + 1799 C16 1.609000 1.217000 1.580000 cA 38 STI -0.116205 + 1800 H161 2.412000 1.545000 0.932000 hA 38 STI 0.037456 + 1801 H162 1.898000 1.492000 2.589000 hA 38 STI 0.037456 + 1802 C17 1.386000 -0.315000 1.466000 cA 38 STI 0.001954 + 1803 H171 0.971000 -0.640000 2.417000 hA 38 STI -0.024089 + 1804 C18 0.644000 -0.221000 -0.987000 cA 38 STI -0.443420 + 1805 H181 1.200000 -1.080000 -1.349000 hA 38 STI 0.097714 + 1806 H182 1.278000 0.651000 -1.094000 hA 38 STI 0.097714 + 1807 H183 -0.196000 -0.087000 -1.655000 hA 38 STI 0.097714 + 1808 C19 -3.905000 -0.369000 -2.085000 cA 38 STI -0.283666 + 1809 H191 -4.809000 -0.144000 -2.635000 hA 38 STI 0.070252 + 1810 H192 -3.570000 -1.347000 -2.412000 hA 38 STI 0.070252 + 1811 H193 -3.161000 0.361000 -2.385000 hA 38 STI 0.070252 + 1812 C20 2.658000 -1.191000 1.271000 cD 38 STI 0.244565 + 1813 H201 2.317000 -2.147000 0.874000 hL 38 STI -0.026337 + 1814 C21 3.292000 -1.491000 2.636000 cD 38 STI -0.322941 + 1815 H211 2.576000 -1.990000 3.281000 hL 38 STI 0.074986 + 1816 H212 3.611000 -0.583000 3.140000 hL 38 STI 0.074986 + 1817 H213 4.156000 -2.140000 2.537000 hL 38 STI 0.074986 + 1818 C22 3.662000 -0.652000 0.268000 cB 38 STI -0.221338 + 1819 C23 4.911000 -0.286000 0.498000 cB 38 STI -0.210439 + 1820 C24 5.865000 0.253000 -0.545000 cD 38 STI -0.064315 + 1821 C25 7.115000 -0.657000 -0.673000 cD 38 STI 0.404864 + 1822 H251 7.599000 -0.679000 0.304000 hL 38 STI -0.068508 + 1823 C26 8.138000 -0.129000 -1.686000 cD 38 STI -0.342950 + 1824 H261 7.703000 -0.061000 -2.680000 hL 38 STI 0.070651 + 1825 H262 8.988000 -0.801000 -1.747000 hL 38 STI 0.070651 + 1826 H263 8.519000 0.850000 -1.420000 hL 38 STI 0.070651 + 1827 C27 6.736000 -2.096000 -1.043000 cD 38 STI -0.342950 + 1828 H271 6.077000 -2.545000 -0.310000 hL 38 STI 0.070651 + 1829 H272 7.624000 -2.717000 -1.119000 hL 38 STI 0.070651 + 1830 H273 6.230000 -2.127000 -2.005000 hL 38 STI 0.070651 + 1831 O1 -8.445000 0.068000 -0.681000 oH 38 STI -0.646680 + 1832 HO1 -9.000000 -0.637000 -0.378000 hO 38 STI 0.364742 + 1833 C28 6.220000 1.728000 -0.205000 cD 38 STI 0.169925 + 1834 H241 5.349000 0.240000 -1.504000 hL 38 STI 0.020617 + 1835 C29 6.177000 2.679000 -1.404000 cD 38 STI -0.166325 + 1836 H281 7.198000 1.775000 0.267000 hL 38 STI -0.033390 + 1837 H282 5.517000 2.098000 0.535000 hL 38 STI -0.033390 + 1838 H291 5.180000 2.707000 -1.834000 hL 38 STI 0.033985 + 1839 H292 6.864000 2.383000 -2.189000 hL 38 STI 0.033985 + 1840 H293 6.434000 3.690000 -1.104000 hL 38 STI 0.033985 + 1841 H221 3.307000 -0.582000 -0.746000 hB 38 STI 0.125257 + 1842 H231 5.315000 -0.338000 1.498000 hB 38 STI 0.128803 +@BOND + 1 1 2 2 + 2 1 3 1 + 3 3 4 1 + 4 4 5 1 + 5 4 6 1 + 6 4 7 1 + 7 7 8 1 + 8 7 9 1 + 9 7 17 1 + 10 9 10 1 + 11 9 11 1 + 12 9 12 1 + 13 12 13 1 + 14 13 14 1 + 15 13 15 1 + 16 13 16 1 + 17 14 20 1 + 18 17 18 1 + 19 18 19 2 + 20 20 21 1 + 21 20 22 1 + 22 20 30 1 + 23 22 23 1 + 24 22 24 1 + 25 22 32 1 + 26 24 25 1 + 27 24 26 1 + 28 24 34 1 + 29 26 27 1 + 30 26 28 1 + 31 26 35 1 + 32 28 29 1 + 33 28 30 1 + 34 28 36 1 + 35 30 31 1 + 36 30 38 1 + 37 32 33 1 + 38 34 40 1 + 39 35 44 1 + 40 36 37 1 + 41 38 39 1 + 42 40 41 1 + 43 40 42 1 + 44 40 43 1 + 45 44 45 1 + 46 44 46 1 + 47 44 47 1 + 48 48 49 2 + 49 48 50 1 + 50 50 51 1 + 51 51 52 1 + 52 51 53 1 + 53 51 54 1 + 54 54 55 1 + 55 54 56 1 + 56 54 64 1 + 57 56 57 1 + 58 56 58 1 + 59 56 59 1 + 60 59 60 1 + 61 60 61 1 + 62 60 62 1 + 63 60 63 1 + 64 61 67 1 + 65 64 65 1 + 66 65 66 2 + 67 67 68 1 + 68 67 69 1 + 69 67 77 1 + 70 69 70 1 + 71 69 71 1 + 72 69 79 1 + 73 71 72 1 + 74 71 73 1 + 75 71 81 1 + 76 73 74 1 + 77 73 75 1 + 78 73 82 1 + 79 75 76 1 + 80 75 77 1 + 81 75 84 1 + 82 77 78 1 + 83 77 85 1 + 84 79 80 1 + 85 81 87 1 + 86 82 83 1 + 87 84 91 1 + 88 85 86 1 + 89 87 88 1 + 90 87 89 1 + 91 87 90 1 + 92 91 92 1 + 93 91 93 1 + 94 91 94 1 + 95 95 96 2 + 96 95 97 1 + 97 97 98 1 + 98 98 99 1 + 99 98 100 1 + 100 98 101 1 + 101 101 102 1 + 102 101 103 1 + 103 101 111 1 + 104 103 104 1 + 105 103 105 1 + 106 103 106 1 + 107 106 107 1 + 108 107 108 1 + 109 107 109 1 + 110 107 110 1 + 111 108 114 1 + 112 111 112 1 + 113 112 113 2 + 114 114 115 1 + 115 114 116 1 + 116 114 124 1 + 117 116 117 1 + 118 116 118 1 + 119 116 126 1 + 120 118 119 1 + 121 118 120 1 + 122 118 128 1 + 123 120 121 1 + 124 120 122 1 + 125 120 130 1 + 126 122 123 1 + 127 122 124 1 + 128 122 131 1 + 129 124 125 1 + 130 124 132 1 + 131 126 127 1 + 132 128 129 1 + 133 130 134 1 + 134 131 138 1 + 135 132 133 1 + 136 134 135 1 + 137 134 136 1 + 138 134 137 1 + 139 138 139 1 + 140 138 140 1 + 141 138 141 1 + 142 142 143 1 + 143 142 144 1 + 144 142 145 1 + 145 142 163 1 + 146 145 146 1 + 147 145 147 1 + 148 145 148 1 + 149 148 149 1 + 150 148 150 1 + 151 148 212 1 + 152 150 151 1 + 153 150 152 1 + 154 150 153 1 + 155 153 154 2 + 156 153 163 1 + 157 154 155 1 + 158 154 156 1 + 159 156 157 1 + 160 156 158 1 + 161 156 159 1 + 162 159 160 1 + 163 159 161 1 + 164 159 171 1 + 165 161 162 1 + 166 161 163 1 + 167 161 164 1 + 168 163 185 1 + 169 164 165 1 + 170 164 166 1 + 171 164 167 1 + 172 167 168 1 + 173 167 169 1 + 174 167 170 1 + 175 170 171 1 + 176 170 179 1 + 177 170 181 1 + 178 171 172 1 + 179 171 173 1 + 180 173 174 1 + 181 173 175 1 + 182 173 176 1 + 183 176 177 1 + 184 176 178 1 + 185 176 179 1 + 186 179 180 1 + 187 179 189 1 + 188 181 182 1 + 189 181 183 1 + 190 181 184 1 + 191 185 186 1 + 192 185 187 1 + 193 185 188 1 + 194 189 190 1 + 195 189 191 1 + 196 189 195 1 + 197 191 192 1 + 198 191 193 1 + 199 191 194 1 + 200 195 196 1 + 201 195 197 1 + 202 195 198 1 + 203 198 199 1 + 204 198 200 1 + 205 198 201 1 + 206 201 202 1 + 207 201 214 1 + 208 201 215 1 + 209 202 203 1 + 210 202 204 1 + 211 202 208 1 + 212 204 205 1 + 213 204 206 1 + 214 204 207 1 + 215 208 209 1 + 216 208 210 1 + 217 208 211 1 + 218 212 213 1 + 219 214 216 1 + 220 214 217 1 + 221 214 218 1 + 222 219 220 2 + 223 219 221 1 + 224 221 222 1 + 225 222 223 1 + 226 222 224 1 + 227 222 225 1 + 228 225 226 1 + 229 225 227 1 + 230 225 242 1 + 231 227 228 1 + 232 227 229 1 + 233 227 230 1 + 234 230 231 1 + 235 231 232 1 + 236 231 240 1 + 237 231 241 1 + 238 232 233 1 + 239 233 234 1 + 240 233 235 1 + 241 233 236 1 + 242 236 237 1 + 243 236 238 1 + 244 236 239 1 + 245 238 266 1 + 246 239 257 1 + 247 239 264 1 + 248 239 265 1 + 249 242 243 1 + 250 243 244 2 + 251 245 246 2 + 252 246 248 1 + 253 247 249 1 + 254 248 249 1 + 255 249 251 1 + 256 249 254 1 + 257 250 253 1 + 258 252 253 1 + 259 252 256 1 + 260 253 257 1 + 261 253 260 1 + 262 254 255 1 + 263 254 256 1 + 264 254 258 1 + 265 256 259 1 + 266 256 262 1 + 267 258 261 1 + 268 261 263 2 + 269 267 268 1 + 270 267 269 1 + 271 267 270 1 + 272 267 285 1 + 273 270 271 1 + 274 270 272 1 + 275 270 273 1 + 276 273 274 1 + 277 273 275 1 + 278 273 330 1 + 279 275 276 1 + 280 275 277 1 + 281 275 278 1 + 282 278 279 2 + 283 278 285 1 + 284 279 280 1 + 285 279 281 1 + 286 281 282 2 + 287 281 332 1 + 288 282 283 1 + 289 282 293 1 + 290 283 284 1 + 291 283 285 1 + 292 283 286 1 + 293 285 307 1 + 294 286 287 1 + 295 286 288 1 + 296 286 289 1 + 297 289 290 1 + 298 289 291 1 + 299 289 292 1 + 300 292 293 1 + 301 292 301 1 + 302 292 303 1 + 303 293 294 1 + 304 293 295 1 + 305 295 296 1 + 306 295 297 1 + 307 295 298 1 + 308 298 299 1 + 309 298 300 1 + 310 298 301 1 + 311 301 302 1 + 312 301 311 1 + 313 303 304 1 + 314 303 305 1 + 315 303 306 1 + 316 307 308 1 + 317 307 309 1 + 318 307 310 1 + 319 311 312 1 + 320 311 313 1 + 321 311 317 1 + 322 313 314 1 + 323 313 315 1 + 324 313 316 1 + 325 317 318 2 + 326 317 333 1 + 327 318 319 1 + 328 318 334 1 + 329 319 320 1 + 330 319 335 1 + 331 319 336 1 + 332 320 321 1 + 333 320 322 1 + 334 320 326 1 + 335 322 323 1 + 336 322 324 1 + 337 322 325 1 + 338 326 327 1 + 339 326 328 1 + 340 326 329 1 + 341 330 331 1 + 342 335 337 1 + 343 335 338 1 + 344 335 339 1 + 345 340 341 2 + 346 340 342 1 + 347 342 343 1 + 348 343 344 1 + 349 343 345 1 + 350 343 346 1 + 351 346 347 1 + 352 346 348 1 + 353 346 356 1 + 354 348 349 1 + 355 348 350 1 + 356 348 351 1 + 357 351 352 1 + 358 352 353 1 + 359 352 354 1 + 360 352 355 1 + 361 353 359 1 + 362 356 357 1 + 363 357 358 2 + 364 359 360 1 + 365 359 361 1 + 366 359 369 1 + 367 361 362 1 + 368 361 363 1 + 369 361 371 1 + 370 363 364 1 + 371 363 365 1 + 372 363 373 1 + 373 365 366 1 + 374 365 367 1 + 375 365 374 1 + 376 367 368 1 + 377 367 369 1 + 378 367 375 1 + 379 369 370 1 + 380 369 377 1 + 381 371 372 1 + 382 373 379 1 + 383 374 383 1 + 384 375 376 1 + 385 377 378 1 + 386 379 380 1 + 387 379 381 1 + 388 379 382 1 + 389 380 387 1 + 390 383 384 1 + 391 383 385 1 + 392 383 386 1 + 393 384 388 1 + 394 389 390 2 + 395 389 391 1 + 396 391 392 1 + 397 392 393 1 + 398 392 394 1 + 399 392 395 1 + 400 395 396 1 + 401 395 397 1 + 402 395 405 1 + 403 397 398 1 + 404 397 399 1 + 405 397 400 1 + 406 400 401 1 + 407 401 402 1 + 408 401 403 1 + 409 401 404 1 + 410 402 408 1 + 411 405 406 1 + 412 406 407 2 + 413 408 409 1 + 414 408 410 1 + 415 408 418 1 + 416 410 411 1 + 417 410 412 1 + 418 410 420 1 + 419 412 413 1 + 420 412 414 1 + 421 412 422 1 + 422 414 415 1 + 423 414 416 1 + 424 414 423 1 + 425 416 417 1 + 426 416 418 1 + 427 416 425 1 + 428 418 419 1 + 429 418 426 1 + 430 420 421 1 + 431 422 428 1 + 432 423 424 1 + 433 425 432 1 + 434 426 427 1 + 435 428 429 1 + 436 428 430 1 + 437 428 431 1 + 438 429 437 1 + 439 432 433 1 + 440 432 434 1 + 441 432 435 1 + 442 433 436 1 + 443 438 439 2 + 444 438 440 1 + 445 440 441 1 + 446 441 442 1 + 447 441 443 1 + 448 441 444 1 + 449 444 445 1 + 450 444 446 1 + 451 444 454 1 + 452 446 447 1 + 453 446 448 1 + 454 446 449 1 + 455 449 450 1 + 456 450 451 1 + 457 450 452 1 + 458 450 453 1 + 459 451 457 1 + 460 454 455 1 + 461 455 456 2 + 462 457 458 1 + 463 457 459 1 + 464 457 467 1 + 465 459 460 1 + 466 459 461 1 + 467 459 469 1 + 468 461 462 1 + 469 461 463 1 + 470 461 471 1 + 471 463 464 1 + 472 463 465 1 + 473 463 473 1 + 474 465 466 1 + 475 465 467 1 + 476 465 474 1 + 477 467 468 1 + 478 467 475 1 + 479 469 470 1 + 480 471 472 1 + 481 473 477 1 + 482 474 481 1 + 483 475 476 1 + 484 477 478 1 + 485 477 479 1 + 486 477 480 1 + 487 479 485 1 + 488 481 482 1 + 489 481 483 1 + 490 481 484 1 + 491 484 486 1 + 492 487 488 2 + 493 487 489 1 + 494 489 490 1 + 495 490 491 1 + 496 490 492 1 + 497 490 493 1 + 498 493 494 1 + 499 493 495 1 + 500 493 503 1 + 501 495 496 1 + 502 495 497 1 + 503 495 498 1 + 504 498 499 1 + 505 499 500 1 + 506 499 501 1 + 507 499 502 1 + 508 500 506 1 + 509 503 504 1 + 510 504 505 2 + 511 506 507 1 + 512 506 508 1 + 513 506 516 1 + 514 508 509 1 + 515 508 510 1 + 516 508 518 1 + 517 510 511 1 + 518 510 512 1 + 519 510 520 1 + 520 512 513 1 + 521 512 514 1 + 522 512 521 1 + 523 514 515 1 + 524 514 516 1 + 525 514 522 1 + 526 516 517 1 + 527 516 524 1 + 528 518 519 1 + 529 520 526 1 + 530 521 530 1 + 531 522 523 1 + 532 524 525 1 + 533 526 527 1 + 534 526 528 1 + 535 526 529 1 + 536 528 534 1 + 537 530 531 1 + 538 530 532 1 + 539 530 533 1 + 540 535 536 2 + 541 535 537 1 + 542 537 538 1 + 543 538 539 1 + 544 538 540 1 + 545 538 541 1 + 546 541 542 1 + 547 541 543 1 + 548 541 551 1 + 549 543 544 1 + 550 543 545 1 + 551 543 546 1 + 552 546 547 1 + 553 547 548 1 + 554 547 549 1 + 555 547 550 1 + 556 548 554 1 + 557 551 552 1 + 558 552 553 2 + 559 554 555 1 + 560 554 556 1 + 561 554 564 1 + 562 556 557 1 + 563 556 558 1 + 564 556 566 1 + 565 558 559 1 + 566 558 560 1 + 567 558 568 1 + 568 560 561 1 + 569 560 562 1 + 570 560 569 1 + 571 562 563 1 + 572 562 564 1 + 573 562 570 1 + 574 564 565 1 + 575 564 572 1 + 576 566 567 1 + 577 568 574 1 + 578 569 578 1 + 579 570 571 1 + 580 572 573 1 + 581 574 575 1 + 582 574 576 1 + 583 574 577 1 + 584 578 579 1 + 585 578 580 1 + 586 578 581 1 + 587 581 582 1 + 588 583 584 2 + 589 583 585 1 + 590 585 586 1 + 591 586 587 1 + 592 586 588 1 + 593 586 589 1 + 594 589 590 1 + 595 589 591 1 + 596 589 599 1 + 597 591 592 1 + 598 591 593 1 + 599 591 594 1 + 600 594 595 1 + 601 595 596 1 + 602 595 597 1 + 603 595 598 1 + 604 596 602 1 + 605 599 600 1 + 606 600 601 2 + 607 602 603 1 + 608 602 604 1 + 609 602 612 1 + 610 604 605 1 + 611 604 606 1 + 612 604 614 1 + 613 606 607 1 + 614 606 608 1 + 615 606 616 1 + 616 608 609 1 + 617 608 610 1 + 618 608 617 1 + 619 610 611 1 + 620 610 612 1 + 621 610 618 1 + 622 612 613 1 + 623 612 619 1 + 624 614 615 1 + 625 616 621 1 + 626 617 629 1 + 627 618 625 1 + 628 619 620 1 + 629 621 622 1 + 630 621 623 1 + 631 621 624 1 + 632 622 630 1 + 633 625 626 1 + 634 625 627 1 + 635 625 628 1 + 636 631 632 2 + 637 631 633 1 + 638 633 634 1 + 639 634 635 1 + 640 634 636 1 + 641 634 637 1 + 642 637 638 1 + 643 637 639 1 + 644 637 647 1 + 645 639 640 1 + 646 639 641 1 + 647 639 642 1 + 648 642 643 1 + 649 643 644 1 + 650 643 645 1 + 651 643 646 1 + 652 644 650 1 + 653 647 648 1 + 654 648 649 2 + 655 650 651 1 + 656 650 652 1 + 657 650 660 1 + 658 652 653 1 + 659 652 654 1 + 660 652 662 1 + 661 654 655 1 + 662 654 656 1 + 663 654 664 1 + 664 656 657 1 + 665 656 658 1 + 666 656 665 1 + 667 658 659 1 + 668 658 660 1 + 669 658 666 1 + 670 660 661 1 + 671 660 667 1 + 672 662 663 1 + 673 664 669 1 + 674 665 678 1 + 675 666 673 1 + 676 667 668 1 + 677 669 670 1 + 678 669 671 1 + 679 669 672 1 + 680 673 674 1 + 681 673 675 1 + 682 673 676 1 + 683 676 677 1 + 684 679 680 2 + 685 679 681 1 + 686 681 682 1 + 687 682 683 1 + 688 682 684 1 + 689 682 685 1 + 690 685 686 1 + 691 685 687 1 + 692 685 695 1 + 693 687 688 1 + 694 687 689 1 + 695 687 690 1 + 696 690 691 1 + 697 691 692 1 + 698 691 693 1 + 699 691 694 1 + 700 692 698 1 + 701 695 696 1 + 702 696 697 2 + 703 698 699 1 + 704 698 700 1 + 705 698 708 1 + 706 700 701 1 + 707 700 702 1 + 708 700 710 1 + 709 702 703 1 + 710 702 704 1 + 711 702 712 1 + 712 704 705 1 + 713 704 706 1 + 714 704 713 1 + 715 706 707 1 + 716 706 708 1 + 717 706 714 1 + 718 708 709 1 + 719 708 715 1 + 720 710 711 1 + 721 712 721 1 + 722 713 722 1 + 723 714 717 1 + 724 715 716 1 + 725 717 718 1 + 726 717 719 1 + 727 717 720 1 + 728 722 723 1 + 729 722 724 1 + 730 722 725 1 + 731 723 726 1 + 732 727 728 2 + 733 727 729 1 + 734 729 730 1 + 735 730 731 1 + 736 730 732 1 + 737 730 733 1 + 738 733 734 1 + 739 733 735 1 + 740 733 743 1 + 741 735 736 1 + 742 735 737 1 + 743 735 738 1 + 744 738 739 1 + 745 739 740 1 + 746 739 741 1 + 747 739 742 1 + 748 740 746 1 + 749 743 744 1 + 750 744 745 2 + 751 746 747 1 + 752 746 748 1 + 753 746 756 1 + 754 748 749 1 + 755 748 750 1 + 756 748 758 1 + 757 750 751 1 + 758 750 752 1 + 759 750 760 1 + 760 752 753 1 + 761 752 754 1 + 762 752 761 1 + 763 754 755 1 + 764 754 756 1 + 765 754 762 1 + 766 756 757 1 + 767 756 763 1 + 768 758 759 1 + 769 760 769 1 + 770 761 770 1 + 771 762 765 1 + 772 763 764 1 + 773 765 766 1 + 774 765 767 1 + 775 765 768 1 + 776 766 774 1 + 777 770 771 1 + 778 770 772 1 + 779 770 773 1 + 780 775 776 2 + 781 775 777 1 + 782 777 778 1 + 783 778 779 1 + 784 778 780 1 + 785 778 781 1 + 786 781 782 1 + 787 781 783 1 + 788 781 791 1 + 789 783 784 1 + 790 783 785 1 + 791 783 786 1 + 792 786 787 1 + 793 787 788 1 + 794 787 789 1 + 795 787 790 1 + 796 788 794 1 + 797 791 792 1 + 798 792 793 2 + 799 794 795 1 + 800 794 796 1 + 801 794 804 1 + 802 796 797 1 + 803 796 798 1 + 804 796 806 1 + 805 798 799 1 + 806 798 800 1 + 807 798 808 1 + 808 800 801 1 + 809 800 802 1 + 810 800 809 1 + 811 802 803 1 + 812 802 804 1 + 813 802 810 1 + 814 804 805 1 + 815 804 811 1 + 816 806 807 1 + 817 808 813 1 + 818 809 817 1 + 819 810 821 1 + 820 811 812 1 + 821 813 814 1 + 822 813 815 1 + 823 813 816 1 + 824 817 818 1 + 825 817 819 1 + 826 817 820 1 + 827 821 822 1 + 828 821 823 1 + 829 821 824 1 + 830 825 826 1 + 831 825 827 1 + 832 827 828 1 + 833 828 829 1 + 834 828 830 1 + 835 828 831 1 + 836 831 832 1 + 837 831 833 1 + 838 831 841 1 + 839 833 834 1 + 840 833 835 1 + 841 833 836 1 + 842 836 837 1 + 843 837 838 1 + 844 837 839 1 + 845 837 840 1 + 846 838 844 1 + 847 841 842 1 + 848 842 843 1 + 849 844 845 1 + 850 844 846 1 + 851 844 854 1 + 852 846 847 1 + 853 846 848 1 + 854 846 856 1 + 855 848 849 1 + 856 848 850 1 + 857 848 858 1 + 858 850 851 1 + 859 850 852 1 + 860 850 859 1 + 861 852 853 1 + 862 852 854 1 + 863 852 860 1 + 864 854 855 1 + 865 854 861 1 + 866 856 857 1 + 867 858 863 1 + 868 859 867 1 + 869 860 871 1 + 870 861 862 1 + 871 863 864 1 + 872 863 865 1 + 873 863 866 1 + 874 865 875 1 + 875 867 868 1 + 876 867 869 1 + 877 867 870 1 + 878 869 876 1 + 879 871 872 1 + 880 871 873 1 + 881 871 874 1 + 882 877 878 2 + 883 877 879 1 + 884 879 880 1 + 885 880 881 1 + 886 880 882 1 + 887 880 883 1 + 888 883 884 1 + 889 883 885 1 + 890 883 893 1 + 891 885 886 1 + 892 885 887 1 + 893 885 888 1 + 894 888 889 1 + 895 889 890 1 + 896 889 891 1 + 897 889 892 1 + 898 890 896 1 + 899 893 894 1 + 900 894 895 2 + 901 896 897 1 + 902 896 898 1 + 903 896 906 1 + 904 898 899 1 + 905 898 900 1 + 906 898 908 1 + 907 900 901 1 + 908 900 902 1 + 909 900 910 1 + 910 902 903 1 + 911 902 904 1 + 912 902 911 1 + 913 904 905 1 + 914 904 906 1 + 915 904 912 1 + 916 906 907 1 + 917 906 913 1 + 918 908 909 1 + 919 910 915 1 + 920 911 919 1 + 921 912 923 1 + 922 913 914 1 + 923 915 916 1 + 924 915 917 1 + 925 915 918 1 + 926 917 927 1 + 927 919 920 1 + 928 919 921 1 + 929 919 922 1 + 930 923 924 1 + 931 923 925 1 + 932 923 926 1 + 933 926 928 1 + 934 929 930 2 + 935 929 931 1 + 936 931 932 1 + 937 932 933 1 + 938 932 934 1 + 939 932 935 1 + 940 935 936 1 + 941 935 937 1 + 942 935 945 1 + 943 937 938 1 + 944 937 939 1 + 945 937 940 1 + 946 940 941 1 + 947 941 942 1 + 948 941 943 1 + 949 941 944 1 + 950 942 948 1 + 951 945 946 1 + 952 946 947 2 + 953 948 949 1 + 954 948 950 1 + 955 948 958 1 + 956 950 951 1 + 957 950 952 1 + 958 950 960 1 + 959 952 953 1 + 960 952 954 1 + 961 952 962 1 + 962 954 955 1 + 963 954 956 1 + 964 954 963 1 + 965 956 957 1 + 966 956 958 1 + 967 956 964 1 + 968 958 959 1 + 969 958 965 1 + 970 960 961 1 + 971 962 967 1 + 972 963 971 1 + 973 964 975 1 + 974 965 966 1 + 975 967 968 1 + 976 967 969 1 + 977 967 970 1 + 978 971 972 1 + 979 971 973 1 + 980 971 974 1 + 981 972 980 1 + 982 975 976 1 + 983 975 977 1 + 984 975 978 1 + 985 978 979 1 + 986 981 982 2 + 987 981 983 1 + 988 983 984 1 + 989 984 985 1 + 990 984 986 1 + 991 984 987 1 + 992 987 988 1 + 993 987 989 1 + 994 987 997 1 + 995 989 990 1 + 996 989 991 1 + 997 989 992 1 + 998 992 993 1 + 999 993 994 1 + 1000 993 995 1 + 1001 993 996 1 + 1002 994 1000 1 + 1003 997 998 1 + 1004 998 999 2 + 1005 1000 1001 1 + 1006 1000 1002 1 + 1007 1000 1010 1 + 1008 1002 1003 1 + 1009 1002 1004 1 + 1010 1002 1012 1 + 1011 1004 1005 1 + 1012 1004 1006 1 + 1013 1004 1014 1 + 1014 1006 1007 1 + 1015 1006 1008 1 + 1016 1006 1015 1 + 1017 1008 1009 1 + 1018 1008 1010 1 + 1019 1008 1016 1 + 1020 1010 1011 1 + 1021 1010 1017 1 + 1022 1012 1013 1 + 1023 1014 1019 1 + 1024 1015 1023 1 + 1025 1016 1027 1 + 1026 1017 1018 1 + 1027 1019 1020 1 + 1028 1019 1021 1 + 1029 1019 1022 1 + 1030 1021 1031 1 + 1031 1023 1024 1 + 1032 1023 1025 1 + 1033 1023 1026 1 + 1034 1027 1028 1 + 1035 1027 1029 1 + 1036 1027 1030 1 + 1037 1032 1033 2 + 1038 1032 1034 1 + 1039 1034 1035 1 + 1040 1035 1036 1 + 1041 1035 1037 1 + 1042 1035 1038 1 + 1043 1038 1039 1 + 1044 1038 1040 1 + 1045 1038 1048 1 + 1046 1040 1041 1 + 1047 1040 1042 1 + 1048 1040 1043 1 + 1049 1043 1044 1 + 1050 1044 1045 1 + 1051 1044 1046 1 + 1052 1044 1047 1 + 1053 1045 1051 1 + 1054 1048 1049 1 + 1055 1049 1050 2 + 1056 1051 1052 1 + 1057 1051 1053 1 + 1058 1051 1061 1 + 1059 1053 1054 1 + 1060 1053 1055 1 + 1061 1053 1063 1 + 1062 1055 1056 1 + 1063 1055 1057 1 + 1064 1055 1065 1 + 1065 1057 1058 1 + 1066 1057 1059 1 + 1067 1057 1066 1 + 1068 1059 1060 1 + 1069 1059 1061 1 + 1070 1059 1067 1 + 1071 1061 1062 1 + 1072 1061 1068 1 + 1073 1063 1064 1 + 1074 1065 1070 1 + 1075 1066 1074 1 + 1076 1067 1078 1 + 1077 1068 1069 1 + 1078 1070 1071 1 + 1079 1070 1072 1 + 1080 1070 1073 1 + 1081 1074 1075 1 + 1082 1074 1076 1 + 1083 1074 1077 1 + 1084 1076 1082 1 + 1085 1078 1079 1 + 1086 1078 1080 1 + 1087 1078 1081 1 + 1088 1083 1084 2 + 1089 1083 1085 1 + 1090 1085 1086 1 + 1091 1086 1087 1 + 1092 1086 1088 1 + 1093 1086 1089 1 + 1094 1089 1090 1 + 1095 1089 1091 1 + 1096 1089 1099 1 + 1097 1091 1092 1 + 1098 1091 1093 1 + 1099 1091 1094 1 + 1100 1094 1095 1 + 1101 1095 1096 1 + 1102 1095 1097 1 + 1103 1095 1098 1 + 1104 1096 1102 1 + 1105 1099 1100 1 + 1106 1100 1101 2 + 1107 1102 1103 1 + 1108 1102 1104 1 + 1109 1102 1112 1 + 1110 1104 1105 1 + 1111 1104 1106 1 + 1112 1104 1114 1 + 1113 1106 1107 1 + 1114 1106 1108 1 + 1115 1106 1116 1 + 1116 1108 1109 1 + 1117 1108 1110 1 + 1118 1108 1117 1 + 1119 1110 1111 1 + 1120 1110 1112 1 + 1121 1110 1118 1 + 1122 1112 1113 1 + 1123 1112 1119 1 + 1124 1114 1115 1 + 1125 1116 1121 1 + 1126 1117 1125 1 + 1127 1118 1129 1 + 1128 1119 1120 1 + 1129 1121 1122 1 + 1130 1121 1123 1 + 1131 1121 1124 1 + 1132 1125 1126 1 + 1133 1125 1127 1 + 1134 1125 1128 1 + 1135 1129 1130 1 + 1136 1129 1131 1 + 1137 1129 1132 1 + 1138 1132 1133 1 + 1139 1134 1135 2 + 1140 1134 1136 1 + 1141 1136 1137 1 + 1142 1137 1138 1 + 1143 1137 1139 1 + 1144 1137 1140 1 + 1145 1140 1141 1 + 1146 1140 1142 1 + 1147 1140 1150 1 + 1148 1142 1143 1 + 1149 1142 1144 1 + 1150 1142 1145 1 + 1151 1145 1146 1 + 1152 1146 1147 1 + 1153 1146 1148 1 + 1154 1146 1149 1 + 1155 1147 1153 1 + 1156 1150 1151 1 + 1157 1151 1152 2 + 1158 1153 1154 1 + 1159 1153 1155 1 + 1160 1153 1163 1 + 1161 1155 1156 1 + 1162 1155 1157 1 + 1163 1155 1165 1 + 1164 1157 1158 1 + 1165 1157 1159 1 + 1166 1157 1167 1 + 1167 1159 1160 1 + 1168 1159 1161 1 + 1169 1159 1168 1 + 1170 1161 1162 1 + 1171 1161 1163 1 + 1172 1161 1169 1 + 1173 1163 1164 1 + 1174 1163 1170 1 + 1175 1165 1166 1 + 1176 1167 1172 1 + 1177 1168 1176 1 + 1178 1169 1180 1 + 1179 1170 1171 1 + 1180 1172 1173 1 + 1181 1172 1174 1 + 1182 1172 1175 1 + 1183 1173 1185 1 + 1184 1176 1177 1 + 1185 1176 1178 1 + 1186 1176 1179 1 + 1187 1178 1184 1 + 1188 1180 1181 1 + 1189 1180 1182 1 + 1190 1180 1183 1 + 1191 1183 1186 1 + 1192 1187 1188 2 + 1193 1187 1189 1 + 1194 1189 1190 1 + 1195 1190 1191 1 + 1196 1190 1192 1 + 1197 1190 1193 1 + 1198 1193 1194 1 + 1199 1193 1195 1 + 1200 1193 1222 1 + 1201 1195 1196 1 + 1202 1195 1197 1 + 1203 1195 1198 1 + 1204 1198 1199 1 + 1205 1199 1200 1 + 1206 1199 1220 1 + 1207 1199 1221 1 + 1208 1200 1201 1 + 1209 1201 1202 1 + 1210 1201 1203 1 + 1211 1201 1204 1 + 1212 1204 1205 1 + 1213 1204 1206 1 + 1214 1204 1207 1 + 1215 1207 1208 1 + 1216 1207 1212 1 + 1217 1207 1216 1 + 1218 1208 1209 1 + 1219 1208 1210 1 + 1220 1208 1211 1 + 1221 1212 1213 1 + 1222 1212 1214 1 + 1223 1212 1215 1 + 1224 1216 1217 1 + 1225 1216 1218 1 + 1226 1216 1219 1 + 1227 1222 1223 1 + 1228 1224 1225 1 + 1229 1224 1260 1 + 1230 1225 1226 1 + 1231 1225 1227 1 + 1232 1225 1228 1 + 1233 1228 1229 1 + 1234 1228 1230 1 + 1235 1228 1257 1 + 1236 1230 1231 1 + 1237 1230 1232 1 + 1238 1230 1233 1 + 1239 1233 1234 1 + 1240 1234 1235 1 + 1241 1234 1255 1 + 1242 1234 1256 1 + 1243 1235 1236 1 + 1244 1236 1237 1 + 1245 1236 1238 1 + 1246 1236 1239 1 + 1247 1239 1240 1 + 1248 1239 1241 1 + 1249 1239 1242 1 + 1250 1242 1243 1 + 1251 1242 1247 1 + 1252 1242 1251 1 + 1253 1243 1244 1 + 1254 1243 1245 1 + 1255 1243 1246 1 + 1256 1247 1248 1 + 1257 1247 1249 1 + 1258 1247 1250 1 + 1259 1251 1252 1 + 1260 1251 1253 1 + 1261 1251 1254 1 + 1262 1257 1258 1 + 1263 1258 1259 2 + 1264 1261 1262 2 + 1265 1261 1263 1 + 1266 1263 1264 1 + 1267 1264 1265 1 + 1268 1264 1266 1 + 1269 1264 1267 1 + 1270 1267 1268 1 + 1271 1267 1269 1 + 1272 1267 1287 1 + 1273 1269 1270 1 + 1274 1269 1271 1 + 1275 1269 1272 1 + 1276 1272 1273 1 + 1277 1273 1274 1 + 1278 1273 1285 1 + 1279 1273 1286 1 + 1280 1274 1275 1 + 1281 1275 1276 1 + 1282 1275 1277 1 + 1283 1275 1278 1 + 1284 1278 1279 1 + 1285 1278 1280 1 + 1286 1278 1281 1 + 1287 1281 1282 1 + 1288 1281 1283 1 + 1289 1281 1284 1 + 1290 1287 1288 1 + 1291 1289 1290 1 + 1292 1289 1316 1 + 1293 1290 1291 1 + 1294 1290 1292 1 + 1295 1290 1293 1 + 1296 1293 1294 1 + 1297 1293 1295 1 + 1298 1293 1313 1 + 1299 1295 1296 1 + 1300 1295 1297 1 + 1301 1295 1298 1 + 1302 1298 1299 1 + 1303 1299 1300 1 + 1304 1299 1311 1 + 1305 1299 1312 1 + 1306 1300 1301 1 + 1307 1301 1302 1 + 1308 1301 1303 1 + 1309 1301 1304 1 + 1310 1304 1305 1 + 1311 1304 1306 1 + 1312 1304 1307 1 + 1313 1307 1308 1 + 1314 1307 1309 1 + 1315 1307 1310 1 + 1316 1313 1314 1 + 1317 1314 1315 2 + 1318 1317 1318 2 + 1319 1317 1319 1 + 1320 1319 1320 1 + 1321 1320 1321 1 + 1322 1320 1322 1 + 1323 1320 1323 1 + 1324 1323 1324 1 + 1325 1323 1325 1 + 1326 1323 1342 1 + 1327 1325 1326 1 + 1328 1325 1327 1 + 1329 1325 1328 1 + 1330 1328 1329 1 + 1331 1329 1330 1 + 1332 1329 1340 1 + 1333 1329 1341 1 + 1334 1330 1331 1 + 1335 1331 1332 1 + 1336 1331 1333 1 + 1337 1331 1334 1 + 1338 1334 1335 1 + 1339 1334 1336 1 + 1340 1334 1337 1 + 1341 1336 1345 1 + 1342 1337 1338 1 + 1343 1337 1339 1 + 1344 1337 1343 1 + 1345 1342 1344 1 + 1346 1343 1346 1 + 1347 1347 1348 1 + 1348 1347 1376 1 + 1349 1348 1349 1 + 1350 1348 1350 1 + 1351 1348 1351 1 + 1352 1351 1352 1 + 1353 1351 1353 1 + 1354 1351 1371 1 + 1355 1353 1354 1 + 1356 1353 1355 1 + 1357 1353 1356 1 + 1358 1356 1357 1 + 1359 1357 1358 1 + 1360 1357 1369 1 + 1361 1357 1370 1 + 1362 1358 1359 1 + 1363 1359 1360 1 + 1364 1359 1361 1 + 1365 1359 1362 1 + 1366 1362 1363 1 + 1367 1362 1364 1 + 1368 1362 1366 1 + 1369 1364 1365 1 + 1370 1366 1367 1 + 1371 1366 1368 1 + 1372 1366 1374 1 + 1373 1371 1372 1 + 1374 1372 1373 2 + 1375 1374 1375 1 + 1376 1377 1378 2 + 1377 1377 1379 1 + 1378 1379 1380 1 + 1379 1380 1381 1 + 1380 1380 1382 1 + 1381 1380 1383 1 + 1382 1383 1384 1 + 1383 1383 1385 1 + 1384 1383 1393 1 + 1385 1385 1386 1 + 1386 1385 1387 1 + 1387 1385 1388 1 + 1388 1388 1389 1 + 1389 1389 1390 1 + 1390 1389 1391 1 + 1391 1389 1392 1 + 1392 1390 1396 1 + 1393 1393 1394 1 + 1394 1394 1395 2 + 1395 1396 1397 1 + 1396 1396 1398 1 + 1397 1396 1406 1 + 1398 1398 1399 1 + 1399 1398 1400 1 + 1400 1398 1408 1 + 1401 1400 1401 1 + 1402 1400 1402 1 + 1403 1400 1410 1 + 1404 1402 1403 1 + 1405 1402 1404 1 + 1406 1402 1411 1 + 1407 1404 1405 1 + 1408 1404 1406 1 + 1409 1404 1413 1 + 1410 1406 1407 1 + 1411 1406 1415 1 + 1412 1408 1409 1 + 1413 1410 1417 1 + 1414 1411 1412 1 + 1415 1413 1414 1 + 1416 1415 1416 1 + 1417 1417 1418 1 + 1418 1417 1419 1 + 1419 1417 1420 1 + 1420 1418 1421 1 + 1421 1422 1423 2 + 1422 1422 1424 1 + 1423 1424 1425 1 + 1424 1425 1426 1 + 1425 1425 1427 1 + 1426 1425 1428 1 + 1427 1428 1429 1 + 1428 1428 1430 1 + 1429 1428 1438 1 + 1430 1430 1431 1 + 1431 1430 1432 1 + 1432 1430 1433 1 + 1433 1433 1434 1 + 1434 1434 1435 1 + 1435 1434 1436 1 + 1436 1434 1437 1 + 1437 1435 1441 1 + 1438 1438 1439 1 + 1439 1439 1440 2 + 1440 1441 1442 1 + 1441 1441 1443 1 + 1442 1441 1451 1 + 1443 1443 1444 1 + 1444 1443 1445 1 + 1445 1443 1453 1 + 1446 1445 1446 1 + 1447 1445 1447 1 + 1448 1445 1455 1 + 1449 1447 1448 1 + 1450 1447 1449 1 + 1451 1447 1457 1 + 1452 1449 1450 1 + 1453 1449 1451 1 + 1454 1449 1458 1 + 1455 1451 1452 1 + 1456 1451 1460 1 + 1457 1453 1454 1 + 1458 1455 1456 1 + 1459 1457 1462 1 + 1460 1458 1459 1 + 1461 1460 1461 1 + 1462 1462 1463 1 + 1463 1462 1464 1 + 1464 1462 1465 1 + 1465 1464 1466 1 + 1466 1467 1468 2 + 1467 1467 1469 1 + 1468 1469 1470 1 + 1469 1470 1471 1 + 1470 1470 1472 1 + 1471 1470 1473 1 + 1472 1473 1474 1 + 1473 1473 1475 1 + 1474 1473 1483 1 + 1475 1475 1476 1 + 1476 1475 1477 1 + 1477 1475 1478 1 + 1478 1478 1479 1 + 1479 1479 1480 1 + 1480 1479 1481 1 + 1481 1479 1482 1 + 1482 1480 1486 1 + 1483 1483 1484 1 + 1484 1484 1485 2 + 1485 1486 1487 1 + 1486 1486 1488 1 + 1487 1486 1496 1 + 1488 1488 1489 1 + 1489 1488 1490 1 + 1490 1488 1498 1 + 1491 1490 1491 1 + 1492 1490 1492 1 + 1493 1490 1500 1 + 1494 1492 1493 1 + 1495 1492 1494 1 + 1496 1492 1502 1 + 1497 1494 1495 1 + 1498 1494 1496 1 + 1499 1494 1504 1 + 1500 1496 1497 1 + 1501 1496 1505 1 + 1502 1498 1499 1 + 1503 1500 1501 1 + 1504 1502 1503 1 + 1505 1504 1507 1 + 1506 1505 1506 1 + 1507 1507 1508 1 + 1508 1507 1509 1 + 1509 1507 1510 1 + 1510 1508 1511 1 + 1511 1512 1513 2 + 1512 1512 1514 1 + 1513 1514 1515 1 + 1514 1515 1516 1 + 1515 1515 1517 1 + 1516 1515 1518 1 + 1517 1518 1519 1 + 1518 1518 1520 1 + 1519 1518 1528 1 + 1520 1520 1521 1 + 1521 1520 1522 1 + 1522 1520 1523 1 + 1523 1523 1524 1 + 1524 1524 1525 1 + 1525 1524 1526 1 + 1526 1524 1527 1 + 1527 1525 1531 1 + 1528 1528 1529 1 + 1529 1529 1530 2 + 1530 1531 1532 1 + 1531 1531 1533 1 + 1532 1531 1541 1 + 1533 1533 1534 1 + 1534 1533 1535 1 + 1535 1533 1543 1 + 1536 1535 1536 1 + 1537 1535 1537 1 + 1538 1535 1545 1 + 1539 1537 1538 1 + 1540 1537 1539 1 + 1541 1537 1547 1 + 1542 1539 1540 1 + 1543 1539 1541 1 + 1544 1539 1549 1 + 1545 1541 1542 1 + 1546 1541 1551 1 + 1547 1543 1544 1 + 1548 1545 1546 1 + 1549 1547 1548 1 + 1550 1549 1550 1 + 1551 1551 1552 1 + 1552 1553 1554 2 + 1553 1553 1555 1 + 1554 1555 1556 1 + 1555 1556 1557 1 + 1556 1556 1558 1 + 1557 1556 1559 1 + 1558 1559 1560 1 + 1559 1559 1561 1 + 1560 1559 1569 1 + 1561 1561 1562 1 + 1562 1561 1563 1 + 1563 1561 1564 1 + 1564 1564 1565 1 + 1565 1565 1566 1 + 1566 1565 1567 1 + 1567 1565 1568 1 + 1568 1566 1572 1 + 1569 1569 1570 1 + 1570 1570 1571 2 + 1571 1572 1573 1 + 1572 1572 1574 1 + 1573 1572 1582 1 + 1574 1574 1575 1 + 1575 1574 1576 1 + 1576 1574 1584 1 + 1577 1576 1577 1 + 1578 1576 1578 1 + 1579 1576 1586 1 + 1580 1578 1579 1 + 1581 1578 1580 1 + 1582 1578 1587 1 + 1583 1580 1581 1 + 1584 1580 1582 1 + 1585 1580 1589 1 + 1586 1582 1583 1 + 1587 1582 1591 1 + 1588 1584 1585 1 + 1589 1586 1593 1 + 1590 1587 1588 1 + 1591 1589 1590 1 + 1592 1591 1592 1 + 1593 1593 1594 1 + 1594 1593 1595 1 + 1595 1593 1596 1 + 1596 1597 1598 2 + 1597 1597 1599 1 + 1598 1599 1600 1 + 1599 1600 1601 1 + 1600 1600 1602 1 + 1601 1600 1603 1 + 1602 1603 1604 1 + 1603 1603 1605 1 + 1604 1603 1613 1 + 1605 1605 1606 1 + 1606 1605 1607 1 + 1607 1605 1608 1 + 1608 1608 1609 1 + 1609 1609 1610 1 + 1610 1609 1611 1 + 1611 1609 1612 1 + 1612 1610 1616 1 + 1613 1613 1614 1 + 1614 1614 1615 2 + 1615 1616 1617 1 + 1616 1616 1618 1 + 1617 1616 1626 1 + 1618 1618 1619 1 + 1619 1618 1620 1 + 1620 1618 1628 1 + 1621 1620 1621 1 + 1622 1620 1622 1 + 1623 1620 1630 1 + 1624 1622 1623 1 + 1625 1622 1624 1 + 1626 1622 1632 1 + 1627 1624 1625 1 + 1628 1624 1626 1 + 1629 1624 1633 1 + 1630 1626 1627 1 + 1631 1626 1635 1 + 1632 1628 1629 1 + 1633 1630 1631 1 + 1634 1632 1637 1 + 1635 1633 1634 1 + 1636 1635 1636 1 + 1637 1637 1638 1 + 1638 1637 1639 1 + 1639 1637 1640 1 + 1640 1641 1642 2 + 1641 1641 1643 1 + 1642 1643 1644 1 + 1643 1644 1645 1 + 1644 1644 1646 1 + 1645 1644 1647 1 + 1646 1647 1648 1 + 1647 1647 1649 1 + 1648 1647 1657 1 + 1649 1649 1650 1 + 1650 1649 1651 1 + 1651 1649 1652 1 + 1652 1652 1653 1 + 1653 1653 1654 1 + 1654 1653 1655 1 + 1655 1653 1656 1 + 1656 1654 1660 1 + 1657 1657 1658 1 + 1658 1658 1659 2 + 1659 1660 1661 1 + 1660 1660 1662 1 + 1661 1660 1670 1 + 1662 1662 1663 1 + 1663 1662 1664 1 + 1664 1662 1672 1 + 1665 1664 1665 1 + 1666 1664 1666 1 + 1667 1664 1674 1 + 1668 1666 1667 1 + 1669 1666 1668 1 + 1670 1666 1676 1 + 1671 1668 1669 1 + 1672 1668 1670 1 + 1673 1668 1678 1 + 1674 1670 1671 1 + 1675 1670 1679 1 + 1676 1672 1673 1 + 1677 1674 1675 1 + 1678 1676 1677 1 + 1679 1678 1681 1 + 1680 1679 1680 1 + 1681 1681 1682 1 + 1682 1681 1683 1 + 1683 1681 1684 1 + 1684 1685 1686 1 + 1685 1685 1687 1 + 1686 1685 1688 1 + 1687 1685 1706 1 + 1688 1688 1689 1 + 1689 1688 1690 1 + 1690 1688 1691 1 + 1691 1691 1692 1 + 1692 1691 1693 1 + 1693 1691 1755 1 + 1694 1693 1694 1 + 1695 1693 1695 1 + 1696 1693 1696 1 + 1697 1696 1697 2 + 1698 1696 1706 1 + 1699 1697 1698 1 + 1700 1697 1699 1 + 1701 1699 1700 1 + 1702 1699 1701 1 + 1703 1699 1702 1 + 1704 1702 1703 1 + 1705 1702 1704 1 + 1706 1702 1714 1 + 1707 1704 1705 1 + 1708 1704 1706 1 + 1709 1704 1707 1 + 1710 1706 1728 1 + 1711 1707 1708 1 + 1712 1707 1709 1 + 1713 1707 1710 1 + 1714 1710 1711 1 + 1715 1710 1712 1 + 1716 1710 1713 1 + 1717 1713 1714 1 + 1718 1713 1722 1 + 1719 1713 1724 1 + 1720 1714 1715 1 + 1721 1714 1716 1 + 1722 1716 1717 1 + 1723 1716 1718 1 + 1724 1716 1719 1 + 1725 1719 1720 1 + 1726 1719 1721 1 + 1727 1719 1722 1 + 1728 1722 1723 1 + 1729 1722 1732 1 + 1730 1724 1725 1 + 1731 1724 1726 1 + 1732 1724 1727 1 + 1733 1728 1729 1 + 1734 1728 1730 1 + 1735 1728 1731 1 + 1736 1732 1733 1 + 1737 1732 1734 1 + 1738 1732 1738 1 + 1739 1734 1735 1 + 1740 1734 1736 1 + 1741 1734 1737 1 + 1742 1738 1739 1 + 1743 1738 1740 1 + 1744 1738 1741 1 + 1745 1741 1742 1 + 1746 1741 1743 1 + 1747 1741 1744 1 + 1748 1744 1745 1 + 1749 1744 1757 1 + 1750 1744 1758 1 + 1751 1745 1746 1 + 1752 1745 1747 1 + 1753 1745 1751 1 + 1754 1747 1748 1 + 1755 1747 1749 1 + 1756 1747 1750 1 + 1757 1751 1752 1 + 1758 1751 1753 1 + 1759 1751 1754 1 + 1760 1755 1756 1 + 1761 1757 1759 1 + 1762 1757 1760 1 + 1763 1757 1761 1 + 1764 1759 1762 1 + 1765 1759 1763 1 + 1766 1759 1764 1 + 1767 1765 1766 1 + 1768 1765 1767 1 + 1769 1765 1768 1 + 1770 1765 1786 1 + 1771 1768 1769 1 + 1772 1768 1770 1 + 1773 1768 1771 1 + 1774 1771 1772 1 + 1775 1771 1773 1 + 1776 1771 1831 1 + 1777 1773 1774 1 + 1778 1773 1775 1 + 1779 1773 1776 1 + 1780 1776 1777 2 + 1781 1776 1786 1 + 1782 1777 1778 1 + 1783 1777 1779 1 + 1784 1779 1780 1 + 1785 1779 1781 1 + 1786 1779 1782 1 + 1787 1782 1783 1 + 1788 1782 1784 1 + 1789 1782 1794 1 + 1790 1784 1785 1 + 1791 1784 1786 1 + 1792 1784 1787 1 + 1793 1786 1808 1 + 1794 1787 1788 1 + 1795 1787 1789 1 + 1796 1787 1790 1 + 1797 1790 1791 1 + 1798 1790 1792 1 + 1799 1790 1793 1 + 1800 1793 1794 1 + 1801 1793 1802 1 + 1802 1793 1804 1 + 1803 1794 1795 1 + 1804 1794 1796 1 + 1805 1796 1797 1 + 1806 1796 1798 1 + 1807 1796 1799 1 + 1808 1799 1800 1 + 1809 1799 1801 1 + 1810 1799 1802 1 + 1811 1802 1803 1 + 1812 1802 1812 1 + 1813 1804 1805 1 + 1814 1804 1806 1 + 1815 1804 1807 1 + 1816 1808 1809 1 + 1817 1808 1810 1 + 1818 1808 1811 1 + 1819 1812 1813 1 + 1820 1812 1814 1 + 1821 1812 1818 1 + 1822 1814 1815 1 + 1823 1814 1816 1 + 1824 1814 1817 1 + 1825 1818 1819 2 + 1826 1818 1841 1 + 1827 1819 1820 1 + 1828 1819 1842 1 + 1829 1820 1821 1 + 1830 1820 1833 1 + 1831 1820 1834 1 + 1832 1821 1822 1 + 1833 1821 1823 1 + 1834 1821 1827 1 + 1835 1823 1824 1 + 1836 1823 1825 1 + 1837 1823 1826 1 + 1838 1827 1828 1 + 1839 1827 1829 1 + 1840 1827 1830 1 + 1841 1831 1832 1 + 1842 1833 1835 1 + 1843 1833 1836 1 + 1844 1833 1837 1 + 1845 1835 1838 1 + 1846 1835 1839 1 + 1847 1835 1840 1 +@SUBSTRUCTURE + 1 2-A 1 **** 0 **** **** + 2 2-B 48 **** 0 **** **** + 3 2-C 95 **** 0 **** **** + 4 CAM 142 **** 0 **** **** + 5 CLI 219 **** 0 **** **** + 6 ERG 267 **** 0 **** **** + 7 H2A 340 **** 0 **** **** + 8 H2B 389 **** 0 **** **** + 9 H2C 438 **** 0 **** **** + 10 P2A 487 **** 0 **** **** + 11 P2B 535 **** 0 **** **** + 12 P2C 583 **** 0 **** **** + 13 P2D 631 **** 0 **** **** + 14 P2E 679 **** 0 **** **** + 15 P2F 727 **** 0 **** **** + 16 P3- 775 **** 0 **** **** + 17 P3A 825 **** 0 **** **** + 18 P3B 877 **** 0 **** **** + 19 P3C 929 **** 0 **** **** + 20 P3D 981 **** 0 **** **** + 21 P3E 1032 **** 0 **** **** + 22 P3F 1083 **** 0 **** **** + 23 P3H 1134 **** 0 **** **** + 24 PC1 1187 **** 0 **** **** + 25 PC2 1224 **** 0 **** **** + 26 PE1 1261 **** 0 **** **** + 27 PE2 1289 **** 0 **** **** + 28 PG1 1317 **** 0 **** **** + 29 PG2 1347 **** 0 **** **** + 30 PH3 1377 **** 0 **** **** + 31 PH4 1422 **** 0 **** **** + 32 PH5 1467 **** 0 **** **** + 33 PI 1512 **** 0 **** **** + 34 PI3 1553 **** 0 **** **** + 35 PI4 1597 **** 0 **** **** + 36 PI5 1641 **** 0 **** **** + 37 SIT 1685 **** 0 **** **** + 38 STI 1765 **** 0 **** **** diff --git a/src/Xponge/forcefield/amber/lipid_ext_manifest.json b/src/Xponge/forcefield/amber/lipid_ext_manifest.json new file mode 100644 index 0000000..a12c42f --- /dev/null +++ b/src/Xponge/forcefield/amber/lipid_ext_manifest.json @@ -0,0 +1,1988 @@ +{ + "format_version": 2, + "source": "lipid_ext.lib", + "source_sha256": "9c42d98a7eaa77edc2650958e8272ce9339d43502899cb8df4cffba914ceed59", + "source_license": "Apache-2.0", + "template_count": 38, + "templates": [ + { + "template": "2-A", + "source_unit_name": "2-A", + "atom_count": 47, + "bond_count": 47, + "total_charge": -5.000001, + "expected_integer_charge": -5, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "2-B", + "source_unit_name": "2-B", + "atom_count": 47, + "bond_count": 47, + "total_charge": -5.000001, + "expected_integer_charge": -5, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "2-C", + "source_unit_name": "2-C", + "atom_count": 47, + "bond_count": 47, + "total_charge": -5.000001, + "expected_integer_charge": -5, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "CAM", + "source_unit_name": "CAM", + "atom_count": 77, + "bond_count": 80, + "total_charge": -1e-06, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": null, + "source_connect_indices": [ + 0, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "CLI", + "source_unit_name": "CL", + "atom_count": 48, + "bond_count": 47, + "total_charge": -1.999999, + "expected_integer_charge": -2, + "head_atom": "C11A", + "tail_atom": "C21A", + "source_connect_indices": [ + 1, + 25 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11A", + "head_reference_atom": "O12A", + "head_link_conditions": [ + { + "atoms": [ + "O11A", + "C11A" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12A", + "O11A", + "C11A" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21A", + "tail_reference_atom": "O22A", + "tail_link_conditions": [ + { + "atoms": [ + "O21A", + "C21A" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22A", + "O21A", + "C21A" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "ERG", + "source_unit_name": "ERG", + "atom_count": 73, + "bond_count": 76, + "total_charge": 4e-06, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": null, + "source_connect_indices": [ + 0, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "H2A", + "source_unit_name": "H2A", + "atom_count": 49, + "bond_count": 49, + "total_charge": -2.999998, + "expected_integer_charge": -3, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "H2B", + "source_unit_name": "H2B", + "atom_count": 49, + "bond_count": 49, + "total_charge": -2.999999, + "expected_integer_charge": -3, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "H2C", + "source_unit_name": "H2C", + "atom_count": 49, + "bond_count": 49, + "total_charge": -2.999999, + "expected_integer_charge": -3, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P2A", + "source_unit_name": "P2A", + "atom_count": 48, + "bond_count": 48, + "total_charge": -4.0, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P2B", + "source_unit_name": "P2B", + "atom_count": 48, + "bond_count": 48, + "total_charge": -4.0, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P2C", + "source_unit_name": "P2C", + "atom_count": 48, + "bond_count": 48, + "total_charge": -4.0, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P2D", + "source_unit_name": "P2D", + "atom_count": 48, + "bond_count": 48, + "total_charge": -4.0, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P2E", + "source_unit_name": "P2E", + "atom_count": 48, + "bond_count": 48, + "total_charge": -3.999999, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P2F", + "source_unit_name": "P2F", + "atom_count": 48, + "bond_count": 48, + "total_charge": -4.0, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3-", + "source_unit_name": "P3-", + "atom_count": 50, + "bond_count": 50, + "total_charge": -7.000001, + "expected_integer_charge": -7, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3A", + "source_unit_name": "P3A", + "atom_count": 52, + "bond_count": 52, + "total_charge": -5.000001, + "expected_integer_charge": -5, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3B", + "source_unit_name": "P3B", + "atom_count": 52, + "bond_count": 52, + "total_charge": -4.999999, + "expected_integer_charge": -5, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3C", + "source_unit_name": "P3C", + "atom_count": 52, + "bond_count": 52, + "total_charge": -5.0, + "expected_integer_charge": -5, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3D", + "source_unit_name": "P3D", + "atom_count": 51, + "bond_count": 51, + "total_charge": -6.000002, + "expected_integer_charge": -6, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3E", + "source_unit_name": "P3E", + "atom_count": 51, + "bond_count": 51, + "total_charge": -6.000001, + "expected_integer_charge": -6, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3F", + "source_unit_name": "P3F", + "atom_count": 51, + "bond_count": 51, + "total_charge": -5.999999, + "expected_integer_charge": -6, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "P3H", + "source_unit_name": "P3H", + "atom_count": 53, + "bond_count": 53, + "total_charge": -3.999999, + "expected_integer_charge": -4, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PC1", + "source_unit_name": "PC1", + "atom_count": 37, + "bond_count": 36, + "total_charge": 0.0, + "expected_integer_charge": 0, + "head_atom": "C11", + "tail_atom": null, + "source_connect_indices": [ + 1, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "PC2", + "source_unit_name": "PC2", + "atom_count": 37, + "bond_count": 36, + "total_charge": -2e-06, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": "C21", + "source_connect_indices": [ + 0, + 35 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PE1", + "source_unit_name": "PE1", + "atom_count": 28, + "bond_count": 27, + "total_charge": 3e-06, + "expected_integer_charge": 0, + "head_atom": "C11", + "tail_atom": null, + "source_connect_indices": [ + 1, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "PE2", + "source_unit_name": "PE2", + "atom_count": 28, + "bond_count": 27, + "total_charge": -1e-06, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": "C21", + "source_connect_indices": [ + 0, + 26 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PG1", + "source_unit_name": "PG1", + "atom_count": 30, + "bond_count": 29, + "total_charge": -1.000001, + "expected_integer_charge": -1, + "head_atom": "C11", + "tail_atom": null, + "source_connect_indices": [ + 1, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "PG2", + "source_unit_name": "PG2", + "atom_count": 30, + "bond_count": 29, + "total_charge": -0.999998, + "expected_integer_charge": -1, + "head_atom": null, + "tail_atom": "C21", + "source_connect_indices": [ + 0, + 26 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PH3", + "source_unit_name": "PH3", + "atom_count": 45, + "bond_count": 45, + "total_charge": -2.0, + "expected_integer_charge": -2, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PH4", + "source_unit_name": "PH4", + "atom_count": 45, + "bond_count": 45, + "total_charge": -2.0, + "expected_integer_charge": -2, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PH5", + "source_unit_name": "PH5", + "atom_count": 45, + "bond_count": 45, + "total_charge": -2.000001, + "expected_integer_charge": -2, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PI", + "source_unit_name": "PI", + "atom_count": 41, + "bond_count": 41, + "total_charge": -0.999999, + "expected_integer_charge": -1, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PI3", + "source_unit_name": "PI3", + "atom_count": 44, + "bond_count": 44, + "total_charge": -3.000001, + "expected_integer_charge": -3, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PI4", + "source_unit_name": "PI4", + "atom_count": 44, + "bond_count": 44, + "total_charge": -3.000001, + "expected_integer_charge": -3, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "PI5", + "source_unit_name": "PI5", + "atom_count": 44, + "bond_count": 44, + "total_charge": -3.0, + "expected_integer_charge": -3, + "head_atom": "C11", + "tail_atom": "C21", + "source_connect_indices": [ + 1, + 18 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": "O11", + "head_reference_atom": "O12", + "head_link_conditions": [ + { + "atoms": [ + "O11", + "C11" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O12", + "O11", + "C11" + ], + "parameter_degrees": 180.0 + } + ], + "head_rule_source": "carbonyl_head", + "tail_next_atom": "O21", + "tail_reference_atom": "O22", + "tail_link_conditions": [ + { + "atoms": [ + "O21", + "C21" + ], + "parameter_degrees": 120.0 + }, + { + "atoms": [ + "O22", + "O21", + "C21" + ], + "parameter_degrees": 180.0 + } + ], + "tail_rule_source": "carbonyl_tail" + }, + { + "template": "SIT", + "source_unit_name": "SIT", + "atom_count": 80, + "bond_count": 83, + "total_charge": 1e-06, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": null, + "source_connect_indices": [ + 0, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + }, + { + "template": "STI", + "source_unit_name": "STI", + "atom_count": 78, + "bond_count": 81, + "total_charge": 1e-06, + "expected_integer_charge": 0, + "head_atom": null, + "tail_atom": null, + "source_connect_indices": [ + 0, + 0 + ], + "source_connectivity_flags": [ + 1, + 2 + ], + "head_next_atom": null, + "head_reference_atom": null, + "head_link_conditions": [], + "head_rule_source": "none", + "tail_next_atom": null, + "tail_reference_atom": null, + "tail_link_conditions": [], + "tail_rule_source": "none" + } + ] +} diff --git a/src/Xponge/forcefield/edip/__init__.py b/src/Xponge/forcefield/edip/__init__.py new file mode 100644 index 0000000..6cbd8fc --- /dev/null +++ b/src/Xponge/forcefield/edip/__init__.py @@ -0,0 +1,6 @@ +"""Legacy Xponge.forcefield.edip shim.""" + +from XpongeCPP._compat.imports import extend_package_path, reexport_module + +reexport_module("XpongeCPP.forcefield.edip", globals(), public=["data_path"]) +extend_package_path(globals(), "XpongeCPP.forcefield.edip") diff --git a/src/Xponge/forcefield/martini/__init__.py b/src/Xponge/forcefield/martini/__init__.py new file mode 100644 index 0000000..5723b59 --- /dev/null +++ b/src/Xponge/forcefield/martini/__init__.py @@ -0,0 +1,6 @@ +"""Legacy Xponge.forcefield.martini shim.""" + +from XpongeCPP._compat.imports import extend_package_path, reexport_module + +reexport_module("XpongeCPP.forcefield.martini", globals(), public=["data_path"]) +extend_package_path(globals(), "XpongeCPP.forcefield.martini") diff --git a/src/Xponge/io_bundle/bundle_builder.py b/src/Xponge/io_bundle/bundle_builder.py new file mode 100644 index 0000000..20a3eac --- /dev/null +++ b/src/Xponge/io_bundle/bundle_builder.py @@ -0,0 +1,3 @@ +"""Legacy package-name shim for :mod:`XpongeCPP.io_bundle.bundle_builder`.""" + +from XpongeCPP.io_bundle.bundle_builder import * # noqa: F401,F403 diff --git a/src/Xponge/io_bundle/contracts.py b/src/Xponge/io_bundle/contracts.py new file mode 100644 index 0000000..58b77bf --- /dev/null +++ b/src/Xponge/io_bundle/contracts.py @@ -0,0 +1,3 @@ +"""Legacy package-name shim for :mod:`XpongeCPP.io_bundle.contracts`.""" + +from XpongeCPP.io_bundle.contracts import * # noqa: F401,F403 diff --git a/src/Xponge/qm/__init__.py b/src/Xponge/qm/__init__.py new file mode 100644 index 0000000..bc13aa5 --- /dev/null +++ b/src/Xponge/qm/__init__.py @@ -0,0 +1,7 @@ +"""Legacy Xponge.qm namespace backed by XpongeCPP.""" + +from XpongeCPP._compat.imports import extend_package_path + +extend_package_path(globals(), "XpongeCPP.qm") + +from XpongeCPP.qm import * # noqa: F401,F403 diff --git a/src/XpongeCPP/__init__.py b/src/XpongeCPP/__init__.py index 4314583..a305a80 100644 --- a/src/XpongeCPP/__init__.py +++ b/src/XpongeCPP/__init__.py @@ -1,5 +1,6 @@ """Python compatibility layer for the XpongeCPP C++ core.""" +import os import numpy as np from ._core import ( @@ -28,7 +29,7 @@ load_gromacs_topology_file, load_molpsf, load_opls_itp_file, - load_parmdat, + load_parmdat as _core_load_parmdat, load_mmcif as _core_load_mmcif, load_pdb as _core_load_pdb, load_rst7, @@ -73,6 +74,7 @@ template_atom_count, ) from .assign import AssignRule +from .capabilities import capability_manifest, capability_status, require_capability from .gromacs import GlobalSetting, GromacsTopologyIterator, load_ffitp, load_molitp from .io_compat import ( get_assignment_from_cif, @@ -92,6 +94,7 @@ ProtocolSITS, ProtocolSoftWall, ProtocolSteering, + ProtocolVirtualAtom, SpongeProtocol, save_sponge_input_bundle, ) @@ -99,6 +102,29 @@ _CoreMolecule = Molecule _CoreResidue = Residue _CoreResidueType = ResidueType + + +def _get_ignore_missing_atoms(molecule): + del molecule + return None + + +def _set_ignore_missing_atoms(molecule, enabled): + molecule.set_ignore_missing_atoms(bool(enabled)) + + +def _get_molecule_charge(molecule): + return sum(float(getattr(atom, "charge", 0.0)) for atom in molecule.atoms) + + +if not hasattr(Molecule, "ignore_missing_atoms"): + Molecule.ignore_missing_atoms = property( + _get_ignore_missing_atoms, + _set_ignore_missing_atoms, + ) +if not hasattr(Molecule, "charge"): + Molecule.charge = property(_get_molecule_charge) + from ._compat.imports import ( Generate_New_Bonded_Force_Type, Generate_New_Pairwise_Force_Type, @@ -168,7 +194,9 @@ from .legacy_types import _LegacyResidueTypeHandle from .template_ops import load_mol2 -__version__ = "0.2.0" +__version__ = "0.2.6" +__mokda_backend__ = "xpongecpp" +__implementation_version__ = __version__ pi = np.pi kb = 0.00198716 bar = 1.439506089041446e-5 @@ -188,29 +216,33 @@ def register_residue_templates_from_mol2_text(text): sync_template_module_globals() return result -def load_frcmod(filename): +def load_frcmod(filename, nbtype="RE", include_nb14=False): set_lj_combining_rule("lorentz_berthelot") register_amber_nb14_scale("X", "X", 0.5, 0.833333) - return _core_load_frcmod(filename) + from ._compat.frcmod import parse_frcmod + return parse_frcmod( + os.fspath(filename), + nbtype=nbtype, + include_nb14=include_nb14, + ) -def load_pdb(*args, **kwargs): - from .forcefield import package_data_path - set_lj_combining_rule("lorentz_berthelot") - register_amber_nb14_scale("X", "X", 0.5, 0.833333) - register_amber_parmdat_file(str(package_data_path("amber", "parm10.dat"))) - register_amber_frcmod_file(str(package_data_path("amber", "ff14SB.frcmod"))) +def load_parmdat(filename): + from ._compat.frcmod import parse_parmdat + + return parse_parmdat(os.fspath(filename)) + + +def load_pdb(*args, **kwargs): + if args and isinstance(args[0], os.PathLike): + args = (os.fspath(args[0]), *args[1:]) return _core_load_pdb(*args, **kwargs) def load_mmcif(*args, **kwargs): - from .forcefield import package_data_path - - set_lj_combining_rule("lorentz_berthelot") - register_amber_nb14_scale("X", "X", 0.5, 0.833333) - register_amber_parmdat_file(str(package_data_path("amber", "parm10.dat"))) - register_amber_frcmod_file(str(package_data_path("amber", "ff14SB.frcmod"))) + if args and isinstance(args[0], os.PathLike): + args = (os.fspath(args[0]), *args[1:]) return _core_load_mmcif(*args, **kwargs) @@ -302,6 +334,7 @@ def load_parameter_from_ffitp(filename, folder, reset=True): "ProtocolSITS", "ProtocolSoftWall", "ProtocolSteering", + "ProtocolVirtualAtom", "save_pdb", "save_gro", "save_mol2", @@ -342,6 +375,9 @@ def load_parameter_from_ffitp(filename, folder, reset=True): "merge_dual_topology", "merge_force_field", "metal_assignment", + "capability_manifest", + "capability_status", + "require_capability", "Add_Ions", "Add_Molecule", "Add_Solvent_Box", diff --git a/src/XpongeCPP/__main__.py b/src/XpongeCPP/__main__.py index 4950891..1de0671 100644 --- a/src/XpongeCPP/__main__.py +++ b/src/XpongeCPP/__main__.py @@ -8,6 +8,31 @@ from .io_bundle.cli import add_legacy_to_bundle_parser +def _add_legacy_test_parser(subparsers) -> None: + parser = subparsers.add_parser( + "test", + help="test the basic function of Xponge", + ) + parser.add_argument( + "-p", + "--purpose", + metavar="programmatic", + default="programmatic", + choices=("programmatic", "academic"), + help="select the programmatic or academic test profile", + ) + parser.add_argument( + "-v", + "--verbose", + metavar="INFO", + default="INFO", + choices=("DEBUG", "INFO", "WARNING", "ERROR"), + help="set the test output verbosity", + ) + parser.add_argument("-d", "--do", metavar="todo", default="base") + parser.add_argument("-f", "--file", metavar="file") + + def main(argv=None) -> int: parser = argparse.ArgumentParser(prog="XpongeCPP") parser.add_argument( @@ -15,8 +40,10 @@ def main(argv=None) -> int: "--version", action="version", version=__version__, + help="show the version of Xponge", ) subparsers = parser.add_subparsers(dest="command") + _add_legacy_test_parser(subparsers) add_legacy_to_bundle_parser(subparsers) args = parser.parse_args(argv) if not hasattr(args, "func"): diff --git a/src/XpongeCPP/_compat/frcmod.py b/src/XpongeCPP/_compat/frcmod.py new file mode 100644 index 0000000..c2d4aef --- /dev/null +++ b/src/XpongeCPP/_compat/frcmod.py @@ -0,0 +1,286 @@ +"""Amber frcmod text parser compatible with Xponge 1.7b8.""" + +from __future__ import annotations + +import re + + +def _nb14_row(line, atoms): + number = r"([+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[Ee][+-]?\d+)?)" + scee = re.search(r"SCEE\s*=\s*" + number, line) + scnb = re.search(r"SCNB\s*=\s*" + number, line) + if not scee and not scnb: + return "" + electrostatic = 1.0 / float(scee.group(1)) if scee else 1.0 / 1.2 + lennard_jones = 1.0 / float(scnb.group(1)) if scnb else 1.0 / 2.0 + return f"{'-'.join(atoms)} {lennard_jones} {electrostatic}\n" + + +def _cmap_row(line, cmap, temporary, cmap_flag): + if line.startswith("%FLAG"): + if "CMAP_COUNT" in line: + if temporary: + for residue in temporary["residues"]: + cmap[f"C-N-{residue}@XC-C-N"] = { + "resolution": temporary["info"]["resolution"], + "parameters": temporary["info"]["parameters"], + } + temporary = { + "residues": [], + "info": { + "resolution": 24, + "count": int(line.split()[-1]), + "parameters": [], + }, + } + cmap_flag = "CMAP_COUNT" + elif "CMAP_RESOLUTION" in line: + temporary["info"]["resolution"] = int(line.split()[-1]) + cmap_flag = "CMAP_RESOLUTION" + elif "CMAP_RESLIST" in line: + cmap_flag = "CMAP_RESLIST" + elif "CMAP_TITLE" in line: + cmap_flag = "CMAP_TITLE" + elif "CMAP_PARAMETER" in line: + cmap_flag = "CMAP_PARAMETER" + elif cmap_flag == "CMAP_RESLIST": + temporary["residues"].extend(line.split()) + elif cmap_flag == "CMAP_PARAMETER": + temporary["info"]["parameters"].extend(float(value) for value in line.split()) + return temporary, cmap_flag + + +def _atoms_and_words(line, width, previous=None): + atom_field = line[:width] + if atom_field.strip(): + return [word.strip() for word in atom_field.split("-")], line[width:].split() + if previous is None: + raise ValueError("Amber parameter continuation line has no preceding atom types") + return list(previous), line[width:].split() + + +def parse_frcmod(filename, nbtype="RE", include_nb14=False): + """Return Xponge-compatible parameter text blocks from an Amber frcmod.""" + atom_types = {} + bonds = ["name k[kcal/mol·A^-2] b[A]\n"] + angles = ["name k[kcal/mol·rad^-2] b[degree]\n"] + propers = ["name k[kcal/mol] phi0[degree] periodicity reset\n"] + nb14s = ["name kLJ kee\n"] + impropers = ["name k[kcal/mol] phi0[degree] periodicity\n"] + cmap = {} + cmap_flag = None + temporary_cmap = {"residues": []} + last_dihedral_atoms = None + reset = 1 + flag = None + + if nbtype == "SK": + raise NotImplementedError + if nbtype == "AC": + ljs = ["name A[kcal/mol·A^-12] B[kcal/mol·A^-6]\n"] + elif nbtype == "RE": + ljs = ["name rmin[A] epsilon[kcal/mol]\n"] + else: + raise ValueError(f"Unsupported Amber frcmod nonbonded type: {nbtype}") + + with open(filename, encoding="utf-8") as frcmod: + next(frcmod, None) + for line in frcmod: + if not line.strip(): + continue + words = line.split() + if flag != "CMAP" and len(words) == 1: + flag = line.strip() + if flag[:4] == "DIHE": + last_dihedral_atoms = None + reset = 1 + elif flag and flag[:4] == "MASS": + atom_types[words[0]] = words[1] + elif flag and flag[:4] == "BOND": + atoms, words = _atoms_and_words(line, 5) + bonds.append( + "-".join(atoms) + "\t" + words[0] + "\t" + words[1] + "\n" + ) + elif flag and flag[:4] == "ANGL": + atoms, words = _atoms_and_words(line, 8) + angles.append( + "-".join(atoms) + "\t" + words[0] + "\t" + words[1] + "\n" + ) + elif flag and flag[:4] == "DIHE": + atoms, words = _atoms_and_words(line, 11, last_dihedral_atoms) + last_dihedral_atoms = atoms + propers.append( + "-".join(atoms) + + "\t" + + str(float(words[1]) / int(words[0])) + + "\t" + + words[2] + + "\t" + + str(abs(int(float(words[3])))) + + "\t" + + str(reset) + + "\n" + ) + nb14s.append(_nb14_row(line, atoms)) + reset = 0 if int(float(words[3])) < 0 else 1 + elif flag and flag[:4] == "IMPR": + atoms, words = _atoms_and_words(line, 11) + impropers.append( + "-".join(atoms) + + "\t" + + words[0] + + "\t" + + words[1] + + "\t" + + str(int(float(words[2]))) + + "\n" + ) + elif flag and flag[:4] == "NONB": + ljs.append( + words[0] + "-" + words[0] + "\t" + words[1] + "\t" + words[2] + "\n" + ) + elif flag and flag[:4] == "CMAP": + temporary_cmap, cmap_flag = _cmap_row( + line, cmap, temporary_cmap, cmap_flag + ) + + for residue in temporary_cmap["residues"]: + cmap[f"C-N-{residue}@XC-C-N"] = { + "resolution": temporary_cmap["info"]["resolution"], + "parameters": temporary_cmap["info"]["parameters"], + } + atoms = ["name mass LJtype\n"] + atoms.extend( + atom + "\t" + mass + "\t" + atom + "\n" + for atom, mass in atom_types.items() + ) + values = [ + "".join(atoms), + "".join(bonds), + "".join(angles), + "".join(propers), + "".join(impropers), + "".join(ljs), + ] + if include_nb14: + values.append("".join(nb14s)) + values.append(cmap) + return values + + +def _read_harmonic_rows(stream, rows, width): + for line in stream: + if not line.strip(): + break + atoms, words = _atoms_and_words(line, width) + rows.append( + "-".join(atoms) + "\t" + words[0] + "\t" + words[1] + "\n" + ) + return rows + + +def parse_parmdat(filename): + """Return Xponge-compatible parameter blocks from an Amber parmdat.""" + with open(filename, encoding="utf-8") as parmdat: + next(parmdat, None) + atom_types = {} + lj_types = {} + for line in parmdat: + if not line.strip(): + break + words = line.split() + atom_types[words[0]] = words[1] + lj_types[words[0]] = words[0] + + next(parmdat, None) + bonds = _read_harmonic_rows( + parmdat, + ["name k[kcal/mol·A^-2] b[A]\n"], + 5, + ) + angles = _read_harmonic_rows( + parmdat, + ["name k[kcal/mol·rad^-2] b[degree]\n"], + 8, + ) + + reset = 1 + propers = ["name k[kcal/mol] phi0[degree] periodicity reset\n"] + nb14s = ["name kLJ kee\n"] + atoms = None + for line in parmdat: + if not line.strip(): + break + atoms, words = _atoms_and_words(line, 11, atoms) + nb14s.append(_nb14_row(line, atoms)) + propers.append( + "-".join(atoms) + + "\t" + + str(float(words[1]) / int(words[0])) + + "\t" + + words[2] + + "\t" + + str(abs(int(float(words[3])))) + + "\t" + + str(reset) + + "\n" + ) + reset = 0 if int(float(words[3])) < 0 else 1 + + impropers = ["name k[kcal/mol] phi0[degree] periodicity\n"] + for line in parmdat: + if not line.strip(): + break + improper_atoms, words = _atoms_and_words(line, 11) + impropers.append( + "-".join(improper_atoms) + + "\t" + + words[0] + + "\t" + + words[1] + + "\t" + + str(int(float(words[2]))) + + "\n" + ) + + next(parmdat, None) + next(parmdat, None) + for line in parmdat: + if not line.strip(): + break + aliases = line.split() + primary = aliases.pop(0) + for alias in aliases: + lj_types[alias] = primary + + mode = next(parmdat).split()[1] + if mode == "SK": + raise NotImplementedError + if mode == "AC": + ljs = ["name A[kcal/mol·A^-12] B[kcal/mol·A^-6]\n"] + elif mode == "RE": + ljs = ["name rmin[A] epsilon[kcal/mol]\n"] + else: + raise ValueError(f"Unsupported Amber parmdat nonbonded type: {mode}") + for line in parmdat: + if not line.strip(): + break + words = line.split() + ljs.append( + words[0] + "-" + words[0] + "\t" + words[1] + "\t" + words[2] + "\n" + ) + + atoms = ["name mass LJtype\n"] + atoms.extend( + atom + "\t" + mass + "\t" + lj_types[atom] + "\n" + for atom, mass in atom_types.items() + ) + return [ + "".join(atoms), + "".join(bonds), + "".join(angles), + "".join(propers), + "".join(impropers), + "".join(ljs), + "".join(nb14s), + ] diff --git a/src/XpongeCPP/_compat/process.py b/src/XpongeCPP/_compat/process.py index e045bab..22b9eb0 100644 --- a/src/XpongeCPP/_compat/process.py +++ b/src/XpongeCPP/_compat/process.py @@ -2,8 +2,6 @@ from __future__ import annotations -from pathlib import Path - from .._core import ( Molecule, Residue, @@ -20,7 +18,6 @@ save_sponge_input as _core_save_sponge_input, set_box_padding, ) -from .runtime import get_legacy_residue_links_override def _single_residue_molecule(value, parameter_name): @@ -75,63 +72,6 @@ def Set_Box_Padding(molecule, padding=0.5, center=True): return set_box_padding(molecule, padding, center) -def _normalise_link_pair(atom1, atom2): - if hasattr(atom1, "index") or not isinstance(atom1, (int, str)): - return _normalise_mol2_bond_pair(atom1, atom2) - return _normalise_mol2_bond_pair(int(atom1), int(atom2)) - - -def _collect_residue_link_pairs(molecule, residue_links=None): - connect_pairs = [] - seen = set() - override = get_legacy_residue_links_override(molecule) or [] - for atom1, atom2 in override: - pair = _normalise_mol2_bond_pair(atom1, atom2) - if pair in seen: - continue - seen.add(pair) - connect_pairs.append(pair) - if residue_links is None: - residue_links = getattr(molecule, "residue_links", None) or [] - for link in residue_links: - if hasattr(link, "atom1") and hasattr(link, "atom2"): - pair = _normalise_link_pair(link.atom1, link.atom2) - else: - pair = _normalise_link_pair(link[0], link[1]) - if pair in seen: - continue - seen.add(pair) - connect_pairs.append(pair) - return connect_pairs - - -def _patch_saved_pdb_residue_links(molecule, filename, residue_links=None): - path = Path(filename) - if not path.exists(): - return None - with path.open(encoding="utf-8", errors="ignore") as handle: - lines = handle.read().splitlines() - end_line = None - if lines and lines[-1].startswith("END"): - end_line = lines.pop() - updated_lines = [] - for line in lines: - if line.startswith("HETATM"): - updated_lines.append("ATOM " + line[6:]) - elif not line.startswith("CONECT"): - updated_lines.append(line) - lines = updated_lines - - for atom1, atom2 in _collect_residue_link_pairs(molecule, residue_links=residue_links): - lines.append(f"CONECT{atom1:5d}{atom2:5d}") - lines.append(f"CONECT{atom2:5d}{atom1:5d}") - if end_line is not None: - lines.append(end_line) - with path.open("w", encoding="utf-8") as handle: - handle.write("\n".join(lines) + "\n") - return None - - def Save_SPONGE_Input( # pylint: disable=redefined-builtin molecule, prefix=None, @@ -171,13 +111,11 @@ def Save_SPONGE_Input( # pylint: disable=redefined-builtin else: raise TypeError("save_sponge_input expects a Molecule, Residue, ResidueType, or template-like object") + new_to_old_atom_order = _prepare_sponge_atom_order(target) + if source_ids is not None: + source_ids = tuple(source_ids[old_index] for old_index in new_to_old_atom_order) + previous_min_flag = None - saved_links = None - if hasattr(target, "residue_links"): - try: - saved_links = list(target.residue_links) - except Exception: - saved_links = None try: from ..forcefield.special.min import min_bonded_parameters_enabled @@ -193,11 +131,15 @@ def Save_SPONGE_Input( # pylint: disable=redefined-builtin finally: if previous_min_flag is not None: target.enable_min_bonded_parameters(False) - if prefix is not None: - _patch_saved_pdb_residue_links(target, f"{prefix}.pdb", residue_links=saved_links) return _save_result_with_mapping(target, source_ids, return_mapping) +def _prepare_sponge_atom_order(molecule): + from .._core import prepare_sponge_atom_order + + return tuple(int(index) for index in prepare_sponge_atom_order(molecule)) + + def _capture_source_atom_ids(molecule, source_atom_ids): if source_atom_ids is None: return None @@ -236,7 +178,6 @@ def save_sponge_input_raw(molecule, prefix=None, dirname="."): def Save_PDB(molecule, filename, write_cryst1=True): target = str(filename) save_pdb(molecule, target, write_cryst1) - _patch_saved_pdb_residue_links(molecule, target) return None diff --git a/src/XpongeCPP/_compat/runtime.py b/src/XpongeCPP/_compat/runtime.py index 575eb42..d01fce9 100644 --- a/src/XpongeCPP/_compat/runtime.py +++ b/src/XpongeCPP/_compat/runtime.py @@ -12,6 +12,7 @@ _legacy_add_residue_links, _legacy_clear_residue_links, _legacy_get_residuetype, + _legacy_get_all_residuetypes, _legacy_get_residue_links, _legacy_get_residue_links_copy, _legacy_make_residue_like, @@ -126,6 +127,8 @@ def install_legacy_runtime_patches(namespace: dict | None = None): ResidueType.get_type = staticmethod(_legacy_get_residuetype) ResidueType.Get_Type = staticmethod(_legacy_get_residuetype) + ResidueType.get_all_types = staticmethod(_legacy_get_all_residuetypes) + ResidueType.Get_All_Types = staticmethod(_legacy_get_all_residuetypes) ResidueType.add_atom = _legacy_residuetype_add_atom ResidueType.addAtom = _legacy_residuetype_add_atom ResidueType.Add_Atom = _legacy_residuetype_add_atom diff --git a/src/XpongeCPP/analysis/md_analysis.py b/src/XpongeCPP/analysis/md_analysis.py index d406529..e496a2a 100644 --- a/src/XpongeCPP/analysis/md_analysis.py +++ b/src/XpongeCPP/analysis/md_analysis.py @@ -65,6 +65,12 @@ def close(self): class SpongeInputReader(TopologyReaderBase): + format = "SPONGE_MASS" + + @staticmethod + def _format_hint(thing): + return isinstance(thing, str) and thing.endswith("_mass.txt") + def parse(self, **kwargs): attrs = [topologyattrs.Segids(np.array(["SYSTEM"], dtype=object))] has_names = False diff --git a/src/XpongeCPP/assign/resp.py b/src/XpongeCPP/assign/resp.py index 476c957..c27ba39 100644 --- a/src/XpongeCPP/assign/resp.py +++ b/src/XpongeCPP/assign/resp.py @@ -6,7 +6,6 @@ from __future__ import annotations import time -import sys from ..helper import Xprint, set_global_alternative_names from ..qm import scheduler as qm_scheduler @@ -28,6 +27,18 @@ "BeslerMerzKollman1990_ESP", ) +RESP_REFERENCE_TEXT = """Reference for resp.py: + Bayly, C.I.; Cieplak, P.; Cornell, W.; Kollman, P.A. + A well-behaved electrostatic potential based method using charge restraints. + Journal of Physical Chemistry 1993 97, 10269-10280. + DOI: 10.1021/j100142a004 +""" + + +def print_references(): + """Print the RESP method reference explicitly on request.""" + Xprint(RESP_REFERENCE_TEXT) + def _normalize_backend_name(backend): try: @@ -74,15 +85,9 @@ def _build_backend_payload(backend_module, assign, resolved_basis, charge, spin, def _legacy_backend_import_or_hint(backend_name, exc): message = str(exc) - if backend_name == "pyscf" and sys.platform.startswith("win"): - message += ( - " On Windows, install Psi4 via conda-forge or the official Psi4 " - "installer and call calculate_charge('resp', backend='psi4', ...)." - ) - elif backend_name == "psi4": + if backend_name == "psi4": message += ( - " On Windows, Psi4 is not installed through pip by default; " - "install it via conda-forge or the official Psi4 installer and retry." + " Install Psi4 via conda-forge or the official Psi4 installer and retry." ) raise ImportError(message) from exc diff --git a/src/XpongeCPP/build.py b/src/XpongeCPP/build.py index c296b33..4fe5388 100644 --- a/src/XpongeCPP/build.py +++ b/src/XpongeCPP/build.py @@ -1,5 +1,6 @@ """Legacy-style build module shim for XpongeCPP.""" +from .helper.math import guess_element_from_mass from ._compat.workflows import build_bonded_force, get_mindsponge_system_energy from ._compat.imports import reexport_module @@ -22,6 +23,36 @@ ], ) + +def _pdb_guess_element(atom): + """Return the two-column PDB element token used by Xponge writers.""" + + element = getattr(atom, "element", None) + if not element: + element = getattr(getattr(atom, "type", None), "element", None) + if not element: + mass = getattr(atom, "mass", None) + if mass is not None and mass > 0: + try: + element = guess_element_from_mass(mass) + except Exception: + element = None + if not element: + name = getattr(atom, "name", "") + letters = "".join(character for character in name if character.isalpha()) + if letters: + element = ( + letters[0].upper() + letters[1].lower() + if len(letters) >= 2 and letters[1].islower() + else letters[0].upper() + ) + else: + element = "X" + if len(element) == 1: + return f"{element:>2}" + return f"{element[:2]:>2}" + + __all__ = [ "save_gro", "save_mol2", diff --git a/src/XpongeCPP/capabilities.py b/src/XpongeCPP/capabilities.py new file mode 100644 index 0000000..7823954 --- /dev/null +++ b/src/XpongeCPP/capabilities.py @@ -0,0 +1,66 @@ +"""Machine-readable Xponge compatibility capabilities. + +Only capabilities declared here are part of the stable compatibility contract. +An unlisted capability is unsupported until it is implemented and covered by +parity tests. ``parity`` distinguishes an available implementation from one +whose numerical equivalence has completed the release gate. +""" + +from __future__ import annotations + +from copy import deepcopy + + +_CAPABILITIES = { + "compat.import_xponge": {"status": "supported", "parity": "verified"}, + "forcefield.amber.protein": {"status": "supported", "parity": "verified"}, + "forcefield.amber.water_ion": {"status": "supported", "parity": "verified"}, + "forcefield.amber.gaff": {"status": "supported", "parity": "verified"}, + "forcefield.amber.gaff2": {"status": "supported", "parity": "verified"}, + "forcefield.amber.glycam": {"status": "supported", "parity": "verified"}, + "forcefield.amber.lipid17": {"status": "supported", "parity": "verified"}, + "forcefield.amber.lipid21": {"status": "supported", "parity": "verified"}, + "io.pdb": {"status": "supported", "parity": "verified"}, + "io.mmcif": {"status": "supported", "parity": "verified"}, + "io.mol2": {"status": "supported", "parity": "verified"}, + "io.sponge.raw": {"status": "supported", "parity": "verified"}, + "io.sponge.bundle": {"status": "supported", "parity": "verified"}, + "assignment.resp": {"status": "supported", "parity": "verified"}, + "metal_assignment.local_patch": {"status": "supported", "parity": "verified"}, + "fep.dual_topology": {"status": "supported", "parity": "verified"}, +} + + +def capability_manifest(): + """Return an isolated JSON-serializable compatibility manifest.""" + + return { + "schema_version": 1, + "implementation": "xpongecpp", + "unlisted_status": "unsupported", + "capabilities": deepcopy(_CAPABILITIES), + } + + +def capability_status(capability_id): + """Return the declared status for *capability_id*.""" + + entry = _CAPABILITIES.get(str(capability_id)) + return "unsupported" if entry is None else entry["status"] + + +def require_capability(capability_id): + """Fail explicitly when a requested compatibility capability is absent.""" + + capability_id = str(capability_id) + if capability_status(capability_id) != "supported": + raise NotImplementedError( + f"XpongeCPP compatibility capability is not supported: {capability_id}" + ) + + +__all__ = [ + "capability_manifest", + "capability_status", + "require_capability", +] diff --git a/src/XpongeCPP/data/amber/glycam_06j/__init__.py b/src/XpongeCPP/data/amber/glycam_06j/__init__.py index 1bceb5e..e2ecf20 100644 --- a/src/XpongeCPP/data/amber/glycam_06j/__init__.py +++ b/src/XpongeCPP/data/amber/glycam_06j/__init__.py @@ -44,6 +44,11 @@ def set_head(res, n): :param n: :return: """ + if n == 0: + res.head = None + res.head_next = None + res.head_link_conditions.clear() + return head_dihedral = -60 if (n <= 6 and res.name[-1] not in "DU") else -180 res.head = f"O{n}" res.head_next = f"C{n}" diff --git a/src/XpongeCPP/forcefield/amber/_lipid_common.py b/src/XpongeCPP/forcefield/amber/_lipid_common.py index b01242c..9581405 100644 --- a/src/XpongeCPP/forcefield/amber/_lipid_common.py +++ b/src/XpongeCPP/forcefield/amber/_lipid_common.py @@ -3,6 +3,7 @@ import json from ... import configure_residue_template_head, configure_residue_template_tail +from ...legacy_types import _remember_template_connection def configure_connection(residue_name, position, anchor, next_atom, length=1.5): @@ -12,6 +13,13 @@ def configure_connection(residue_name, position, anchor, next_atom, length=1.5): else configure_residue_template_tail ) configure(residue_name, anchor, length, next_atom) + _remember_template_connection( + residue_name, + position, + anchor, + next_atom, + length, + ) def configure_standard_chain(residue_name): @@ -35,5 +43,12 @@ def configure_manifest(path): configure_connection( entry["template"], position, anchor, entry[f"{position}_next_atom"] ) + _remember_template_connection( + entry["template"], + position, + anchor, + entry[f"{position}_next_atom"], + 1.5, + entry.get(f"{position}_link_conditions", []), + ) return manifest - diff --git a/src/XpongeCPP/forcefield/amber/_parmchk2.py b/src/XpongeCPP/forcefield/amber/_parmchk2.py index 0a76775..38a504b 100644 --- a/src/XpongeCPP/forcefield/amber/_parmchk2.py +++ b/src/XpongeCPP/forcefield/amber/_parmchk2.py @@ -52,112 +52,7 @@ def coerce_parmchk2_input(ifname): ) -def _is_gaff_like_type(atom_type): - return any(character.islower() for character in atom_type) - - -def filter_mixed_gaff_mol2(mol2_path): - sections = {} - current = None - with open(mol2_path, encoding="utf-8", errors="ignore") as handle: - for line in handle.read().splitlines(): - if line.startswith("@"): - current = line.strip() - sections[current] = [] - continue - if current is not None: - sections[current].append(line) - atom_records = [] - for line in sections.get("@ATOM", []): - if not line.strip(): - continue - fields = line.split() - if len(fields) < 6: - return mol2_path, None - atom_records.append(fields) - if not atom_records: - return mol2_path, None - keep_old_ids = { - int(fields[0]) - for fields in atom_records - if _is_gaff_like_type(fields[5]) - } - if not keep_old_ids or len(keep_old_ids) == len(atom_records): - return mol2_path, None - tempdir = TemporaryDirectory() - filtered_path = os.path.join(tempdir.name, "gaff_subset.mol2") - old_to_new = { - old_id: index + 1 for index, old_id in enumerate(sorted(keep_old_ids)) - } - sub_old_to_new = {} - filtered_atoms = [] - for fields in atom_records: - old_id = int(fields[0]) - if old_id not in old_to_new: - continue - fields = list(fields) - fields[0] = str(old_to_new[old_id]) - sub_id = int(fields[6]) if len(fields) > 6 else 1 - sub_old_to_new.setdefault(sub_id, len(sub_old_to_new) + 1) - if len(fields) > 6: - fields[6] = str(sub_old_to_new[sub_id]) - filtered_atoms.append(fields) - filtered_bonds = [] - for line in sections.get("@BOND", []): - fields = line.split() - if len(fields) < 4: - continue - old_a = int(fields[1]) - old_b = int(fields[2]) - if old_a not in old_to_new or old_b not in old_to_new: - continue - fields = list(fields) - fields[0] = str(len(filtered_bonds) + 1) - fields[1] = str(old_to_new[old_a]) - fields[2] = str(old_to_new[old_b]) - filtered_bonds.append(fields) - filtered_substructures = [] - substructure_lines = sections.get("@SUBSTRUCTURE", []) - for old_sub_id, new_sub_id in sorted( - sub_old_to_new.items(), key=lambda item: item[1] - ): - source = None - for line in substructure_lines: - fields = line.split() - if fields and int(fields[0]) == old_sub_id: - source = list(fields) - break - if source is None: - source = [ - str(old_sub_id), "MOL", "1", "TEMP", "0", - "****", "****", "0", "ROOT", - ] - source[0] = str(new_sub_id) - if len(source) > 2: - source[2] = "1" - filtered_substructures.append(source) - with open(filtered_path, "w", encoding="utf-8") as handle: - handle.write("@MOLECULE\n") - handle.write("GAFF_SUBSET\n") - handle.write( - f"{len(filtered_atoms):6d}{len(filtered_bonds):6d}" - f"{len(filtered_substructures):6d} 0 1\n" - ) - handle.write("SMALL\nUSER_CHARGES\n") - handle.write("@ATOM\n") - for fields in filtered_atoms: - handle.write(" ".join(fields) + "\n") - handle.write("@BOND\n") - for fields in filtered_bonds: - handle.write(" ".join(fields) + "\n") - handle.write("@SUBSTRUCTURE\n") - for fields in filtered_substructures: - handle.write(" ".join(fields) + "\n") - return filtered_path, tempdir - - __all__ = [ "coerce_parmchk2_input", - "filter_mixed_gaff_mol2", "import_xpongelib", ] diff --git a/src/XpongeCPP/forcefield/amber/bsc1.py b/src/XpongeCPP/forcefield/amber/bsc1.py index 970519a..9136c83 100644 --- a/src/XpongeCPP/forcefield/amber/bsc1.py +++ b/src/XpongeCPP/forcefield/amber/bsc1.py @@ -1,8 +1,11 @@ """Register Amber bsc1 DNA templates and parameters.""" from ... import ( + configure_residue_template_head, + configure_residue_template_tail, register_amber_frcmod_file, register_amber_parmdat_file, + register_pdb_residue_name_mapping, register_residue_templates_from_mol2_file, ) from . import data_path @@ -11,3 +14,14 @@ register_amber_frcmod_file(str(data_path("parmbsc1.frcmod"))) register_residue_templates_from_mol2_file(str(data_path("RNA.mol2"))) register_residue_templates_from_mol2_file(str(data_path("bsc1.mol2"))) + +for base in "ATCG": + residue = f"D{base}" + residue5 = f"{residue}5" + residue3 = f"{residue}3" + configure_residue_template_tail(residue, "O3'", 1.5, "C3'") + configure_residue_template_tail(residue5, "O3'", 1.5, "C3'") + configure_residue_template_head(residue, "P", 1.5, "OP2") + configure_residue_template_head(residue3, "P", 1.5, "OP2") + register_pdb_residue_name_mapping("head", residue, residue5) + register_pdb_residue_name_mapping("tail", residue, residue3) diff --git a/src/XpongeCPP/forcefield/amber/ff19sb.py b/src/XpongeCPP/forcefield/amber/ff19sb.py index 681343e..8673c67 100644 --- a/src/XpongeCPP/forcefield/amber/ff19sb.py +++ b/src/XpongeCPP/forcefield/amber/ff19sb.py @@ -7,6 +7,7 @@ from ... import ( register_amber_frcmod_file, register_amber_parmdat_file, + register_his_mapping, register_residue_templates_from_mol2_file, ) from . import configure_proline_like_terminal_mapping, data_path @@ -15,4 +16,5 @@ register_amber_frcmod_file(str(data_path("ff19SB.frcmod"))) register_residue_templates_from_mol2_file(str(data_path("ff19SB.mol2"))) register_residue_templates_from_mol2_file(str(data_path("ff19SB_nhyp.mol2"))) +register_his_mapping("HIS", "HID", "HIE", "HIP") configure_proline_like_terminal_mapping("HYP", "CHYP", "NHYP") diff --git a/src/XpongeCPP/forcefield/amber/gaff.py b/src/XpongeCPP/forcefield/amber/gaff.py index 1d6b021..3693b78 100644 --- a/src/XpongeCPP/forcefield/amber/gaff.py +++ b/src/XpongeCPP/forcefield/amber/gaff.py @@ -56,102 +56,11 @@ def _coerce_parmchk2_input(ifname): raise TypeError("parmchk2_gaff expects a mol2 path or a template-like molecule object") -def _is_gaff_like_type(atom_type): - return any(ch.islower() for ch in atom_type) - - -def _filter_mixed_gaff_mol2(mol2_path): - sections = {} - current = None - with open(mol2_path, encoding="utf-8", errors="ignore") as handle: - for line in handle.read().splitlines(): - if line.startswith("@"): - current = line.strip() - sections[current] = [] - continue - if current is not None: - sections[current].append(line) - atom_records = [] - for line in sections.get("@ATOM", []): - if not line.strip(): - continue - fields = line.split() - if len(fields) < 6: - return mol2_path, None - atom_records.append(fields) - if not atom_records: - return mol2_path, None - keep_old_ids = {int(fields[0]) for fields in atom_records if _is_gaff_like_type(fields[5])} - if not keep_old_ids or len(keep_old_ids) == len(atom_records): - return mol2_path, None - tempdir = TemporaryDirectory() - filtered_path = os.path.join(tempdir.name, "gaff_subset.mol2") - old_to_new = {old_id: index + 1 for index, old_id in enumerate(sorted(keep_old_ids))} - sub_old_to_new = {} - filtered_atoms = [] - for fields in atom_records: - old_id = int(fields[0]) - if old_id not in old_to_new: - continue - fields = list(fields) - fields[0] = str(old_to_new[old_id]) - sub_id = int(fields[6]) if len(fields) > 6 else 1 - sub_old_to_new.setdefault(sub_id, len(sub_old_to_new) + 1) - if len(fields) > 6: - fields[6] = str(sub_old_to_new[sub_id]) - filtered_atoms.append(fields) - filtered_bonds = [] - for line in sections.get("@BOND", []): - fields = line.split() - if len(fields) < 4: - continue - old_a = int(fields[1]) - old_b = int(fields[2]) - if old_a not in old_to_new or old_b not in old_to_new: - continue - fields = list(fields) - fields[0] = str(len(filtered_bonds) + 1) - fields[1] = str(old_to_new[old_a]) - fields[2] = str(old_to_new[old_b]) - filtered_bonds.append(fields) - filtered_substructures = [] - for old_sub_id, new_sub_id in sorted(sub_old_to_new.items(), key=lambda item: item[1]): - source = None - for line in sections.get("@SUBSTRUCTURE", []): - fields = line.split() - if fields and int(fields[0]) == old_sub_id: - source = list(fields) - break - if source is None: - source = [str(old_sub_id), "MOL", "1", "TEMP", "0", "****", "****", "0", "ROOT"] - source[0] = str(new_sub_id) - if len(source) > 2: - source[2] = "1" - filtered_substructures.append(source) - with open(filtered_path, "w", encoding="utf-8") as handle: - handle.write("@MOLECULE\n") - handle.write("GAFF_SUBSET\n") - handle.write(f"{len(filtered_atoms):6d}{len(filtered_bonds):6d}{len(filtered_substructures):6d} 0 1\n") - handle.write("SMALL\nUSER_CHARGES\n") - handle.write("@ATOM\n") - for fields in filtered_atoms: - handle.write(" ".join(fields) + "\n") - handle.write("@BOND\n") - for fields in filtered_bonds: - handle.write(" ".join(fields) + "\n") - handle.write("@SUBSTRUCTURE\n") - for fields in filtered_substructures: - handle.write(" ".join(fields) + "\n") - return filtered_path, tempdir - - def parmchk2_gaff(ifname, ofname, direct_load=True, keep=True): """Generate frcmod parameters with legacy Xponge-compatible semantics.""" xlib = _import_xpongelib() mol2_path, tempdir = _coerce_parmchk2_input(ifname) - filtered_tempdir = None try: - mol2_path, filtered_tempdir = _filter_mixed_gaff_mol2(mol2_path) datapath = os.path.dirname(xlib.__file__) xlib._parmchk2(mol2_path, "mol2", str(ofname), datapath, 0, 1, 1) if direct_load: @@ -159,7 +68,5 @@ def parmchk2_gaff(ifname, ofname, direct_load=True, keep=True): if not keep: os.remove(ofname) finally: - if filtered_tempdir is not None: - filtered_tempdir.cleanup() if tempdir is not None: tempdir.cleanup() diff --git a/src/XpongeCPP/forcefield/amber/gaff2.py b/src/XpongeCPP/forcefield/amber/gaff2.py index 0bbe6bf..d6034f5 100644 --- a/src/XpongeCPP/forcefield/amber/gaff2.py +++ b/src/XpongeCPP/forcefield/amber/gaff2.py @@ -11,7 +11,6 @@ from . import load_parameters_from_frcmod from ._parmchk2 import ( coerce_parmchk2_input, - filter_mixed_gaff_mol2, import_xpongelib, ) @@ -23,9 +22,7 @@ def parmchk2_gaff2(ifname, ofname, direct_load=True, keep=True): """Generate GAFF2 frcmod parameters with Xponge-compatible semantics.""" xlib = import_xpongelib() mol2_path, tempdir = coerce_parmchk2_input(ifname) - filtered_tempdir = None try: - mol2_path, filtered_tempdir = filter_mixed_gaff_mol2(mol2_path) datapath = os.path.dirname(xlib.__file__) xlib._parmchk2(mol2_path, "mol2", str(ofname), datapath, 0, 1, 2) if direct_load: @@ -33,7 +30,5 @@ def parmchk2_gaff2(ifname, ofname, direct_load=True, keep=True): if not keep: os.remove(ofname) finally: - if filtered_tempdir is not None: - filtered_tempdir.cleanup() if tempdir is not None: tempdir.cleanup() diff --git a/src/XpongeCPP/forcefield/amber/glycam_06j/__init__.py b/src/XpongeCPP/forcefield/amber/glycam_06j/__init__.py index d726281..deedae0 100644 --- a/src/XpongeCPP/forcefield/amber/glycam_06j/__init__.py +++ b/src/XpongeCPP/forcefield/amber/glycam_06j/__init__.py @@ -23,6 +23,9 @@ def configure_glycam_head(resname, oxygen_index): """Set the glycosidic head atom to the indexed hydroxyl oxygen.""" + if oxygen_index == 0: + configure_residue_template_head(resname, "", 1.4, "") + return configure_residue_template_head(resname, f"O{oxygen_index}", 1.4, f"C{oxygen_index}") diff --git a/src/XpongeCPP/forcefield/amber/glycam_06j/prep_to_mol2.py b/src/XpongeCPP/forcefield/amber/glycam_06j/prep_to_mol2.py index 9e769ca..ae7ca11 100644 --- a/src/XpongeCPP/forcefield/amber/glycam_06j/prep_to_mol2.py +++ b/src/XpongeCPP/forcefield/amber/glycam_06j/prep_to_mol2.py @@ -9,7 +9,7 @@ from dataclasses import dataclass from pathlib import Path -from audit import EXTERNAL_COVERAGE, FUNCTIONAL_GROUP_TEMPLATES, _parse_mol2_units +from .audit import EXTERNAL_COVERAGE, FUNCTIONAL_GROUP_TEMPLATES, _parse_mol2_units _UNIT_RE = re.compile(r"^([A-Za-z0-9]{3,4})\s+INT\s+0\s*$") _ATOM_TYPE_NORMALIZATION = { diff --git a/src/XpongeCPP/forcefield/amber/tip3p.py b/src/XpongeCPP/forcefield/amber/tip3p.py index 96fa019..2d163d5 100644 --- a/src/XpongeCPP/forcefield/amber/tip3p.py +++ b/src/XpongeCPP/forcefield/amber/tip3p.py @@ -3,6 +3,7 @@ from ... import ( AtomType, register_amber_frcmod_file, + register_pdb_residue_alias_mapping, register_residue_template_alias, register_residue_templates_from_mol2_file, register_tip3p, @@ -21,6 +22,8 @@ register_residue_templates_from_mol2_file(str(data_path("tip3p.mol2"))) register_residue_template_alias("H2O", "WAT") register_residue_template_alias("HOH", "WAT") +register_pdb_residue_alias_mapping("H2O", "WAT") +register_pdb_residue_alias_mapping("HOH", "WAT") register_amber_frcmod_file(str(data_path("ions1lm_126_tip3p.frcmod"))) register_amber_frcmod_file(str(data_path("ionsjc_tip3p.frcmod"))) register_amber_frcmod_file(str(data_path("ions234lm_126_tip3p.frcmod"))) diff --git a/src/XpongeCPP/forcefield/base/lj_base.py b/src/XpongeCPP/forcefield/base/lj_base.py index cc6ea7e..3414922 100644 --- a/src/XpongeCPP/forcefield/base/lj_base.py +++ b/src/XpongeCPP/forcefield/base/lj_base.py @@ -4,6 +4,8 @@ import math +from ..._core import _find_amber_lj_parameter + class _LJEntry: def __init__(self, name, epsilon, rmin): @@ -34,7 +36,18 @@ def _norm(name): @classmethod def get_type(cls, name): - return cls._types[cls._norm(name)] + key = cls._norm(name) + try: + return cls._types[key] + except KeyError: + left, separator, right = str(name).partition("-") + if not separator or left != right: + raise + parameter = _find_amber_lj_parameter(left) + if parameter is None: + raise + epsilon, rmin = parameter + return cls._store(name, epsilon, rmin) @classmethod def Get_Type(cls, name): @@ -82,6 +95,9 @@ def New_From_String(cls, text): elif {"epsilon", "rmin"} <= keyset: epsilon = float(row["epsilon"]) rmin = float(row["rmin"]) + elif {"epsilon[kcal/mol]", "rmin[a]"} <= keyset: + epsilon = float(row["epsilon[kcal/mol]"]) + rmin = float(row["rmin[a]"]) elif {"epsilon[ev]", "sigma[nm]"} <= keyset: epsilon = float(row["epsilon[ev]"]) * 23.06054783061903 sigma = float(row["sigma[nm]"]) * 10.0 diff --git a/src/XpongeCPP/helper/__init__.py b/src/XpongeCPP/helper/__init__.py index 65c3808..c025bd8 100644 --- a/src/XpongeCPP/helper/__init__.py +++ b/src/XpongeCPP/helper/__init__.py @@ -21,7 +21,14 @@ xopen, xprint, ) -from .._core import Atom, Molecule, Residue, ResidueType as _CoreResidueType +from .._core import ( + Atom, + Molecule, + Residue, + ResidueType as _CoreResidueType, + _find_amber_lj_parameter, + _find_amber_lj_type, +) from ..legacy_types import _remember_dynamic_residuetype from ..gromacs import GlobalSetting from .cv import CVSystem @@ -124,7 +131,14 @@ def contents(self): @classmethod def get_type(cls, name): - return cls._types[str(name)] + key = str(name) + try: + return cls._types[key] + except KeyError: + lj_type = _find_amber_lj_type(key) + if _find_amber_lj_parameter(lj_type) is None: + raise + return cls(key, LJtype=lj_type) @classmethod def Get_Type(cls, name): diff --git a/src/XpongeCPP/io_bundle/__init__.py b/src/XpongeCPP/io_bundle/__init__.py index 4c9eec7..97630ac 100644 --- a/src/XpongeCPP/io_bundle/__init__.py +++ b/src/XpongeCPP/io_bundle/__init__.py @@ -46,6 +46,7 @@ ProtocolSITS, ProtocolSoftWall, ProtocolSteering, + ProtocolVirtualAtom, SpongeProtocol, ) from .reverse_converter import ( @@ -86,6 +87,7 @@ "ProtocolSITS", "ProtocolSoftWall", "ProtocolSteering", + "ProtocolVirtualAtom", "ReverseConversionManifest", "SpongeProtocol", "UnverifiedBundlePairError", diff --git a/src/XpongeCPP/io_bundle/protocol.py b/src/XpongeCPP/io_bundle/protocol.py index 3c662b1..715504b 100644 --- a/src/XpongeCPP/io_bundle/protocol.py +++ b/src/XpongeCPP/io_bundle/protocol.py @@ -42,6 +42,7 @@ class ProtocolCollectiveVariable: name: str type: str atom_indices: tuple[int, ...] = () + atom_refs: tuple[int | str, ...] = () parameters: Mapping[str, Any] = field(default_factory=dict) period: tuple[float, ...] = () sigma: tuple[float, ...] = () @@ -54,6 +55,17 @@ class ProtocolCollectiveVariable: max_padding: float | None = None +@dataclass(frozen=True) +class ProtocolVirtualAtom: + """One named center used as an atom by collective variables.""" + + name: str + type: str + atom_indices: tuple[int, ...] + weight: tuple[float, ...] = () + enabled: bool = True + + @dataclass(frozen=True) class ProtocolDistanceConstraints: """Extra distance-constraint pairs used by the runtime constraint module.""" @@ -180,6 +192,7 @@ class SpongeProtocol: """Composable native protocol attached to a serialized XPONGE system.""" collective_variables: tuple[ProtocolCollectiveVariable, ...] = () + virtual_atoms: tuple[ProtocolVirtualAtom, ...] = () distance_constraints: tuple[ProtocolDistanceConstraints, ...] = () positional_restraints: tuple[ProtocolPositionalRestraint, ...] = () cv_restraints: tuple[ProtocolCVRestraint, ...] = () @@ -216,6 +229,7 @@ def add_protocol_to_bundle( ) cvs = tuple(protocol.collective_variables) + virtual_atoms = tuple(protocol.virtual_atoms) constraints = tuple(protocol.distance_constraints) positional = tuple(protocol.positional_restraints) cv_restraints = tuple(protocol.cv_restraints) @@ -226,6 +240,7 @@ def add_protocol_to_bundle( soft_walls = tuple(protocol.soft_walls) _validate_protocol( cvs, + virtual_atoms, constraints, positional, cv_restraints, @@ -237,6 +252,8 @@ def add_protocol_to_bundle( atom_count=atom_count, ) + for virtual_atom in virtual_atoms: + _write_virtual_atom(builder, virtual_atom) for cv in cvs: _write_cv(builder, cv) for constraint in constraints: @@ -272,6 +289,7 @@ def add_protocol_to_bundle( def _validate_protocol( cvs: tuple[ProtocolCollectiveVariable, ...], + virtual_atoms: tuple[ProtocolVirtualAtom, ...], constraints: tuple[ProtocolDistanceConstraints, ...], positional: tuple[ProtocolPositionalRestraint, ...], cv_restraints: tuple[ProtocolCVRestraint, ...], @@ -286,19 +304,75 @@ def _validate_protocol( if atom_count <= 0: raise BundleValidationError("a native protocol requires a positive atom count") _require_unique_names(cvs, "collective variable") + _require_unique_names(virtual_atoms, "virtual atom") _require_unique_names(constraints, "distance constraint") _require_unique_names(positional + cv_restraints, "restraint") _require_unique_names(metadynamics, "metadynamics") cv_by_name = {cv.name: cv for cv in cvs if cv.enabled} + virtual_atom_names = {item.name for item in virtual_atoms if item.enabled} + overlapping_names = {cv.name for cv in cvs} & {item.name for item in virtual_atoms} + if overlapping_names: + raise BundleValidationError( + f"collective variables and virtual atoms must use distinct names: {sorted(overlapping_names)}" + ) + for item in virtual_atoms: + _validate_name(item.name, "virtual atom") + if item.type not in {"center", "center_of_mass"}: + raise BundleValidationError( + f"virtual atom {item.name!r} type must be 'center' or 'center_of_mass'" + ) + if not item.atom_indices: + raise BundleValidationError(f"virtual atom {item.name!r} requires atom_indices") + _validate_atom_indices(item.atom_indices, atom_count, f"virtual atom {item.name!r}") + if item.type == "center": + _validate_vector_length( + item.weight, + len(item.atom_indices), + f"virtual atom {item.name!r} weight", + required=True, + ) + _require_finite(item.weight, f"virtual atom {item.name!r} weight") + elif item.weight: + raise BundleValidationError( + f"virtual atom {item.name!r} center_of_mass must not define weight" + ) for cv in cvs: _validate_name(cv.name, "collective variable") + if cv.name == "virtual_atom": + raise BundleValidationError( + "collective variable name 'virtual_atom' is reserved by /cv/virtual_atom" + ) _validate_name(cv.type, f"collective variable {cv.name!r} type") if cv.dimension != 1: raise BundleValidationError( f"collective variable {cv.name!r} dimension must be 1 for the current SPONGE runtime" ) + if cv.atom_indices and cv.atom_refs: + raise BundleValidationError( + f"collective variable {cv.name!r} atom_indices and atom_refs are mutually exclusive" + ) _validate_atom_indices(cv.atom_indices, atom_count, f"collective variable {cv.name!r}") + physical_atom_refs = [item for item in cv.atom_refs if isinstance(item, (int, np.integer))] + invalid_atom_refs = [item for item in cv.atom_refs if not isinstance(item, (str, int, np.integer))] + if invalid_atom_refs: + raise BundleValidationError( + f"collective variable {cv.name!r} atom_refs must contain atom indices or virtual atom names" + ) + normalized_atom_refs = tuple(str(item) for item in cv.atom_refs) + if len(normalized_atom_refs) != len(set(normalized_atom_refs)): + raise BundleValidationError( + f"collective variable {cv.name!r} atom_refs must be unique" + ) + _validate_atom_indices(physical_atom_refs, atom_count, f"collective variable {cv.name!r}") + missing_atom_refs = [ + name for name in cv.atom_refs if isinstance(name, str) and name not in virtual_atom_names + ] + if missing_atom_refs: + raise BundleValidationError( + f"collective variable {cv.name!r} references missing or disabled virtual atoms: " + f"{missing_atom_refs}" + ) _validate_vector_length(cv.period, cv.dimension, f"collective variable {cv.name!r} period") _validate_vector_length(cv.sigma, cv.dimension, f"collective variable {cv.name!r} sigma") if cv.sigma and any(value <= 0 or not np.isfinite(value) for value in cv.sigma): @@ -308,7 +382,7 @@ def _validate_protocol( if cv.reference_coordinates: _validate_xyz( cv.reference_coordinates, - len(cv.atom_indices), + len(cv.atom_indices or cv.atom_refs), f"collective variable {cv.name!r} reference coordinates", ) for key, value in cv.parameters.items(): @@ -655,6 +729,8 @@ def _write_cv(builder: BundleBuilder, cv: ProtocolCollectiveVariable) -> None: _add_scalar(builder, root + "/enabled_default", int(cv.enabled), np.int32) if cv.atom_indices: _add_array(builder, root + "/atom_indices", cv.atom_indices, np.int32) + if cv.atom_refs: + _add_array(builder, root + "/atom_refs", tuple(str(item) for item in cv.atom_refs), object) if cv.period: _add_array(builder, root + "/period", cv.period, np.float32) if cv.sigma: @@ -683,6 +759,15 @@ def _write_cv(builder: BundleBuilder, cv: ProtocolCollectiveVariable) -> None: ) +def _write_virtual_atom(builder: BundleBuilder, virtual_atom: ProtocolVirtualAtom) -> None: + root = f"/cv/virtual_atom/{virtual_atom.name}" + _add_scalar(builder, root + "/type", virtual_atom.type) + _add_scalar(builder, root + "/enabled_default", int(virtual_atom.enabled), np.int32) + _add_array(builder, root + "/atom_indices", virtual_atom.atom_indices, np.int32) + if virtual_atom.weight: + _add_array(builder, root + "/weight", virtual_atom.weight, np.float32) + + def _write_constraint(builder: BundleBuilder, constraint: ProtocolDistanceConstraints) -> None: root = f"/constraint/{constraint.name}" _add_scalar(builder, root + "/schema_version", 1, np.int64) diff --git a/src/XpongeCPP/legacy_types.py b/src/XpongeCPP/legacy_types.py index 804d637..1a640b2 100644 --- a/src/XpongeCPP/legacy_types.py +++ b/src/XpongeCPP/legacy_types.py @@ -14,6 +14,8 @@ get_template_molecule, has_template, molecule_from_residuetype, + register_residue_type_template, + registered_template_names, register_residue_templates_from_mol2_text, ) @@ -46,8 +48,10 @@ def head(self): @head.setter def head(self, value): _legacy_template_metadata.setdefault(self._name, {})["head"] = value - if value: - configure_residue_template_head(self._name, str(value)) + configure_residue_template_head( + self._name, + "" if value is None else str(value), + ) @property def tail(self): @@ -56,13 +60,80 @@ def tail(self): @tail.setter def tail(self, value): _legacy_template_metadata.setdefault(self._name, {})["tail"] = value - if value: - configure_residue_template_tail(self._name, str(value)) + configure_residue_template_tail( + self._name, + "" if value is None else str(value), + ) + + @property + def head_next(self): + return _legacy_template_metadata.get(self._name, {}).get("head_next") + + @head_next.setter + def head_next(self, value): + _legacy_template_metadata.setdefault(self._name, {})["head_next"] = value + + @property + def tail_next(self): + return _legacy_template_metadata.get(self._name, {}).get("tail_next") + + @tail_next.setter + def tail_next(self, value): + _legacy_template_metadata.setdefault(self._name, {})["tail_next"] = value + + @property + def head_length(self): + return _legacy_template_metadata.get(self._name, {}).get("head_length") + + @head_length.setter + def head_length(self, value): + _legacy_template_metadata.setdefault(self._name, {})["head_length"] = value + + @property + def tail_length(self): + return _legacy_template_metadata.get(self._name, {}).get("tail_length") + + @tail_length.setter + def tail_length(self, value): + _legacy_template_metadata.setdefault(self._name, {})["tail_length"] = value + + @property + def head_link_conditions(self): + return _legacy_template_metadata.setdefault(self._name, {}).setdefault( + "head_link_conditions", [] + ) + + @property + def tail_link_conditions(self): + return _legacy_template_metadata.setdefault(self._name, {}).setdefault( + "tail_link_conditions", [] + ) @property def atoms(self): + dynamic = _legacy_dynamic_residue_types.get(self._name) + if dynamic is not None: + return dynamic.atoms return get_template_molecule(self._name).residues[0].atoms + def name2atom(self, name): + for atom in self.atoms: + if atom.name == name: + return atom + raise KeyError(name) + + def add_atom(self, name, atom_type, x, y, z, charge=0.0, mass=0.0): + residue_type = _materialize_dynamic_residuetype(self._name) + return residue_type.add_atom( + name, + atom_type, + x, + y, + z, + charge=charge, + mass=mass, + ) + def deepcopy(self, name): name = str(name) _register_template_variant(self._name, name) @@ -106,6 +177,63 @@ def _legacy_get_residuetype(name): return _LegacyResidueTypeHandle(name) +def _legacy_get_all_residuetypes(): + names = set(registered_template_names()) + names.update(_legacy_dynamic_residue_types) + return {name: _legacy_get_residuetype(name) for name in sorted(names)} + + +def _materialize_dynamic_residuetype(name): + """Return a writable copy of a registered residue template.""" + + name = str(name) + dynamic = _legacy_dynamic_residue_types.get(name) + if dynamic is not None: + return dynamic + if not has_template(name): + raise KeyError(f"ResidueType {name!r} is not registered") + + template = get_template_molecule(name) + if template.residue_count != 1: + raise TypeError( + "residue template compatibility expects one-residue templates" + ) + residue = template.residues[0] + dynamic = _remember_dynamic_residuetype(ResidueType(name)) + for atom in residue.atoms: + dynamic.add_atom( + atom.name, + atom.type, + atom.x, + atom.y, + atom.z, + charge=atom.charge, + mass=atom.mass, + ) + for atom1, atom2 in template.explicit_bonds: + dynamic.add_connectivity( + template.atoms[int(atom1)].name, + template.atoms[int(atom2)].name, + ) + return dynamic + + +def _remember_template_connection( + residue_name, + position, + anchor, + next_atom, + length, + conditions=None, +): + metadata = _legacy_template_metadata.setdefault(str(residue_name), {}) + metadata[str(position)] = anchor + metadata[f"{position}_next"] = next_atom + metadata[f"{position}_length"] = length + if conditions is not None: + metadata[f"{position}_link_conditions"] = list(conditions) + + def _coerce_atom_index(atom): if isinstance(atom, (int, np.integer)): return int(atom) @@ -126,16 +254,13 @@ def get(self, atom, default=None): _core_molecule_add_residue_link = Molecule.add_residue_link +_core_molecule_clear_residue_links = Molecule.clear_residue_links _core_molecule_residue_links = Molecule.residue_links def _legacy_add_residue_link(self, atom1, atom2): pair = [_coerce_atom_index(atom1), _coerce_atom_index(atom2)] - override = _legacy_residue_links_override.get(self) - if override is not None: - if pair not in override: - override.append(pair) - return None + _legacy_residue_links_override.pop(self, None) return _core_molecule_add_residue_link(self, pair[0], pair[1]) @@ -229,9 +354,12 @@ def _ensure_dynamic_residuetype_template(name): residue_type = _legacy_dynamic_residue_types.get(str(name)) if residue_type is None: return False - register_residue_templates_from_mol2_text( - _dynamic_residuetype_mol2_text(residue_type) - ) + register_residue_type_template(residue_type) + metadata = _legacy_template_metadata.get(str(name), {}) + if metadata.get("head"): + configure_residue_template_head(str(name), str(metadata["head"])) + if metadata.get("tail"): + configure_residue_template_tail(str(name), str(metadata["tail"])) return True @@ -256,7 +384,8 @@ def _legacy_get_residue_links(self): def _legacy_clear_residue_links(self): - _legacy_residue_links_override[self] = [] + _core_molecule_clear_residue_links(self) + _legacy_residue_links_override.pop(self, None) return self @@ -270,7 +399,10 @@ def _legacy_set_residue_links(self, links): continue seen.add(pair) normalized.append([atom1, atom2]) - _legacy_residue_links_override[self] = normalized + _core_molecule_clear_residue_links(self) + for atom1, atom2 in normalized: + _core_molecule_add_residue_link(self, atom1, atom2) + _legacy_residue_links_override.pop(self, None) return self diff --git a/src/XpongeCPP/metal_assignment/molecule_api.py b/src/XpongeCPP/metal_assignment/molecule_api.py index a35da6c..347b2f9 100644 --- a/src/XpongeCPP/metal_assignment/molecule_api.py +++ b/src/XpongeCPP/metal_assignment/molecule_api.py @@ -174,7 +174,19 @@ def _normalized_patch_mapping( try: index = molecule_atom_index[value] except (KeyError, TypeError) as exc: - raise ValidationError("molecule_atom_not_found", external_id) from exc + native_index = getattr(value, "index", None) + if isinstance(native_index, bool): + raise ValidationError( + "molecule_atom_not_found", + external_id, + ) from exc + try: + index = int(native_index) + except (TypeError, ValueError): + raise ValidationError( + "molecule_atom_not_found", + external_id, + ) from exc if index < 0 or index >= len(molecule.atoms): raise ValidationError("invalid_molecule_atom_index", external_id) molecule_atom = molecule.atoms[index] diff --git a/src/XpongeCPP/process.py b/src/XpongeCPP/process.py index 790da48..ec06d8e 100644 --- a/src/XpongeCPP/process.py +++ b/src/XpongeCPP/process.py @@ -161,15 +161,18 @@ def main_axis_rotate(molecule, direction_long=None, direction_middle=None, direc direction_short = np.array(direction_short if direction_short is not None else [1, 0, 0], dtype=float) coordinates = _molecule_coordinates(molecule) center = np.zeros(3, dtype=float) - total_mass = 0.0 - for atom, coordinate in zip(molecule.atoms, coordinates): - total_mass += atom.mass - center += atom.mass * coordinate + masses = np.asarray([float(atom.mass) for atom in molecule.atoms], dtype=float) + total_mass = float(masses.sum()) + if not np.isfinite(total_mass) or total_mass <= 0.0: + masses = np.ones(len(molecule.atoms), dtype=float) + total_mass = float(len(molecule.atoms)) + for mass, coordinate in zip(masses, coordinates): + center += mass * coordinate center /= total_mass inertia = np.zeros((3, 3), dtype=float) - for atom, coordinate in zip(molecule.atoms, coordinates): + for mass, coordinate in zip(masses, coordinates): x, y, z = coordinate - center - inertia += atom.mass * np.array([ + inertia += mass * np.array([ [y * y + z * z, -x * y, -x * z], [-x * y, x * x + z * z, -y * z], [-x * z, -y * z, x * x + y * y], diff --git a/src/XpongeCPP/qm/scheduler.py b/src/XpongeCPP/qm/scheduler.py index ab5d794..ba5ec3d 100644 --- a/src/XpongeCPP/qm/scheduler.py +++ b/src/XpongeCPP/qm/scheduler.py @@ -2,7 +2,7 @@ from __future__ import annotations -import sys +from importlib.util import find_spec from .backends import psi4_backend, pyscf_backend from ._esp_memory import normalize_chunk_policy, normalize_safety_factor, parse_memory_limit_bytes @@ -31,10 +31,21 @@ }) +def _backend_available(backend_name): + try: + return find_spec(backend_name) is not None + except (ImportError, ValueError): + return False + + def default_backend_name(): - if sys.platform.startswith("win"): - return "psi4" - return "pyscf" + for backend_name in ("pyscf", "psi4"): + if _backend_available(backend_name): + return backend_name + raise QMBackendImportError( + "Neither PySCF nor Psi4 is installed; quantum chemistry features are " + "unavailable. Install PySCF (preferred) or Psi4 before retrying." + ) def normalize_backend_name(backend): @@ -49,10 +60,8 @@ def normalize_backend_name(backend): def backend_import_or_hint(backend_name, exc): message = str(exc) - if backend_name == "pyscf" and sys.platform.startswith("win"): - message += " On Windows, install Psi4 via conda-forge or the official Psi4 installer and call calculate_charge('resp', backend='psi4', ...)." - elif backend_name == "psi4": - message += " On Windows, Psi4 is not installed through pip by default; install it via conda-forge or the official Psi4 installer and retry." + if backend_name == "psi4": + message += " Install Psi4 via conda-forge or the official Psi4 installer and retry." raise QMBackendImportError(message) from exc diff --git a/src/XpongeCPP/scientific_manifest.py b/src/XpongeCPP/scientific_manifest.py new file mode 100644 index 0000000..0921e29 --- /dev/null +++ b/src/XpongeCPP/scientific_manifest.py @@ -0,0 +1,722 @@ +"""Provider-neutral scientific manifests for SPONGE input cases. + +The manifest intentionally describes parsed scientific state instead of file +bytes. It is therefore suitable for comparing SPONGE input generated by +Xponge-origin and XpongeCPP even when harmless formatting differs. +""" + +from __future__ import annotations + +import hashlib +import json +from pathlib import Path +from typing import Any + +import numpy as np + +from ._core import load_coordinate +from .io_bundle import convert_bundle_to_legacy, scan_legacy_case +from .io_bundle.contracts import contracts_by_legacy_key +from .io_bundle.legacy_case import LegacyCase +from .io_bundle.topology_parsers import parse_topology_file + + +SCHEMA = "xponge.scientific_manifest" +SCHEMA_VERSION = 1 + +_TEXT_KEYS = { + "atom_name_in_file": "/atoms/name", + "atom_type_name_in_file": "/atoms/type_name", + "resname_in_file": "/residues/name", +} + + +def _sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def _json_array(value: np.ndarray) -> dict[str, Any]: + array = np.asarray(value) + return { + "dtype": str(array.dtype), + "shape": list(array.shape), + "values": array.tolist(), + } + + +def _read_counted_text(path: Path) -> list[str]: + lines = path.read_text(encoding="utf-8").splitlines() + if not lines: + return [] + try: + count = int(lines[0].strip()) + except ValueError: + return lines + values = lines[1:] + if len(values) != count: + raise ValueError( + f"{path} declares {count} text records but contains {len(values)}" + ) + return values + + +def _find_mdin(root: Path, mdin: str | Path | None) -> Path | None: + if mdin is not None: + path = Path(mdin) + if not path.is_absolute(): + path = root / path + if not path.is_file(): + raise FileNotFoundError(f"SPONGE mdin does not exist: {path}") + return path + candidates = sorted(root.glob("mdin*.toml")) + if not candidates: + return None + if len(candidates) != 1: + raise ValueError( + f"expected one mdin*.toml in {root}, found {len(candidates)}" + ) + return candidates[0] + + +def _materialize_raw_case( + root: Path, + *, + mdin: str | Path | None, + temporary_root: Path | None, +) -> tuple[Path, Path | None]: + topology_h5 = root / "topology.spgp.h5" + if not topology_h5.is_file(): + return root, _find_mdin(root, mdin) + if temporary_root is None: + raise ValueError( + "temporary_root is required when building a manifest from a bundle" + ) + prefix = str(root.name or "system") + converted = temporary_root / "legacy" + result = convert_bundle_to_legacy(root, converted, prefix=prefix) + return converted, Path(result.generated_mdin) + + +def _set_string_dataset( + datasets: dict[str, dict[str, Any]], + path: str, + values: list[str], +) -> None: + datasets[path] = { + "dtype": "string", + "shape": [len(values)], + "values": values, + } + + +def _canonicalize_interactions( + datasets: dict[str, dict[str, Any]], + atom_map: np.ndarray, + *, + stem: str, + atom_arity: int, + parameter_names: tuple[str, ...], + reversible: bool, +) -> None: + atom_path = f"/forcefield/{stem}/atoms" + if atom_path not in datasets: + return + parameter_paths = tuple( + f"/forcefield/{stem}/{name}" for name in parameter_names + ) + if any(path not in datasets for path in parameter_paths): + return + atoms = np.asarray(datasets[atom_path]["values"], dtype=np.int64) + if atoms.ndim != 2 or atoms.shape[1] != atom_arity: + return + mapped_atoms = atom_map[atoms] + parameters = [ + np.asarray(datasets[path]["values"]) for path in parameter_paths + ] + records: list[tuple[Any, ...]] = [] + for index, raw_atoms in enumerate(mapped_atoms): + atom_tuple = tuple(int(value) for value in raw_atoms) + if reversible: + atom_tuple = min(atom_tuple, atom_tuple[::-1]) + records.append(( + atom_tuple, + *(parameter[index].tolist() for parameter in parameters), + )) + order = sorted(range(len(records)), key=records.__getitem__) + datasets[atom_path] = _json_array(np.asarray( + [records[index][0] for index in order], + dtype=np.int32, + )) + for offset, path in enumerate(parameter_paths, start=1): + datasets[path] = _json_array(np.asarray([ + records[index][offset] for index in order + ])) + + +def _canonicalize_lj_types( + datasets: dict[str, dict[str, Any]], + atom_order: np.ndarray, +) -> None: + type_path = "/forcefield/lj/type" + count_path = "/forcefield/lj/atom_type_count" + atom_type_path = "/atoms/type_name" + pair_a_path = "/forcefield/lj/pair_A_12" + pair_b_path = "/forcefield/lj/pair_B_6" + required = ( + type_path, + count_path, + atom_type_path, + pair_a_path, + pair_b_path, + ) + if any(path not in datasets for path in required): + return + raw_ids = np.asarray(datasets[type_path]["values"], dtype=np.int64) + atom_type_names = list(datasets[atom_type_path]["values"]) + type_count = int(np.asarray( + datasets[count_path]["values"], + ).reshape(())) + if ( + raw_ids.shape != (len(atom_type_names),) + or type_count <= 0 + or np.any(raw_ids < 0) + or np.any(raw_ids >= type_count) + ): + return + labels: list[tuple[str, ...]] = [] + for type_id in range(type_count): + names = sorted({ + str(atom_type_names[index]) + for index in np.flatnonzero(raw_ids == type_id) + }) + labels.append(tuple(names) if names else (f"",)) + canonical_old_ids = sorted(range(type_count), key=labels.__getitem__) + old_to_new = np.empty(type_count, dtype=np.int32) + for new_id, old_id in enumerate(canonical_old_ids): + old_to_new[old_id] = new_id + datasets[type_path] = _json_array(old_to_new[raw_ids[atom_order]]) + + def reorder_pairs(path: str) -> None: + flat = np.asarray(datasets[path]["values"]) + if flat.size != type_count * (type_count + 1) // 2: + return + matrix = np.zeros((type_count, type_count), dtype=flat.dtype) + cursor = 0 + for first in range(type_count): + for second in range(first + 1): + matrix[first, second] = flat[cursor] + matrix[second, first] = flat[cursor] + cursor += 1 + reordered: list[Any] = [] + for first in canonical_old_ids: + first_new = int(old_to_new[first]) + for second_new in range(first_new + 1): + second = canonical_old_ids[second_new] + reordered.append(matrix[first, second]) + datasets[path] = _json_array(np.asarray(reordered, dtype=flat.dtype)) + + reorder_pairs(pair_a_path) + reorder_pairs(pair_b_path) + + +def _canonicalize_exclusions( + datasets: dict[str, dict[str, Any]], + atom_order: np.ndarray, + atom_map: np.ndarray, +) -> None: + offset_path = "/topology/exclusions/offset" + list_path = "/topology/exclusions/list" + if offset_path not in datasets or list_path not in datasets: + return + offsets = np.asarray(datasets[offset_path]["values"], dtype=np.int64) + excluded = np.asarray(datasets[list_path]["values"], dtype=np.int64) + if offsets.shape != (len(atom_order) + 1,): + return + pairs: set[tuple[int, int]] = set() + for old_atom in range(len(atom_order)): + mapped_atom = int(atom_map[old_atom]) + values = atom_map[excluded[offsets[old_atom]:offsets[old_atom + 1]]] + for mapped_excluded in values: + pair = tuple(sorted((mapped_atom, int(mapped_excluded)))) + if pair[0] != pair[1]: + pairs.add(pair) + del datasets[offset_path] + del datasets[list_path] + datasets["/topology/exclusions/pairs"] = _json_array( + np.asarray(sorted(pairs), dtype=np.int32).reshape(-1, 2) + ) + + +def _canonicalize_atom_order( + datasets: dict[str, dict[str, Any]], +) -> None: + """Make atom-indexed state independent of provider insertion order.""" + + name_path = "/atoms/name" + residue_path = "/atoms/residue_index" + if name_path not in datasets or residue_path not in datasets: + return + names = [str(value) for value in datasets[name_path]["values"]] + residue_indices = np.asarray( + datasets[residue_path]["values"], + dtype=np.int64, + ) + if residue_indices.shape != (len(names),): + return + keys = [ + (int(residue_indices[index]), names[index]) + for index in range(len(names)) + ] + if len(set(keys)) != len(keys): + return + atom_order = np.asarray(sorted( + range(len(keys)), + key=keys.__getitem__, + ), dtype=np.int64) + atom_map = np.empty(len(atom_order), dtype=np.int32) + atom_map[atom_order] = np.arange(len(atom_order), dtype=np.int32) + + atom_paths = ( + "/atoms/charge", + "/atoms/mass", + "/atoms/residue_index", + "/atoms/type_name", + "/restart/position", + ) + _canonicalize_lj_types(datasets, atom_order) + for path in atom_paths: + if path not in datasets: + continue + if path == "/atoms/type_name": + values = [str(value) for value in datasets[path]["values"]] + _set_string_dataset( + datasets, + path, + [values[index] for index in atom_order], + ) + continue + values = np.asarray(datasets[path]["values"]) + if values.shape and values.shape[0] == len(atom_order): + datasets[path] = _json_array(values[atom_order]) + _set_string_dataset( + datasets, + name_path, + [names[index] for index in atom_order], + ) + + _canonicalize_interactions( + datasets, + atom_map, + stem="bond", + atom_arity=2, + parameter_names=("k", "r0"), + reversible=True, + ) + _canonicalize_interactions( + datasets, + atom_map, + stem="angle", + atom_arity=3, + parameter_names=("k", "theta0"), + reversible=True, + ) + _canonicalize_interactions( + datasets, + atom_map, + stem="nb14", + atom_arity=2, + parameter_names=("params",), + reversible=True, + ) + dihedral_path = "/forcefield/dihedral/atoms" + if dihedral_path in datasets: + atoms = np.asarray( + datasets[dihedral_path]["values"], + dtype=np.int64, + ) + datasets[dihedral_path] = _json_array(atom_map[atoms]) + _canonicalize_exclusions(datasets, atom_order, atom_map) + + +def _canonicalize_dihedrals( + datasets: dict[str, dict[str, Any]], +) -> None: + atom_path = "/forcefield/dihedral/atoms" + if atom_path not in datasets: + return + parameter_paths = ( + "/forcefield/dihedral/periodicity", + "/forcefield/dihedral/k", + "/forcefield/dihedral/phi0", + ) + if any(path not in datasets for path in parameter_paths): + return + bond_atoms = np.asarray( + datasets.get("/forcefield/bond/atoms", {}).get("values", []), + dtype=np.int64, + ) + bond_pairs = { + frozenset((int(atom1), int(atom2))) for atom1, atom2 in bond_atoms + } + atoms = np.asarray(datasets[atom_path]["values"], dtype=np.int64) + parameters = [ + np.asarray(datasets[path]["values"]) for path in parameter_paths + ] + records = [] + kinds = [] + for index, raw_atoms in enumerate(atoms): + atom_tuple = tuple(int(value) for value in raw_atoms) + centers = [ + atom + for atom in atom_tuple + if all( + other == atom or frozenset((atom, other)) in bond_pairs + for other in atom_tuple + ) + ] + if len(centers) == 1: + center = centers[0] + outer = sorted(atom for atom in atom_tuple if atom != center) + canonical_atoms = (outer[0], outer[1], center, outer[2]) + kind = "improper" + else: + reverse = atom_tuple[::-1] + canonical_atoms = min(atom_tuple, reverse) + kind = "proper" + record = ( + canonical_atoms, + *(parameter[index].item() for parameter in parameters), + ) + records.append(record) + kinds.append(kind) + order = sorted(range(len(records)), key=records.__getitem__) + datasets[atom_path] = _json_array( + np.asarray([records[index][0] for index in order], dtype=np.int32) + ) + for offset, path in enumerate(parameter_paths, start=1): + datasets[path] = _json_array( + np.asarray([records[index][offset] for index in order]) + ) + ordered_kinds = [kinds[index] for index in order] + datasets["/forcefield/dihedral/kind"] = { + "dtype": "string", + "shape": [len(ordered_kinds)], + "values": ordered_kinds, + } + + +def _canonicalize_cmaps( + datasets: dict[str, dict[str, Any]], +) -> None: + """Canonicalize CMAP tables independently of provider type numbering. + + SPONGE CMAP type identifiers are local indices into the grids written in + ``system_cmap.txt``. Xponge-origin numbers them by first topology use, + whereas XpongeCPP retains force-field declaration order. Moreover, + multiple chemical CMAP types can share an identical numerical grid. The + numerical grid is the complete scientific identity available in SPONGE + input, so manifests deduplicate and sort by that identity before remapping + interaction records. + """ + + atom_path = "/forcefield/cmap/atoms" + type_path = "/forcefield/cmap/type" + resolution_path = "/forcefield/cmap/resolution" + grid_path = "/forcefield/cmap/grid_value" + required = (atom_path, type_path, resolution_path, grid_path) + if any(path not in datasets for path in required): + return + + atoms = np.asarray(datasets[atom_path]["values"], dtype=np.int64) + raw_types = np.asarray(datasets[type_path]["values"], dtype=np.int64) + resolutions = np.asarray( + datasets[resolution_path]["values"], dtype=np.int64 + ) + grid_values = np.asarray(datasets[grid_path]["values"]) + if ( + atoms.ndim != 2 + or atoms.shape[1] != 5 + or raw_types.shape != (atoms.shape[0],) + or np.any(resolutions <= 0) + or np.any(raw_types < 0) + or np.any(raw_types >= len(resolutions)) + ): + return + + signatures: list[tuple[int, tuple[Any, ...]]] = [] + cursor = 0 + for resolution in resolutions: + size = int(resolution) ** 2 + block = grid_values[cursor:cursor + size] + if block.size != size: + return + signatures.append(( + int(resolution), + tuple(block.tolist()), + )) + cursor += size + if cursor != grid_values.size: + return + + canonical_signatures = sorted(set(signatures)) + signature_to_type = { + signature: index + for index, signature in enumerate(canonical_signatures) + } + remapped_types = np.asarray( + [signature_to_type[signatures[int(type_id)]] for type_id in raw_types], + dtype=np.int32, + ) + records = [ + (tuple(int(value) for value in atoms[index]), int(remapped_types[index])) + for index in range(len(atoms)) + ] + order = sorted(range(len(records)), key=records.__getitem__) + datasets[atom_path] = _json_array(np.asarray( + [records[index][0] for index in order], dtype=np.int32 + )) + datasets[type_path] = _json_array(np.asarray( + [records[index][1] for index in order], dtype=np.int32 + )) + datasets[resolution_path] = _json_array(np.asarray( + [signature[0] for signature in canonical_signatures], dtype=np.int32 + )) + canonical_grid = [ + value + for _, values in canonical_signatures + for value in values + ] + datasets[grid_path] = _json_array(np.asarray( + canonical_grid, dtype=grid_values.dtype + )) + + +def _scan_case(root: Path, mdin_path: Path | None) -> LegacyCase: + if mdin_path is not None: + return scan_legacy_case(root, mdin_path) + coordinate_files = sorted(root.glob("*_coordinate.txt")) + if len(coordinate_files) != 1: + raise ValueError( + f"cannot infer SPONGE prefix in {root}: expected one " + f"*_coordinate.txt, found {len(coordinate_files)}" + ) + coordinate_suffix = "_coordinate.txt" + prefix = str(coordinate_files[0])[: -len(coordinate_suffix)] + return LegacyCase( + root=root, + mdin_path=root / "", + mdin_text="", + commands={"default_in_file_prefix": prefix}, + ) + + +def build_scientific_manifest( + case_root: str | Path, + *, + mdin: str | Path | None = None, + case_id: str | None = None, + metadata: dict[str, Any] | None = None, + temporary_root: str | Path | None = None, +) -> dict[str, Any]: + """Parse a raw or bundled SPONGE input case into a stable JSON manifest.""" + + root = Path(case_root).resolve() + temporary = ( + Path(temporary_root).resolve() if temporary_root is not None else None + ) + raw_root, mdin_path = _materialize_raw_case( + root, + mdin=mdin, + temporary_root=temporary, + ) + case = _scan_case(raw_root, mdin_path) + datasets: dict[str, dict[str, Any]] = {} + files: dict[str, dict[str, Any]] = {} + + coordinate_path = case.resolve_legacy_input_path("coordinate_in_file") + if coordinate_path is not None and coordinate_path.is_file(): + coordinate, box = load_coordinate(str(coordinate_path)) + datasets["/restart/position"] = _json_array( + np.asarray(coordinate, dtype=np.float64) + ) + datasets["/restart/box"] = _json_array( + np.asarray(box, dtype=np.float64) + ) + + input_keys = { + key for key in case.commands if key.endswith("_in_file") + } | { + key for key in contracts_by_legacy_key() if key.endswith("_in_file") + } | set(_TEXT_KEYS) + for key in sorted(input_keys): + if not key.endswith("_in_file"): + continue + path = case.resolve_legacy_input_path(key) + if path is None or not path.is_file(): + continue + files[key] = { + "name": path.name, + "sha256": _sha256(path), + "size": path.stat().st_size, + } + text_path = _TEXT_KEYS.get(key) + if text_path is not None: + values = _read_counted_text(path) + datasets[text_path] = { + "dtype": "string", + "shape": [len(values)], + "values": values, + } + continue + parsed = parse_topology_file(key, path) + if parsed is None: + continue + for dataset in parsed: + if dataset.path in datasets: + raise ValueError(f"duplicate scientific dataset: {dataset.path}") + datasets[dataset.path] = _json_array(dataset.data) + + _canonicalize_atom_order(datasets) + _canonicalize_dihedrals(datasets) + _canonicalize_cmaps(datasets) + return { + "schema": SCHEMA, + "schema_version": SCHEMA_VERSION, + "case_id": case_id or root.name, + "metadata": dict(metadata or {}), + "source": { + "root": str(root), + "mdin": mdin_path.name if mdin_path is not None else None, + "mdin_sha256": _sha256(mdin_path) if mdin_path is not None else None, + }, + "datasets": dict(sorted(datasets.items())), + "files": files, + } + + +def _tolerance(path: str) -> tuple[float, float]: + if path == "/restart/position" or path == "/restart/box": + return 0.0, 1.0e-6 + if path == "/atoms/charge": + return 0.0, 1.0e-8 + return 1.0e-10, 1.0e-12 + + +def compare_scientific_manifests( + reference: dict[str, Any], + candidate: dict[str, Any], +) -> dict[str, Any]: + """Return a compact, machine-readable semantic diff.""" + + issues: list[dict[str, Any]] = [] + if reference.get("schema") != SCHEMA or candidate.get("schema") != SCHEMA: + issues.append({"kind": "schema_mismatch"}) + if reference.get("schema_version") != candidate.get("schema_version"): + issues.append({ + "kind": "schema_version_mismatch", + "reference": reference.get("schema_version"), + "candidate": candidate.get("schema_version"), + }) + + reference_datasets = reference.get("datasets") or {} + candidate_datasets = candidate.get("datasets") or {} + reference_keys = set(reference_datasets) + candidate_keys = set(candidate_datasets) + if reference_keys != candidate_keys: + issues.append({ + "kind": "dataset_set_mismatch", + "missing": sorted(reference_keys - candidate_keys), + "unexpected": sorted(candidate_keys - reference_keys), + }) + + compared = 0 + for path in sorted(reference_keys & candidate_keys): + expected = reference_datasets[path] + actual = candidate_datasets[path] + if expected.get("shape") != actual.get("shape"): + issues.append({ + "kind": "shape_mismatch", + "path": path, + "reference": expected.get("shape"), + "candidate": actual.get("shape"), + }) + continue + expected_dtype = str(expected.get("dtype")) + actual_dtype = str(actual.get("dtype")) + if expected_dtype == "string" or actual_dtype == "string": + if expected_dtype != actual_dtype or expected.get("values") != actual.get("values"): + issues.append({"kind": "exact_value_mismatch", "path": path}) + compared += 1 + continue + expected_values = np.asarray(expected.get("values")) + actual_values = np.asarray(actual.get("values")) + if expected_values.dtype.kind in "iu" or actual_values.dtype.kind in "iu": + if not np.array_equal(expected_values, actual_values): + mismatch = np.flatnonzero( + expected_values.reshape(-1) != actual_values.reshape(-1) + ) + issues.append({ + "kind": "exact_value_mismatch", + "path": path, + "first_index": int(mismatch[0]) if mismatch.size else None, + "count": int(mismatch.size), + }) + else: + rtol, atol = _tolerance(path) + delta = np.abs( + expected_values.astype(np.float64) + - actual_values.astype(np.float64) + ) + allowed = atol + rtol * np.abs(expected_values.astype(np.float64)) + failed = delta > allowed + if np.any(failed): + flat_delta = delta.reshape(-1) + issues.append({ + "kind": "numeric_mismatch", + "path": path, + "rtol": rtol, + "atol": atol, + "count": int(np.count_nonzero(failed)), + "max_abs": float(np.max(flat_delta)), + "rms": float(np.sqrt(np.mean(flat_delta * flat_delta))), + "first_index": int(np.flatnonzero(failed.reshape(-1))[0]), + }) + compared += 1 + + return { + "schema": "xponge.scientific_manifest.diff", + "schema_version": 1, + "ok": not issues, + "reference_case_id": reference.get("case_id"), + "candidate_case_id": candidate.get("case_id"), + "compared_dataset_count": compared, + "issues": issues, + } + + +def write_scientific_manifest( + manifest: dict[str, Any], + path: str | Path, +) -> Path: + """Write a manifest or diff with deterministic JSON formatting.""" + + output = Path(path) + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text( + json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True) + "\n", + encoding="utf-8", + ) + return output + + +__all__ = [ + "SCHEMA", + "SCHEMA_VERSION", + "build_scientific_manifest", + "compare_scientific_manifests", + "write_scientific_manifest", +] diff --git a/src/XpongeCPP/template_ops.py b/src/XpongeCPP/template_ops.py index 41365f5..3fc2912 100644 --- a/src/XpongeCPP/template_ops.py +++ b/src/XpongeCPP/template_ops.py @@ -12,8 +12,8 @@ has_template, load_mol2 as _core_load_mol2, molecule_from_residuetype, - register_residue_templates_from_mol2_file, - register_residue_templates_from_mol2_text, + register_new_residue_templates_from_mol2_file, + register_new_residue_templates_from_mol2_text, reorder_atoms_by_template, replace_residues, ) @@ -24,7 +24,7 @@ def load_mol2(source, ignore_atom_type=False, as_template=False): del ignore_atom_type # First-wave compatibility: current core already tolerates raw MOL2 atom-type strings. if isinstance(source, (str, Path)): try: - register_residue_templates_from_mol2_file(str(source)) + register_new_residue_templates_from_mol2_file(str(source)) sync_template_module_globals() except ValueError as exc: if as_template or "duplicate atom name in ResidueType" not in str(exc): @@ -33,7 +33,7 @@ def load_mol2(source, ignore_atom_type=False, as_template=False): if hasattr(source, "read"): text = source.read() try: - register_residue_templates_from_mol2_text(text) + register_new_residue_templates_from_mol2_text(text) sync_template_module_globals() except ValueError as exc: if as_template or "duplicate atom name in ResidueType" not in str(exc): diff --git a/tests/data/8ryk/spg_init.txt b/tests/data/8ryk/spg_init.txt index a4f3e5c..2e2f025 100644 --- a/tests/data/8ryk/spg_init.txt +++ b/tests/data/8ryk/spg_init.txt @@ -247,53 +247,6 @@ if box_padding is not None: if set_box_padding is None: raise RuntimeError('Xponge set_box_padding 不可用') set_box_padding(padding=box_padding, center=True) -saved_links = None -if hasattr(mol_out, 'residue_links'): - try: - saved_links = list(mol_out.residue_links) - mol_out.residue_links = [] - except Exception: - saved_links = None save_pdb(mol_out, '/media/yuh/BCDC9249DC91FDB8/Data/Mokda-FEP/8RYK/sponge/input.pdb') -if saved_links: - try: - atom_index = getattr(mol_out, 'atom_index', {}) - connect_map = {} - for link in saved_links: - a = getattr(link, 'atom1', None) - b = getattr(link, 'atom2', None) - if a is None or b is None: - continue - idx_a = atom_index.get(a) - idx_b = atom_index.get(b) - if idx_a is None or idx_b is None: - continue - connect_map.setdefault(idx_a, set()).add(idx_b) - connect_map.setdefault(idx_b, set()).add(idx_a) - if connect_map: - pdb_path = '/media/yuh/BCDC9249DC91FDB8/Data/Mokda-FEP/8RYK/sponge/input.pdb' - with open(pdb_path, 'r', encoding='utf-8', errors='ignore') as handle: - lines = handle.read().splitlines() - end_line = None - if lines and lines[-1].startswith('END'): - end_line = lines.pop() - conect_lines = [] - for idx in sorted(connect_map.keys()): - targets = sorted(connect_map[idx]) - for chunk_start in range(0, len(targets), 4): - chunk = targets[chunk_start:chunk_start + 4] - conect_lines.append('CONECT' + f"{idx + 1:5d}" + ''.join([f"{j + 1:5d}" for j in chunk])) - lines.extend(conect_lines) - if end_line: - lines.append(end_line) - with open(pdb_path, 'w', encoding='utf-8') as handle: - handle.write('\n'.join(lines) + '\n') - except Exception: - pass if not only_pdb: - if saved_links is not None: - try: - mol_out.residue_links = saved_links - except Exception: - pass - save_input(mol_out, '/media/yuh/BCDC9249DC91FDB8/Data/Mokda-FEP/8RYK/sponge/input') \ No newline at end of file + save_input(mol_out, '/media/yuh/BCDC9249DC91FDB8/Data/Mokda-FEP/8RYK/sponge/input') diff --git a/tests/origin_test_metal_assignment_apply.py b/tests/origin_test_metal_assignment_apply.py index 2fd3108..e507a7c 100644 --- a/tests/origin_test_metal_assignment_apply.py +++ b/tests/origin_test_metal_assignment_apply.py @@ -5,6 +5,7 @@ from uuid import uuid4 import XpongeCPP.forcefield.amber # noqa: F401 - register native force types +from XpongeCPP import register_residue_templates_from_mol2_text from XpongeCPP.forcefield.base.lj_base import LJType from XpongeCPP.helper import AtomType, Molecule, ResidueType from XpongeCPP.metal_assignment import ( @@ -79,6 +80,57 @@ def _ordinary_molecule(patch): class MetalAssignmentApplyTests(unittest.TestCase): + def test_prepare_residue_templates_materializes_registered_template(self): + patch = _local_patch() + residue_name = f"PATCH_STATIC_{uuid4().hex[:8]}" + register_residue_templates_from_mol2_text( + "\n".join(( + "@MOLECULE", + residue_name, + "2 1 1", + "SMALL", + "USER_CHARGES", + "@ATOM", + f"1 C1 0.0 0.0 0.0 C 1 {residue_name} -0.1", + f"2 C2 1.4 0.0 0.0 C 1 {residue_name} 0.1", + "@BOND", + "1 1 2 1", + "", + )) + ) + residue_type = ResidueType.get_type(residue_name) + metal_id = patch.target_metal_atom_ids[0] + metal_identity = next( + atom for atom in patch.atoms + if atom.external_id == metal_id + ) + + report = prepare_residue_templates(patch, [{ + "external_id": metal_id, + "residue_name": residue_name, + "atom_name": metal_identity.atom_name, + }]) + + self.assertEqual(report["prepared_atom_ids"], (metal_id,)) + self.assertEqual( + {atom.name for atom in ResidueType.get_type(residue_name).atoms}, + {"C1", "C2", metal_identity.atom_name}, + ) + prepared_metal = ResidueType.get_type(residue_name).name2atom( + metal_identity.atom_name + ) + self.assertEqual(prepared_metal.element, metal_identity.element) + self.assertAlmostEqual( + prepared_metal.mass, + patch.parameterization_result.metal_overlay.masses[metal_id], + ) + repeated = prepare_residue_templates(patch, [{ + "external_id": metal_id, + "residue_name": residue_name, + "atom_name": metal_identity.atom_name, + }]) + self.assertEqual(repeated["prepared_atom_ids"], ()) + def test_prepare_residue_templates_adds_only_missing_embedded_metal(self): patch = _local_patch() residue_name = f"PATCH_EMBEDDED_{uuid4().hex[:8]}" @@ -155,6 +207,22 @@ def test_hash_closed_patch_applies_to_an_existing_molecule(self): patch.parameterization_result.metal_overlay.masses[metal_id], ) + def test_apply_accepts_equivalent_native_atom_handles(self): + patch = _local_patch() + molecule, _mapping = _ordinary_molecule(patch) + mapping = { + identity.external_id: atom + for identity, atom in zip( + patch.atoms, + molecule.residues[0].atoms, + ) + } + + output = apply(molecule, patch, mapping) + + self.assertEqual(output.application_report["patch_hash"], patch.patch_hash) + self.assertTrue(output.application_report["topology_preserved"]) + def test_identity_mismatch_is_rejected_without_mutating_the_input(self): patch = _local_patch() molecule, mapping = _ordinary_molecule(patch) diff --git a/tests/test_8ryk_manual_frcmod.py b/tests/test_8ryk_manual_frcmod.py index 5908cf1..fd1cc18 100644 --- a/tests/test_8ryk_manual_frcmod.py +++ b/tests/test_8ryk_manual_frcmod.py @@ -126,3 +126,5 @@ def test_xpongecpp_matches_manual_8ryk_script_contract(tmp_path): frcmod_text = raw_frcmod.read_text() assert "MASS" in frcmod_text assert "NONBON" in frcmod_text + bond_section = frcmod_text.split("BOND", 1)[1].split("ANGLE", 1)[0] + assert bond_section.strip(), "mixed standard/GAFF boundary bonds must reach parmchk2" diff --git a/tests/test_assign_charge_models.py b/tests/test_assign_charge_models.py index d9f01cf..599ca71 100644 --- a/tests/test_assign_charge_models.py +++ b/tests/test_assign_charge_models.py @@ -197,10 +197,22 @@ def fake_import(name, *args, **kwargs): assignment.calculate_charge("resp") -def test_resp_defaults_to_platform_backend(monkeypatch): +@pytest.mark.parametrize( + ("available_backends", "expected_backend"), + [ + ({"pyscf", "psi4"}, "pyscf"), + ({"psi4"}, "psi4"), + ], +) +def test_resp_defaults_to_available_backend(monkeypatch, available_backends, expected_backend): assignment = _assignment("water", ["O", "H", "H"], [(0, 1, 1), (0, 2, 1)]) calls = [] - default_backend = qm_scheduler.normalize_backend_name(None) + + monkeypatch.setattr( + qm_scheduler, + "find_spec", + lambda name: object() if name in available_backends else None, + ) class FakeBackend: @staticmethod @@ -220,7 +232,7 @@ def compute_esp_on_grid(payload, grids, *, memory_limit=None, chunk_policy="auto calls.append(("esp", len(grids), memory_limit, chunk_policy, safety_factor)) return np.zeros(len(grids)) - monkeypatch.setitem(resp_module._BACKEND_MODULES, default_backend, FakeBackend) + monkeypatch.setitem(resp_module._BACKEND_MODULES, expected_backend, FakeBackend) monkeypatch.setattr(resp_module.resp_core, "get_mk_grid", lambda *args, **kwargs: __import__("numpy").zeros((2, 3))) monkeypatch.setattr(resp_module.resp_core, "fit_resp_from_esp", lambda *args, **kwargs: [0.0, 0.0, 0.0]) @@ -327,7 +339,7 @@ def test_resp_rejects_unknown_core(): resp_module.resp_fit(assignment, core="unknown") -def test_resp_windows_hint_mentions_psi4(monkeypatch): +def test_resp_pyscf_import_error_is_not_platform_specific(monkeypatch): assignment = _assignment("water", ["O", "H", "H"], [(0, 1, 1), (0, 2, 1)]) class FailingBackend: @@ -336,9 +348,7 @@ def build_backend_payload(assign, basis, charge, spin, opt): raise ImportError("PySCF is required for RESP charge calculation") monkeypatch.setitem(resp_module._BACKEND_MODULES, "pyscf", FailingBackend) - monkeypatch.setattr(resp_module.sys, "platform", "win32") - - with pytest.raises(ImportError, match="install Psi4"): + with pytest.raises(ImportError, match="PySCF is required"): resp_module.resp_fit(assignment, backend="pyscf") @@ -356,9 +366,7 @@ def build_backend_payload(assign, basis, charge, spin, opt): resp_module.resp_fit(assignment, backend="psi4") -def test_qm_scheduler_windows_psi4_hint_mentions_external_install(monkeypatch): - monkeypatch.setattr(qm_scheduler.sys, "platform", "win32") - +def test_qm_scheduler_psi4_hint_mentions_external_install(): with pytest.raises(ImportError, match="official Psi4 installer"): qm_scheduler.backend_import_or_hint("psi4", ImportError("Psi4 is required")) @@ -370,16 +378,32 @@ def test_qm_scheduler_exposes_known_backends(): qm_get_backend("unknown") -def test_qm_scheduler_default_backend_matches_platform(monkeypatch): - monkeypatch.setattr(qm_scheduler.sys, "platform", "linux") +def test_qm_scheduler_default_backend_prefers_pyscf(monkeypatch): + monkeypatch.setattr(qm_scheduler, "find_spec", lambda name: object()) assert qm_scheduler.normalize_backend_name(None) == "pyscf" assert qm_get_backend(None).name == "pyscf" - monkeypatch.setattr(qm_scheduler.sys, "platform", "win32") + +def test_qm_scheduler_default_backend_falls_back_to_psi4(monkeypatch): + monkeypatch.setattr( + qm_scheduler, + "find_spec", + lambda name: object() if name == "psi4" else None, + ) assert qm_scheduler.normalize_backend_name(None) == "psi4" assert qm_get_backend(None).name == "psi4" +def test_qm_scheduler_default_backend_errors_when_none_installed(monkeypatch): + monkeypatch.setattr(qm_scheduler, "find_spec", lambda name: None) + + with pytest.raises( + qm_scheduler.QMBackendImportError, + match="Neither PySCF nor Psi4 is installed", + ): + qm_scheduler.normalize_backend_name(None) + + def test_qm_scheduler_runs_pyscf_scf_and_esp_smoke(): assignment = Xponge.get_assignment_from_mol2(str(FORMAMIDE_RESP_MOL2), total_charge="sum") scf_result = qm_run_scf( @@ -1025,12 +1049,12 @@ def test_save_as_mol2_atomtype_argument_and_equal_atoms_api(tmp_path): assert any(set(group) == {0, 1} for group in groups) -def test_resp_uses_pyscf_backend_or_reports_missing_dependency(): +def test_resp_uses_available_backend_or_reports_missing_dependency(): water = _assignment("water", ["O", "H", "H"], [(0, 1, 1), (0, 2, 1)]) try: water.calculate_charge("resp", basis="sto-3g", charge=0, grid_density=1, grid_cell_layer=1, only_esp=True) except ImportError as exc: - assert "PySCF" in str(exc) + assert "PySCF" in str(exc) or "Psi4" in str(exc) return assert len(water.charges) == 3 assert math.isclose(sum(water.charges), 0.0, abs_tol=1e-5) diff --git a/tests/test_assign_gaff_parity.py b/tests/test_assign_gaff_parity.py index 84ea46f..72c4d7c 100644 --- a/tests/test_assign_gaff_parity.py +++ b/tests/test_assign_gaff_parity.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import site import subprocess import sys from base64 import b64encode @@ -39,7 +40,7 @@ def _assignment_from_smiles_with_3d(smiles: str): def _origin_reference_types_from_smiles(smiles: str, rule: str, indices: list[int]) -> list[str]: if not ORIGIN_REPO.exists(): pytest.skip("local Xponge-origin repo not available") - env_site_packages = Path(sys.executable).resolve().parent.parent / "lib" / f"python{sys.version_info.major}.{sys.version_info.minor}" / "site-packages" + env_site_packages = Path(site.getsitepackages()[0]) script = dedent( f""" import json, sys @@ -49,8 +50,7 @@ def _origin_reference_types_from_smiles(smiles: str, rule: str, indices: list[in from rdkit.Chem import AllChem import Xponge from Xponge.helper.rdkit import rdmol_to_assign - import Xponge.forcefield.amber.gaff - import Xponge.forcefield.amber.gaff2 + import Xponge.forcefield.amber.{rule} mol = Chem.MolFromSmiles({smiles!r}) mol = Chem.AddHs(mol) params = AllChem.ETKDGv3() @@ -74,12 +74,7 @@ def _origin_reference_types_from_smiles(smiles: str, rule: str, indices: list[in def _origin_reference_types_from_mol2_text(mol2_text: str, rule: str, indices: list[int]) -> list[str]: if not ORIGIN_REPO.exists(): pytest.skip("local Xponge-origin repo not available") - env_site_packages = ( - Path(sys.executable).resolve().parent.parent - / "lib" - / f"python{sys.version_info.major}.{sys.version_info.minor}" - / "site-packages" - ) + env_site_packages = Path(site.getsitepackages()[0]) encoded = b64encode(mol2_text.encode("utf-8")).decode("ascii") script = dedent( f""" @@ -88,8 +83,7 @@ def _origin_reference_types_from_mol2_text(mol2_text: str, rule: str, indices: l sys.path.insert(0, {str(ORIGIN_REPO)!r}) sys.path.append({str(env_site_packages)!r}) import Xponge - import Xponge.forcefield.amber.gaff - import Xponge.forcefield.amber.gaff2 + import Xponge.forcefield.amber.{rule} text = base64.b64decode({encoded!r}).decode("utf-8") assign = Xponge.get_assignment_from_mol2(StringIO(text)) assign.determine_atom_type({rule!r}) @@ -109,17 +103,11 @@ def test_gaff_cross_family_alternating_regression(): assert _assigned_type_names(assign, [4, 5, 6, 8, 9]) == ["cc", "cc", "cd", "cd", "cf"] -def test_public_get_assignment_from_smiles_supports_gaff_and_gaff2(): - import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 - +@pytest.mark.parametrize("rule", ["gaff", "gaff2"]) +def test_public_get_assignment_from_smiles_supports_gaff_and_gaff2(rule): + __import__(f"XpongeCPP.forcefield.amber.{rule}") assign = Xponge.get_assignment_from_smiles("c1ccccc1") - assign.determine_atom_type("gaff") - assert _assigned_type_names(assign, list(range(6))) == ["ca"] * 6 - assert _assigned_type_names(assign, list(range(6, 12))) == ["ha"] * 6 - - assign = Xponge.get_assignment_from_smiles("c1ccccc1") - assign.determine_atom_type("gaff2") + assign.determine_atom_type(rule) assert _assigned_type_names(assign, list(range(6))) == ["ca"] * 6 assert _assigned_type_names(assign, list(range(6, 12))) == ["ha"] * 6 @@ -182,7 +170,6 @@ def test_gaff2_atom_type_determination(): def test_gaff_assignment_state_and_residuetype_regression(): import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 mol2_text = dedent( """ @@ -317,62 +304,41 @@ def test_gaff_assignment_state_and_residuetype_regression(): assert [str(atom.type) for atom in restype.atoms[13:17]] == ["cc", "cd", "cd", "cc"] -def test_gaff_cp_cq_pure_aromatic_regression(): - import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 - +@pytest.mark.parametrize("rule", ["gaff", "gaff2"]) +def test_gaff_cp_cq_pure_aromatic_regression(rule): + __import__(f"XpongeCPP.forcefield.amber.{rule}") smiles = "c1ccc(-c2nc(-c3ccccc3)c(-c3ccccc3)nc2-c2ccccc2)cc1" expected = ["cp", "cp", "cp", "cp", "cp", "cp", "cq", "cq"] assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff") - assert _assigned_type_names(assign, [3, 4, 6, 7, 13, 14, 21, 22]) == expected - - assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff2") + assign.determine_atom_type(rule) assert _assigned_type_names(assign, [3, 4, 6, 7, 13, 14, 21, 22]) == expected -def test_gaff_nitroso_ne_regression(): - import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 - +@pytest.mark.parametrize("rule", ["gaff", "gaff2"]) +def test_gaff_nitroso_ne_regression(rule): + __import__(f"XpongeCPP.forcefield.amber.{rule}") smiles = "CN(C)S(=O)(=O)c1cc2c(N=O)c(O)[nH]c2c2c1CCCC2" assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff") - assert str(assign.atom_types[10]) == "ne" - - assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff2") + assign.determine_atom_type(rule) assert str(assign.atom_types[10]) == "ne" -def test_gaff_nitroso_sequence_sensitive_n2_regression(): - import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 - +@pytest.mark.parametrize("rule", ["gaff", "gaff2"]) +def test_gaff_nitroso_sequence_sensitive_n2_regression(rule): + __import__(f"XpongeCPP.forcefield.amber.{rule}") smiles = "O=Nc1c(O)[nH]c2c3c(c([N+](=O)[O-])cc12)CCCC3" assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff") - assert str(assign.atom_types[1]) == "n2" - - assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff2") + assign.determine_atom_type(rule) assert str(assign.atom_types[1]) == "n2" -def test_gaff_carbonyl_ring_c_regression(): - import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 - +@pytest.mark.parametrize("rule", ["gaff", "gaff2"]) +def test_gaff_carbonyl_ring_c_regression(rule): + __import__(f"XpongeCPP.forcefield.amber.{rule}") smiles = "Cc1noc2c(-c3ccccc3)nn(CCCN3CCN(c4cccc(Cl)c4)CC3)c(=O)c12" assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff") - assert str(assign.atom_types[30]) == "c" - assert str(assign.atom_types[32]) == "cc" - - assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff2") + assign.determine_atom_type(rule) assert str(assign.atom_types[30]) == "c" assert str(assign.atom_types[32]) == "cc" @@ -612,10 +578,9 @@ def test_gaff2_sulfoxide_s4_regression(): assert str(assign.atom_types[3]) == "ca" -def test_gaff_macrocycle_matches_origin_reference(): - import XpongeCPP.forcefield.amber.gaff # noqa: F401 - import XpongeCPP.forcefield.amber.gaff2 # noqa: F401 - +@pytest.mark.parametrize("rule", ["gaff", "gaff2"]) +def test_gaff_macrocycle_matches_origin_reference(rule): + __import__(f"XpongeCPP.forcefield.amber.{rule}") smiles = ( "C=CC1=C(C)c2cc3nc(cc4[nH]c(cc5[nH]c(cc1n2)c(C)c5CCC(=O)NC1C(O)OC(CO)C(O)C1O)" "c(CCC(=O)NC1C(O)OC(CO)C(O)C1O)c4C)C(C=C)=C3C" @@ -623,12 +588,8 @@ def test_gaff_macrocycle_matches_origin_reference(): indices = [6, 8, 10, 14, 18, 20, 21, 23, 40, 57] assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff") - assert _assigned_type_names(assign, indices) == _origin_reference_types_from_smiles(smiles, "gaff", indices) - - assign = _assignment_from_smiles_with_3d(smiles) - assign.determine_atom_type("gaff2") - assert _assigned_type_names(assign, indices) == _origin_reference_types_from_smiles(smiles, "gaff2", indices) + assign.determine_atom_type(rule) + assert _assigned_type_names(assign, indices) == _origin_reference_types_from_smiles(smiles, rule, indices) @pytest.mark.parametrize( diff --git a/tests/test_b96_mol2_gaff.py b/tests/test_b96_mol2_gaff.py index dfae155..ed0dbf3 100644 --- a/tests/test_b96_mol2_gaff.py +++ b/tests/test_b96_mol2_gaff.py @@ -23,10 +23,11 @@ def _write_xpongecpp_b96(dirname): import json import XpongeCPP as Xponge import XpongeCPP.forcefield.amber.gaff # noqa: F401 + from XpongeCPP.forcefield import amber out = Path({str(dirname)!r}) out.mkdir(parents=True, exist_ok=True) - Xponge.load_frcmod({str(B96_FRCMOD)!r}) + amber.load_parameters_from_frcmod({str(B96_FRCMOD)!r}, prefix=False) mol = Xponge.load_mol2({str(B96_MOL2)!r}) Xponge.Save_SPONGE_Input(mol, prefix="b96", dirname=str(out)) (out / "b96_meta.json").write_text(json.dumps({{ @@ -58,10 +59,11 @@ def _write_xpongecpp_1kv2(dirname, with_solvent=False): import XpongeCPP.forcefield.amber.ff14sb # noqa: F401 import XpongeCPP.forcefield.amber.gaff # noqa: F401 {"import XpongeCPP.forcefield.amber.tip3p # noqa: F401" if with_solvent else ""} + from XpongeCPP.forcefield import amber out = Path({str(dirname)!r}) out.mkdir(parents=True, exist_ok=True) - Xponge.load_frcmod({str(B96_FRCMOD)!r}) + amber.load_parameters_from_frcmod({str(B96_FRCMOD)!r}, prefix=False) protein = Xponge.load_pdb({str(DATA_DIR / "1KV2_H.pdb")!r}) ligand = Xponge.load_mol2({str(B96_MOL2)!r}) Xponge.Add_Molecule(protein, ligand) @@ -269,14 +271,35 @@ def test_b96_h_mol2_gaff_assign_matches_xponge_atom_types(tmp_path): assert assignment.atom_count == 76 assert assignment.bond_count == 80 - assert assignment.atom_types == [ - "c", "o", "n", "ca", "ca", "ca", "ca", "ca", "ca", "ca", "ca", "ca", "ca", "n", - "c2", "c2", "c2", "n2", "na", "ca", "c3", "c3", "c3", "c3", "ca", "ca", "ca", - "ca", "ca", "c3", "os", "c3", "c3", "n3", "c3", "c3", "os", "c3", "c3", "hn", - "ha", "ha", "ha", "ha", "ha", "ha", "hn", "ha", "hc", "hc", "hc", "hc", "hc", - "hc", "hc", "hc", "hc", "ha", "ha", "ha", "ha", "hc", "hc", "hc", "h1", "h1", - "h1", "h1", "h1", "h1", "h1", "h1", "h1", "h1", "h1", "h1", - ] + reference_path = tmp_path / "b96_h_xponge_atom_types.json" + reference_script = textwrap.dedent( + f""" + import json + import Xponge + import Xponge.forcefield.amber.gaff # noqa: F401 + + assignment = Xponge.get_assignment_from_mol2( + {str(DATA_DIR / "B96_H.mol2")!r}, + total_charge="sum", + ) + assignment.determine_atom_type("gaff") + with open({str(reference_path)!r}, "w", encoding="utf-8") as handle: + json.dump([ + getattr(assignment.atom_types[index], "name", str(assignment.atom_types[index])) + for index in range(len(assignment.atoms)) + ], handle) + """ + ) + result = subprocess.run( + [sys.executable, "-c", reference_script], + cwd=XPONGE_REPO, + check=False, + text=True, + capture_output=True, + ) + if result.returncode != 0: + pytest.fail(f"Xponge B96_H GAFF assignment failed: {result.stderr[-1000:]}") + assert assignment.atom_types == json.loads(reference_path.read_text()) typed = assignment.to_molecule("B") Xponge.Save_Mol2(typed, str(tmp_path / "typed_b96.mol2")) diff --git a/tests/test_bsc1_dihedral_parity.py b/tests/test_bsc1_dihedral_parity.py new file mode 100644 index 0000000..6d9a1fc --- /dev/null +++ b/tests/test_bsc1_dihedral_parity.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +from io import StringIO + +import pytest + +import Xponge +import Xponge.forcefield.amber.bsc1 # noqa: F401 +import Xponge.forcefield.amber.tip3p # noqa: F401 + + +MOL2 = """@MOLECULE +BSC1_DIHEDRAL +4 3 1 0 0 +SMALL +USER_CHARGES + +@ATOM +1 A1 0.0 0.0 0.0 CM 1 TMP 0.0 +2 A2 1.0 0.0 0.0 N* 1 TMP 0.0 +3 A3 2.0 0.0 0.0 CT 1 TMP 0.0 +4 A4 3.0 0.0 0.0 OS 1 TMP 0.0 +@BOND +1 1 2 1 +2 2 3 1 +3 3 4 1 +@SUBSTRUCTURE +1 TMP 1 +""" + + +@pytest.mark.parametrize( + ("periodicity", "k", "phi0"), + ( + (1, 1.03, 184.8), + (2, 1.52, 7.8), + (3, 0.26, 209.6), + ), +) +def test_bsc1_cytosine_chi_uses_all_frcmod_terms( + tmp_path, + periodicity, + k, + phi0, +): + molecule = Xponge.load_mol2(StringIO(MOL2)) + Xponge.save_sponge_input(molecule, "system", tmp_path, format="raw") + rows = [ + line.split() + for line in (tmp_path / "system_dihedral.txt").read_text().splitlines()[1:] + ] + assert any( + int(row[4]) == periodicity + and float(row[5]) == pytest.approx(k) + and float(row[6]) == pytest.approx( + phi0 / 180.0 * Xponge.pi, + abs=1.0e-6, + ) + for row in rows + ) + + +def test_bsc1_completed_cytosine_keeps_chi_frcmod_terms(tmp_path): + control = Xponge.load_mol2(StringIO(MOL2)) + control_before = tmp_path / "control-before" + Xponge.save_sponge_input(control, "system", control_before, format="raw") + control_repeated = tmp_path / "control-repeated" + Xponge.save_sponge_input(control, "system", control_repeated, format="raw") + assert ( + control_before / "system_dihedral.txt" + ).read_text() == ( + control_repeated / "system_dihedral.txt" + ).read_text() + pdb = tmp_path / "cytosine.pdb" + pdb.write_text( + "\n".join( + ( + "ATOM 1 O4' DC A 1 0.000 0.000 0.000 1.00 0.00 O", + "ATOM 2 C1' DC A 1 1.000 0.000 0.000 1.00 0.00 C", + "ATOM 3 N1 DC A 1 2.000 0.000 0.000 1.00 0.00 N", + "ATOM 4 C6 DC A 1 3.000 0.000 0.000 1.00 0.00 C", + "TER", + "END", + ) + ) + + "\n", + encoding="utf-8", + ) + molecule = Xponge.load_pdb(pdb) + control_loaded = tmp_path / "control-loaded" + Xponge.save_sponge_input(control, "system", control_loaded, format="raw") + assert ( + control_before / "system_dihedral.txt" + ).read_text() == ( + control_loaded / "system_dihedral.txt" + ).read_text() + molecule.add_missing_atoms() + control_after = tmp_path / "control-after" + Xponge.save_sponge_input(control, "system", control_after, format="raw") + assert ( + control_before / "system_dihedral.txt" + ).read_text() == ( + control_after / "system_dihedral.txt" + ).read_text() + Xponge.save_sponge_input(molecule, "system", tmp_path, format="raw") + names = (tmp_path / "system_atom_name.txt").read_text().splitlines()[1:] + atom_ids = {name: names.index(name) for name in ("O4'", "C1'", "N1", "C6")} + expected_atoms = [ + atom_ids["O4'"], + atom_ids["C1'"], + atom_ids["N1"], + atom_ids["C6"], + ] + matching_rows = [ + line.split() + for line in (tmp_path / "system_dihedral.txt").read_text().splitlines()[1:] + if [int(value) for value in line.split()[:4]] == expected_atoms + ] + assert [int(row[4]) for row in matching_rows] == [1, 2, 3] diff --git a/tests/test_bundle_protocol.py b/tests/test_bundle_protocol.py index 9c4409c..92edc85 100644 --- a/tests/test_bundle_protocol.py +++ b/tests/test_bundle_protocol.py @@ -138,6 +138,36 @@ def test_invalid_protocol_does_not_publish_partial_bundle(tmp_path): assert not list(tmp_path.glob("invalid_*")) +def test_protocol_writes_typed_virtual_atom_arrays_and_cv_references(tmp_path): + molecule = _peptide() + protocol = Xponge.SpongeProtocol( + virtual_atoms=( + Xponge.ProtocolVirtualAtom( + name="center", + type="center", + atom_indices=(0, 1), + weight=(0.25, 0.75), + ), + ), + collective_variables=( + Xponge.ProtocolCollectiveVariable( + name="distance_cv", + type="distance", + atom_refs=("center", 2), + ), + ), + ) + + Xponge.save_sponge_input_bundle(molecule, "virtual", tmp_path, protocol=protocol) + + with h5py.File(tmp_path / "virtual_protocol.spgp.h5", "r") as handle: + assert _text(handle["/cv/virtual_atom/center/type"]) == "center" + assert handle["/cv/virtual_atom/center/atom_indices"][...].tolist() == [0, 1] + assert handle["/cv/virtual_atom/center/weight"][...].tolist() == pytest.approx([0.25, 0.75]) + assert handle["/cv/distance_cv/atom_refs"].asstr()[...].tolist() == ["center", "2"] + assert int(handle["/protocol/cv_count"][()]) == 1 + + @pytest.mark.parametrize("prefix", ["../escape", ".", "subdir/.."]) def test_protocol_saver_rejects_unsafe_prefixes(tmp_path, prefix): with pytest.raises(BundlePathError, match="prefix|escapes"): diff --git a/tests/test_compat_process.py b/tests/test_compat_process.py index 2a0f13b..ded8a00 100644 --- a/tests/test_compat_process.py +++ b/tests/test_compat_process.py @@ -205,6 +205,31 @@ def test_save_mol2_exports_core_residue_links_as_bonds(tmp_path): assert int(count_fields[1]) == len(bond_pairs) +def test_save_mol2_exports_links_from_public_legacy_molecule_factory(tmp_path): + import Xponge + import Xponge.forcefield.amber.ff19sb # noqa: F401 + + molecule = Xponge.Molecule("public_factory_links") + molecule.add_residue( + Xponge.Residue(Xponge.ResidueType.get_type("ALA"), directly_copy=True) + ) + molecule.add_residue( + Xponge.Residue(Xponge.ResidueType.get_type("GLY"), directly_copy=True) + ) + molecule.add_residue_link( + molecule.residues[0].name2atom("C"), + molecule.residues[1].name2atom("N"), + ) + + path = tmp_path / "public_factory_links.mol2" + Xponge.Save_Mol2(molecule, path) + + count_fields, bond_pairs = _mol2_bond_pairs(path) + assert count_fields is not None + assert (9, 11) in bond_pairs + assert int(count_fields[1]) == len(bond_pairs) + + def test_save_mol2_exports_legacy_override_residue_links_as_bonds(tmp_path): import Xponge diff --git a/tests/test_compat_surface.py b/tests/test_compat_surface.py index ecb0284..845b27a 100644 --- a/tests/test_compat_surface.py +++ b/tests/test_compat_surface.py @@ -1,3 +1,5 @@ +from types import SimpleNamespace + import XpongeCPP as Xponge import pytest @@ -134,6 +136,41 @@ def test_xpongecpp_common_legacy_import_paths_resolve(): assert mass_base is not None +def test_build_pdb_element_helper_preserves_two_letter_metals(): + import Xponge.build as build + + assert build._pdb_guess_element( + SimpleNamespace(name="ZN", element="Zn", mass=65.38) + ).strip() == "Zn" + assert build._pdb_guess_element( + SimpleNamespace(name="ZN", element="", mass=65.38) + ).strip() == "Zn" + + +def test_pdb_reader_applies_nucleic_terminals_and_template_alias_names(tmp_path): + import XpongeCPP.forcefield.amber.bsc1 # noqa: F401 + import XpongeCPP.forcefield.amber.tip3p # noqa: F401 + + text = "\n".join( + [ + "ATOM 1 O5' DC A 1 0.000 0.000 0.000 1.00 0.00 O", + "ATOM 2 O5' DG A 2 1.000 0.000 0.000 1.00 0.00 O", + "TER", + "HETATM 3 O HOH B 1 3.000 0.000 0.000 1.00 0.00 O", + "END", + ] + ) + path = tmp_path / "nucleic-and-water.pdb" + path.write_text(text + "\n", encoding="utf-8") + molecule = Xponge.load_pdb(path) + + assert [residue.name for residue in molecule.residues] == [ + "DC5", + "DG3", + "WAT", + ] + + def test_xponge_package_alias_supports_common_legacy_import_paths(): import Xponge.assign as assign import Xponge.build as build @@ -161,6 +198,31 @@ def test_xponge_package_alias_supports_common_legacy_import_paths(): assert mass_base is not None +def test_legacy_atom_and_lj_type_views_follow_native_registry(): + import Xponge.forcefield.amber.ff14sb # noqa: F401 + from Xponge.helper import AtomType + from Xponge.forcefield.base.lj_base import LJType + + atom_type = AtomType.get_type("N3") + lj_type = LJType.get_type(f"{atom_type.LJtype}-{atom_type.LJtype}") + + assert atom_type.LJtype == "N3" + assert lj_type.epsilon == 0.17 + assert lj_type.rmin == 1.824 + + +def test_capability_manifest_is_explicit_and_fail_closed(): + manifest = Xponge.capability_manifest() + + assert manifest["schema_version"] == 1 + assert manifest["implementation"] == "xpongecpp" + assert manifest["unlisted_status"] == "unsupported" + assert manifest["capabilities"]["io.sponge.bundle"]["status"] == "supported" + assert Xponge.capability_status("unknown.future.feature") == "unsupported" + with pytest.raises(NotImplementedError, match="unknown.future.feature"): + Xponge.require_capability("unknown.future.feature") + + def test_xponge_package_alias_supports_high_frequency_forcefield_and_helper_modules(): import Xponge.forcefield.amber.bsc1 as bsc1 import Xponge.forcefield.amber.ol3 as ol3 diff --git a/tests/test_forcefield_families.py b/tests/test_forcefield_families.py index c5fceae..3636362 100644 --- a/tests/test_forcefield_families.py +++ b/tests/test_forcefield_families.py @@ -11,7 +11,7 @@ def _run(code): env = os.environ.copy() - env["PYTHONPATH"] = str(ROOT / "src") + env.pop("PYTHONPATH", None) return subprocess.run( [sys.executable, "-c", code], cwd=ROOT, diff --git a/tests/test_full_amber_data.py b/tests/test_full_amber_data.py index c3ee6eb..14be896 100644 --- a/tests/test_full_amber_data.py +++ b/tests/test_full_amber_data.py @@ -23,7 +23,7 @@ def _exported_keys(directory, prefix): def _run_isolated(code, *args): env = os.environ.copy() - env["PYTHONPATH"] = str(ROOT / "src") + env.pop("PYTHONPATH", None) return subprocess.run( [sys.executable, "-c", code, *map(str, args)], cwd=ROOT, env=env, text=True, capture_output=True, check=True, @@ -117,6 +117,41 @@ def test_ff19sb_import_registers_real_templates_and_cmap_parameters(tmp_path): assert (tmp_path / "ff19_cmap.txt").read_text().splitlines()[0] == "1 1" +def test_ff19sb_maps_generic_mmcif_histidine_to_a_registered_protonation_template(): + completed = _run_isolated( + "from io import StringIO\n" + "import XpongeCPP as X\n" + "import XpongeCPP.forcefield.amber.ff19sb\n" + "text = '''data_his\n" + "loop_\n" + "_atom_site.group_PDB\n" + "_atom_site.id\n" + "_atom_site.type_symbol\n" + "_atom_site.label_atom_id\n" + "_atom_site.label_comp_id\n" + "_atom_site.label_asym_id\n" + "_atom_site.label_seq_id\n" + "_atom_site.Cartn_x\n" + "_atom_site.Cartn_y\n" + "_atom_site.Cartn_z\n" + "_atom_site.auth_seq_id\n" + "_atom_site.auth_comp_id\n" + "_atom_site.auth_asym_id\n" + "_atom_site.auth_atom_id\n" + "_atom_site.pdbx_PDB_model_num\n" + "ATOM 1 N N HIS A 1 0.0 0.0 0.0 1 HIS A N 1\n" + "ATOM 2 C CA HIS A 1 1.4 0.0 0.0 1 HIS A CA 1\n" + "ATOM 3 C C HIS A 1 2.8 0.0 0.0 1 HIS A C 1\n" + "ATOM 4 O O HIS A 1 3.8 0.0 0.0 1 HIS A O 1\n" + "ATOM 5 H HE2 HIS A 1 1.0 1.0 0.0 1 HIS A HE2 1\n" + "#\n" + "'''\n" + "molecule = X.load_mmcif(StringIO(text), infer_terminals=False)\n" + "assert [residue.name for residue in molecule.residues] == ['HIE']\n" + ) + assert completed.returncode == 0 + + def test_gaff_and_gaff2_imports_register_packaged_parameters(tmp_path): mol2 = tmp_path / "eth.mol2" mol2.write_text("""@MOLECULE diff --git a/tests/test_gaff_assign_migration.py b/tests/test_gaff_assign_migration.py index 6519064..2d0bf90 100644 --- a/tests/test_gaff_assign_migration.py +++ b/tests/test_gaff_assign_migration.py @@ -1,6 +1,10 @@ import io import json import re +import site +import subprocess +import sys +import textwrap from pathlib import Path import pytest @@ -13,6 +17,108 @@ GAFF_100_DIR = REPO_ROOT / "tests" / "data" / "gaff_assign_100" +def _prepare_largest_connected_mol2(source, destination): + text = Path(source).read_text() + sections = [] + current_name = None + current_lines = [] + for line in text.splitlines(): + if line.startswith("@"): + if current_name is not None: + sections.append((current_name, current_lines)) + current_name = line + current_lines = [] + else: + current_lines.append(line) + if current_name is not None: + sections.append((current_name, current_lines)) + + by_name = {name: lines for name, lines in sections} + atom_lines = [line for line in by_name["@ATOM"] if line.strip()] + bond_lines = [line for line in by_name.get("@BOND", []) if line.strip()] + atom_ids = [int(line.split()[0]) for line in atom_lines] + adjacency = {atom_id: set() for atom_id in atom_ids} + parsed_bonds = [] + for line in bond_lines: + words = line.split() + atom1, atom2 = int(words[1]), int(words[2]) + parsed_bonds.append((atom1, atom2, words)) + adjacency[atom1].add(atom2) + adjacency[atom2].add(atom1) + + components = [] + remaining = set(atom_ids) + while remaining: + root = min(remaining) + stack = [root] + component = set() + while stack: + atom = stack.pop() + if atom in component: + continue + component.add(atom) + stack.extend(adjacency[atom] - component) + remaining -= component + components.append(component) + largest = min(components, key=lambda component: (-len(component), min(component))) + if len(largest) == len(atom_ids): + return Path(source), False + + destination = Path(destination) + destination.parent.mkdir(parents=True, exist_ok=True) + remap = {old: new for new, old in enumerate(sorted(largest), start=1)} + filtered_atoms = [] + for line in atom_lines: + words = line.split() + old_id = int(words[0]) + if old_id not in largest: + continue + words[0] = str(remap[old_id]) + filtered_atoms.append(" ".join(words)) + filtered_bonds = [] + for atom1, atom2, words in parsed_bonds: + if atom1 not in largest or atom2 not in largest: + continue + words[0] = str(len(filtered_bonds) + 1) + words[1] = str(remap[atom1]) + words[2] = str(remap[atom2]) + filtered_bonds.append(" ".join(words)) + + molecule_lines = list(by_name["@MOLECULE"]) + counts = molecule_lines[1].split() + counts[0] = str(len(filtered_atoms)) + counts[1] = str(len(filtered_bonds)) + molecule_lines[1] = " ".join(counts) + replacements = { + "@MOLECULE": molecule_lines, + "@ATOM": filtered_atoms, + "@BOND": filtered_bonds, + } + unity_lines = by_name.get("@UNITY_ATOM_ATTR") + if unity_lines is not None: + filtered_unity = [] + index = 0 + while index < len(unity_lines): + if not unity_lines[index].strip(): + index += 1 + continue + words = unity_lines[index].split() + atom_id, attribute_count = int(words[0]), int(words[1]) + attributes = unity_lines[index + 1:index + 1 + attribute_count] + if atom_id in largest: + filtered_unity.append(f"{remap[atom_id]} {attribute_count}") + filtered_unity.extend(attributes) + index += 1 + attribute_count + replacements["@UNITY_ATOM_ATTR"] = filtered_unity + + output = [] + for name, lines in sections: + output.append(name) + output.extend(replacements.get(name, lines)) + destination.write_text("\n".join(output) + "\n") + return destination, True + + def _original_gaff_rule_names(): if not XPONGE_GAFF.exists(): pytest.skip("local Xponge GAFF reference is not available") @@ -30,7 +136,7 @@ def test_gaff_assign_rule_coverage_matches_original_xponge(): assert Xponge.implemented_gaff_assign_types() == _original_gaff_rule_names() -def test_gaff_assign_100_manifest_matches_original_xponge_baseline(): +def test_gaff_assign_100_matches_current_original_xponge(tmp_path): manifest_path = GAFF_100_DIR / "manifest.json" if not manifest_path.exists(): pytest.skip("run benchmarks/generate_gaff_assign_100_baseline.py to create the 100-molecule baseline") @@ -38,17 +144,60 @@ def test_gaff_assign_100_manifest_matches_original_xponge_baseline(): manifest = json.loads(manifest_path.read_text()) entries = manifest.get("entries", []) assert len(entries) >= 100 + entries = entries[:100] + prepared = [ + _prepare_largest_connected_mol2( + GAFF_100_DIR / entry["input_mol2"], + tmp_path / "prepared" / Path(entry["input_mol2"]).name, + ) + for entry in entries + ] + mol2_paths = [str(path) for path, _ in prepared] + assert sum(was_prepared for _, was_prepared in prepared) == 8 + reference_path = tmp_path / "xponge-current-gaff-reference.json" + site_packages = Path(site.getsitepackages()[0]) + script = textwrap.dedent( + f""" + import json + import sys + + sys.path.insert(0, {str(original_xponge_repo())!r}) + sys.path.append({str(site_packages)!r}) + import Xponge + import Xponge.forcefield.amber.gaff # noqa: F401 + + results = [] + for path in {mol2_paths!r}: + assignment = Xponge.get_assignment_from_mol2(path, total_charge="sum") + assignment.determine_atom_type("gaff") + results.append([ + getattr(assignment.atom_types[index], "name", str(assignment.atom_types[index])) + for index in range(len(assignment.atoms)) + ]) + with open({str(reference_path)!r}, "w", encoding="utf-8") as handle: + json.dump(results, handle) + """ + ) + result = subprocess.run( + [sys.executable, "-S", "-c", script], + cwd=original_xponge_repo(), + check=False, + text=True, + capture_output=True, + ) + if result.returncode != 0: + pytest.fail(f"current Xponge GAFF reference failed: {result.stderr[-2000:]}") + references = json.loads(reference_path.read_text()) mismatches = [] - for entry in entries[:100]: - mol2_path = GAFF_100_DIR / entry["input_mol2"] - assignment = Xponge.get_assignment_from_mol2(str(mol2_path), total_charge="sum") + for entry, mol2_path, expected in zip(entries, mol2_paths, references): + assignment = Xponge.get_assignment_from_mol2(mol2_path, total_charge="sum") assignment.determine_atom_type("gaff") - if assignment.atom_types != entry["xponge_gaff_atom_types"]: + if assignment.atom_types != expected: mismatches.append( { "source_id": entry.get("source_id", entry.get("cid")), - "expected": entry["xponge_gaff_atom_types"], + "expected": expected, "actual": assignment.atom_types, } ) @@ -99,7 +248,7 @@ def test_assignment_compatibility_entrypoints_and_writers(tmp_path): assignment.save_as_mol2(str(mol2_path), residue_name="WAT") assignment.save_as_pdb(str(pdb_path), residue_name="WAT") assert "@ATOM" in mol2_path.read_text() - assert pdb_path.read_text().startswith("ATOM") + assert any(line.startswith("ATOM") for line in pdb_path.read_text().splitlines()) pdb_assignment = Xponge.get_assignment_from_pdb(io.StringIO(pdb_path.read_text())) assert pdb_assignment.atoms == ["O", "H", "H"] diff --git a/tests/test_glycam_parity.py b/tests/test_glycam_parity.py index 9fd05e6..5abf4d0 100644 --- a/tests/test_glycam_parity.py +++ b/tests/test_glycam_parity.py @@ -90,6 +90,29 @@ def test_glycam_modified_monosaccharide_templates_load(): assert Xponge.has_template(resname) +def test_glycam_terminal_zero_templates_have_no_synthetic_head(tmp_path): + import XpongeCPP.forcefield.amber.glycam_06j.d_furanose # noqa: F401 + import XpongeCPP.forcefield.amber.glycam_06j.d_pyranose # noqa: F401 + import XpongeCPP.forcefield.amber.glycam_06j.l_furanose # noqa: F401 + import XpongeCPP.forcefield.amber.glycam_06j.l_pyranose # noqa: F401 + + representatives = ["0MA", "0aA", "0AD", "0aD"] + for resname in representatives: + residue_type = Xponge.ResidueType.get_type(resname) + atom_names = {atom.name for atom in residue_type.atoms} + assert residue_type.head is None + assert residue_type.head_next is None + assert residue_type.head_link_conditions == [] + assert "O0" not in atom_names + assert "C0" not in atom_names + + output_path = tmp_path / "terminal-zero.pdb" + molecule = Xponge.ResidueType.get_type("0MA") + Xponge.ResidueType.get_type("0MA") + Xponge.save_pdb(molecule, output_path) + assert output_path.is_file() + assert "O0" not in output_path.read_text() + + def test_glycam_coverage_audit_classifies_extension_layers(tmp_path): from XpongeCPP.forcefield.amber.glycam_06j.audit import audit_glycam_coverage diff --git a/tests/test_legacy_import_matrix.py b/tests/test_legacy_import_matrix.py index 7e9ba1e..c39f38c 100644 --- a/tests/test_legacy_import_matrix.py +++ b/tests/test_legacy_import_matrix.py @@ -1,4 +1,12 @@ -import importlib +import os +import subprocess +import sys +from pathlib import Path + +import pytest + + +ROOT = Path(__file__).resolve().parents[1] CORE_SCOPE_LEGACY_IMPORTS = [ @@ -47,11 +55,45 @@ ] -def test_core_scope_legacy_import_matrix(): - failures = [] - for module_name in CORE_SCOPE_LEGACY_IMPORTS: - try: - importlib.import_module(module_name) - except Exception as exc: # pragma: no cover - this is the failure path we want reported - failures.append((module_name, repr(exc))) - assert not failures, f"legacy imports failed: {failures}" +def _run_import(module_name): + env = os.environ.copy() + env.pop("PYTHONPATH", None) + return subprocess.run( + [ + sys.executable, + "-c", + f"import importlib; importlib.import_module({module_name!r})", + ], + cwd=ROOT, + env=env, + text=True, + capture_output=True, + ) + + +def _public_forcefield_imports(): + package_root = ROOT / "src" / "XpongeCPP" / "forcefield" + modules = set() + for path in package_root.rglob("*.py"): + relative = path.relative_to(ROOT / "src").with_suffix("") + parts = list(relative.parts) + if parts[-1] == "__init__": + parts.pop() + if any(part.startswith("_") for part in parts[2:]): + continue + native = ".".join(parts) + modules.add(native) + modules.add(native.replace("XpongeCPP", "Xponge", 1)) + return sorted(modules) + + +@pytest.mark.parametrize("module_name", CORE_SCOPE_LEGACY_IMPORTS) +def test_core_scope_legacy_import_matrix(module_name): + result = _run_import(module_name) + assert result.returncode == 0, result.stderr + + +@pytest.mark.parametrize("module_name", _public_forcefield_imports()) +def test_public_forcefield_import_matrix(module_name): + result = _run_import(module_name) + assert result.returncode == 0, result.stderr diff --git a/tests/test_legacy_mdanalysis_raw.py b/tests/test_legacy_mdanalysis_raw.py new file mode 100644 index 0000000..2721b58 --- /dev/null +++ b/tests/test_legacy_mdanalysis_raw.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +import pytest + + +pytest.importorskip("MDAnalysis") + + +def test_sponge_input_reader_exposes_origin_format_contract(): + from Xponge.analysis import md_analysis as xmda + + assert xmda.SpongeInputReader.format == "SPONGE_MASS" + assert xmda.SpongeInputReader._format_hint("system_mass.txt") is True + assert xmda.SpongeInputReader._format_hint("system_charge.txt") is False + diff --git a/tests/test_lipid17_extension.py b/tests/test_lipid17_extension.py index 7a24281..f5137ab 100644 --- a/tests/test_lipid17_extension.py +++ b/tests/test_lipid17_extension.py @@ -18,7 +18,7 @@ def _run_python(code, *args): env = os.environ.copy() - env["PYTHONPATH"] = str(ROOT / "src") + env.pop("PYTHONPATH", None) return subprocess.run( [sys.executable, "-c", code, *map(str, args)], text=True, @@ -98,8 +98,11 @@ def test_all_extension_templates_export_with_complete_parameters(tmp_path): " molecule = X.get_template_molecule(entry['template'])\n" " assert molecule.atom_count == entry['atom_count']\n" " assert abs(sum(atom.charge for atom in molecule.atoms) - entry['total_charge']) < 1e-7\n" - " output = X.Save_SPONGE_Input(molecule, prefix=entry['template'].replace('-', 'minus'), dirname=sys.argv[2])\n" - " assert {'bond', 'angle', 'dihedral', 'nb14'}.issubset(output)\n", + " prefix = entry['template'].replace('-', 'minus')\n" + " output = X.Save_SPONGE_Input(molecule, prefix=prefix, dirname=sys.argv[2])\n" + " assert output is molecule\n" + " assert all((Path(sys.argv[2]) / f'{prefix}_{suffix}.txt').is_file() " + "for suffix in ('bond', 'angle', 'dihedral', 'nb14'))\n", AMBER_DATA / "lipid_ext_manifest.json", tmp_path, ) @@ -121,7 +124,9 @@ def test_representative_pdbs_load_with_expected_links_and_export(tmp_path): " assert [residue.name for residue in molecule.residues] == residue_names\n" " assert len(molecule.residue_links) == 2\n" " output = X.Save_SPONGE_Input(molecule, prefix=name, dirname=outdir)\n" - " assert {'bond', 'angle', 'dihedral', 'nb14', 'coordinate'}.issubset(output)\n", + " assert output is molecule\n" + " assert all((Path(outdir) / f'{name}_{suffix}.txt').is_file() " + "for suffix in ('bond', 'angle', 'dihedral', 'nb14', 'coordinate'))\n", DATA, tmp_path, ) diff --git a/tests/test_lipid21.py b/tests/test_lipid21.py index 5debdec..a1c6628 100644 --- a/tests/test_lipid21.py +++ b/tests/test_lipid21.py @@ -18,7 +18,7 @@ def _run(code, *args): env = os.environ.copy() - env["PYTHONPATH"] = str(ROOT / "src") + env.pop("PYTHONPATH", None) return subprocess.run( [sys.executable, "-c", code, *map(str, args)], cwd=ROOT, @@ -69,8 +69,11 @@ def test_all_lipid21_and_extension_templates_export_with_complete_parameters(tmp " molecule = X.get_template_molecule(entry['template'])\n" " assert molecule.atom_count == entry['atom_count']\n" " assert abs(sum(atom.charge for atom in molecule.atoms) - entry['total_charge']) < 1e-7\n" - " output = X.Save_SPONGE_Input(molecule, prefix=entry['template'].replace('-', 'minus'), dirname=sys.argv[3])\n" - " assert {'bond','angle','dihedral','nb14'}.issubset(output)\n", + " prefix = entry['template'].replace('-', 'minus')\n" + " output = X.Save_SPONGE_Input(molecule, prefix=prefix, dirname=sys.argv[3])\n" + " assert output is molecule\n" + " assert all((Path(sys.argv[3]) / f'{prefix}_{suffix}.txt').is_file() " + "for suffix in ('bond','angle','dihedral','nb14'))\n", AMBER_DATA / "lipid21_manifest.json", AMBER_DATA / "lipid_ext_manifest.json", tmp_path, diff --git a/tests/test_non_amber_parsers.py b/tests/test_non_amber_parsers.py index ad156aa..2878bc4 100644 --- a/tests/test_non_amber_parsers.py +++ b/tests/test_non_amber_parsers.py @@ -365,9 +365,10 @@ def test_load_molitp_reuses_generated_residue_variants_matches_original_xponge_r reference = json.loads(_run_original_xponge(script)) assert current_summary == reference - assert current_summary["residue_names"] == ["ALA", "ALA_1", "ALA_1"] - assert current_summary["mols"]["MOD1"] == ["ALA_1"] - assert current_summary["mols"]["MOD2"] == ["ALA_1"] + assert current_summary["residue_names"][1] == current_summary["residue_names"][2] + assert current_summary["residue_names"][0] != current_summary["residue_names"][1] + assert current_summary["mols"]["MOD1"] == current_summary["mols"]["MOD2"] + assert current_summary["mols"]["MOD1"] == [current_summary["residue_names"][1]] def test_load_molitp_invokes_registered_bonded_type_parsers_and_copies_special_forces(tmp_path): @@ -748,7 +749,7 @@ def test_martini300_module_supports_loader_driven_small_molecule_export_workflow assert "LJ" in _exported_keys(tmp_path, "martini_chex") -def test_martini300_constraints_topology_reports_current_connectivity_limitation_explicitly(tmp_path): +def test_martini300_constraint_only_topology_exports_without_covalent_bonds(tmp_path): import XpongeCPP.forcefield.martini.martini300 # noqa: F401 top = tmp_path / "4mimi.top" @@ -767,8 +768,15 @@ def test_martini300_constraints_topology_reports_current_connectivity_limitation assert system.atom_count == 3 assert [res.name for res in system.residues] == ["4MIMI"] assert sorted(mols) == ["4MIMI"] - with pytest.raises(RuntimeError, match="missing residue template/connectivity for residue: 4MIMI"): - Xponge.Save_SPONGE_Input(system, prefix="martini_4mimi", dirname=str(tmp_path)) + output = Xponge.Save_SPONGE_Input( + system, + prefix="martini_4mimi", + dirname=str(tmp_path), + ) + assert output is system + assert system.validate() + assert (tmp_path / "martini_4mimi_bond.txt").read_text().splitlines()[0] == "0" + assert "LJ" in _exported_keys(tmp_path, "martini_4mimi") def test_non_amber_forcefield_import_modules_are_available(): diff --git a/tests/test_pdb_chain_terminal_semantics.py b/tests/test_pdb_chain_terminal_semantics.py index 9c866f3..30abb15 100644 --- a/tests/test_pdb_chain_terminal_semantics.py +++ b/tests/test_pdb_chain_terminal_semantics.py @@ -132,23 +132,25 @@ def test_pdb_ssbond_and_link_records_create_residue_links(tmp_path): LINK C ACE C 1 N ALA C 2 ATOM 1 N CYS A 1 0.000 0.000 0.000 1.00 0.00 N ATOM 2 CA CYS A 1 1.000 0.000 0.000 1.00 0.00 C -ATOM 3 C CYS A 1 2.000 0.000 0.000 1.00 0.00 C -ATOM 4 O CYS A 1 3.000 0.000 0.000 1.00 0.00 O -ATOM 5 SG CYS A 1 1.000 1.800 0.000 1.00 0.00 S +ATOM 3 CB CYS A 1 1.000 1.000 0.000 1.00 0.00 C +ATOM 4 C CYS A 1 2.000 0.000 0.000 1.00 0.00 C +ATOM 5 O CYS A 1 3.000 0.000 0.000 1.00 0.00 O +ATOM 6 SG CYS A 1 1.000 1.800 0.000 1.00 0.00 S TER -ATOM 6 N CYS B 1 0.000 5.000 0.000 1.00 0.00 N -ATOM 7 CA CYS B 1 1.000 5.000 0.000 1.00 0.00 C -ATOM 8 C CYS B 1 2.000 5.000 0.000 1.00 0.00 C -ATOM 9 O CYS B 1 3.000 5.000 0.000 1.00 0.00 O -ATOM 10 SG CYS B 1 1.000 3.200 0.000 1.00 0.00 S +ATOM 7 N CYS B 1 0.000 5.000 0.000 1.00 0.00 N +ATOM 8 CA CYS B 1 1.000 5.000 0.000 1.00 0.00 C +ATOM 9 CB CYS B 1 1.000 4.000 0.000 1.00 0.00 C +ATOM 10 C CYS B 1 2.000 5.000 0.000 1.00 0.00 C +ATOM 11 O CYS B 1 3.000 5.000 0.000 1.00 0.00 O +ATOM 12 SG CYS B 1 1.000 3.200 0.000 1.00 0.00 S TER -ATOM 11 CH3 ACE C 1 0.000 10.000 0.000 1.00 0.00 C -ATOM 12 C ACE C 1 1.000 10.000 0.000 1.00 0.00 C -ATOM 13 O ACE C 1 2.000 10.000 0.000 1.00 0.00 O -ATOM 14 N ALA C 2 3.000 10.000 0.000 1.00 0.00 N -ATOM 15 CA ALA C 2 4.000 10.000 0.000 1.00 0.00 C -ATOM 16 C ALA C 2 5.000 10.000 0.000 1.00 0.00 C -ATOM 17 O ALA C 2 6.000 10.000 0.000 1.00 0.00 O +ATOM 13 CH3 ACE C 1 0.000 10.000 0.000 1.00 0.00 C +ATOM 14 C ACE C 1 1.000 10.000 0.000 1.00 0.00 C +ATOM 15 O ACE C 1 2.000 10.000 0.000 1.00 0.00 O +ATOM 16 N ALA C 2 3.000 10.000 0.000 1.00 0.00 N +ATOM 17 CA ALA C 2 4.000 10.000 0.000 1.00 0.00 C +ATOM 18 C ALA C 2 5.000 10.000 0.000 1.00 0.00 C +ATOM 19 O ALA C 2 6.000 10.000 0.000 1.00 0.00 O TER END """ @@ -158,8 +160,8 @@ def test_pdb_ssbond_and_link_records_create_residue_links(tmp_path): pairs = _bond_pairs(tmp_path / "linked_bond.txt") assert [res.name for res in mol.residues[:2]] == ["NCYX", "NCYX"] - assert (4, 9) in pairs - assert (11, 13) in pairs + assert (5, 11) in pairs + assert (13, 15) in pairs def test_pdb_options_for_altloc_hydrogen_conect_and_cryst1(tmp_path): @@ -245,25 +247,27 @@ def test_pdb_writer_rebuilds_ssbond_link_and_conect_records(tmp_path): SSBOND 1 CYS A 1 CYS B 1 ATOM 1 N CYS A 1 0.000 0.000 0.000 1.00 0.00 N ATOM 2 CA CYS A 1 1.000 0.000 0.000 1.00 0.00 C -ATOM 3 C CYS A 1 2.000 0.000 0.000 1.00 0.00 C -ATOM 4 O CYS A 1 3.000 0.000 0.000 1.00 0.00 O -ATOM 5 SG CYS A 1 1.000 1.800 0.000 1.00 0.00 S -ATOM 6 N ALA A 2 4.000 0.000 0.000 1.00 0.00 N -ATOM 7 CA ALA A 2 5.000 0.000 0.000 1.00 0.00 C -ATOM 8 C ALA A 2 6.000 0.000 0.000 1.00 0.00 C -ATOM 9 O ALA A 2 7.000 0.000 0.000 1.00 0.00 O +ATOM 3 CB CYS A 1 1.000 1.000 0.000 1.00 0.00 C +ATOM 4 C CYS A 1 2.000 0.000 0.000 1.00 0.00 C +ATOM 5 O CYS A 1 3.000 0.000 0.000 1.00 0.00 O +ATOM 6 SG CYS A 1 1.000 1.800 0.000 1.00 0.00 S +ATOM 7 N ALA A 2 4.000 0.000 0.000 1.00 0.00 N +ATOM 8 CA ALA A 2 5.000 0.000 0.000 1.00 0.00 C +ATOM 9 C ALA A 2 6.000 0.000 0.000 1.00 0.00 C +ATOM 10 O ALA A 2 7.000 0.000 0.000 1.00 0.00 O TER -ATOM 10 N CYS B 1 0.000 5.000 0.000 1.00 0.00 N -ATOM 11 CA CYS B 1 1.000 5.000 0.000 1.00 0.00 C -ATOM 12 C CYS B 1 2.000 5.000 0.000 1.00 0.00 C -ATOM 13 O CYS B 1 3.000 5.000 0.000 1.00 0.00 O -ATOM 14 SG CYS B 1 1.000 3.200 0.000 1.00 0.00 S -ATOM 15 N ALA B 2 4.000 5.000 0.000 1.00 0.00 N -ATOM 16 CA ALA B 2 5.000 5.000 0.000 1.00 0.00 C -ATOM 17 C ALA B 2 6.000 5.000 0.000 1.00 0.00 C -ATOM 18 O ALA B 2 7.000 5.000 0.000 1.00 0.00 O +ATOM 11 N CYS B 1 0.000 5.000 0.000 1.00 0.00 N +ATOM 12 CA CYS B 1 1.000 5.000 0.000 1.00 0.00 C +ATOM 13 CB CYS B 1 1.000 4.000 0.000 1.00 0.00 C +ATOM 14 C CYS B 1 2.000 5.000 0.000 1.00 0.00 C +ATOM 15 O CYS B 1 3.000 5.000 0.000 1.00 0.00 O +ATOM 16 SG CYS B 1 1.000 3.200 0.000 1.00 0.00 S +ATOM 17 N ALA B 2 4.000 5.000 0.000 1.00 0.00 N +ATOM 18 CA ALA B 2 5.000 5.000 0.000 1.00 0.00 C +ATOM 19 C ALA B 2 6.000 5.000 0.000 1.00 0.00 C +ATOM 20 O ALA B 2 7.000 5.000 0.000 1.00 0.00 O TER -CONECT 7 16 +CONECT 8 18 END """ ), @@ -279,8 +283,8 @@ def test_pdb_writer_rebuilds_ssbond_link_and_conect_records(tmp_path): assert any(line.startswith("LINK") and "ALA A 2" in line and "ALA B 2" in line for line in text.splitlines()) assert "CONECT" not in text Xponge.Save_SPONGE_Input(reloaded, prefix="roundtrip", dirname=str(tmp_path)) - assert (4, 13) in _bond_pairs(tmp_path / "roundtrip_bond.txt") - assert (6, 15) in _bond_pairs(tmp_path / "roundtrip_bond.txt") + assert (5, 15) in _bond_pairs(tmp_path / "roundtrip_bond.txt") + assert (7, 17) in _bond_pairs(tmp_path / "roundtrip_bond.txt") def test_pdb_writer_uses_conect_for_single_residue_chains(tmp_path): diff --git a/tests/test_psf_io.py b/tests/test_psf_io.py index c874106..7dd7b42 100644 --- a/tests/test_psf_io.py +++ b/tests/test_psf_io.py @@ -124,3 +124,45 @@ def test_load_molpsf_distinguishes_reused_residue_name_with_charge_type_conflict assert [res.type_name for res in mol.residues] == ["LIG", "LIG_1"] assert [res.atoms[0].type for res in mol.residues] == ["CT", "C2"] assert [res.atoms[0].charge for res in mol.residues] == [0.0, 0.5] + + +def test_load_molpsf_keeps_zero_bond_multiatom_residue_intact(): + psf = StringIO( + """\ +PSF + 0 !NTITLE + 3 !NATOM + 1 SYS 1 LIG C1 CT 0.000000 12.0100 0 + 2 SYS 1 LIG C2 CT 0.000000 12.0100 0 + 3 SYS 2 ION NA NA 1.000000 22.9900 0 + 0 !NBOND: bonds +""" + ) + + mol, mols = Xponge.load_molpsf(psf) + + assert mol.residue_count == 2 + assert [[atom.name for atom in residue.atoms] for residue in mol.residues] == [["C1", "C2"], ["NA"]] + assert sorted(mols) == ["psf_1", "psf_3"] + assert mols["psf_1"].atom_count == 2 + assert mols["psf_3"].atom_count == 1 + + +def test_load_molpsf_does_not_merge_noncontiguous_reused_residue_keys(): + psf = StringIO( + """\ +PSF + 0 !NTITLE + 3 !NATOM + 1 SYS 1 LIG C1 CT 0.000000 12.0100 0 + 2 SYS 2 MID C2 CT 0.000000 12.0100 0 + 3 SYS 1 LIG C3 CT 0.000000 12.0100 0 + 0 !NBOND: bonds +""" + ) + + mol, _ = Xponge.load_molpsf(psf, split_by=None) + + assert mol.residue_count == 3 + assert [res.name for res in mol.residues] == ["LIG", "MID", "LIG"] + assert [[atom.name for atom in res.atoms] for res in mol.residues] == [["C1"], ["C2"], ["C3"]] diff --git a/tests/test_release_020.py b/tests/test_release_025.py similarity index 91% rename from tests/test_release_020.py rename to tests/test_release_025.py index d88daa5..c25d4f6 100644 --- a/tests/test_release_020.py +++ b/tests/test_release_025.py @@ -1,4 +1,4 @@ -"""Release-contract checks for the Xponge-origin 1.7b8 alignment.""" +"""Release-contract checks for the Xponge-origin 1.7b10 alignment.""" from __future__ import annotations @@ -18,8 +18,8 @@ def test_release_version_and_compatibility_target(): metadata = tomllib.loads( (ROOT / "pyproject.toml").read_text(encoding="utf-8") )["project"] - assert metadata["version"] == XpongeCPP.__version__ == "0.2.0" - assert "Xponge-origin 1.7b8" in metadata["description"] + assert metadata["version"] == XpongeCPP.__version__ == "0.2.6" + assert "Xponge-origin 1.7b10" in metadata["description"] assert metadata["requires-python"] == ">=3.10,<3.13" diff --git a/tests/test_resp_linear_constraints.py b/tests/test_resp_linear_constraints.py index 15a9eb8..97038a7 100644 --- a/tests/test_resp_linear_constraints.py +++ b/tests/test_resp_linear_constraints.py @@ -46,6 +46,36 @@ def _exact_esp_problem(charges): return atom_coordinates, nuclear, grids, electronic_esp +def test_cpp_mk_grid_uses_the_xponge_fibonacci_orientation(): + assignment = _assignment(["H"]) + center = np.asarray([[0.25, -0.5, 1.0]]) + grids = np.asarray( + resp_core.get_mk_grid( + assignment, + center, + area_density=1.0, + layer=1, + ) + ) + + radius = 1.2 / 0.52918 * 1.4 + point_count = int(1.0 * 0.52918**2 * 4.0 * np.pi * radius**2) + indices = np.arange(1, point_count + 1) + theta = (np.sqrt(5.0) - 1.0) * np.pi * indices + z = (2.0 * indices - 1.0) / point_count - 1.0 + planar_radius = np.sqrt(1.0 - z * z) + expected = np.column_stack( + ( + planar_radius * np.cos(theta), + planar_radius * np.sin(theta), + z, + ) + ) + expected = expected * radius + center[0] + + assert grids == pytest.approx(expected, abs=1e-12) + + def test_constrained_resp_recovers_linear_and_equivalence_targets(): assignment = _assignment(["O", "H", "H"]) problem = _exact_esp_problem([-0.4, 0.2, 0.2]) diff --git a/tests/test_scientific_manifest.py b/tests/test_scientific_manifest.py new file mode 100644 index 0000000..a8cfe86 --- /dev/null +++ b/tests/test_scientific_manifest.py @@ -0,0 +1,215 @@ +from __future__ import annotations + +from copy import deepcopy +import subprocess +import sys + +from XpongeCPP.scientific_manifest import ( + _canonicalize_atom_order, + build_scientific_manifest, + compare_scientific_manifests, + write_scientific_manifest, +) + + +def _write_case(root): + subprocess.run( + [ + sys.executable, + "-c", + ( + "import XpongeCPP as Xponge;" + "import XpongeCPP.forcefield.amber.ff14sb;" + "molecule=Xponge.get_peptide_from_sequence('AA');" + "molecule.set_box_padding(4.0);" + "Xponge.save_sponge_input(" + f"molecule,'system',{str(root)!r},format='raw')" + ), + ], + check=True, + ) + + +def test_scientific_manifest_round_trip_and_numeric_diff(tmp_path): + case_root = tmp_path / "case" + _write_case(case_root) + manifest = build_scientific_manifest(case_root, case_id="ala2") + + assert manifest["schema"] == "xponge.scientific_manifest" + assert manifest["case_id"] == "ala2" + assert "/atoms/mass" in manifest["datasets"] + assert "/atoms/charge" in manifest["datasets"] + assert "/forcefield/bond/atoms" in manifest["datasets"] + assert "/restart/position" in manifest["datasets"] + assert compare_scientific_manifests(manifest, manifest)["ok"] + + changed = deepcopy(manifest) + changed["datasets"]["/atoms/charge"]["values"][0] += 1.0e-4 + diff = compare_scientific_manifests(manifest, changed) + assert not diff["ok"] + assert diff["issues"][0]["path"] == "/atoms/charge" + + output = write_scientific_manifest(manifest, tmp_path / "manifest.json") + assert output.is_file() + + +def test_scientific_manifest_canonicalizes_improper_permutations(): + from XpongeCPP.scientific_manifest import _canonicalize_dihedrals + + def manifest_atoms(values): + return { + "/forcefield/bond/atoms": { + "dtype": "int32", + "shape": [3, 2], + "values": [[2, 1], [2, 3], [2, 4]], + }, + "/forcefield/dihedral/atoms": { + "dtype": "int32", + "shape": [1, 4], + "values": [values], + }, + "/forcefield/dihedral/periodicity": { + "dtype": "int32", + "shape": [1], + "values": [2], + }, + "/forcefield/dihedral/k": { + "dtype": "float32", + "shape": [1], + "values": [10.5], + }, + "/forcefield/dihedral/phi0": { + "dtype": "float32", + "shape": [1], + "values": [3.141593], + }, + } + + first = manifest_atoms([1, 3, 2, 4]) + second = manifest_atoms([4, 2, 1, 3]) + _canonicalize_dihedrals(first) + _canonicalize_dihedrals(second) + assert first["/forcefield/dihedral/atoms"] == second["/forcefield/dihedral/atoms"] + assert first["/forcefield/dihedral/kind"]["values"] == ["improper"] + + +def test_scientific_manifest_canonicalizes_atom_insertion_order(): + first = { + "/atoms/name": { + "dtype": "string", + "shape": [3], + "values": ["C", "A", "B"], + }, + "/atoms/type_name": { + "dtype": "string", + "shape": [3], + "values": ["tc", "ta", "tb"], + }, + "/atoms/residue_index": { + "dtype": "int32", + "shape": [3], + "values": [0, 0, 0], + }, + "/atoms/charge": { + "dtype": "float32", + "shape": [3], + "values": [3.0, 1.0, 2.0], + }, + "/restart/position": { + "dtype": "float32", + "shape": [3, 3], + "values": [[3.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0]], + }, + "/forcefield/bond/atoms": { + "dtype": "int32", + "shape": [2, 2], + "values": [[0, 2], [2, 1]], + }, + "/forcefield/bond/k": { + "dtype": "float32", + "shape": [2], + "values": [20.0, 10.0], + }, + "/forcefield/bond/r0": { + "dtype": "float32", + "shape": [2], + "values": [2.0, 1.0], + }, + "/topology/exclusions/offset": { + "dtype": "int32", + "shape": [4], + "values": [0, 0, 1, 1], + }, + "/topology/exclusions/list": { + "dtype": "int32", + "shape": [1], + "values": [2], + }, + } + second = deepcopy(first) + second["/atoms/name"]["values"] = ["A", "B", "C"] + second["/atoms/type_name"]["values"] = ["ta", "tb", "tc"] + second["/atoms/charge"]["values"] = [1.0, 2.0, 3.0] + second["/restart/position"]["values"] = [ + [1.0, 0.0, 0.0], + [2.0, 0.0, 0.0], + [3.0, 0.0, 0.0], + ] + second["/forcefield/bond/atoms"]["values"] = [[2, 1], [1, 0]] + second["/forcefield/bond/k"]["values"] = [20.0, 10.0] + second["/forcefield/bond/r0"]["values"] = [2.0, 1.0] + second["/topology/exclusions/list"]["values"] = [0] + + _canonicalize_atom_order(first) + _canonicalize_atom_order(second) + assert first == second + + +def test_scientific_manifest_canonicalizes_cmap_grid_order_and_duplicates(): + from XpongeCPP.scientific_manifest import _canonicalize_cmaps + + first = { + "/forcefield/cmap/atoms": { + "dtype": "int32", + "shape": [3, 5], + "values": [[5, 6, 7, 8, 9], [0, 1, 2, 3, 4], [10, 11, 12, 13, 14]], + }, + "/forcefield/cmap/type": { + "dtype": "int32", + "shape": [3], + "values": [0, 1, 2], + }, + "/forcefield/cmap/resolution": { + "dtype": "int32", + "shape": [3], + "values": [2, 2, 2], + }, + "/forcefield/cmap/grid_value": { + "dtype": "float32", + "shape": [12], + "values": [4.0, 3.0, 2.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 3.0, 2.0, 1.0], + }, + } + second = { + "/forcefield/cmap/atoms": deepcopy(first["/forcefield/cmap/atoms"]), + "/forcefield/cmap/type": { + "dtype": "int32", + "shape": [3], + "values": [1, 0, 1], + }, + "/forcefield/cmap/resolution": { + "dtype": "int32", + "shape": [2], + "values": [2, 2], + }, + "/forcefield/cmap/grid_value": { + "dtype": "float32", + "shape": [8], + "values": [1.0, 2.0, 3.0, 4.0, 4.0, 3.0, 2.0, 1.0], + }, + } + + _canonicalize_cmaps(first) + _canonicalize_cmaps(second) + + assert first == second diff --git a/tests/test_xpongecpp_api.py b/tests/test_xpongecpp_api.py index 4d3df2c..2c2e36a 100644 --- a/tests/test_xpongecpp_api.py +++ b/tests/test_xpongecpp_api.py @@ -88,6 +88,40 @@ """ +MMCIF_WATER_CHEM_COMP_BOND_TEXT = """\ +data_water +loop_ +_atom_site.group_PDB +_atom_site.id +_atom_site.type_symbol +_atom_site.label_atom_id +_atom_site.auth_atom_id +_atom_site.label_comp_id +_atom_site.auth_comp_id +_atom_site.label_asym_id +_atom_site.auth_asym_id +_atom_site.label_seq_id +_atom_site.auth_seq_id +_atom_site.pdbx_PDB_ins_code +_atom_site.label_alt_id +_atom_site.Cartn_x +_atom_site.Cartn_y +_atom_site.Cartn_z +_atom_site.occupancy +_atom_site.B_iso_or_equiv +_atom_site.pdbx_PDB_model_num +HETATM 1 O O O WAT WAT A A 1 1 ? . 0.000 0.000 0.000 1.00 0.00 1 +HETATM 2 H H1 H1 WAT WAT A A 1 1 ? . 0.957 0.000 0.000 1.00 0.00 1 +HETATM 3 H H2 H2 WAT WAT A A 1 1 ? . -0.240 0.927 0.000 1.00 0.00 1 +loop_ +_chem_comp_bond.comp_id +_chem_comp_bond.atom_id_1 +_chem_comp_bond.atom_id_2 +WAT O H1 +WAT O H2 +""" + + MMCIF_AUTH_LABEL_COLLISION_TEXT = """\ data_auth_label_collision loop_ @@ -315,6 +349,17 @@ def test_load_mmcif_reads_internal_links_and_deduplicates_external_links(): assert mol.residue_links == [[0, 1]] +def test_load_mmcif_preserves_template_pseudobonds_with_chem_comp_bonds(): + import XpongeCPP.forcefield.amber.tip3p # noqa: F401 + + mol = Xponge.load_mmcif( + StringIO(MMCIF_WATER_CHEM_COMP_BOND_TEXT), + infer_terminals=False, + ) + + assert sorted(map(tuple, mol.explicit_bonds)) == [(0, 1), (0, 2), (1, 2)] + + def test_load_mmcif_prefers_auth_identity_for_struct_conn(): import XpongeCPP.forcefield.amber.ff14sb # noqa: F401 @@ -420,6 +465,112 @@ def test_load_mol2_as_template_registers_legacy_residuetype_lookup(): assert Xponge.has_template("WAT") +def test_load_mol2_as_template_preserves_existing_caps_and_infers_new_head_tail(): + Xponge.load_mol2( + StringIO( + """@MOLECULE +CAPS +2 0 2 +SMALL +USER_CHARGES +@ATOM +1 KEEP 0.0 0.0 0.0 c3 1 ZCA 0.0 +2 KEEP 4.0 0.0 0.0 c3 2 ZCB 0.0 +@BOND +""" + ), + as_template=True, + ) + Xponge.configure_residue_template_tail("ZCA", "KEEP") + Xponge.configure_residue_template_head("ZCB", "KEEP") + Xponge.load_mol2( + StringIO( + """@MOLECULE +CAPPED_NEW +5 4 3 +SMALL +USER_CHARGES +@ATOM +1 REPLACEMENT 0.0 0.0 0.0 c 1 ZCA 0.0 +2 HEAD 1.0 0.0 0.0 n 2 ZNEW 0.0 +3 TAIL 2.0 0.0 0.0 c 2 ZNEW 0.0 +4 H 1.0 1.0 0.0 hn 2 ZNEW 0.0 +5 REPLACEMENT 3.0 0.0 0.0 n 3 ZCB 0.0 +@BOND +1 1 2 1 +2 2 3 1 +3 2 4 1 +4 3 5 1 +""" + ), + as_template=True, + ) + + left = Xponge.ResidueType.get_type("ZCA") + center = Xponge.ResidueType.get_type("ZNEW") + right = Xponge.ResidueType.get_type("ZCB") + + assert [atom.name for atom in left.atoms] == ["KEEP"] + assert [atom.name for atom in right.atoms] == ["KEEP"] + assert {atom.name for atom in center.atoms} == {"HEAD", "TAIL", "H"} + molecule = ( + Xponge.get_template_molecule("ZCA") + + Xponge.get_template_molecule("ZNEW") + + Xponge.get_template_molecule("ZCB") + ) + assert len(molecule.residue_links) == 2 + assert { + tuple(sorted((molecule.atoms[int(atom1)].name, molecule.atoms[int(atom2)].name))) + for atom1, atom2 in molecule.residue_links + } == {("HEAD", "KEEP"), ("KEEP", "TAIL")} + + +def test_legacy_residuetype_none_temporarily_disables_native_auto_linking(): + Xponge.load_mol2( + StringIO( + """@MOLECULE +AUTO_LINK_TYPES +2 0 2 +SMALL +USER_CHARGES +@ATOM +1 TAIL 0.0 0.0 0.0 c3 1 ZTL 0.0 +2 HEAD 2.0 0.0 0.0 n 2 ZHD 0.0 +@BOND +""" + ), + as_template=True, + ) + left = Xponge.ResidueType.get_type("ZTL") + right = Xponge.ResidueType.get_type("ZHD") + left.tail = "TAIL" + right.head = "HEAD" + assert len( + ( + Xponge.get_template_molecule("ZTL") + + Xponge.get_template_molecule("ZHD") + ).residue_links + ) == 1 + + saved_tail = left.tail + saved_head = right.head + left.tail = None + right.head = None + assert not ( + Xponge.get_template_molecule("ZTL") + + Xponge.get_template_molecule("ZHD") + ).residue_links + + left.tail = saved_tail + right.head = saved_head + assert len( + ( + Xponge.get_template_molecule("ZTL") + + Xponge.get_template_molecule("ZHD") + ).residue_links + ) == 1 + + def test_template_atoms_follow_forcefield_mass_and_element_inference(): import importlib import XpongeCPP.forcefield.amber.ff14sb as ff14sb @@ -963,6 +1114,63 @@ def test_save_sponge_input_reorders_linked_residue_components_for_export(tmp_pat assert (tmp_path / "linked_resname.txt").read_text().splitlines() == ["3", "FAR", "WAT", "LIG"] +def test_save_sponge_input_mapping_tracks_reordered_linked_components(tmp_path): + Xponge.register_tip3p() + mol = Xponge.load_mol2(StringIO(CUSTOM_MOL2_TEXT)) | Xponge.load_mol2(StringIO(MOL2_TEXT)) + + residue_counts = [len(residue.atoms) for residue in mol.residues] + source_ids = tuple(f"source:{index}" for index, _atom in enumerate(mol.atoms)) + mol.add_residue_link(mol.residues[0].name2atom("O1"), mol.residues[2].name2atom("O")) + + saved, mapping = Xponge.Save_SPONGE_Input( + mol, + prefix="linked_mapping", + dirname=str(tmp_path), + source_atom_ids=source_ids, + return_mapping=True, + ) + + far_end = residue_counts[0] + ligand_end = far_end + residue_counts[1] + expected_source_ids = ( + source_ids[:far_end] + + source_ids[ligand_end:] + + source_ids[far_end:ligand_end] + ) + assert saved is mol + assert [residue.name for residue in saved.residues] == ["FAR", "WAT", "LIG"] + assert tuple(record["source_atom_id"] for record in mapping) == expected_source_ids + + +def test_save_sponge_input_reorders_coordination_components_for_export(tmp_path): + Xponge.register_tip3p() + mol = Xponge.load_mol2(StringIO(CUSTOM_MOL2_TEXT)) | Xponge.load_mol2(StringIO(MOL2_TEXT)) + + assert [res.name for res in mol.residues] == ["FAR", "LIG", "WAT"] + + mol.add_coordination_bond( + mol.residues[0].name2atom("O1").index, + mol.residues[2].name2atom("O").index, + ) + mol._set_bond_parameter_override( + mol.residues[0].name2atom("O1").index, + mol.residues[2].name2atom("O").index, + 100.0, + 2.0, + "test:coordination", + ) + Xponge.Save_SPONGE_Input(mol, prefix="coordinated", dirname=str(tmp_path)) + + assert [res.name for res in mol.residues] == ["FAR", "WAT", "LIG"] + assert mol.coordination_bonds == [(0, 3)] + assert (tmp_path / "coordinated_resname.txt").read_text().splitlines() == [ + "3", + "FAR", + "WAT", + "LIG", + ] + + def test_save_sponge_input_rejects_noncontiguous_atom_components(tmp_path): Xponge.register_tip3p() mol = Xponge.load_mol2(StringIO(SPLIT_COMPONENT_MOL2_TEXT)) diff --git a/third_party/xponge_reference_forcefield/amber/glycam_06j/__init__.py b/third_party/xponge_reference_forcefield/amber/glycam_06j/__init__.py index b61949a..2e5d5c9 100644 --- a/third_party/xponge_reference_forcefield/amber/glycam_06j/__init__.py +++ b/third_party/xponge_reference_forcefield/amber/glycam_06j/__init__.py @@ -28,6 +28,11 @@ def set_head(res, n): :param n: :return: """ + if n == 0: + res.head = None + res.head_next = None + res.head_link_conditions.clear() + return head_dihedral = -60 if (n <= 6 and res.name[-1] not in "DU") else -180 res.head = f"O{n}" res.head_next = f"C{n}"