diff --git a/.github/workflows/choose_branch.yaml b/.github/workflows/choose_branch.yaml index 611368a6f..534742c71 100644 --- a/.github/workflows/choose_branch.yaml +++ b/.github/workflows/choose_branch.yaml @@ -20,7 +20,7 @@ jobs: max-parallel: 5 fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.10", "3.11", "3.12"] platform: - { name: "windows", os: "windows-latest", shell: "pwsh" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } @@ -30,14 +30,14 @@ jobs: # but Linux - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.8" + python-version: "3.10" - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } - python-version: "3.8" + python-version: "3.10" - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.9" + python-version: "3.12" # MacOS can't run 3.12 yet... - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } - python-version: "3.9" + python-version: "3.11" environment: name: sire-build defaults: @@ -49,7 +49,7 @@ jobs: REPO: "${{ github.repository }}" steps: # - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ matrix.python-version }} @@ -62,7 +62,7 @@ jobs: run: git clone https://github.com/${{ env.REPO }} -b ${{ github.event.inputs.branch }} sire # - name: Setup Conda - run: mamba install -y -c conda-forge boa anaconda-client packaging=21 pip-requirements-parser + run: mamba install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser # - name: Update Conda recipe run: python ${{ github.workspace }}/sire/actions/update_recipe.py diff --git a/.github/workflows/devel.yaml b/.github/workflows/devel.yaml index 07d54eb54..e63e5072a 100644 --- a/.github/workflows/devel.yaml +++ b/.github/workflows/devel.yaml @@ -15,10 +15,10 @@ jobs: name: build (${{ matrix.python-version }}, ${{ matrix.platform.name }}) runs-on: ${{ matrix.platform.os }} strategy: - max-parallel: 5 + max-parallel: 6 fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11", "3.12"] platform: - { name: "windows", os: "windows-latest", shell: "pwsh" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } @@ -28,11 +28,11 @@ jobs: # but Linux - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.9" - - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } - python-version: "3.9" + python-version: "3.12" # MacOS can't run 3.12 yet... We want 3.10 and 3.11 - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } python-version: "3.10" + - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } + python-version: "3.11" environment: name: sire-build defaults: @@ -44,7 +44,7 @@ jobs: REPO: "${{ github.repository }}" steps: # - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ matrix.python-version }} @@ -57,7 +57,7 @@ jobs: run: git clone https://github.com/${{ env.REPO }} sire # - name: Setup Conda - run: mamba install -y -c conda-forge boa anaconda-client packaging=21 pip-requirements-parser + run: mamba install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser # - name: Update Conda recipe run: python ${{ github.workspace }}/sire/actions/update_recipe.py diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 3934946d3..76732f2ec 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -24,11 +24,15 @@ jobs: max-parallel: 9 fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11", "3.12"] platform: - { name: "windows", os: "windows-latest", shell: "pwsh" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } - { name: "macos", os: "macos-latest", shell: "bash -l {0}" } + exclude: + - platform: + { name: "macos", os: "macos-latest", shell: "bash -l {0}" } + python-version: "3.12" # MacOS can't run 3.12 yet... environment: name: sire-build defaults: @@ -40,7 +44,7 @@ jobs: REPO: "${{ github.event.pull_request.head.repo.full_name || github.repository }}" steps: # - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ matrix.python-version }} @@ -53,7 +57,7 @@ jobs: run: git clone -b main https://github.com/openbiosim/sire sire # - name: Setup Conda - run: mamba install -y -c conda-forge boa anaconda-client packaging=21 pip-requirements-parser + run: mamba install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser # - name: Update Conda recipe run: python ${{ github.workspace }}/sire/actions/update_recipe.py diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index c1badfa4e..e1a45542b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -17,7 +17,7 @@ jobs: max-parallel: 5 fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11", "3.12"] platform: - { name: "windows", os: "windows-latest", shell: "pwsh" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } @@ -27,14 +27,14 @@ jobs: # but Linux - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.9" + python-version: "3.10" - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } - python-version: "3.9" + python-version: "3.10" - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.10" + python-version: "3.12" # MacOS can't run 3.12 yet... - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } - python-version: "3.10" + python-version: "3.11" environment: name: sire-build defaults: @@ -46,7 +46,7 @@ jobs: REPO: "${{ github.event.pull_request.head.repo.full_name || github.repository }}" steps: # - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ matrix.python-version }} @@ -59,7 +59,7 @@ jobs: run: git clone -b ${{ github.head_ref }} --single-branch https://github.com/${{ env.REPO }} sire # - name: Setup Conda - run: mamba install -y -c conda-forge boa anaconda-client packaging=21 pip-requirements-parser + run: mamba install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser # - name: Update Conda recipe run: python ${{ github.workspace }}/sire/actions/update_recipe.py diff --git a/README.rst b/README.rst index 564b5296c..4689732d8 100644 --- a/README.rst +++ b/README.rst @@ -43,7 +43,7 @@ To create a new environment: .. code-block:: bash - conda create -n openbiosim "python<3.12" + conda create -n openbiosim "python<3.13" conda activate openbiosim conda install -c conda-forge -c openbiosim sire @@ -51,10 +51,45 @@ To install the latest development version you can use: .. code-block:: bash - conda create -n openbiosim-dev "python<3.12" + conda create -n openbiosim-dev "python<3.13" conda activate openbiosim-dev conda install -c conda-forge -c openbiosim/label/dev sire +Installing older versions +------------------------- + +You can install a specific version of sire by specifying the version number +in the conda install command, e.g. + +.. code-block:: bash + + conda install -c conda-forge -c openbiosim sire==2024.1.0 + +Note that limited space means that we can only keep a small number of +versions of sire on the official openbiosim conda channel. Generally +these are all point releases of the latest major version, plus the latest +point release of the last major version. + +We do provide an +`archive channel `__ +of all previous releases. You can search this archive channel for the +release you are interested in using the following command: + +.. code-block:: bash + + conda search -c https://openbiosim.blob.core.windows.net/archive sire + +This will return a list of all versions of sire available in the archive. + +You can install a specific version from the archive using a command like: + +.. code-block:: bash + + conda install -c https://openbiosim.blob.core.windows.net/archive sire==2023.2.3 + +Installation from source +------------------------ + However, as you are here, it is likely you want to download the latest, greatest version of the code, which you will need to compile. To compile sire, diff --git a/actions/update_recipe.py b/actions/update_recipe.py index 41e93d5cf..b21922146 100644 --- a/actions/update_recipe.py +++ b/actions/update_recipe.py @@ -254,4 +254,4 @@ def check_reqs(reqs0, reqs1): channels = " ".join([f"-c {x}" for x in channels]) print("\nBuild this package using the command") -print(f"conda mambabuild {channels} {condadir}") +print(f"conda build {channels} {condadir}") diff --git a/corelib/src/libs/SireBase/CMakeLists.txt b/corelib/src/libs/SireBase/CMakeLists.txt index 92811520d..55f240aca 100644 --- a/corelib/src/libs/SireBase/CMakeLists.txt +++ b/corelib/src/libs/SireBase/CMakeLists.txt @@ -27,6 +27,7 @@ set ( SIREBASE_HEADERS combineproperties.h convert_property.hpp countflops.h + console.h cpuid.h errors.h findexe.h @@ -87,6 +88,7 @@ set ( SIREBASE_SOURCES chunkedhash.cpp chunkedvector.cpp combineproperties.cpp + console.cpp countflops.cpp cpuid.cpp errors.cpp diff --git a/corelib/src/libs/SireBase/console.cpp b/corelib/src/libs/SireBase/console.cpp new file mode 100644 index 000000000..8268df4db --- /dev/null +++ b/corelib/src/libs/SireBase/console.cpp @@ -0,0 +1,88 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#include "SireBase/console.h" + +using namespace SireBase; + +ConsoleBase::ConsoleBase() +{ +} + +ConsoleBase::~ConsoleBase() +{ +} + +ConsoleBase *Console::c(0); + +Console::Console() +{ +} + +Console::~Console() +{ +} + +/** Write the passed debug message to the console */ +void Console::debug(const QString &message) +{ + if (c) + c->debug(message); +} + +/** Write the passed warning message to the console */ +void Console::warning(const QString &message) +{ + if (c) + c->warning(message); +} + +/** Write the passed error message to the console */ +void Console::error(const QString &message) +{ + if (c) + c->error(message); +} + +/** Write the passed info message to the console */ +void Console::info(const QString &message) +{ + if (c) + c->info(message); +} + +/** Set the driver for the global console - this will delete + * any existing console - and will take ownership of the pointer! + */ +void Console::setConsole(ConsoleBase *console) +{ + if (c) + delete c; + + c = console; +} diff --git a/corelib/src/libs/SireBase/console.h b/corelib/src/libs/SireBase/console.h new file mode 100644 index 000000000..36a2525ad --- /dev/null +++ b/corelib/src/libs/SireBase/console.h @@ -0,0 +1,75 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#ifndef SIREBASE_CONSOLE_H +#define SIREBASE_CONSOLE_H + +#include "sireglobal.h" + +SIRE_BEGIN_HEADER + +namespace SireBase +{ + /** Virtual base class of the actual console implementation */ + class SIREBASE_EXPORT ConsoleBase + { + public: + ConsoleBase(); + virtual ~ConsoleBase(); + + virtual void debug(const QString &message) const = 0; + virtual void warning(const QString &message) const = 0; + virtual void error(const QString &message) const = 0; + virtual void info(const QString &message) const = 0; + }; + + /** This class provides static functions that can be used + * to (sparingly) output messages to the console. This is + * controlled by the tools in sire.utils.console + */ + class SIREBASE_EXPORT Console + { + public: + static void debug(const QString &message); + static void warning(const QString &message); + static void error(const QString &message); + static void info(const QString &message); + + static void setConsole(ConsoleBase *console); + + private: + Console(); + ~Console(); + + static ConsoleBase *c; + }; +} + +SIRE_END_HEADER + +#endif // SIREBASE_CONSOLE_H diff --git a/corelib/src/libs/SireCAS/lambdaschedule.cpp b/corelib/src/libs/SireCAS/lambdaschedule.cpp index 71f6b3ae6..11eae8e35 100644 --- a/corelib/src/libs/SireCAS/lambdaschedule.cpp +++ b/corelib/src/libs/SireCAS/lambdaschedule.cpp @@ -30,6 +30,8 @@ #include "SireCAS/values.h" +#include "SireBase/console.h" + #include "SireError/errors.h" #include "SireStream/datastream.h" @@ -300,6 +302,11 @@ LambdaSchedule LambdaSchedule::charge_scaled_morph(double scale) return l; } +/** Return a schedule that can be used for a standard double-decoupling + * free energy perturbation. If `perturbed_is_decoupled` is true, then + * the perturbed state is decoupled, otherwise the reference state is + * decoupled. + */ LambdaSchedule LambdaSchedule::standard_decouple(bool perturbed_is_decoupled) { LambdaSchedule l; @@ -308,6 +315,13 @@ LambdaSchedule LambdaSchedule::standard_decouple(bool perturbed_is_decoupled) return l; } +/** Return a schedule that can be used for a standard double-decoupling + * free energy perturbation. If `perturbed_is_decoupled` is true, then + * the perturbed state is decoupled, otherwise the reference state is + * decoupled. In this case also add states to decharge and recharge + * the molecule either side of the decoupling stage, where the charges + * are scaled to 'scale' times their original value. + */ LambdaSchedule LambdaSchedule::charge_scaled_decouple(double scale, bool perturbed_is_decoupled) { LambdaSchedule l; @@ -317,6 +331,35 @@ LambdaSchedule LambdaSchedule::charge_scaled_decouple(double scale, bool perturb return l; } +/** Return a schedule that can be used for a standard double-annihilation + * free energy perturbation. If `perturbed_is_annihilated` is true, then + * the perturbed state is annihilated, otherwise the reference state is + * annihilated. + */ +LambdaSchedule LambdaSchedule::standard_annihilate(bool perturbed_is_annihilated) +{ + LambdaSchedule l; + l.addAnnihilateStage(perturbed_is_annihilated); + + return l; +} + +/** Return a schedule that can be used for a standard double-annihilation + * free energy perturbation. If `perturbed_is_annihilated` is true, then + * the perturbed state is annihilated, otherwise the reference state is + * annihilated. In this case also add states to decharge and recharge + * the molecule either side of the annihilation stage, where the charges + * are scaled to 'scale' times their original value. + */ +LambdaSchedule LambdaSchedule::charge_scaled_annihilate(double scale, bool perturbed_is_annihilated) +{ + LambdaSchedule l; + l.addAnnihilateStage(perturbed_is_annihilated); + l.addChargeScaleStages(scale); + + return l; +} + /** Return the symbol used to represent the :lambda: coordinate. * This symbol is used to represent the per-stage :lambda: * variable that goes from 0.0-1.0 within that stage. @@ -633,16 +676,63 @@ void LambdaSchedule::addMorphStage() this->addMorphStage("morph"); } +/** Add a stage to the schedule that will decouple the perturbed + * state if `perturbed_is_decoupled` is true, otherwise the + * reference state is decoupled. The stage will be called 'decouple'. + */ void LambdaSchedule::addDecoupleStage(bool perturbed_is_decoupled) { this->addDecoupleStage("decouple", perturbed_is_decoupled); } +/** Add a named stage to the schedule that will decouple the perturbed + * state if `perturbed_is_decoupled` is true, otherwise the + * reference state is decoupled. + */ void LambdaSchedule::addDecoupleStage(const QString &name, bool perturbed_is_decoupled) { - throw SireError::incomplete_code(QObject::tr( - "Decouple stages are not yet implemented."), - CODELOC); + this->addStage(name, default_morph_equation); + + // we now need to ensure that the ghost/ghost and ghost-14 parameters are + // not perturbed + if (perturbed_is_decoupled) + { + this->setEquation(name, "ghost/ghost", "*", this->initial()); + this->setEquation(name, "ghost-14", "*", this->initial()); + + // we also need to scale down kappa as the decoupled state is + // not evaluated in the NonbondedForce, so must not be cancelled + this->setEquation(name, "ghost/ghost", "kappa", 1.0 - this->lam()); + this->setEquation(name, "ghost-14", "kappa", 1.0 - this->lam()); + } + else + { + this->setEquation(name, "ghost/ghost", "*", this->final()); + this->setEquation(name, "ghost-14", "*", this->final()); + + // we also need to scale up kappa as the decoupled state is + // not evaluated in the NonbondedForce, so must not be cancelled + this->setEquation(name, "ghost/ghost", "kappa", this->lam()); + this->setEquation(name, "ghost-14", "kappa", this->lam()); + } +} + +/** Add a stage to the schedule that will annihilate the perturbed + * state if `perturbed_is_annihilated` is true, otherwise the + * reference state is annihilated. The stage will be called 'annihilate'. + */ +void LambdaSchedule::addAnnihilateStage(bool perturbed_is_annihilated) +{ + this->addAnnihilateStage("annihilate", perturbed_is_annihilated); +} + +/** Add a named stage to the schedule that will annihilate the perturbed + * state if `perturbed_is_annihilated` is true, otherwise the + * reference state is annihilated. + */ +void LambdaSchedule::addAnnihilateStage(const QString &name, bool perturbed_is_annihilated) +{ + this->addStage(name, default_morph_equation); } /** Sandwich the current set of stages with a charge-descaling and @@ -1320,10 +1410,12 @@ QVector LambdaSchedule::morph(const QString &force, if (equation == default_morph_equation) { + double stage_lam = std::get<1>(resolved); + for (int i = 0; i < nparams; ++i) { - morphed_data[i] = (1.0 - lambda_value) * initial_data[i] + - lambda_value * final_data[i]; + morphed_data[i] = (1.0 - stage_lam) * initial_data[i] + + stage_lam * final_data[i]; } } else @@ -1389,10 +1481,12 @@ QVector LambdaSchedule::morph(const QString &force, if (equation == default_morph_equation) { + double stage_lam = std::get<1>(resolved); + for (int i = 0; i < nparams; ++i) { - morphed_data[i] = int((1.0 - lambda_value) * initial_data[i] + - lambda_value * final_data[i]); + morphed_data[i] = int((1.0 - stage_lam) * initial_data[i] + + stage_lam * final_data[i]); } } else diff --git a/corelib/src/libs/SireCAS/lambdaschedule.h b/corelib/src/libs/SireCAS/lambdaschedule.h index 7e48e8e01..1ac9fa9f6 100644 --- a/corelib/src/libs/SireCAS/lambdaschedule.h +++ b/corelib/src/libs/SireCAS/lambdaschedule.h @@ -82,6 +82,9 @@ namespace SireCAS static LambdaSchedule standard_decouple(bool perturbed_is_decoupled = true); static LambdaSchedule charge_scaled_decouple(double scale = 0.2, bool perturbed_is_decoupled = true); + static LambdaSchedule standard_annihilate(bool perturbed_is_annihilated = true); + static LambdaSchedule charge_scaled_annihilate(double scale = 0.2, bool perturbed_is_annihilated = true); + static SireCAS::Symbol lam(); static SireCAS::Symbol initial(); static SireCAS::Symbol final(); @@ -142,6 +145,9 @@ namespace SireCAS void addDecoupleStage(bool perturbed_is_decoupled = true); void addDecoupleStage(const QString &name, bool perturbed_is_decoupled = true); + void addAnnihilateStage(bool perturbed_is_annihilated = true); + void addAnnihilateStage(const QString &name, bool perturbed_is_annihilated = true); + void setDefaultStageEquation(const QString &stage, const SireCAS::Expression &equation); diff --git a/corelib/src/libs/SireIO/amber.cpp b/corelib/src/libs/SireIO/amber.cpp index 29cfa63a8..4f6c824e4 100644 --- a/corelib/src/libs/SireIO/amber.cpp +++ b/corelib/src/libs/SireIO/amber.cpp @@ -1966,7 +1966,6 @@ tuple Amber::readCrdTop(const QString &crdfile, const Q MoleculeGroup molecules(QString("%1:%2").arg(crdfile, topfile)); - int molnum = 1; int resnum = 1; int total_molecules; @@ -2147,7 +2146,6 @@ tuple Amber::readCrdTop(const QString &crdfile, const Q molecule = editmol.commit(); molecules.add(molecule); - ++molnum; } // Now the box information diff --git a/corelib/src/libs/SireIO/mol2.cpp b/corelib/src/libs/SireIO/mol2.cpp index db3b0531c..d608b4145 100644 --- a/corelib/src/libs/SireIO/mol2.cpp +++ b/corelib/src/libs/SireIO/mol2.cpp @@ -2624,7 +2624,15 @@ MolEditor Mol2::getMolecule(int imol, const PropertyMap &map) const status_bits.set(cgatomidx, atom.getStatusBits()); // Infer the element from the SYBYL atom type. - elements.set(cgatomidx, Element::biologicalElement(atom.getType())); + if (atom.getType() != "Du") + { + elements.set(cgatomidx, Element::biologicalElement(atom.getType())); + } + else + { + // try to infer the element from the atom name + elements.set(cgatomidx, Element::biologicalElement(atom.getName())); + } } // Instantiate the residue property objects that we need. diff --git a/corelib/src/libs/SireMM/amberparams.cpp b/corelib/src/libs/SireMM/amberparams.cpp index 275970234..bdb1dd249 100644 --- a/corelib/src/libs/SireMM/amberparams.cpp +++ b/corelib/src/libs/SireMM/amberparams.cpp @@ -52,6 +52,7 @@ #include "SireCAS/trigfuncs.h" #include "SireCAS/values.h" +#include "SireBase/console.h" #include "SireBase/parallel.h" #include "SireBase/stringproperty.h" @@ -2749,3 +2750,28 @@ PropertyPtr AmberParams::_pvt_makeCompatibleWith(const MoleculeInfoData &newinfo throw SireError::incomplete_code("Cannot make compatible if atom order has changed!", CODELOC); } + +/** Merge this property with another property */ +PropertyList AmberParams::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} diff --git a/corelib/src/libs/SireMM/amberparams.h b/corelib/src/libs/SireMM/amberparams.h index 635164b20..47fb2d1f4 100644 --- a/corelib/src/libs/SireMM/amberparams.h +++ b/corelib/src/libs/SireMM/amberparams.h @@ -513,6 +513,11 @@ namespace SireMM DihedralID convert(const DihedralID &dihedral) const; ImproperID convert(const ImproperID &improper) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, const AtomMatcher &atommatcher) const; diff --git a/corelib/src/libs/SireMM/atomfunctions.h b/corelib/src/libs/SireMM/atomfunctions.h index a81a28538..c2b249581 100644 --- a/corelib/src/libs/SireMM/atomfunctions.h +++ b/corelib/src/libs/SireMM/atomfunctions.h @@ -34,6 +34,7 @@ #include "SireMol/cgatomidx.h" #include "SireMol/molviewproperty.h" +#include "SireMol/atomidxmapping.h" #include "SireCAS/expression.h" #include "SireCAS/identities.h" diff --git a/corelib/src/libs/SireMM/atomljs.cpp b/corelib/src/libs/SireMM/atomljs.cpp index 90679ecae..8bc272b25 100644 --- a/corelib/src/libs/SireMM/atomljs.cpp +++ b/corelib/src/libs/SireMM/atomljs.cpp @@ -29,6 +29,8 @@ #include "SireBase/quickcopy.hpp" #include "SireBase/incremint.h" +#include "SireBase/propertylist.h" +#include "SireBase/console.h" #include "SireStream/magic_error.h" #include "SireStream/datastream.h" @@ -38,6 +40,7 @@ #include using namespace SireMM; +using namespace SireBase; using namespace SireMol; using namespace SireStream; @@ -1456,3 +1459,61 @@ QList AtomProperty::getExceptions(int i) const { return this->lj_exceptions.value(i); } + +/** Merge this property with another property */ +PropertyList AtomProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + const AtomProperty &ref = *this; + const AtomProperty &pert = other.asA>(); + + AtomProperty prop0 = ref; + AtomProperty prop1 = ref; + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for LJ parameters is ignored").arg(ghost)); + } + + for (const auto &index : mapping) + { + if (index.isUnmappedIn0() and index.isUnmappedIn1()) + { + prop0.set(index.cgAtomIdx0(), LJParameter::dummy()); + prop1.set(index.cgAtomIdx0(), LJParameter::dummy()); + } + else if (index.isUnmappedIn0()) + { + auto lj1 = pert.get(index.cgAtomIdx1()); + prop0.set(index.cgAtomIdx0(), LJParameter(lj1.sigma(), SireUnits::Dimension::MolarEnergy(0))); + prop1.set(index.cgAtomIdx0(), lj1); + } + else if (index.isUnmappedIn1()) + { + auto lj0 = ref.get(index.cgAtomIdx0()); + prop1.set(index.cgAtomIdx0(), LJParameter(lj0.sigma(), SireUnits::Dimension::MolarEnergy(0))); + } + else + { + prop1.set(index.cgAtomIdx0(), pert.get(index.cgAtomIdx1())); + } + } + + SireBase::PropertyList ret; + ret.append(prop0); + ret.append(prop1); + + return ret; + + return ret; +} diff --git a/corelib/src/libs/SireMM/atomljs.h b/corelib/src/libs/SireMM/atomljs.h index 83c01e071..eaad03761 100644 --- a/corelib/src/libs/SireMM/atomljs.h +++ b/corelib/src/libs/SireMM/atomljs.h @@ -274,6 +274,11 @@ namespace SireMol QList> getExceptions() const; QList> getExceptions(const AtomProperty &other) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual atomic property values */ SireBase::PackedArray2D props; diff --git a/corelib/src/libs/SireMM/atompairs.hpp b/corelib/src/libs/SireMM/atompairs.hpp index 6f8becc41..4cf92c2ab 100644 --- a/corelib/src/libs/SireMM/atompairs.hpp +++ b/corelib/src/libs/SireMM/atompairs.hpp @@ -30,12 +30,14 @@ #include "SireBase/property.h" #include "SireBase/sparsematrix.hpp" +#include "SireBase/console.h" #include "SireMol/atommatcher.h" #include "SireMol/cgatomidx.h" #include "SireMol/moleculeinfodata.h" #include "SireMol/moleculeview.h" #include "SireMol/molviewproperty.h" +#include "SireMol/atomidxmapping.h" #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" @@ -87,7 +89,7 @@ namespace SireMM { friend SIREMM_EXPORT QDataStream & ::operator<< <>(QDataStream &, const CGAtomPairs &); - friend SIREMM_EXPORT QDataStream & ::operator>><>(QDataStream &, CGAtomPairs &); + friend SIREMM_EXPORT QDataStream & ::operator>> <>(QDataStream &, CGAtomPairs &); template friend class CGAtomPairs; @@ -139,7 +141,7 @@ namespace SireMM { friend SIREMM_EXPORT QDataStream & ::operator<< <>(QDataStream &, const AtomPairs &); - friend SIREMM_EXPORT QDataStream & ::operator>><>(QDataStream &, AtomPairs &); + friend SIREMM_EXPORT QDataStream & ::operator>> <>(QDataStream &, AtomPairs &); template friend class AtomPairs; @@ -215,6 +217,11 @@ namespace SireMM bool isCompatibleWith(const MoleculeInfoData &molinfo) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, const AtomMatcher &atommatcher) const; @@ -874,6 +881,32 @@ namespace SireMM return ret; } + /** Merge this property with another property */ + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList AtomPairs::merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(SireBase::PropertyPtr(this->clone())); + ret.append(SireBase::PropertyPtr(this->clone())); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // end of namespace SireMM diff --git a/corelib/src/libs/SireMM/cljnbpairs.cpp b/corelib/src/libs/SireMM/cljnbpairs.cpp index 641d3f075..848ca2316 100644 --- a/corelib/src/libs/SireMM/cljnbpairs.cpp +++ b/corelib/src/libs/SireMM/cljnbpairs.cpp @@ -969,3 +969,323 @@ const char *LJNBPairs::typeName() { return QMetaType::typeName(qMetaTypeId()); } + +/** Merge this property with another property */ +PropertyList CLJNBPairs::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for CLJNBPairs parameters is ignored").arg(ghost)); + } + + const CLJNBPairs &ref = *this; + const CLJNBPairs &pert = other.asA(); + + CLJNBPairs prop0 = ref; + CLJNBPairs prop1 = ref; + + // we now go through all of the atoms that are mapped and set the + // CLJ NB pair to the right value for each end state. We copy the + // values from the alternate end state for ghost atoms, as we can + // assume that the ghost atoms will have the same bonding + // arrangement as in their end state + for (auto it1 = mapping.begin(); it1 != mapping.end(); ++it1) + { + const auto &atom_a = *it1; + + for (auto it2 = it1 + 1; it2 != mapping.end(); ++it2) + { + const auto &atom_b = *it2; + + if (atom_a.isUnmappedIn0() or atom_b.isUnmappedIn0()) + { + // this pair does not exist in the reference state + if (atom_a.isUnmappedIn1() or atom_b.isUnmappedIn1()) + { + // this pair does not exist in the perturbed state either. + // This pair should not interact with each other + prop0.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), CLJScaleFactor(0, 0)); + prop1.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), CLJScaleFactor(0, 0)); + } + else + { + // set both end states to the value in the perturbed state + const auto &scl = pert.get(atom_a.cgAtomIdx1(), atom_b.cgAtomIdx1()); + + prop0.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), scl); + prop1.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), scl); + } + } + else if (atom_a.isUnmappedIn1() or atom_b.isUnmappedIn1()) + { + if (atom_a.isUnmappedIn0() or atom_b.isUnmappedIn0()) + { + // this pair does not exist in the reference state + // This pair should not interact with each other + prop0.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), CLJScaleFactor(0, 0)); + prop1.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), CLJScaleFactor(0, 0)); + } + else + { + // set both end states to the value in the reference state + const auto &scl = ref.get(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0()); + // already set in the reference state + prop1.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), scl); + } + } + else + { + // we only need to update the pertubed state to equal the + // value from the perturbed parameters + prop1.set(atom_a.cgAtomIdx0(), atom_b.cgAtomIdx0(), + pert.get(atom_a.cgAtomIdx1(), atom_b.cgAtomIdx1())); + } + } + } + + SireBase::PropertyList ret; + + ret.append(prop0); + ret.append(prop1); + + return ret; +} + +/** Return a copy of this property that has been made to be compatible + with the molecule layout in 'molinfo' - this uses the atom matching + functions in 'atommatcher' to match atoms from the current molecule + to the atoms in the molecule whose layout is in 'molinfo' + + This will only copy the values of pairs of atoms that are + successfully matched - all other pairs will have the default + value of this AtomPairs object. + + \throw SireError::incompatible_error +*/ +SireBase::PropertyPtr CLJNBPairs::_pvt_makeCompatibleWith( + const MoleculeInfoData &other_info, const AtomMatcher &atommatcher) const +{ + // if the atommatcher doesn't change order and the new molecule info + // has the same number of atoms in the same number of cutgroups, then + // there is nothing that we need to do + if (not atommatcher.changesOrder(this->info(), other_info)) + { + bool same_arrangement = true; + + // ensure that the number of atoms and number of cutgroups are the same + if (this->info().nAtoms() == other_info.nAtoms() and this->info().nCutGroups() == other_info.nCutGroups()) + { + for (int i = 0; i < other_info.nCutGroups(); ++i) + { + if (this->info().nAtoms(CGIdx(i)) != other_info.nAtoms(CGIdx(i))) + { + same_arrangement = false; + break; + } + } + } + + if (same_arrangement) + { + // there is no change in the atom order - this AtomPairs object is still valid, + // create a copy of the object and update the molinfo + CLJNBPairs ret(*this); + ret.molinfo = other_info; + return ret; + } + } + + QHash matched_atoms = atommatcher.match(this->info(), other_info); + + // check to see if the AtomIdx to AtomIdx map changes - if not, then + // we can return a copy of this object with the new molinfo + bool same_mapping = true; + + for (auto it = matched_atoms.begin(); it != matched_atoms.end(); ++it) + { + if (it.key() != it.value()) + { + same_mapping = false; + break; + } + } + + if (same_mapping) + { + CLJNBPairs ret(*this); + ret.molinfo = other_info; + return ret; + } + else + return this->_pvt_makeCompatibleWith(other_info, matched_atoms); +} + +/** Return a copy of this property that has been made to be compatible + with the molecule layout in 'molinfo' - this uses the atom map in + 'map' to match atoms from the current molecule to the atoms in the + molecule whose layout is in 'molinfo' + + This will only copy the values of pairs of atoms that are + successfully matched - all other pairs will have the default + value of this AtomPairs object. + + \throw SireError::incompatible_error +*/ +SireBase::PropertyPtr CLJNBPairs::_pvt_makeCompatibleWith( + const MoleculeInfoData &other_info, const QHash &map) const +{ + const auto &this_info = this->info(); + + // create a map from CGAtomIdx to CGAtomIdx for both states + // Only insert values where they have changed - use a null + // value to indicate that the atom does not exist in the new map + QHash cg_map; + cg_map.reserve(map.count()); + + QSet changed_cgroups, deleted_cgroups, mapped_cgroups; + const int ncg = this_info.nCutGroups(); + mapped_cgroups.reserve(ncg); + changed_cgroups.reserve(ncg); + deleted_cgroups.reserve(ncg); + + for (CGIdx i(0); i < ncg; ++i) + { + deleted_cgroups.insert(i); + } + + for (auto it = map.begin(); it != map.end(); ++it) + { + CGAtomIdx atom0 = this_info.cgAtomIdx(it.key()); + CGAtomIdx atom1; + + if (not it.value().isNull()) + atom1 = other_info.cgAtomIdx(it.value()); + + if (not atom1.isNull()) + { + deleted_cgroups.remove(atom1.cutGroup()); + mapped_cgroups.insert(atom0.cutGroup()); + } + + if (atom0 != atom1) + { + // this has changed + cg_map.insert(atom0, atom1); + changed_cgroups.insert(atom0.cutGroup()); + + if (not atom1.isNull()) + changed_cgroups.insert(atom1.cutGroup()); + } + } + + if (cg_map.isEmpty()) + { + // nothing has changed - we don't need to do any work + CLJNBPairs ret(*this); + ret.molinfo = other_info; + return ret; + } + + // there are some changes - start by creating a completely + // empty set of pairs, using a default value of 1,1 + CLJNBPairs ret(other_info, CLJScaleFactor(1, 1)); + + // now go through all of the atom pairs, in CGIdx order, and + // copy where we can from this object to the new object, and + // if not possible, then copy individual values + for (CGIdx i(0); i < ncg; ++i) + { + bool changed_i = changed_cgroups.contains(i); + const int nats_i = this_info.nAtoms(i); + + if (not mapped_cgroups.contains(i)) + { + // this CutGroup has been deleted + continue; + } + + for (CGIdx j(i); j < ncg; ++j) + { + if (not mapped_cgroups.contains(j)) + { + // this CutGroup has been deleted + continue; + } + + bool changed_j = changed_cgroups.contains(j); + + const auto &cgpairs = this->get(i, j); + + if (not(changed_i or changed_j)) + { + // nothing has changed, so copy in the original values (only if the CutGroup + // pair hasn't been deleted) + if (not(deleted_cgroups.contains(i) or deleted_cgroups.contains(j))) + ret.cgpairs.set(i, j, cgpairs); + + continue; + } + + // there's change, so just copy the values for all atom pairs + const int nats_j = this_info.nAtoms(j); + + auto new_cgpairs = CGPairs(CLJScaleFactor(1, 1)); + bool changed_atom_pair = false; + + for (int atom_i = 0; atom_i < nats_i; ++atom_i) + { + auto new_cgidx_i = cg_map.value(CGAtomIdx(i, Index(atom_i)), CGAtomIdx(i, Index(atom_i))); + + if (new_cgidx_i.isNull()) + // this atom isn't mapped, so don't copy any values + continue; + + for (int atom_j = 0; atom_j < nats_j; ++atom_j) + { + auto new_cgidx_j = cg_map.value(CGAtomIdx(j, Index(atom_j)), CGAtomIdx(j, Index(atom_j))); + + if (new_cgidx_j.isNull()) + { + // this atom isn't mapped, so don't copy any values + continue; + } + + // get the current value at the current index + const auto &scl0 = cgpairs.get(atom_i, atom_j); + + // set the new value at the new index + if (new_cgidx_i.cutGroup() == i and new_cgidx_j.cutGroup() == j) + { + // this is in the current CutGroup pair, so can set directly + new_cgpairs.set(new_cgidx_i.atom().value(), new_cgidx_j.atom().value(), scl0); + changed_atom_pair = true; + } + else + { + // this is in a completely different CutGroup pair! + ret.set(new_cgidx_i, new_cgidx_j, scl0); + } + } + } + + // save the cgpairs + if (changed_atom_pair) + { + ret.cgpairs.set(i, j, new_cgpairs); + } + } + } + + return ret; +} diff --git a/corelib/src/libs/SireMM/cljnbpairs.h b/corelib/src/libs/SireMM/cljnbpairs.h index ee6e46b5b..0a119c1b2 100644 --- a/corelib/src/libs/SireMM/cljnbpairs.h +++ b/corelib/src/libs/SireMM/cljnbpairs.h @@ -294,6 +294,17 @@ namespace SireMM QVector excludedAtoms(const AtomID &atomid) const; QHash> excludedAtoms(CGIdx cgidx) const; + + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + + protected: + SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, + const AtomMatcher &atommatcher) const; + SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, + const QHash &map) const; }; } // namespace SireMM diff --git a/corelib/src/libs/SireMM/excludedpairs.cpp b/corelib/src/libs/SireMM/excludedpairs.cpp index 581de9912..a13438941 100644 --- a/corelib/src/libs/SireMM/excludedpairs.cpp +++ b/corelib/src/libs/SireMM/excludedpairs.cpp @@ -429,3 +429,28 @@ void ExcludedPairs::setExcluded(const AtomID &atom0, const AtomID &atom1, this->excl_pairs.removeAt(idx); } } + +/** Merge this property with another property */ +PropertyList ExcludedPairs::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} diff --git a/corelib/src/libs/SireMM/excludedpairs.h b/corelib/src/libs/SireMM/excludedpairs.h index e227bed1d..40ceccab6 100644 --- a/corelib/src/libs/SireMM/excludedpairs.h +++ b/corelib/src/libs/SireMM/excludedpairs.h @@ -92,6 +92,11 @@ namespace SireMM void setExcluded(const SireMol::AtomID &atom0, const SireMol::AtomID &atom1, bool are_excluded); + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: int getIndex(qint64 atom0, qint64 atom1) const; diff --git a/corelib/src/libs/SireMM/fouratomfunctions.cpp b/corelib/src/libs/SireMM/fouratomfunctions.cpp index 182f0c0fc..220c712f7 100644 --- a/corelib/src/libs/SireMM/fouratomfunctions.cpp +++ b/corelib/src/libs/SireMM/fouratomfunctions.cpp @@ -29,12 +29,16 @@ #include "fouratomfunctions.h" +#include "SireBase/console.h" + #include "SireCAS/symbols.h" #include "SireMol/atommatcher.h" #include "SireMol/atomselection.h" #include "SireMol/moleculeinfodata.h" +#include "SireError/errors.h" + #include "SireMol/errors.h" #include "SireStream/datastream.h" @@ -492,6 +496,45 @@ void FourAtomFunctions::clear(AtomIdx atom) } } +/** Clear all functions that involve any of the atoms in 'atoms' + * - if 'exclusive' is true, then this only removes functions + * that exclusively involve these atoms - if false, then + * if removes functions that involve any of these atoms + */ +void FourAtomFunctions::clear(const QList &atoms, bool exclusive) +{ + QSet atms; + atms.reserve(atoms.count()); + + for (const auto &atom : atoms) + { + atms.insert(atom.map(info().nAtoms())); + } + + QList keys = potentials_by_atoms.keys(); + + if (exclusive) + { + for (const auto &key : keys) + { + if (atms.contains(key.atom0) and atms.contains(key.atom1) and atms.contains(key.atom2) and atms.contains(key.atom3)) + { + FourAtomFunctions::removeSymbols(potentials_by_atoms.take(key).symbols()); + } + } + } + else + { + for (const auto &key : keys) + { + if (atms.contains(key.atom0) or atms.contains(key.atom1) or atms.contains(key.atom2) or atms.contains(key.atom3)) + { + FourAtomFunctions::removeSymbols(potentials_by_atoms.take(key).symbols()); + } + } + } +} + /** Clear any function that acts on the atoms identified by 'atom' \throw SireMol::missing_atom @@ -746,6 +789,47 @@ Expression FourAtomFunctions::force(const ImproperID &improperid, const Symbol & return -(this->potential(improperid).differentiate(symbol)); } +/** Return the potential energy functions acting between the identified + atoms - if exclusive is true then only return potentials where + all atoms are in the dihedral or improper +*/ +QVector FourAtomFunctions::potentials(const QList &atms, bool exclusive) const +{ + QVector funcs; + funcs.reserve(potentials_by_atoms.count()); + + QSet atoms(atms.begin(), atms.end()); + + for (QHash::const_iterator it = potentials_by_atoms.constBegin(); + it != potentials_by_atoms.constEnd(); ++it) + { + if (exclusive) + { + if (atoms.contains(AtomIdx(it.key().atom0)) and atoms.contains(AtomIdx(it.key().atom1)) and atoms.contains(AtomIdx(it.key().atom2)) and atoms.contains(AtomIdx(it.key().atom3))) + { + funcs.append(FourAtomFunction(info().cgAtomIdx(AtomIdx(it.key().atom0)), + info().cgAtomIdx(AtomIdx(it.key().atom1)), + info().cgAtomIdx(AtomIdx(it.key().atom2)), + info().cgAtomIdx(AtomIdx(it.key().atom3)), + it.value())); + } + } + else + { + if (atoms.contains(AtomIdx(it.key().atom0)) or atoms.contains(AtomIdx(it.key().atom1)) or atoms.contains(AtomIdx(it.key().atom2)) or atoms.contains(AtomIdx(it.key().atom3))) + { + funcs.append(FourAtomFunction(info().cgAtomIdx(AtomIdx(it.key().atom0)), + info().cgAtomIdx(AtomIdx(it.key().atom1)), + info().cgAtomIdx(AtomIdx(it.key().atom2)), + info().cgAtomIdx(AtomIdx(it.key().atom3)), + it.value())); + } + } + } + + return funcs; +} + /** Return the potential energy functions acting between the identified quads of atoms */ QVector FourAtomFunctions::potentials() const @@ -914,3 +998,94 @@ const char *FourAtomFunctions::typeName() { return QMetaType::typeName(qMetaTypeId()); } + +/** Merge this property with another property */ +PropertyList FourAtomFunctions::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for dihedral/improper parameters is ignored").arg(ghost)); + } + + const FourAtomFunctions &ref = *this; + const FourAtomFunctions &pert = other.asA(); + + FourAtomFunctions prop0 = ref; + FourAtomFunctions prop1 = ref; + + // the prop1 properties are made by finding all of the atoms that + // are involved in dihedrals in 'pert' and removing any involving + // only those atoms from 'prop1', and then adding back the matching + // dihedral from 'pert'. Use 'true' to only remove angles where all + // atoms are in the mapping + prop1.clear(mapping.mappedIn1(), true); + + // get the mapping from the perturbed to reference states, including + // atoms that don't exist in the reference state. In all cases, + // the values are the indexes in the merged molecule + auto map1to0 = mapping.map1to0(true); + + // now find all of the dihedrals in 'pert' where all atoms in the + // dihedral are in map1to0.keys() - i.e. exist and are mapped from + // the perturbed state + const auto pert_dihs = pert.potentials(map1to0.keys(), true); + + for (const auto &pert_dih : pert_dihs) + { + const auto atom0 = map1to0.value(info().atomIdx(pert_dih.atom0())); + const auto atom1 = map1to0.value(info().atomIdx(pert_dih.atom1())); + const auto atom2 = map1to0.value(info().atomIdx(pert_dih.atom2())); + const auto atom3 = map1to0.value(info().atomIdx(pert_dih.atom3())); + + prop1.set(atom0, atom1, atom2, atom3, pert_dih.function()); + + if (mapping.isUnmappedIn0(atom0) or mapping.isUnmappedIn0(atom1) or mapping.isUnmappedIn0(atom2) or mapping.isUnmappedIn0(atom3)) + { + // the prop0 properties are nearly correct - we just need to add + // in dihedrals from 'pert' that involve the atoms that are not mapped + // in the reference state - this way, those added atoms are held + // by a constant dihedral potential, so won't fly away in the + // simulation of the reference state + prop0.set(atom0, atom1, atom2, atom3, pert_dih.function()); + } + } + + // now add in the dihedrals to the perturbed state from the reference + // state for any atoms that aren't mapped to the perturbed state. + // This way, the removed atoms are held by a constant potential, + // so won't fly away in the simulation of the perturbed state + auto map0to1 = mapping.map0to1(true); + + const auto ref_dihs = prop0.potentials(map0to1.keys(), true); + + for (const auto &ref_dih : ref_dihs) + { + const auto atom0 = info().atomIdx(ref_dih.atom0()); + const auto atom1 = info().atomIdx(ref_dih.atom1()); + const auto atom2 = info().atomIdx(ref_dih.atom2()); + const auto atom3 = info().atomIdx(ref_dih.atom3()); + + if (mapping.isUnmappedIn1(atom0) or mapping.isUnmappedIn1(atom1) or mapping.isUnmappedIn1(atom2) or mapping.isUnmappedIn1(atom3)) + { + prop1.set(atom0, atom1, atom2, atom3, ref_dih.function()); + } + } + + SireBase::PropertyList ret; + + ret.append(prop0); + ret.append(prop1); + + return ret; +} diff --git a/corelib/src/libs/SireMM/fouratomfunctions.h b/corelib/src/libs/SireMM/fouratomfunctions.h index 8f66d7175..ea83aa9dd 100644 --- a/corelib/src/libs/SireMM/fouratomfunctions.h +++ b/corelib/src/libs/SireMM/fouratomfunctions.h @@ -184,8 +184,6 @@ namespace SireMM QString toString() const; - int nFunctions() const; - void set(AtomIdx atom0, AtomIdx atom1, AtomIdx atom2, AtomIdx atom3, const Expression &expression); void set(const AtomID &atom0, const AtomID &atom1, const AtomID &atom2, const AtomID &atom3, @@ -203,12 +201,16 @@ namespace SireMM void clear(const DihedralID &dihedralid); void clear(const ImproperID &improperid); + void clear(const QList &atoms, bool exclusive = true); + void clear(); void substitute(const Identities &identities); bool isEmpty() const; + int nFunctions() const; + Expression potential(AtomIdx atom0, AtomIdx atom1, AtomIdx atom2, AtomIdx atom3) const; Expression potential(const AtomID &atom0, const AtomID &atom1, const AtomID &atom2, const AtomID &atom3) const; @@ -225,8 +227,15 @@ namespace SireMM QVector potentials() const; QVector forces(const Symbol &symbol) const; + QVector potentials(const QList &atoms, bool exclusive = true) const; + FourAtomFunctions includeOnly(const AtomSelection &selected_atoms, bool isstrict = true) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, const AtomMatcher &atommatcher) const; diff --git a/corelib/src/libs/SireMM/threeatomfunctions.cpp b/corelib/src/libs/SireMM/threeatomfunctions.cpp index 2d573e911..0b9f90886 100644 --- a/corelib/src/libs/SireMM/threeatomfunctions.cpp +++ b/corelib/src/libs/SireMM/threeatomfunctions.cpp @@ -29,12 +29,16 @@ #include "threeatomfunctions.h" +#include "SireBase/console.h" + #include "SireCAS/symbols.h" #include "SireMol/atommatcher.h" #include "SireMol/atomselection.h" #include "SireMol/moleculeinfodata.h" +#include "SireError/errors.h" + #include "SireMol/errors.h" #include "SireStream/datastream.h" @@ -446,6 +450,45 @@ void ThreeAtomFunctions::clear(AtomIdx atom) } } +/** Clear all functions that involve any of the atoms in 'atoms' + * - if 'exclusive' is true, then this only removes functions + * that exclusively involve these atoms - if false, then + * if removes functions that involve any of these atoms + */ +void ThreeAtomFunctions::clear(const QList &atoms, bool exclusive) +{ + QSet atms; + atms.reserve(atoms.count()); + + for (const auto &atom : atoms) + { + atms.insert(atom.map(info().nAtoms())); + } + + QList keys = potentials_by_atoms.keys(); + + if (exclusive) + { + for (const auto &key : keys) + { + if (atms.contains(key.atom0) and atms.contains(key.atom1) and atms.contains(key.atom2)) + { + ThreeAtomFunctions::removeSymbols(potentials_by_atoms.take(key).symbols()); + } + } + } + else + { + for (const auto &key : keys) + { + if (atms.contains(key.atom0) or atms.contains(key.atom1) or atms.contains(key.atom2)) + { + ThreeAtomFunctions::removeSymbols(potentials_by_atoms.take(key).symbols()); + } + } + } +} + /** Clear any function that acts on the atoms identified by 'atom' \throw SireMol::missing_atom @@ -627,6 +670,45 @@ Expression ThreeAtomFunctions::force(const AngleID &angleid, const Symbol &symbo return -(this->potential(angleid).differentiate(symbol)); } +/** Return the potential energy functions acting between the identified + atoms - if exclusive is true then only return potentials where + all atoms are in the angle +*/ +QVector ThreeAtomFunctions::potentials(const QList &atms, bool exclusive) const +{ + QVector funcs; + funcs.reserve(potentials_by_atoms.count()); + + QSet atoms(atms.begin(), atms.end()); + + for (QHash::const_iterator it = potentials_by_atoms.constBegin(); + it != potentials_by_atoms.constEnd(); ++it) + { + if (exclusive) + { + if (atoms.contains(AtomIdx(it.key().atom0)) and atoms.contains(AtomIdx(it.key().atom1)) and atoms.contains(AtomIdx(it.key().atom2))) + { + funcs.append(ThreeAtomFunction(info().cgAtomIdx(AtomIdx(it.key().atom0)), + info().cgAtomIdx(AtomIdx(it.key().atom1)), + info().cgAtomIdx(AtomIdx(it.key().atom2)), + it.value())); + } + } + else + { + if (atoms.contains(AtomIdx(it.key().atom0)) or atoms.contains(AtomIdx(it.key().atom1)) or atoms.contains(AtomIdx(it.key().atom2))) + { + funcs.append(ThreeAtomFunction(info().cgAtomIdx(AtomIdx(it.key().atom0)), + info().cgAtomIdx(AtomIdx(it.key().atom1)), + info().cgAtomIdx(AtomIdx(it.key().atom2)), + it.value())); + } + } + } + + return funcs; +} + /** Return the potential energy functions acting between the identified triples of atoms */ QVector ThreeAtomFunctions::potentials() const @@ -792,3 +874,92 @@ const char *ThreeAtomFunctions::typeName() { return QMetaType::typeName(qMetaTypeId()); } + +/** Merge this property with another property */ +PropertyList ThreeAtomFunctions::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for angle parameters is ignored").arg(ghost)); + } + + const ThreeAtomFunctions &ref = *this; + const ThreeAtomFunctions &pert = other.asA(); + + ThreeAtomFunctions prop0 = ref; + ThreeAtomFunctions prop1 = ref; + + // the prop1 properties are made by finding all of the atoms that + // are involved in angles in 'pert' and removing any angles involving + // only those atoms from 'prop1', and then adding back the matching + // angle from 'pert'. Use 'true' to only remove angles where all + // atoms are in the mapping + prop1.clear(mapping.mappedIn1(), true); + + // get the mapping from the perturbed to reference states, including + // atoms that don't exist in the reference state. In all cases, + // the values are the indexes in the merged molecule + auto map1to0 = mapping.map1to0(true); + + // now find all of the angles in 'pert' where all atoms in the + // angle are in map1to0.keys() - i.e. exist and are mapped from + // the perturbed state + const auto pert_angs = pert.potentials(map1to0.keys(), true); + + for (const auto &pert_ang : pert_angs) + { + const auto atom0 = map1to0.value(info().atomIdx(pert_ang.atom0())); + const auto atom1 = map1to0.value(info().atomIdx(pert_ang.atom1())); + const auto atom2 = map1to0.value(info().atomIdx(pert_ang.atom2())); + + prop1.set(atom0, atom1, atom2, pert_ang.function()); + + if (mapping.isUnmappedIn0(atom0) or mapping.isUnmappedIn0(atom1) or mapping.isUnmappedIn0(atom2)) + { + // the prop0 properties are nearly correct - we just need to add + // in angles from 'pert' that involve the atoms that are not mapped + // in the reference state - this way, those added atoms are held + // by a constant angle potential, so won't fly away in the + // simulation of the reference state + prop0.set(atom0, atom1, atom2, pert_ang.function()); + } + } + + // now add in the angles to the perturbed state from the reference + // state for any atoms that aren't mapped to the perturbed state. + // This way, the removed atoms are held by a constant angle potential, + // so won't fly away in the simulation of the perturbed state + auto map0to1 = mapping.map0to1(true); + + const auto ref_angs = prop0.potentials(map0to1.keys(), true); + + for (const auto &ref_ang : ref_angs) + { + const auto atom0 = info().atomIdx(ref_ang.atom0()); + const auto atom1 = info().atomIdx(ref_ang.atom1()); + const auto atom2 = info().atomIdx(ref_ang.atom2()); + + if (mapping.isUnmappedIn1(atom0) or mapping.isUnmappedIn1(atom1) or mapping.isUnmappedIn1(atom2)) + { + prop1.set(atom0, atom1, atom2, ref_ang.function()); + } + } + + SireBase::PropertyList ret; + + ret.append(prop0); + ret.append(prop1); + + return ret; +} diff --git a/corelib/src/libs/SireMM/threeatomfunctions.h b/corelib/src/libs/SireMM/threeatomfunctions.h index a6781b622..e4415b323 100644 --- a/corelib/src/libs/SireMM/threeatomfunctions.h +++ b/corelib/src/libs/SireMM/threeatomfunctions.h @@ -189,14 +189,16 @@ namespace SireMM void clear(const AtomID &atom0, const AtomID &atom1, const AtomID &atom2); void clear(const AngleID &angleid); + void clear(const QList &atoms, bool exclusive = true); + void clear(); void substitute(const Identities &identities); - int nFunctions() const; - bool isEmpty() const; + int nFunctions() const; + Expression potential(AtomIdx atom0, AtomIdx atom1, AtomIdx atom2) const; Expression potential(const AtomID &atom0, const AtomID &atom1, const AtomID &atom2) const; Expression potential(const AngleID &angleid) const; @@ -208,8 +210,15 @@ namespace SireMM QVector potentials() const; QVector forces(const Symbol &symbol) const; + QVector potentials(const QList &atoms, bool exclusive = true) const; + ThreeAtomFunctions includeOnly(const AtomSelection &selected_atoms, bool isstrict = true) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, const AtomMatcher &atommatcher) const; diff --git a/corelib/src/libs/SireMM/twoatomfunctions.cpp b/corelib/src/libs/SireMM/twoatomfunctions.cpp index a1ddbc452..9c4f91b8f 100644 --- a/corelib/src/libs/SireMM/twoatomfunctions.cpp +++ b/corelib/src/libs/SireMM/twoatomfunctions.cpp @@ -29,6 +29,8 @@ #include "twoatomfunctions.h" +#include "SireBase/console.h" + #include "SireCAS/symbols.h" #include "SireMol/atommatcher.h" @@ -427,6 +429,45 @@ void TwoAtomFunctions::clear(AtomIdx atom) } } +/** Clear all functions that invole any of the atoms in 'atoms' + * - if 'exclusive' is true, then this only removes functions + * that exclusively involve these atoms - if false, then + * if removes functions that involve any of these atoms + */ +void TwoAtomFunctions::clear(const QList &atoms, bool exclusive) +{ + QSet atms; + atms.reserve(atoms.count()); + + for (const auto &atom : atoms) + { + atms.insert(atom.map(info().nAtoms())); + } + + QList keys = potentials_by_atoms.keys(); + + if (exclusive) + { + for (const auto &key : keys) + { + if (atms.contains(key.atom0) and atms.contains(key.atom1)) + { + TwoAtomFunctions::removeSymbols(potentials_by_atoms.take(key).symbols()); + } + } + } + else + { + for (const auto &key : keys) + { + if (atms.contains(key.atom0) or atms.contains(key.atom1)) + { + TwoAtomFunctions::removeSymbols(potentials_by_atoms.take(key).symbols()); + } + } + } +} + /** Clear any function that acts on the atoms identified by 'atom' \throw SireMol::missing_atom @@ -598,6 +639,41 @@ Expression TwoAtomFunctions::force(const BondID &bondid, const Symbol &symbol) c return -(this->potential(bondid).differentiate(symbol)); } +/** Return the potential energy functions acting between the identified + pairs of atoms - if exclusive is true then only return potentials where + both atoms are in the bond +*/ +QVector TwoAtomFunctions::potentials(const QList &atms, bool exclusive) const +{ + QVector funcs; + funcs.reserve(potentials_by_atoms.count()); + + QSet atoms(atms.begin(), atms.end()); + + for (QHash::const_iterator it = potentials_by_atoms.constBegin(); + it != potentials_by_atoms.constEnd(); ++it) + { + if (exclusive) + { + if (atoms.contains(AtomIdx(it.key().atom0)) and atoms.contains(AtomIdx(it.key().atom1))) + { + funcs.append(TwoAtomFunction(info().cgAtomIdx(AtomIdx(it.key().atom0)), + info().cgAtomIdx(AtomIdx(it.key().atom1)), it.value())); + } + } + else + { + if (atoms.contains(AtomIdx(it.key().atom0)) or atoms.contains(AtomIdx(it.key().atom1))) + { + funcs.append(TwoAtomFunction(info().cgAtomIdx(AtomIdx(it.key().atom0)), + info().cgAtomIdx(AtomIdx(it.key().atom1)), it.value())); + } + } + } + + return funcs; +} + /** Return the potential energy functions acting between the identified pairs of atoms */ QVector TwoAtomFunctions::potentials() const @@ -758,3 +834,135 @@ const char *TwoAtomFunctions::typeName() { return QMetaType::typeName(qMetaTypeId()); } + +template +QSet _to_set(const QList &vals) +{ + QSet ret; + ret.reserve(vals.count()); + + for (const auto &val : vals) + { + ret.insert(val); + } + + return ret; +} + +/** Merge this property with another property */ +PropertyList TwoAtomFunctions::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for bond parameters is ignored").arg(ghost)); + } + + const TwoAtomFunctions &ref = *this; + const TwoAtomFunctions &pert = other.asA(); + + TwoAtomFunctions prop0 = ref; + TwoAtomFunctions prop1 = ref; + + // the prop1 properties are made by finding all of the atoms that + // are involved in bonds in 'pert' and removing any bonds involving + // only those atoms from 'prop1', and then adding back the matching + // bonds from 'pert'. Use 'true' to only remove bonds where both + // atoms are in the mapping + prop1.clear(mapping.mappedIn1(), true); + + // get the mapping from the perturbed to reference states, including + // atoms that don't exist in the reference state. In all cases, + // the values are the indexes in the merged molecule + auto map1to0 = mapping.map1to0(true); + + // now find all of the bonds in 'pert' where both atoms in the + // bond are in map1to0.keys() - i.e. exist and are mapped from + // the perturbed state + const auto pert_bonds = pert.potentials(map1to0.keys(), true); + + for (const auto &pert_bond : pert_bonds) + { + const auto atom0 = map1to0.value(info().atomIdx(pert_bond.atom0())); + const auto atom1 = map1to0.value(info().atomIdx(pert_bond.atom1())); + + prop1.set(atom0, atom1, pert_bond.function()); + + if (mapping.isUnmappedIn0(atom0) or mapping.isUnmappedIn0(atom1)) + { + // the prop0 properties are nearly correct - we just need to add + // in bonds from 'pert' that involve the atoms that are not mapped + // in the reference state - this way, those added atoms are held + // by a constant bond potential, so won't fly away in the + // simulation of the reference state + prop0.set(atom0, atom1, pert_bond.function()); + } + } + + // now add in the bonds to the perturbed state from the reference + // state for any atoms that aren't mapped to the perturbed state. + // This way, the removed atoms are held by a constant bond potential, + // so won't fly away in the simulation of the perturbed state + auto map0to1 = mapping.map0to1(true); + + const auto ref_bonds = prop0.potentials(map0to1.keys(), true); + + for (const auto &ref_bond : ref_bonds) + { + const auto atom0 = info().atomIdx(ref_bond.atom0()); + const auto atom1 = info().atomIdx(ref_bond.atom1()); + + if (mapping.isUnmappedIn1(atom0) or mapping.isUnmappedIn1(atom1)) + { + prop1.set(atom0, atom1, ref_bond.function()); + } + } + + // check if we are allowed to change the size of a ring or break rings + bool allow_ring_breaking = true; + bool allow_ring_size_change = true; + + if (map.specified("allow_ring_breaking")) + { + allow_ring_breaking = map["allow_ring_breaking"].value().asABoolean(); + } + + if (map.specified("allow_ring_size_change")) + { + allow_ring_size_change = map["allow_ring_size_change"].value().asABoolean(); + } + + if (not(allow_ring_breaking or allow_ring_size_change)) + { + if (prop0.nFunctions() != prop1.nFunctions()) + { + // number of bond functions has changed - this indicates + // (but not necessarily proves) that a ring has been broken + // or a ring size has changed + throw SireError::incompatible_error( + QObject::tr("The number of bonds in the reference (%1) and " + "perturbed (%2) states is different, indicating that a ring has been broken or a ring size has changed. " + "If you want to allow this perturbation, set 'allow_ring_breaking' or 'allow_ring_size_change' to true.") + .arg(prop0.nFunctions()) + .arg(prop1.nFunctions()), + CODELOC); + } + } + + SireBase::PropertyList ret; + + ret.append(prop0); + ret.append(prop1); + + return ret; +} diff --git a/corelib/src/libs/SireMM/twoatomfunctions.h b/corelib/src/libs/SireMM/twoatomfunctions.h index 2eeaf9ea3..cc6d1cfee 100644 --- a/corelib/src/libs/SireMM/twoatomfunctions.h +++ b/corelib/src/libs/SireMM/twoatomfunctions.h @@ -181,6 +181,8 @@ namespace SireMM void clear(const AtomID &atom0, const AtomID &atom1); void clear(const BondID &bondid); + void clear(const QList &atoms, bool exclusive = true); + void clear(); void substitute(const Identities &identities); @@ -200,8 +202,15 @@ namespace SireMM QVector potentials() const; QVector forces(const Symbol &symbol) const; + QVector potentials(const QList &atoms, bool exclusive = true) const; + TwoAtomFunctions includeOnly(const AtomSelection &selection, bool isstrict = true) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, const AtomMatcher &atommatcher) const; diff --git a/corelib/src/libs/SireMol/CMakeLists.txt b/corelib/src/libs/SireMol/CMakeLists.txt index 75decba70..9d725e90a 100644 --- a/corelib/src/libs/SireMol/CMakeLists.txt +++ b/corelib/src/libs/SireMol/CMakeLists.txt @@ -29,6 +29,7 @@ set ( SIREMOL_HEADERS atomidcombos.h atomidentifier.h atomidx.h + atomidxmapping.h atommapping.h atommasses.h atommatch.h @@ -88,6 +89,7 @@ set ( SIREMOL_HEADERS improperid.h iswater.h geometryperturbation.h + getghostparam.hpp getrmsd.h groupatomids.h groupgroupids.h @@ -169,10 +171,11 @@ set ( SIREMOL_SOURCES angleid.cpp atom.cpp atomcoords.cpp + atomcutting.cpp atomeditor.cpp atomid.cpp atomidentifier.cpp - atomcutting.cpp + atomidxmapping.cpp atommapping.cpp atommatch.cpp atommatcher.cpp diff --git a/corelib/src/libs/SireMol/amberparameters.cpp b/corelib/src/libs/SireMol/amberparameters.cpp index 5c656b4c7..6e112227d 100644 --- a/corelib/src/libs/SireMol/amberparameters.cpp +++ b/corelib/src/libs/SireMol/amberparameters.cpp @@ -34,11 +34,15 @@ #include "SireMol/improperid.h" #include "SireMol/molecule.h" #include "SireMol/partialmolecule.h" +#include "SireMol/atomidxmapping.h" + +#include "SireError/errors.h" #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" using namespace SireMol; +using namespace SireBase; using namespace SireStream; /////////// @@ -317,3 +321,13 @@ QList AmberParameters::getAll14Pairs() { return nb14pairs.keys(); } + +PropertyList AmberParameters::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + throw SireError::incomplete_code(QObject::tr( + "AmberParameters::merge() is not implemented yet!"), + CODELOC); +} diff --git a/corelib/src/libs/SireMol/amberparameters.h b/corelib/src/libs/SireMol/amberparameters.h index 7be7a9321..89fe20c53 100644 --- a/corelib/src/libs/SireMol/amberparameters.h +++ b/corelib/src/libs/SireMol/amberparameters.h @@ -39,6 +39,7 @@ #include "SireMol/molviewproperty.h" #include "SireMol/mover.hpp" #include "SireMol/partialmolecule.h" +#include "SireMol/atomidxmapping.h" SIRE_BEGIN_HEADER @@ -125,6 +126,11 @@ namespace SireMol QList get14PairParams(const BondID &pair); QList getAll14Pairs(); + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The molecule that this flexibility operates on */ SireBase::SharedDataPointer molinfo; diff --git a/corelib/src/libs/SireMol/atom.cpp b/corelib/src/libs/SireMol/atom.cpp index 4c50d97d3..6aa637805 100644 --- a/corelib/src/libs/SireMol/atom.cpp +++ b/corelib/src/libs/SireMol/atom.cpp @@ -213,6 +213,12 @@ AtomName Atom::name() const return d->info().name(atomidx); } +/** Return the alternate name of the atom */ +AtomName Atom::alternateName() const +{ + return d->getAlternateAtomName(atomidx); +} + /** Return the number of the atom */ AtomNum Atom::number() const { diff --git a/corelib/src/libs/SireMol/atom.h b/corelib/src/libs/SireMol/atom.h index a000bcf0e..084541306 100644 --- a/corelib/src/libs/SireMol/atom.h +++ b/corelib/src/libs/SireMol/atom.h @@ -130,6 +130,8 @@ namespace SireMol AtomIdx index() const; const CGAtomIdx &cgAtomIdx() const; + AtomName alternateName() const; + bool hasProperty(const PropertyName &key) const; bool hasMetadata(const PropertyName &metakey) const; bool hasMetadata(const PropertyName &key, const PropertyName &metakey) const; diff --git a/corelib/src/libs/SireMol/atomcoords.cpp b/corelib/src/libs/SireMol/atomcoords.cpp index 860e022bd..0f527a9b8 100644 --- a/corelib/src/libs/SireMol/atomcoords.cpp +++ b/corelib/src/libs/SireMol/atomcoords.cpp @@ -33,6 +33,7 @@ #include "SireVol/space.h" +#include "SireBase/console.h" #include "SireBase/quickcopy.hpp" #include "SireMaths/vectorproperty.h" @@ -1031,3 +1032,54 @@ AtomProperty *AtomCoords::clone() const { return new AtomProperty(*this); } + +PropertyList AtomCoords::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + const AtomCoords &ref = *this; + const AtomCoords &pert = other.asA(); + + AtomCoords prop0 = ref; + AtomCoords prop1 = ref; + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for LJ parameters is ignored").arg(ghost)); + } + + for (const auto &index : mapping) + { + if (index.isUnmappedIn0()) + { + // use the coordinates of the perturbed state + prop0.set(index.cgAtomIdx0(), pert.get(index.cgAtomIdx1())); + } + + if (index.isUnmappedIn1()) + { + // use the coordinates of the reference state + prop1.set(index.cgAtomIdx0(), prop0.get(index.cgAtomIdx0())); + } + else + { + // we can use the coordinates of the perturbed state + prop1.set(index.cgAtomIdx0(), pert.get(index.cgAtomIdx1())); + } + } + + SireBase::PropertyList ret; + ret.append(prop0); + ret.append(prop1); + + return ret; +} diff --git a/corelib/src/libs/SireMol/atomcoords.h b/corelib/src/libs/SireMol/atomcoords.h index 06eb8aa7c..8c21da8a0 100644 --- a/corelib/src/libs/SireMol/atomcoords.h +++ b/corelib/src/libs/SireMol/atomcoords.h @@ -196,6 +196,11 @@ namespace SireMol void assertCanConvert(const QVariant &value) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual atomic coordinates, arranged into CoordGroups */ CoordGroupArray coords; diff --git a/corelib/src/libs/SireMol/atomeditor.cpp b/corelib/src/libs/SireMol/atomeditor.cpp index 33c7de4f4..d810d4311 100644 --- a/corelib/src/libs/SireMol/atomeditor.cpp +++ b/corelib/src/libs/SireMol/atomeditor.cpp @@ -133,6 +133,30 @@ QString AtomEditor::toString() const return QObject::tr("Editor{ %1 }").arg(Atom::toString()); } +/** Return the alternate name for this atom */ +AtomName AtomEditor::alternateName() const +{ + return d->getAlternateAtomName(this->index()); +} + +/** Set the alternate name for this atom */ +AtomEditor &AtomEditor::setAlternateName(const AtomName &newname) +{ + if (newname == this->alternateName()) + // nothing needs to be done + return *this; + + d->setAlternateAtomName(this->index(), newname); + + return *this; +} + +/** Set the alternate name for this atom */ +AtomEditor &AtomEditor::setAlternateName(const QString &newname) +{ + return this->setAlternateName(AtomName(newname)); +} + /** Rename this atom so that it is called 'newname' */ AtomEditor &AtomEditor::rename(const AtomName &newname) { @@ -145,6 +169,12 @@ AtomEditor &AtomEditor::rename(const AtomName &newname) return *this; } +/** Rename this atom */ +AtomEditor &AtomEditor::rename(const QString &newname) +{ + return this->rename(AtomName(newname)); +} + /** Renumber this atom so that it has number 'newnum' */ AtomEditor &AtomEditor::renumber(AtomNum newnum) { @@ -157,6 +187,12 @@ AtomEditor &AtomEditor::renumber(AtomNum newnum) return *this; } +/** Renumber this atom */ +AtomEditor &AtomEditor::renumber(int newnum) +{ + return this->renumber(AtomNum(newnum)); +} + /** Reindex this atom so that it lies at index 'newidx'. Note that if 'newidx' is greater than the number of atoms, then this will move this atom to be the last in the list */ @@ -167,6 +203,12 @@ AtomStructureEditor AtomEditor::reindex(AtomIdx newidx) const return editor; } +/** Reindex this atom */ +AtomStructureEditor AtomEditor::reindex(int newidx) const +{ + return this->reindex(AtomIdx(newidx)); +} + /** Remove this atom from the molecule, returning an editor that can further edit the structure of the molecule */ MolStructureEditor AtomEditor::remove() const @@ -412,6 +454,25 @@ MolStructureEditor AtomStructureEditor::molecule() return MolStructureEditor(*this); } +/** Return the alternate name for this atom */ +const AtomName &AtomStructureEditor::alternateName() const +{ + return StructureEditor::getAlternateAtomName(uid); +} + +/** Set the alternate name for this atom */ +AtomStructureEditor &AtomStructureEditor::setAlternateName(const AtomName &newname) +{ + StructureEditor::setAlternateAtomName(uid, newname); + return *this; +} + +/** Set the alternate name for this atom */ +AtomStructureEditor &AtomStructureEditor::setAlternateName(const QString &newname) +{ + return this->setAlternateName(AtomName(newname)); +} + /** Rename this atom to 'newname' */ AtomStructureEditor &AtomStructureEditor::rename(const AtomName &newname) { @@ -419,6 +480,12 @@ AtomStructureEditor &AtomStructureEditor::rename(const AtomName &newname) return *this; } +/** Rename this atom */ +AtomStructureEditor &AtomStructureEditor::rename(const QString &newname) +{ + return this->rename(AtomName(newname)); +} + /** Renumber this atom to 'newnum' */ AtomStructureEditor &AtomStructureEditor::renumber(AtomNum newnum) { @@ -426,6 +493,12 @@ AtomStructureEditor &AtomStructureEditor::renumber(AtomNum newnum) return *this; } +/** Renumber this atom */ +AtomStructureEditor &AtomStructureEditor::renumber(int newnum) +{ + return this->renumber(AtomNum(newnum)); +} + /** Reindex this atom to 'newidx' - this will move the atom to the end if 'newidx' is greater than the number of atoms in the molecule */ @@ -435,6 +508,12 @@ AtomStructureEditor &AtomStructureEditor::reindex(AtomIdx newidx) return *this; } +/** Reindex this atom */ +AtomStructureEditor &AtomStructureEditor::reindex(int newidx) +{ + return this->reindex(AtomIdx(newidx)); +} + /** Completely remove this atom from the molecule and return a MolStructureEditor that can be used to continue editing the molecule */ diff --git a/corelib/src/libs/SireMol/atomeditor.h b/corelib/src/libs/SireMol/atomeditor.h index e26044c72..9a3e248e9 100644 --- a/corelib/src/libs/SireMol/atomeditor.h +++ b/corelib/src/libs/SireMol/atomeditor.h @@ -109,7 +109,16 @@ namespace SireMol AtomEditor &rename(const AtomName &name); AtomEditor &renumber(AtomNum number); + AtomEditor &rename(const QString &name); + AtomEditor &renumber(int number); + AtomStructureEditor reindex(AtomIdx atomidx) const; + AtomStructureEditor reindex(int atomidx) const; + + AtomEditor &setAlternateName(const QString &name); + AtomEditor &setAlternateName(const AtomName &name); + + AtomName alternateName() const; MolStructureEditor remove() const; @@ -170,6 +179,10 @@ namespace SireMol AtomNum number() const; AtomIdx index() const; + AtomStructureEditor &rename(const QString &name); + AtomStructureEditor &renumber(int number); + AtomStructureEditor &reindex(int idx); + AtomStructureEditor &rename(const AtomName &name); AtomStructureEditor &renumber(AtomNum number); AtomStructureEditor &reindex(AtomIdx idx); @@ -185,6 +198,11 @@ namespace SireMol AtomStructureEditor &reparent(SegIdx segidx); AtomStructureEditor &reparent(const SegID &segid); + AtomStructureEditor &setAlternateName(const QString &name); + AtomStructureEditor &setAlternateName(const AtomName &name); + + const AtomName &alternateName() const; + template T property(const QString &key) const; diff --git a/corelib/src/libs/SireMol/atomidxmapping.cpp b/corelib/src/libs/SireMol/atomidxmapping.cpp new file mode 100644 index 000000000..f8b1cd9f7 --- /dev/null +++ b/corelib/src/libs/SireMol/atomidxmapping.cpp @@ -0,0 +1,936 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#include "atomidxmapping.h" + +#include "moleculeinfodata.h" + +#include "SireID/index.h" + +#include "SireError/errors.h" +#include "SireMol/errors.h" + +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" + +using namespace SireMol; +using namespace SireBase; +using namespace SireStream; + +//////// +//////// Implementation of AtomIdxMappingEntry +//////// + +RegisterMetaType r_entry(NO_ROOT); + +QDataStream &operator<<(QDataStream &ds, const AtomIdxMappingEntry &entry) +{ + writeHeader(ds, r_entry, 1); + + SharedDataStream sds(ds); + + sds << entry.atomidx0 << entry.atomidx1 + << entry.cgatomidx0 << entry.cgatomidx1 + << entry.unmapped0; + + return ds; +} + +QDataStream &operator>>(QDataStream &ds, AtomIdxMappingEntry &entry) +{ + auto v = readHeader(ds, r_entry); + + if (v == 1) + { + SharedDataStream sds(ds); + + sds >> entry.atomidx0 >> entry.atomidx1 >> entry.cgatomidx0 >> entry.cgatomidx1 >> entry.unmapped0; + } + else + throw SireStream::version_error(v, "1", r_entry, CODELOC); + + return ds; +} + +/** Null constructor */ +AtomIdxMappingEntry::AtomIdxMappingEntry() + : atomidx0(), atomidx1(), cgatomidx0(), cgatomidx1(), unmapped0(false) +{ +} + +/** Construct to map from 'index0' in 'molinfo0' to 'index1' in 'molinfo1'. + * There is no mapping in the perturbed state if 'index1' is null. There + * is no mapping in the reference state if 'is_unmapped_in_reference' is true. + * It is an error to have 'index0' null, or if you cannot look up + * 'index0' in 'molinfo0' or 'index1' in 'molinfo1'. + */ +AtomIdxMappingEntry::AtomIdxMappingEntry(const AtomIdx &index0, const AtomIdx &index1, + const MoleculeInfoData &molinfo0, + const MoleculeInfoData &molinfo1, + bool is_unmapped_in_reference) + : atomidx0(index0), atomidx1(index1), unmapped0(is_unmapped_in_reference) +{ + if (atomidx0.isNull()) + { + throw SireError::incompatible_error(QObject::tr("The atom index in the reference state is null!"), CODELOC); + } + + cgatomidx0 = molinfo0.cgAtomIdx(atomidx0); + + if (not atomidx1.isNull()) + { + cgatomidx1 = molinfo1.cgAtomIdx(atomidx1); + } +} + +/** Copy constructor */ +AtomIdxMappingEntry::AtomIdxMappingEntry(const AtomIdxMappingEntry &other) + : atomidx0(other.atomidx0), atomidx1(other.atomidx1), + cgatomidx0(other.cgatomidx0), cgatomidx1(other.cgatomidx1), + unmapped0(other.unmapped0) +{ +} + +/** Destructor */ +AtomIdxMappingEntry::~AtomIdxMappingEntry() +{ +} + +/** Assignment operator */ +AtomIdxMappingEntry &AtomIdxMappingEntry::operator=(const AtomIdxMappingEntry &other) +{ + if (this != &other) + { + atomidx0 = other.atomidx0; + atomidx1 = other.atomidx1; + cgatomidx0 = other.cgatomidx0; + cgatomidx1 = other.cgatomidx1; + unmapped0 = other.unmapped0; + } + + return *this; +} + +/** Equality operator */ +bool AtomIdxMappingEntry::operator==(const AtomIdxMappingEntry &other) const +{ + return atomidx0 == other.atomidx0 and atomidx1 == other.atomidx1 and + cgatomidx0 == other.cgatomidx0 and cgatomidx1 == other.cgatomidx1 and + unmapped0 == other.unmapped0; +} + +/** Inequality operator */ +bool AtomIdxMappingEntry::operator!=(const AtomIdxMappingEntry &other) const +{ + return not this->operator==(other); +} + +/** Clone this object */ +AtomIdxMappingEntry *AtomIdxMappingEntry::clone() const +{ + return new AtomIdxMappingEntry(*this); +} + +/** Return whether or not this is a null entry */ +bool AtomIdxMappingEntry::isNull() const +{ + return atomidx0.isNull(); +} + +/** Convert this object to a string */ +QString AtomIdxMappingEntry::toString() const +{ + if (this->isNull()) + { + return QString("AtomIdxMappingEntry: null"); + } + else if (this->isUnmappedIn0()) + { + return QString("%1 unmapped -> %2").arg(this->atomIdx0().value()).arg(this->atomIdx1().value()); + } + else if (this->isUnmappedIn1()) + { + return QString("%1 -> unmapped").arg(this->atomIdx0().value()); + } + else + { + return QString("%1 -> %2").arg(this->atomIdx0().value()).arg(this->atomIdx1().value()); + } +} + +const char *AtomIdxMappingEntry::typeName() +{ + return QMetaType::typeName(qMetaTypeId()); +} + +const char *AtomIdxMappingEntry::what() const +{ + return AtomIdxMappingEntry::typeName(); +} + +/** Return whether or not this atom is unmapped in the reference state */ +bool AtomIdxMappingEntry::isUnmappedIn0() const +{ + return unmapped0; +} + +/** Return whether or not this atom is unmapped in the perturbed state */ +bool AtomIdxMappingEntry::isUnmappedIn1() const +{ + return atomidx1.isNull(); +} + +/** Return whether or not this atom is mapped in the reference state */ +bool AtomIdxMappingEntry::isMappedIn0() const +{ + return not unmapped0; +} + +/** Return whether or not this atom is mapped in the perturbed state */ +bool AtomIdxMappingEntry::isMappedIn1() const +{ + return not atomidx1.isNull(); +} + +/** Return whether or not this atom is unmapped in both end states */ +bool AtomIdxMappingEntry::isUnmappedInBoth() const +{ + return this->isUnmappedIn0() and this->isUnmappedIn1(); +} + +/** Return whether or not this atom is mapped in both end states */ +bool AtomIdxMappingEntry::isMappedInBoth() const +{ + return this->isMappedIn0() and this->isMappedIn1(); +} + +/** Return the atom index in the reference state. This will always have + * a value, even if the atom is unmapped in the reference state + * (this signals that any parameter with this index should be zero) + */ +AtomIdx AtomIdxMappingEntry::atomIdx0() const +{ + return atomidx0; +} + +/** Return the atom index in the perturbed state, or a null index if + * the atom is unmapped in the perturbed state */ +AtomIdx AtomIdxMappingEntry::atomIdx1() const +{ + return atomidx1; +} + +/** Return the atom index in the reference state. This will always have + * a value, even if the atom is unmapped in the reference state + * (this signals that any parameter with this index should be zero) + */ +CGAtomIdx AtomIdxMappingEntry::cgAtomIdx0() const +{ + return cgatomidx0; +} + +/** Return the atom index in the perturbed state, or a null index if + * the atom is unmapped in the perturbed state */ +CGAtomIdx AtomIdxMappingEntry::cgAtomIdx1() const +{ + return cgatomidx1; +} + +//////// +//////// Implementation of AtomIdxMapping +//////// + +RegisterMetaType r_mapping; + +QDataStream &operator<<(QDataStream &ds, const AtomIdxMapping &mapping) +{ + writeHeader(ds, r_mapping, 1); + + SharedDataStream sds(ds); + + sds << mapping.entries << static_cast(mapping); + + return ds; +} + +QDataStream &operator>>(QDataStream &ds, AtomIdxMapping &mapping) +{ + auto v = readHeader(ds, r_mapping); + + if (v == 1) + { + SharedDataStream sds(ds); + + sds >> mapping.entries >> static_cast(mapping); + + mapping.rebuild(); + } + else + throw SireStream::version_error(v, "1", r_mapping, CODELOC); + + return ds; +} + +/** Null constructor */ +AtomIdxMapping::AtomIdxMapping() + : ConcreteProperty() +{ +} + +/** Construct from a single entry */ +AtomIdxMapping::AtomIdxMapping(const AtomIdxMappingEntry &entry) + : ConcreteProperty() +{ + if (not entry.isNull()) + entries.append(entry); + + this->rebuild(); +} + +/** Assert that this object is sane */ +void AtomIdxMapping::assertSane() const +{ + QHash seen_0, seen_1; + seen_0.reserve(entries.size()); + seen_1.reserve(entries.size()); + + for (const auto &entry : entries) + { + if (entry.isNull()) + { + throw SireError::incompatible_error(QObject::tr("The AtomIdxMapping contains a null entry!"), CODELOC); + } + else if (seen_0.contains(entry.atomIdx0().value()) or + (entry.isMappedIn1() and seen_1.contains(entry.atomIdx1().value()))) + { + throw SireError::incompatible_error(QObject::tr("The AtomIdxMapping contains a duplicate entry (%1 vs %2)!") + .arg(entry.toString()) + .arg(seen_0[entry.atomIdx0().value()].toString()), + CODELOC); + } + else + { + seen_0.insert(entry.atomIdx0().value(), entry); + + if (entry.isMappedIn1()) + seen_1.insert(entry.atomIdx1().value(), entry); + } + } +} + +/** Construct from a list of entries */ +AtomIdxMapping::AtomIdxMapping(const QList &e) + : ConcreteProperty() +{ + bool any_null = false; + + for (const auto &entry : e) + { + if (entry.isNull()) + { + any_null = true; + break; + } + } + + if (not any_null) + { + entries = e; + } + else + { + for (const auto &entry : e) + { + if (not entry.isNull()) + { + entries.append(entry); + } + } + } + + this->assertSane(); + this->rebuild(); +} + +/** Copy constructor */ +AtomIdxMapping::AtomIdxMapping(const AtomIdxMapping &other) + : ConcreteProperty(other), + entries(other.entries), + unmapped0_set(other.unmapped0_set), unmapped1_set(other.unmapped1_set), + unmapped0_list(other.unmapped0_list), unmapped1_list(other.unmapped1_list), + mapped0_list(other.mapped0_list), mapped1_list(other.mapped1_list), + map0_to_1_inc(other.map0_to_1_inc), map1_to_0_inc(other.map1_to_0_inc), + map0_to_1_exc(other.map0_to_1_exc), map1_to_0_exc(other.map1_to_0_exc) +{ +} + +/** Destructor */ +AtomIdxMapping::~AtomIdxMapping() +{ +} + +/** Assignment operator */ +AtomIdxMapping &AtomIdxMapping::operator=(const AtomIdxMapping &other) +{ + if (this != &other) + { + entries = other.entries; + unmapped0_set = other.unmapped0_set; + unmapped1_set = other.unmapped1_set; + unmapped0_list = other.unmapped0_list; + unmapped1_list = other.unmapped1_list; + mapped0_list = other.mapped0_list; + mapped1_list = other.mapped1_list; + map0_to_1_inc = other.map0_to_1_inc; + map1_to_0_inc = other.map1_to_0_inc; + map0_to_1_exc = other.map0_to_1_exc; + map1_to_0_exc = other.map1_to_0_exc; + + Property::operator=(other); + } + + return *this; +} + +/** Equality operator */ +bool AtomIdxMapping::operator==(const AtomIdxMapping &other) const +{ + return entries == other.entries and Property::operator==(other); +} + +/** Inequality operator */ +bool AtomIdxMapping::operator!=(const AtomIdxMapping &other) const +{ + return not this->operator==(other); +} + +/** Clone this object */ +AtomIdxMapping *AtomIdxMapping::clone() const +{ + return new AtomIdxMapping(*this); +} + +/** Convert this object to a string */ +QString AtomIdxMapping::toString() const +{ + if (this->isEmpty()) + { + return QObject::tr("AtomIdxMapping::empty"); + } + else + { + QStringList parts; + + const auto n = this->count(); + + if (n <= 10) + { + for (int i = 0; i < n; ++i) + { + parts.append(QObject::tr("%1: %2").arg(i).arg(this->operator[](i).toString())); + } + } + else + { + for (int i = 0; i < 5; ++i) + { + parts.append(QObject::tr("%1: %2").arg(i).arg(this->operator[](i).toString())); + } + + parts.append("..."); + + for (int i = n - 5; i < n; ++i) + { + parts.append(QObject::tr("%1: %2").arg(i).arg(this->operator[](i).toString())); + } + } + + return QObject::tr("AtomIdxMapping( size=%2\n%3\n)").arg(n).arg(parts.join("\n")); + } +} + +const char *AtomIdxMapping::typeName() +{ + return QMetaType::typeName(qMetaTypeId()); +} + +const char *AtomIdxMapping::what() const +{ + return AtomIdxMapping::typeName(); +} + +/** Add another mapping to this one */ +AtomIdxMapping &AtomIdxMapping::operator+=(const AtomIdxMapping &other) +{ + this->append(other); + return *this; +} + +/** Add another mapping to this one */ +AtomIdxMapping &AtomIdxMapping::operator+=(const AtomIdxMappingEntry &entry) +{ + this->append(entry); + return *this; +} + +/** Add another mapping to this one */ +AtomIdxMapping AtomIdxMapping::operator+(const AtomIdxMapping &other) const +{ + AtomIdxMapping result(*this); + result += other; + return result; +} + +/** Add another mapping to this one */ +AtomIdxMapping AtomIdxMapping::operator+(const AtomIdxMappingEntry &entry) const +{ + AtomIdxMapping result(*this); + result += entry; + return result; +} + +/** Return an iterator to the beginning of the list */ +QList::const_iterator AtomIdxMapping::begin() const +{ + return entries.begin(); +} + +/** Return an iterator to the beginning of the list */ +QList::const_iterator AtomIdxMapping::constBegin() const +{ + return entries.constBegin(); +} + +/** Return an iterator to the end of the list */ +QList::const_iterator AtomIdxMapping::end() const +{ + return entries.end(); +} + +/** Return an iterator to the end of the list */ +QList::const_iterator AtomIdxMapping::constEnd() const +{ + return entries.constEnd(); +} + +/** Find an entry in the list */ +QList::const_iterator AtomIdxMapping::find(AtomIdx atom) const +{ + return std::find_if(entries.constBegin(), entries.constEnd(), [atom](const AtomIdxMappingEntry &entry) + { return entry.atomIdx0() == atom; }); +} + +/** Find an entry in the list */ +QList::const_iterator AtomIdxMapping::find(CGAtomIdx atom) const +{ + return std::find_if(entries.constBegin(), entries.constEnd(), [atom](const AtomIdxMappingEntry &entry) + { return entry.cgAtomIdx0() == atom; }); +} + +/** Append an entry to the list */ +void AtomIdxMapping::append(const AtomIdxMappingEntry &new_entry) +{ + if (new_entry.isNull()) + return; + + for (const auto &entry : entries) + { + if (entry.atomIdx0() == new_entry.atomIdx0()) + { + throw SireError::incompatible_error(QObject::tr("The AtomIdxMapping already contains an entry for atom %1!") + .arg(new_entry.atomIdx0().value()), + CODELOC); + } + } + + entries.append(new_entry); + this->rebuild(); +} + +/** Append all of the passed entries of other onto this list */ +void AtomIdxMapping::append(const AtomIdxMapping &other) +{ + AtomIdxMapping ret(*this); + + for (const auto &entry : other.entries) + { + ret.append(entry); + } + + ret.rebuild(); + + *this = ret; +} + +/** Clear the list */ +void AtomIdxMapping::clear() +{ + entries.clear(); + this->rebuild(); +} + +/** Return whether or not the list is empty */ +bool AtomIdxMapping::isEmpty() const +{ + return entries.isEmpty(); +} + +/** Return the size of the list */ +int AtomIdxMapping::size() const +{ + return entries.size(); +} + +/** Return the count of the list */ +int AtomIdxMapping::count() const +{ + return entries.count(); +} + +/** Return the entry at index 'i' */ +const AtomIdxMappingEntry &AtomIdxMapping::operator[](int i) const +{ + i = SireID::Index(i).map(entries.size()); + return entries[i]; +} + +/** Take the entry at index 'i' */ +AtomIdxMappingEntry AtomIdxMapping::take(int i) +{ + i = SireID::Index(i).map(entries.size()); + auto entry = entries.takeAt(i); + this->rebuild(); + return entry; +} + +/** Take the entry for atom 'atom' */ +AtomIdxMappingEntry AtomIdxMapping::take(const AtomIdx &atom) +{ + auto it = this->find(atom); + + if (it != this->constEnd()) + { + return this->take(std::distance(this->constBegin(), it)); + } + else + { + throw SireMol::missing_atom(QObject::tr( + "The AtomIdxMapping does not contain an entry for atom %1!") + .arg(atom.toString()), + CODELOC); + + return AtomIdxMappingEntry(); + } +} + +/** Take the entry for atom 'atom' */ +AtomIdxMappingEntry AtomIdxMapping::take(const CGAtomIdx &atom) +{ + auto it = this->find(atom); + + if (it != this->constEnd()) + { + return this->take(std::distance(this->constBegin(), it)); + } + else + { + throw SireMol::missing_atom(QObject::tr( + "The AtomIdxMapping does not contain an entry for atom %1!") + .arg(atom.toString()), + CODELOC); + + return AtomIdxMappingEntry(); + } +} + +/** Remove the entry at index 'i' */ +void AtomIdxMapping::remove(int i) +{ + i = SireID::Index(i).map(entries.size()); + entries.removeAt(i); + this->rebuild(); +} + +/** Remove the entry for atom 'atom' */ +void AtomIdxMapping::remove(const AtomIdx &atom) +{ + auto it = this->find(atom); + + if (it != this->constEnd()) + { + this->remove(std::distance(this->constBegin(), it)); + } +} + +/** Remove the entry for atom 'atom' */ +void AtomIdxMapping::remove(const CGAtomIdx &atom) +{ + auto it = this->find(atom); + + if (it != this->constEnd()) + { + this->remove(std::distance(this->constBegin(), it)); + } +} + +void AtomIdxMapping::rebuild() +{ + unmapped0_set.clear(); + unmapped1_set.clear(); + unmapped0_list.clear(); + unmapped1_list.clear(); + mapped0_list.clear(); + mapped1_list.clear(); + map0_to_1_inc.clear(); + map1_to_0_inc.clear(); + map0_to_1_exc.clear(); + map1_to_0_exc.clear(); + + for (const auto &entry : entries) + { + if (entry.isMappedIn0()) + { + mapped0_list.append(entry.atomIdx0()); + } + else + { + unmapped0_set.insert(entry.atomIdx0()); + unmapped0_list.append(entry.atomIdx0()); + } + + if (entry.isMappedIn1()) + { + mapped1_list.append(entry.atomIdx0()); + } + else + { + unmapped1_set.insert(entry.atomIdx0()); + unmapped1_list.append(entry.atomIdx0()); + } + + if (entry.isMappedIn0() and entry.isMappedIn1()) + { + map0_to_1_inc.insert(entry.atomIdx0(), entry.atomIdx1()); + map1_to_0_inc.insert(entry.atomIdx1(), entry.atomIdx0()); + map0_to_1_exc.insert(entry.atomIdx0(), entry.atomIdx1()); + map1_to_0_exc.insert(entry.atomIdx1(), entry.atomIdx0()); + } + else if (entry.isMappedIn0()) + { + if (not entry.atomIdx0().isNull()) + { + map0_to_1_inc.insert(entry.atomIdx0(), entry.atomIdx1()); + map0_to_1_exc.insert(entry.atomIdx0(), entry.atomIdx1()); + } + } + else if (entry.isMappedIn1()) + { + if (not entry.atomIdx1().isNull()) + { + map1_to_0_inc.insert(entry.atomIdx1(), entry.atomIdx0()); + map1_to_0_exc.insert(entry.atomIdx1(), entry.atomIdx0()); + } + } + } +} + +/** Return the indexes, in the merged molecule, of atoms that + * are not mapped in the reference state (i.e. they only exist + * in the perturbed state). Note - these are the indicies of these + * atoms in the merged molecule, not the perturbed molecule. + */ +QList AtomIdxMapping::unmappedIn0() const +{ + return unmapped0_list; +} + +/** Return the indexes, in the merged molecule, of atoms that + * are not mapped in the perturbed state (i.e. they only exist + * in the reference state). Note - these are the indicies of these + * atoms in the merged molecule, not the reference molecule. + */ +QList AtomIdxMapping::unmappedIn1() const +{ + return unmapped1_list; +} + +/** Return the indexes, in the merged molecule, of atoms that + * are mapped in the reference state (i.e. they exist in the + * reference state, regardless of whether or not they exist + * in the perturbed state). Note - these are the indicies of + * these atoms in the merged molecule, not the reference molecule. + */ +QList AtomIdxMapping::mappedIn0() const +{ + return mapped0_list; +} + +/** Return the indexes, in the merged molecule, of atoms that + * are mapped in the perturbed state (i.e. they exist in the + * perturbed state, regardless of whether or not they exist + * in the reference state). Note - these are the indicies of + * these atoms in the merged molecule, not the perturbed molecule. + */ +QList AtomIdxMapping::mappedIn1() const +{ + return mapped1_list; +} + +/** Equivalent of unmappedIn0, but return as a CGAtomIdx */ +QList AtomIdxMapping::unmappedCGAtomIdxIn0() const +{ + QList result; + + for (const auto &entry : entries) + { + if (entry.isUnmappedIn0()) + { + result.append(entry.cgAtomIdx0()); + } + } + + return result; +} + +/** Equivalent of unmappedIn1, but return as a CGAtomIdx */ +QList AtomIdxMapping::unmappedCGAtomIdxIn1() const +{ + QList result; + + for (const auto &entry : entries) + { + if (entry.isUnmappedIn1()) + { + result.append(entry.cgAtomIdx0()); + } + } + + return result; +} + +/** Equivalent of mappedIn0, but return as a CGAtomIdx */ +QList AtomIdxMapping::mappedCGAtomIdxIn0() const +{ + QList result; + + for (const auto &entry : entries) + { + if (entry.isMappedIn0()) + { + result.append(entry.cgAtomIdx0()); + } + } + + return result; +} + +/** Equivalent of mappedIn1, but return as a CGAtomIdx */ +QList AtomIdxMapping::mappedCGAtomIdxIn1() const +{ + QList result; + + for (const auto &entry : entries) + { + if (entry.isMappedIn1()) + { + result.append(entry.cgAtomIdx0()); + } + } + + return result; +} + +/** Return the mapping for the atoms that exist in both the reference + * and perturbed states, from the index of the atom in the merged + * molecule to the index of the atom in the perturbed molecule. + * Note - the reference index is the index in the merged molecule. + * + * If 'include_unmapped' is true, then also include atoms that are + * unmapped in either end state. In these cases, the reference index + * will be the index in the merged molecule (so will always be valid) + * but the perturbed index will be null for atoms that are unmapped + * in the perturbed state. + */ +QHash AtomIdxMapping::map0to1(bool include_unmapped) const +{ + if (include_unmapped) + { + return map0_to_1_inc; + } + else + { + return map0_to_1_exc; + } +} + +/** Return the mapping for the atoms that exist in both the reference + * and perturbed states, from the index of the atom in the perturbed + * molecule to the index of the atom in the merged molecule. + * Note - the reference index is the index in the merged molecule. + * + * If 'include_unmapped' is true, then also include atoms that are + * unmapped in either end state. In these cases, the reference index + * will be the index in the merged molecule (so will always be valid) + * and atoms that are unmapped in the perturbed state are not + * included in the returned dictionary. + */ +QHash AtomIdxMapping::map1to0(bool include_unmapped) const +{ + if (include_unmapped) + { + return map1_to_0_inc; + } + else + { + return map1_to_0_exc; + } +} + +/** Return whether or not this atom is mapped in the reference state */ +bool AtomIdxMapping::isMappedIn0(const AtomIdx &atom) const +{ + return not this->isUnmappedIn0(atom); +} + +/** Return whether or not this atom is mapped in the perturbed state */ +bool AtomIdxMapping::isMappedIn1(const AtomIdx &atom) const +{ + return not this->isUnmappedIn1(atom); +} + +/** Return whether or not this atom is unmapped in both end states */ +bool AtomIdxMapping::isUnmappedInBoth(const AtomIdx &atom) const +{ + return this->isUnmappedIn0(atom) and this->isUnmappedIn1(atom); +} + +/** Return whether or not this atom is mapped in both end states */ +bool AtomIdxMapping::isMappedInBoth(const AtomIdx &atom) const +{ + return this->isMappedIn0(atom) and this->isMappedIn1(atom); +} diff --git a/corelib/src/libs/SireMol/atomidxmapping.h b/corelib/src/libs/SireMol/atomidxmapping.h new file mode 100644 index 000000000..393ad7599 --- /dev/null +++ b/corelib/src/libs/SireMol/atomidxmapping.h @@ -0,0 +1,289 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#ifndef SIREMOL_ATOMIDXMAPPING_H +#define SIREMOL_ATOMIDXMAPPING_H + +#include "SireBase/property.h" + +#include "SireMol/atomidx.h" +#include "SireMol/cgatomidx.h" + +SIRE_BEGIN_HEADER + +namespace SireMol +{ + class AtomIdxMapping; + class AtomIdxMappingEntry; +} + +SIREMOL_EXPORT QDataStream &operator<<(QDataStream &, const SireMol::AtomIdxMapping &); +SIREMOL_EXPORT QDataStream &operator>>(QDataStream &, SireMol::AtomIdxMapping &); + +SIREMOL_EXPORT QDataStream &operator<<(QDataStream &, const SireMol::AtomIdxMappingEntry &); +SIREMOL_EXPORT QDataStream &operator>>(QDataStream &, SireMol::AtomIdxMappingEntry &); + +namespace SireMol +{ + /** This is an individual mapping for a single atom */ + class SIREMOL_EXPORT AtomIdxMappingEntry + { + friend QDataStream & ::operator<<(QDataStream &, const AtomIdxMappingEntry &); + friend QDataStream & ::operator>>(QDataStream &, AtomIdxMappingEntry &); + + public: + AtomIdxMappingEntry(); + AtomIdxMappingEntry(const AtomIdx &index0, const AtomIdx &index1, + const MoleculeInfoData &molinfo0, + const MoleculeInfoData &molinfo1, + bool is_unmapped_in_reference); + + AtomIdxMappingEntry(const AtomIdxMappingEntry &other); + ~AtomIdxMappingEntry(); + + AtomIdxMappingEntry &operator=(const AtomIdxMappingEntry &other); + + bool operator==(const AtomIdxMappingEntry &other) const; + bool operator!=(const AtomIdxMappingEntry &other) const; + + AtomIdxMappingEntry *clone() const; + + bool isNull() const; + + QString toString() const; + + static const char *typeName(); + const char *what() const; + + bool isUnmappedIn0() const; + bool isUnmappedIn1() const; + + bool isMappedIn0() const; + bool isMappedIn1() const; + + bool isMappedInBoth() const; + bool isUnmappedInBoth() const; + + AtomIdx atomIdx0() const; + AtomIdx atomIdx1() const; + + CGAtomIdx cgAtomIdx0() const; + CGAtomIdx cgAtomIdx1() const; + + private: + /** The atomidx in the reference state */ + AtomIdx atomidx0; + + /** The atomidx in the perturbed state */ + AtomIdx atomidx1; + + /** The CGAtomIdx in the reference state */ + CGAtomIdx cgatomidx0; + + /** The CGAtomIdx in the perturbed state */ + CGAtomIdx cgatomidx1; + + /** Whether or not this atom is unmapped in the reference state */ + bool unmapped0; + }; + + /** This class holds the mapping from one set of atom indices to another. + * This enables you to associate, atom by atom, atom indices in one set to + * atom indices in another set. This is useful, e.g. for building perturbations, + * or for specifying mappings for alignments or RMSD calculations etc. + * + * This is mainly designed to provide sufficient information to merge + * properties together. It lists not just the atoms that map, but + * also which atoms are the ghost atoms that map (i.e. were created + * as ghost equivalents) + */ + class SIREMOL_EXPORT AtomIdxMapping + : public SireBase::ConcreteProperty + { + friend QDataStream & ::operator<<(QDataStream &, const AtomIdxMapping &); + friend QDataStream & ::operator>>(QDataStream &, AtomIdxMapping &); + + public: + AtomIdxMapping(); + AtomIdxMapping(const AtomIdxMappingEntry &entry); + AtomIdxMapping(const QList &entries); + + AtomIdxMapping(const AtomIdxMapping &other); + + ~AtomIdxMapping(); + + AtomIdxMapping &operator=(const AtomIdxMapping &other); + + bool operator==(const AtomIdxMapping &other) const; + bool operator!=(const AtomIdxMapping &other) const; + + AtomIdxMapping *clone() const; + + QString toString() const; + + static const char *typeName(); + const char *what() const; + + AtomIdxMapping &operator+=(const AtomIdxMapping &other); + AtomIdxMapping &operator+=(const AtomIdxMappingEntry &entry); + + AtomIdxMapping operator+(const AtomIdxMapping &other) const; + AtomIdxMapping operator+(const AtomIdxMappingEntry &entry) const; + + QList::const_iterator begin() const; + QList::const_iterator constBegin() const; + + QList::const_iterator end() const; + QList::const_iterator constEnd() const; + + QList::const_iterator find(AtomIdx atom) const; + QList::const_iterator find(CGAtomIdx atom) const; + + void append(const AtomIdxMappingEntry &entry); + void append(const AtomIdxMapping &other); + + void clear(); + + bool isEmpty() const; + + int size() const; + int count() const; + + const AtomIdxMappingEntry &operator[](int i) const; + + AtomIdxMappingEntry take(int i); + AtomIdxMappingEntry take(const AtomIdx &atom); + AtomIdxMappingEntry take(const CGAtomIdx &atom); + + void remove(int i); + void remove(const AtomIdx &atom); + void remove(const CGAtomIdx &atom); + + QList unmappedIn0() const; + QList unmappedIn1() const; + + QList mappedIn0() const; + QList mappedIn1() const; + + QList unmappedCGAtomIdxIn0() const; + QList unmappedCGAtomIdxIn1() const; + + QList mappedCGAtomIdxIn0() const; + QList mappedCGAtomIdxIn1() const; + + bool isUnmappedIn0(const AtomIdx &atom) const; + bool isUnmappedIn1(const AtomIdx &atom) const; + + bool isMappedIn0(const AtomIdx &atom) const; + bool isMappedIn1(const AtomIdx &atom) const; + + bool isMappedInBoth(const AtomIdx &atom) const; + bool isUnmappedInBoth(const AtomIdx &atom) const; + + QHash map0to1(bool include_unmapped = false) const; + QHash map1to0(bool include_unmapped = false) const; + + private: + void assertSane() const; + void rebuild(); + + /** The list of atom entries */ + QList entries; + + /** The set of atoms that are unmapped in the reference state */ + QSet unmapped0_set; + + /** The set of atoms that are unmapped in the perturbed state */ + QSet unmapped1_set; + + /** The list of atoms that are unmapped in the reference state */ + QList unmapped0_list; + + /** The list of atoms that are unmapped in the perturbed state */ + QList unmapped1_list; + + /** The list of atoms that are mapped in the reference state */ + QList mapped0_list; + + /** The list of atoms that are mapped in the perturbed state */ + QList mapped1_list; + + /** The mapping from reference to perturbed atoms, + * which includes the unmapped atoms + */ + QHash map0_to_1_inc; + + /** The mapping from perturbed to reference atoms, + * which includes the unmapped atoms + */ + QHash map1_to_0_inc; + + /** The mapping from reference to perturbed atoms, + * which excludes the unmapped atoms + */ + QHash map0_to_1_exc; + + /** The mapping from perturbed to reference atoms, + * which excludes the unmapped atoms + */ + QHash map1_to_0_exc; + }; + +#ifndef SIRE_SKIP_INLINE_FUNCTIONS + + /** Return whether or not the passed atom is unmapped in the + * reference state - the atom index should be for the + * merged molecule + */ + inline bool AtomIdxMapping::isUnmappedIn0(const AtomIdx &atom) const + { + return unmapped0_set.contains(atom); + } + + /** Return whether or not the passed atom is unmapped in the + * perturbed state - the atom index should be for the + * merged molecule + */ + inline bool AtomIdxMapping::isUnmappedIn1(const AtomIdx &atom) const + { + return unmapped1_set.contains(atom); + } + +#endif // SIRE_SKIP_INLINE_FUNCTIONS + +} // namespace SireMol + +Q_DECLARE_METATYPE(SireMol::AtomIdxMappingEntry) +Q_DECLARE_METATYPE(SireMol::AtomIdxMapping) + +SIRE_EXPOSE_CLASS(SireMol::AtomIdxMappingEntry) +SIRE_EXPOSE_CLASS(SireMol::AtomIdxMapping) + +SIRE_END_HEADER + +#endif diff --git a/corelib/src/libs/SireMol/atommapping.cpp b/corelib/src/libs/SireMol/atommapping.cpp index be33f0329..c38616017 100644 --- a/corelib/src/libs/SireMol/atommapping.cpp +++ b/corelib/src/libs/SireMol/atommapping.cpp @@ -28,6 +28,10 @@ #include "atommapping.h" +#include "SireMaths/align.h" + +#include "SireMol/core.h" + #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" @@ -41,11 +45,14 @@ static const RegisterMetaType r_mapping; QDataStream &operator<<(QDataStream &ds, const AtomMapping &mapping) { - writeHeader(ds, r_mapping, 1); + writeHeader(ds, r_mapping, 2); SharedDataStream sds(ds); sds << mapping.atms0 << mapping.atms1 + << mapping.orig_atms0 << mapping.orig_atms1 + << mapping.unmapped_atms0 << mapping.unmapped_atms1 + << mapping.map0 << mapping.map1 << static_cast(mapping); return ds; @@ -55,14 +62,29 @@ QDataStream &operator>>(QDataStream &ds, AtomMapping &mapping) { VersionID v = readHeader(ds, r_mapping); - if (v == 1) + if (v == 2) + { + SharedDataStream sds(ds); + + sds >> mapping.atms0 >> mapping.atms1 >> mapping.orig_atms0 >> mapping.orig_atms1 >> mapping.unmapped_atms0 >> mapping.unmapped_atms1 >> mapping.map0 >> mapping.map1 >> static_cast(mapping); + } + else if (v == 1) { SharedDataStream sds(ds); sds >> mapping.atms0 >> mapping.atms1 >> static_cast(mapping); + + mapping.map0 = PropertyMap(); + mapping.map1 = PropertyMap(); + + mapping.orig_atms0 = mapping.atms0; + mapping.orig_atms1 = mapping.atms1; + + mapping.unmapped_atms0.clear(); + mapping.unmapped_atms1.clear(); } else - throw version_error(v, "1", r_mapping, CODELOC); + throw version_error(v, "1,2", r_mapping, CODELOC); return ds; } @@ -72,9 +94,13 @@ AtomMapping::AtomMapping() : ConcreteProperty() } AtomMapping::AtomMapping(const SelectorM &atoms0, - const SelectorM &atoms1) + const SelectorM &atoms1, + const PropertyMap &m0, + const PropertyMap &m1) : ConcreteProperty(), - atms0(atoms0), atms1(atoms1) + atms0(atoms0), atms1(atoms1), + orig_atms0(atoms0), orig_atms1(atoms1), + map0(m0), map1(m1) { if (atms0.count() != atms1.count()) { @@ -88,22 +114,100 @@ AtomMapping::AtomMapping(const SelectorM &atoms0, } } -AtomMapping::AtomMapping(const MoleculeView &mol0, const MoleculeView &mol1) +AtomMapping::AtomMapping(const SelectorM &atoms0, + const SelectorM &atoms1, + const PropertyMap &map) + : ConcreteProperty() +{ + this->operator=(AtomMapping(atoms0, atoms1, map, map)); +} + +AtomMapping::AtomMapping(const MoleculeView &mol0, const MoleculeView &mol1, + const PropertyMap &map) + : ConcreteProperty() +{ + this->operator=(AtomMapping(SelectorM(mol0.atoms()), + SelectorM(mol1.atoms()), + map)); +} + +AtomMapping::AtomMapping(const MoleculeView &mol0, const MoleculeView &mol1, + const PropertyMap &m0, const PropertyMap &m1) : ConcreteProperty() { this->operator=(AtomMapping(SelectorM(mol0.atoms()), - SelectorM(mol1.atoms()))); + SelectorM(mol1.atoms()), + m0, m1)); } -AtomMapping::AtomMapping(const SelectorMol &mols0, const SelectorMol &mols1) +AtomMapping::AtomMapping(const SelectorMol &mols0, const SelectorMol &mols1, + const PropertyMap &map) : ConcreteProperty() { - this->operator=(AtomMapping(mols0.atoms(), mols1.atoms())); + this->operator=(AtomMapping(mols0.atoms(), mols1.atoms(), map)); +} + +AtomMapping::AtomMapping(const SelectorMol &mols0, const SelectorMol &mols1, + const PropertyMap &m0, const PropertyMap &m1) + : ConcreteProperty() +{ + this->operator=(AtomMapping(mols0.atoms(), mols1.atoms(), m0, m1)); +} + +AtomMapping::AtomMapping(const SelectorM &atoms0, + const SelectorM &atoms1, + const SelectorM &matched_atoms0, + const SelectorM &matched_atoms1, + const SireBase::PropertyMap &m0, + const SireBase::PropertyMap &m1) + : ConcreteProperty(), + atms0(matched_atoms0), atms1(matched_atoms1), + orig_atms0(atoms0), orig_atms1(atoms1), + map0(m0), map1(m1) +{ + if (atms0.count() != atms1.count()) + { + throw SireError::incompatible_error(QObject::tr( + "The number of atoms in 'atoms0' (%1) is not equal to the " + "number of atoms in 'atoms1' (%2). You can only create a " + "mapping if the number of atoms is the same.") + .arg(atms0.count()) + .arg(atms1.count()), + CODELOC); + } + + // find the indexes of missing atoms + for (int i = 0; i < atoms0.count(); ++i) + { + if (not atms0.contains(atoms0[i])) + this->unmapped_atms0.append(i); + } + + for (int i = 0; i < atoms1.count(); ++i) + { + if (not atms1.contains(atoms1[i])) + this->unmapped_atms1.append(i); + } +} + +AtomMapping::AtomMapping(const SelectorM &atoms0, + const SelectorM &atoms1, + const SelectorM &matched_atoms0, + const SelectorM &matched_atoms1, + const SireBase::PropertyMap &map) + : ConcreteProperty() +{ + this->operator=(AtomMapping(atoms0, atoms1, + matched_atoms0, matched_atoms1, + map, map)); } AtomMapping::AtomMapping(const AtomMapping &other) : ConcreteProperty(other), - atms0(other.atms0), atms1(other.atms1) + atms0(other.atms0), atms1(other.atms1), + orig_atms0(other.orig_atms0), orig_atms1(other.orig_atms1), + unmapped_atms0(other.unmapped_atms0), unmapped_atms1(other.unmapped_atms1), + map0(other.map0), map1(other.map1) { } @@ -117,6 +221,13 @@ AtomMapping &AtomMapping::operator=(const AtomMapping &other) { atms0 = other.atms0; atms1 = other.atms1; + orig_atms0 = other.orig_atms0; + orig_atms1 = other.orig_atms1; + unmapped_atms0 = other.unmapped_atms0; + unmapped_atms1 = other.unmapped_atms1; + map0 = other.map0; + map1 = other.map1; + Property::operator=(other); } @@ -125,7 +236,9 @@ AtomMapping &AtomMapping::operator=(const AtomMapping &other) bool AtomMapping::operator==(const AtomMapping &other) const { - return atms0 == other.atms0 and atms1 == other.atms1; + return orig_atms0 == other.orig_atms0 and orig_atms1 == other.orig_atms1 and + atms0 == other.atms0 and atms1 == other.atms1 and + map0 == other.map0 and map1 == other.map1; } bool AtomMapping::operator!=(const AtomMapping &other) const @@ -241,28 +354,59 @@ QString AtomMapping::toString() const } } - return QObject::tr("AtomMapping( size=%1\n%2\n)").arg(n).arg(parts.join("\n")); + return QObject::tr("AtomMapping( size=%1, unmapped0=%2, unmapped1=%3\n%4\n)") + .arg(n) + .arg(this->unmapped_atms0.count()) + .arg(this->unmapped_atms1.count()) + .arg(parts.join("\n")); } } -/** Return the reference atoms. We map from these atom to - * the mapped atoms (atoms1) */ +/** Return the original reference atoms. This is the collection of both + * mapped and unmapped reference atoms + */ const SelectorM &AtomMapping::atoms0() const { - return this->atms0; + return this->orig_atms0; } -/** Return the mapped atoms. We map from the reference atoms (atoms0) - * to these atoms. */ +/** Return the original mapped atoms. This is the collection of both + * mapped and unmapped mapped atoms + */ const SelectorM &AtomMapping::atoms1() const { - return this->atms1; + return this->orig_atms1; } /** Return an AtomMapping that swaps the reference and mapped atoms */ AtomMapping AtomMapping::swap() const { - return AtomMapping(this->atms1, this->atms0); + AtomMapping ret; + + ret.orig_atms0 = this->orig_atms1; + ret.orig_atms1 = this->orig_atms0; + + ret.atms0 = this->atms1; + ret.atms1 = this->atms0; + + ret.map0 = this->map1; + ret.map1 = this->map0; + + ret.unmapped_atms0 = this->unmapped_atms1; + ret.unmapped_atms1 = this->unmapped_atms0; + + return ret; +} + +/** Return whether or not the forward mapping contains the + * passed atom - this returns true if the atom is contained + * in the original reference atoms, i.e. it doesn't guarantee + * that the atom is mapped. Use the 'isMapped' method to + * check if the atom is mapped. + */ +bool AtomMapping::contains(const Atom &atom) const +{ + return this->orig_atms0.contains(atom); } /** Map from 'atom' (which must be in the reference atoms) to @@ -469,3 +613,161 @@ SelectorM AtomMapping::find(const SelectorM &atoms, return filtered; } + +/** Return all of the reference atoms that have been mapped, + * in the same order as the mapped atoms they match with + */ +SelectorM AtomMapping::mappedAtoms0() const +{ + return this->atms0; +} + +/** Return all of the mapped atoms that have been mapped, + * in the same order as the reference atoms they match with + */ +SelectorM AtomMapping::mappedAtoms1() const +{ + return this->atms1; +} + +/** Return all of the reference atoms that haven't been mapped, + * in the same order as they appear in the original reference + */ +SelectorM AtomMapping::unmappedAtoms0() const +{ + if (this->unmapped_atms0.isEmpty()) + { + return SelectorM(); + } + else + { + return this->orig_atms0[this->unmapped_atms0]; + } +} + +/** Return all of the mapped atoms that haven't been mapped, + * in the same order as they appear in the original mapped atoms + */ +SelectorM AtomMapping::unmappedAtoms1() const +{ + if (this->unmapped_atms1.isEmpty()) + { + return SelectorM(); + } + else + { + return this->orig_atms1[this->unmapped_atms1]; + } +} + +/** Return whether or not the passed reference atom has been + * mapped to a mapped atom + */ +bool AtomMapping::isMapped(const Atom &atom) const +{ + return this->atms0.contains(atom); +} + +/** Return whether or not this mapping refers to only a single molecule */ +bool AtomMapping::isSingleMolecule() const +{ + return this->orig_atms0.isSingleMolecule() and this->orig_atms1.isSingleMolecule(); +} + +/** Assert that this mapping refers only to a single molecule */ +void AtomMapping::assertSingleMolecule() const +{ + if (not this->isSingleMolecule()) + { + throw SireError::incompatible_error(QObject::tr( + "This mapping refers to more than one molecule, and so " + "cannot be used in this context."), + CODELOC); + } +} + +/** Return the property map used to find properties of the + * reference molecule + */ +const PropertyMap &AtomMapping::propertyMap0() const +{ + return this->map0; +} + +/** Return the property map used to find properties of the + * mapped molecule + */ +const PropertyMap &AtomMapping::propertyMap1() const +{ + return this->map1; +} + +/** Return the mapping where the perturbed state (1) has been + * aligned against the reference state (0). + */ +AtomMapping AtomMapping::align() const +{ + return this->alignTo0(); +} + +/** Return the mapping where the perturbed state (1) has been + * aligned against the reference state (0). + */ +AtomMapping AtomMapping::alignTo0() const +{ + if (this->isEmpty()) + return *this; + else if (this->atms0.isEmpty()) + return *this; + + QVector coords0 = this->atms0.property(map0["coordinates"]).toVector(); + QVector coords1 = this->atms1.property(map1["coordinates"]).toVector(); + + // calculate the transform to do a RMSD aligment of the two sets of coordinates + auto transform = SireMaths::getAlignment(coords0, coords1, true); + + auto mols1 = this->orig_atms1.molecules(); + + AtomMapping ret(*this); + + for (int i = 0; i < mols1.count(); ++i) + { + auto mol = mols1[i].move().transform(transform, map1).commit(); + + ret.atms1.update(mol); + ret.orig_atms1.update(mol); + } + + return ret; +} + +/** Return the mapping where the perturbed state (1) has been + * aligned against the reference state (0). + */ +AtomMapping AtomMapping::alignTo1() const +{ + if (this->isEmpty()) + return *this; + else if (this->atms0.isEmpty()) + return *this; + + QVector coords0 = this->atms0.property(map0["coordinates"]).toVector(); + QVector coords1 = this->atms1.property(map1["coordinates"]).toVector(); + + // calculate the transform to do a RMSD aligment of the two sets of coordinates + auto transform = SireMaths::getAlignment(coords1, coords0, true); + + auto mols0 = this->orig_atms0.molecules(); + + AtomMapping ret(*this); + + for (int i = 0; i < mols0.count(); ++i) + { + auto mol = mols0[i].move().transform(transform, map0).commit(); + + ret.atms0.update(mol); + ret.orig_atms0.update(mol); + } + + return ret; +} diff --git a/corelib/src/libs/SireMol/atommapping.h b/corelib/src/libs/SireMol/atommapping.h index 033e6fe41..579d9d4d0 100644 --- a/corelib/src/libs/SireMol/atommapping.h +++ b/corelib/src/libs/SireMol/atommapping.h @@ -33,6 +33,8 @@ #include "atom.h" #include "selectorm.hpp" +#include "SireBase/propertymap.h" + SIRE_BEGIN_HEADER namespace SireMol @@ -61,13 +63,44 @@ namespace SireMol public: AtomMapping(); AtomMapping(const SelectorM &atoms0, - const SelectorM &atoms1); + const SelectorM &atoms1, + const SireBase::PropertyMap &map = SireBase::PropertyMap()); + + AtomMapping(const SelectorM &atoms0, + const SelectorM &atoms1, + const SireBase::PropertyMap &map0, + const SireBase::PropertyMap &map1); AtomMapping(const MoleculeView &mol0, - const MoleculeView &mol1); + const MoleculeView &mol1, + const SireBase::PropertyMap &map = SireBase::PropertyMap()); + + AtomMapping(const MoleculeView &mol0, + const MoleculeView &mol1, + const SireBase::PropertyMap &map0, + const SireBase::PropertyMap &map1); + + AtomMapping(const SelectorMol &mols0, + const SelectorMol &mols1, + const SireBase::PropertyMap &map = SireBase::PropertyMap()); AtomMapping(const SelectorMol &mols0, - const SelectorMol &mols1); + const SelectorMol &mols1, + const SireBase::PropertyMap &map0, + const SireBase::PropertyMap &map1); + + AtomMapping(const SelectorM &atoms0, + const SelectorM &atoms1, + const SelectorM &matched_atoms0, + const SelectorM &matched_atoms1, + const SireBase::PropertyMap &map = SireBase::PropertyMap()); + + AtomMapping(const SelectorM &atoms0, + const SelectorM &atoms1, + const SelectorM &matched_atoms0, + const SelectorM &matched_atoms1, + const SireBase::PropertyMap &map0, + const SireBase::PropertyMap &map1); AtomMapping(const AtomMapping &other); @@ -99,11 +132,30 @@ namespace SireMol bool isEmpty() const; + bool contains(const Atom &atom) const; + const SelectorM &atoms0() const; const SelectorM &atoms1() const; + SelectorM mappedAtoms0() const; + SelectorM mappedAtoms1() const; + + SelectorM unmappedAtoms0() const; + SelectorM unmappedAtoms1() const; + + bool isMapped(const Atom &atom) const; + + bool isSingleMolecule() const; + + void assertSingleMolecule() const; + AtomMapping swap() const; + AtomMapping align() const; + + AtomMapping alignTo0() const; + AtomMapping alignTo1() const; + Atom map(const Atom &atom, bool find_all = true) const; SelectorM map(const MoleculeView &atoms, @@ -132,14 +184,42 @@ namespace SireMol const SelectorM &container, bool find_all = true) const; + const SireBase::PropertyMap &propertyMap0() const; + const SireBase::PropertyMap &propertyMap1() const; + private: /** The reference atoms - we map from these to the other atoms */ SelectorM atms0; /** The mapped atoms - we map from the reference atoms to these atoms */ SelectorM atms1; - }; + /** The original set of reference atoms - this includes the atoms + * in the same order as input, including any unmatched atoms + */ + SelectorM orig_atms0; + + /** The original set of mapped atoms - this includes the atoms + * in the same order as input, including any unmatched atoms + */ + SelectorM orig_atms1; + + /** The indexes of reference atoms in `orig_atms0` that are not mapped, + * in the order they appear in `orig_atms0` + */ + QList unmapped_atms0; + + /** The indexes of mapped atoms in `orig_atms1` that are not mapped, + * in the order they appear in `orig_atms1` + */ + QList unmapped_atms1; + + /** Property map for the reference atoms */ + SireBase::PropertyMap map0; + + /** Property map for the mapped atoms */ + SireBase::PropertyMap map1; + }; } Q_DECLARE_METATYPE(SireMol::AtomMapping) diff --git a/corelib/src/libs/SireMol/atommatchers.cpp b/corelib/src/libs/SireMol/atommatchers.cpp index 3bbe343e3..29ce1593e 100644 --- a/corelib/src/libs/SireMol/atommatchers.cpp +++ b/corelib/src/libs/SireMol/atommatchers.cpp @@ -86,14 +86,12 @@ QDataStream &operator>>(QDataStream &ds, AtomCoordMatcher &coordmatcher) } /** Constructor */ -AtomCoordMatcher::AtomCoordMatcher() : - ConcreteProperty(), zero_com(false) +AtomCoordMatcher::AtomCoordMatcher() : ConcreteProperty(), zero_com(false) { } /** Constructor */ -AtomCoordMatcher::AtomCoordMatcher(bool zero_com) : - ConcreteProperty(), zero_com(zero_com) +AtomCoordMatcher::AtomCoordMatcher(bool zero_com) : ConcreteProperty(), zero_com(zero_com) { } @@ -500,6 +498,7 @@ QHash AtomNameMatcher::pvt_match(const MoleculeView &mol0, con const MoleculeView &mol1, const PropertyMap &map1) const { QHash map; + QHash reverse_map; const AtomSelection sel0 = mol0.selection(); const AtomSelection sel1 = mol1.selection(); @@ -512,37 +511,48 @@ QHash AtomNameMatcher::pvt_match(const MoleculeView &mol0, con const AtomName name = mol0.data().info().name(idx0); - try - { - AtomIdx idx1 = mol1.data().info().atomIdx(name); - map.insert(idx0, idx1); - } - catch (...) + auto matches = mol1.data().info().mapNoThrow(name); + + // can only match unique matches + if (matches.count() == 1) { + if (reverse_map.contains(matches[0])) + { + // remove the duplicate match + map.remove(reverse_map[matches[0]]); + } + else + { + reverse_map.insert(matches[0], idx0); + map.insert(idx0, matches[0]); + } } } } else { - foreach (const AtomIdx idx0, sel0.selectedAtoms()) + for (const AtomIdx &idx0 : sel0.selectedAtoms()) { const AtomName name0 = mol0.data().info().name(idx0); - // A list of matches. - QList matches; - - foreach (const AtomIdx idx1, sel1.selectedAtoms()) + for (const AtomIdx &idx1 : sel1.selectedAtoms()) { const AtomName name1 = mol1.data().info().name(idx1); - // Add the match. if (name0 == name1) - matches.append(idx1); + { + if (reverse_map.contains(idx1)) + { + // remove the duplicate match + map.remove(reverse_map[idx1]); + } + else + { + reverse_map.insert(idx1, idx0); + map.insert(idx0, idx1); + } + } } - - // Only insert unique matche into the map. - if (matches.count() == 1) - map.insert(idx0, matches[0]); } } @@ -558,6 +568,7 @@ QHash AtomNameMatcher::pvt_match(const MoleculeView &mol0, con QHash AtomNameMatcher::pvt_match(const MoleculeInfoData &mol0, const MoleculeInfoData &mol1) const { QHash map; + QHash reverse_map; for (int i = 0; i < mol0.nAtoms(); ++i) { @@ -565,13 +576,21 @@ QHash AtomNameMatcher::pvt_match(const MoleculeInfoData &mol0, const AtomName name = mol0.name(idx0); - try - { - AtomIdx idx1 = mol1.atomIdx(name); - map.insert(idx0, idx1); - } - catch (...) + auto matches = mol1.mapNoThrow(name); + + // can only match unique matches + if (matches.count() == 1) { + if (reverse_map.contains(matches[0])) + { + // remove the duplicate match + map.remove(reverse_map[matches[0]]); + } + else + { + reverse_map.insert(matches[0], idx0); + map.insert(idx0, matches[0]); + } } } @@ -583,6 +602,188 @@ const char *AtomNameMatcher::typeName() return QMetaType::typeName(qMetaTypeId()); } +///////// +///////// Implementation of AtomNumMatcher +///////// + +static const RegisterMetaType r_nummatcher; + +/** Serialise to a binary datastream */ +QDataStream &operator<<(QDataStream &ds, const AtomNumMatcher &nummatcher) +{ + writeHeader(ds, r_nummatcher, 1); + ds << static_cast(nummatcher); + + return ds; +} + +/** Extract from a binary datastream */ +QDataStream &operator>>(QDataStream &ds, AtomNumMatcher &nummatcher) +{ + VersionID v = readHeader(ds, r_nummatcher); + + if (v == 1) + { + ds >> static_cast(nummatcher); + } + else + throw version_error(v, "1", r_nummatcher, CODELOC); + + return ds; +} + +/** Constructor */ +AtomNumMatcher::AtomNumMatcher() : ConcreteProperty() +{ +} + +/** Copy constructor */ +AtomNumMatcher::AtomNumMatcher(const AtomNumMatcher &other) : ConcreteProperty(other) +{ +} + +/** Destructor */ +AtomNumMatcher::~AtomNumMatcher() +{ +} + +/** Copy assignment operator */ +AtomNumMatcher &AtomNumMatcher::operator=(const AtomNumMatcher &other) +{ + return *this; +} + +/** Comparison operator */ +bool AtomNumMatcher::operator==(const AtomNumMatcher &other) const +{ + return true; +} + +/** Comparison operator */ +bool AtomNumMatcher::operator!=(const AtomNumMatcher &other) const +{ + return false; +} + +QString AtomNumMatcher::toString() const +{ + return QObject::tr("AtomNumMatcher()"); +} + +/** Match the atoms in 'mol1' to the atoms in 'mol0' - this + returns the AtomIdxs of the atoms in 'mol1' that are in + 'mol0', indexed by the AtomIdx of the atom in 'mol0'. + + This skips atoms in 'mol1' that are not in 'mol0' +*/ +QHash AtomNumMatcher::pvt_match(const MoleculeView &mol0, const PropertyMap &map0, + const MoleculeView &mol1, const PropertyMap &map1) const +{ + QHash map; + QHash reverse_map; + + const AtomSelection sel0 = mol0.selection(); + const AtomSelection sel1 = mol1.selection(); + + if (sel0.selectedAll() and sel1.selectedAll()) + { + for (int i = 0; i < mol0.data().info().nAtoms(); ++i) + { + const AtomIdx idx0(i); + + const AtomNum num = mol0.data().info().number(idx0); + + auto matches = mol1.data().info().mapNoThrow(num); + + // can only match unique matches + if (matches.count() == 1) + { + if (reverse_map.contains(matches[0])) + { + // remove the duplicate match + map.remove(reverse_map[matches[0]]); + } + else + { + reverse_map.insert(matches[0], idx0); + map.insert(idx0, matches[0]); + } + } + } + } + else + { + for (const AtomIdx &idx0 : sel0.selectedAtoms()) + { + const AtomNum num0 = mol0.data().info().number(idx0); + + for (const AtomIdx &idx1 : sel1.selectedAtoms()) + { + const AtomNum num1 = mol1.data().info().number(idx1); + + if (num0 == num1) + { + if (reverse_map.contains(idx1)) + { + // remove the duplicate match + map.remove(reverse_map[idx1]); + } + else + { + reverse_map.insert(idx1, idx0); + map.insert(idx0, idx1); + } + } + } + } + } + + return map; +} + +/** Match the atoms in 'mol1' to the atoms in 'mol0' - this + returns the AtomIdxs of the atoms in 'mol1' that are in + 'mol0', indexed by the AtomIdx of the atom in 'mol0'. + + This skips atoms in 'mol1' that are not in 'mol0' +*/ +QHash AtomNumMatcher::pvt_match(const MoleculeInfoData &mol0, const MoleculeInfoData &mol1) const +{ + QHash map; + QHash reverse_match; + + for (int i = 0; i < mol0.nAtoms(); ++i) + { + const AtomIdx idx0(i); + + const AtomNum num = mol0.number(idx0); + + auto matches = mol1.mapNoThrow(num); + + // can only match unique matches + if (matches.count() == 1) + { + if (reverse_match.contains(matches[0])) + { + // remove the duplicate match + map.remove(reverse_match[matches[0]]); + } + else + { + reverse_match.insert(matches[0], idx0); + map.insert(idx0, matches[0]); + } + } + } + + return map; +} + +const char *AtomNumMatcher::typeName() +{ + return QMetaType::typeName(qMetaTypeId()); +} + ///////// ///////// Implementation of AtomMCSMatcher ///////// diff --git a/corelib/src/libs/SireMol/atommatchers.h b/corelib/src/libs/SireMol/atommatchers.h index 136b015e3..b806d99b3 100644 --- a/corelib/src/libs/SireMol/atommatchers.h +++ b/corelib/src/libs/SireMol/atommatchers.h @@ -38,6 +38,7 @@ namespace SireMol class AtomCoordMatcher; class AtomIdxMatcher; class AtomNameMatcher; + class AtomNumMatcher; class AtomIDMatcher; class AtomMultiMatcher; class AtomMCSMatcher; @@ -56,6 +57,9 @@ SIREMOL_EXPORT QDataStream &operator>>(QDataStream &, SireMol::AtomIdxMatcher &) SIREMOL_EXPORT QDataStream &operator<<(QDataStream &, const SireMol::AtomNameMatcher &); SIREMOL_EXPORT QDataStream &operator>>(QDataStream &, SireMol::AtomNameMatcher &); +SIREMOL_EXPORT QDataStream &operator<<(QDataStream &, const SireMol::AtomNumMatcher &); +SIREMOL_EXPORT QDataStream &operator>>(QDataStream &, SireMol::AtomNumMatcher &); + SIREMOL_EXPORT QDataStream &operator<<(QDataStream &, const SireMol::AtomIDMatcher &); SIREMOL_EXPORT QDataStream &operator>>(QDataStream &, SireMol::AtomIDMatcher &); @@ -212,6 +216,43 @@ namespace SireMol const MoleculeView &molview1, const PropertyMap &map1) const; }; + /** This is a simple atom matcher that matches the atoms based + on their numbers, so the atom with number '1' in molinfo0 will + be matched to the atom with number '1' in molinfo1 + */ + class SIREMOL_EXPORT AtomNumMatcher : public SireBase::ConcreteProperty + { + + friend SIREMOL_EXPORT QDataStream & ::operator<<(QDataStream &, const AtomNumMatcher &); + friend SIREMOL_EXPORT QDataStream & ::operator>>(QDataStream &, AtomNumMatcher &); + + public: + AtomNumMatcher(); + AtomNumMatcher(const AtomNumMatcher &); + + ~AtomNumMatcher(); + + static const char *typeName(); + + const char *what() const + { + return AtomNumMatcher::typeName(); + } + + AtomNumMatcher &operator=(const AtomNumMatcher &other); + + bool operator==(const AtomNumMatcher &other) const; + bool operator!=(const AtomNumMatcher &other) const; + + QString toString() const; + + protected: + QHash pvt_match(const MoleculeInfoData &molinfo0, const MoleculeInfoData &molinfo1) const; + + QHash pvt_match(const MoleculeView &molview0, const PropertyMap &map0, + const MoleculeView &molview1, const PropertyMap &map1) const; + }; + /** This is an atom matcher that allows the user to specify exactly how one atom matches another in the molecule by mapping one AtomIdentifier to another @@ -568,6 +609,7 @@ namespace SireMol Q_DECLARE_METATYPE(SireMol::AtomCoordMatcher) Q_DECLARE_METATYPE(SireMol::AtomIdxMatcher) Q_DECLARE_METATYPE(SireMol::AtomNameMatcher) +Q_DECLARE_METATYPE(SireMol::AtomNumMatcher) Q_DECLARE_METATYPE(SireMol::AtomIDMatcher) Q_DECLARE_METATYPE(SireMol::AtomMultiMatcher) Q_DECLARE_METATYPE(SireMol::AtomMCSMatcher) @@ -579,6 +621,7 @@ Q_DECLARE_METATYPE(SireMol::ResIdxAtomCoordMatcher) SIRE_EXPOSE_CLASS(SireMol::AtomCoordMatcher) SIRE_EXPOSE_CLASS(SireMol::AtomIdxMatcher) SIRE_EXPOSE_CLASS(SireMol::AtomNameMatcher) +SIRE_EXPOSE_CLASS(SireMol::AtomNumMatcher) SIRE_EXPOSE_CLASS(SireMol::AtomIDMatcher) SIRE_EXPOSE_CLASS(SireMol::AtomMultiMatcher) SIRE_EXPOSE_CLASS(SireMol::AtomMCSMatcher) diff --git a/corelib/src/libs/SireMol/atomproperty.hpp b/corelib/src/libs/SireMol/atomproperty.hpp index 7e241cdb2..2e6604995 100644 --- a/corelib/src/libs/SireMol/atomproperty.hpp +++ b/corelib/src/libs/SireMol/atomproperty.hpp @@ -34,9 +34,11 @@ #include "SireBase/qvariant_metatype.h" #include "atomselection.h" +#include "atomidxmapping.h" #include "moleculeinfo.h" #include "moleculeinfodata.h" #include "molviewproperty.h" +#include "getghostparam.hpp" #include "SireBase/packedarray2d.hpp" #include "SireBase/quickcopy.hpp" @@ -110,6 +112,11 @@ namespace SireMol virtual PropertyPtr divide(const QVector &beads) const = 0; virtual PropertyPtr divideByResidue(const MoleculeInfoData &molinfo) const = 0; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const = 0; + protected: void throwIncorrectNumberOfAtoms(int nats, int ntotal) const; void throwIncorrectNumberOfSelectedAtoms(int nats, int nselected) const; @@ -234,6 +241,11 @@ namespace SireMol void assertCanConvert(const QVariant &value) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual atomic property values */ SireBase::PackedArray2D props; @@ -1221,6 +1233,58 @@ namespace SireMol return AtomProperty(res_vals); } + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList AtomProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + const AtomProperty &ref = *this; + const AtomProperty &pert = other.asA>(); + + AtomProperty prop0 = ref; + AtomProperty prop1 = ref; + + const T ghost_param = getGhostParam(ghost); + + for (const auto &index : mapping) + { + if (index.isUnmappedIn0() and index.isUnmappedIn1()) + { + prop0.set(index.cgAtomIdx0(), ghost_param); + prop1.set(index.cgAtomIdx0(), ghost_param); + } + else if (index.isUnmappedIn0()) + { + auto lj1 = pert.get(index.cgAtomIdx1()); + prop0.set(index.cgAtomIdx0(), ghost_param); + prop1.set(index.cgAtomIdx0(), lj1); + } + else if (index.isUnmappedIn1()) + { + prop1.set(index.cgAtomIdx0(), ghost_param); + } + else + { + prop1.set(index.cgAtomIdx0(), pert.get(index.cgAtomIdx1())); + } + } + + SireBase::PropertyList ret; + ret.append(prop0); + ret.append(prop1); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // namespace SireMol diff --git a/corelib/src/libs/SireMol/atomselection.cpp b/corelib/src/libs/SireMol/atomselection.cpp index 95dcb6713..c0c81ecc1 100644 --- a/corelib/src/libs/SireMol/atomselection.cpp +++ b/corelib/src/libs/SireMol/atomselection.cpp @@ -28,7 +28,7 @@ #include "atomselection.h" #include "moleculedata.h" #include "moleculeview.h" - +#include "atomidxmapping.h" #include "moleculeinfodata.h" #include "SireError/errors.h" @@ -4224,3 +4224,15 @@ bool AtomSelection::isSegment() const return false; } + +PropertyList AtomSelection::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + PropertyList ret; + ret.append(*this); + ret.append(*this); + + return ret; +} diff --git a/corelib/src/libs/SireMol/atomselection.h b/corelib/src/libs/SireMol/atomselection.h index 81d631c8a..eecc66023 100644 --- a/corelib/src/libs/SireMol/atomselection.h +++ b/corelib/src/libs/SireMol/atomselection.h @@ -454,6 +454,11 @@ namespace SireMol template void assertCompatibleWith(const AtomProperty &prop) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: bool _pvt_selected(const CGAtomIdx &cgatomidx) const; bool _pvt_selected(AtomIdx atomidx) const; diff --git a/corelib/src/libs/SireMol/beading.cpp b/corelib/src/libs/SireMol/beading.cpp index 78d8e84d0..fcca1ad82 100644 --- a/corelib/src/libs/SireMol/beading.cpp +++ b/corelib/src/libs/SireMol/beading.cpp @@ -35,6 +35,8 @@ #include +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireError/errors.h" @@ -135,6 +137,31 @@ NullBeading Beading::null() return NullBeading(); } +/** Merge this property with another property */ +SireBase::PropertyList Beading::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} + ////////// ////////// Implementation of MoleculeBeading ////////// diff --git a/corelib/src/libs/SireMol/beading.h b/corelib/src/libs/SireMol/beading.h index 1f76b2712..124f9ee97 100644 --- a/corelib/src/libs/SireMol/beading.h +++ b/corelib/src/libs/SireMol/beading.h @@ -109,6 +109,11 @@ namespace SireMol bool isCompatibleWith(const MoleculeInfoData &molinfo) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: Beading &operator=(const Beading &other); bool operator==(const Beading &other) const; diff --git a/corelib/src/libs/SireMol/beadproperty.hpp b/corelib/src/libs/SireMol/beadproperty.hpp index fe2ea9b86..82876c94d 100644 --- a/corelib/src/libs/SireMol/beadproperty.hpp +++ b/corelib/src/libs/SireMol/beadproperty.hpp @@ -32,6 +32,7 @@ #include "SireBase/qvariant_metatype.h" #include "SireBase/slice.h" +#include "SireBase/console.h" #include "beadidx.h" #include "beading.h" @@ -124,7 +125,7 @@ namespace SireMol { friend SIREMOL_EXPORT QDataStream & ::operator<< <>(QDataStream &, const BeadProperty &); - friend SIREMOL_EXPORT QDataStream & ::operator>><>(QDataStream &, BeadProperty &); + friend SIREMOL_EXPORT QDataStream & ::operator>> <>(QDataStream &, BeadProperty &); public: BeadProperty(); @@ -185,6 +186,11 @@ namespace SireMol void assertCanConvert(const QVariant &value) const; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual bead property values */ QVector props; @@ -545,6 +551,32 @@ namespace SireMol return this->getNBeads(molinfo) == this->nBeads(); } + /** Merge this property with another property */ + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList BeadProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // namespace SireMol diff --git a/corelib/src/libs/SireMol/cgproperty.hpp b/corelib/src/libs/SireMol/cgproperty.hpp index 215bc4ada..ce0d564f6 100644 --- a/corelib/src/libs/SireMol/cgproperty.hpp +++ b/corelib/src/libs/SireMol/cgproperty.hpp @@ -33,9 +33,11 @@ #include "SireBase/convert_property.hpp" #include "SireBase/qvariant_metatype.h" #include "SireBase/slice.h" +#include "SireBase/console.h" #include "moleculeinfodata.h" #include "molviewproperty.h" +#include "getghostparam.hpp" #include "SireError/errors.h" @@ -105,7 +107,7 @@ namespace SireMol { friend SIREMOL_EXPORT QDataStream & ::operator<< <>(QDataStream &, const CGProperty &); - friend SIREMOL_EXPORT QDataStream & ::operator>><>(QDataStream &, CGProperty &); + friend SIREMOL_EXPORT QDataStream & ::operator>> <>(QDataStream &, CGProperty &); public: CGProperty(); @@ -169,6 +171,11 @@ namespace SireMol bool isCompatibleWith(const MoleculeInfoData &molinfo) const; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual CutGroup property values */ QVector props; @@ -548,6 +555,32 @@ namespace SireMol return molinfo.nCutGroups() == this->nCutGroups(); } + /** Merge this property with another property */ + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList CGProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // namespace SireMol diff --git a/corelib/src/libs/SireMol/chainproperty.hpp b/corelib/src/libs/SireMol/chainproperty.hpp index 7df5f41b2..35c42c3ff 100644 --- a/corelib/src/libs/SireMol/chainproperty.hpp +++ b/corelib/src/libs/SireMol/chainproperty.hpp @@ -33,6 +33,7 @@ #include "SireBase/convert_property.hpp" #include "SireBase/qvariant_metatype.h" #include "SireBase/slice.h" +#include "SireBase/console.h" #include "moleculeinfodata.h" #include "molviewproperty.h" @@ -104,7 +105,7 @@ namespace SireMol { friend SIREMOL_EXPORT QDataStream & ::operator<< <>(QDataStream &, const ChainProperty &); - friend SIREMOL_EXPORT QDataStream & ::operator>><>(QDataStream &, ChainProperty &); + friend SIREMOL_EXPORT QDataStream & ::operator>> <>(QDataStream &, ChainProperty &); public: ChainProperty(); @@ -168,6 +169,11 @@ namespace SireMol void assertCanConvert(const QVariant &value) const; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual chain property values */ QVector props; @@ -547,6 +553,32 @@ namespace SireMol return molinfo.nChains() == this->nChains(); } + /** Merge this property with another property */ + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList ChainProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // namespace SireMol diff --git a/corelib/src/libs/SireMol/connectivity.cpp b/corelib/src/libs/SireMol/connectivity.cpp index 3f2e562e2..e884e9caf 100644 --- a/corelib/src/libs/SireMol/connectivity.cpp +++ b/corelib/src/libs/SireMol/connectivity.cpp @@ -37,6 +37,7 @@ #include "moleculeinfo.h" #include "moleculeinfodata.h" #include "moleculeview.h" +#include "atomidxmapping.h" #include "angleid.h" #include "bondid.h" @@ -46,8 +47,11 @@ #include "SireMol/errors.h" #include "SireBase/errors.h" +#include "SireBase/console.h" #include "SireBase/parallel.h" +#include "SireError/errors.h" + #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" @@ -320,7 +324,9 @@ PropertyPtr ConnectivityBase::_pvt_makeCompatibleWith(const MoleculeInfoData &mo // AtomIdx indicies are still valid Connectivity ret; ret.connected_atoms = connected_atoms; + ret.connected_atoms.resize(molinfo.nAtoms()); ret.connected_res = connected_res; + ret.connected_res.resize(molinfo.nResidues()); ret.bond_props = bond_props; ret.minfo = MoleculeInfo(molinfo); return ret; @@ -328,7 +334,93 @@ PropertyPtr ConnectivityBase::_pvt_makeCompatibleWith(const MoleculeInfoData &mo QHash matched_atoms = atommatcher.match(this->info(), molinfo); - return this->_pvt_makeCompatibleWith(molinfo, matched_atoms); + // see if there is any actual change - if not, then we can just return + bool same_mapping = true; + + for (auto it = matched_atoms.begin(); it != matched_atoms.end(); ++it) + { + if (it.key() != it.value()) + { + same_mapping = false; + break; + } + } + + if (same_mapping) + { + Connectivity ret; + ret.connected_atoms = connected_atoms; + ret.connected_atoms.resize(molinfo.nAtoms()); + ret.connected_res = connected_res; + ret.connected_res.resize(molinfo.nResidues()); + ret.bond_props = bond_props; + ret.minfo = MoleculeInfo(molinfo); + + if (ret.minfo.nAtoms() < this->minfo.nAtoms()) + { + const int nats = ret.minfo.nAtoms(); + const int nres = ret.minfo.nResidues(); + + // atoms have been removed, so need to remove any references + // to atoms that no longer exist + for (int i = 0; i < ret.connected_atoms.count(); ++i) + { + QSet &connected = ret.connected_atoms[i]; + + for (auto it = connected.begin(); it != connected.end();) + { + if (it->value() >= nats) + { + it = connected.erase(it); + } + else + { + ++it; + } + } + } + + for (int i = 0; i < ret.connected_res.count(); ++i) + { + QSet &connected = ret.connected_res[i]; + + for (auto it = connected.begin(); it != connected.end();) + { + if (it->value() >= nres) + { + it = connected.erase(it); + } + else + { + ++it; + } + } + } + + // remove any bond properties that refer to atoms that no longer exist + for (auto it = ret.bond_props.begin(); it != ret.bond_props.end();) + { + if (it.key().atom0 >= nats or it.key().atom1 >= nats) + { + it = ret.bond_props.erase(it); + } + else + { + ++it; + } + } + + // clear the angle, dihedral and improper properties as + // these are too complex to make compatible + ret.ang_props.clear(); + ret.dih_props.clear(); + ret.imp_props.clear(); + } + + return ret; + } + else + return this->_pvt_makeCompatibleWith(molinfo, matched_atoms); } catch (const SireError::exception &e) { @@ -2409,6 +2501,45 @@ QList ConnectivityBase::getBonds(const AtomID &atom) const return ret; } +/** Return all of the connections that involve the passed atoms - if exclusive is true, + * then return only connections where both atoms are present in the list. + */ +QList ConnectivityBase::getBonds(const QList &atoms, bool exclusive) const +{ + QList ret; + + const QSet atoms_set(atoms.begin(), atoms.end()); + + if (exclusive) + { + for (const auto &bond : this->getBonds()) + { + const auto atom0 = this->minfo.atomIdx(bond.atom0()); + const auto atom1 = this->minfo.atomIdx(bond.atom1()); + + if (atoms_set.contains(atom0) and atoms_set.contains(atom1)) + { + ret.append(bond); + } + } + } + else + { + for (const auto &bond : this->getBonds()) + { + const auto atom0 = this->minfo.atomIdx(bond.atom0()); + const auto atom1 = this->minfo.atomIdx(bond.atom1()); + + if (atoms_set.contains(atom0) or atoms_set.contains(atom1)) + { + ret.append(bond); + } + } + } + + return ret; +} + namespace SireMol { namespace detail @@ -3373,6 +3504,315 @@ void ConnectivityBase::assertHasProperty(const ImproperID &improper, const Prope CODELOC); } +/** Return whether or not this atom is in a ring */ +static bool is_on_ring(const AtomIdx &atom, const Connectivity &conn) +{ + if (conn.inRing(atom)) + { + // loop over all atoms connected to this atom + for (const auto &neighbour : conn.connectionsTo(atom)) + { + // if the neighbour is in the ring, then this atom is in the ring + if (not(conn.inRing(neighbour, atom))) + return true; + } + } + + return false; +} + +/** Return whether or not there is a change in ring between the passed + * two atoms in the passed two connectivities */ +static bool is_ring_size_changed(const Connectivity &conn0, + const Connectivity &conn1, + const AtomIdxMappingEntry &atom0, + const AtomIdxMappingEntry &atom1, + int max_ring_size = 12) +{ + // Have a ring changed size? If so, then the minimum path size between + // two atoms will have changed. + + // Work out the paths connecting the atoms in the two end states. + auto paths0 = conn0.findPaths(atom0.atomIdx0(), atom1.atomIdx0(), max_ring_size); + auto paths1 = conn1.findPaths(atom0.atomIdx1(), atom1.atomIdx1(), max_ring_size); + + // Initialise the ring size in each end state. + auto ring0 = -1; + auto ring1 = -1; + + // Determine the minimum path in the lambda = 0 state. + if (paths0.count() > 1) + { + QVector path_lengths0; + + for (const auto &path : paths0) + { + path_lengths0.append(path.count()); + } + + ring0 = *(std::min_element(path_lengths0.begin(), path_lengths0.end())); + } + + if (ring0 == -1) + return false; + + // Determine the minimum path in the lambda = 1 state. + if (paths1.count() > 1) + { + QVector path_lengths1; + + for (const auto &path : paths1) + { + path_lengths1.append(path.count()); + } + + ring1 = *(std::min_element(path_lengths1.begin(), path_lengths1.end())); + } + + // Return whether the ring has changed size. + return ring0 != ring1; +} + +/** Return whether any ring that both the atoms are on is broken/formed + * during the merge */ +static bool is_ring_broken(const Connectivity &conn0, + const Connectivity &conn1, + const AtomIdxMappingEntry &atom0, + const AtomIdxMappingEntry &atom1) +{ + // Have we opened/closed a ring? This means that both atoms are part of a + // ring in one end state (either in it, or on it), whereas at least one + // isn't in the other state. + + if (not(atom0.isMappedInBoth() and atom1.isMappedInBoth())) + // either atom isn't in both end states, so cannot be part + // of a ring that is in both end states... + return false; + + const auto idx0 = atom0.atomIdx0(); + const auto idy0 = atom1.atomIdx0(); + + const auto idx1 = atom0.atomIdx1(); + const auto idy1 = atom1.atomIdx1(); + + // Whether each atom is in a ring in both end states. + const auto in_ring_idx0 = conn0.inRing(idx0); + const auto in_ring_idy0 = conn0.inRing(idy0); + const auto in_ring_idx1 = conn1.inRing(idx1); + const auto in_ring_idy1 = conn1.inRing(idy1); + + // Whether each atom is on a ring in both end states. + const auto on_ring_idx0 = is_on_ring(idx0, conn0); + const auto on_ring_idy0 = is_on_ring(idy0, conn0); + const auto on_ring_idx1 = is_on_ring(idx1, conn1); + const auto on_ring_idy1 = is_on_ring(idy1, conn1); + + // Both atoms are in a ring in one end state and at least one isn't in the other. + if ((in_ring_idx0 & in_ring_idy0) ^ (in_ring_idx1 & in_ring_idy1)) + return true; + + // Both atoms are on a ring in one end state and at least one isn't in the other. + if ((on_ring_idx0 & on_ring_idy0 & (conn0.connectionType(idx0, idy0) == 4)) ^ (on_ring_idx1 & on_ring_idy1 & (conn1.connectionType(idx1, idy1) == 4))) + { + // Make sure that the change isn't a result of ring growth, i.e. one of + // the atoms isn't in a ring in one end state, while its "on" ring status + // has changed between states. + if (not((in_ring_idx0 | in_ring_idx1) & (on_ring_idx0 ^ on_ring_idx1) or (in_ring_idy0 | in_ring_idy1) & (on_ring_idy0 ^ on_ring_idy1))) + { + return true; + } + } + + // Both atoms are in or on a ring in one state and at least one isn't in the other. + if (((in_ring_idx0 | on_ring_idx0) & (in_ring_idy0 | on_ring_idy0) & (conn0.connectionType(idx0, idy0) == 3)) ^ + ((in_ring_idx1 | on_ring_idx1) & (in_ring_idy1 | on_ring_idy1) & (conn1.connectionType(idx1, idy1) == 3))) + { + auto iscn0 = conn0.connectionsTo(idx0); + iscn0.intersect(conn0.connectionsTo(idy0)); + + if (iscn0.count() != 1) + return true; + + auto common_idx = *(iscn0.constBegin()); + iscn0.remove(common_idx); + + const auto in_ring_bond0 = conn0.inRing(idx0, common_idx) or conn0.inRing(idy0, common_idx); + + auto iscn1 = conn1.connectionsTo(idx1); + iscn1.intersect(conn1.connectionsTo(idy1)); + + if (iscn1.count() != 1) + return true; + + common_idx = *(iscn1.constBegin()); + iscn1.remove(common_idx); + + const auto in_ring_bond1 = conn1.inRing(idx1, common_idx) or conn1.inRing(idy1, common_idx); + + if (in_ring_bond0 ^ in_ring_bond1) + return true; + } + + // If we get this far, then a ring wasn't broken. + return false; +} + +/** Merge this property with another property */ +PropertyList ConnectivityBase::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + if (not ghost.isEmpty()) + { + Console::warning(QObject::tr("The ghost parameter '%1' for bond parameters is ignored").arg(ghost)); + } + + const ConnectivityBase &ref = *this; + const ConnectivityBase &pert = other.asA(); + + auto prop0 = Connectivity(ref).edit(); + auto prop1 = Connectivity(ref).edit(); + + // the prop0 properties are already correct + + // the prop1 properties are made by finding all of the atoms that + // are involved in bonds in 'pert' and removing any bonds involving + // only those atoms from 'prop1', and then adding back the matching + // bonds from 'pert'. Use 'true' to only remove bonds where both + // atoms are in the mapping + prop1.disconnect(mapping.mappedIn1(), true); + + // get the mapping from the perturbed to reference states, including + // atoms that don't exist in the reference state. In all cases, + // the values are the indexes in the merged molecule + auto map1to0 = mapping.map1to0(true); + + // now find all of the bonds in 'pert' where both atoms in the + // bond are in map1to0.keys() - i.e. exist and are mapped from + // the perturbed state + const auto pert_bonds = pert.getBonds(map1to0.keys(), true); + + // connect those bonds together + for (const auto &pert_bond : pert_bonds) + { + const auto atom0 = map1to0.value(info().atomIdx(pert_bond.atom0())); + const auto atom1 = map1to0.value(info().atomIdx(pert_bond.atom1())); + + prop1.connect(atom0, atom1); + + if (mapping.isUnmappedIn0(atom0) or mapping.isUnmappedIn0(atom1)) + { + // the prop0 properties are nearly correct - we just need to add + // in a connection from 'pert' that involve the atoms that are not mapped + // in the reference state - this way, those added atoms are + // connected to the reference atoms + prop0.connect(atom0, atom1); + } + } + + // now add in the connections to the perturbed state from the reference + // state for any atoms that aren't mapped to the perturbed state. + // This way, the removed atoms are connected to the perturbed atoms + auto map0to1 = mapping.map0to1(true); + + const auto ref_bonds = ref.getBonds(map0to1.keys(), true); + + for (const auto &ref_bond : ref_bonds) + { + const auto atom0 = info().atomIdx(ref_bond.atom0()); + const auto atom1 = info().atomIdx(ref_bond.atom1()); + + if (mapping.isUnmappedIn1(atom0) or mapping.isUnmappedIn1(atom1)) + { + prop1.connect(atom0, atom1); + } + } + + // check if we are allowed to change the size of a ring or break rings + bool allow_ring_breaking = true; + bool allow_ring_size_change = true; + + if (map.specified("allow_ring_breaking")) + { + allow_ring_breaking = map["allow_ring_breaking"].value().asABoolean(); + } + + if (map.specified("allow_ring_size_change")) + { + allow_ring_size_change = map["allow_ring_size_change"].value().asABoolean(); + } + + SireBase::PropertyList ret; + + ret.append(prop0.commit()); + ret.append(prop1.commit()); + + if (allow_ring_breaking and allow_ring_size_change) + { + // nothing more to do + return ret; + } + + // we need to check that the merge doesn't break or change rings - do this + // by looping over pairs of atoms mapped in both states and checking, + // if they are in a ring, if that ring has changed size or been broken or + // formed by the merge + for (auto it0 = mapping.constBegin(); it0 != mapping.constEnd(); ++it0) + { + const auto &atom0 = *it0; + + if (not atom0.isMappedInBoth()) + // this cannot be part of a ring, as it is not in both states + continue; + + for (auto it1 = it0 + 1; it1 != mapping.constEnd(); ++it1) + { + const auto &atom1 = *it1; + + if (not atom1.isMappedInBoth()) + // this cannot be part of a ring, as it is not in both states + continue; + + if (not allow_ring_size_change) + { + if (is_ring_size_changed(ref, pert, atom0, atom1)) + { + throw SireError::incompatible_error(QObject::tr("The merge has changed the size of a ring. To allow this " + "perturbation, set the 'allow_ring_size_change' option " + "to 'True'. Be aware that this perturbation may not work " + "and a transition through an intermediate state may be " + "preferable."), + CODELOC); + } + } + + if (not allow_ring_breaking) + { + if (is_ring_broken(ref, pert, atom0, atom1)) + { + throw SireError::incompatible_error(QObject::tr("The merge has changed the molecular connectivity " + "but a ring didn't open/close or change size. " + "If you want to proceed with this mapping pass " + "'force=True'. You are warned that the resulting " + "perturbation will likely be unstable."), + CODELOC); + } + } + } + } + + return ret; +} + ///////// ///////// Implementation of Connectivity ///////// @@ -3629,6 +4069,23 @@ ConnectivityEditor &ConnectivityEditor::connect(const AtomID &atom0, const AtomI return this->connect(info().atomIdx(atom0), info().atomIdx(atom1)); } +/** Create a connection for the passed bond */ +ConnectivityEditor &ConnectivityEditor::connect(const BondID &bond) +{ + return this->connect(bond.atom0(), bond.atom1()); +} + +/** Create a connection for the passed bonds */ +ConnectivityEditor &ConnectivityEditor::connect(const QList &bonds) +{ + for (const auto &bond : bonds) + { + this->connect(bond); + } + + return *this; +} + /** Remove the connection between the atoms at indicies 'atom0' and 'atom1' - this does nothing if there isn't already a connection @@ -3673,6 +4130,67 @@ ConnectivityEditor &ConnectivityEditor::disconnect(const AtomID &atom0, const At return this->disconnect(info().atomIdx(atom0), info().atomIdx(atom1)); } +/** Disconnect the atoms in the passed bond - this does nothing if the + * atoms aren't connected */ +ConnectivityEditor &ConnectivityEditor::disconnect(const BondID &bond) +{ + return this->disconnect(bond.atom0(), bond.atom1()); +} + +/** Disconnect the atoms in the passed bonds - this does nothing for any + * of the atoms that aren't connected */ +ConnectivityEditor &ConnectivityEditor::disconnect(const QList &bonds) +{ + for (const auto &bond : bonds) + { + this->disconnect(bond); + } + + return *this; +} + +/** Disconnect any and all bonds involving the passed atoms. If exclusive is true, + * then this only removes connection where both atoms are in 'atoms', otherwise + * it removes connections which have one of more atoms in 'atoms' + */ +ConnectivityEditor &ConnectivityEditor::disconnect(const QList &atoms, bool exclusive) +{ + const QSet atoms_set(atoms.begin(), atoms.end()); + + if (exclusive) + { + const auto bonds = this->getBonds(); + + for (const auto &bond : bonds) + { + const auto atom0 = info().atomIdx(bond.atom0()); + const auto atom1 = info().atomIdx(bond.atom1()); + + if (atoms_set.contains(atom0) and atoms_set.contains(atom1)) + { + this->disconnect(atom0, atom1); + } + } + } + else + { + const auto bonds = this->getBonds(); + + for (const auto &bond : bonds) + { + const auto atom0 = info().atomIdx(bond.atom0()); + const auto atom1 = info().atomIdx(bond.atom1()); + + if (atoms_set.contains(atom0) or atoms_set.contains(atom1)) + { + this->disconnect(atom0, atom1); + } + } + } + + return *this; +} + /** Remove all of the connections to the atom at index 'atomidx' \throw SireError::invalid_index diff --git a/corelib/src/libs/SireMol/connectivity.h b/corelib/src/libs/SireMol/connectivity.h index 5a9f7f5ca..f75472737 100644 --- a/corelib/src/libs/SireMol/connectivity.h +++ b/corelib/src/libs/SireMol/connectivity.h @@ -248,6 +248,9 @@ namespace SireMol QList getBonds() const; QList getBonds(const AtomID &atom) const; + + QList getBonds(const QList &atoms, bool exclusive = true) const; + QList getAngles() const; QList getAngles(const AtomID &atom0) const; QList getAngles(const AtomID &atom0, const AtomID &atom1) const; @@ -329,6 +332,11 @@ namespace SireMol void assertHasProperty(const ImproperID &imp, const SireBase::PropertyName &key) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: ConnectivityBase(); ConnectivityBase(const MoleculeInfo &molinfo); @@ -466,6 +474,14 @@ namespace SireMol ConnectivityEditor &connect(const AtomID &atom0, const AtomID &atom1); ConnectivityEditor &disconnect(const AtomID &atom0, const AtomID &atom1); + ConnectivityEditor &connect(const BondID &bond); + ConnectivityEditor &disconnect(const BondID &bond); + + ConnectivityEditor &connect(const QList &bonds); + ConnectivityEditor &disconnect(const QList &bonds); + + ConnectivityEditor &disconnect(const QList &atoms, bool exclusive = true); + ConnectivityEditor &disconnectAll(AtomIdx atomidx); ConnectivityEditor &disconnectAll(ResIdx residx); diff --git a/corelib/src/libs/SireMol/getghostparam.hpp b/corelib/src/libs/SireMol/getghostparam.hpp new file mode 100644 index 000000000..35426f68d --- /dev/null +++ b/corelib/src/libs/SireMol/getghostparam.hpp @@ -0,0 +1,167 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#ifndef SIREMOL_GETGHOSTPARAM_HPP +#define SIREMOL_GETGHOSTPARAM_HPP + +#include "SireBase/booleanproperty.h" +#include "SireBase/stringproperty.h" + +#include "SireMol/element.h" + +#include "SireUnits/generalunit.h" + +SIRE_BEGIN_HEADER + +namespace SireMol +{ + template + inline T getGhostParam(const QString &ghost) + { + return T(); + } + + template <> + inline QString getGhostParam(const QString &ghost) + { + return ghost; + } + + template <> + inline qint64 getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return 0; + else + return ghost.toLongLong(); + } + + template <> + inline double getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return 0.0; + else + return ghost.toDouble(); + } + + template <> + inline bool getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return false; + else + return SireBase::BooleanProperty(ghost).value(); + } + + template <> + inline SireUnits::Dimension::GeneralUnit getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireUnits::Dimension::GeneralUnit(0); + else + return SireUnits::Dimension::GeneralUnit(ghost); + } + + template <> + inline QVariant getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return QVariant(); + else + return QVariant(ghost); + } + + template <> + inline SireUnits::Dimension::MolarMass getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireUnits::Dimension::MolarMass(0.0); + else + return SireUnits::Dimension::MolarMass(ghost); + } + + template <> + inline SireUnits::Dimension::MolarEnergy getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireUnits::Dimension::MolarEnergy(0.0); + else + return SireUnits::Dimension::MolarEnergy(ghost); + } + + template <> + inline SireUnits::Dimension::Charge getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireUnits::Dimension::Charge(0.0); + else + return SireUnits::Dimension::Charge(ghost); + } + + template <> + inline SireMol::Element getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireMol::Element(0); + else + return SireMol::Element(ghost); + } + + template <> + inline SireUnits::Dimension::Volume getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireUnits::Dimension::Volume(0.0); + else + return SireUnits::Dimension::Volume(ghost); + } + + template <> + inline SireUnits::Dimension::Length getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireUnits::Dimension::Length(0.0); + else + return SireUnits::Dimension::Length(ghost); + } + + template <> + inline SireBase::PropertyPtr getGhostParam(const QString &ghost) + { + if (ghost.isEmpty()) + return SireBase::PropertyPtr(); + else + return SireBase::PropertyPtr(SireBase::StringProperty(ghost)); + } + +} + +SIRE_END_HEADER + +#endif diff --git a/corelib/src/libs/SireMol/moleculedata.cpp b/corelib/src/libs/SireMol/moleculedata.cpp index d60133099..0c35d73e4 100644 --- a/corelib/src/libs/SireMol/moleculedata.cpp +++ b/corelib/src/libs/SireMol/moleculedata.cpp @@ -672,6 +672,64 @@ void MoleculeData::rename(const MolName &newname) } } +/** Set the alternate atom name for the specified atom */ +void MoleculeData::setAlternateAtomName(AtomIdx atomidx, const AtomName &newname) +{ + MoleculeInfoData newinfo = molinfo->setAlternateName(atomidx, newname); + + if (newinfo.UID() != molinfo.constData()->UID()) + { + SireBase::assert_true(vrsns.get() != 0, CODELOC); + + molinfo = newinfo; + updatePropertyMolInfo(); + vrsn = vrsns->increment(); + } +} + +/** Set the alternate residue name for the specified residue */ +void MoleculeData::setAlternateResName(ResIdx residx, const ResName &newname) +{ + MoleculeInfoData newinfo = molinfo->setAlternateName(residx, newname); + + if (newinfo.UID() != molinfo.constData()->UID()) + { + SireBase::assert_true(vrsns.get() != 0, CODELOC); + + molinfo = newinfo; + updatePropertyMolInfo(); + vrsn = vrsns->increment(); + } +} + +/** Return the alternate atom name for the specified atom */ +AtomName MoleculeData::getAlternateAtomName(AtomIdx atomidx) const +{ + return molinfo->alternateName(atomidx); +} + +/** Return the alternate residue name for the specified residue */ +ResName MoleculeData::getAlternateResName(ResIdx residx) const +{ + return molinfo->alternateName(residx); +} + +/** Switch to using the alternate names for all atoms and residues. + * If 'keep_originals' is true, then the original names will be + * stored in the alternate names. If 'keep_originals' is false, + * then the original names will be removed. + */ +void MoleculeData::switchToAlternateNames(bool keep_originals) +{ + molinfo = molinfo->switchToAlternateNames(keep_originals); +} + +/** Remove all alternate names from this molecule */ +void MoleculeData::removeAlternateNames() +{ + molinfo = molinfo->removeAlternateNames(); +} + /** Rename the atom at index 'atomidx' to 'newname' \throw SireError::invalid_index diff --git a/corelib/src/libs/SireMol/moleculedata.h b/corelib/src/libs/SireMol/moleculedata.h index b1cc92cb7..191fb256f 100644 --- a/corelib/src/libs/SireMol/moleculedata.h +++ b/corelib/src/libs/SireMol/moleculedata.h @@ -247,6 +247,15 @@ namespace SireMol void renumber(const QHash &resnums); void renumber(const QHash &atomnums, const QHash &resnums); + void setAlternateAtomName(AtomIdx atomidx, const AtomName &newname); + void setAlternateResName(ResIdx residx, const ResName &newname); + + AtomName getAlternateAtomName(AtomIdx atomidx) const; + ResName getAlternateResName(ResIdx residx) const; + + void switchToAlternateNames(bool keep_originals = true); + void removeAlternateNames(); + void setProperty(const QString &key, const Property &value, bool clear_metadata = false); bool updateProperty(const QString &key, const Property &value, bool auto_add = true); diff --git a/corelib/src/libs/SireMol/moleculeinfo.cpp b/corelib/src/libs/SireMol/moleculeinfo.cpp index 2b3b70902..648a3845f 100644 --- a/corelib/src/libs/SireMol/moleculeinfo.cpp +++ b/corelib/src/libs/SireMol/moleculeinfo.cpp @@ -1136,3 +1136,55 @@ void MoleculeInfo::assertEqualTo(const MoleculeInfoData &other) const { d->assertEqualTo(other); } + +/** Return the alternate name of the specified atom */ +const AtomName &MoleculeInfo::alternateName(const AtomID &atomid) const +{ + return d->alternateName(atomid); +} + +/** Return the alternate name of the specified atom */ +const AtomName &MoleculeInfo::alternateName(AtomIdx atomidx) const +{ + return d->alternateName(atomidx); +} + +/** Return the alternate name of the specified residue */ +const ResName &MoleculeInfo::alternateName(const ResID &resid) const +{ + return d->alternateName(resid); +} + +/** Return the alternate name of the specified residue */ +const ResName &MoleculeInfo::alternateName(ResIdx residx) const +{ + return d->alternateName(residx); +} + +/** Set the alternate name of the passed atom */ +MoleculeInfo MoleculeInfo::setAlternateName(AtomIdx atomidx, const AtomName &name) const +{ + return MoleculeInfo(d->setAlternateName(atomidx, name)); +} + +/** Set the alternate name of the passed atom */ +MoleculeInfo MoleculeInfo::setAlternateName(ResIdx residx, const ResName &name) const +{ + return MoleculeInfo(d->setAlternateName(residx, name)); +} + +/** Switch to using the alternate names for all atoms and residues. + * If 'keep_originals' is true, then the original names will be + * stored in the alternate names. If 'keep_originals' is false, + * then the original names will be removed. + */ +MoleculeInfo MoleculeInfo::switchToAlternateNames(bool keep_originals) const +{ + return MoleculeInfo(d->switchToAlternateNames(keep_originals)); +} + +/** Remove all alternate names from this molecule */ +MoleculeInfo MoleculeInfo::removeAlternateNames() const +{ + return MoleculeInfo(d->removeAlternateNames()); +} diff --git a/corelib/src/libs/SireMol/moleculeinfo.h b/corelib/src/libs/SireMol/moleculeinfo.h index fe2695b6f..38f8d3aea 100644 --- a/corelib/src/libs/SireMol/moleculeinfo.h +++ b/corelib/src/libs/SireMol/moleculeinfo.h @@ -123,6 +123,18 @@ namespace SireMol const AtomName &name(const AtomID &atomid) const; const AtomName &name(AtomIdx atomidx) const; + const AtomName &alternateName(const AtomID &atomid) const; + const AtomName &alternateName(AtomIdx atomidx) const; + + const ResName &alternateName(const ResID &resid) const; + const ResName &alternateName(ResIdx residx) const; + + MoleculeInfo setAlternateName(AtomIdx atomidx, const AtomName &name) const; + MoleculeInfo setAlternateName(ResIdx residx, const ResName &name) const; + + MoleculeInfo switchToAlternateNames(bool keep_originals = true) const; + MoleculeInfo removeAlternateNames() const; + ResNum number(const ResID &resid) const; ResNum number(ResIdx residx) const; diff --git a/corelib/src/libs/SireMol/moleculeinfodata.cpp b/corelib/src/libs/SireMol/moleculeinfodata.cpp index 32db83780..24329965c 100644 --- a/corelib/src/libs/SireMol/moleculeinfodata.cpp +++ b/corelib/src/libs/SireMol/moleculeinfodata.cpp @@ -83,6 +83,9 @@ namespace SireMol /** The name of this residue */ ResName name; + /** The alternate name of this residue */ + ResName altname; + /** The number of this residue */ ResNum number; @@ -169,6 +172,9 @@ namespace SireMol /** The name of this atom */ AtomName name; + /** The alternate name of this atom */ + AtomName altname; + /** The number of this atom */ AtomNum number; @@ -206,10 +212,12 @@ QDataStream &operator>>(QDataStream &ds, AtomInfo &atominfo) { ds >> atominfo.name >> atominfo.number >> atominfo.residx >> atominfo.segidx >> atominfo.cgatomidx; + atominfo.altname = atominfo.name; + return ds; } -AtomInfo::AtomInfo() : name(QString()), number(AtomNum::null()), residx(ResIdx::null()), segidx(SegIdx::null()) +AtomInfo::AtomInfo() : name(QString()), altname(QString()), number(AtomNum::null()), residx(ResIdx::null()), segidx(SegIdx::null()) { } @@ -219,7 +227,8 @@ AtomInfo::~AtomInfo() bool AtomInfo::operator==(const AtomInfo &other) const { - return this == &other or (name == other.name and number == other.number and residx == other.residx and + return this == &other or (name == other.name and altname == other.altname and + number == other.number and residx == other.residx and segidx == other.segidx and cgatomidx == other.cgatomidx); } @@ -280,12 +289,14 @@ QDataStream &operator>>(QDataStream &ds, ResInfo &resinfo) { ds >> resinfo.name >> resinfo.number >> resinfo.chainidx >> resinfo.atom_indicies; + resinfo.altname = resinfo.name; + resinfo.cgidx = CGIdx::null(); return ds; } -ResInfo::ResInfo() : name(QString()), number(ResNum::null()), chainidx(ChainIdx::null()) +ResInfo::ResInfo() : name(QString()), altname(QString()), number(ResNum::null()), chainidx(ChainIdx::null()) { } @@ -295,7 +306,8 @@ ResInfo::~ResInfo() bool ResInfo::operator==(const ResInfo &other) const { - return this == &other or (name == other.name and number == other.number and chainidx == other.chainidx and + return this == &other or (name == other.name and altname == other.altname and + number == other.number and chainidx == other.chainidx and atom_indicies == other.atom_indicies); } @@ -385,13 +397,31 @@ static const RegisterMetaType r_molinfo(NO_ROOT); /** Serialise to a binary datastream */ QDataStream &operator<<(QDataStream &ds, const MoleculeInfoData &molinfo) { - writeHeader(ds, r_molinfo, 1); + writeHeader(ds, r_molinfo, 2); SharedDataStream sds(ds); sds << molinfo.uid << molinfo.atoms_by_index << molinfo.res_by_index << molinfo.chains_by_index << molinfo.seg_by_index << molinfo.cg_by_index; + QHash alt_atomnames; + + for (int i = 0; i < molinfo.atoms_by_index.count(); ++i) + { + if (molinfo.atoms_by_index[i].name != molinfo.atoms_by_index[i].altname) + alt_atomnames.insert(i, molinfo.atoms_by_index[i].altname.value()); + } + + QHash alt_resnames; + + for (int i = 0; i < molinfo.res_by_index.count(); ++i) + { + if (molinfo.res_by_index[i].name != molinfo.res_by_index[i].altname) + alt_resnames.insert(i, molinfo.res_by_index[i].altname.value()); + } + + sds << alt_atomnames << alt_resnames; + return ds; } @@ -595,7 +625,38 @@ QDataStream &operator>>(QDataStream &ds, MoleculeInfoData &molinfo) { VersionID v = readHeader(ds, r_molinfo); - if (v == 1) + if (v == 2) + { + SharedDataStream sds(ds); + + sds >> molinfo.uid >> molinfo.atoms_by_index >> molinfo.res_by_index >> molinfo.chains_by_index >> + molinfo.seg_by_index >> molinfo.cg_by_index; + + QHash alt_atomnames; + QHash alt_resnames; + + sds >> alt_atomnames >> alt_resnames; + + for (auto it = alt_atomnames.constBegin(); it != alt_atomnames.constEnd(); ++it) + { + if (it.key() >= 0 and it.key() < molinfo.atoms_by_index.count()) + { + molinfo.atoms_by_index[it.key()].altname = AtomName(it.value()); + } + } + + for (auto it = alt_resnames.constBegin(); it != alt_resnames.constEnd(); ++it) + { + if (it.key() >= 0 and it.key() < molinfo.res_by_index.count()) + { + molinfo.res_by_index[it.key()].altname = ResName(it.value()); + } + } + + // reconstruct the name and number indexes + molinfo.rebuildNameAndNumberIndexes(); + } + else if (v == 1) { SharedDataStream sds(ds); @@ -606,7 +667,7 @@ QDataStream &operator>>(QDataStream &ds, MoleculeInfoData &molinfo) molinfo.rebuildNameAndNumberIndexes(); } else - throw version_error(v, "1", r_molinfo, CODELOC); + throw version_error(v, "1, 2", r_molinfo, CODELOC); return ds; } @@ -658,6 +719,7 @@ MoleculeInfoData::MoleculeInfoData(const QString &resname, qint64 resnum, ResInfo res; res.name = ResName(resname.simplified()); + res.altname = res.name; res.number = ResNum(resnum); res.cgidx = CGIdx(0); @@ -685,6 +747,7 @@ MoleculeInfoData::MoleculeInfoData(const QString &resname, qint64 resnum, auto &atom = atoms_by_index_data[i]; atom.name = AtomName(atomnames_data[i].simplified()); + atom.altname = atom.name; atom.number = AtomNum(atomnums_data[i]); atom.residx = ResIdx(0); atom.cgatomidx = CGAtomIdx(CGIdx(0), Index(i)); @@ -849,13 +912,14 @@ MoleculeInfoData::MoleculeInfoData(const StructureEditor &editor) : RefCountData // create the data for atom 'i' AtomInfo &atom = atoms_by_index_array[i]; - tuple atomdata = editor.getAtomData(i); + tuple atomdata = editor.getAtomData(i); atom.name = atomdata.get<0>(); - atom.number = atomdata.get<1>(); - atom.cgatomidx = atomdata.get<2>(); - atom.residx = atomdata.get<3>(); - atom.segidx = atomdata.get<4>(); + atom.altname = atomdata.get<1>(); + atom.number = atomdata.get<2>(); + atom.cgatomidx = atomdata.get<3>(); + atom.residx = atomdata.get<4>(); + atom.segidx = atomdata.get<5>(); if (atom.cgatomidx.cutGroup().isNull()) atoms_missing_cutgroups.append(i); @@ -902,12 +966,13 @@ MoleculeInfoData::MoleculeInfoData(const StructureEditor &editor) : RefCountData { ResInfo &residue = res_by_index_array[i]; - tuple> resdata = editor.getResData(i); + tuple> resdata = editor.getResData(i); residue.name = resdata.get<0>(); - residue.number = resdata.get<1>(); - residue.chainidx = resdata.get<2>(); - residue.atom_indicies = resdata.get<3>(); + residue.altname = resdata.get<1>(); + residue.number = resdata.get<2>(); + residue.chainidx = resdata.get<3>(); + residue.atom_indicies = resdata.get<4>(); if (residue.atom_indicies.isEmpty()) empty_residues.append(i); @@ -1336,6 +1401,144 @@ void remove_from_hash(QMultiHash &hash, const Key &key, const T &value) } #endif +/** Return the alternate name of the specified atom */ +const AtomName &MoleculeInfoData::alternateName(const AtomID &atomid) const +{ + return this->alternateName(this->atomIdx(atomid)); +} + +/** Return the alternate name of the specified atom */ +const AtomName &MoleculeInfoData::alternateName(AtomIdx atomidx) const +{ + atomidx = atomidx.map(this->nAtoms()); + return atoms_by_index.at(atomidx).altname; +} + +/** Return the alternate name of the specified residue */ +const ResName &MoleculeInfoData::alternateName(const ResID &resid) const +{ + return this->alternateName(this->resIdx(resid)); +} + +/** Return the alternate name of the specified residue */ +const ResName &MoleculeInfoData::alternateName(ResIdx residx) const +{ + residx = residx.map(this->nResidues()); + return res_by_index.at(residx).altname; +} + +/** Set the alternate name of the passed atom */ +MoleculeInfoData MoleculeInfoData::setAlternateName(AtomIdx atomidx, const AtomName &altname) const +{ + atomidx = atomidx.map(this->nAtoms()); + + if (atoms_by_index.at(atomidx).altname == altname) + return *this; + + // make the change in a copy of this object + MoleculeInfoData newinfo(*this); + newinfo.atoms_by_index[atomidx].altname = altname; + + return newinfo; +} + +/* Set the alternate name of the passed residue */ +MoleculeInfoData MoleculeInfoData::setAlternateName(ResIdx residx, const ResName &altname) const +{ + residx = residx.map(this->nResidues()); + + if (res_by_index.at(residx).altname == altname) + return *this; + + // make the change in a copy of this object + MoleculeInfoData newinfo(*this); + newinfo.res_by_index[residx].altname = altname; + + return newinfo; +} + +/** Switch to using the alternate names for all atoms and residues. + * If 'keep_originals' is true, then the original names will be + * stored in the alternate names. If 'keep_originals' is false, + * then the original names will be removed. + */ +MoleculeInfoData MoleculeInfoData::switchToAlternateNames(bool keep_originals) const +{ + MoleculeInfoData newinfo(*this); + + bool changed = false; + + for (int i = 0; i < newinfo.atoms_by_index.count(); ++i) + { + AtomInfo &atom = newinfo.atoms_by_index[i]; + + auto newname = atom.altname; + + if (newname.isNull()) + newname = atom.name; + + if (newname != atom.name) + { + if (keep_originals) + atom.altname = atom.name; + else + atom.altname = newname; + + atom.name = newname; + changed = true; + } + } + + for (int i = 0; i < newinfo.res_by_index.count(); ++i) + { + ResInfo &res = newinfo.res_by_index[i]; + + auto newname = res.altname; + + if (newname.isNull()) + newname = res.name; + + if (newname != res.name) + { + if (keep_originals) + res.altname = res.name; + else + res.altname = newname; + + res.name = newname; + changed = true; + } + } + + if (changed) + { + newinfo.rebuildNameAndNumberIndexes(); + newinfo.uid = QUuid::createUuid(); + } + + return newinfo; +} + +/** Remove all alternate names from this molecule */ +MoleculeInfoData MoleculeInfoData::removeAlternateNames() const +{ + MoleculeInfoData newinfo(*this); + + for (int i = 0; i < newinfo.atoms_by_index.count(); ++i) + { + AtomInfo &atom = newinfo.atoms_by_index[i]; + atom.altname = atom.name; + } + + for (int i = 0; i < newinfo.res_by_index.count(); ++i) + { + ResInfo &res = newinfo.res_by_index[i]; + res.altname = res.name; + } + + return newinfo; +} + /** Rename the atom at index 'atomidx' to have the new name 'newname'. \throw SireError::invalid_index diff --git a/corelib/src/libs/SireMol/moleculeinfodata.h b/corelib/src/libs/SireMol/moleculeinfodata.h index 012cc4f0b..ffb30e52f 100644 --- a/corelib/src/libs/SireMol/moleculeinfodata.h +++ b/corelib/src/libs/SireMol/moleculeinfodata.h @@ -182,6 +182,12 @@ namespace SireMol const AtomName &name(const AtomID &atomid) const; const AtomName &name(AtomIdx atomidx) const; + const AtomName &alternateName(const AtomID &atomid) const; + const AtomName &alternateName(AtomIdx atomidx) const; + + const ResName &alternateName(const ResID &resid) const; + const ResName &alternateName(ResIdx residx) const; + SegIdx number(const SegID &segid) const; SegIdx number(SegIdx segidx) const; @@ -197,6 +203,12 @@ namespace SireMol AtomNum number(const AtomID &atomid) const; AtomNum number(AtomIdx atomidx) const; + MoleculeInfoData setAlternateName(AtomIdx atomidx, const AtomName &newname) const; + MoleculeInfoData setAlternateName(ResIdx residx, const ResName &newname) const; + + MoleculeInfoData switchToAlternateNames(bool keep_originals = true) const; + MoleculeInfoData removeAlternateNames() const; + MoleculeInfoData rename(AtomIdx atomidx, const AtomName &newname) const; MoleculeInfoData renumber(AtomIdx atomidx, const AtomNum &newnum) const; diff --git a/corelib/src/libs/SireMol/moleditor.cpp b/corelib/src/libs/SireMol/moleditor.cpp index dd0df85e3..ff7f3ef7e 100644 --- a/corelib/src/libs/SireMol/moleditor.cpp +++ b/corelib/src/libs/SireMol/moleditor.cpp @@ -137,6 +137,24 @@ MolEditor &MolEditor::rename(const QString &newname) return *this; } +/** Switch to using the alternate names for all atoms and residues. + * If 'keep_originals' is true, then the original names will be + * stored in the alternate names. If 'keep_originals' is false, + * then the original names will be removed. + */ +MolEditor &MolEditor::switchToAlternateNames(bool keep_originals) +{ + d->switchToAlternateNames(keep_originals); + return *this; +} + +/** Remove all alternate names from this molecule */ +MolEditor &MolEditor::removeAlternateNames() +{ + d->removeAlternateNames(); + return *this; +} + /** Give this molecule a new, unique ID number */ MolEditor &MolEditor::renumber() { @@ -189,6 +207,15 @@ MolEditor &MolEditor::renumber(const QHash &atomnums, const QH return *this; } +/** Return an editor where all atoms have been moved into a + * single cutgroup + */ +MolStructureEditor MolEditor::makeSingleCutGroup() const +{ + MolStructureEditor editor(*this); + return editor.makeSingleCutGroup(); +} + /** Add an atom called 'name' and return an editor that can be used to edit it */ AtomStructureEditor MolEditor::add(const AtomName &name) const @@ -633,6 +660,31 @@ MolStructureEditor &MolStructureEditor::rename(const MolName &newname) return *this; } +/** Switch to using the alternate names for all atoms and residues. + * If 'keep_originals' is true, then the original names will be + * stored in the alternate names. If 'keep_originals' is false, + * then the original names will be removed. + */ +MolStructureEditor MolStructureEditor::switchToAlternateNames(bool keep_originals) +{ + StructureEditor::switchToAlternates(keep_originals); + return *this; +} + +/** Remove all alternate names from this molecule */ +MolStructureEditor MolStructureEditor::removeAlternateNames() +{ + StructureEditor::removeAlternates(); + return *this; +} + +/** Move all atoms into a single CutGroup */ +MolStructureEditor &MolStructureEditor::makeSingleCutGroup() +{ + StructureEditor::convertToSingleCutGroupMolecule(); + return *this; +} + /** Give this molecule a new, unique ID number */ MolStructureEditor &MolStructureEditor::renumber() { diff --git a/corelib/src/libs/SireMol/moleditor.h b/corelib/src/libs/SireMol/moleditor.h index ea148af4a..afd3f7190 100644 --- a/corelib/src/libs/SireMol/moleditor.h +++ b/corelib/src/libs/SireMol/moleditor.h @@ -111,6 +111,9 @@ namespace SireMol MolEditor &renumber(const QHash &resnums); MolEditor &renumber(const QHash &atomnums, const QHash &resnums); + MolEditor &switchToAlternateNames(bool keep_originals = true); + MolEditor &removeAlternateNames(); + bool updateProperty(const QString &key, const Property &value, bool auto_add = true); template @@ -120,6 +123,8 @@ namespace SireMol MolEditor &removeLink(const QString &key); MolEditor &removeAllLinks(); + MolStructureEditor makeSingleCutGroup() const; + AtomStructureEditor add(const AtomName &atom) const; AtomStructureEditor add(const AtomNum &atom) const; @@ -191,6 +196,8 @@ namespace SireMol int nChains() const; int nSegments() const; + MolStructureEditor &makeSingleCutGroup(); + AtomStructureEditor select(const AtomID &atomid); CGStructureEditor select(const CGID &cgid); ResStructureEditor select(const ResID &resid); @@ -207,6 +214,9 @@ namespace SireMol MolStructureEditor &renumber(MolNum newnum); MolStructureEditor &renumber(); + MolStructureEditor switchToAlternateNames(bool keep_originals = true); + MolStructureEditor removeAlternateNames(); + AtomStructureEditor add(const AtomName &atom); AtomStructureEditor add(const AtomNum &atom); diff --git a/corelib/src/libs/SireMol/molviewproperty.cpp b/corelib/src/libs/SireMol/molviewproperty.cpp index d6ddc7214..6be688a0d 100644 --- a/corelib/src/libs/SireMol/molviewproperty.cpp +++ b/corelib/src/libs/SireMol/molviewproperty.cpp @@ -29,6 +29,7 @@ #include "atommatcher.h" #include "atommatchers.h" #include "moleculeinfodata.h" +#include "atomidxmapping.h" #include "mover.hpp" diff --git a/corelib/src/libs/SireMol/molviewproperty.h b/corelib/src/libs/SireMol/molviewproperty.h index c2250e0f8..a27770ec5 100644 --- a/corelib/src/libs/SireMol/molviewproperty.h +++ b/corelib/src/libs/SireMol/molviewproperty.h @@ -31,6 +31,7 @@ #include #include "SireBase/property.h" +#include "SireBase/propertylist.h" #include "moleculeinfo.h" @@ -45,10 +46,12 @@ namespace SireMol { class MoleculeInfoData; + class MoleculeInfo; class MoleculeView; class AtomSelection; class AtomIdx; class AtomMatcher; + class AtomIdxMapping; /** This is the base class of all properties that are specifically attached to views of a molecule (e.g. AtomProperty, ResProperty, @@ -83,6 +86,11 @@ namespace SireMol SireBase::PropertyPtr makeCompatibleWith(const MoleculeView &mol, const AtomMatcher &atommatcher) const; SireBase::PropertyPtr makeCompatibleWith(const MoleculeView &mol, const QHash &map) const; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const = 0; + void assertCompatibleWith(const MoleculeInfoData &molinfo) const; void assertCompatibleWith(const MoleculeInfo &molinfo) const; diff --git a/corelib/src/libs/SireMol/reseditor.cpp b/corelib/src/libs/SireMol/reseditor.cpp index 86ff70e83..71c86a5f2 100644 --- a/corelib/src/libs/SireMol/reseditor.cpp +++ b/corelib/src/libs/SireMol/reseditor.cpp @@ -127,6 +127,30 @@ QString ResEditor::toString() const return QObject::tr("Editor{ %1 }").arg(Residue::toString()); } +/** Return the alternate name for this residue */ +ResName ResEditor::alternateName() const +{ + return d->getAlternateResName(this->index()); +} + +/** Set the alternate residue name for this residue */ +ResEditor &ResEditor::setAlternateName(const ResName &altname) +{ + if (altname == this->alternateName()) + // nothing to do + return *this; + + d->setAlternateResName(this->index(), altname); + + return *this; +} + +/** Set the alternate name for this residue */ +ResEditor &ResEditor::setAlternateName(const QString &altname) +{ + return this->setAlternateName(ResName(altname)); +} + /** Rename this residue to 'newname' */ ResEditor &ResEditor::rename(const ResName &newname) { @@ -139,6 +163,12 @@ ResEditor &ResEditor::rename(const ResName &newname) return *this; } +/** Rename this residue to 'newname' */ +ResEditor &ResEditor::rename(const QString &newname) +{ + return this->rename(ResName(newname)); +} + /** Renumber this residue to 'newnum' */ ResEditor &ResEditor::renumber(ResNum newnum) { @@ -151,6 +181,12 @@ ResEditor &ResEditor::renumber(ResNum newnum) return *this; } +/** Renumber this residue to 'newnum' */ +ResEditor &ResEditor::renumber(int newnum) +{ + return this->renumber(ResNum(newnum)); +} + /** Change the index of this residue to 'newidx'. If this is larger than the number of residues in the molecule then this residue is moved to the end */ @@ -162,6 +198,12 @@ ResStructureEditor ResEditor::reindex(ResIdx newidx) const return editor; } +/** Reindex this residue to 'newidx' */ +ResStructureEditor ResEditor::reindex(int newidx) const +{ + return this->reindex(ResIdx(newidx)); +} + /** Completely remove this residue from the molecule - this returns a MolStructureEditor that can be used to further edit the molecule */ MolStructureEditor ResEditor::remove() const @@ -447,6 +489,25 @@ AtomStructureEditor ResStructureEditor::select(const AtomID &atomid) return AtomStructureEditor(*this, atomIdx(atomid)); } +/** Return the alternate name for this residue */ +const ResName &ResStructureEditor::alternateName() const +{ + return StructureEditor::getAlternateResName(uid); +} + +/** Set the alternate residue name for this residue */ +ResStructureEditor &ResStructureEditor::setAlternateName(const ResName &altname) +{ + StructureEditor::setAlternateResName(uid, altname); + return *this; +} + +/** Set the alternate name for this residue */ +ResStructureEditor &ResStructureEditor::setAlternateName(const QString &altname) +{ + return this->setAlternateName(ResName(altname)); +} + /** Rename this residue to 'newname' */ ResStructureEditor &ResStructureEditor::rename(const ResName &newname) { @@ -454,6 +515,12 @@ ResStructureEditor &ResStructureEditor::rename(const ResName &newname) return *this; } +/** Rename this residue to 'newname' */ +ResStructureEditor &ResStructureEditor::rename(const QString &newname) +{ + return this->rename(ResName(newname)); +} + /** Renumber this residue to 'newnum' */ ResStructureEditor &ResStructureEditor::renumber(ResNum newnum) { @@ -461,6 +528,12 @@ ResStructureEditor &ResStructureEditor::renumber(ResNum newnum) return *this; } +/** Renumber this residue to 'newnum' */ +ResStructureEditor &ResStructureEditor::renumber(int newnum) +{ + return this->renumber(ResNum(newnum)); +} + /** Change the index of this residue to 'newidx'. If this is larger than the number of residues in the molecule then this residue is moved to the end */ @@ -470,6 +543,12 @@ ResStructureEditor &ResStructureEditor::reindex(ResIdx newidx) return *this; } +/** Reindex this residue to 'newidx' */ +ResStructureEditor &ResStructureEditor::reindex(int newidx) +{ + return this->reindex(ResIdx(newidx)); +} + /** Completely remove this residue from the molecule - this returns a MolStructureEditor that can be used to further edit the molecule */ MolStructureEditor ResStructureEditor::remove() diff --git a/corelib/src/libs/SireMol/reseditor.h b/corelib/src/libs/SireMol/reseditor.h index 1029052d2..4a794ab3d 100644 --- a/corelib/src/libs/SireMol/reseditor.h +++ b/corelib/src/libs/SireMol/reseditor.h @@ -101,7 +101,16 @@ namespace SireMol ResEditor &rename(const ResName &name); ResEditor &renumber(ResNum number); + ResEditor &rename(const QString &name); + ResEditor &renumber(int number); + ResStructureEditor reindex(ResIdx index) const; + ResStructureEditor reindex(int index) const; + + ResEditor &setAlternateName(const ResName &name); + ResEditor &setAlternateName(const QString &name); + + ResName alternateName() const; MolStructureEditor remove() const; @@ -174,9 +183,17 @@ namespace SireMol ResStructureEditor &rename(const ResName &name); ResStructureEditor &renumber(ResNum number); - ResStructureEditor &reindex(ResIdx index); + ResStructureEditor &rename(const QString &name); + ResStructureEditor &renumber(int number); + ResStructureEditor &reindex(int index); + + ResStructureEditor &setAlternateName(const ResName &name); + ResStructureEditor &setAlternateName(const QString &name); + + const ResName &alternateName() const; + MolStructureEditor remove(); ResStructureEditor &reparent(const ChainID &chainid); diff --git a/corelib/src/libs/SireMol/residue.cpp b/corelib/src/libs/SireMol/residue.cpp index cdf76ce34..a254f02cd 100644 --- a/corelib/src/libs/SireMol/residue.cpp +++ b/corelib/src/libs/SireMol/residue.cpp @@ -228,6 +228,12 @@ ResName Residue::name() const return d->info().name(residx); } +/** Return the alternate name of this residue */ +ResName Residue::alternateName() const +{ + return d->getAlternateResName(residx); +} + /** Return the number of this residue */ ResNum Residue::number() const { diff --git a/corelib/src/libs/SireMol/residue.h b/corelib/src/libs/SireMol/residue.h index 3d6e2a39f..a130a63ab 100644 --- a/corelib/src/libs/SireMol/residue.h +++ b/corelib/src/libs/SireMol/residue.h @@ -120,6 +120,8 @@ namespace SireMol ResNum number() const; ResIdx index() const; + ResName alternateName() const; + bool hasProperty(const PropertyName &key) const; bool hasMetadata(const PropertyName &metakey) const; bool hasMetadata(const PropertyName &key, const PropertyName &metakey) const; diff --git a/corelib/src/libs/SireMol/resproperty.hpp b/corelib/src/libs/SireMol/resproperty.hpp index 0ab9828b6..ca3448be2 100644 --- a/corelib/src/libs/SireMol/resproperty.hpp +++ b/corelib/src/libs/SireMol/resproperty.hpp @@ -33,6 +33,7 @@ #include "SireBase/convert_property.hpp" #include "SireBase/qvariant_metatype.h" #include "SireBase/slice.h" +#include "SireBase/console.h" #include "moleculeinfodata.h" #include "molviewproperty.h" @@ -104,7 +105,7 @@ namespace SireMol { friend SIREMOL_EXPORT QDataStream & ::operator<< <>(QDataStream &, const ResProperty &); - friend SIREMOL_EXPORT QDataStream & ::operator>><>(QDataStream &, ResProperty &); + friend SIREMOL_EXPORT QDataStream & ::operator>> <>(QDataStream &, ResProperty &); public: ResProperty(); @@ -168,6 +169,11 @@ namespace SireMol void assertCanConvert(const QVariant &value) const; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual residue property values */ QVector props; @@ -547,6 +553,32 @@ namespace SireMol return molinfo.nResidues() == this->nResidues(); } + /** Merge this property with another property */ + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList ResProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // namespace SireMol diff --git a/corelib/src/libs/SireMol/segproperty.hpp b/corelib/src/libs/SireMol/segproperty.hpp index de7518b93..e9eedc980 100644 --- a/corelib/src/libs/SireMol/segproperty.hpp +++ b/corelib/src/libs/SireMol/segproperty.hpp @@ -33,6 +33,7 @@ #include "SireBase/convert_property.hpp" #include "SireBase/qvariant_metatype.h" #include "SireBase/slice.h" +#include "SireBase/console.h" #include "moleculeinfodata.h" #include "molviewproperty.h" @@ -104,7 +105,7 @@ namespace SireMol { friend SIREMOL_EXPORT QDataStream & ::operator<< <>(QDataStream &, const SegProperty &); - friend SIREMOL_EXPORT QDataStream & ::operator>><>(QDataStream &, SegProperty &); + friend SIREMOL_EXPORT QDataStream & ::operator>> <>(QDataStream &, SegProperty &); public: SegProperty(); @@ -168,6 +169,11 @@ namespace SireMol void assertCanConvert(const QVariant &value) const; + virtual SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The actual segment property values */ QVector props; @@ -547,6 +553,32 @@ namespace SireMol return molinfo.nSegments() == this->nSegments(); } + /** Merge this property with another property */ + template + SIRE_OUTOFLINE_TEMPLATE SireBase::PropertyList SegProperty::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const + { + if (not other.isA>()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // namespace SireMol diff --git a/corelib/src/libs/SireMol/selector.hpp b/corelib/src/libs/SireMol/selector.hpp index 967c937d8..58d24d2cb 100644 --- a/corelib/src/libs/SireMol/selector.hpp +++ b/corelib/src/libs/SireMol/selector.hpp @@ -114,7 +114,7 @@ namespace SireMol { friend SIREMOL_EXPORT QDataStream & ::operator<< <>(QDataStream &, const Selector &); - friend SIREMOL_EXPORT QDataStream & ::operator>><>(QDataStream &, Selector &); + friend SIREMOL_EXPORT QDataStream & ::operator>> <>(QDataStream &, Selector &); public: Selector(); @@ -206,6 +206,12 @@ namespace SireMol bool isSelector() const; + void assertSingleMolecule() const; + + bool isSingleMolecule() const; + + Selector toSingleMolecule() const; + Selector add(const Selector &other) const; Selector add(const T &view) const; Selector add(const typename T::ID &id) const; @@ -1840,6 +1846,33 @@ namespace SireMol return this->operator()(0).metadataKeys(key); } + template + SIRE_OUTOFLINE_TEMPLATE bool Selector::isSingleMolecule() const + { + if (this->isEmpty()) + return false; + else + return true; + } + + template + SIRE_OUTOFLINE_TEMPLATE void Selector::assertSingleMolecule() const + { + if (not this->isSingleMolecule()) + { + throw SireMol::missing_molecule(QObject::tr( + "There are no molecules represented in this object."), + CODELOC); + } + } + + template + SIRE_OUTOFLINE_TEMPLATE Selector Selector::toSingleMolecule() const + { + this->assertSingleMolecule(); + return *this; + } + #endif // SIRE_SKIP_INLINE_FUNCTIONS } // end of namespace SireMol diff --git a/corelib/src/libs/SireMol/selectorm.hpp b/corelib/src/libs/SireMol/selectorm.hpp index 0859fc9c7..7852e66ed 100644 --- a/corelib/src/libs/SireMol/selectorm.hpp +++ b/corelib/src/libs/SireMol/selectorm.hpp @@ -317,6 +317,11 @@ namespace SireMol QStringList metadataKeys() const; QStringList metadataKeys(const PropertyName &key) const; + bool isSingleMolecule() const; + void assertSingleMolecule() const; + + Selector toSingleMolecule() const; + template QList property(const PropertyName &key) const; @@ -2861,6 +2866,64 @@ namespace SireMol return ret; } + template + SIRE_OUTOFLINE_TEMPLATE bool SelectorM::isSingleMolecule() const + { + if (this->isEmpty()) + return false; + else if (this->vws.count() == 1) + return true; + else + { + MolNum molnum = this->vws.at(0).data().number(); + + for (int i = 1; i < this->vws.count(); ++i) + { + if (this->vws.at(i).data().number() != molnum) + return false; + } + + return true; + } + } + + template + SIRE_OUTOFLINE_TEMPLATE void SelectorM::assertSingleMolecule() const + { + if (this->isEmpty()) + { + throw SireMol::missing_molecule(QObject::tr( + "There are no molecules represented in this object - it is empty."), + CODELOC); + } + else if (not this->isSingleMolecule()) + { + throw SireMol::duplicate_molecule(QObject::tr( + "There is more than one molecule represented in this object. The molecules are: %1") + .arg(this->molecules().toString()), + CODELOC); + } + } + + template + SIRE_OUTOFLINE_TEMPLATE Selector SelectorM::toSingleMolecule() const + { + this->assertSingleMolecule(); + + if (this->vws.count() == 1) + return this->vws.at(0); + + // we need to combine the matching views together into a single view + Selector ret = this->vws.at(0); + + for (int i = 1; i < this->vws.count(); ++i) + { + ret += this->vws.at(i); + } + + return ret; + } + template SIRE_OUTOFLINE_TEMPLATE QString SelectorM::toString() const { diff --git a/corelib/src/libs/SireMol/structureeditor.cpp b/corelib/src/libs/SireMol/structureeditor.cpp index 3196b2c68..df276c401 100644 --- a/corelib/src/libs/SireMol/structureeditor.cpp +++ b/corelib/src/libs/SireMol/structureeditor.cpp @@ -75,6 +75,7 @@ #include "segproperty.hpp" #include "SireBase/properties.h" +#include "SireBase/console.h" #include "tostring.h" @@ -153,6 +154,7 @@ namespace SireMol ~EditAtomData(); AtomName name; + AtomName altname; AtomNum number; quint32 cg_parent; @@ -198,6 +200,7 @@ namespace SireMol ~EditResData(); ResName name; + ResName altname; ResNum number; quint32 chain_parent; @@ -404,6 +407,8 @@ QDataStream &operator>>(QDataStream &ds, EditAtomData &editatom) ds >> editatom.name >> editatom.number >> editatom.cg_parent >> editatom.res_parent >> editatom.seg_parent >> editatom.properties >> editatom.molecule_metadata >> editatom.property_metadata; + editatom.altname = AtomName(); + return ds; } @@ -485,6 +490,8 @@ QDataStream &operator>>(QDataStream &ds, EditResData &editres) ds >> editres.name >> editres.number >> editres.chain_parent >> editres.atoms >> editres.properties >> editres.molecule_metadata >> editres.property_metadata; + editres.altname = ResName(); + return ds; } @@ -2889,12 +2896,38 @@ static const RegisterMetaType r_editor(MAGIC_ONLY, "SireMol::St /** Serialise to a binary datastream */ QDataStream &operator<<(QDataStream &ds, const StructureEditor &editor) { - writeHeader(ds, r_editor, 1); + writeHeader(ds, r_editor, 2); SharedDataStream sds(ds); sds << editor.d; + QHash alt_atomnames; + + for (int i = 0; i < editor.d->atoms.count(); ++i) + { + const EditAtomData &atom = editor.d->atoms[i]; + + if (not atom.altname.isEmpty()) + { + alt_atomnames.insert(i, atom.altname.value()); + } + } + + QHash alt_resnames; + + for (int i = 0; i < editor.d->residues.count(); ++i) + { + const EditResData &res = editor.d->residues[i]; + + if (not res.altname.isEmpty()) + { + alt_resnames.insert(i, res.altname.value()); + } + } + + sds << alt_atomnames << alt_resnames; + return ds; } @@ -2903,10 +2936,29 @@ QDataStream &operator>>(QDataStream &ds, StructureEditor &editor) { VersionID v = readHeader(ds, r_editor); - if (v == 1) + if (v == 1 or v == 2) { SharedDataStream sds(ds); sds >> editor.d; + + if (v == 2) + { + QHash alt_atomnames, alt_resnames; + + sds >> alt_atomnames >> alt_resnames; + + for (auto it = alt_atomnames.constBegin(); it != alt_atomnames.constEnd(); ++it) + { + if (it.key() >= 0 and it.key() < editor.d->atoms.count()) + editor.d->atoms[it.key()].altname = AtomName(it.value()); + } + + for (auto it = alt_resnames.constBegin(); it != alt_resnames.constEnd(); ++it) + { + if (it.key() >= 0 and it.key() < editor.d->residues.count()) + editor.d->residues[it.key()].altname = ResName(it.value()); + } + } } else throw version_error(v, "1", r_editor, CODELOC); @@ -3002,15 +3054,15 @@ SegIdx EditMolData::segIdx(const EditAtomData &atom) const \throw SireError::invalid_index */ -tuple StructureEditor::getAtomData(AtomIdx atomidx) const +tuple StructureEditor::getAtomData(AtomIdx atomidx) const { this->assertSane(); quint32 atomuid = getUID(atomidx); const EditAtomData &atom = d->atom(atomuid); - return tuple(atom.name, atom.number, d->cgAtomIdx(atomuid, atom), - d->resIdx(atom), d->segIdx(atom)); + return tuple(atom.name, atom.altname, atom.number, d->cgAtomIdx(atomuid, atom), + d->resIdx(atom), d->segIdx(atom)); } /** Return all of the metadata about the CutGroup at index 'cgidx' @@ -3050,7 +3102,7 @@ ChainIdx EditMolData::chainIdx(const EditResData &residue) const \throw SireError::invalid_index */ -boost::tuple> StructureEditor::getResData(ResIdx residx) const +boost::tuple> StructureEditor::getResData(ResIdx residx) const { this->assertSane(); @@ -3063,8 +3115,8 @@ boost::tuple> StructureEditor::getResD atomidxs.append(AtomIdx(d->atoms_by_index.indexOf(atom))); } - return tuple>(residue.name, residue.number, d->chainIdx(residue), - atomidxs); + return tuple>(residue.name, residue.altname, residue.number, d->chainIdx(residue), + atomidxs); } /** Return the metadata for the chain at index 'chainidx' @@ -3150,7 +3202,7 @@ const MoleculeInfoData &StructureEditor::commitInfo() { const auto info = this->getAtomData(AtomIdx(i)); - if (info.get<2>().isNull()) + if (info.get<3>().isNull()) { // this atom isn't in a CutGroup // Reparent it into the first CutGroup @@ -3909,6 +3961,119 @@ void StructureEditor::renumberMolecule(MolNum newnum) d->molnum = newnum; } +/** Set the alternate atom name */ +void StructureEditor::setAlternateAtomName(quint32 uid, const AtomName &name) +{ + this->assertSane(); + + EditAtomData &atom = d->atom(uid); + + if (atom.altname != name) + { + atom.altname = AtomName(cacheName(name)); + d->cached_molinfo = 0; + } +} + +/** Set the alternate residue name */ +void StructureEditor::setAlternateResName(quint32 uid, const ResName &name) +{ + this->assertSane(); + + EditResData &res = d->residue(uid); + + if (res.altname != name) + { + res.altname = ResName(cacheName(name)); + d->cached_molinfo = 0; + } +} + +/** Return the alternate atom name - this will be the atom name if + * this hasn't been set + */ +const AtomName &StructureEditor::getAlternateAtomName(quint32 uid) const +{ + this->assertSane(); + + EditAtomData &atom = d->atom(uid); + + if (atom.altname.isNull()) + return atom.name; + else + return atom.altname; +} + +const ResName &StructureEditor::getAlternateResName(quint32 uid) const +{ + this->assertSane(); + + EditResData &res = d->residue(uid); + + if (res.altname.isNull()) + return res.name; + else + return res.altname; +} + +/** Switch to using the alternate names for all atoms and residues. + * If 'keep_originals' is true, then the original names will be + * stored in the alternate names. If 'keep_originals' is false, + * then the original names will be removed. + */ +void StructureEditor::switchToAlternates(bool keep_originals) +{ + this->assertSane(); + + for (auto it = d->atoms.begin(); it != d->atoms.end(); ++it) + { + if (not it.value().altname.isNull()) + { + auto newname = it.value().altname; + + if (keep_originals) + it.value().altname = it.value().name; + + it.value().name = newname; + } + } + + for (auto it = d->residues.begin(); it != d->residues.end(); ++it) + { + if (not it.value().altname.isNull()) + { + auto newname = it.value().altname; + + if (keep_originals) + it.value().altname = it.value().name; + + it.value().name = newname; + } + } +} + +/** Remove all alternate names from this molecule */ +void StructureEditor::removeAlternates() +{ + this->assertSane(); + + for (auto it = d->atoms.begin(); it != d->atoms.end(); ++it) + { + if (not it.value().altname.isNull()) + { + it.value().altname = AtomName(); + } + } + + for (auto it = d->residues.begin(); it != d->residues.end(); ++it) + { + if (not it.value().altname.isNull()) + { + it.value().altname = ResName(); + } + } +} + /** Rename the atom identified by 'uid' to 'newname' \throw SireMol::missing_atom @@ -4425,6 +4590,31 @@ void StructureEditor::removeAllAtoms() } } +/** Move all atoms into a single CutGroup */ +void StructureEditor::convertToSingleCutGroupMolecule() +{ + this->assertSane(); + + QList cg_by_index = d->cg_by_index; + + if (cg_by_index.count() <= 1) + { + // nothing to do + return; + } + + for (quint32 i = 0; i < this->nAtomsInMolecule(); ++i) + { + this->reparentAtom(i, CGIdx(0)); + } + + // now remove all of the other CutGroups + for (int i = cg_by_index.count() - 1; i > 0; --i) + { + this->removeCutGroup(CGIdx(i)); + } +} + /** Remove all CutGroups from this molecule */ void StructureEditor::removeAllCutGroups() { @@ -4856,8 +5046,14 @@ Properties StructureEditor::properties() const { updated_property = updated_property->asA().makeCompatibleWith(this->info(), mapping); } - catch (...) + catch (const SireError::exception &e) { + SireBase::Console::warning(QObject::tr("Could not convert the old property at key %1 with type %2 to match " + "the new, edited molecule. This property has been deleted.\nError was %3: %4") + .arg(key) + .arg(updated_property->what()) + .arg(e.what()) + .arg(e.error())); updated_property = NullProperty(); } } diff --git a/corelib/src/libs/SireMol/structureeditor.h b/corelib/src/libs/SireMol/structureeditor.h index 8f335b6a2..209e04ce9 100644 --- a/corelib/src/libs/SireMol/structureeditor.h +++ b/corelib/src/libs/SireMol/structureeditor.h @@ -175,17 +175,18 @@ namespace SireMol const MoleculeInfoData &info() const; /// functions used by MoleculeInfoData when committing - boost::tuple getAtomData(AtomIdx atomidx) const; + boost::tuple getAtomData(AtomIdx atomidx) const; boost::tuple> getCGData(CGIdx cgidx) const; - boost::tuple> getResData(ResIdx residx) const; + boost::tuple> getResData(ResIdx residx) const; boost::tuple> getChainData(ChainIdx chainidx) const; boost::tuple> getSegData(SegIdx segidx) const; /// Functions predominantly for StructureEditor derived classes + void convertToSingleCutGroupMolecule(); quint32 getUID(AtomIdx atomidx) const; quint32 getUID(CGIdx cgidx) const; @@ -275,6 +276,15 @@ namespace SireMol void renameSegment(quint32 uid, const SegName &name); void reindexSegment(quint32 uid, SegIdx index); + void setAlternateAtomName(quint32 uid, const AtomName &name); + void setAlternateResName(quint32 uid, const ResName &name); + + const AtomName &getAlternateAtomName(quint32 uid) const; + const ResName &getAlternateResName(quint32 uid) const; + + void switchToAlternates(bool keep_originals = true); + void removeAlternates(); + void removeAtom(quint32 uid); void removeCutGroup(quint32 uid); void removeResidue(quint32 uid); diff --git a/corelib/src/libs/SireMol/trajectory.cpp b/corelib/src/libs/SireMol/trajectory.cpp index 3f13c6766..c2728c59f 100644 --- a/corelib/src/libs/SireMol/trajectory.cpp +++ b/corelib/src/libs/SireMol/trajectory.cpp @@ -27,6 +27,7 @@ #include "trajectory.h" #include "trajectoryaligner.h" +#include "atomidxmapping.h" #include "SireID/index.h" @@ -41,6 +42,7 @@ #include "SireBase/generalunitproperty.h" #include "SireBase/lazyevaluator.h" +#include "SireBase/console.h" #include "SireBase/slice.h" @@ -1010,6 +1012,31 @@ bool Trajectory::isCompatibleWith(const MoleculeInfoData &molinfo) const return this->nAtoms() == molinfo.nAtoms(); } +/** Merge this property with another property */ +PropertyList Trajectory::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} + /////// /////// Implementation of Frame /////// @@ -1839,3 +1866,28 @@ Frame Frame::join(const QVector &frames, return ret; } + +/** Merge this property with another property */ +PropertyList Frame::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} diff --git a/corelib/src/libs/SireMol/trajectory.h b/corelib/src/libs/SireMol/trajectory.h index 1a44040d3..c5172d2a9 100644 --- a/corelib/src/libs/SireMol/trajectory.h +++ b/corelib/src/libs/SireMol/trajectory.h @@ -32,6 +32,7 @@ #include "SireMol/atomforces.h" #include "SireMol/atomvelocities.h" #include "SireMol/molviewproperty.h" +#include "SireMol/atomidxmapping.h" #include "SireVol/space.h" @@ -165,6 +166,11 @@ namespace SireMol bool isCompatibleWith(const MoleculeInfoData &molinfo) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + static Frame join(const QVector &frames, bool use_parallel = true); @@ -367,6 +373,11 @@ namespace SireMol bool isCompatibleWith(const MoleculeInfoData &molinfo) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: int _getIndexForFrame(int &frame) const; diff --git a/corelib/src/libs/SireMove/flexibility.cpp b/corelib/src/libs/SireMove/flexibility.cpp index 24d9c0c14..67a109abe 100644 --- a/corelib/src/libs/SireMove/flexibility.cpp +++ b/corelib/src/libs/SireMove/flexibility.cpp @@ -36,10 +36,13 @@ #include "SireMol/molecule.h" #include "SireMol/mover.hpp" #include "SireMol/partialmolecule.h" +#include "SireMol/atomidxmapping.h" #include "SireUnits/convert.h" #include "SireUnits/units.h" +#include "SireBase/console.h" + #include "SireError/errors.h" #include "SireMol/errors.h" #include "SireMove/errors.h" @@ -49,6 +52,7 @@ using namespace SireMove; using namespace SireMol; +using namespace SireBase; using namespace SireUnits; using namespace SireUnits::Dimension; using namespace SireStream; @@ -586,3 +590,28 @@ const char *Flexibility::typeName() { return QMetaType::typeName(qMetaTypeId()); } + +/** Merge this property with another property */ +PropertyList Flexibility::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} diff --git a/corelib/src/libs/SireMove/flexibility.h b/corelib/src/libs/SireMove/flexibility.h index 9ae1a0289..06f617a01 100644 --- a/corelib/src/libs/SireMove/flexibility.h +++ b/corelib/src/libs/SireMove/flexibility.h @@ -34,6 +34,7 @@ #include "SireMol/atomidx.h" #include "SireMol/molviewproperty.h" #include "SireMol/mover.hpp" +#include "SireMol/atomidxmapping.h" #include "SireUnits/units.h" @@ -195,6 +196,11 @@ namespace SireMove QList flexibleAngles() const; QList flexibleDihedrals() const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: /** The molecule that this flexibility operates on */ SireBase::SharedDataPointer molinfo; diff --git a/corelib/src/libs/SireMove/zmatrix.cpp b/corelib/src/libs/SireMove/zmatrix.cpp index 80dd88901..5792a1e01 100644 --- a/corelib/src/libs/SireMove/zmatrix.cpp +++ b/corelib/src/libs/SireMove/zmatrix.cpp @@ -42,6 +42,8 @@ #include "SireUnits/convert.h" #include "SireUnits/units.h" +#include "SireBase/console.h" + #include "SireError/errors.h" #include "SireMol/errors.h" #include "SireMove/errors.h" @@ -1511,6 +1513,31 @@ const char *ZMatrix::typeName() return QMetaType::typeName(qMetaTypeId()); } +/** Merge this property with another property */ +PropertyList ZMatrix::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} + ////////// ////////// Implementation of ZMatrixCoords ////////// @@ -2856,3 +2883,28 @@ const char *ZMatrixCoords::typeName() { return QMetaType::typeName(qMetaTypeId()); } + +/** Merge this property with another property */ +PropertyList ZMatrixCoords::merge(const MolViewProperty &other, + const AtomIdxMapping &mapping, + const QString &ghost, + const SireBase::PropertyMap &map) const +{ + if (not other.isA()) + { + throw SireError::incompatible_error(QObject::tr("Cannot merge %1 with %2 as they are different types.") + .arg(this->what()) + .arg(other.what()), + CODELOC); + } + + SireBase::Console::warning(QObject::tr("Merging %1 properties is not yet implemented. Returning two copies of the original property.") + .arg(this->what())); + + SireBase::PropertyList ret; + + ret.append(*this); + ret.append(*this); + + return ret; +} diff --git a/corelib/src/libs/SireMove/zmatrix.h b/corelib/src/libs/SireMove/zmatrix.h index 5cee724df..867becacc 100644 --- a/corelib/src/libs/SireMove/zmatrix.h +++ b/corelib/src/libs/SireMove/zmatrix.h @@ -298,6 +298,11 @@ namespace SireMove bool isCompatibleWith(const SireMol::MoleculeInfoData &molinfo) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + protected: SireBase::PropertyPtr _pvt_makeCompatibleWith(const MoleculeInfoData &molinfo, const AtomMatcher &atommatcher) const; @@ -480,6 +485,11 @@ namespace SireMove ZMatrixCoords matchToSelection(const AtomSelection &selection) const; + SireBase::PropertyList merge(const MolViewProperty &other, + const SireMol::AtomIdxMapping &mapping, + const QString &ghost = QString(), + const SireBase::PropertyMap &map = SireBase::PropertyMap()) const; + private: void rebuildInternals(); void rebuildCartesian() const; diff --git a/corelib/src/libs/SireSystem/CMakeLists.txt b/corelib/src/libs/SireSystem/CMakeLists.txt index b490c697c..6bdea44f9 100644 --- a/corelib/src/libs/SireSystem/CMakeLists.txt +++ b/corelib/src/libs/SireSystem/CMakeLists.txt @@ -32,6 +32,7 @@ set ( SIRESYSTEM_HEADERS geometrycomponent.h idassigner.h identityconstraint.h + merge.h moleculeconstraint.h monitorcomponent.h monitorcomponents.h @@ -77,6 +78,7 @@ set ( SIRESYSTEM_SOURCES geometrycomponent.cpp idassigner.cpp identityconstraint.cpp + merge.cpp moleculeconstraint.cpp monitorcomponent.cpp monitorcomponents.cpp diff --git a/corelib/src/libs/SireSystem/merge.cpp b/corelib/src/libs/SireSystem/merge.cpp new file mode 100644 index 000000000..5031f81d8 --- /dev/null +++ b/corelib/src/libs/SireSystem/merge.cpp @@ -0,0 +1,589 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#include "SireSystem/merge.h" + +#include "SireMol/core.h" +#include "SireMol/moleditor.h" +#include "SireMol/atomidxmapping.h" +#include "SireMol/connectivity.h" +#include "SireMol/bondid.h" + +#include "SireMM/mmdetail.h" +#include "SireMM/cljnbpairs.h" + +using namespace SireMol; +using namespace SireBase; + +namespace SireSystem +{ + /** + * @brief Merge function that combines multiple molecules into a single molecule. + * + * @param mols The AtomMapping object that contains the molecules to be merged. + * @param properties The list of properties to be merged. If this is empty then + * a default set of properties will be merged. + * @param as_new_molecule Flag indicating whether the merged molecule should be created as a new molecule. + * @param allow_ring_breaking Whether to allow the opening/closing of rings during a merge. + * @param allow_ring_size_change Whether to allow changes in ring size. + * @param force Whether to try to force the merge, even when the molecular + * connectivity changes not as the result of a ring transformation. + * This will likely lead to an unstable perturbation. This option + * takes precedence over 'allow_ring_breaking' and + * 'allow_ring_size_change'. + * @param map The PropertyMap object that contains additional properties for the merged molecule. + * @return The merged molecule. + */ + Molecule merge(const AtomMapping &mols, + const QStringList &properties, + bool as_new_molecule, + bool allow_ring_breaking, bool allow_ring_size_change, + bool force, const PropertyMap &input_map) + { + // and a handle on the whole reference and perturbed molecule + if (mols.atoms0().isEmpty()) + { + // notiing to map + return Molecule(); + } + else if (mols.atoms1().isEmpty()) + { + // nothing to map to + return mols.atoms0().toSingleMolecule().molecule(); + } + else if (not mols.isSingleMolecule()) + { + throw SireError::incompatible_error(QObject::tr( + "You can only create a merged molecule from a mapping that " + "refers to a single molecule. You cannot use:\n%1") + .arg(mols.toString())); + } + + PropertyMap map = input_map; + + if (map.specified("as_new_molecule")) + { + as_new_molecule = map["as_new_molecule"].value().asABoolean(); + } + + if (map.specified("allow_ring_breaking")) + { + allow_ring_breaking = map["allow_ring_breaking"].value().asABoolean(); + } + + if (map.specified("allow_ring_size_change")) + { + allow_ring_size_change = map["allow_ring_size_change"].value().asABoolean(); + } + + if (map.specified("as_new_molecule")) + { + as_new_molecule = map["as_new_molecule"].value().asABoolean(); + } + + if (map.specified("force")) + { + force = map["force"].value().asABoolean(); + } + + if (force) + { + allow_ring_breaking = true; + allow_ring_size_change = true; + } + + map.set("as_new_molecule", BooleanProperty(as_new_molecule)); + map.set("allow_ring_breaking", BooleanProperty(allow_ring_breaking)); + + // see which properties to merge + QStringList props = properties; + + if (props.isEmpty()) + { + props = QStringList({ + "angle", + "ambertype", + "atomtype", + "bond", + "charge", + "connectivity", + "coordinates", + "dihedral", + "element", + "improper", + "intrascale", + "LJ", + "mass", + }); + } + + // get the forwards and backwards map + auto forwards_map = mols; + auto backwards_map = mols.swap(); + + // get the merged maps for the reference and perturbed states + auto map0 = map.merge(mols.propertyMap0()); + auto map1 = map.merge(mols.propertyMap1()); + + const auto mol0 = mols.atoms0().toSingleMolecule().molecule(); + const auto mol1 = mols.atoms1().toSingleMolecule().molecule(); + + // get the MolEditor that can be used to set properties + MolEditor editmol = mol0.edit(); + + // check and set the forcefields + SireMM::MMDetail ffield0; + SireMM::MMDetail ffield1; + + bool have_ffield0 = false; + bool have_ffield1 = false; + + try + { + ffield0 = mol0.data().property(map0["forcefield"]).asA(); + have_ffield0 = true; + } + catch (...) + { + } + + try + { + ffield1 = mol1.data().property(map1["forcefield"]).asA(); + have_ffield1 = true; + } + catch (...) + { + } + + if (not(have_ffield0 and have_ffield1)) + { + throw SireError::incompatible_error(QObject::tr( + "You must specify a forcefield for both the reference and " + "perturbed states in order to merge the molecules."), + CODELOC); + } + else if (not have_ffield1) + { + ffield1 = ffield0; + } + else + { + ffield0 = ffield1; + } + + if (not ffield0.isCompatibleWith(ffield1)) + { + throw SireError::incompatible_error(QObject::tr( + "The forcefields for the reference and perturbed states are " + "incompatible. You cannot merge the molecules. The forcefields " + "are %1 and %2") + .arg(ffield0.toString()) + .arg(ffield1.toString()), + CODELOC); + } + + // remove the parameters properties + if (editmol.hasProperty(map["parameters"])) + { + editmol.removeProperty(map["parameters"]); + } + + if (editmol.hasProperty(map0["parameters"])) + { + editmol.removeProperty(map0["parameters"]); + } + + if (editmol.hasProperty(map["amberparams"])) + { + editmol.removeProperty(map["amberparams"]); + } + + if (editmol.hasProperty(map0["amberparams"])) + { + editmol.removeProperty(map0["amberparams"]); + } + + // find the largest AtomNum in mol0 + AtomNum largest_atomnum; + + const auto &molinfo = mol0.info(); + + for (int i = 0; i < molinfo.nAtoms(); ++i) + { + const auto num = molinfo.number(AtomIdx(i)); + + if (largest_atomnum.isNull()) + { + largest_atomnum = num; + } + else if (not num.isNull()) + { + if (num.value() > largest_atomnum.value()) + largest_atomnum = num; + } + } + + // use a property to track which atoms have been mapped - + // a value of -1 means that this atom is not mapped + editmol.setProperty("_mol0_index", AtomIntProperty(mol0.info(), -1)); + editmol.setProperty("_mol1_index", AtomIntProperty(mol0.info(), -1)); + + // get an editable copy of the molecule to be changed + MolStructureEditor mol(editmol); + + // a map from the residue index in the mapped state back to the + // residue index in the merged molecule + QHash pert_to_merge_residx; + + // all of the residue indicies that we have seen + QHash residx_to_cgidx; + + if (not mols.mappedAtoms0().isEmpty()) + { + // the list of mapped atoms + const auto mapped_atoms0 = mols.mappedAtoms0().toSingleMolecule(); + const auto mapped_atoms1 = mols.mappedAtoms1().toSingleMolecule(); + + if (mapped_atoms0.count() != mapped_atoms1.count()) + { + throw SireError::program_bug(QObject::tr( + "The number of atoms in the forward and backward mappings " + "are not the same. This is a bug!."), + CODELOC); + } + + // go through all of the common atoms and save their indicies + // and set the atom and residue names + for (int i = 0; i < mapped_atoms0.count(); ++i) + { + const auto atom0 = mapped_atoms0(i); + const auto atom1 = mapped_atoms1(i); + + auto atom = mol.atom(atom0.index()); + + // save the index of this atom in both mol0 and mol1 + atom.setProperty("_mol0_index", atom0.index().value()); + atom.setProperty("_mol1_index", atom1.index().value()); + + // save the perturbed state atom and residue names into new properties, so + // that we can use these when extracting the end states + atom.setAlternateName(atom1.name()); + + ResIdx residx; + + try + { + residx = atom0.residue().index(); + } + catch (...) + { + } + + if (not(residx.isNull() or residx_to_cgidx.contains(residx))) + { + // we haven't seen this residue before - assume that + // all residues that are mapped from this residue + // exist in the same equivalent residue in the + // perturbed molecule (using the cutgroup of the + // first atom in this residue) + residx_to_cgidx.insert(residx, atom0.cutGroup().index()); + + // first, get an editor for this residue + // and save the alternate residue name for the mapped state + auto res = mol.residue(residx); + res.setAlternateName(atom1.residue().name()); + + // now save the mapping from perturbed residue index + // to merged residue index + pert_to_merge_residx[atom1.residue().index()] = residx; + } + } + } + + // now go through the unmapped atoms of the reference molecule and + // save their indicies + if (not mols.unmappedAtoms0().isEmpty()) + { + const auto unmapped_atoms0 = mols.unmappedAtoms0().toSingleMolecule(); + + for (int i = 0; i < unmapped_atoms0.count(); ++i) + { + const auto atom0 = unmapped_atoms0(i); + + auto atom = mol.atom(atom0.index()); + + // unmapped atoms are called "Xxx" + atom.setAlternateName("Xxx"); + atom.setProperty("_mol0_index", atom0.index().value()); + atom.setProperty("_mol1_index", -1); + } + } + + // now go through the unmapped atoms of the perturbed molecule and + // add them to the merged molecule, saving their indicies + if (not mols.unmappedAtoms1().isEmpty()) + { + const auto unmapped_atoms1 = mols.unmappedAtoms1().toSingleMolecule(); + + for (int i = 0; i < unmapped_atoms1.count(); ++i) + { + const auto atom1 = unmapped_atoms1(i); + + // we should have seen this residue before... + auto residx = pert_to_merge_residx.value(atom1.residue().index()); + + if (residx.isNull()) + { + // we haven't seen this residue before, so we don't know + // really where to add the atoms. The best thing to do + // is add this to the last residue that we saw in the + // molecule (the one with the highest index) + if (residx_to_cgidx.isEmpty()) + { + throw SireError::program_bug(QObject::tr( + "We have not seen any residues before, so we don't know " + "where to add the atoms. This is a bug!"), + CODELOC); + } + + auto residxs = residx_to_cgidx.keys(); + std::sort(residxs.begin(), residxs.end()); + + residx = residxs.last(); + } + + auto cgidx = residx_to_cgidx.value(residx); + + if (cgidx.isNull()) + { + throw SireError::program_bug(QObject::tr( + "We don't know the CutGroup for the residue, so we don't know " + "where to add the atoms. This is a bug!"), + CODELOC); + } + + auto res = mol.residue(residx); + + // add the atom - it has the name "Xxx" as it doesn't exist + // in the reference state + auto atom = res.add(AtomName("Xxx")); + largest_atomnum = AtomNum(largest_atomnum.value() + 1); + atom.renumber(largest_atomnum); + + // reparent this atom to the CutGroup for this residue + atom.reparent(cgidx); + + // save the name in the perturbed state + atom.setAlternateName(atom1.name()); + atom.setProperty("_mol0_index", -1); + atom.setProperty("_mol1_index", atom1.index().value()); + } + } + + if (as_new_molecule) + { + mol.renumber(); + } + + editmol = mol.commit().edit(); + + // now we have the merged molecule, we need to work out the mapping + // of atoms from the reference to the perturbed state in this + // merged molecule + QList idx_entries; + + const auto &molinfo0 = editmol.info(); + const auto &molinfo1 = mol1.info(); + + for (int i = 0; i < molinfo0.nAtoms(); ++i) + { + const auto atom = editmol.atom(AtomIdx(i)); + + const auto index0 = atom.property("_mol0_index"); + const auto index1 = atom.property("_mol1_index"); + + if (index0 == -1 and index1 == -1) + { + // this atom is not involved in the mapping + continue; + } + + const bool is_unmapped_in_reference = (index0 == -1); + + AtomIdx atomidx1(index1); + + if (index1 == -1) + { + // this atom is not in the perturbed state, so this + // index should be set to null + atomidx1 = AtomIdx(); + } + + idx_entries.append(AtomIdxMappingEntry(AtomIdx(i), atomidx1, + molinfo0, molinfo1, + is_unmapped_in_reference)); + } + + AtomIdxMapping entries(idx_entries); + idx_entries.clear(); + + // now go through all of the properties that we want to merge + // and merge them using the AtomIdxMapping object - remove + // the common property of these + for (const auto &prop : props) + { + if (editmol.hasProperty(map0[prop]) and mol1.hasProperty(map1[prop])) + { + // we both have the property, so it should be mergeable + const auto &prop0 = editmol.property(map0[prop]); + const auto &prop1 = mol1.property(map1[prop]); + + if (prop0.what() != prop1.what()) + { + // the properties are not the same type + throw SireError::incompatible_error(QObject::tr( + "Cannot merge the molecule because the property %1 is not the " + "same type in both molecules. It is %2=%3 in the reference " + "and %4=%5 in the perturbed molecule.") + .arg(prop) + .arg(map0[prop].source()) + .arg(prop0.what()) + .arg(map1[prop].source()) + .arg(prop1.what()), + CODELOC); + } + + if (prop0.isA()) + { + // they can be properly merged - get the value of the ghost parameter for this property + QString ghost_param; + + if (map.specified("ghost_" + prop)) + { + ghost_param = map["ghost_" + prop].source(); + } + else if (prop == "atomtype" or prop == "ambertype") + { + ghost_param = "Xx"; + } + + auto merged = prop0.asA().merge(prop1.asA(), + entries, ghost_param, map); + + if (merged.count() != 2) + throw SireError::program_bug(QObject::tr( + "The merge of the property %1 did not return two properties. " + "This is a bug!") + .arg(prop), + CODELOC); + + editmol.removeProperty(map0[prop]); + + if (prop == "connectivity") + { + // we need to set the connectivity of the merged molecule + auto merged_connectivity = merged[0].asA().edit(); + + // the merged connectivity has the connections of both the + // reference and perturbed states + merged_connectivity.connect(merged[1].asA().getBonds()); + + editmol.setProperty(map["connectivity"].source(), merged_connectivity.commit()); + } + else if (prop == "intrascale") + { + // we need to copy the intrascale parameters involving ghost atoms + // from the state where they are not ghosts + const auto unmapped_in0 = entries.unmappedCGAtomIdxIn0(); + const auto unmapped_in1 = entries.unmappedCGAtomIdxIn1(); + + if (not(unmapped_in0.isEmpty() and unmapped_in1.isEmpty())) + { + auto scl0 = merged[0].asA(); + auto scl1 = merged[1].asA(); + + merged.clear(); + + const int nats = editmol.nAtoms(); + + for (AtomIdx idx(0); idx < nats; ++idx) + { + const auto i = editmol.info().cgAtomIdx(idx); + + // set all of the CLJ scale factors for atoms unmapped + // in the reference state to equal the scale factor + // for this pair in the perturbed state + for (const auto &j : unmapped_in0) + { + scl0.set(i, j, scl1.get(i, j)); + } + + // set all of the CLJ scale factors for atoms unmapped + // in the perturbed state to equal the scale factor + // for this pair in the reference state + for (const auto &j : unmapped_in1) + { + scl0.set(j, i, scl1.get(j, i)); + } + } + + merged.append(scl0); + merged.append(scl1); + } + } + + editmol.setProperty(map[prop + "0"].source(), merged[0]); + editmol.setProperty(map[prop + "1"].source(), merged[1]); + } + else + { + // they are normal properties - they cannot be merged + // so just add them as the two end states + editmol.removeProperty(map0[prop]); + editmol.setProperty(map[prop + "0"].source(), prop0); + editmol.setProperty(map[prop + "1"].source(), prop1); + } + } + } + + // add the reference and perturbed molecules as 'molecule0' and 'molecule1' + editmol.setProperty(map["molecule0"].source(), mol0); + editmol.setProperty(map["molecule1"].source(), mol1); + + // add the forcefields for the two molecules - need the same, + // so choosing ffield0 + editmol.setProperty(map["forcefield0"].source(), ffield0); + editmol.setProperty(map["forcefield1"].source(), ffield0); + + // set the flag that this is a perturbable molecule + editmol.setProperty(map["is_perturbable"].source(), BooleanProperty(true)); + + return editmol.commit(); + } +} diff --git a/corelib/src/libs/SireSystem/merge.h b/corelib/src/libs/SireSystem/merge.h new file mode 100644 index 000000000..e6f925b9f --- /dev/null +++ b/corelib/src/libs/SireSystem/merge.h @@ -0,0 +1,54 @@ +/********************************************\ + * + * Sire - Molecular Simulation Framework + * + * Copyright (C) 2024 Christopher Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For full details of the license please see the COPYING file + * that should have come with this distribution. + * + * You can contact the authors via the website + * at https://sire.openbiosim.org + * +\*********************************************/ + +#ifndef SIRESYSTEM_MERGE_H +#define SIRESYSTEM_MERGE_H + +#include "SireMol/atommapping.h" +#include "SireMol/molecule.h" + +#include "SireBase/propertymap.h" + +SIRE_BEGIN_HEADER + +namespace SireSystem +{ + SIRESYSTEM_EXPORT SireMol::Molecule merge(const SireMol::AtomMapping &mols, + const QStringList &properties = QStringList(), + bool as_new_molecule = true, + bool allow_ring_breaking = false, + bool allow_ring_size_change = false, + bool force = false, + const SireBase::PropertyMap &map = SireBase::PropertyMap()); +} + +SIRE_EXPOSE_FUNCTION(SireSystem::merge); + +SIRE_END_HEADER; + +#endif diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst index e0c665db9..92e3f27f7 100644 --- a/doc/source/changelog.rst +++ b/doc/source/changelog.rst @@ -12,9 +12,14 @@ Development was migrated into the `OpenBioSim `__ organisation on `GitHub `__. -`2024.1.0 `__ - March 2024 +`2024.1.0 `__ - April 2024 ------------------------------------------------------------------------------------------ +* Dropped official builds and support for Python 3.9, and added official + builds and support for Python 3.12. Note that MacOS builds are currently + 3.10 and 3.11 only, due to missing dependencies. This will be fixed + in upcoming point releases. + * BREAKING CHANGE: Updated the API of :class:`sire.cas.LambdaSchedule` so that you have to use named arguments for many of the functions (e.g. :meth:`~sire.cas.LambdaSchedule.set_equation`). This is because the addition @@ -28,6 +33,21 @@ organisation on `GitHub `__. to add support for calculating absolute binding free energies. This is described in the new :doc:`tutorial chapter `. +* Exposed the underlying :class:`~sire.legacy.Convert.PerturbableOpenMMMolecule` + class, which can be created from a merged molecule via + ``mol.perturbation().to_openmm()``. This lets you easily see which parameters + are changing between the reference and perturbed states. This is described + in the :doc:`tutorial `. + +* Added the ability for the lambda schedule to show how it will actually + act to perturb the parameters of the + :class:`~sire.legacy.Convert.PerturbableOpenMMMolecule` molecule. + This is described in the :doc:`tutorial `. + +* Added support for reading older somd-style pertfiles, and creating + merged molecules from these. This is described in + the :doc:`tutorial `. + * Added "not-perturbable" constraints so that bonds and angles that change with lambda are not perturbed. As part of this, have also added a ``dynamic_constraints`` option that lets constrained bonds update with @@ -90,6 +110,19 @@ organisation on `GitHub `__. It was a little-used part of the code, with the main use case being the replacement with the easier ``sire.morph.link_to_XXX`` functions. +* Added ability to create merge molecules for relative free energy calculations + via :func:`sire.morph.merge` and :func:`sire.morph.match`. This is + described in the :doc:`tutorial `. + +* Added ability to create merge molecules for absolute free energy + calculations via :func:`sire.morph.decouple` and + :func:`sire.morph.annihilate`. This is described in the + :doc:`tutorial `. + +* Added support for residue perturbations and also for mutating residues + and parts of molecules using a new "copy and paste" algorithm. This is + described in the :doc:`tutorial `. + * Exposed the ``SOMMContext``, ``PerturbableOpenMMMolecule``, ``OpenMMMetaData`` and ``LambdaLever`` classes to Python, as part of the new ``sire.convert.openmm`` module. These are useful if you want more @@ -99,13 +132,6 @@ organisation on `GitHub `__. be used to get changing parameters as dataframes, which is really useful for debugging. These are described in the :doc:`new tutorial `. -* Added an ``AtomCoordMatcher`` to match atoms by coordinates in two selections. - -* Fix bug that disabled the ``DEBUG`` log level from the global logger. - -* Fixed bug in :class`sire.legacy.Mol.ResIdxAtomCoordMatcher` by ensuring - that we only compare residues with the same number of atoms. - * Preserve user atom names when writing to PDB format. * Updated the :class:`~sire.mol.Cursor` so that it is easier to get and @@ -128,17 +154,6 @@ organisation on `GitHub `__. iterations reset. If it fails again, then this structure, with constraints re-applied, is returned. -* Code can now detect when an Amber PRMTOP file has discontiguous molecules, - and thus when atoms are reordered after load. This information is passed - to subsequent frame file parsers that are loaded at the same time, so - that they are able to reorder the frames before being added to the atoms. - This happens transparently, so that the user doesn't have to worry about - the reordering. This fixes issue #164. - -* Added ``map`` support to writing perturbable Gromacs topology files. This - enables the user to specify which perturbable properties to use, - e.g. ``map={"dihedral0": "dihedral_a", "dihedral1": "dihedral_b"}``. - * Added more support for Boresch restraints. Specifically, :func:`sire.restraints.boresch` now supports the specification of equilibrium values, uses different default force constants, and warns the user if the restraints are likely to be unstable. @@ -146,6 +161,58 @@ organisation on `GitHub `__. restraints. Tests were added for restraint creation and for the standard state correction. Boresch restraints were added to :doc:`tutorial `. +* Added power support to GeneralUnit in python. You can now raise a unit value + to a valid power, e.g. ``sr.u("5A")**2``. You can also square root via a new + ``.sqrt()`` function on the unit. There is also a new ``sire.sqrt`` function + that will automatically called ``obj.sqrt()`` if that exists, or will fall + back to ``math.sqrt`` if not. This implements wishlist item #176. + +* Conversion to and from RDKit now preserves atoms and residue names and + numbers. This makes used of AtomPDBResidueInfo in RDKit to populate metadata + when the RDKit molecule is created. On conversion to sire, the atom monomer + info will be checked. If it is simple, then only the atom name will be + obtained. If it is a AtomPDBResidueInfo, then the atom name and number, + and residue name and number (plus any chain information) will be extracted. + If no atom name is set, then the value of the property + "molFileAlias" will be checked. This implements wishlist item #168. + +* Implemented the ``auto-bonds`` constraint, which automatically chooses + bonds to constrain by comparing the estimated vibrational frequency + against the simulation timestep multiplied by the factor + ``auto_bonds_factor`` (defaults to 10). + This is described in the :doc:`OpenMM detailed guide `. + This implements wishlist item #185. + +* Fixed a bug in the algorithm used to infer bond order when converting to + RDKit format. This fixes issue #177. + +* Fixed a bug in the :class:`~sire.legacy.Convert.LambdaLever` class where + it was not using the stage-specific value of lambda when using multiple + stages where one or more stages contained a standard morph equation. + +* Please add an item to this changelog when you create your PR + +`2023.5.2 `__ - March 2024 +------------------------------------------------------------------------------------------ + +* Fix bug that disabled the ``DEBUG`` log level from the global logger. + +* Fixed bug in :class`sire.legacy.Mol.ResIdxAtomCoordMatcher` by ensuring + that we only compare residues with the same number of atoms. + +* Added an ``AtomCoordMatcher`` to match atoms by coordinates in two selections. + +* Added ``map`` support to writing perturbable Gromacs topology files. This + enables the user to specify which perturbable properties to use, + e.g. ``map={"dihedral0": "dihedral_a", "dihedral1": "dihedral_b"}``. + +* Code can now detect when an Amber PRMTOP file has discontiguous molecules, + and thus when atoms are reordered after load. This information is passed + to subsequent frame file parsers that are loaded at the same time, so + that they are able to reorder the frames before being added to the atoms. + This happens transparently, so that the user doesn't have to worry about + the reordering. This fixes issue #164. + * Fixed a bug where the SDF parser would wrongly try to parse Amber RST7 files that weren't immediately recognised as such. The fix adds ``.inpcrd`` as a recognised extension for Amber RST7 files, and changes the scoring logic of the SDF parser @@ -155,15 +222,10 @@ organisation on `GitHub `__. when reading Mol2 files. This is more robust than using the atom name. Fixes issue #166. -* Made it easier to convert from strings to elements. Added the ability to +* Made it easier to convert from strings to elements. Added the ability to customise the list of elements that are considered biological. This fixes issue #170. -* Fixed a bug in the algorithm used to infer bond order when converting to - RDKit format. This fixes issue #177. - -* Please add an item to this changelog when you create your PR - `2023.5.1 `__ - January 2024 -------------------------------------------------------------------------------------------- diff --git a/doc/source/cheatsheet/openmm.rst b/doc/source/cheatsheet/openmm.rst index 72e14b64e..d53daa436 100644 --- a/doc/source/cheatsheet/openmm.rst +++ b/doc/source/cheatsheet/openmm.rst @@ -76,6 +76,13 @@ Available keys and allowable values are listed below. +------------------------------+----------------------------------------------------------+ | Key | Valid values | +==============================+==========================================================+ +| auto_constraints_factor | The factor by which to multiply the timestep when | +| | deciding whether or not an auto-constrained bond should | +| | be constrained. The calculated period of a bond | +| | vibration is compared to the simulation timestep | +| | multiplied by this factor. If the period is less than | +| | this, the bond is constrained. This defaults to 10. | ++------------------------------+----------------------------------------------------------+ | barostat_frequency | The frequency at which the barostat acts to perform | | | the MC moves to change the box volume when performing | | | constant pressure simulations (default 25). | @@ -102,7 +109,8 @@ Available keys and allowable values are listed below. | | removed. | +------------------------------+----------------------------------------------------------+ | constraint | Type of constraint to use for bonds and/or angles. | -| | Valid strings are ``none``, ``h-bonds``, | +| | Valid strings are ``none``, | +| | ``auto-bonds``, ``h-bonds``, | | | ``h-bonds-not-perturbed``, | | | ``h-bonds-not-heavy-perturbed``, | | | ``bonds``, ``bonds-not-perturbed``, | diff --git a/doc/source/features.rst b/doc/source/features.rst index 5fa08b231..b08bc9f12 100644 --- a/doc/source/features.rst +++ b/doc/source/features.rst @@ -44,6 +44,13 @@ molecular (predominantly biomolecular) systems. including across :doc:`frames of trajectories ` (or subsets of trajectories). +* Create merged molecules that represent perturbations for + :doc:`relative ` and + :doc:`absolute ` free energy calculations. +* Create merged molecules that represnet perturbations of + :doc:`residues in proteins `. +* Mutate residues or parts of molecules via + :doc:`copy-and-pasting ` bits of molecules. * A powerful :doc:`property system ` that lets you associate nearly any data with nearly any molecular view or sub-view. For example, you can assign multiple different coordinate properties diff --git a/doc/source/install.rst b/doc/source/install.rst index 97db15d3f..72e745f9b 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -92,16 +92,16 @@ And then... Install sire into a new environment We recommend that :mod:`sire` is installed into a new (clean) environment. This minimises the risk of failures caused by incompatible dependencies. -Sire is currently packaged for Python 3.9, 3.10 and Python 3.11. We will start -by creating a Python 3.11 environment that we will call ``openbiosim``. +Sire is currently packaged for Python 3.10, 3.11 and Python 3.12. We will start +by creating a Python 3.12 environment that we will call ``openbiosim``. .. code-block:: bash - $ conda create -n openbiosim "python<3.12" + $ conda create -n openbiosim "python<3.13" .. note:: - We use ``python<3.12`` as this will install the most recent 3.11 + We use ``python<3.13`` as this will install the most recent 3.12 release of python. We can now install :mod:`sire` into that environment by typing @@ -125,6 +125,35 @@ If you want the latest development release, then install by typing $ conda install -n openbiosim -c conda-forge -c "openbiosim/label/dev" sire +You can install a specific version of sire by specifying the version number +in the conda install command, e.g. + +.. code-block:: bash + + conda install -n openbiosim -c conda-forge -c openbiosim sire==2024.1.0 + +Note that limited space means that we can only keep a small number of +versions of sire on the official openbiosim conda channel. Generally +these are all point releases of the latest major version, plus the latest +point release of the last major version. + +We do provide an +`archive channel `__ +of all previous releases. You can search this archive channel for the +release you are interested in using the following command: + +.. code-block:: bash + + conda search -c https://openbiosim.blob.core.windows.net/archive sire + +This will return a list of all versions of sire available in the archive. + +You can install a specific version from the archive using a command like: + +.. code-block:: bash + + conda install -n openbiosim -c https://openbiosim.blob.core.windows.net/archive sire==2023.2.3 + You may (optionally) want to install additional tools such as ``ipython`` and ``jupyterlab``. To do this, type diff --git a/doc/source/tutorial/index_part05.rst b/doc/source/tutorial/index_part05.rst index 412f984a1..30aeb051f 100644 --- a/doc/source/tutorial/index_part05.rst +++ b/doc/source/tutorial/index_part05.rst @@ -7,7 +7,8 @@ and work with other molecular modelling python packages. You can also convert molecules between the :mod:`sire` format and the format of other popular molecular packages, e.g. -`rdkit `__, `openmm `_ and +`rdkit `__, `openmm `_, +`Gemmi `__ and `BioSimSpace `__. This chapter will teach you how to do the conversion, and also how diff --git a/doc/source/tutorial/index_part07.rst b/doc/source/tutorial/index_part07.rst index 35766ff77..174ff8e6b 100644 --- a/doc/source/tutorial/index_part07.rst +++ b/doc/source/tutorial/index_part07.rst @@ -22,3 +22,8 @@ calculating free energies that involve breaking rings in ligands. part07/01_perturbation part07/02_levers + part07/03_ghosts + part07/04_merge + part07/05_pertfile + part07/06_decouple + part07/07_residue diff --git a/doc/source/tutorial/part05/05_dynamics.rst b/doc/source/tutorial/part05/05_dynamics.rst index 02600b635..f1f064939 100644 --- a/doc/source/tutorial/part05/05_dynamics.rst +++ b/doc/source/tutorial/part05/05_dynamics.rst @@ -72,7 +72,7 @@ the amount of time between saved coordinate/velocity snapshots. For example, here we will run 10 picoseconds of dynamics, saving a frame every 0.5 picoseconds ->>> d.run(10*sr.units.picosecond, 0.5*sr.units.picosecond) +>>> d.run("10ps", "0.5ps") Dynamics(completed=10 ps, energy=-8.82722 kcal mol-1, speed=119.2 ns day-1) .. note:: @@ -95,7 +95,7 @@ of the loaded system. We can perform dynamics on all the molecules by calling :func:`~sire.mol.SelectorMol.dynamics` on the complete collection. >>> d = mols.dynamics() ->>> d.run(10*sr.units.picosecond, 0.5*sr.units.picosecond) +>>> d.run("10ps", "0.5ps") Dynamics(completed=6010 ps, energy=-5974.09 kcal mol-1, speed=80.5 ns day-1) >>> mols = d.commit() >>> mols.trajectory().energy().pretty_plot() @@ -121,14 +121,14 @@ intervals to save frames for each run. For example, you could have a long "equilibration" run that doesn't save frames at all by setting ``save_frequency`` to ``0``. ->>> d.run(10*sr.units.picosecond, save_frequency=0) +>>> d.run("10ps", save_frequency=0) Dynamics(completed=6020 ps, energy=-5974.9 kcal mol-1, speed=89.2 ns day-1) You can run as many blocks as you like, e.g. ->>> d.run(1*sr.units.picosecond, save_frequency=0.01*sr.units.picosecond) +>>> d.run("1ps", save_frequency="0.01ps") Dynamics(completed=6021 ps, energy=-5974.61 kcal mol-1, speed=84.4 ns day-1) ->>> d.run(50*sr.units.picosecond, save_frequency=1*sr.units.picosecond) +>>> d.run("50ps", save_frequency="1ps") Dynamics(completed=6071 ps, energy=-5976.05 kcal mol-1, speed=58.3 ns day-1) >>> mols = d.commit() >>> mols.view() @@ -164,17 +164,17 @@ the :class:`~sire.mol.Dynamics` object. Available options are; 25 picoseconds (ps). * ``constraint`` - the level of constraints to apply to the molecules, e.g. constraining bonds, angles etc. By default this is inferred from - the value of ``timestep``. It defaults to no constraints. But timesteps - greater than 1 femtoseconds will constrain all bonds involving hydrogen - and all angles involving hydrogen. Timesteps greater than 2 femtoseconds will - constrain all bonds, and all angles involving hydrogen. + the value of ``timestep``. It defaults to no constraints. A good choice + for this parameter is ``auto-bonds``, which will automatically constrain + bonds based on a comparison between the bonds vibrational frequency + and the simulation timestep. For example >>> d = mols.dynamics(cutoff_type="reaction_field", -... timestep=4*sr.units.femtosecond, -... save_frequency=1*sr.units.picosecond) ->>> d.run(10*sr.units.picosecond) +... timestep="4fs", +... save_frequency="1ps") +>>> d.run("10ps") Dynamics(completed=6081 ps, energy=-6601.59 kcal mol-1, speed=432.2 ns day-1) will perform 10 picoseconds of dynamics saving a frame every 1 picosecond. @@ -196,10 +196,10 @@ that can be re-used between multiple dynamics runs. ... "timestep": 4*sr.units.femtosecond, ... "save_frequency": 1*sr.units.picosecond} >>> d = mols.dynamics(map=m) ->>> d.run(10*sr.units.picosecond) +>>> d.run("10ps") Dynamics(completed=6081 ps, energy=-6601.01 kcal mol-1, speed=439.8 ns day-1) >>> d2 = mols.dynamics(map=m) ->>> d2.run(10*sr.units.picosecond) +>>> d2.run("10ps") Dynamics(completed=6081 ps, energy=-6601.01 kcal mol-1, speed=440.6 ns day-1) The parameter map approach can be used to set other properties of the diff --git a/doc/source/tutorial/part07/02_levers.rst b/doc/source/tutorial/part07/02_levers.rst index 24d3ac3e2..5d240fe34 100644 --- a/doc/source/tutorial/part07/02_levers.rst +++ b/doc/source/tutorial/part07/02_levers.rst @@ -28,7 +28,7 @@ system will be morphed in a single stage (called "morph"), using a linear interpolation between the initial and final values of the parameters. As we saw in the :doc:`last section <01_perturbation>`, we can find the exact -values of all of the perturbable parameters of a perturbable molecle via +values of all of the perturbable parameters of a perturbable molecule via the perturbation object. >>> p = mols[0].perturbation() @@ -51,6 +51,11 @@ and the above schedule will morph the bond length from 0.15375 nm to 0.10969 nm, and the force constant from 251793.12 kJ mol-1 nm-2 to 276646.08 kJ mol-1 nm-2, linearly with respect to λ. +.. note:: + + The parameters are directly as would be used in an OpenMM force, + i.e. in OpenMM default units of nanometers and kilojoules per mole. + Controlling individual levers ----------------------------- @@ -96,6 +101,16 @@ interpolated from the initial to final value by λ^2, rather than λ. All of the other levers continue to use the default equation for this stage, which is the linear interpolation between the initial and final values. +You can change the default equation used for a stage using the +:meth:`~sire.cas.LambdaSchedule.set_default_equation` function, e.g. + +>>> s.set_default_equation(stage="morph", equation=(1-l)*init + l*fin) +>>> print(s) +LambdaSchedule( + morph: initial * (-λ + 1) + final * λ + bond_length: initial * (-λ^2 + 1) + final * λ^2 +) + Controlling individual levers in individual forces -------------------------------------------------- @@ -229,3 +244,54 @@ LambdaSchedule( ghost/ghost::alpha: 0.5 * (initial * (-λ + 1) + final * λ) ) ) + +Viewing the effect of levers on a merged molecule +------------------------------------------------- + +You can view the effect of the :class:`~sire.cas.LambdaSchedule` on a +the :class:`~sire.legacy.Convert.PerturbableOpenMMMolecule` using +the :meth:`~sire.legacy.Convert.PerturbableOpenMMMolecule.get_lever_values` +function. + +>>> df = p_omm.get_lever_values(schedule=orig_s) +>>> print(df) + clj-charge-1 clj-charge-2 clj-charge-4 ... bond-bond_length-3 angle-angle_k-19 angle-angle_size-19 +λ ... +0.00 -0.085335 -0.060235 -0.085335 ... 0.10969 387.438400 1.916372 +0.01 -0.084482 -0.059362 -0.085566 ... 0.10969 386.861008 1.915985 +0.02 -0.083629 -0.058489 -0.085797 ... 0.10969 386.283616 1.915597 +0.03 -0.082775 -0.057615 -0.086027 ... 0.10969 385.706224 1.915210 +0.04 -0.081922 -0.056742 -0.086258 ... 0.10969 385.128832 1.914822 +... ... ... ... ... ... ... ... +0.96 -0.003413 0.023607 -0.107477 ... 0.10969 332.008768 1.879176 +0.97 -0.002560 0.024480 -0.107708 ... 0.10969 331.431376 1.878788 +0.98 -0.001707 0.025353 -0.107939 ... 0.10969 330.853984 1.878401 +0.99 -0.000853 0.026227 -0.108169 ... 0.10969 330.276592 1.878013 +1.00 0.000000 0.027100 -0.108400 ... 0.10969 329.699200 1.877626 +[101 rows x 19 columns] + +It can be useful to plot these, to check that the morphing is as expected. + +>>> ax = df.plot() +>>> ax.legend(bbox_to_anchor=(1.0, 1.0)) + +.. image:: images/07_02_01.jpg + :alt: Graph of the effect of all levers on the perturbable molecule. + +.. note:: + + The line ``ax.legend(bbox_to_anchor=(1.0, 1.0))`` is used to move the + legend outside of the plot area, so that it doesn't obscure the data. + +Unfortunately, the large values of the bond force constant make it very +difficult to see the effect of the :class:`~sire.cas.LambdaSchedule` on the +other parameters. To fix this, lets filter out any columns that contain +values that have an absolute value greater than 5. + +>>> skip_columns = df.abs().gt(5).apply(lambda x: x.index[x].tolist(), axis=1)[0] +>>> ax = df.loc[:, ~df.columns.isin(skip_columns)].plot() +>>> ax.legend(bbox_to_anchor=(1.0, 1.0)) + +.. image:: images/07_02_02.jpg + :alt: Graph of the effect of all levers on the perturbable molecule for + levers with parameters with values less than 5. diff --git a/doc/source/tutorial/part07/03_ghosts.rst b/doc/source/tutorial/part07/03_ghosts.rst new file mode 100644 index 000000000..c044b1057 --- /dev/null +++ b/doc/source/tutorial/part07/03_ghosts.rst @@ -0,0 +1,218 @@ +==================================== +Ghost Atoms and Softening Potentials +==================================== + +Ghost atoms are used by the sire/OpenMM interface +to represent atoms that either appear or disappear during a +perturbation. They are used as part of the implementation of a +soft-core potential in OpenMM, to avoid singularities / crashes +when atoms are annihilated or created. + +A ghost atom is one which has zero charge **and** zero LJ parameters in +either the reference or perturbed end states. + +.. note:: + + In this case, "zero LJ parameters" means either the sigma or epsilon + parameter is zero (or both). + + +Only atoms that have a zero charge **and** zero LJ parameters at either +end state are ghost atoms. These atoms are treated differently to the +rest of the atoms in the system. + +All normal atoms (called "non-ghost atoms") are treated as standard atoms +in the sire to OpenMM conversion, and added to standard OpenMM Force objects +(e.g. NonBondedForce, HarmonicBondForce, etc). + +Ghost atoms are treated differently. They are added to the OpenMM Force objects +as other atoms, but with the following key difference: + +* Ghost atoms are added to the NonBondedForce with their standard charge, + but with zero LJ parameters. This means that only the electrostatic + energy and force from ghost atoms is evaluated here. + +Ghost atoms are then added to three custom OpenMM Forces: + +1. A CustomNonbondedForce called the "ghost/ghost" force. This uses a + custom energy function to calculate the soft-core electrostatic and + LJ interactions between all ghost atoms. It also calculates the + "hard" electrostatic interaction and subtracts this from the + total (to remove the real-space contribution that was calculated + in the standard OpenMM NonBondedForce). + +2. A CustomNonbondedForce called the "ghost/non-ghost" force. This uses a + custom energy function to calculate the soft-core electrostatic and + LJ interactions between all ghost atoms and all non-ghost atoms. + It also calculates the "hard" electrostatic interaction and subtracts + this from the total (to remove the real-space contribution that was + calculated in the standard OpenMM NonBondedForce). + +3. A CustomBondForce called the "ghost-14" force. This uses a custom + energy function to calculate the soft-core electrostatic and LJ + interactions between all 1-4 non-bonded interactions involving + ghost atoms. It also calculates the "hard" electrostatic + interaction and subtracts this from the total (to remove the real-space + contribution that was calculated in the standard OpenMM NonBondedForce). + +There are two different soft-core potentials available. The default is +the Zacharias potential, while the second is the Taylor potential. + +Zacharias softening +------------------- + +This is the default soft-core potential. You can also use it by +setting the map option ``use_zacharias_softening`` to True. + +It is based on the following electrostatic and Lennard-Jones potentials: + +.. math:: + + V_{\text{elec}}(r) = q_i q_j \left[ \frac{(1 - \alpha)^n}{\sqrt{r^2 + \delta_\text{coulomb}^2}} - \frac{\kappa}{r} \right] + + V_{\text{LJ}}(r) = 4\epsilon \left[ \frac{\sigma^{12}}{(\delta_\text{LJ} \sigma + r^2)^6} - \frac{\sigma^6}{(\delta_\text{LJ} \sigma + r^2)^3} \right] + +where + +.. math:: + + \delta_\text{coulomb} = \alpha \times \text{shift_coulomb} + + \delta_\text{LJ} = \alpha \times \text{shift_LJ} + +and + +.. math:: + + \alpha = \max(\alpha_i, \alpha_j) + + \kappa = \max(\kappa_i, \kappa_j) + +The parameters ``r``, ``q_i``, ``q_j``, ``\epsilon``, and ``\sigma`` +are the standard parameters for the electrostatic and Lennard-Jones +potentials. + +The soft-core parameters are: + +* ``α_i`` and ``α_j`` control the amount of "softening" of the + electrostatic and LJ interactions. A value of 0 means no softening + (fully hard), while a value of 1 means fully soft. Ghost atoms which + disappear as a function of λ have a value of α of 0 in the + reference state, and 1 in the perturbed state. Ghost atoms which appear + as a function of λ have a value of α of 1 in the reference + state, and 0 in the perturbed state. These values can be perturbed + via the ``alpha`` lever in the λ-schedule. + +* ``n`` is the "coulomb power", and is set to 0 by default. It can be + any integer between 0 and 4. It is set via ``coulomb_power`` map + parameter. + +* ``shift_coulomb`` and ``shift_LJ`` are the so-called "shift delta" + parameters, which are specified individually for the coulomb and LJ\ + potentials. They are set via the ``shift_coulomb`` and ``shift_delta`` + map parameters. They default to 1 Å and 2.5 Å respectively. + +* ``κ_i`` and ``κ_j`` are the "hard" electrostatic parameters, + which control whether or not to calculate the "hard" electrostatic + interaction to subtract from the total energy and force (thus cancelling + out the double-counting of this interaction from the NonbondedForce). + By default, these are always equal to 1. You can perturb these via the + ``kappa`` lever in the λ-schedule, e.g. if you want to decouple the + intramolecular electrostatic interactions, when the "hard" interaction + would not be calculated in the NonbondedForce. + + +Taylor softening +---------------- + +This is the second soft-core potential. You can use it by setting the +map option ``use_taylor_softening`` to True. + +It is based on the following electrostatic and Lennard-Jones potentials: + +.. math:: + + V_{\text{elec}}(r) = q_i q_j \left[ \frac{(1 - \alpha)^n}{\sqrt{r^2 + \delta^2}} - \frac{\kappa}{r} \right] + + V_{\text{LJ}}(r) = 4\epsilon \left[ \frac{\sigma^{12}}{(\alpha^m \sigma^6 + r^6)^2} - \frac{\sigma^6}{\alpha^m \sigma^6 + r^6} \right] + +where + +.. math:: + + \delta = \alpha \times \text{shift_coulomb} + +and + +.. math:: + + \alpha = \max(\alpha_i, \alpha_j) + + \kappa = \max(\kappa_i, \kappa_j) + +The parameters ``r``, ``q_i``, ``q_j``, ``\epsilon``, and ``\sigma`` +are the standard parameters for the electrostatic and Lennard-Jones +potentials. + +The soft-core parameters are: + +* ``α_i`` and ``α_j`` control the amount of "softening" of the + electrostatic and LJ interactions. A value of 0 means no softening + (fully hard), while a value of 1 means fully soft. Ghost atoms which + disappear as a function of λ have a value of α of 0 in the + reference state, and 1 in the perturbed state. Ghost atoms which appear + as a function of λ have a value of α of 1 in the reference + state, and 0 in the perturbed state. These values can be perturbed + via the ``alpha`` lever in the λ-schedule. + +* ``m`` is the "taylor power", and is set to 1 by default. It can be + any integer between 0 and 4. It is set via ``taylor_power`` map + parameter. + +* ``n`` is the "coulomb power", and is set to 0 by default. It can be + any integer between 0 and 4. It is set via ``coulomb_power`` map + parameter. + +* ``shift_coulomb`` is the so-called "shift delta" + parameters, which are specified only for the coulomb + potential. This is set via the ``shift_coulomb`` + map parameters. This defaults to 1 Å. + +* ``κ_i`` and ``κ_j`` are the "hard" electrostatic parameters, + which control whether or not to calculate the "hard" electrostatic + interaction to subtract from the total energy and force (thus cancelling + out the double-counting of this interaction from the NonbondedForce). + By default, these are always equal to 1. You can perturb these via the + ``kappa`` lever in the λ-schedule, e.g. if you want to decouple the + intramolecular electrostatic interactions, when the "hard" interaction + would not be calculated in the NonbondedForce. + +Good practice +------------- + +Softening potentials can help to avoid singularities and crashes +when atoms are annihilated or created. However, you still need to be +careful when using them. For example, it is best when creating or +destroying an atom to keep the sigma LJ parameter the same for both +end states. This way, only the epsilon parameter is scaled to zero, +while the atom keeps its same "size". This avoids the atom shrinking +as a function of λ, which could result in atoms (and thus charges) +getting too close to one another. + +For complex or large molecules, it may be better to separate out the +decharging from the decoupling or annihilation, e.g. first set up +a λ-schedule to have two stages; the first stage decouples the charges, +while the second stage annihilates or decouples the atoms. + +This could be achieved using the following λ-schedule: + +>>> import sire as sr +>>> s = sr.cas.LambdaSchedule.standard_morph() +>>> s.set_equation(stage="morph", lever="charge", equation=s.final()) +>>> s.prepend_stage("decharge", s.initial()) +>>> s.set_equation(stage="decharge", lever="charge", +... equation=l.lam() * s.final() + s.initial() * (1 - s.lam())) +>>> s.get_lever_values(initial=2.0, final=3.0).plot() + +.. image:: images/07_03_01.jpg + :alt: How parameters would be changed by the above λ-schedule. diff --git a/doc/source/tutorial/part07/04_merge.rst b/doc/source/tutorial/part07/04_merge.rst new file mode 100644 index 000000000..625c6e558 --- /dev/null +++ b/doc/source/tutorial/part07/04_merge.rst @@ -0,0 +1,446 @@ +======================== +Creating merge molecules +======================== + +Merged molecules are used in free energy calculations to represent the +perturbation between two molecules; the reference molecule (at λ=0) +and the perturbed molecule (at λ=1). + +To start, let's load up two molecules, neopentane and methane, which we +will use to create a merged molecule to calculate the relative hydration +free energy. + +>>> neopentane = sr.load_test_files("neopentane.prm7", "neopentane.rst")[0] +>>> neopentane.view() + +.. image:: images/07_04_01.jpg + :alt: A picture of neopentane + +>>> methane = sr.load_test_files("methane.prm7", "methane.rst")[0] +>>> methane.view() + +.. image:: images/07_04_02.jpg + :alt: A picture of methane + +Matching atoms +-------------- + +The first step to creating a merged molecule is to decide how atoms +should relate between the two end states. This is done by matching atoms +from the reference molecule (in this case neopentane) to the perturbed +molecule (in this case methane). + +For example, let's say that we want the central carbon of neopentane to +perturb into the central carbon of methane. We could specify this by +creating a dictionary that says that the name of this atom in neopentane +should map to the name of the equivalent atom in methane. + +We can get the name of these atoms using the 3D viewer, as shown above. +The central carbon of neopentane is called ``C1``, while the central +carbon of methane is also called ``C1``. + +>>> matching = {"C1": "C1"} + +Next, we would match each of the other carbon atoms in neopentane to +the hydrogen atoms in methane. + +>>> matching["C2"] = "H2" +>>> matching["C3"] = "H3" +>>> matching["C4"] = "H4" +>>> matching["C5"] = "H5" +>>> print(matching) +{'C1': 'C1', 'C2': 'H2', 'C3': 'H3', 'C4': 'H4', 'C5': 'H5'} + +Merging molecules +----------------- + +We use the :func:`sire.morph.merge` function to create merged molecules. +This takes in the two molecules you want to merge, and the matching +dictionary you have created. + +>>> merged = sr.morph.merge(mol0=neopentane, mol1=methane, match=matching) +>>> merged.perturbation().view_reference() + +.. image:: images/07_04_03.jpg + :alt: A picture of the merged neopentance to methane + +.. note:: + + The reference state is numbered ``0`` (i.e. ``mol0``) while the + perturbed state is numbered ``1`` (i.e. ``mol1``). This is used to + remind us what λ-value each state corresponds to. + +We can see how the underlying OpenMM parameters will be perturbed by +checking the :class:`~sire.legacy.Convert.PerturbableOpenMMMolecule` +that would be created from the merged molecule. + +>>> p = merged.perturbation().to_openmm() +>>> print(p.changed_atoms()) + atom charge0 charge1 sigma0 sigma1 epsilon0 epsilon1 alpha0 alpha1 kappa0 kappa1 +0 C2:1 -0.085335 0.0271 0.339967 0.264953 0.457730 0.065689 0.0 0.0 0.0 0.0 +1 C1:2 -0.060235 -0.1084 0.339967 0.339967 0.457730 0.457730 0.0 0.0 0.0 0.0 +2 C3:3 -0.085335 0.0271 0.339967 0.264953 0.457730 0.065689 0.0 0.0 0.0 0.0 +3 C4:4 -0.085335 0.0271 0.339967 0.264953 0.457730 0.065689 0.0 0.0 0.0 0.0 +4 C5:5 -0.085335 0.0271 0.339967 0.264953 0.457730 0.065689 0.0 0.0 0.0 0.0 +5 H6:6 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +6 H7:7 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +7 H8:8 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +8 H9:9 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +9 H10:10 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +10 H11:11 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +11 H12:12 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +12 H13:13 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +13 H14:14 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +14 H15:15 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +15 H16:16 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +16 H17:17 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 + +We can see here that the five carbons in neopentane have their charge +and LJ parameters perturbed from the neopentane values to the methane +values. + +We can also see that the hydrogens in neopentane are converted to ghost +atoms, as they have no match in methane. The conversion to ghost atoms +involves setting their charge to zero, and setting the LJ epsilon parameter +of the atoms to zero (keeping the sigma parameter the same, as suggested +as best practice in the :doc:`last tutorial <03_ghosts>`). + +Note also how the alpha parameters of the hydrogens changes from 0 to 1 +as those atoms become ghosts. + +We can also look at the changes in internal parameters. + +>>> print(p.changed_bonds()) + bond length0 length1 k0 k1 +0 C2:1-C1:2 0.15375 0.10969 251793.12 276646.08 +1 C1:2-C3:3 0.15375 0.10969 251793.12 276646.08 +2 C1:2-C4:4 0.15375 0.10969 251793.12 276646.08 +3 C1:2-C5:5 0.15375 0.10969 251793.12 276646.08 +>>> print(p.changed_angles()) + angle size0 size1 k0 k1 +0 C4:4-C1:2-C5:5 1.946217 1.877626 526.3472 329.6992 +1 C3:3-C1:2-C4:4 1.946217 1.877626 526.3472 329.6992 +2 C3:3-C1:2-C5:5 1.946217 1.877626 526.3472 329.6992 +3 C2:1-C1:2-C3:3 1.946217 1.877626 526.3472 329.6992 +4 C2:1-C1:2-C4:4 1.946217 1.877626 526.3472 329.6992 +5 C2:1-C1:2-C5:5 1.946217 1.877626 526.3472 329.6992 +>>> print(p.changed_torsions()) +Empty DataFrame +Columns: [torsion, k0, k1, periodicity0, periodicity1, phase0, phase1] +Index: [] + +We can see that the bond lengths and angles are perturbed from their values +in neopentane (representing C-C bonds and C-C-C angles) to their values +in methane (representing C-H bonds and H-C-H angles). Note that the +bonds, angles and torsions for the hydrogens in neopentane are not +perturbed. This is because all of these atoms are converted to ghost atoms, +and the default is that internals involving ghost atoms keep the parameters +from the end state where they are not ghosts (i.e. the reference state +values in this case). + +Implementation - AtomMapping +---------------------------- + +Under the hood, the above merge was implemented via the +:class:`sire.mol.AtomMapping` class. This class holds all of the information +about how atoms are mapped between end states, and an object of this +class was created automatically by the :func:`~sire.morph.merge` function. + +We can create the mapping object directly using the +:func:`sire.morph.match` function. + +>>> m = sr.morph.match(mol0=neopentane, mol1=methane, match=matching) +>>> print(m) +AtomMapping( size=5, unmapped0=12, unmapped1=0 +0: MolNum(3) Atom( C1:2 ) <=> MolNum(2) Atom( C1:2 ) +1: MolNum(3) Atom( C2:1 ) <=> MolNum(2) Atom( H2:1 ) +2: MolNum(3) Atom( C4:4 ) <=> MolNum(2) Atom( H4:4 ) +3: MolNum(3) Atom( C3:3 ) <=> MolNum(2) Atom( H3:3 ) +4: MolNum(3) Atom( C5:5 ) <=> MolNum(2) Atom( H5:5 ) +) + +This shows how the five carbon atoms in neopentane are mapped to the +carbon and four hydrogens of methane. It also shows how 12 atoms in the +reference state are unmapped (``unmapped0=12``) and how no atoms in the +perturbed state are unmapped (``unmapped1=0``). + +This class has some useful functions. One is +:func:`~sire.mol.AtomMapping.align`, which aligns the perturbed state +against the reference state, using an algorithm that minimises the +RMSD of the mapped atoms. + +>>> m = m.align() + +Another useful function is :func:`~sire.mol.AtomMapping.merge`, which +actually performs the merge, returning the merged molecule, with +perturbable properties linked to the reference state. + +>>> merged = m.merge() +>>> print(merged) +Molecule( NEO:7 num_atoms=17 num_residues=1 ) + +The :func:`~sire.morph.merge` function is really a wrapper that create +this :class:`~sire.mol.AtomMapping` object, calls align, and then +calls the :func:`~sire.mol.AtomMapping.merge` function. + +Automatic matching +------------------ + +Creating the matching dictionary by hand can be a bit tedious! Fortunately, +there are lots of tools that can help automate this process. + +One such tool is the above :func:`~sire.morph.match` function. If you don't +pass in a ``match`` argument, then an internal maximum common substructure +algorithm will be used to try to infer the matching. + +>>> m = sr.morph.match(mol0=neopentane, mol1=methane) +>>> print(m) +AtomMapping( size=1, unmapped0=16, unmapped1=4 +0: MolNum(3) Atom( C2:1 ) <=> MolNum(2) Atom( C1:2 ) +) + +.. warning:: + + The maximum common substructure algorithm is not supported on Windows. + This will only work on MacOS and Linux. + +By default, this algorithm ignores hydrogens. This is why only a single +atom was matched above. You can change this by passing in the +``ignore_light_atoms=True`` argument. + +>>> m = sr.morph.match(mol0=neopentane, mol1=methane, match_light_atoms=True) +>>> print(m) +AtomMapping( size=4, unmapped0=13, unmapped1=1 +0: MolNum(3) Atom( C2:1 ) <=> MolNum(2) Atom( C1:2 ) +1: MolNum(3) Atom( H6:6 ) <=> MolNum(2) Atom( H2:1 ) +2: MolNum(3) Atom( H8:8 ) <=> MolNum(2) Atom( H4:4 ) +3: MolNum(3) Atom( H7:7 ) <=> MolNum(2) Atom( H3:3 ) +) + +Note how this has come up with a different mapping than the one we created +manually. + +The internal algorithm is quite slow, especially for large molecules. +It is also not aware of stereochemistry, and generally not recommended +if other tools are available. + +Fortunately, because the funtion accepts a python dictionary, it is very +easy to use other tools to generate the mapping and pass to this function. + +Using Kartograf mappings +------------------------ + +`Kartograf `__ is a package +for generating atom mappings which takes into account 3D geometries. +This means that mappings can account for stereochemistry. It is also +extremely fast and robust, with lots of active development. It is a very +good choice for generating atom mappings. + +To use Kartograf, you may need to install it. You can do this with conda. + +.. code-block:: bash + + conda install -c conda-forge kartograf + +Next, we will import the components of Kartograf that we need. + +>>> from kartograf.atom_aligner import align_mol_shape +>>> from kartograf import KartografAtomMapper, SmallMoleculeComponent + +Kartograf can work from RDKit molecules, so we'll now convert our sire +molecules to RDKit. + +>>> rd_neopentane = sr.convert.to(neopentane, "rdkit") +>>> rd_methane = sr.convert.to(methane, "rdkit") + +Next, we will create two Kartograf molecules from these RDKit molecules. + +>>> k_neopentane, k_methane = [ +... SmallMoleculeComponent.from_rdkit(m) for m in [rd_neopentane, rd_methane] +... ] + +Now, we align the molecules based on their shape, aligning methane on top +of neopentane. + +>>> k_aligned_methane = align_mol_shape(k_methane, ref_mol=k_neopentane) + +To generate the mappings, we will create a KartografAtomMapper object +which is allowed to match light atoms. + +>>> mapper = KartografAtomMapper(atom_map_hydrogens=True) + +This can be used to generate the mappings. + +>>> mappings = mapper.suggest_mappings(k_neopentane, k_aligned_methane) + +We will now get the first mapping... + +>>> mapping = next(mappings) +>>> print(mapping) +LigandAtomMapping(componentA=SmallMoleculeComponent(name=NEO), + componentB=SmallMoleculeComponent(name=CH4), + componentA_to_componentB={1: 0, 11: 2, 12: 3, 13: 4, 3: 1}, + annotations={}) + +The mappings are atom indexes. We can collect these and create a +dictionary that maps from atom index to atom index using this code. + +>>> matching = {} +>>> for atom0, atom1 in mapping.componentA_to_componentB.items(): +... matching[sr.atomid(idx=atom0)] = sr.atomid(idx=atom1) +>>> print(matching) +{AtomIdx(1): AtomIdx(0), AtomIdx(11): AtomIdx(2), AtomIdx(12): AtomIdx(3), + AtomIdx(13): AtomIdx(4), AtomIdx(3): AtomIdx(1)} + +Finally, we can pass this into the :func:`~sire.morph.match` function +to create the :class:`~sire.mol.AtomMapping` object. + +>>> mapping = sr.morph.match(mol0=neopentane, mol1=methane, match=matching) +>>> print(mapping) +AtomMapping( size=5, unmapped0=12, unmapped1=0 +0: MolNum(3) Atom( H12:12 ) <=> MolNum(2) Atom( H3:3 ) +1: MolNum(3) Atom( H14:14 ) <=> MolNum(2) Atom( H5:5 ) +2: MolNum(3) Atom( H13:13 ) <=> MolNum(2) Atom( H4:4 ) +3: MolNum(3) Atom( C1:2 ) <=> MolNum(2) Atom( H2:1 ) +4: MolNum(3) Atom( C4:4 ) <=> MolNum(2) Atom( C1:2 ) +) + +Automatic Kartograf mapping +--------------------------- + +The above code can be quite tedious to write, so we have created the +ability to pass in a ``KartografAtomMapper`` object as the ``match`` +argument to the :func:`~sire.morph.match` and :func:`~sire.morph.merge` +functions, which then does all of the above automatically. + +>>> mapper = KartografAtomMapper(atom_map_hydrogens=True) +>>> mapping = sr.morph.match(mol0=neopentane, mol1=methane, match=mapper) +>>> print(mapping) +AtomMapping( size=5, unmapped0=12, unmapped1=0 +0: MolNum(3) Atom( H12:12 ) <=> MolNum(2) Atom( H3:3 ) +1: MolNum(3) Atom( H14:14 ) <=> MolNum(2) Atom( H5:5 ) +2: MolNum(3) Atom( H13:13 ) <=> MolNum(2) Atom( H4:4 ) +3: MolNum(3) Atom( C1:2 ) <=> MolNum(2) Atom( H2:1 ) +4: MolNum(3) Atom( C4:4 ) <=> MolNum(2) Atom( C1:2 ) +) +>>> merged = sr.morph.merge(mol0=neopentane, mol1=methane, match=mapper) +>>> print(merged) +Molecule( NEO:8 num_atoms=17 num_residues=1 ) +>>> m = merged.perturbation().to_openmm() +>>> print(m.changed_atoms()) + atom charge0 charge1 sigma0 sigma1 epsilon0 epsilon1 alpha0 alpha1 kappa0 kappa1 +0 C2:1 -0.085335 0.0000 0.339967 0.339967 0.457730 0.000000 0.0 1.0 1.0 1.0 +1 C1:2 -0.060235 0.0271 0.339967 0.264953 0.457730 0.065689 0.0 0.0 0.0 0.0 +2 C3:3 -0.085335 0.0000 0.339967 0.339967 0.457730 0.000000 0.0 1.0 1.0 1.0 +3 C4:4 -0.085335 -0.1084 0.339967 0.339967 0.457730 0.457730 0.0 0.0 0.0 0.0 +4 C5:5 -0.085335 0.0000 0.339967 0.339967 0.457730 0.000000 0.0 1.0 1.0 1.0 +5 H6:6 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +6 H7:7 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +7 H8:8 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +8 H9:9 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +9 H10:10 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +10 H11:11 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +11 H12:12 0.033465 0.0271 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +12 H13:13 0.033465 0.0271 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +13 H14:14 0.033465 0.0271 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +14 H15:15 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +15 H16:16 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +16 H17:17 0.033465 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 + +This is a much easier way to create merged molecules! + +Extracting the end states +------------------------- + +As with all merged molecules, we can extract the end states via the +:func:`sire.morph.extract_reference` and :func:`sire.morph.extract_perturbed` +functions. + +>>> neopentane = sr.morph.extract_reference(merged) +>>> print(neopentane.atoms()) +Selector( size=17 +0: Atom( C2:1 [ 2.24, 1.01, 0.00] ) +1: Atom( C1:2 [ 1.26, 0.09, -0.75] ) +2: Atom( C3:3 [ 0.99, 0.66, -2.15] ) +3: Atom( C4:4 [ -0.06, -0.00, 0.04] ) +4: Atom( C5:5 [ 1.88, -1.32, -0.88] ) +... +12: Atom( H13:13 [ -0.78, -0.67, -0.49] ) +13: Atom( H14:14 [ 0.11, -0.42, 1.05] ) +14: Atom( H15:15 [ 2.83, -1.27, -1.44] ) +15: Atom( H16:16 [ 2.08, -1.75, 0.13] ) +16: Atom( H17:17 [ 1.19, -2.00, -1.42] ) +) +>>> methane = sr.morph.extract_perturbed(merged) +>>> print(methane.atoms()) +Selector( size=5 +0: Atom( H2:2 [ -0.45, 1.01, 0.10] ) +1: Atom( C1:4 [ -0.00, 0.00, 0.00] ) +2: Atom( H3:12 [ -0.71, -0.67, -0.53] ) +3: Atom( H4:13 [ 0.95, 0.07, -0.57] ) +4: Atom( H5:14 [ 0.21, -0.41, 1.01] ) +) + +The names of the atoms and residues are preserved in the merged molecule, +meaning that they are correctly output for each end state. In the merged +molecule, the atom and residue names default to the reference state names. +The perturbed state names are held in the "alternate" names. + +>>> print(merged.residues()[0].name(), merged.residues()[0].alternate_name()) +ResName('NEO') ResName('CH4') +>>> print(merged[1].name(), merged[1].alternate_name()) +AtomName('C1') AtomName('H2') + +Atoms that are unmapped in an end state are called ``Xxx``, e.g. + +>>> print(merged[0].name(), merged[0].alternate_name()) +AtomName('C2') AtomName('Xxx') + +You can switch between the standard and alternate names of a molecule +by calling the :func:`~sire.legacy.Mol.MolEditor.switch_to_alternate_names` +function. + +>>> print(merged.atoms()) +Selector( size=17 +0: Atom( C2:1 [ 2.24, 1.01, 0.00] ) +1: Atom( C1:2 [ 1.26, 0.09, -0.75] ) +2: Atom( C3:3 [ 0.99, 0.66, -2.15] ) +3: Atom( C4:4 [ -0.06, -0.00, 0.04] ) +4: Atom( C5:5 [ 1.88, -1.32, -0.88] ) +... +12: Atom( H13:13 [ -0.78, -0.67, -0.49] ) +13: Atom( H14:14 [ 0.11, -0.42, 1.05] ) +14: Atom( H15:15 [ 2.83, -1.27, -1.44] ) +15: Atom( H16:16 [ 2.08, -1.75, 0.13] ) +16: Atom( H17:17 [ 1.19, -2.00, -1.42] ) +) +>>> merged = merged.edit().switch_to_alternate_names().commit() +>>> print(merged.atoms()) +Selector( size=17 +0: Atom( Xxx:1 [ 2.24, 1.01, 0.00] ) +1: Atom( H2:2 [ 1.26, 0.09, -0.75] ) +2: Atom( Xxx:3 [ 0.99, 0.66, -2.15] ) +3: Atom( C1:4 [ -0.06, -0.00, 0.04] ) +4: Atom( Xxx:5 [ 1.88, -1.32, -0.88] ) +... +12: Atom( H4:13 [ -0.78, -0.67, -0.49] ) +13: Atom( H5:14 [ 0.11, -0.42, 1.05] ) +14: Atom( Xxx:15 [ 2.83, -1.27, -1.44] ) +15: Atom( Xxx:16 [ 2.08, -1.75, 0.13] ) +16: Atom( Xxx:17 [ 1.19, -2.00, -1.42] ) +) +>>> merged = merged.edit().switch_to_alternate_names().commit() +>>> print(merged.atoms()) +Selector( size=17 +0: Atom( C2:1 [ 2.24, 1.01, 0.00] ) +1: Atom( C1:2 [ 1.26, 0.09, -0.75] ) +2: Atom( C3:3 [ 0.99, 0.66, -2.15] ) +3: Atom( C4:4 [ -0.06, -0.00, 0.04] ) +4: Atom( C5:5 [ 1.88, -1.32, -0.88] ) +... +12: Atom( H13:13 [ -0.78, -0.67, -0.49] ) +13: Atom( H14:14 [ 0.11, -0.42, 1.05] ) +14: Atom( H15:15 [ 2.83, -1.27, -1.44] ) +15: Atom( H16:16 [ 2.08, -1.75, 0.13] ) +16: Atom( H17:17 [ 1.19, -2.00, -1.42] ) +) diff --git a/doc/source/tutorial/part07/05_pertfile.rst b/doc/source/tutorial/part07/05_pertfile.rst new file mode 100644 index 000000000..60584e84f --- /dev/null +++ b/doc/source/tutorial/part07/05_pertfile.rst @@ -0,0 +1,108 @@ +============================== +Perturbation Files (pertfiles) +============================== + +Perturbation files (or pertfiles) are an older mechanism that was used +in ``somd`` to create a merged molecule from a passed input molecule. +They are a simple text file that describes the perturbation in terms +of changing forcefield parameters. You can create a merged molecule +from a single molecule plus pertfile using the +:func:`sire.morph.create_from_pertfile` function. + +>>> merged_mol = sr.morph.create_from_pertfile(mol, "neopentane_methane.pert") +>>> print(merged_mol.property("charge0")) + +>>> print(merged_mol.property("charge1")) + +.. note:: + + This is an older mechanism that has many limitations due to the + inherent limits of the pertfile format. It is provided to aid + compatibility with older ``somd`` workflows, but is not + recommended for new use cases. + +Updating internals involving ghost atoms +---------------------------------------- + +Sometimes you want to update the internals (bonds, angles, torsions) when +one or more of the atoms involved are ghosts in either the reference or +perturbed states. + +The function :func:`sire.morph.zero_ghost_torsions` will automatically add +torsion perturbations that zero the force constant of any torsions that +involve ghost atoms in that state. This is useful when you want to +fade in or out torsion forces as ghost atoms appear or disappear. + +>>> mols = sr.morph.zero_ghost_torsions(mols) +>>> print(mols[0].perturbation().to_openmm().changed_torsions()) + torsion k0 k1 periodicity0 periodicity1 phase0 phase1 +0 C5:5-C2:2-C3:3-H11:11 0.66944 0.0 3 3 -0.0 -0.0 +1 C1:1-C2:2-C3:3-H11:11 0.66944 0.0 3 3 -0.0 -0.0 +2 C5:5-C2:2-C3:3-H10:10 0.66944 0.0 3 3 -0.0 -0.0 +3 C3:3-C2:2-C4:4-H12:12 0.66944 0.0 3 3 -0.0 -0.0 +4 C1:1-C2:2-C3:3-H10:10 0.66944 0.0 3 3 -0.0 -0.0 +5 C1:1-C2:2-C5:5-H16:16 0.66944 0.0 3 3 -0.0 -0.0 +6 C5:5-C2:2-C3:3-H9:9 0.66944 0.0 3 3 -0.0 -0.0 +7 C1:1-C2:2-C3:3-H9:9 0.66944 0.0 3 3 -0.0 -0.0 +8 C3:3-C2:2-C1:1-H7:7 0.66944 0.0 3 3 -0.0 -0.0 +9 C3:3-C2:2-C1:1-H8:8 0.66944 0.0 3 3 -0.0 -0.0 +10 C3:3-C2:2-C1:1-H6:6 0.66944 0.0 3 3 -0.0 -0.0 +11 C1:1-C2:2-C5:5-H15:15 0.66944 0.0 3 3 -0.0 -0.0 +12 C4:4-C2:2-C5:5-H17:17 0.66944 0.0 3 3 -0.0 -0.0 +13 C4:4-C2:2-C3:3-H11:11 0.66944 0.0 3 3 -0.0 -0.0 +14 C4:4-C2:2-C3:3-H10:10 0.66944 0.0 3 3 -0.0 -0.0 +15 C4:4-C2:2-C5:5-H16:16 0.66944 0.0 3 3 -0.0 -0.0 +16 C4:4-C2:2-C3:3-H9:9 0.66944 0.0 3 3 -0.0 -0.0 +17 C5:5-C2:2-C4:4-H14:14 0.66944 0.0 3 3 -0.0 -0.0 +18 C5:5-C2:2-C4:4-H13:13 0.66944 0.0 3 3 -0.0 -0.0 +19 C1:1-C2:2-C4:4-H14:14 0.66944 0.0 3 3 -0.0 -0.0 +20 C4:4-C2:2-C5:5-H15:15 0.66944 0.0 3 3 -0.0 -0.0 +21 C3:3-C2:2-C5:5-H17:17 0.66944 0.0 3 3 -0.0 -0.0 +22 C1:1-C2:2-C4:4-H13:13 0.66944 0.0 3 3 -0.0 -0.0 +23 C5:5-C2:2-C4:4-H12:12 0.66944 0.0 3 3 -0.0 -0.0 +24 C1:1-C2:2-C4:4-H12:12 0.66944 0.0 3 3 -0.0 -0.0 +25 C3:3-C2:2-C5:5-H16:16 0.66944 0.0 3 3 -0.0 -0.0 +26 C5:5-C2:2-C1:1-H7:7 0.66944 0.0 3 3 -0.0 -0.0 +27 C5:5-C2:2-C1:1-H8:8 0.66944 0.0 3 3 -0.0 -0.0 +28 C5:5-C2:2-C1:1-H6:6 0.66944 0.0 3 3 -0.0 -0.0 +29 C3:3-C2:2-C5:5-H15:15 0.66944 0.0 3 3 -0.0 -0.0 +30 C3:3-C2:2-C4:4-H14:14 0.66944 0.0 3 3 -0.0 -0.0 +31 C3:3-C2:2-C4:4-H13:13 0.66944 0.0 3 3 -0.0 -0.0 +32 C4:4-C2:2-C1:1-H7:7 0.66944 0.0 3 3 -0.0 -0.0 +33 C4:4-C2:2-C1:1-H8:8 0.66944 0.0 3 3 -0.0 -0.0 +34 C4:4-C2:2-C1:1-H6:6 0.66944 0.0 3 3 -0.0 -0.0 +35 C1:1-C2:2-C5:5-H17:17 0.66944 0.0 3 3 -0.0 -0.0 + +Similarly, the :func:`sire.morph.shrink_ghost_atoms` function will automatically +adjust the bond lengths of bonds that involve ghost atoms, so that they will +either be pulled into, or emerge from their connected atoms. + +>>> mols = sr.morph.shrink_ghost_atoms(mols) +>>> print(mols[0].perturbation().to_openmm(constraint="bonds").changed_constraints()) + atompair length0 length1 +0 C2:2-C3:3 0.15375 0.06000 +1 C5:5-H17:17 0.10969 0.06000 +2 C2:2-C4:4 0.15375 0.10969 +3 C1:1-C2:2 0.15375 0.06000 +4 C1:1-H7:7 0.10969 0.06000 +5 C2:2-C5:5 0.15375 0.06000 +6 C1:1-H8:8 0.10969 0.06000 +7 C1:1-H6:6 0.10969 0.06000 +8 C3:3-H11:11 0.10969 0.06000 +9 C5:5-H15:15 0.10969 0.06000 +10 C3:3-H9:9 0.10969 0.06000 +11 C5:5-H16:16 0.10969 0.06000 +12 C3:3-H10:10 0.10969 0.06000 + +.. note:: + + You can control the length of the ghost bond using the ``length`` + argument, e.g. ``shrink_ghost_atoms(mols, length="0.2A")`` would + shrink the bond to 0.2 Å. The default length is 0.6 Å. + +.. note:: + + In general, you don't often need to pull ghost atoms into or out + from their connected atoms. This is because a soft-core potential + is used to soften interactions involving ghost atoms, such that + they fade away smoothly as they disappear. diff --git a/doc/source/tutorial/part07/06_decouple.rst b/doc/source/tutorial/part07/06_decouple.rst new file mode 100644 index 000000000..eca57afaf --- /dev/null +++ b/doc/source/tutorial/part07/06_decouple.rst @@ -0,0 +1,318 @@ +=========================== +Annihilation and Decoupling +=========================== + +So far, we have discussed how to construct merge molecules that represent +perturbations from one molecule to another. These are useful for +relative free energy calculations. + +Absolute free energy calculations require perturbations that decouple +or annihilate molecules. The :func:`sire.morph.decouple` and +:func:`sire.morph.annihilate` create merged molecules that represent +these perturbations. + +Decoupling +---------- + +Decoupling is the process of turning off the interactions between the +molecule of interest, and all other molecules in the system. + +For example, let's load up a system comprising benzene in a box of +water (with some ions). + +>>> import sire as sr +>>> mols = sr.load_test_files("benzene.prm7", "benzene.rst") +>>> benzene = mols[0] +>>> print(benzene) +Molecule( BEN:2 num_atoms=12 num_residues=1 ) + +We can create a merged molecule that represents the decoupling of the +benzene via the :func:`sire.morph.decouple` function. + +>>> benzene = sr.morph.decouple(benzene, as_new_molecule=False) +>>> print(benzene) +Molecule( BEN:2 num_atoms=12 num_residues=1 ) + +.. note:: + + We pass in ``as_new_molecule=False`` so that the resulting merged + molecule keeps the same molecule number as the original benzene. + If we had passed in ``as_new_molecule=True`` (which is the default) + then the returned molecule would be a "new" molecule, with its + own, unique molecule number. + +The decoupled benzene molecule is a merged molecule where all of the +atoms are converted to ghost atoms. + +>>> p = benzene.perturbation().to_openmm() +>>> print(p.changed_atoms()) + atom charge0 charge1 sigma0 sigma1 epsilon0 epsilon1 alpha0 alpha1 kappa0 kappa1 +0 C:1 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +1 C2:2 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +2 C3:3 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +3 C4:4 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +4 C5:5 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +5 C6:6 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +6 H1:7 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +7 H2:8 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +8 H3:9 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +9 H4:10 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +10 H5:11 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +11 H6:12 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 + +.. note:: + + Note how the atoms are converted to ghosts by setting the charge and epsilon + parameters to zero, and setting the alpha value to 1.0 in the end state, + and the kappa values to 1.0 in both end states. + +All of the internals (bonds, angles, torsions) are kept the same at both +end states. + +>>> print(p.changed_bonds()) +Empty DataFrame +Columns: [bond, length0, length1, k0, k1] +Index: [] +>>> print(p.changed_angles()) +Empty DataFrame +Columns: [angle, size0, size1, k0, k1 +Index: [] +>>> print(p.changed_torsions()) +Empty DataFrame +Columns: [torsion, k0, k1, periodicity0, periodicity1, phase0, phase1] +Index: [] + +To decouple the benzene molecule correctly, a custom :class:`sire.cas.LambdaSchedule` +is needed. This schedule turns off intermolecular interactions involving the +benzene, while keeping the intramolecular interactions the same. + +The :func:`sire.morph.decouple` function creates a suitable schedule by +default, and attaches it to the merged molecule via its ``schedule`` +property. + +>>> schedule = benzene.property("schedule") +>>> print(schedule) +LambdaSchedule( + decouple: (-λ + 1) * initial + λ * final + ghost-14::*: initial + ghost-14::kappa: -λ + 1 + ghost/ghost::*: initial + ghost/ghost::kappa: -λ + 1 +) + +This schedule has a single stage called ``decouple``. The default is that +all levers use the standard morphing equation to linearly interpolate +from the initial to final states. This has the effect of turning off +all charge and LJ interactions involving benzene. + +However, we want to preserve the intramolecular charge and LJ interactions +of benzene. Since all atoms are ghost atoms, these are +all evaluated in the ghost/ghost and ghost-14 forces. We therefore set all +levers in the ghost/ghost and ghost-14 forces to use the parameters in the +initial state (i.e. the full charges and epsilon LJ parameters for benzene). + +But, because the ghost/ghost force includes a correction to subtract +a double-counted electrostatic interaction from the NonbondedForce, +we also need to have a lever that scales kappa with 1-λ. In this way, +the kappa parameter will ensure that the correction is applied at +λ=0, when the electrostatic interactions of benzene are evaluated in both +the NonbondedForce and the ghost/ghost and ghost-14 forces, while it will +scale kappa to 0 at λ=1, when the electrostatic interactions of benzene are +only evaluated in the ghost/ghost and ghost-14 forces. + +We can view exactly how a schedule will perturb the real parameters of +a merged molecule using the +:meth:`~sire.legacy.Convert.PerturbableOpenMMMolecule.get_lever_values` +function. + +>>> df = p.get_lever_values(schedule=schedule) +>>> print(df) + clj-charge-1 clj-charge-7 clj-epsilon-1 clj-epsilon-7 clj-alpha-1 ghost/ghost-kappa-1 +λ +0.00 -0.1300 0.1300 0.363503 0.065318 0.00 1.00 +0.01 -0.1287 0.1287 0.359868 0.064665 0.01 0.99 +0.02 -0.1274 0.1274 0.356233 0.064012 0.02 0.98 +0.03 -0.1261 0.1261 0.352598 0.063358 0.03 0.97 +0.04 -0.1248 0.1248 0.348963 0.062705 0.04 0.96 +... ... ... ... ... ... ... +0.96 -0.0052 0.0052 0.014540 0.002613 0.96 0.04 +0.97 -0.0039 0.0039 0.010905 0.001960 0.97 0.03 +0.98 -0.0026 0.0026 0.007270 0.001306 0.98 0.02 +0.99 -0.0013 0.0013 0.003635 0.000653 0.99 0.01 +1.00 0.0000 0.0000 0.000000 0.000000 1.00 0.00 +[101 rows x 6 columns] + +>>> ax = df.plot() + +.. image:: images/07_06_01.jpg + :alt: Graph of the effect of all levers on the decoupled molecule. + +Running a decoupling simulation +------------------------------- + +We can run a decoupling simulation in the same way as any other +free energy simulation. + +First, we will update the system to use the decoupled benzene molecule. + +>>> mols.update(benzene) + +This works because we used ``as_new_molecule=False`` when creating +the merged molecule, so it kept its original molecule number. + +Next, we will create a simulation object. + +>>> d = mols.dynamics(timestep="2fs", temperature="25oC", +... schedule=schedule, lambda_value=1.0) +>>> d.run("100ps", lambda_windows=[0.0, 0.5, 1.0]) +>>> print(d.energy_trajectory()) +EnergyTrajectory( size=4 +time lambda 0.0 0.5 1.0 kinetic potential +25 1.0 2.49529e+06 -8686.04 -8895.63 1583.95 -8895.63 +50 1.0 1.54343e+06 -8750.01 -8914.34 1527.78 -8914.34 +75 1.0 2.20708e+08 -8465.13 -8872.06 1624.18 -8872.06 +100 1.0 1.02181e+11 -8534.06 -8949.38 1537.6 -8949.38 +) + +.. note:: + + We expect the energies at λ=0 to be high in this case, as the simulation + was run at λ=1, where the benzene is not interacting with the the rest + of the system, and thus free to overlap with other atoms. + +Annihilation +------------ + +Annihilation is the process of turning off all interactions involving +all of the atoms of the molecule being annihilated. Note that this will +also turn off all intramolecular interactions, so care must be taken +to use restraints to prevent the simulation exploding. + +You can create an annihilated molecule using the :func:`sire.morph.annihilate`. + +>>> benzene = sr.morph.annihilate(benzene, as_new_molecule=False) +>>> print(benzene) +Molecule( BEN:2 num_atoms=12 num_residues=1 ) + +.. note:: + + As before, we pass in ``as_new_molecule=False`` so that the resulting merged + molecule keeps the same molecule number as the original benzene. + +The annihilated benzene molecule is a merged molecule where all of the +atoms are converted to ghost atoms, and all of the intramolecular interactions +are turned off. + +>>> p = benzene.perturbation().to_openmm() +>>> print(p.changed_atoms()) + atom charge0 charge1 sigma0 sigma1 epsilon0 epsilon1 alpha0 alpha1 kappa0 kappa1 +0 C:1 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +1 C2:2 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +2 C3:3 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +3 C4:4 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +4 C5:5 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +5 C6:6 -0.13 0.0 0.348065 0.348065 0.363503 0.0 0.0 1.0 1.0 1.0 +6 H1:7 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +7 H2:8 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +8 H3:9 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +9 H4:10 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +10 H5:11 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +11 H6:12 0.13 0.0 0.257258 0.257258 0.065318 0.0 0.0 1.0 1.0 1.0 +>>> print(p.changed_bonds()) + bond length0 length1 k0 k1 +0 C2:2-C3:3 0.138719 0.138719 301905.092179 0.0 +1 C:1-C2:2 0.138719 0.138719 301905.092179 0.0 +2 C6:6-H6:12 0.108536 0.108536 332422.631707 0.0 +3 C5:5-H5:11 0.108536 0.108536 332422.631707 0.0 +4 C4:4-H4:10 0.108536 0.108536 332422.631707 0.0 +5 C3:3-H3:9 0.108536 0.108536 332422.631707 0.0 +6 C5:5-C6:6 0.138719 0.138719 301905.092179 0.0 +7 C2:2-H2:8 0.108536 0.108536 332422.631707 0.0 +8 C4:4-C5:5 0.138719 0.138719 301905.092179 0.0 +9 C:1-H1:7 0.108536 0.108536 332422.631707 0.0 +10 C:1-C6:6 0.138719 0.138719 301905.092179 0.0 +11 C3:3-C4:4 0.138719 0.138719 301905.092179 0.0 + +To annihilate the benzene molecule correctly, a custom :class:`sire.cas.LambdaSchedule` +is needed. + +The :func:`sire.morph.annihilate` function creates a suitable schedule by +default, and attaches it to the merged molecule via its ``schedule`` +property. + +>>> schedule = benzene.property("schedule") +>>> print(schedule) +LambdaSchedule( + annihilate: initial * (-λ + 1) + final * λ +) + +As before, we can view exactly how a schedule will perturb the real parameters +of a merged molecule using the +:meth:`~sire.legacy.Convert.PerturbableOpenMMMolecule.get_lever_values` +function. + +>>> df = p.get_lever_values(schedule=schedule) +>>> print(df) + clj-charge-1 clj-charge-7 clj-epsilon-1 ... angle-angle_k-5 torsion-torsion_k-1 torsion-torsion_k-3 +λ ... +0.00 -0.1300 0.1300 0.363503 ... 484.492886 1.534133 15.321516 +0.01 -0.1287 0.1287 0.359868 ... 479.647957 1.518792 15.168300 +0.02 -0.1274 0.1274 0.356233 ... 474.803028 1.503451 15.015085 +0.03 -0.1261 0.1261 0.352598 ... 469.958099 1.488109 14.861870 +0.04 -0.1248 0.1248 0.348963 ... 465.113170 1.472768 14.708655 +... ... ... ... ... ... ... ... +0.96 -0.0052 0.0052 0.014540 ... 19.379715 0.061365 0.612861 +0.97 -0.0039 0.0039 0.010905 ... 14.534787 0.046024 0.459645 +0.98 -0.0026 0.0026 0.007270 ... 9.689858 0.030683 0.306430 +0.99 -0.0013 0.0013 0.003635 ... 4.844929 0.015341 0.153215 +1.00 0.0000 0.0000 0.000000 ... 0.000000 0.000000 0.000000 +[101 rows x 14 columns] + +The key difference between the annihilation schedule and the decoupling +schedule is that the annihilation schedule linearly scales down all interactions +involving the atoms of the molecule being annihilated, rather than +only turning off the intermolecular interactions. + +Running an annihilation simulation +---------------------------------- + +We can run an annihilation simulation in the same way as any other +free energy simulation. + +First, we will update the system to use the annihilated benzene molecule. + +>>> mols.update(benzene) + +This works because we used ``as_new_molecule=False`` when creating +the merged molecule, so it kept its original molecule number. + +Next, we will create a simulation object. + +>>> d = mols.dynamics(timestep="2fs", temperature="25oC", +... schedule=schedule, lambda_value=1.0) +>>> d.run("100ps", lambda_windows=[0.0, 0.5, 1.0]) +>>> print(d.energy_trajectory()) +EnergyTrajectory( size=4 +time lambda 0.0 0.5 1.0 kinetic potential +25 1.0 2.20919e+08 3.70208e+06 -8898.02 1561.3 -8898.02 +50 1.0 2.73685e+07 1.26643e+07 -8863.57 1591.31 -8863.57 +75 1.0 2.49653e+07 1.24605e+07 -8894.69 1611.1 -8894.69 +100 1.0 1.20317e+09 1.90568e+07 -8908.07 1516.37 -8908.07 +) + +.. note:: + + We expect the energies at all values except λ=1 to be very high in this case, + as the simulation was run at λ=1, where the atoms of the benzene + are not interacting with the the rest of the system, and thus free + to overlap with other atoms, and also be too far from each other to give + sensible energies for their intramolecular interactions. + +Ideally, in the above simulation you should add positional restraints to +all atoms in benzene which gradually switch on to hold the atoms in +position as their interactions are annihilated. The end state would +represent non-interacting particles in harmonic wells, for which an +analytical solution exists to calculate the free energy of annihilation. + +While this is not covered in this tutorial, future versions of +:mod:`sire` will include tools to help with this. diff --git a/doc/source/tutorial/part07/07_residue.rst b/doc/source/tutorial/part07/07_residue.rst new file mode 100644 index 000000000..969be7526 --- /dev/null +++ b/doc/source/tutorial/part07/07_residue.rst @@ -0,0 +1,228 @@ +================= +Residue mutations +================= + +So far, perturbations have involved changing an entire molecule. +However, we can also change individual residues in a molecule. This +can be useful to, e.g. study the effect of residue mutation on a protein, +and how this could impact ligand binding or protein folding. + +Sub-structure matching +---------------------- + +To start, we need to define the sub-structure that we want to change. + +Let's first load the kigaki protein system. + +>>> import sire as sr +>>> mols = sr.load_test_files("kigaki.gro", "kigaki.top") +>>> protein = mols[0] +>>> print(protein) +Molecule( Protein:6 num_atoms=302 num_residues=19 ) +>>> print(protein.residues().names()) +[ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('ALA'), + ResName('LYS'), ResName('ILE'), ResName('LYS'), ResName('ILE'), + ResName('GLY'), ResName('ALA'), ResName('LYS'), ResName('ILE'), + ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('ALA'), + ResName('LYS'), ResName('ILE'), ResName('NH2')] + +To start with, let's mutate the first alanine residue that we find in the +protein into a lysine. First, let's select the first alanine... + +>>> ala = protein["resname ALA"][0] +>>> print(ala) +Residue( ALA:4 num_atoms=10 ) + +To mutate this into a lysine, we need to tell :mod:`sire` what a +lysine looks like. Fortunately, our protein already contains lysine +residues, so let's select on of those... + +>>> lys = protein["resname LYS"][1] +>>> print(lys) +Residue( LYS:5 num_atoms=22 ) + +.. note:: + + We have selected the second lysine residue in the protein, + as the first lysine residue is the N-terminal residue. Since + our alanine is a mid-chain residue, it makes more sense to + use a mid-chain lysine. + +Next, we need to match the alanine residue to the lysine residue, +just as we did when perturbing entire molecules. Calling +:func:`sire.morph.match` on sub-views of molecules will only match +the atoms in those views. + +>>> mapping = sr.morph.match(ala, lys, match_light_atoms=True) +>>> print(mapping) +AtomMapping( size=9, unmapped0=1, unmapped1=13 +0: MolNum(6) Atom( HA:54 ) <=> MolNum(6) Atom( HA:64 ) +1: MolNum(6) Atom( CA:53 ) <=> MolNum(6) Atom( CA:63 ) +2: MolNum(6) Atom( O:60 ) <=> MolNum(6) Atom( O:82 ) +3: MolNum(6) Atom( C:59 ) <=> MolNum(6) Atom( C:81 ) +4: MolNum(6) Atom( HB2:57 ) <=> MolNum(6) Atom( HB2:67 ) +5: MolNum(6) Atom( H:52 ) <=> MolNum(6) Atom( H:62 ) +6: MolNum(6) Atom( N:51 ) <=> MolNum(6) Atom( N:61 ) +7: MolNum(6) Atom( HB1:56 ) <=> MolNum(6) Atom( HB1:66 ) +8: MolNum(6) Atom( CB:55 ) <=> MolNum(6) Atom( CB:65 ) +) + +.. warning:: + + This used the default MCS matching algorithm built into :mod:`sire`. + This is not supported on Windows. You may want to use a different + matching algorithm, e.g. using + `Kartograf `__ + +We can see that this mapping has nicely matched the atoms in alanine +to the corresponding atoms in lysine. + +Next, we will align the lysine in the mapping onto the alanine. + +>>> mapping = mapping.align() + +And finally, we will create the merged molecule. + +>>> merged = mapping.merge(as_new_molecule=False) +>>> print(merged) +Molecule( Protein:6 num_atoms=315 num_residues=19 ) + +This has created the merged molecule as before. To see what has changed, +we can check the perturbation... + +>>> p_omm = merged.perturbation().to_openmm() +>>> print(p_omm.changed_atoms()) + atom charge0 charge1 sigma0 sigma1 epsilon0 epsilon1 alpha0 alpha1 kappa0 kappa1 +0 N:51 -0.4157 -0.3479 0.325000 0.325000 0.711280 0.711280 0.0 0.0 0.0 0.0 +1 H:52 0.2719 0.2747 0.106908 0.106908 0.065689 0.065689 0.0 0.0 0.0 0.0 +2 CA:53 0.0337 -0.2400 0.339967 0.339967 0.457730 0.457730 0.0 0.0 0.0 0.0 +3 HA:54 0.0823 0.1426 0.247135 0.247135 0.065689 0.065689 0.0 0.0 0.0 0.0 +4 CB:55 -0.1825 -0.0094 0.339967 0.339967 0.457730 0.457730 0.0 0.0 0.0 0.0 +5 HB1:56 0.0603 0.0362 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +6 HB2:57 0.0603 0.0362 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +7 HB3:58 0.0603 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +8 C:59 0.5973 0.7341 0.339967 0.339967 0.359824 0.359824 0.0 0.0 0.0 0.0 +9 O:60 -0.5679 -0.5894 0.295992 0.295992 0.878640 0.878640 0.0 0.0 0.0 0.0 +10 Xxx:303 0.0000 0.0187 0.339967 0.339967 0.000000 0.457730 1.0 0.0 1.0 1.0 +11 Xxx:304 0.0000 0.0103 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +12 Xxx:305 0.0000 0.0103 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +13 Xxx:306 0.0000 -0.0479 0.339967 0.339967 0.000000 0.457730 1.0 0.0 1.0 1.0 +14 Xxx:307 0.0000 0.0621 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +15 Xxx:308 0.0000 0.0621 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +16 Xxx:309 0.0000 -0.0143 0.339967 0.339967 0.000000 0.457730 1.0 0.0 1.0 1.0 +17 Xxx:310 0.0000 0.1135 0.195998 0.195998 0.000000 0.065689 1.0 0.0 1.0 1.0 +18 Xxx:311 0.0000 0.1135 0.195998 0.195998 0.000000 0.065689 1.0 0.0 1.0 1.0 +19 Xxx:312 0.0000 -0.3854 0.325000 0.325000 0.000000 0.711280 1.0 0.0 1.0 1.0 +20 Xxx:313 0.0000 0.3400 0.106908 0.106908 0.000000 0.065689 1.0 0.0 1.0 1.0 +21 Xxx:314 0.0000 0.3400 0.106908 0.106908 0.000000 0.065689 1.0 0.0 1.0 1.0 +22 Xxx:315 0.0000 0.3400 0.106908 0.106908 0.000000 0.065689 1.0 0.0 1.0 1.0 + +This shows how the atoms in alanine have been perturbed into the equivalent +atoms in lysine, plus how a number of ghost atoms have been added that +correspond to the additional atoms in lysine. In addition, the HB3 atom +of alanine is turned into a ghost. + +One-stop function +----------------- + +Just as before, the entire set of steps above can be performed in one +step via the :func:`sire.morph.merge` function. + +>>> merged = sr.morph.merge(ala, lys) +>>> print(merged) +Molecule( Protein:3627 num_atoms=315 num_residues=19 ) +>>> p_omm = merged.perturbation().to_openmm() +>>> print(p_omm.changed_atoms()) + atom charge0 charge1 sigma0 sigma1 epsilon0 epsilon1 alpha0 alpha1 kappa0 kappa1 +0 N:51 -0.4157 -0.3479 0.325000 0.325000 0.711280 0.711280 0.0 0.0 0.0 0.0 +1 H:52 0.2719 0.2747 0.106908 0.106908 0.065689 0.065689 0.0 0.0 0.0 0.0 +2 CA:53 0.0337 -0.2400 0.339967 0.339967 0.457730 0.457730 0.0 0.0 0.0 0.0 +3 HA:54 0.0823 0.1426 0.247135 0.247135 0.065689 0.065689 0.0 0.0 0.0 0.0 +4 CB:55 -0.1825 -0.0094 0.339967 0.339967 0.457730 0.457730 0.0 0.0 0.0 0.0 +5 HB1:56 0.0603 0.0362 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +6 HB2:57 0.0603 0.0362 0.264953 0.264953 0.065689 0.065689 0.0 0.0 0.0 0.0 +7 HB3:58 0.0603 0.0000 0.264953 0.264953 0.065689 0.000000 0.0 1.0 1.0 1.0 +8 C:59 0.5973 0.7341 0.339967 0.339967 0.359824 0.359824 0.0 0.0 0.0 0.0 +9 O:60 -0.5679 -0.5894 0.295992 0.295992 0.878640 0.878640 0.0 0.0 0.0 0.0 +10 Xxx:303 0.0000 0.0187 0.339967 0.339967 0.000000 0.457730 1.0 0.0 1.0 1.0 +11 Xxx:304 0.0000 0.0103 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +12 Xxx:305 0.0000 0.0103 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +13 Xxx:306 0.0000 -0.0479 0.339967 0.339967 0.000000 0.457730 1.0 0.0 1.0 1.0 +14 Xxx:307 0.0000 0.0621 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +15 Xxx:308 0.0000 0.0621 0.264953 0.264953 0.000000 0.065689 1.0 0.0 1.0 1.0 +16 Xxx:309 0.0000 -0.0143 0.339967 0.339967 0.000000 0.457730 1.0 0.0 1.0 1.0 +17 Xxx:310 0.0000 0.1135 0.195998 0.195998 0.000000 0.065689 1.0 0.0 1.0 1.0 +18 Xxx:311 0.0000 0.1135 0.195998 0.195998 0.000000 0.065689 1.0 0.0 1.0 1.0 +19 Xxx:312 0.0000 -0.3854 0.325000 0.325000 0.000000 0.711280 1.0 0.0 1.0 1.0 +20 Xxx:313 0.0000 0.3400 0.106908 0.106908 0.000000 0.065689 1.0 0.0 1.0 1.0 +21 Xxx:314 0.0000 0.3400 0.106908 0.106908 0.000000 0.065689 1.0 0.0 1.0 1.0 +22 Xxx:315 0.0000 0.3400 0.106908 0.106908 0.000000 0.065689 1.0 0.0 1.0 1.0 + +This merged molecule can be used in a free energy simulation in the same +way as any other merged molecule. + +Protein Mutation +---------------- + +Just as for other merged molecules, we can extract the end states using +the :func:`sire.morph.extract_reference` and +:func:`sire.morph.extract_perturbed` functions. + +>>> ref_prot = sr.morph.extract_reference(merged) +>>> pert_prot = sr.morph.extract_perturbed(merged) +>>> print(ref_prot.residues().names()) +[ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('ALA'), + ResName('LYS'), ResName('ILE'), ResName('LYS'), ResName('ILE'), + ResName('GLY'), ResName('ALA'), ResName('LYS'), ResName('ILE'), + ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('ALA'), + ResName('LYS'), ResName('ILE'), ResName('NH2')] +>>> print(pert_prot.residues().names()) +[ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('LYS'), + ResName('LYS'), ResName('ILE'), ResName('LYS'), ResName('ILE'), + ResName('GLY'), ResName('ALA'), ResName('LYS'), ResName('ILE'), + ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('ALA'), + ResName('LYS'), ResName('ILE'), ResName('NH2')] + +This shows that the first alanine residue has been mutated into a +lysine residue. + +Interestingly, if you are only interested in mutation, and are not +interested in the merged molecule, then mutation is just the process +of performing a merge, and then extracting the perturbed end state. + +To make this easier, there is a one-stop function for this, +:func:`sire.morph.mutate`. + +>>> mutated_protein = sr.morph.mutate(ala, lys) +>>> print(mutated_protein.residues().names()) +[ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('LYS'), + ResName('LYS'), ResName('ILE'), ResName('LYS'), ResName('ILE'), + ResName('GLY'), ResName('ALA'), ResName('LYS'), ResName('ILE'), + ResName('LYS'), ResName('ILE'), ResName('GLY'), ResName('ALA'), + ResName('LYS'), ResName('ILE'), ResName('NH2')] + +.. warning:: + + By default this uses the (potentially slow) internal MCS matching + algorithm (which also is not supported on Windows). You may want to + use a different matching algorithm, either by passing in the + dictionary of the mapping you want to use via the ``match`` + argument, or by using `Kartograf `__. + The ``match`` argument works identically in this function as it + does in the ``merge`` and ``match`` functions. + +In this case, we copied and pasted the lysine residue from one part of the +protein over the alanine. But, you can copy and paste in this way between +different molecules. For example, you could have a template library of +different residues that you could use for mutation. + +Assuming ``template["lys"]`` contained your template for a lysine residue, +then you could have run the following; + +>>> mutated_protein = sr.morph.mutate(ala, template["lys"]) + +This works for any kind of molecules - not just proteins. In future +versions of :mod:`sire` we will add functionality to make it easier to +manage libraries of templates, and to perform molecular editing by +copying and pasting between molecules, and between fragments constructed +via, e.g. smiles strings. diff --git a/doc/source/tutorial/part07/images/07_02_01.jpg b/doc/source/tutorial/part07/images/07_02_01.jpg new file mode 100644 index 000000000..e7da57430 Binary files /dev/null and b/doc/source/tutorial/part07/images/07_02_01.jpg differ diff --git a/doc/source/tutorial/part07/images/07_02_02.jpg b/doc/source/tutorial/part07/images/07_02_02.jpg new file mode 100644 index 000000000..07a40f4c0 Binary files /dev/null and b/doc/source/tutorial/part07/images/07_02_02.jpg differ diff --git a/doc/source/tutorial/part07/images/07_03_01.jpg b/doc/source/tutorial/part07/images/07_03_01.jpg new file mode 100644 index 000000000..4bcf7f6ec Binary files /dev/null and b/doc/source/tutorial/part07/images/07_03_01.jpg differ diff --git a/doc/source/tutorial/part07/images/07_04_01.jpg b/doc/source/tutorial/part07/images/07_04_01.jpg new file mode 100644 index 000000000..484417415 Binary files /dev/null and b/doc/source/tutorial/part07/images/07_04_01.jpg differ diff --git a/doc/source/tutorial/part07/images/07_04_02.jpg b/doc/source/tutorial/part07/images/07_04_02.jpg new file mode 100644 index 000000000..eeae985f6 Binary files /dev/null and b/doc/source/tutorial/part07/images/07_04_02.jpg differ diff --git a/doc/source/tutorial/part07/images/07_04_03.jpg b/doc/source/tutorial/part07/images/07_04_03.jpg new file mode 100644 index 000000000..edbb9dd8e Binary files /dev/null and b/doc/source/tutorial/part07/images/07_04_03.jpg differ diff --git a/doc/source/tutorial/part07/images/07_06_01.jpg b/doc/source/tutorial/part07/images/07_06_01.jpg new file mode 100644 index 000000000..43fdd5fc3 Binary files /dev/null and b/doc/source/tutorial/part07/images/07_06_01.jpg differ diff --git a/requirements_bss.txt b/requirements_bss.txt index aa5d60ec7..98a166778 100644 --- a/requirements_bss.txt +++ b/requirements_bss.txt @@ -14,6 +14,10 @@ openmmtools >= 0.21.5 ambertools >= 22 ; sys_platform != "win32" gromacs ; sys_platform != "win32" +# kartograf on Windows pulls in an openfe that has an old / incompatble +# ambertools +kartograf >= 1.0.0 ; sys_platform != "win32" + # The following are actual BioSimSpace run-time requirements. Please update # this list as new requirements are added. configargparse diff --git a/requirements_build.txt b/requirements_build.txt index c2b7173ea..a9ea6f100 100644 --- a/requirements_build.txt +++ b/requirements_build.txt @@ -19,4 +19,6 @@ rdkit-dev >=2023.0.0 # These packages are needed to compile # the SireGemmi plugin gemmi >=0.6.4 -pybind11 + +pybind11 ==2.11.1 ; sys_platform == "win32" +pybind11 sys_platform != "win32" diff --git a/requirements_host.txt b/requirements_host.txt index 13cd912df..9b0e2a797 100644 --- a/requirements_host.txt +++ b/requirements_host.txt @@ -12,6 +12,9 @@ qt-main rich tbb tbb-devel -gemmi >=0.6.4 rdkit >=2023.0.0 +gemmi >=0.6.4 +# kartograf on Windows pulls in an openfe that has an old / incompatble +# ambertools +kartograf >= 1.0.0 ; sys_platform != "win32" diff --git a/requirements_test.txt b/requirements_test.txt index dbd4a6cdd..b8800e418 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -3,3 +3,7 @@ rdkit >=2023.0.0 gemmi >=0.6.4 + +# kartograf on Windows pulls in an openfe that has an old / incompatble +# ambertools +kartograf >= 1.0.0 ; sys_platform != "win32" diff --git a/src/sire/__init__.py b/src/sire/__init__.py index 631ae5930..7422391a6 100644 --- a/src/sire/__init__.py +++ b/src/sire/__init__.py @@ -45,6 +45,7 @@ "set_max_num_threads", "smiles", "smarts", + "sqrt", "supported_formats", "tutorial_url", "u", @@ -121,6 +122,16 @@ def _fix_openmm_path(): _fix_openmm_path() +def sqrt(x): + """Return the square root of the passed value""" + if hasattr(x, "sqrt"): + return x.sqrt() + else: + import math + + return math.sqrt(x) + + def u(unit): """ Return a sire unit created from the passed expression. If this is a diff --git a/src/sire/_match.py b/src/sire/_match.py index c1405a7a7..de83f9003 100644 --- a/src/sire/_match.py +++ b/src/sire/_match.py @@ -1,21 +1,135 @@ __all__ = ["match_atoms"] -def match_atoms(mol0, mol1, match_light_atoms=False, map0=None, map1=None): +def match_atoms( + mol0, mol1, match=None, prematch=None, match_light_atoms=False, map0=None, map1=None +): """ Perform a simple match that tries to identify the mapping from - atoms in 'mol0' to the atoms in 'mol1'. + atoms in 'mol0' to the atoms in 'mol1'. This uses the `AtomMCSMatcher` + to match the atoms, using the passed `prematch` argument. + + However, if the `match` argument is provided, this will be used + as the atom mapping directly (it can either be a dictionary mapping + atom identifiers, or an `AtomMatcher` object). + + Parameters + ---------- + mol0 : Molecule view + The reference state molecule (or part of molecule) + mol1 : Molecule view + The perturbed state molecule (or part of molecule) + match : dict, AtomMatcher, optional + The atom matcher to use to match atoms. If this is a dictionary + of atom identifiers, then this will be passed to a + `AtomIDMatcher` object. If this is an `AtomMatcher` object, then + this will be used directly. + prematch : dict, AtomMatcher, optional + The atom matcher to use to prematch atoms. If `match` is not + supplied, then this will be used as the `prematch` argument + to the `AtomMCSMatcher` used to find the maximum common subgraph + match. + match_light_atoms : bool, optional + Whether to match light atoms (i.e. hydrogen atoms) if using the + default `AtomMCSMatcher`. Default is False. + map0 : dict, optional + Property map to find properties in `mol0` + map1 : dict, optional + Property map to find properties in `mol1` + + Returns + ------- + AtomMapping + The atom mapping between the two molecules (or parts of molecules) """ from .mol import AtomMapping - from .legacy.Mol import AtomMCSMatcher + from .legacy.Mol import AtomMCSMatcher, AtomMatcher from .base import create_map + if len(mol0.molecules()) != 1 or len(mol1.molecules()) != 1: + raise ValueError("You cannot match multiple molecules at once") + + from .system import System + + if System.is_system(mol0): + mol0 = mol0[0] + + if System.is_system(mol1): + mol1 = mol1[0] + map0 = create_map(map0) map1 = create_map(map1) - matcher = AtomMCSMatcher( - match_light_atoms=match_light_atoms, verbose=False - ) + if match is not None: + if prematch is not None: + raise ValueError("You cannot provide both a `match` and a `prematch`") + + if not isinstance(match, AtomMatcher): + from .legacy.Mol import AtomIDMatcher + + # create a dictionary of atom identifiers + if isinstance(match, dict): + from . import atomid + + matches = {} + + for atom0, atom1 in match.items(): + if isinstance(atom0, int): + atom0 = atomid(idx=atom0) + elif isinstance(atom0, str): + atom0 = atomid(name=atom0) + + if isinstance(atom1, int): + atom1 = atomid(idx=atom1) + elif isinstance(atom1, str): + atom1 = atomid(name=atom1) + + matches[atom0] = atom1 + + match = matches + + elif "KartografAtomMapper" in str(match.__class__): + # use Kartograf to get the mapping - convert to RDKit then Kartograf + from kartograf.atom_aligner import align_mol_shape + from kartograf import KartografAtomMapper, SmallMoleculeComponent + + if not isinstance(match, KartografAtomMapper): + raise TypeError("match must be a KartografAtomMapper") + + from .convert import to + from . import atomid + + rd_mol0 = to(mol0, "rdkit") + rd_mol1 = to(mol1, "rdkit") + + k_mol0, k_mol1 = [ + SmallMoleculeComponent.from_rdkit(m) for m in [rd_mol0, rd_mol1] + ] + + k_0mol1 = align_mol_shape(k_mol1, ref_mol=k_mol0) + + mapping = next(match.suggest_mappings(k_mol0, k_0mol1)) + + match = {} + + for k, v in mapping.componentA_to_componentB.items(): + match[atomid(idx=k)] = atomid(idx=v) + + matcher = AtomIDMatcher(match) + else: + matcher = match + + elif prematch is not None: + if not isinstance(prematch, AtomMatcher): + from .legacy.Mol import AtomIDMatcher + + prematch = AtomIDMatcher(prematch) + + matcher = AtomMCSMatcher( + prematcher=prematch, match_light_atoms=match_light_atoms, verbose=False + ) + else: + matcher = AtomMCSMatcher(match_light_atoms=match_light_atoms, verbose=False) m = matcher.match(mol0, map0, mol1, map1) @@ -27,5 +141,10 @@ def match_atoms(mol0, mol1, match_light_atoms=False, map0=None, map1=None): atoms1.append(atom1.value()) return AtomMapping( - mol0.molecule().atoms()[atoms0], mol1.molecule().atoms()[atoms1] + mol0.atoms(), + mol1.atoms(), + mol0.molecule().atoms()[atoms0], + mol1.molecule().atoms()[atoms1], + map0, + map1, ) diff --git a/src/sire/_pythonize.py b/src/sire/_pythonize.py index aa0ddc86d..ec6f4d3c7 100644 --- a/src/sire/_pythonize.py +++ b/src/sire/_pythonize.py @@ -193,13 +193,13 @@ def _load_new_api_modules(delete_old: bool = True, is_base: bool = False): # call Pythonize on all of the new modules from .legacy import ( # noqa: F401 Base, + Mol, Move, IO, System, Squire, MM, FF, - Mol, Analysis, CAS, Cluster, diff --git a/src/sire/cas/__init__.py b/src/sire/cas/__init__.py index 8de0212a0..59ebd8f14 100644 --- a/src/sire/cas/__init__.py +++ b/src/sire/cas/__init__.py @@ -22,10 +22,10 @@ def _fix_lambdaschedule(): try: LambdaSchedule.__orig__get_lever_values = LambdaSchedule.getLeverValues + LambdaSchedule.set_default_equation = LambdaSchedule.setDefaultStageEquation except AttributeError: - LambdaSchedule.__orig__get_lever_values = ( - LambdaSchedule.get_lever_values - ) + LambdaSchedule.__orig__get_lever_values = LambdaSchedule.get_lever_values + LambdaSchedule.set_default_equation = LambdaSchedule.set_default_stage_equation def get_lever_values( obj, diff --git a/src/sire/mol/_dynamics.py b/src/sire/mol/_dynamics.py index 824d06458..71c98b52c 100644 --- a/src/sire/mol/_dynamics.py +++ b/src/sire/mol/_dynamics.py @@ -969,6 +969,15 @@ class NeedsMinimiseError(Exception): self.run(**orig_args) return + def to_xml(self, f=None): + """ + Save the current state of the dynamics to XML. + This is mostly used for debugging. This will return the + XML string if 'f' is None. Otherwise it will write the + XML to 'f' (either a filename, or a FILE object) + """ + return self._omm_mols.to_xml(f=f) + def commit(self, return_as_system: bool = False): if self.is_null(): return @@ -1528,6 +1537,15 @@ def energy_trajectory(self, to_pandas: bool = False, to_alchemlyb: bool = False) else: return t + def to_xml(self, f=None): + """ + Save the current state of the dynamics to XML. + This is mostly used for debugging. This will return the + XML string if 'f' is None. Otherwise it will write the + XML to 'f' (either a filename, or a FILE object) + """ + return self._d.to_xml(f=f) + def commit(self, return_as_system: bool = False): """ Commit the dynamics and return the molecules after the simulation. diff --git a/src/sire/mol/_trajectory.py b/src/sire/mol/_trajectory.py index b2dcdebc1..37ccac992 100644 --- a/src/sire/mol/_trajectory.py +++ b/src/sire/mol/_trajectory.py @@ -67,9 +67,7 @@ def __init__( self._map = create_map(map) self._view = view - self._values = list( - range(0, max(1, self._view.num_frames(self._map))) - ) + self._values = list(range(0, max(1, self._view.num_frames(self._map)))) self._times = None self._iter = None self._frame = None @@ -125,9 +123,7 @@ def __init__( find_all=False, ) - self._aligner = TrajectoryAligner( - align, reference, map=self._map - ) + self._aligner = TrajectoryAligner(align, reference, map=self._map) elif wrap or (smooth != 1): self._aligner = TrajectoryAligner( self._view.evaluate().center(), @@ -401,9 +397,7 @@ def energies(self, obj1=None, to_pandas=True, map=None): for v in self.first(): colnames.append(colname(v)) - forcefields.append( - create_forcefield(v, obj1_mols, map=map) - ) + forcefields.append(create_forcefield(v, obj1_mols, map=map)) else: for v in self.first(): colnames.append(colname(v)) @@ -427,9 +421,7 @@ def energies(self, obj1=None, to_pandas=True, map=None): components = {} - ff_nrgs = calculate_trajectory_energies( - forcefields, self._values, map=map - ) + ff_nrgs = calculate_trajectory_energies(forcefields, self._values, map=map) for ff_idx in range(0, len(forcefields)): nrg = ff_nrgs[ff_idx][0] @@ -449,9 +441,7 @@ def energies(self, obj1=None, to_pandas=True, map=None): for i in range(0, nframes): for ff_idx in range(0, len(forcefields)): nrg = ff_nrgs[ff_idx][i] - components[colname(colnames[ff_idx], "total")][ - i - ] = nrg.to_default() + components[colname(colnames[ff_idx], "total")][i] = nrg.to_default() for key in nrg.components().keys(): try: @@ -649,9 +639,7 @@ def _simple_measures(self, to_pandas): colnames.append(colname(view)) columns.append(np.zeros(nframes, dtype=float)) - with ProgressBar( - total=nframes, text="Looping through frames" - ) as progress: + with ProgressBar(total=nframes, text="Looping through frames") as progress: for idx, frame in enumerate(self.__iter__()): for i, measure in enumerate(frame.measures(map=self._map)): columns[i][idx] = measure.to_default() @@ -659,9 +647,7 @@ def _simple_measures(self, to_pandas): if measure_unit is None: if not measure.is_zero(): - measure_unit = ( - measure.get_default().unit_string() - ) + measure_unit = measure.get_default().unit_string() if time_unit is None: time = frame.frame_time() @@ -674,9 +660,7 @@ def _simple_measures(self, to_pandas): colnames.append(colname(self._view)) column = np.zeros(nframes, dtype=float) - with ProgressBar( - total=nframes, text="Looping through frames" - ) as progress: + with ProgressBar(total=nframes, text="Looping through frames") as progress: for idx, frame in enumerate(self.__iter__()): measure = frame.measure(map=self._map) column[idx] = measure.to_default() @@ -761,9 +745,7 @@ def _custom_measures(self, func, to_pandas): from ..base import ProgressBar - with ProgressBar( - total=nframes, text="Looping through frames" - ) as progress: + with ProgressBar(total=nframes, text="Looping through frames") as progress: for idx, frame in enumerate(self.__iter__()): for i, f in enumerate(func.values()): measure = f(frame) @@ -857,9 +839,7 @@ def apply(self, func, *args, **kwargs): if str(func) == func: # we calling a named function - with ProgressBar( - total=nframes, text="Looping through frames" - ) as progress: + with ProgressBar(total=nframes, text="Looping through frames") as progress: for i in range(0, nframes): obj = self.__getitem__(i).current() result.append(getattr(obj, func)(*args, **kwargs)) @@ -867,9 +847,7 @@ def apply(self, func, *args, **kwargs): else: # we have been passed the function to call - with ProgressBar( - total=nframes, text="Looping through frames" - ) as progress: + with ProgressBar(total=nframes, text="Looping through frames") as progress: for i in range(0, nframes): obj = self.__getitem__(i).current() result.append(func(obj, *args, **kwargs)) @@ -944,10 +922,7 @@ def rmsd( elif align is None: # auto-align only for smaller systems - if ( - hasattr(reference, "molecules") - and len(reference.molecules()) > 100 - ): + if hasattr(reference, "molecules") and len(reference.molecules()) > 100: align = False else: align = True diff --git a/src/sire/morph/CMakeLists.txt b/src/sire/morph/CMakeLists.txt index d0ce6a852..11ea25882 100644 --- a/src/sire/morph/CMakeLists.txt +++ b/src/sire/morph/CMakeLists.txt @@ -8,8 +8,11 @@ set ( SCRIPTS __init__.py _alchemy.py + _decouple.py _ghost_atoms.py _hmr.py + _merge.py + _mutate.py _pertfile.py _perturbation.py _repex.py diff --git a/src/sire/morph/__init__.py b/src/sire/morph/__init__.py index d0b26373d..e5931ee5e 100644 --- a/src/sire/morph/__init__.py +++ b/src/sire/morph/__init__.py @@ -8,6 +8,11 @@ "extract_perturbed", "link_to_reference", "link_to_perturbed", + "annihilate", + "decouple", + "match", + "merge", + "mutate", "zero_ghost_bonds", "zero_ghost_angles", "zero_ghost_torsions", @@ -25,6 +30,9 @@ zero_ghost_torsions, ) + +from .. import match_atoms as match + from ._ghost_atoms import shrink_ghost_atoms from ._repex import replica_exchange @@ -34,3 +42,9 @@ from ._alchemy import to_alchemlyb from ._pertfile import create_from_pertfile + +from ._merge import merge + +from ._mutate import mutate + +from ._decouple import annihilate, decouple diff --git a/src/sire/morph/_decouple.py b/src/sire/morph/_decouple.py new file mode 100644 index 000000000..d7ca2e98c --- /dev/null +++ b/src/sire/morph/_decouple.py @@ -0,0 +1,252 @@ +__all__ = ["annihilate", "decouple"] + + +def annihilate(mol, as_new_molecule: bool = True, map=None): + """ + Return a merged molecule that represents the perturbation that + completely annihilates the molecule. The returned merged molecule + will be suitable for using in a double-annihilation free energy + simulation, e.g. to calculate absolute binding free energies. + + Parameters + ---------- + mol : Molecule view + The molecule (or part of molecule) to annihilate. + This will only annihilate the atoms in this molecule view. + Normally, you would want to pass in the entire molecule. + as_new_molecule : bool, optional + Whether to return the merged molecule as a new molecule, + or to assign a new molecule number to the result. Default is True. + map : dict, optional + Property map to assign properties in the returned, + merged molecule, plus to find the properties that will be + annihilated. + + Returns + ------- + Molecule + The merged molecule representing the annihilation perturbation + """ + try: + # make sure we have only the reference state + mol = mol.perturbation().extract_reference(remove_ghosts=True) + except Exception: + pass + + from ..base import create_map + from ..mm import LJParameter + from ..mol import Element + from ..units import kcal_per_mol, mod_electron, g_per_mol + + map = create_map(map) + + c = mol.cursor() + c_mol = c.molecule() + + c["is_perturbable"] = True + + has_key = {} + + for key in [ + "charge", + "LJ", + "bond", + "angle", + "dihedral", + "improper", + "forcefield", + "intrascale", + "mass", + "element", + "atomtype", + "ambertype", + "connectivity", + ]: + key = map[key].source() + + if key in c: + c_mol[f"{key}0"] = c_mol[key] + c_mol[f"{key}1"] = c_mol[key] + + has_key[key] = True + + if key != "connectivity": + del c_mol[key] + else: + has_key[key] = False + + lj_prop = map["LJ"].source() + chg_prop = map["charge"].source() + elem_prop = map["element"].source() + ambtype_prop = map["ambertype"].source() + atomtype_prop = map["atomtype"].source() + mass_prop = map["mass"].source() + + # destroy all of the atoms + for atom in c.atoms(): + lj = atom[f"{lj_prop}0"] + + atom[f"{lj_prop}1"] = LJParameter(lj.sigma(), 0.0 * kcal_per_mol) + atom[f"{chg_prop}1"] = 0 * mod_electron + + if has_key[elem_prop]: + atom[f"{elem_prop}1"] = Element(0) + + if has_key[ambtype_prop]: + atom[f"{ambtype_prop}1"] = "Xx" + + if has_key[atomtype_prop]: + atom[f"{atomtype_prop}1"] = "Xx" + + if has_key[mass_prop]: + atom[f"{mass_prop}1"] = 0.0 * g_per_mol + + # now remove all of the bonds, angles, dihedrals, impropers + for key in ["bond", "angle", "dihedral", "improper"]: + key = map[key].source() + + if has_key[key]: + p = c[f"{key}1"] + p.clear() + c[f"{key}1"] = p + + # now scale the nbpairs to zero, as we can't have any + # 1-4 interactions when there are no dihedrals... + sclkey = map["intrascale"].source() + if has_key[sclkey]: + from ..legacy.MM import CLJScaleFactor + + nbscl = c[f"{sclkey}1"] + nbscl.set_all(CLJScaleFactor(0, 0)) + c[f"{sclkey}1"] = nbscl + + mol = c_mol.commit() + + c_mol["molecule0"] = mol.perturbation().extract_reference(remove_ghosts=True) + c_mol["molecule1"] = mol.perturbation().extract_perturbed(remove_ghosts=True) + + if "parameters" in c_mol: + del c_mol["parameters"] + + if "amberparams" in c_mol: + del c_mol["amberparams"] + + if as_new_molecule: + c_mol.renumber() + + # need to add a LambdaSchedule that could be used to decouple + # the molecule + from ..cas import LambdaSchedule + + # we decouple via a standard morph which does not scale the + # intramolecular terms + c_mol["schedule"] = LambdaSchedule.standard_annihilate( + perturbed_is_annihilated=True + ) + + mol = c_mol.commit().perturbation().link_to_reference() + + return mol + + +def decouple(mol, as_new_molecule: bool = True, map=None): + """ + Return a merged molecule that represents the perturbation that + completely decouples the molecule. The returned merged molecule + will be suitable for using in a double-decoupling free energy + simulation, e.g. to calculate absolute binding free energies. + + Parameters + ---------- + mol : Molecule view + The molecule (or part of molecule) to decouple. + This will only decouple the atoms in this molecule view. + Normally, you would want to pass in the entire molecule. + as_new_molecule : bool, optional + Whether to return the merged molecule as a new molecule, + or to assign a new molecule number to the result. Default is True. + map : dict, optional + Property map to assign properties in the returned, + merged molecule, plus to find the properties that will be + decoupled. + + Returns + ------- + Molecule + The merged molecule representing the decoupling perturbation + """ + try: + # make sure we have only the reference state + mol = mol.perturbation().extract_reference(remove_ghosts=True) + except Exception: + pass + + from ..base import create_map + from ..mm import LJParameter + from ..units import kcal_per_mol, mod_electron + + map = create_map(map) + + c = mol.cursor() + + c_mol = c.molecule() + c_mol["is_perturbable"] = True + + for key in [ + "charge", + "LJ", + "bond", + "angle", + "dihedral", + "improper", + "forcefield", + "intrascale", + "mass", + "element", + "atomtype", + "ambertype", + "connectivity", + ]: + key = map[key].source() + + if key in c: + c_mol[f"{key}0"] = c_mol[key] + c_mol[f"{key}1"] = c_mol[key] + + if key != "connectivity": + del c_mol[key] + + lj_prop = map["LJ"].source() + chg_prop = map["charge"].source() + + for atom in c.atoms(): + lj = atom[f"{lj_prop}0"] + + atom[f"{lj_prop}1"] = LJParameter(lj.sigma(), 0.0 * kcal_per_mol) + atom[f"{chg_prop}1"] = 0 * mod_electron + + mol = c_mol.commit() + + c_mol["molecule0"] = mol.perturbation().extract_reference(remove_ghosts=True) + c_mol["molecule1"] = mol.perturbation().extract_perturbed(remove_ghosts=True) + + if "parameters" in c_mol: + del c_mol["parameters"] + + if "amberparams" in c_mol: + del c_mol["amberparams"] + + if as_new_molecule: + c_mol.renumber() + + # need to add a LambdaSchedule that could be used to decouple + # the molecule + from ..cas import LambdaSchedule + + # we decouple via a standard morph which does not scale the + # intramolecular terms + c_mol["schedule"] = LambdaSchedule.standard_decouple(perturbed_is_decoupled=True) + + mol = c_mol.commit().perturbation().link_to_reference() + + return mol diff --git a/src/sire/morph/_merge.py b/src/sire/morph/_merge.py new file mode 100644 index 000000000..b31383b29 --- /dev/null +++ b/src/sire/morph/_merge.py @@ -0,0 +1,112 @@ +__all__ = ["merge"] + + +from ..mol import AtomMapping as _AtomMapping + + +def _merge(mapping: _AtomMapping, as_new_molecule: bool = True, map=None): + """ + Merge the atoms in this mapping and return as a single merged + (perturbable) molecule. This function will conduct a merge and + return a perturbable molecule such that it is equivalent to + `mol0` at the reference state (lambda=0) and equivalent to `mol1` + at the perturbed state (lambda=1). + + Parameters + ---------- + + as_new_molecule : bool, optional + If True, the merged molecule will be assigned a new molecule + number and treated as a new molecule. If False, the merged + molecule will use the molecule number of the reference molecule. + map : dict, optional + Property map to assign properties in the returned, + merged molecule. + + Returns + ------- + Molecule + The merged molecule + """ + from ..legacy.System import merge as _merge_mols + from ..base import create_map + + map = create_map(map) + + # now align the perturbed state onto the reference state, + # so that any added atoms have roughly the right coordinates + aligned_mapping = mapping.align() + + mol = _merge_mols(aligned_mapping, as_new_molecule=as_new_molecule, map=map) + + return mol.perturbation().link_to_reference() + + +def merge(mol0, mol1, match=None, prematch=None, map=None, map0=None, map1=None): + """ + Merge together the atoms in 'mol0' and 'mol1' and return as a single + merged (perturbable) molecule. This function will conduct a merge + and return a perturbable molecule such that it is equivalent to + `mol0` at the reference state (lambda=0) and equivalent to `mol1` at + the perturbed state (lambda=1). + + The `sr.morph.match_atoms` function will be called with the passed + `match` and `prematch` arguments to determine the atom mapping between + the two molecules. + + Parameters + ---------- + mol0 : Molecule view + The reference state molecule (or part of molecule) + mol1 : Molecule view + The perturbed state molecule (or part of molecule) + match : dict, AtomMapping, optional + If provided, this will be passed as the `match` argument + to `sr.morph.match_atoms`, to aid in the atom mapping. + prematch : dict, AtomMapping, optional + If provided, this will be passed as the `prematch` argument + to `sr.morph.match_atoms`, to aid in the atom mapping. + map : dict, optional + Property map to assign properties in the returned, + merged molecule. + map0 : dict, optional + Property map to find properties in `mol0` + map1 : dict, optional + Property map to find properties in `mol1` + + Returns + ------- + Molecule + The merged molecule + """ + from ..base import create_map + + map = create_map(map) + + if map0 is None: + map0 = map + else: + map0 = create_map(map, map0) + + if map1 is None: + map1 = map + else: + map1 = create_map(map, map1) + + from . import match as _match + + mapping = _match( + mol0=mol0, + mol1=mol1, + match=match, + prematch=prematch, + match_light_atoms=True, + map0=map0, + map1=map1, + ) + + return mapping.merge(as_new_molecule=True, map=map) + + +if not hasattr(_AtomMapping, "merge"): + _AtomMapping.merge = _merge diff --git a/src/sire/morph/_mutate.py b/src/sire/morph/_mutate.py new file mode 100644 index 000000000..5613b1bed --- /dev/null +++ b/src/sire/morph/_mutate.py @@ -0,0 +1,103 @@ +__all__ = ["mutate"] + + +from ..mol import AtomMapping as _AtomMapping + + +def _mutate(mapping: _AtomMapping, as_new_molecule: bool = True, map=None): + """ + Mutate the reference atoms in this mapping to the perturbed atoms, + returning the mutated (new) molecule. + + This is equivalent to calling `merge` and then extracting the + perturbed state from the returned merged molecule. + + This function is most useful for mutating parts of molecules, + e.g. calling this on a mapping of two residues would mutate + one residue into another within the larger molecule containing + the reference mapping. This can be used for mutating residues + in proteins, or for copying and pasting parts of one molecule + into another. + + Parameters + ---------- + as_new_molecule : bool, optional + Whether to return the mutated molecule as a new molecule, + or to mutate the original molecule in place. Default is True. + map : dict, optional + Property map to assign properties in the returned, + mutated molecule. + + Returns + ------- + Molecule + The mutated molecule + """ + return ( + mapping.merge(as_new_molecule=as_new_molecule, map=map) + .perturbation() + .extract_perturbed(remove_ghosts=True) + ) + + +def mutate(mol0, mol1, match=None, prematch=None, map=None, map0=None, map1=None): + """ + Mutate `mol0` to `mol1`, returning the mutated (new) molecule. + This is equivalent to calling `merge` on the two molecules (or + parts of molecules) and then extracting the perturbed state. + + This function is most useful for mutating parts of molecules, + e.g. passing in two residues as `mol0` and `mol1` would mutate + that residue to the other within the larger molecule containing + `mol0`. This can be used for mutating residues in proteins, or + for copying and pasting parts of one molecule into another. + + Parameters + ---------- + mol0 : Molecule view + The molecule (or part of molecule) that will be mutated. + mol1 : Molecule view + The molecule (or part of molecule) that will be mutated to. + This will replace the atoms in `mol0`. + match : dict, AtomMatcher, optional + If provided, this will be passed as the `match` argument + to `sr.morph.match_atoms`, to aid in the atom mapping. + prematch : dict, AtomMatcher, optional + If provided, this will be passed as the `prematch` argument + to `sr.morph.match_atoms`, to aid in the atom mapping. + map : dict, optional + Property map to assign properties in the returned, + mutated molecule. + map0 : dict, optional + Property map to find properties in `mol0` + map1 : dict, optional + Property map to find properties in `mol1` + + Returns + ------- + Molecule + The mutated molecule + """ + from ..base import create_map + + map = create_map(map) + + if map0 is None: + map0 = map + else: + map0 = create_map(map, map0) + + if map1 is None: + map1 = map + else: + map1 = create_map(map, map1) + + from . import match + + mapping = match(mol0=mol0, mol1=mol1, match_light_atoms=True, map0=map0, map1=map1) + + return mapping.mutate(as_new_molecule=True, map=map) + + +if not hasattr(_AtomMapping, "mutate"): + _AtomMapping.mutate = _mutate diff --git a/src/sire/morph/_perturbation.py b/src/sire/morph/_perturbation.py index 3cb36a9ba..6f6698a5e 100644 --- a/src/sire/morph/_perturbation.py +++ b/src/sire/morph/_perturbation.py @@ -134,17 +134,7 @@ def __init__(self, mol, map=None): # construct the perturbation objects that can move the # coordinates between the end states - from ..legacy.Mol import ( - BondPerturbation, - AnglePerturbation, - GeometryPerturbations, - ) - - from ..legacy.MM import AmberBond, AmberAngle - from ..cas import Symbol - from ..units import angstrom, radian - - self._perturbations = GeometryPerturbations() + self._perturbations = None props = [ "LJ", @@ -171,6 +161,33 @@ def __init__(self, mol, map=None): self._map0 = map.add_suffix("0", props) self._map1 = map.add_suffix("1", props) + self._mol = mol.clone() + + def __str__(self): + return f"Perturbation( {self._mol} )" + + def __repr__(self): + return self.__str__() + + def _get_perturbations(self): + """ + Find all of the perturbations in the molecule + """ + from ..legacy.MM import AmberBond, AmberAngle + from ..cas import Symbol + from ..units import angstrom, radian + from ..legacy.Mol import ( + GeometryPerturbations, + BondPerturbation, + AnglePerturbation, + ) + + if self._perturbations is not None: + return self._perturbations + + mol = self._mol + self._perturbations = GeometryPerturbations() + # identify all of the ghost atoms from_ghosts = [] to_ghosts = [] @@ -214,7 +231,7 @@ def __init__(self, mol, map=None): angle=angle.id(), start=theta0_0 * radian, end=theta0_1 * radian, - map=map, + map=self._map, ) ) @@ -232,17 +249,11 @@ def __init__(self, mol, map=None): bond=bond.id(), start=r0_0 * angstrom, end=r0_1 * angstrom, - map=map, + map=self._map, ) ) - self._mol = mol.clone() - - def __str__(self): - return f"Perturbation( {self._mol} )" - - def __repr__(self): - return self.__str__() + return self._perturbations def extract_reference( self, @@ -297,7 +308,15 @@ def extract_reference( mol = mol.commit().molecule() if remove_ghosts: - mol = mol["not element Xx"].extract(to_same_molecule=True) + try: + mol = mol["not element Xx"] + except Exception: + # there are no non-ghost atoms! + from ..mol import Molecule + + return Molecule() + + mol = mol.extract(to_same_molecule=True) return mol @@ -351,10 +370,22 @@ def extract_perturbed( if mol.has_property("is_perturbable"): mol.remove_property("is_perturbable") + mol.switch_to_alternate_names() + mol = mol.commit().molecule() if remove_ghosts: - mol = mol["not element Xx"].extract(to_same_molecule=True) + try: + mol = mol["not element Xx"] + except Exception: + # there are no non-ghost atoms! + from ..mol import Molecule + + return Molecule() + + mol = mol.extract(to_same_molecule=True) + + return mol return mol @@ -471,7 +502,7 @@ def set_lambda(self, lam_val: float): ) vals = Values({Symbol("lambda"): lam_val}) - self._mol.update(self._perturbations.perturb(mol, vals)) + self._mol.update(self._get_perturbations().perturb(mol, vals)) return self def commit(self): @@ -518,12 +549,12 @@ def view(self, *args, state="perturbed", **kwargs): for lam in range(0, 11): vals = Values({Symbol("lambda"): 0.1 * lam}) - mol = self._perturbations.perturb(mol, vals) + mol = self._get_perturbations().perturb(mol, vals) mol.save_frame() for lam in range(9, 0, -1): vals = Values({Symbol("lambda"): 0.1 * lam}) - mol = self._perturbations.perturb(mol, vals) + mol = self._get_perturbations().perturb(mol, vals) mol.save_frame() return mol["not element Xx"].view(*args, **kwargs) diff --git a/src/sire/options/_dynamics_options.py b/src/sire/options/_dynamics_options.py index 4da2dcb25..1f0fd35f8 100644 --- a/src/sire/options/_dynamics_options.py +++ b/src/sire/options/_dynamics_options.py @@ -95,6 +95,12 @@ class Constraint(_Option): "excluding those that are perturbed " "but do not involve a hydrogen in any end state.", ) + AUTO_BONDS = ( + "auto_bonds", + "Choose the constraints automatically, constraining bonds based " + "on whether their predicted vibrational periods are less than a " + "tenth of the simulaton timestep.", + ) @staticmethod def create(option: str): diff --git a/src/sire/units/__init__.py b/src/sire/units/__init__.py index 041988a6e..7db6573c2 100644 --- a/src/sire/units/__init__.py +++ b/src/sire/units/__init__.py @@ -382,10 +382,51 @@ def __generalunit__abs__(obj): else: return obj + def __generalunit__pow__(obj, power): + try: + power = float(power) + except Exception: + raise TypeError( + "unsupported operand type(s) for ^: '%s' and '%s'" + % (obj.__class__.__qualname__, power.__class__.__qualname__) + ) + + if obj.is_zero(): + return obj + + elif power == 0: + return obj / obj + + value = obj.value() ** power + + dims = obj.dimensions() + + # Compute the new dimensions, rounding floats to 16 decimal places. + new_dims = [round(dim * power, 16) for dim in dims] + + # Make sure the new dimensions are integers. + def is_integer(dim): + return dim == int(dim) + + if not all(is_integer(dim) for dim in new_dims): + raise ValueError( + "The exponent must be a factor of all the unit dimensions." + ) + + # Convert to integers. + new_dims = [int(dim) for dim in new_dims] + + return GeneralUnit(value, new_dims) + + def __generalunit__sqrt__(obj): + return obj**0.5 + GeneralUnit.__bool__ = __generalunit__bool__ GeneralUnit.__float__ = __generalunit__float__ GeneralUnit.__int__ = __generalunit__int__ GeneralUnit.__abs__ = __generalunit__abs__ + GeneralUnit.__pow__ = __generalunit__pow__ + GeneralUnit.sqrt = __generalunit__sqrt__ if not hasattr(GeneralUnit, "to_default"): diff --git a/tests/conftest.py b/tests/conftest.py index 328176c28..f0c82a7d1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,6 +60,11 @@ def ose_mols(): return sr.load_test_files("ose.top", "ose.crd") +@pytest.fixture(scope="session") +def zan_mols(): + return sr.load_test_files("zan.top", "zan.rst") + + @pytest.fixture(scope="session") def h7n9_mols(): return sr.load_test_files("h7n9.pdb", "h7n9.dcd") diff --git a/tests/convert/test_openmm_constraints.py b/tests/convert/test_openmm_constraints.py index a3c38e795..a8cf77371 100644 --- a/tests/convert/test_openmm_constraints.py +++ b/tests/convert/test_openmm_constraints.py @@ -396,3 +396,58 @@ def test_dynamic_constraints(merged_ethane_methanol, openmm_platform): nrg = d.current_potential_energy() assert nrg.value() == pytest.approx(13.8969, abs=0.001) + + +@pytest.mark.skipif( + "openmm" not in sr.convert.supported_formats(), + reason="openmm support is not available", +) +def test_auto_constraints(ala_mols, openmm_platform): + mols = ala_mols + mol = mols[0] + + NA = 6.02214076e23 + CONV = 0.695039 + + periods = {} + + for bond in mol.bonds(): + mass0 = bond.atom0().mass().value() / (1000.0 * NA) + mass1 = bond.atom1().mass().value() / (1000.0 * NA) + k = sr.mm.AmberBond(bond.potential(), sr.cas.Symbol("r")).k() * CONV + + mu = (mass0 * mass1) / (mass0 + mass1) + + # period in fs + period = 1e15 * 2.0 * 3.14159 * (mu / k) ** 0.5 + periods[bond.id()] = period + + for factor in [5.0, 10.0, 15.0]: + for timestep in [sr.u("1fs"), sr.u("2fs"), sr.u("4fs")]: + fs = timestep.to("fs") + + constrained = [] + + for bond in mol.bonds(): + period = periods[bond.id()] + + if period < factor * fs: + constrained.append(bond.id()) + + d = mol.dynamics( + constraint="auto-bonds", + platform=openmm_platform, + timestep=timestep, + temperature="25oC", + map={"auto_constraints_factor": factor}, + ) + + constraints = d.get_constraints() + + assert len(constraints) == len(constrained) + + for constraint in constraints: + bond = sr.bondid( + constraint[0].atom(0).index(), constraint[0].atom(1).index() + ) + assert bond in constrained diff --git a/tests/convert/test_rdkit.py b/tests/convert/test_rdkit.py index 363aca631..780f4e3a8 100644 --- a/tests/convert/test_rdkit.py +++ b/tests/convert/test_rdkit.py @@ -135,3 +135,33 @@ def test_rdkit_infer_bonds(ejm55_sdf, ejm55_gro): for s, g in zip(match_sdf, match_gro): assert s.number() == g.number() + + +@pytest.mark.skipif( + "rdkit" not in sr.convert.supported_formats(), + reason="rdkit support is not available", +) +def test_rdkit_preserve_info(ala_mols, ejm55_gro): + mol0 = ala_mols[0] + mol1 = ejm55_gro["not (protein or water)"].molecule() + + r0 = sr.convert.to(mol0, "rdkit") + r1 = sr.convert.to(mol1, "rdkit") + + m0 = sr.convert.to(r0, "sire") + m1 = sr.convert.to(r1, "sire") + + for mol, m in [(mol0, m0), (mol1, m1)]: + for res0, res1 in zip(mol.residues(), m.residues()): + assert res0.name() == res1.name() + assert res0.number() == res1.number() + + for atom0, atom1 in zip(mol.atoms(), m.atoms()): + assert atom0.name() == atom1.name() + assert atom0.number() == atom1.number() + + res0 = atom0.residue() + res1 = atom1.residue() + + assert res0.name() == res1.name() + assert res0.number() == res1.number() diff --git a/tests/mol/test_extract.py b/tests/mol/test_extract.py new file mode 100644 index 000000000..ea2d2d1fe --- /dev/null +++ b/tests/mol/test_extract.py @@ -0,0 +1,34 @@ +import sire as sr + +import pytest + + +def test_extract(neura_mols): + protein = neura_mols["protein"] + + # Extract the middle 10 residues + middle_residues = protein.residues()[10:20] + + extracted_middle_residues = middle_residues.extract().molecule() + + assert middle_residues.num_atoms() == extracted_middle_residues.num_atoms() + + assert middle_residues.num_residues() == extracted_middle_residues.num_residues() + + # Extract the third of these residues + res_0 = middle_residues[2].extract().molecule() + res_1 = extracted_middle_residues.residues()[2].extract().molecule() + + assert res_0.num_atoms() == middle_residues[2].num_atoms() + assert res_0.num_residues() == 1 + + assert res_0.num_atoms() == res_1.num_atoms() + assert res_0.num_residues() == res_1.num_residues() + + # this validates that most of the properties have been extracted + # properly + assert res_0.energy().value() == pytest.approx(res_1.energy().value()) + assert res_0.energy().value() == pytest.approx(middle_residues[2].energy().value()) + assert extracted_middle_residues.energy().value() == pytest.approx( + middle_residues.energy().value() + ) diff --git a/tests/morph/test_decouple.py b/tests/morph/test_decouple.py new file mode 100644 index 000000000..8c0dc68c3 --- /dev/null +++ b/tests/morph/test_decouple.py @@ -0,0 +1,224 @@ +import sire as sr + +import pytest + + +@pytest.mark.skipif( + "openmm" not in sr.convert.supported_formats(), + reason="openmm support is not available", +) +def test_decouple(ala_mols, openmm_platform): + mol = ala_mols[0] + + dmol = sr.morph.decouple(mol) + + # check the energies are the same forwards and backwards + d_fwds = dmol.dynamics(platform=openmm_platform, constraint="h-bonds") + d_bwds = dmol.dynamics( + platform=openmm_platform, constraint="h-bonds", swap_end_states=True + ) + + d_fwds.set_lambda(0.0) + d_bwds.set_lambda(1.0) + + assert d_fwds.current_potential_energy().value() == pytest.approx( + d_bwds.current_potential_energy().value(), abs=1e-4 + ) + + d_fwds.set_lambda(1.0) + d_bwds.set_lambda(0.0) + + assert d_fwds.current_potential_energy().value() == pytest.approx( + d_bwds.current_potential_energy().value(), abs=1e-4 + ) + + # use .changed_bonds() etc to validate that the forwards + # and backwards perturbations are the same + omm_fwds = dmol.perturbation().to_openmm(constraint="h-bonds") + + omm_bwds = dmol.perturbation().to_openmm(constraint="h-bonds", swap_end_states=True) + + fwds = omm_fwds.changed_atoms() + bwds = omm_bwds.changed_atoms() + + assert fwds["charge0"].equals(bwds["charge1"]) + assert fwds["charge1"].equals(bwds["charge0"]) + assert fwds["sigma0"].equals(bwds["sigma1"]) + assert fwds["sigma1"].equals(bwds["sigma0"]) + assert fwds["epsilon0"].equals(bwds["epsilon1"]) + assert fwds["epsilon1"].equals(bwds["epsilon0"]) + + # also check that parameters are being set equal to zero correctly + assert (fwds["charge1"] == 0.0).all() + assert (fwds["sigma1"] != 0.0).all() + assert (fwds["epsilon1"] == 0.0).all() + assert (bwds["charge0"] == 0.0).all() + assert (bwds["sigma0"] != 0.0).all() + assert (bwds["epsilon0"] == 0.0).all() + + fwds = omm_fwds.changed_bonds() + bwds = omm_bwds.changed_bonds() + + assert fwds.empty + assert bwds.empty + + fwds = omm_fwds.changed_angles() + bwds = omm_bwds.changed_angles() + + assert fwds.empty + assert bwds.empty + + fwds = omm_fwds.changed_torsions() + bwds = omm_bwds.changed_torsions() + + assert fwds.empty + assert bwds.empty + + fwds = omm_fwds.changed_exceptions() + bwds = omm_bwds.changed_exceptions() + + assert fwds.empty + assert bwds.empty + + fwds = omm_fwds.changed_constraints() + bwds = omm_bwds.changed_constraints() + + assert fwds.empty + assert bwds.empty + + +@pytest.mark.skipif( + "openmm" not in sr.convert.supported_formats(), + reason="openmm support is not available", +) +def test_annihilate(ala_mols, openmm_platform): + mol = ala_mols[0] + + amol = sr.morph.annihilate(mol) + + # check the energies are the same forwards and backwards + d_fwds = amol.dynamics(platform=openmm_platform, constraint="h-bonds") + d_bwds = amol.dynamics( + platform=openmm_platform, constraint="h-bonds", swap_end_states=True + ) + + d_fwds.set_lambda(0.0) + d_bwds.set_lambda(1.0) + + assert d_fwds.current_potential_energy().value() == pytest.approx( + d_bwds.current_potential_energy().value(), abs=1e-4 + ) + + d_fwds.set_lambda(1.0) + d_bwds.set_lambda(0.0) + + assert d_fwds.current_potential_energy().value() == pytest.approx( + d_bwds.current_potential_energy().value(), abs=1e-4 + ) + + # use .changed_bonds() etc to validate that the forwards + # and backwards perturbations are the same + omm_fwds = amol.perturbation().to_openmm(constraint="h-bonds") + + omm_bwds = amol.perturbation().to_openmm(constraint="h-bonds", swap_end_states=True) + + fwds = omm_fwds.changed_atoms() + bwds = omm_bwds.changed_atoms() + + assert fwds["charge0"].equals(bwds["charge1"]) + assert fwds["charge1"].equals(bwds["charge0"]) + assert fwds["sigma0"].equals(bwds["sigma1"]) + assert fwds["sigma1"].equals(bwds["sigma0"]) + assert fwds["epsilon0"].equals(bwds["epsilon1"]) + assert fwds["epsilon1"].equals(bwds["epsilon0"]) + + # also check that parameters are being set equal to zero correctly + assert (fwds["charge1"] == 0.0).all() + assert (fwds["sigma1"] != 0.0).all() + assert (fwds["epsilon1"] == 0.0).all() + assert (bwds["charge0"] == 0.0).all() + assert (bwds["sigma0"] != 0.0).all() + assert (bwds["epsilon0"] == 0.0).all() + + fwds = omm_fwds.changed_bonds() + bwds = omm_bwds.changed_bonds() + + joined = fwds.merge(bwds, on="bond", suffixes=("_fwds", "_bwds")) + + assert joined["length0_fwds"].equals(joined["length1_bwds"]) + assert joined["length1_fwds"].equals(joined["length0_bwds"]) + assert joined["k0_fwds"].equals(joined["k1_bwds"]) + assert joined["k1_fwds"].equals(joined["k0_bwds"]) + + # also check that parameters are being set equal to zero correctly + assert (joined["length1_fwds"] != 0.0).all() + assert (joined["k1_fwds"] == 0.0).all() + assert (joined["length0_bwds"] != 0.0).all() + assert (joined["k0_bwds"] == 0.0).all() + + fwds = omm_fwds.changed_angles() + bwds = omm_bwds.changed_angles() + + joined = fwds.merge(bwds, on="angle", suffixes=("_fwds", "_bwds")) + + assert joined["size0_fwds"].equals(joined["size1_bwds"]) + assert joined["size1_fwds"].equals(joined["size0_bwds"]) + assert joined["k0_fwds"].equals(joined["k1_bwds"]) + assert joined["k1_fwds"].equals(joined["k0_bwds"]) + + # also check that parameters are being set equal to zero correctly + assert (joined["size1_fwds"] != 0.0).all() + assert (joined["k1_fwds"] == 0.0).all() + assert (joined["size0_bwds"] != 0.0).all() + assert (joined["k0_bwds"] == 0.0).all() + + fwds = omm_fwds.changed_torsions() + bwds = omm_bwds.changed_torsions() + + # there are multiple torsions, so these need searching for + # and matching directly + for _, row_fwds in fwds.iterrows(): + torsion = row_fwds["torsion"] + + found = False + + for _, row_bwds in bwds[bwds["torsion"] == torsion].iterrows(): + if ( + row_fwds["k0"] == row_bwds["k1"] + and row_fwds["k1"] == row_bwds["k0"] + and row_fwds["periodicity0"] == row_bwds["periodicity1"] + and row_fwds["periodicity1"] == row_bwds["periodicity0"] + and row_fwds["phase0"] == row_bwds["phase1"] + and row_fwds["phase1"] == row_bwds["phase0"] + ): + found = True + break + + assert found + + # also check that parameters are being set equal to zero correctly + assert (fwds["k1"] == 0.0).all() + assert (bwds["k0"] == 0.0).all() + + fwds = omm_fwds.changed_exceptions() + bwds = omm_bwds.changed_exceptions() + + joined = fwds.merge(bwds, on="atompair", suffixes=("_fwds", "_bwds")) + + assert joined["charge_scale0_fwds"].equals(joined["charge_scale1_bwds"]) + assert joined["charge_scale1_fwds"].equals(joined["charge_scale0_bwds"]) + assert joined["lj_scale0_fwds"].equals(joined["lj_scale1_bwds"]) + assert joined["lj_scale1_fwds"].equals(joined["lj_scale0_bwds"]) + + # also check that parameters are being set equal to zero correctly + assert (joined["charge_scale1_fwds"] == 0.0).all() + assert (joined["lj_scale1_fwds"] == 0.0).all() + assert (joined["charge_scale0_bwds"] == 0.0).all() + assert (joined["lj_scale0_bwds"] == 0.0).all() + + fwds = omm_fwds.changed_constraints() + bwds = omm_bwds.changed_constraints() + + # there should be no changed constraints + assert fwds.empty + assert bwds.empty diff --git a/tests/morph/test_match.py b/tests/morph/test_match.py new file mode 100644 index 000000000..b1d6a872d --- /dev/null +++ b/tests/morph/test_match.py @@ -0,0 +1,84 @@ +import sire as sr + +import pytest +import sys + + +# skip if we run on windows +@pytest.mark.skipif( + sys.platform == "win32", + reason="Does not run on Windows because there is no match support", +) +def test_match(kigaki_mols): + mols = kigaki_mols + + mol = mols.molecule("protein") + + ala = mol.residues("ALA")[1] + phe = mol.residues("LYS")[1] + + m = sr.morph.match(ala, phe, match_light_atoms=True) + + assert m is not None + + assert len(m) == 9 + + assert len(m.mapped_atoms0()) == 9 + assert len(m.mapped_atoms1()) == 9 + + assert len(m.unmapped_atoms0().atoms()) == 1 + assert len(m.unmapped_atoms1().atoms()) == 13 + + assert len(m.atoms0()) == len(ala.atoms()) + assert len(m.atoms1()) == len(phe.atoms()) + + assert m.atoms0() == ala.atoms() + assert m.atoms1() == phe.atoms() + + assert m.is_single_molecule() + + assert not m.is_empty() + + num_unmapped = 0 + + for atom in ala.atoms(): + assert m.contains(atom) + + if atom.element().num_protons() != 1: + assert m.is_mapped(atom) + + if not m.is_mapped(atom): + num_unmapped += 1 + + assert num_unmapped == 1 + + m = m.swap() + + assert len(m) == 9 + + assert len(m.mapped_atoms0()) == 9 + assert len(m.mapped_atoms1()) == 9 + + assert len(m.unmapped_atoms0().atoms()) == 13 + assert len(m.unmapped_atoms1().atoms()) == 1 + + assert len(m.atoms0()) == len(phe.atoms()) + assert len(m.atoms1()) == len(ala.atoms()) + + assert m.atoms0() == phe.atoms() + assert m.atoms1() == ala.atoms() + + assert m.is_single_molecule() + + assert not m.is_empty() + + num_unmapped = 0 + + for atom in phe.atoms(): + assert m.contains(atom) + + if not m.is_mapped(atom): + num_unmapped += 1 + + assert m.atoms0().to_single_molecule() == phe.atoms().to_single_molecule() + assert m.atoms1().to_single_molecule() == ala.atoms().to_single_molecule() diff --git a/tests/morph/test_merge.py b/tests/morph/test_merge.py new file mode 100644 index 000000000..8d5311569 --- /dev/null +++ b/tests/morph/test_merge.py @@ -0,0 +1,204 @@ +import sire as sr + +import pytest +import sys + +try: + from kartograf import KartografAtomMapper +except ImportError: + KartografAtomMapper = None + + +@pytest.mark.skipif( + "openmm" not in sr.convert.supported_formats(), + reason="openmm support is not available", +) +def test_extract_remerge(merged_zan_ose, openmm_platform): + merged = merged_zan_ose[0].perturbation().link_to_reference() + + extracted_ose = merged.perturbation().extract_reference() + extracted_zan = merged.perturbation().extract_perturbed() + + remerged = sr.morph.merge( + extracted_ose, extracted_zan, match=sr.legacy.Mol.AtomNumMatcher() + ) + + nrg_merged_0 = merged.dynamics( + lambda_value=0, platform=openmm_platform + ).current_potential_energy() + + nrg_merged_1 = merged.dynamics( + lambda_value=1, platform=openmm_platform + ).current_potential_energy() + + nrg_remerged_0 = remerged.dynamics( + lambda_value=0, platform=openmm_platform + ).current_potential_energy() + + nrg_remerged_1 = remerged.dynamics( + lambda_value=1, platform=openmm_platform + ).current_potential_energy() + + assert nrg_merged_0.value() == pytest.approx(nrg_remerged_0.value()) + assert nrg_merged_1.value() == pytest.approx(nrg_remerged_1.value()) + + +@pytest.mark.slow +@pytest.mark.skipif( + "openmm" not in sr.convert.supported_formats() or KartografAtomMapper is None, + reason="openmm or kartograf support is not available", +) +def test_merge(ose_mols, zan_mols, openmm_platform): + ose = ose_mols[0] + zan = zan_mols[0] + + merged = sr.morph.merge( + ose, zan, match=KartografAtomMapper(atom_map_hydrogens=True) + ) + + ose_nrg = ose.dynamics(platform=openmm_platform).current_potential_energy() + zan_nrg = zan.dynamics(platform=openmm_platform).current_potential_energy() + + extracted_ose = merged.perturbation().extract_reference() + extracted_zan = merged.perturbation().extract_perturbed() + + extracted_ose_nrg = extracted_ose.dynamics( + platform=openmm_platform + ).current_potential_energy() + + extracted_zan_nrg = extracted_zan.dynamics( + platform=openmm_platform + ).current_potential_energy() + + assert extracted_ose_nrg.value() == pytest.approx(ose_nrg.value()) + assert extracted_zan_nrg.value() == pytest.approx(zan_nrg.value()) + + merged = sr.morph.merge( + zan, ose, match=KartografAtomMapper(atom_map_hydrogens=True) + ) + + extracted_zan = merged.perturbation().extract_reference() + extracted_ose = merged.perturbation().extract_perturbed() + + extracted_ose_nrg = extracted_ose.dynamics( + platform=openmm_platform + ).current_potential_energy() + + extracted_zan_nrg = extracted_zan.dynamics( + platform=openmm_platform + ).current_potential_energy() + + assert extracted_ose_nrg.value() == pytest.approx(ose_nrg.value()) + assert extracted_zan_nrg.value() == pytest.approx(zan_nrg.value()) + + # we don't test merged molecule energies are these + # energies are not equal because there are additional bonds, + # angle and dihedrals to ghost atoms in the merged molecule + + +@pytest.mark.veryslow +@pytest.mark.skipif( + sys.platform == "win32", + reason="Does not run on Windows because there is no match support", +) +def test_merge_protein(neura_mols): + protein = neura_mols["protein"] + + ala = protein.residues("ALA")[1] + lys = protein.residues("LYS")[1] + + merged = sr.morph.merge(ala, lys) + + merged_ala = merged.perturbation().extract_reference()[ala.number()] + merged_lys = merged.perturbation().extract_perturbed()[lys.number()] + + scl_ala = ala.property("intrascale") + scl_merged_ala = merged_ala.property("intrascale") + + for i in range(ala.num_atoms()): + for j in range(ala.num_atoms()): + atom0 = sr.atomid(idx=i) + atom1 = sr.atomid(idx=j) + s_ala = scl_ala.get(atom0, atom1) + s_merged_ala = scl_merged_ala.get(atom0, atom1) + assert s_ala == s_merged_ala + + scl_lys = lys.property("intrascale") + scl_merged_lys = merged_lys.property("intrascale") + + for i in range(lys.num_atoms()): + for j in range(lys.num_atoms()): + atom0 = sr.atomid(idx=i) + atom1 = sr.atomid(idx=j) + s_lys = scl_lys.get(atom0, atom1) + s_merged_lys = scl_merged_lys.get(atom0, atom1) + assert s_lys == s_merged_lys + + assert ala.energy().value() == pytest.approx(merged_ala.energy().value()) + assert lys.energy().value() == pytest.approx(merged_lys.energy().value()) + + +@pytest.mark.skipif( + "openmm" not in sr.convert.supported_formats() or KartografAtomMapper is None, + reason="openmm or kartograf support is not available", +) +def test_merge_neopentane_methane(neopentane_methane, openmm_platform): + neopentane = neopentane_methane[0].perturbation().extract_reference() + methane = neopentane_methane[0].perturbation().extract_perturbed() + + orig_merged = sr.morph.link_to_reference(neopentane_methane[0]) + + nrg_neo = neopentane.dynamics(platform=openmm_platform).current_potential_energy() + nrg_met = methane.dynamics(platform=openmm_platform).current_potential_energy() + + merged = sr.morph.merge( + neopentane, methane, match=KartografAtomMapper(atom_map_hydrogens=True) + ) + + nrg_merged_0 = merged.dynamics( + lambda_value=0, platform=openmm_platform + ).current_potential_energy() + + nrg_merged_1 = merged.dynamics( + lambda_value=1, platform=openmm_platform + ).current_potential_energy() + + nrg_merged_05 = merged.dynamics( + lambda_value=0.5, platform=openmm_platform + ).current_potential_energy() + + extracted_neo = merged.perturbation().extract_reference() + extracted_met = merged.perturbation().extract_perturbed() + + nrg_extracted_neo = extracted_neo.dynamics( + platform=openmm_platform + ).current_potential_energy() + + nrg_extracted_met = extracted_met.dynamics( + platform=openmm_platform + ).current_potential_energy() + + nrg_orig_merged_0 = orig_merged.dynamics( + lambda_value=0, platform=openmm_platform + ).current_potential_energy() + + nrg_orig_merged_1 = orig_merged.dynamics( + lambda_value=1, platform=openmm_platform + ).current_potential_energy() + + nrg_orig_merged_05 = orig_merged.dynamics( + lambda_value=0.5, platform=openmm_platform + ).current_potential_energy() + + assert nrg_neo.value() == pytest.approx(nrg_extracted_neo.value(), abs=1e-3) + assert nrg_met.value() == pytest.approx(nrg_extracted_met.value(), abs=1e-3) + + assert nrg_merged_0.value() == pytest.approx(nrg_orig_merged_0.value(), abs=1e-3) + assert nrg_merged_1.value() == pytest.approx(nrg_orig_merged_1.value(), abs=1e-3) + + # this is different - worth checking why! + # assert nrg_merged_05.value() == pytest.approx(nrg_orig_merged_05.value(), abs=1e-3) + + # These energies aren't correct - extra ghost atom internals? + assert nrg_neo.value() == pytest.approx(nrg_merged_0.value(), abs=1e-3) + # assert nrg_met.value() == pytest.approx(nrg_merged_1.value(), abs=1e-3) diff --git a/wrapper/Base/releasegil_impl.cpp b/wrapper/Base/releasegil_impl.cpp index 99e2bc40b..35474cd0e 100644 --- a/wrapper/Base/releasegil_impl.cpp +++ b/wrapper/Base/releasegil_impl.cpp @@ -2,6 +2,7 @@ #include "boost/python.hpp" #include "SireBase/releasegil.h" +#include "SireBase/console.h" #include @@ -282,6 +283,169 @@ class ReleaseGIL : public SireBase::detail::ReleaseGILBase PyThreadState *thread_state; }; +class ConsoleImpl : public SireBase::ConsoleBase +{ +public: + ConsoleImpl() : SireBase::ConsoleBase(), pyconsole(0) + { + } + + ~ConsoleImpl() + { + if (pyconsole) + { + PyGILState_STATE gilstate = PyGILState_Ensure(); + Py_DECREF(pyconsole); + delete pyconsole; + pyconsole = 0; + PyGILState_Release(gilstate); + } + } + + void debug(const QString &message) const + { + const_cast(this)->get_pyconsole(); + + if (pyconsole) + { + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *result = PyObject_CallMethod(pyconsole, "debug", "s", message.toUtf8().constData()); + + if (result == 0) + { + qDebug() << "UNABLE TO CALL DEBUG"; + qDebug() << message; + } + else + { + Py_DECREF(result); + } + + PyGILState_Release(gilstate); + } + else + { + qDebug() << "NO PYCONSOLE"; + qDebug() << message; + } + } + + void warning(const QString &message) const + { + const_cast(this)->get_pyconsole(); + + if (pyconsole) + { + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *result = PyObject_CallMethod(pyconsole, "warning", "s", message.toUtf8().constData()); + + if (result == 0) + { + qWarning() << message; + } + else + { + Py_DECREF(result); + } + + PyGILState_Release(gilstate); + } + else + { + qWarning() << message; + } + } + + void error(const QString &message) const + { + const_cast(this)->get_pyconsole(); + + if (pyconsole) + { + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *result = PyObject_CallMethod(pyconsole, "error", "s", message.toUtf8().constData()); + + if (result == 0) + { + qCritical() << message; + } + else + { + Py_DECREF(result); + } + + PyGILState_Release(gilstate); + } + else + { + qCritical() << message; + } + } + + void info(const QString &message) const + { + const_cast(this)->get_pyconsole(); + + if (pyconsole) + { + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *result = PyObject_CallMethod(pyconsole, "info", "s", message.toUtf8().constData()); + + if (result == 0) + { + qInfo() << "UNABLE TO CALL INFO"; + qInfo() << message; + } + else + { + Py_DECREF(result); + } + + PyGILState_Release(gilstate); + } + else + { + qInfo() << "NO PYCONSOLE"; + qInfo() << message; + } + } + +private: + void get_pyconsole() + { + if (pyconsole) + return; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *sire_utils = PyImport_ImportModule("sire.utils"); + + if (sire_utils == 0) + { + qWarning() << "COULD NOT IMPORT SIRE.UTILS"; + PyGILState_Release(gilstate); + return; + } + + pyconsole = PyObject_GetAttrString(sire_utils, "Console"); + + Py_DECREF(sire_utils); + + if (pyconsole == 0) + { + qWarning() << "Could not import Console from sire.utils"; + PyGILState_Release(gilstate); + return; + } + } + + PyObject *pyconsole; +}; + QMutex ReleaseGIL::release_mutex; std::weak_ptr ReleaseGIL::current_state; @@ -291,4 +455,6 @@ void register_releasegil() ReleaseGIL::register_releasegil(); boost::python::def("set_is_ipython", &set_is_ipython); + + SireBase::Console::setConsole(new ConsoleImpl()); } diff --git a/wrapper/CAS/LambdaSchedule.pypp.cpp b/wrapper/CAS/LambdaSchedule.pypp.cpp index f2709cd9e..34f75ae16 100644 --- a/wrapper/CAS/LambdaSchedule.pypp.cpp +++ b/wrapper/CAS/LambdaSchedule.pypp.cpp @@ -8,6 +8,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/values.h" #include "SireError/errors.h" @@ -35,6 +37,30 @@ void register_LambdaSchedule_class(){ LambdaSchedule_exposer_t LambdaSchedule_exposer = LambdaSchedule_exposer_t( "LambdaSchedule", "This is a schedule that specifies how parameters are changed according\nto a global lambda value. The change can be broken up by sub lever,\nand by stage.\n", bp::init< >("") ); bp::scope LambdaSchedule_scope( LambdaSchedule_exposer ); LambdaSchedule_exposer.def( bp::init< SireCAS::LambdaSchedule const & >(( bp::arg("other") ), "") ); + { //::SireCAS::LambdaSchedule::addAnnihilateStage + + typedef void ( ::SireCAS::LambdaSchedule::*addAnnihilateStage_function_type)( bool ) ; + addAnnihilateStage_function_type addAnnihilateStage_function_value( &::SireCAS::LambdaSchedule::addAnnihilateStage ); + + LambdaSchedule_exposer.def( + "addAnnihilateStage" + , addAnnihilateStage_function_value + , ( bp::arg("perturbed_is_annihilated")=(bool)(true) ) + , "Add a stage to the schedule that will annihilate the perturbed\n state if `perturbed_is_annihilated` is true, otherwise the\n reference state is annihilated. The stage will be called annihilate.\n" ); + + } + { //::SireCAS::LambdaSchedule::addAnnihilateStage + + typedef void ( ::SireCAS::LambdaSchedule::*addAnnihilateStage_function_type)( ::QString const &,bool ) ; + addAnnihilateStage_function_type addAnnihilateStage_function_value( &::SireCAS::LambdaSchedule::addAnnihilateStage ); + + LambdaSchedule_exposer.def( + "addAnnihilateStage" + , addAnnihilateStage_function_value + , ( bp::arg("name"), bp::arg("perturbed_is_annihilated")=(bool)(true) ) + , "Add a named stage to the schedule that will annihilate the perturbed\n state if `perturbed_is_annihilated` is true, otherwise the\n reference state is annihilated.\n" ); + + } { //::SireCAS::LambdaSchedule::addChargeScaleStages typedef void ( ::SireCAS::LambdaSchedule::*addChargeScaleStages_function_type)( double ) ; @@ -68,7 +94,7 @@ void register_LambdaSchedule_class(){ "addDecoupleStage" , addDecoupleStage_function_value , ( bp::arg("perturbed_is_decoupled")=(bool)(true) ) - , "" ); + , "Add a stage to the schedule that will decouple the perturbed\n state if `perturbed_is_decoupled` is true, otherwise the\n reference state is decoupled. The stage will be called decouple.\n" ); } { //::SireCAS::LambdaSchedule::addDecoupleStage @@ -80,7 +106,7 @@ void register_LambdaSchedule_class(){ "addDecoupleStage" , addDecoupleStage_function_value , ( bp::arg("name"), bp::arg("perturbed_is_decoupled")=(bool)(true) ) - , "" ); + , "Add a named stage to the schedule that will decouple the perturbed\n state if `perturbed_is_decoupled` is true, otherwise the\n reference state is decoupled.\n" ); } { //::SireCAS::LambdaSchedule::addForce @@ -93,7 +119,7 @@ void register_LambdaSchedule_class(){ , addForce_function_value , ( bp::arg("force") ) , bp::release_gil_policy() - , "" ); + , "Add a force to a schedule. This is only useful if you want to\n plot how the equations would affect the lever. Forces will be\n automatically added by any perturbation run that needs them,\n so you dont need to add them manually yourself.\n" ); } { //::SireCAS::LambdaSchedule::addForces @@ -106,7 +132,7 @@ void register_LambdaSchedule_class(){ , addForces_function_value , ( bp::arg("forces") ) , bp::release_gil_policy() - , "" ); + , "Add some forces to a schedule. This is only useful if you want to\n plot how the equations would affect the lever. Forces will be\n automatically added by any perturbation run that needs them,\n so you dont need to add them manually yourself.\n" ); } { //::SireCAS::LambdaSchedule::addLever @@ -185,6 +211,18 @@ void register_LambdaSchedule_class(){ , bp::release_gil_policy() , "Append a stage called name which uses the passed equation\n to the end of this schedule. The equation will be the default\n equation that scales all parameters (levers) that dont have\n a custom lever for this stage.\n" ); + } + { //::SireCAS::LambdaSchedule::charge_scaled_annihilate + + typedef ::SireCAS::LambdaSchedule ( *charge_scaled_annihilate_function_type )( double,bool ); + charge_scaled_annihilate_function_type charge_scaled_annihilate_function_value( &::SireCAS::LambdaSchedule::charge_scaled_annihilate ); + + LambdaSchedule_exposer.def( + "charge_scaled_annihilate" + , charge_scaled_annihilate_function_value + , ( bp::arg("scale")=0.20000000000000001, bp::arg("perturbed_is_annihilated")=(bool)(true) ) + , "Return a schedule that can be used for a standard double-annihilation\n free energy perturbation. If `perturbed_is_annihilated` is true, then\n the perturbed state is annihilated, otherwise the reference state is\n annihilated. In this case also add states to decharge and recharge\n the molecule either side of the annihilation stage, where the charges\n are scaled to scale times their original value.\n" ); + } { //::SireCAS::LambdaSchedule::charge_scaled_decouple @@ -195,7 +233,7 @@ void register_LambdaSchedule_class(){ "charge_scaled_decouple" , charge_scaled_decouple_function_value , ( bp::arg("scale")=0.20000000000000001, bp::arg("perturbed_is_decoupled")=(bool)(true) ) - , "" ); + , "Return a schedule that can be used for a standard double-decoupling\n free energy perturbation. If `perturbed_is_decoupled` is true, then\n the perturbed state is decoupled, otherwise the reference state is\n decoupled. In this case also add states to decharge and recharge\n the molecule either side of the decoupling stage, where the charges\n are scaled to scale times their original value.\n" ); } { //::SireCAS::LambdaSchedule::charge_scaled_morph @@ -295,7 +333,7 @@ void register_LambdaSchedule_class(){ "getEquation" , getEquation_function_value , ( bp::arg("stage")="*", bp::arg("force")="*", bp::arg("lever")="*" ) - , "" ); + , "Return the equation used to control the specified lever\n in the specified force at the specified stage. This will\n be a custom equation if that has been set for this lever in this\n force, or else it will be a custom equation set for this lever,\n else it will be the default equation for this stage\n" ); } { //::SireCAS::LambdaSchedule::getForces @@ -307,7 +345,7 @@ void register_LambdaSchedule_class(){ "getForces" , getForces_function_value , bp::release_gil_policy() - , "" ); + , "Return all of the forces that have been explicitly added\n to the schedule. Note that forces will be automatically added\n by any perturbation run that needs them, so you dont normally\n need to manage them manually yourself.\n" ); } { //::SireCAS::LambdaSchedule::getLambdaInStage @@ -333,7 +371,7 @@ void register_LambdaSchedule_class(){ , getLeverStages_function_value , ( bp::arg("lambda_values") ) , bp::release_gil_policy() - , "Return the list of lever stages that are used for the passed list\n of lambda values. The lever names will be returned in the matching\n order of the lambda values.\n" ); + , "Return the list of stages that are used for the passed list\n of lambda values. The stage names will be returned in the matching\n order of the lambda values.\n" ); } { //::SireCAS::LambdaSchedule::getLeverStages @@ -345,7 +383,7 @@ void register_LambdaSchedule_class(){ "getLeverStages" , getLeverStages_function_value , ( bp::arg("num_lambda")=(int)(101) ) - , "Return the lever stages used for the list of `nvalue` lambda values\n generated for the global lambda value between 0 and 1 inclusive.\n" ); + , "Return the stages used for the list of `nvalue` lambda values\n generated for the global lambda value between 0 and 1 inclusive.\n" ); } { //::SireCAS::LambdaSchedule::getLeverValues @@ -357,7 +395,7 @@ void register_LambdaSchedule_class(){ "getLeverValues" , getLeverValues_function_value , ( bp::arg("lambda_values"), bp::arg("initial")=1., bp::arg("final")=2. ) - , "Return the lever name and parameter values for that lever\n for the specified list of lambda values, assuming that a\n parameter for that lever has an initial value of\n `initial_value` and a final value of `final_value`. This\n is mostly useful for testing and graphing how this\n schedule would change some hyperthetical forcefield\n parameters for the specified lambda values.\n" ); + , "Return the stage name and parameter values for that lever\n for the specified list of lambda values, assuming that a\n parameter for that stage has an initial value of\n `initial_value` and a final value of `final_value`. This\n is mostly useful for testing and graphing how this\n schedule would change some hyperthetical forcefield\n parameters for the specified lambda values.\n" ); } { //::SireCAS::LambdaSchedule::getLeverValues @@ -394,7 +432,7 @@ void register_LambdaSchedule_class(){ , getMoleculeSchedule_function_value , ( bp::arg("pert_mol_id") ) , bp::return_value_policy() - , "" ); + , "Return the schedule used to control perturbations for the\n perturbable molecule (or part of molecule) that is identified by the\n passed pert_mol_id. This schedule will be used to control\n all of the levers for this molecule (or part of molecule).\n\n This returns this schedule if there is no specified schedule\n for this molecule\n" ); } { //::SireCAS::LambdaSchedule::getStage @@ -431,7 +469,7 @@ void register_LambdaSchedule_class(){ "hasForceSpecificEquation" , hasForceSpecificEquation_function_value , ( bp::arg("stage")="*", bp::arg("force")="*", bp::arg("lever")="*" ) - , "" ); + , "Return whether or not the specified lever in the specified force\n at the specified stage has a custom equation set for it\n" ); } { //::SireCAS::LambdaSchedule::hasMoleculeSchedule @@ -444,7 +482,7 @@ void register_LambdaSchedule_class(){ , hasMoleculeSchedule_function_value , ( bp::arg("pert_mol_id") ) , bp::release_gil_policy() - , "" ); + , "Return whether or not the perturbable molecule (or part of molecule)\n that is identified by passed pert_mol_id has its own schedule" ); } { //::SireCAS::LambdaSchedule::initial @@ -505,7 +543,7 @@ void register_LambdaSchedule_class(){ "morph" , morph_function_value , ( bp::arg("force")="*", bp::arg("lever")="*", bp::arg("initial")=0, bp::arg("final")=1, bp::arg("lambda_value")=0 ) - , "" ); + , "Return the parameters for the specified lever called `lever_name`\n in the force force\n that have been morphed from the passed list of initial values\n (in `initial`) to the passed list of final values (in `final`)\n for the specified global value of :lambda: (in `lambda_value`).\n\n The morphed parameters will be returned in the matching\n order to `initial` and `final`.\n\n This morphs a single floating point parameters.\n" ); } { //::SireCAS::LambdaSchedule::morph @@ -517,7 +555,7 @@ void register_LambdaSchedule_class(){ "morph" , morph_function_value , ( bp::arg("force")="*", bp::arg("lever")="*", bp::arg("initial")=::QVector( ), bp::arg("final")=::QVector( ), bp::arg("lambda_value")=0. ) - , "" ); + , "Return the parameters for the specified lever called `lever_name`\n in the specified force,\n that have been morphed from the passed list of initial values\n (in `initial`) to the passed list of final values (in `final`)\n for the specified global value of :lambda: (in `lambda_value`).\n\n The morphed parameters will be returned in the matching\n order to `initial` and `final`.\n\n This morphs floating point parameters. There is an overload\n of this function that morphs integer parameters, in which\n case the result would be rounded to the nearest integer.\n" ); } { //::SireCAS::LambdaSchedule::morph @@ -529,7 +567,7 @@ void register_LambdaSchedule_class(){ "morph" , morph_function_value , ( bp::arg("force")="*", bp::arg("lever")="*", bp::arg("initial")=::QVector( ), bp::arg("final")=::QVector( ), bp::arg("lambda_value")=0. ) - , "" ); + , "Return the parameters for the specified lever called `lever_name`\n for the specified force\n that have been morphed from the passed list of initial values\n (in `initial`) to the passed list of final values (in `final`)\n for the specified global value of :lambda: (in `lambda_value`).\n\n The morphed parameters will be returned in the matching\n order to `initial` and `final`.\n\n This function morphs integer parameters. In this case,\n the result will be the rounded to the nearest integer.\n" ); } { //::SireCAS::LambdaSchedule::nForces @@ -541,7 +579,7 @@ void register_LambdaSchedule_class(){ "nForces" , nForces_function_value , bp::release_gil_policy() - , "" ); + , "Return the number of forces that have been explicitly added\n to the schedule. Note that forces will be automatically added\n by any perturbation run that needs them, so you dont normally\n need to manage them manually yourself.\n" ); } { //::SireCAS::LambdaSchedule::nLevers @@ -605,7 +643,7 @@ void register_LambdaSchedule_class(){ "removeEquation" , removeEquation_function_value , ( bp::arg("stage")="*", bp::arg("force")="*", bp::arg("lever")="*" ) - , "" ); + , "Remove the custom equation for the specified `lever` in the\n specified force at the specified `stage`.\n The lever will now use the equation specified for this\n lever for this stage, or the default lever for the stage\n if this isnt set\n" ); } { //::SireCAS::LambdaSchedule::removeForce @@ -618,7 +656,7 @@ void register_LambdaSchedule_class(){ , removeForce_function_value , ( bp::arg("force") ) , bp::release_gil_policy() - , "" ); + , "Remove a force from a schedule. This will not impact any\n perturbation runs that use this schedule, as any missing\n forces will be re-added.\n" ); } { //::SireCAS::LambdaSchedule::removeForces @@ -631,7 +669,7 @@ void register_LambdaSchedule_class(){ , removeForces_function_value , ( bp::arg("forces") ) , bp::release_gil_policy() - , "" ); + , "Remove some forces from a schedule. This will not impact any\n perturbation runs that use this schedule, as any missing\n forces will be re-added.\n" ); } { //::SireCAS::LambdaSchedule::removeLever @@ -670,7 +708,7 @@ void register_LambdaSchedule_class(){ , removeMoleculeSchedule_function_value , ( bp::arg("pert_mol_id") ) , bp::release_gil_policy() - , "" ); + , "Remove the perturbable molecule-specific schedule associated\n with the perturbable molecule (or part of molecule) that is\n identified by the passed pert_mol_id.\n" ); } { //::SireCAS::LambdaSchedule::removeStage @@ -683,7 +721,7 @@ void register_LambdaSchedule_class(){ , removeStage_function_value , ( bp::arg("stage") ) , bp::release_gil_policy() - , "" ); + , "Remove the stage stage" ); } { //::SireCAS::LambdaSchedule::setConstant @@ -722,7 +760,7 @@ void register_LambdaSchedule_class(){ , setDefaultStageEquation_function_value , ( bp::arg("stage"), bp::arg("equation") ) , bp::release_gil_policy() - , "" ); + , "Set the default equation used to control levers for the\n stage stage to equation. This equation will be used\n to control any levers in this stage that dont have\n their own custom equation.\n" ); } { //::SireCAS::LambdaSchedule::setEquation @@ -734,7 +772,7 @@ void register_LambdaSchedule_class(){ "setEquation" , setEquation_function_value , ( bp::arg("stage")="*", bp::arg("force")="*", bp::arg("lever")="*", bp::arg("equation")=SireCAS::Expression() ) - , "" ); + , "Set the custom equation used to control the specified lever\n for the specified force at the stage stage to equation.\n This equation will only be used to control the parameters for the\n specified lever in the specified force at the specified stage\n" ); } { //::SireCAS::LambdaSchedule::setMoleculeSchedule @@ -747,7 +785,19 @@ void register_LambdaSchedule_class(){ , setMoleculeSchedule_function_value , ( bp::arg("pert_mol_id"), bp::arg("schedule") ) , bp::release_gil_policy() - , "" ); + , "Set schedule as the molecule-specific schedule for the\n perturbable molecule (or part of molecule) that is identified by the\n passed pert_mol_id. This schedule will be used to control\n all of the levers for this molecule (or part of molecule),\n and replaces any levers provided by this schedule\n" ); + + } + { //::SireCAS::LambdaSchedule::standard_annihilate + + typedef ::SireCAS::LambdaSchedule ( *standard_annihilate_function_type )( bool ); + standard_annihilate_function_type standard_annihilate_function_value( &::SireCAS::LambdaSchedule::standard_annihilate ); + + LambdaSchedule_exposer.def( + "standard_annihilate" + , standard_annihilate_function_value + , ( bp::arg("perturbed_is_annihilated")=(bool)(true) ) + , "Return a schedule that can be used for a standard double-annihilation\n free energy perturbation. If `perturbed_is_annihilated` is true, then\n the perturbed state is annihilated, otherwise the reference state is\n annihilated.\n" ); } { //::SireCAS::LambdaSchedule::standard_decouple @@ -759,7 +809,7 @@ void register_LambdaSchedule_class(){ "standard_decouple" , standard_decouple_function_value , ( bp::arg("perturbed_is_decoupled")=(bool)(true) ) - , "" ); + , "Return a schedule that can be used for a standard double-decoupling\n free energy perturbation. If `perturbed_is_decoupled` is true, then\n the perturbed state is decoupled, otherwise the reference state is\n decoupled.\n" ); } { //::SireCAS::LambdaSchedule::standard_morph @@ -784,7 +834,7 @@ void register_LambdaSchedule_class(){ , takeMoleculeSchedule_function_value , ( bp::arg("pert_mol_id") ) , bp::release_gil_policy() - , "" ); + , "Remove the perturbable molecule-specific schedule associated\n with the perturbable molecule (or part of molecule) that is\n identified by the passed pert_mol_id. This returns the\n schedule that was removed. If no such schedule exists, then\n a copy of this schedule is returned.\n" ); } { //::SireCAS::LambdaSchedule::toString @@ -823,11 +873,13 @@ void register_LambdaSchedule_class(){ , "" ); } + LambdaSchedule_exposer.staticmethod( "charge_scaled_annihilate" ); LambdaSchedule_exposer.staticmethod( "charge_scaled_decouple" ); LambdaSchedule_exposer.staticmethod( "charge_scaled_morph" ); LambdaSchedule_exposer.staticmethod( "final" ); LambdaSchedule_exposer.staticmethod( "initial" ); LambdaSchedule_exposer.staticmethod( "lam" ); + LambdaSchedule_exposer.staticmethod( "standard_annihilate" ); LambdaSchedule_exposer.staticmethod( "standard_decouple" ); LambdaSchedule_exposer.staticmethod( "standard_morph" ); LambdaSchedule_exposer.staticmethod( "typeName" ); diff --git a/wrapper/Convert/SireOpenMM/LambdaLever.pypp.cpp b/wrapper/Convert/SireOpenMM/LambdaLever.pypp.cpp index 4602fc721..ac45c54ee 100644 --- a/wrapper/Convert/SireOpenMM/LambdaLever.pypp.cpp +++ b/wrapper/Convert/SireOpenMM/LambdaLever.pypp.cpp @@ -7,12 +7,20 @@ namespace bp = boost::python; +#include "SireBase/arrayproperty.hpp" + +#include "SireBase/propertymap.h" + #include "SireCAS/values.h" #include "lambdalever.h" #include "tostring.h" +#include "SireBase/arrayproperty.hpp" + +#include "SireBase/propertymap.h" + #include "SireCAS/values.h" #include "lambdalever.h" @@ -96,6 +104,19 @@ void register_LambdaLever_class(){ , bp::release_gil_policy() , "Get the C++ type of the force called name. Returns an\n empty string if there is no such force\n" ); + } + { //::SireOpenMM::LambdaLever::getLeverValues + + typedef ::SireBase::PropertyList ( ::SireOpenMM::LambdaLever::*getLeverValues_function_type)( ::QVector< double > const &,::SireOpenMM::PerturbableOpenMMMolecule const & ) const; + getLeverValues_function_type getLeverValues_function_value( &::SireOpenMM::LambdaLever::getLeverValues ); + + LambdaLever_exposer.def( + "getLeverValues" + , getLeverValues_function_value + , ( bp::arg("lambda_values"), bp::arg("mol") ) + , bp::release_gil_policy() + , "" ); + } { //::SireOpenMM::LambdaLever::getPerturbableMoleculeMaps diff --git a/wrapper/Convert/SireOpenMM/_SireOpenMM_free_functions.pypp.cpp b/wrapper/Convert/SireOpenMM/_SireOpenMM_free_functions.pypp.cpp index 172713bbb..e75947576 100644 --- a/wrapper/Convert/SireOpenMM/_SireOpenMM_free_functions.pypp.cpp +++ b/wrapper/Convert/SireOpenMM/_SireOpenMM_free_functions.pypp.cpp @@ -991,8 +991,18 @@ namespace bp = boost::python; #include +#include + +#include + +#include + +#include + #include +#include + #include #include @@ -1021,8 +1031,18 @@ namespace bp = boost::python; #include +#include + +#include + +#include + +#include + #include +#include + #include #include @@ -1051,8 +1071,18 @@ namespace bp = boost::python; #include +#include + +#include + +#include + +#include + #include +#include + #include #include @@ -1081,8 +1111,18 @@ namespace bp = boost::python; #include +#include + +#include + +#include + +#include + #include +#include + #include #include diff --git a/wrapper/Convert/SireOpenMM/_perturbablemol.py b/wrapper/Convert/SireOpenMM/_perturbablemol.py index b6b4da935..8697ba817 100644 --- a/wrapper/Convert/SireOpenMM/_perturbablemol.py +++ b/wrapper/Convert/SireOpenMM/_perturbablemol.py @@ -5,9 +5,139 @@ "_changed_torsions", "_changed_exceptions", "_changed_constraints", + "_get_lever_values", ] +def _get_lever_values( + obj, + schedule=None, + lambda_values=None, + num_lambda: int = 101, + to_pandas: bool = True, +): + """ + Return the value of all of the parameters for this perturbable molecule + at all of the specified values of lambda, given the passed + lambda schedule. If no schedule is passed then a default morph + will be used. Return this as a pandas DataFrame if 'to_pandas' is True + + If a pandas DataFrame is returned then note the following two points: + + 1. Note that this function will only return the values of parameters + that change during the morph. If a parameter does not change then + it is not included. + + 2. Also note that columns are merged together if they have identical + values. You can see which columns have been merged by looking at the + "merged" attribute of the returned DataFrame (e.g. 'df.attrs["merged"]') + + Otherwise, the raw data is returned as a set of dictionaries with + no additional processing. + + Parameters + ---------- + + schedule: LambdaSchedule, optional, default=None + The lambda schedule to use for the morph. If this is not + passed then a default morph will be used + + lambda_values: list[float], optional, default=None + A list of lambda values to evaluate. If this is not passed + then the lambda values will be auto-generated based on an + even spacing between 0 and 1 of 'num_lambda' points + + num_lambda: int, optional, default=101 + The number of lambda values to evaluate if 'lambda_values' + is not passed + + to_pandas: bool, optional, default=True + Whether or not to return the result as a pandas DataFrame + (defaults to True) + + Returns + ------- + + pandas.DataFrame or dict + A pandas DataFrame containing the values of the parameters + at each of the lambda values, or a dictionary containing + the values of the parameters at each of the lambda values + """ + if lambda_values is None: + import numpy as np + + lambda_values = np.linspace(0.0, 1.0, num_lambda) + + lambda_values = [float(x) for x in lambda_values] + + if schedule is None: + from ...cas import LambdaSchedule + + schedule = LambdaSchedule.standard_morph() + + from . import LambdaLever + + lever = LambdaLever() + lever.set_schedule(schedule) + + results = lever.get_lever_values(lambda_values=lambda_values, mol=obj) + + if to_pandas: + import pandas as pd + + colnames = results[0] + + if len(colnames) < 2: + return None + + columns = results + columns.pop_front() + + results = {} + + merged = {} + + # only add in columns that change values + for i in range(len(colnames)): + column = columns[i] + + if len(column) > 1: + changed = False + + for j in range(1, len(column)): + if column[j] != column[j - 1]: + changed = True + break + + if not changed: + continue + + colname = colnames[i].replace("lambda", "λ") + + column = [x for x in column] + + # see if this is a duplicate of existing columns + is_duplicate = None + for key, value in results.items(): + if key != "λ" and value == column: + is_duplicate = key + + if is_duplicate is None: + if colname != "λ": + merged[colname] = [] + + results[colname] = [x for x in column] + else: + merged[is_duplicate].append(colname) + + results = pd.DataFrame(results) + results = results.set_index("λ") + + results.attrs["merged"] = merged + + return results + + def _name(atom): return f"{atom.name().value()}:{atom.number().value()}" diff --git a/wrapper/Convert/SireOpenMM/_sommcontext.py b/wrapper/Convert/SireOpenMM/_sommcontext.py index 8f3c23d79..3757b0078 100644 --- a/wrapper/Convert/SireOpenMM/_sommcontext.py +++ b/wrapper/Convert/SireOpenMM/_sommcontext.py @@ -294,3 +294,20 @@ def get_constraints(self): ) return constraints + + def to_xml(self, f=None): + """ + Save the current state of the dynamics to XML. + This is mostly used for debugging. This will return the + XML string if 'f' is None. Otherwise it will write the + XML to 'f' (either a filename, or a FILE object) + """ + from openmm.openmm import XmlSerializer as _XmlSerializer + + if f is None: + return _XmlSerializer.serialize(self.getSystem()) + elif isinstance(f, str): + with open(f, "w") as handle: + handle.write(_XmlSerializer.serialize(self.getSystem())) + else: + f.write(_XmlSerializer.serialize(self.getSystem())) diff --git a/wrapper/Convert/SireOpenMM/lambdalever.cpp b/wrapper/Convert/SireOpenMM/lambdalever.cpp index 59ccd848a..f44b38f90 100644 --- a/wrapper/Convert/SireOpenMM/lambdalever.cpp +++ b/wrapper/Convert/SireOpenMM/lambdalever.cpp @@ -28,12 +28,16 @@ #include "lambdalever.h" +#include "SireBase/propertymap.h" +#include "SireBase/arrayproperty.hpp" + #include "SireCAS/values.h" #include "tostring.h" using namespace SireOpenMM; using namespace SireCAS; +using namespace SireBase; ////// ////// Implementation of MolLambdaCache @@ -402,6 +406,720 @@ get_exception(int atom0, int atom1, int start_index, alpha, kappa); } +/** Get all of the lever values that would be set for the passed + * lambda values using the current context. This returns a PropertyList + * of columns, where each column is a PropertyMap with the column name + * and either double or QString array property of values. + * + * This is designed to be used by a higher-level python function that + * will convert this output into, e.g. a pandas DataFrame + */ +PropertyList LambdaLever::getLeverValues(const QVector &lambda_values, + const PerturbableOpenMMMolecule &mol) const +{ + if (lambda_values.isEmpty() or this->lambda_schedule.isNull() or mol.isNull()) + return PropertyList(); + + PropertyList ret; + + const auto &schedule = this->lambda_schedule.getMoleculeSchedule(0); + + QVector column_names; + + column_names.append("lambda"); + + QVector lamvals; + QVector> lever_values; + + bool is_first = true; + + for (auto lambda_value : lambda_values) + { + int idx = 0; + + lambda_value = this->lambda_schedule.clamp(lambda_value); + + lamvals.append(lambda_value); + + const auto &cache = this->lambda_cache.get(0, lambda_value); + + QVector vals; + + const auto morphed_charges = cache.morph( + schedule, + "clj", "charge", + mol.getCharges0(), + mol.getCharges1()); + + vals += morphed_charges; + + if (is_first) + { + for (int i = 0; i < morphed_charges.count(); ++i) + { + column_names.append(QString("clj-charge-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : vals) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_sigmas = cache.morph( + schedule, + "clj", "sigma", + mol.getSigmas0(), + mol.getSigmas1()); + + if (is_first) + { + for (int i = 0; i < morphed_sigmas.count(); ++i) + { + column_names.append(QString("clj-sigma-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_sigmas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_epsilons = cache.morph( + schedule, + "clj", "epsilon", + mol.getEpsilons0(), + mol.getEpsilons1()); + + if (is_first) + { + for (int i = 0; i < morphed_epsilons.count(); ++i) + { + column_names.append(QString("clj-epsilon-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_epsilons) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_alphas = cache.morph( + schedule, + "clj", "alpha", + mol.getAlphas0(), + mol.getAlphas1()); + + if (is_first) + { + for (int i = 0; i < morphed_alphas.count(); ++i) + { + column_names.append(QString("clj-alpha-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_alphas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_kappas = cache.morph( + schedule, + "clj", "kappa", + mol.getKappas0(), + mol.getKappas1()); + + if (is_first) + { + for (int i = 0; i < morphed_kappas.count(); ++i) + { + column_names.append(QString("clj-kappa-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_kappas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_charge_scale = cache.morph( + schedule, + "clj", "charge_scale", + mol.getChargeScales0(), + mol.getChargeScales1()); + + if (is_first) + { + for (int i = 0; i < morphed_charge_scale.count(); ++i) + { + column_names.append(QString("clj-charge_scale-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_charge_scale) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_lj_scale = cache.morph( + schedule, + "clj", "lj_scale", + mol.getLJScales0(), + mol.getLJScales1()); + + if (is_first) + { + for (int i = 0; i < morphed_lj_scale.count(); ++i) + { + column_names.append(QString("clj-lj_scale-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_lj_scale) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost_charges = cache.morph( + schedule, + "ghost/ghost", "charge", + mol.getCharges0(), + mol.getCharges1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost_charges.count(); ++i) + { + column_names.append(QString("ghost/ghost-charge-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost_charges) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost_sigmas = cache.morph( + schedule, + "ghost/ghost", "sigma", + mol.getSigmas0(), + mol.getSigmas1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost_sigmas.count(); ++i) + { + column_names.append(QString("ghost/ghost-sigma-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost_sigmas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost_epsilons = cache.morph( + schedule, + "ghost/ghost", "epsilon", + mol.getEpsilons0(), + mol.getEpsilons1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost_epsilons.count(); ++i) + { + column_names.append(QString("ghost/ghost-epsilon-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost_epsilons) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost_alphas = cache.morph( + schedule, + "ghost/ghost", "alpha", + mol.getAlphas0(), + mol.getAlphas1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost_alphas.count(); ++i) + { + column_names.append(QString("ghost/ghost-alpha-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost_alphas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost_kappas = cache.morph( + schedule, + "ghost/ghost", "kappa", + mol.getKappas0(), + mol.getKappas1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost_kappas.count(); ++i) + { + column_names.append(QString("ghost/ghost-kappa-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost_kappas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_nonghost_charges = cache.morph( + schedule, + "ghost/non-ghost", "charge", + mol.getCharges0(), + mol.getCharges1()); + + if (is_first) + { + for (int i = 0; i < morphed_nonghost_charges.count(); ++i) + { + column_names.append(QString("ghost/non-ghost-charge-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_nonghost_charges) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_nonghost_sigmas = cache.morph( + schedule, + "ghost/non-ghost", "sigma", + mol.getSigmas0(), + mol.getSigmas1()); + + if (is_first) + { + for (int i = 0; i < morphed_nonghost_sigmas.count(); ++i) + { + column_names.append(QString("ghost/non-ghost-sigma-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_nonghost_sigmas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_nonghost_epsilons = cache.morph( + schedule, + "ghost/non-ghost", "epsilon", + mol.getEpsilons0(), + mol.getEpsilons1()); + + if (is_first) + { + for (int i = 0; i < morphed_nonghost_epsilons.count(); ++i) + { + column_names.append(QString("ghost/non-ghost-epsilon-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_nonghost_epsilons) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_nonghost_alphas = cache.morph( + schedule, + "ghost/non-ghost", "alpha", + mol.getAlphas0(), + mol.getAlphas1()); + + if (is_first) + { + for (int i = 0; i < morphed_nonghost_alphas.count(); ++i) + { + column_names.append(QString("ghost/non-ghost-alpha-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_nonghost_alphas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_nonghost_kappas = cache.morph( + schedule, + "ghost/non-ghost", "kappa", + mol.getKappas0(), + mol.getKappas1()); + + if (is_first) + { + for (int i = 0; i < morphed_nonghost_kappas.count(); ++i) + { + column_names.append(QString("ghost/non-ghost-kappa-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_nonghost_kappas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_charges = cache.morph( + schedule, + "ghost-14", "charge", + mol.getCharges0(), + mol.getCharges1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_charges.count(); ++i) + { + column_names.append(QString("ghost-14-charge-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_charges) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_sigmas = cache.morph( + schedule, + "ghost-14", "sigma", + mol.getSigmas0(), + mol.getSigmas1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_sigmas.count(); ++i) + { + column_names.append(QString("ghost-14-sigma-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_sigmas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_epsilons = cache.morph( + schedule, + "ghost-14", "epsilon", + mol.getEpsilons0(), + mol.getEpsilons1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_epsilons.count(); ++i) + { + column_names.append(QString("ghost-14-epsilon-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_epsilons) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_alphas = cache.morph( + schedule, + "ghost-14", "alpha", + mol.getAlphas0(), + mol.getAlphas1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_alphas.count(); ++i) + { + column_names.append(QString("ghost-14-alpha-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_alphas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_kappas = cache.morph( + schedule, + "ghost-14", "kappa", + mol.getKappas0(), + mol.getKappas1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_kappas.count(); ++i) + { + column_names.append(QString("ghost-14-kappa-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_kappas) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_charge_scale = cache.morph( + schedule, + "ghost-14", "charge_scale", + mol.getChargeScales0(), + mol.getChargeScales1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_charge_scale.count(); ++i) + { + column_names.append(QString("ghost-14-charge_scale-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_charge_scale) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_ghost14_lj_scale = cache.morph( + schedule, + "ghost-14", "lj_scale", + mol.getLJScales0(), + mol.getLJScales1()); + + if (is_first) + { + for (int i = 0; i < morphed_ghost14_lj_scale.count(); ++i) + { + column_names.append(QString("ghost-14-lj_scale-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_ghost14_lj_scale) + { + lever_values[idx].append(val); + idx += 1; + } + + auto perturbable_constraints = mol.getPerturbableConstraints(); + + const auto &idxs = boost::get<0>(perturbable_constraints); + const auto &r0_0 = boost::get<1>(perturbable_constraints); + const auto &r0_1 = boost::get<2>(perturbable_constraints); + + if (not idxs.isEmpty()) + { + const auto morphed_constraint_length = cache.morph( + schedule, + "bond", "bond_length", "constraint", + r0_0, r0_1); + + if (is_first) + { + for (int i = 0; i < morphed_constraint_length.count(); ++i) + { + column_names.append(QString("bond-constraint-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_constraint_length) + { + lever_values[idx].append(val); + idx += 1; + } + } + + const auto morphed_bond_k = cache.morph( + schedule, + "bond", "bond_k", + mol.getBondKs0(), + mol.getBondKs1()); + + if (is_first) + { + for (int i = 0; i < morphed_bond_k.count(); ++i) + { + column_names.append(QString("bond-bond_k-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_bond_k) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_bond_length = cache.morph( + schedule, + "bond", "bond_length", + mol.getBondLengths0(), + mol.getBondLengths1()); + + if (is_first) + { + for (int i = 0; i < morphed_bond_length.count(); ++i) + { + column_names.append(QString("bond-bond_length-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_bond_length) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_angle_k = cache.morph( + schedule, + "angle", "angle_k", + mol.getAngleKs0(), + mol.getAngleKs1()); + + if (is_first) + { + for (int i = 0; i < morphed_angle_k.count(); ++i) + { + column_names.append(QString("angle-angle_k-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_angle_k) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_angle_size = cache.morph( + schedule, + "angle", "angle_size", + mol.getAngleSizes0(), + mol.getAngleSizes1()); + + if (is_first) + { + for (int i = 0; i < morphed_angle_size.count(); ++i) + { + column_names.append(QString("angle-angle_size-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_angle_size) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_torsion_phase = cache.morph( + schedule, + "torsion", "torsion_phase", + mol.getTorsionPhases0(), + mol.getTorsionPhases1()); + + if (is_first) + { + for (int i = 0; i < morphed_torsion_phase.count(); ++i) + { + column_names.append(QString("torsion-torsion_phase-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_torsion_phase) + { + lever_values[idx].append(val); + idx += 1; + } + + const auto morphed_torsion_k = cache.morph( + schedule, + "torsion", "torsion_k", + mol.getTorsionKs0(), + mol.getTorsionKs1()); + + if (is_first) + { + for (int i = 0; i < morphed_torsion_k.count(); ++i) + { + column_names.append(QString("torsion-torsion_k-%1").arg(i + 1)); + lever_values.append(QVector()); + } + } + + for (const auto &val : morphed_torsion_k) + { + lever_values[idx].append(val); + idx += 1; + } + + is_first = false; + } + + ret.append(StringArrayProperty(column_names)); + ret.append(DoubleArrayProperty(lamvals)); + + for (const auto &column : lever_values) + { + ret.append(DoubleArrayProperty(column)); + } + + return ret; +} + /** Set the value of lambda in the passed context. Returns the * actual value of lambda set. */ @@ -1042,7 +1760,6 @@ double LambdaLever::setLambda(OpenMM::Context &context, // follow whatever is set by lambda, e.g. 'initial*lambda' // to switch them on, or `final*lambda` to switch them off) const double rho = lambda_schedule.morph("*", - restraint, 1.0, 1.0, lambda_value); diff --git a/wrapper/Convert/SireOpenMM/lambdalever.h b/wrapper/Convert/SireOpenMM/lambdalever.h index 13b8e3d0c..9bf0b60d7 100644 --- a/wrapper/Convert/SireOpenMM/lambdalever.h +++ b/wrapper/Convert/SireOpenMM/lambdalever.h @@ -112,6 +112,9 @@ namespace SireOpenMM const char *what() const; static const char *typeName(); + SireBase::PropertyList getLeverValues(const QVector &lambda_values, + const PerturbableOpenMMMolecule &mol) const; + double setLambda(OpenMM::Context &system, double lambda_value, bool update_constraints = true) const; diff --git a/wrapper/Convert/SireOpenMM/openmmmolecule.cpp b/wrapper/Convert/SireOpenMM/openmmmolecule.cpp index a69909e0a..7062c1451 100644 --- a/wrapper/Convert/SireOpenMM/openmmmolecule.cpp +++ b/wrapper/Convert/SireOpenMM/openmmmolecule.cpp @@ -141,11 +141,15 @@ OpenMMMolecule::OpenMMMolecule(const Molecule &mol, { constraint_type = CONSTRAIN_BONDS | CONSTRAIN_HANGLES | CONSTRAIN_NOT_HEAVY_PERTURBED; } + else if (c == "auto-bonds") + { + constraint_type = CONSTRAIN_AUTO_BONDS; + } else { throw SireError::invalid_key(QObject::tr( "Unrecognised constraint type '%1'. Valid values are " - "'none', 'h-bonds', " + "'none', 'auto-bonds', 'h-bonds', " "'h-bonds-not-perturbed', 'h-bonds-not-heavy-perturbed', " "'h-bonds-h-angles-not-perturbed', 'h-bonds-h-angles-not-heavy-perturbed' " "'bonds', 'bonds-not-perturbed', 'bonds-not-heavy-perturbed', " @@ -216,11 +220,15 @@ OpenMMMolecule::OpenMMMolecule(const Molecule &mol, { perturbable_constraint_type = CONSTRAIN_BONDS | CONSTRAIN_HANGLES | CONSTRAIN_NOT_HEAVY_PERTURBED; } + else if (c == "auto-bonds") + { + perturbable_constraint_type = CONSTRAIN_AUTO_BONDS; + } else { throw SireError::invalid_key(QObject::tr( "Unrecognised perturbable constraint type '%1'. Valid values are " - "'none', 'h-bonds', " + "'none', 'auto-bonds', 'h-bonds', " "'h-bonds-not-perturbed', 'h-bonds-not-heavy-perturbed', " "'h-bonds-h-angles-not-perturbed', 'h-bonds-h-angles-not-heavy-perturbed' " "'bonds', 'bonds-not-perturbed', 'bonds-not-heavy-perturbed', " @@ -736,6 +744,38 @@ void OpenMMMolecule::constructFromAmber(const Molecule &mol, dynamic_constraints = map["dynamic_constraints"].value().asABoolean(); } + double auto_constraints_factor = 10.0; + + if (map.specified("auto_constraints_factor")) + { + auto_constraints_factor = map["auto_constraints_factor"].value().asADouble(); + + if (auto_constraints_factor < 1) + { + auto_constraints_factor = 1; + } + else if (auto_constraints_factor > 1e6) + { + auto_constraints_factor = 1e6; + } + } + + double timestep_in_fs = 2.0; + + if (map.specified("timestep_in_fs")) + { + timestep_in_fs = map["timestep_in_fs"].value().asADouble(); + + if (timestep_in_fs < 1.0) + { + timestep_in_fs = 1.0; + } + else if (timestep_in_fs > 100) + { + timestep_in_fs = 100; + } + } + auto bonds = params.bonds(); if (is_perturbable) @@ -769,6 +809,7 @@ void OpenMMMolecule::constructFromAmber(const Molecule &mol, const double k = bondparam.k() * bond_k_to_openmm; const double r0 = bondparam.r0() * bond_r0_to_openmm; + double r0_1 = r0; if (k != 0) { @@ -787,13 +828,32 @@ void OpenMMMolecule::constructFromAmber(const Molecule &mol, } bool bond_is_not_constrained = true; + bool should_constrain_bond = false; - if ((not has_massless_atom) and ((this_constraint_type & CONSTRAIN_BONDS) or - (has_light_atom and (this_constraint_type & CONSTRAIN_HBONDS)))) + if (this_constraint_type == CONSTRAIN_AUTO_BONDS) { - bool should_constrain_bond = true; + // constrain the bond if its predicted vibrational frequency is less than + // 10 times the simulation timestep + const double mass0 = masses_data[atom0]; + const double mass1 = masses_data[atom1]; + + // masses in g mol-1 - this converts the reduced mass to kg + const static double mass_to_reduced_mass = 0.001 / SireUnits::mole.value(); + const double reduced_mass_in_kg = ((mass0 * mass1) / (mass0 + mass1)) * mass_to_reduced_mass; + + // k in kJ mol-1 nm-2 - this converts to J m-2 + const static double k_to_J_m2 = 4184 * 1e20 / SireUnits::mole.value(); + const double k_in_J_m2 = bondparam.k() * k_to_J_m2; - double r0_1 = r0; + // vibrational period in femtoseconds + const double vibrational_period = 2e15 * SireMaths::pi * std::sqrt(reduced_mass_in_kg / k_in_J_m2); + + should_constrain_bond = vibrational_period < auto_constraints_factor * timestep_in_fs; + } + else if ((not has_massless_atom) and ((this_constraint_type & CONSTRAIN_BONDS) or + (has_light_atom and (this_constraint_type & CONSTRAIN_HBONDS)))) + { + should_constrain_bond = true; if (is_perturbable) { @@ -832,23 +892,23 @@ void OpenMMMolecule::constructFromAmber(const Molecule &mol, } } } + } - if (should_constrain_bond) + if (should_constrain_bond) + { + if (dynamic_constraints and (std::abs(r0 - r0_1) > 1e-4)) // match to somd1 { - if (dynamic_constraints and (std::abs(r0 - r0_1) > 1e-4)) // match to somd1 - { - // this is a dynamic constraint that should change with lambda - this->perturbable_constraints.append(boost::make_tuple(atom0, atom1, r0, r0_1)); - } - else - { - // use the r0 for the bond - this->constraints.append(boost::make_tuple(atom0, atom1, r0)); - } - - constrained_pairs.insert(to_pair(atom0, atom1)); - bond_is_not_constrained = false; + // this is a dynamic constraint that should change with lambda + this->perturbable_constraints.append(boost::make_tuple(atom0, atom1, r0, r0_1)); + } + else + { + // use the r0 for the bond + this->constraints.append(boost::make_tuple(atom0, atom1, r0)); } + + constrained_pairs.insert(to_pair(atom0, atom1)); + bond_is_not_constrained = false; } if (include_constrained_energies or bond_is_not_constrained) @@ -2016,6 +2076,14 @@ PerturbableOpenMMMolecule::PerturbableOpenMMMolecule(const Molecule &mol, this->operator=(PerturbableOpenMMMolecule(OpenMMMolecule(mol, map))); } +/** Return whether or not this is null */ +bool PerturbableOpenMMMolecule::isNull() const +{ + return perturbed_atoms.isEmpty() and perturbed_bonds.isEmpty() and + perturbed_angs.isEmpty() and perturbed_dihs.isEmpty() and + perturbable_constraints.isEmpty(); +} + /** Construct from the passed OpenMMMolecule */ PerturbableOpenMMMolecule::PerturbableOpenMMMolecule(const OpenMMMolecule &mol) : ConcreteProperty() diff --git a/wrapper/Convert/SireOpenMM/openmmmolecule.h b/wrapper/Convert/SireOpenMM/openmmmolecule.h index 8215ed7d9..30420f0be 100644 --- a/wrapper/Convert/SireOpenMM/openmmmolecule.h +++ b/wrapper/Convert/SireOpenMM/openmmmolecule.h @@ -38,6 +38,8 @@ namespace SireOpenMM CONSTRAIN_HANGLES = 0x00001000, CONSTRAIN_NOT_PERTURBED = 0x00010000, CONSTRAIN_NOT_HEAVY_PERTURBED = 0x00100000, + CONSTRAIN_AUTO = 0x01000000, + CONSTRAIN_AUTO_BONDS = CONSTRAIN_BONDS | CONSTRAIN_AUTO, }; OpenMMMolecule(); @@ -224,6 +226,8 @@ namespace SireOpenMM PerturbableOpenMMMolecule *clone() const; + bool isNull() const; + QVector getAlphas0() const; QVector getAlphas1() const; diff --git a/wrapper/Convert/SireOpenMM/sire_to_openmm_system.cpp b/wrapper/Convert/SireOpenMM/sire_to_openmm_system.cpp index 8c399b5e7..bb4733f93 100644 --- a/wrapper/Convert/SireOpenMM/sire_to_openmm_system.cpp +++ b/wrapper/Convert/SireOpenMM/sire_to_openmm_system.cpp @@ -891,9 +891,10 @@ OpenMMMetaData SireOpenMM::sire_to_openmm_system(OpenMM::System &system, { nb14_expression = QString( "coul_nrg+lj_nrg;" - "coul_nrg=138.9354558466661*q*(((%1)/sqrt((%2*alpha)+r^2))-(kappa/r));" + "coul_nrg=138.9354558466661*q*(((%1)/sqrt((%2*alpha)+r_safe^2))-(kappa/r_safe));" "lj_nrg=four_epsilon*sig6*(sig6-1);" - "sig6=(sigma^6)/(%3*sigma^6 + r^6);") + "sig6=(sigma^6)/(%3*sigma^6 + r_safe^6);" + "r_safe=max(r, 0.001);") .arg(coulomb_power_expression("alpha", coulomb_power)) .arg(shift_coulomb) .arg(taylor_power_expression("alpha", taylor_power)) @@ -903,9 +904,10 @@ OpenMMMetaData SireOpenMM::sire_to_openmm_system(OpenMM::System &system, { nb14_expression = QString( "coul_nrg+lj_nrg;" - "coul_nrg=138.9354558466661*q*(((%1)/sqrt((%2*alpha)+r^2))-(kappa/r));" + "coul_nrg=138.9354558466661*q*(((%1)/sqrt((%2*alpha)+r_safe^2))-(kappa/r_safe));" "lj_nrg=four_epsilon*sig6*(sig6-1);" - "sig6=(sigma^6)/(((sigma*delta) + r^2)^3);" + "sig6=(sigma^6)/(((sigma*delta) + r_safe^2)^3);" + "r_safe=max(r, 0.001);" "delta=%3*alpha;") .arg(coulomb_power_expression("alpha", coulomb_power)) .arg(shift_coulomb) @@ -949,9 +951,10 @@ OpenMMMetaData SireOpenMM::sire_to_openmm_system(OpenMM::System &system, // kJ mol-1 given the units of charge (|e|) and distance (nm) // clj_expression = QString("coul_nrg+lj_nrg;" - "coul_nrg=138.9354558466661*q1*q2*(((%1)/sqrt((%2*max_alpha)+r^2))-(max_kappa/r));" + "coul_nrg=138.9354558466661*q1*q2*(((%1)/sqrt((%2*max_alpha)+r_safe^2))-(max_kappa/r_safe));" "lj_nrg=two_sqrt_epsilon1*two_sqrt_epsilon2*sig6*(sig6-1);" - "sig6=(sigma^6)/(%3*sigma^6 + r^6);" + "sig6=(sigma^6)/(%3*sigma^6 + r_safe^6);" + "r_safe=max(r, 0.001);" "max_kappa=max(kappa1, kappa2);" "max_alpha=max(alpha1, alpha2);" "sigma=half_sigma1+half_sigma2;") @@ -986,10 +989,11 @@ OpenMMMetaData SireOpenMM::sire_to_openmm_system(OpenMM::System &system, // kJ mol-1 given the units of charge (|e|) and distance (nm) // clj_expression = QString("coul_nrg+lj_nrg;" - "coul_nrg=138.9354558466661*q1*q2*(((%1)/sqrt((%2*max_alpha)+r^2))-(max_kappa/r));" + "coul_nrg=138.9354558466661*q1*q2*(((%1)/sqrt((%2*max_alpha)+r_safe^2))-(max_kappa/r_safe));" "lj_nrg=two_sqrt_epsilon1*two_sqrt_epsilon2*sig6*(sig6-1);" - "sig6=(sigma^6)/(((sigma*delta) + r^2)^3);" + "sig6=(sigma^6)/(((sigma*delta) + r_safe^2)^3);" "delta=%3*max_alpha;" + "r_safe=max(r, 0.001);" "max_kappa=max(kappa1, kappa2);" "max_alpha=max(alpha1, alpha2);" "sigma=half_sigma1+half_sigma2;") @@ -1184,8 +1188,17 @@ OpenMMMetaData SireOpenMM::sire_to_openmm_system(OpenMM::System &system, // now the reference CLJ parameters const auto &clj = cljs_data[j]; + // make sure that charges are added here - if all are zero, + // the NonbondedForce will not include support for charge! + double charge = boost::get<0>(clj); + + if (charge == 0.0) + { + charge = 1.0e-6; + } + // reduced_q - custom_params[0] = boost::get<0>(clj); + custom_params[0] = charge; // half_sigma custom_params[1] = 0.5 * boost::get<1>(clj); // two_sqrt_epsilon @@ -1211,13 +1224,13 @@ OpenMMMetaData SireOpenMM::sire_to_openmm_system(OpenMM::System &system, // calculated using the ghost forcefields // (the ghost forcefields include a coulomb term // that subtracts from whatever was calculated here) - cljff->addParticle(boost::get<0>(clj), 0.0, 0.0); + cljff->addParticle(charge, 0.0, 0.0); } else { // this isn't a ghost atom. Record this fact and // just add it to the standard cljff as normal - cljff->addParticle(boost::get<0>(clj), boost::get<1>(clj), + cljff->addParticle(charge, boost::get<1>(clj), boost::get<2>(clj)); non_ghost_atoms.insert(atom_index); } diff --git a/wrapper/Convert/SireRDKit/sire_rdkit.cpp b/wrapper/Convert/SireRDKit/sire_rdkit.cpp index 7eecc3fdc..f5574cdc4 100644 --- a/wrapper/Convert/SireRDKit/sire_rdkit.cpp +++ b/wrapper/Convert/SireRDKit/sire_rdkit.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" @@ -612,6 +613,29 @@ namespace SireRDKit molecule.addAtom(true); auto a = molecule.getActiveAtom(); + // create a AtomPDBResidueInfo object for the atom, and + // populate it with the name and residue information + auto info = new RDKit::AtomPDBResidueInfo(); + + info->setSerialNumber(atom.number().value()); + info->setName(atom.name().value().toStdString()); + + if (atom.isWithinResidue()) + { + auto residue = atom.residue(); + info->setResidueName(residue.name().value().toStdString()); + info->setResidueNumber(residue.number().value()); + } + + if (atom.isWithinChain()) + { + auto chain = atom.chain(); + info->setChainId(chain.name().value().toStdString()); + } + + a->setMonomerInfo(info); + a->setProp("molFileAlias", info->getName()); + const auto element = atom.property(map["element"]); a->setAtomicNum(element.nProtons()); @@ -847,8 +871,6 @@ namespace SireRDKit } auto cg = Molecule().edit().rename(molname).add(SireMol::CGName("0")); - auto res = cg.molecule().add(SireMol::ResNum(1)); - res.rename(SireMol::ResName("LIG")); int n = 0; @@ -860,12 +882,101 @@ namespace SireRDKit { atom_to_idx[atom] = n; n += 1; - auto a = cg.add(SireMol::AtomNum(n)); + + // see if there is a PDBResidueInfo object for this atom + const auto *info = atom->getMonomerInfo(); + + SireMol::AtomName atomname; + SireMol::AtomNum atomnum; + SireMol::ResName resname; + SireMol::ResNum resnum; + SireMol::ChainName chainname; + + if (info != 0) + { + atomname = SireMol::AtomName(QString::fromStdString(info->getName())); + + if (info->getMonomerType() == RDKit::AtomMonomerInfo::PDBRESIDUE) + { + auto resinfo = static_cast(info); + + atomname = SireMol::AtomName(QString::fromStdString(resinfo->getName())); + atomnum = SireMol::AtomNum(resinfo->getSerialNumber()); + resname = SireMol::ResName(QString::fromStdString(resinfo->getResidueName())); + resnum = SireMol::ResNum(resinfo->getResidueNumber()); + chainname = SireMol::ChainName(QString::fromStdString(resinfo->getChainId())); + } + else + { + atomnum = SireMol::AtomNum(n); + } + } + else + { + atomnum = SireMol::AtomNum(n); + } + + // check the molFileAlias property if the atom name hasn't been set + if (atomname.value().isEmpty()) + { + std::string alias; + + if (atom->getPropIfPresent("molFileAlias", alias)) + { + atomname = SireMol::AtomName(QString::fromStdString(alias)); + } + } + + if (atomname.value().isEmpty()) + { + atomname = SireMol::AtomName(QString("%1%2").arg(QString::fromStdString(atom->getSymbol())).arg(n)); + } + + // place all atoms into the same cutgroup + auto a = cg.add(atomnum); + + // now find a residue + if (resname.value().isEmpty()) + { + resname = SireMol::ResName("LIG"); + } + + if (resnum.isNull()) + { + resnum = SireMol::ResNum(1); + } + + // find this residue - if it doesn't exist, then create it + SireMol::ResStructureEditor res; + + try + { + res = cg.molecule().select(resnum); + } + catch (...) + { + res = cg.molecule().add(resnum); + res.rename(resname); + } + + if (not chainname.value().isEmpty()) + { + SireMol::ChainStructureEditor chain; + + try + { + chain = cg.molecule().select(chainname); + } + catch (...) + { + chain = cg.molecule().add(chainname); + } + + res.reparent(chain.name()); + } + a.reparent(res.number()); - a.rename(SireMol::AtomName( - QString("%1%2") - .arg(QString::fromStdString(atom->getSymbol())) - .arg(n))); + a.rename(atomname); set_prop(a, "element", SireMol::Element(atom->getAtomicNum()), map); set_prop(a, "formal_charge", atom->getFormalCharge() * SireUnits::mod_electron, map); diff --git a/wrapper/Convert/__init__.py b/wrapper/Convert/__init__.py index 266d6dd68..31f915362 100644 --- a/wrapper/Convert/__init__.py +++ b/wrapper/Convert/__init__.py @@ -89,6 +89,7 @@ def smarts_to_rdkit(*args, **kwargs): _changed_torsions, _changed_exceptions, _changed_constraints, + _get_lever_values, ) from ._SireOpenMM import LambdaLever, PerturbableOpenMMMolecule, OpenMMMetaData @@ -105,6 +106,7 @@ def smarts_to_rdkit(*args, **kwargs): PerturbableOpenMMMolecule.changed_torsions = _changed_torsions PerturbableOpenMMMolecule.changed_exceptions = _changed_exceptions PerturbableOpenMMMolecule.changed_constraints = _changed_constraints + PerturbableOpenMMMolecule.get_lever_values = _get_lever_values _has_openmm = True @@ -162,6 +164,7 @@ def sire_to_openmm(mols, map): timestep_in_fs = timestep.to(femtosecond) timestep = timestep.to(picosecond) * openmm.unit.picosecond + map.set("timestep_in_fs", timestep_in_fs) ensemble = Ensemble(map=map) diff --git a/wrapper/MM/AmberAngle.pypp.cpp b/wrapper/MM/AmberAngle.pypp.cpp index e350ce314..3a0c92514 100644 --- a/wrapper/MM/AmberAngle.pypp.cpp +++ b/wrapper/MM/AmberAngle.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" diff --git a/wrapper/MM/AmberBond.pypp.cpp b/wrapper/MM/AmberBond.pypp.cpp index 6defbb1a8..cd1d926e2 100644 --- a/wrapper/MM/AmberBond.pypp.cpp +++ b/wrapper/MM/AmberBond.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" diff --git a/wrapper/MM/AmberDihPart.pypp.cpp b/wrapper/MM/AmberDihPart.pypp.cpp index 145eb49c5..901450127 100644 --- a/wrapper/MM/AmberDihPart.pypp.cpp +++ b/wrapper/MM/AmberDihPart.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" diff --git a/wrapper/MM/AmberDihedral.pypp.cpp b/wrapper/MM/AmberDihedral.pypp.cpp index 572d00d3d..de9fce62c 100644 --- a/wrapper/MM/AmberDihedral.pypp.cpp +++ b/wrapper/MM/AmberDihedral.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" diff --git a/wrapper/MM/AmberNB14.pypp.cpp b/wrapper/MM/AmberNB14.pypp.cpp index 2e7423dab..de9f3bd99 100644 --- a/wrapper/MM/AmberNB14.pypp.cpp +++ b/wrapper/MM/AmberNB14.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" diff --git a/wrapper/MM/AmberParams.pypp.cpp b/wrapper/MM/AmberParams.pypp.cpp index 10db71762..a1306fe96 100644 --- a/wrapper/MM/AmberParams.pypp.cpp +++ b/wrapper/MM/AmberParams.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" @@ -574,6 +576,18 @@ void register_AmberParams_class(){ , bp::release_gil_policy() , "Return the atom masses" ); + } + { //::SireMM::AmberParams::merge + + typedef ::SireBase::PropertyList ( ::SireMM::AmberParams::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::AmberParams::merge ); + + AmberParams_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMM::AmberParams::nb14s diff --git a/wrapper/MM/AtomLJs.pypp.cpp b/wrapper/MM/AtomLJs.pypp.cpp index 80ffcfe98..44b00dc65 100644 --- a/wrapper/MM/AtomLJs.pypp.cpp +++ b/wrapper/MM/AtomLJs.pypp.cpp @@ -7,8 +7,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/incremint.h" +#include "SireBase/propertylist.h" + #include "SireBase/quickcopy.hpp" #include "SireStream/datastream.h" @@ -493,6 +497,19 @@ void register_AtomLJs_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMM::LJParameter >::merge + + typedef SireMol::AtomProperty< SireMM::LJParameter > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMM::LJParameter >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMM::LJParameter >::merge ); + + AtomLJs_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMM::LJParameter >::nAtoms diff --git a/wrapper/MM/AtomPairs_CLJScaleFactor_.pypp.cpp b/wrapper/MM/AtomPairs_CLJScaleFactor_.pypp.cpp index 7c2035a26..690194983 100644 --- a/wrapper/MM/AtomPairs_CLJScaleFactor_.pypp.cpp +++ b/wrapper/MM/AtomPairs_CLJScaleFactor_.pypp.cpp @@ -180,6 +180,19 @@ void register_AtomPairs_CLJScaleFactor__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMM::AtomPairs< SireMM::CLJScaleFactor >::merge + + typedef SireMM::AtomPairs< SireMM::CLJScaleFactor > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMM::AtomPairs< SireMM::CLJScaleFactor >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::AtomPairs< SireMM::CLJScaleFactor >::merge ); + + AtomPairs_CLJScaleFactor__exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMM::AtomPairs< SireMM::CLJScaleFactor >::nAtoms diff --git a/wrapper/MM/AtomPairs_CoulombScaleFactor_.pypp.cpp b/wrapper/MM/AtomPairs_CoulombScaleFactor_.pypp.cpp index 78a736ccb..1f29b1983 100644 --- a/wrapper/MM/AtomPairs_CoulombScaleFactor_.pypp.cpp +++ b/wrapper/MM/AtomPairs_CoulombScaleFactor_.pypp.cpp @@ -180,6 +180,19 @@ void register_AtomPairs_CoulombScaleFactor__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMM::AtomPairs< SireMM::CoulombScaleFactor >::merge + + typedef SireMM::AtomPairs< SireMM::CoulombScaleFactor > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMM::AtomPairs< SireMM::CoulombScaleFactor >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::AtomPairs< SireMM::CoulombScaleFactor >::merge ); + + AtomPairs_CoulombScaleFactor__exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMM::AtomPairs< SireMM::CoulombScaleFactor >::nAtoms diff --git a/wrapper/MM/AtomPairs_LJScaleFactor_.pypp.cpp b/wrapper/MM/AtomPairs_LJScaleFactor_.pypp.cpp index 5a0a55eda..5f8f516a4 100644 --- a/wrapper/MM/AtomPairs_LJScaleFactor_.pypp.cpp +++ b/wrapper/MM/AtomPairs_LJScaleFactor_.pypp.cpp @@ -180,6 +180,19 @@ void register_AtomPairs_LJScaleFactor__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMM::AtomPairs< SireMM::LJScaleFactor >::merge + + typedef SireMM::AtomPairs< SireMM::LJScaleFactor > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMM::AtomPairs< SireMM::LJScaleFactor >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::AtomPairs< SireMM::LJScaleFactor >::merge ); + + AtomPairs_LJScaleFactor__exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMM::AtomPairs< SireMM::LJScaleFactor >::nAtoms diff --git a/wrapper/MM/CLJNBPairs.pypp.cpp b/wrapper/MM/CLJNBPairs.pypp.cpp index 0a164e5c8..c918920de 100644 --- a/wrapper/MM/CLJNBPairs.pypp.cpp +++ b/wrapper/MM/CLJNBPairs.pypp.cpp @@ -73,6 +73,18 @@ void register_CLJNBPairs_class(){ , bp::release_gil_policy() , "Return all of the excluded atoms for the atoms in the specified\n CutGroup, returned in a hash indexed by the AtomIdx of those\n atoms. This is equivalent to calling excludedAtoms individually,\n but is far more efficient if trying to get all of the\n excluded atoms in the whole molecule\n" ); + } + { //::SireMM::CLJNBPairs::merge + + typedef ::SireBase::PropertyList ( ::SireMM::CLJNBPairs::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::CLJNBPairs::merge ); + + CLJNBPairs_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMM::CLJNBPairs::nExcludedAtoms diff --git a/wrapper/MM/ExcludedPairs.pypp.cpp b/wrapper/MM/ExcludedPairs.pypp.cpp index 8d990c987..3b4c4d621 100644 --- a/wrapper/MM/ExcludedPairs.pypp.cpp +++ b/wrapper/MM/ExcludedPairs.pypp.cpp @@ -84,6 +84,18 @@ void register_ExcludedPairs_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMM::ExcludedPairs::merge + + typedef ::SireBase::PropertyList ( ::SireMM::ExcludedPairs::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::ExcludedPairs::merge ); + + ExcludedPairs_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMM::ExcludedPairs::nExcludedPairs diff --git a/wrapper/MM/FourAtomFunction.pypp.cpp b/wrapper/MM/FourAtomFunction.pypp.cpp index 6b20f2d18..2456677e9 100644 --- a/wrapper/MM/FourAtomFunction.pypp.cpp +++ b/wrapper/MM/FourAtomFunction.pypp.cpp @@ -8,8 +8,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/symbols.h" +#include "SireError/errors.h" + #include "SireMol/atommatcher.h" #include "SireMol/atomselection.h" diff --git a/wrapper/MM/FourAtomFunctions.pypp.cpp b/wrapper/MM/FourAtomFunctions.pypp.cpp index 8263ceda2..ff40dfe7d 100644 --- a/wrapper/MM/FourAtomFunctions.pypp.cpp +++ b/wrapper/MM/FourAtomFunctions.pypp.cpp @@ -7,8 +7,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/symbols.h" +#include "SireError/errors.h" + #include "SireMol/atommatcher.h" #include "SireMol/atomselection.h" @@ -123,6 +127,18 @@ void register_FourAtomFunctions_class(){ , bp::release_gil_policy() , "Clear the potential that acts over the improper identified by improperid\nThis clears all matching impropers, so 1-2-3-4 and 1-2-4-3\nThrow: SireMol::missing_atom\nThrow: SireError::invalid_index\n" ); + } + { //::SireMM::FourAtomFunctions::clear + + typedef void ( ::SireMM::FourAtomFunctions::*clear_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) ; + clear_function_type clear_function_value( &::SireMM::FourAtomFunctions::clear ); + + FourAtomFunctions_exposer.def( + "clear" + , clear_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Clear all functions that involve any of the atoms in atoms\n - if exclusive is true, then this only removes functions\n that exclusively involve these atoms - if false, then\n if removes functions that involve any of these atoms\n" ); + } { //::SireMM::FourAtomFunctions::clear @@ -224,6 +240,18 @@ void register_FourAtomFunctions_class(){ , bp::release_gil_policy() , "Return whether or not this is empty (has no potentials for any internals)" ); + } + { //::SireMM::FourAtomFunctions::merge + + typedef ::SireBase::PropertyList ( ::SireMM::FourAtomFunctions::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::FourAtomFunctions::merge ); + + FourAtomFunctions_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMM::FourAtomFunctions::nFunctions @@ -315,6 +343,18 @@ void register_FourAtomFunctions_class(){ , bp::release_gil_policy() , "Return the potential energy functions acting between the identified\nquads of atoms" ); + } + { //::SireMM::FourAtomFunctions::potentials + + typedef ::QVector< SireMM::FourAtomFunction > ( ::SireMM::FourAtomFunctions::*potentials_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) const; + potentials_function_type potentials_function_value( &::SireMM::FourAtomFunctions::potentials ); + + FourAtomFunctions_exposer.def( + "potentials" + , potentials_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Return the potential energy functions acting between the identified\natoms - if exclusive is true then only return potentials where\nall atoms are in the dihedral or improper\n" ); + } { //::SireMM::FourAtomFunctions::set diff --git a/wrapper/MM/LJException.pypp.cpp b/wrapper/MM/LJException.pypp.cpp index 2af1c90c1..cf1805cc4 100644 --- a/wrapper/MM/LJException.pypp.cpp +++ b/wrapper/MM/LJException.pypp.cpp @@ -7,8 +7,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/incremint.h" +#include "SireBase/propertylist.h" + #include "SireBase/quickcopy.hpp" #include "SireStream/datastream.h" diff --git a/wrapper/MM/LJExceptionID.pypp.cpp b/wrapper/MM/LJExceptionID.pypp.cpp index c1fe158ed..cc5842269 100644 --- a/wrapper/MM/LJExceptionID.pypp.cpp +++ b/wrapper/MM/LJExceptionID.pypp.cpp @@ -7,8 +7,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/incremint.h" +#include "SireBase/propertylist.h" + #include "SireBase/quickcopy.hpp" #include "SireStream/datastream.h" diff --git a/wrapper/MM/ThreeAtomFunction.pypp.cpp b/wrapper/MM/ThreeAtomFunction.pypp.cpp index fb446f073..96a5d3b2c 100644 --- a/wrapper/MM/ThreeAtomFunction.pypp.cpp +++ b/wrapper/MM/ThreeAtomFunction.pypp.cpp @@ -8,8 +8,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/symbols.h" +#include "SireError/errors.h" + #include "SireMol/atommatcher.h" #include "SireMol/atomselection.h" diff --git a/wrapper/MM/ThreeAtomFunctions.pypp.cpp b/wrapper/MM/ThreeAtomFunctions.pypp.cpp index 6338a305a..5dfeb3e2c 100644 --- a/wrapper/MM/ThreeAtomFunctions.pypp.cpp +++ b/wrapper/MM/ThreeAtomFunctions.pypp.cpp @@ -7,8 +7,12 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/symbols.h" +#include "SireError/errors.h" + #include "SireMol/atommatcher.h" #include "SireMol/atomselection.h" @@ -110,6 +114,18 @@ void register_ThreeAtomFunctions_class(){ , bp::release_gil_policy() , "Clear the potential that acts over the angle identified by angleid\nThis clears both 1-2-3 and 3-2-1\nThrow: SireMol::missing_atom\nThrow: SireError::invalid_index\n" ); + } + { //::SireMM::ThreeAtomFunctions::clear + + typedef void ( ::SireMM::ThreeAtomFunctions::*clear_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) ; + clear_function_type clear_function_value( &::SireMM::ThreeAtomFunctions::clear ); + + ThreeAtomFunctions_exposer.def( + "clear" + , clear_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Clear all functions that involve any of the atoms in atoms\n - if exclusive is true, then this only removes functions\n that exclusively involve these atoms - if false, then\n if removes functions that involve any of these atoms\n" ); + } { //::SireMM::ThreeAtomFunctions::clear @@ -198,6 +214,18 @@ void register_ThreeAtomFunctions_class(){ , bp::release_gil_policy() , "Return whether or not this is empty (has no potentials for any internals)" ); + } + { //::SireMM::ThreeAtomFunctions::merge + + typedef ::SireBase::PropertyList ( ::SireMM::ThreeAtomFunctions::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::ThreeAtomFunctions::merge ); + + ThreeAtomFunctions_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMM::ThreeAtomFunctions::nFunctions @@ -276,6 +304,18 @@ void register_ThreeAtomFunctions_class(){ , bp::release_gil_policy() , "Return the potential energy functions acting between the identified\ntriples of atoms" ); + } + { //::SireMM::ThreeAtomFunctions::potentials + + typedef ::QVector< SireMM::ThreeAtomFunction > ( ::SireMM::ThreeAtomFunctions::*potentials_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) const; + potentials_function_type potentials_function_value( &::SireMM::ThreeAtomFunctions::potentials ); + + ThreeAtomFunctions_exposer.def( + "potentials" + , potentials_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Return the potential energy functions acting between the identified\natoms - if exclusive is true then only return potentials where\nall atoms are in the angle\n" ); + } { //::SireMM::ThreeAtomFunctions::set diff --git a/wrapper/MM/TwoAtomFunction.pypp.cpp b/wrapper/MM/TwoAtomFunction.pypp.cpp index faaeffea5..a21e15e4d 100644 --- a/wrapper/MM/TwoAtomFunction.pypp.cpp +++ b/wrapper/MM/TwoAtomFunction.pypp.cpp @@ -8,6 +8,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/symbols.h" #include "SireError/errors.h" diff --git a/wrapper/MM/TwoAtomFunctions.pypp.cpp b/wrapper/MM/TwoAtomFunctions.pypp.cpp index a3dd07cce..45c42139c 100644 --- a/wrapper/MM/TwoAtomFunctions.pypp.cpp +++ b/wrapper/MM/TwoAtomFunctions.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireCAS/symbols.h" #include "SireError/errors.h" @@ -112,6 +114,18 @@ void register_TwoAtomFunctions_class(){ , bp::release_gil_policy() , "Clear the potential that acts over the bond identified by bondid\nNote that this removes both 1-2 and 2-1\nThrow: SireMol::missing_atom\nThrow: SireError::invalid_index\n" ); + } + { //::SireMM::TwoAtomFunctions::clear + + typedef void ( ::SireMM::TwoAtomFunctions::*clear_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) ; + clear_function_type clear_function_value( &::SireMM::TwoAtomFunctions::clear ); + + TwoAtomFunctions_exposer.def( + "clear" + , clear_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Clear all functions that invole any of the atoms in atoms\n - if exclusive is true, then this only removes functions\n that exclusively involve these atoms - if false, then\n if removes functions that involve any of these atoms\n" ); + } { //::SireMM::TwoAtomFunctions::clear @@ -200,6 +214,18 @@ void register_TwoAtomFunctions_class(){ , bp::release_gil_policy() , "Return whether or not this is empty (has no potentials for any internals)" ); + } + { //::SireMM::TwoAtomFunctions::merge + + typedef ::SireBase::PropertyList ( ::SireMM::TwoAtomFunctions::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMM::TwoAtomFunctions::merge ); + + TwoAtomFunctions_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMM::TwoAtomFunctions::nFunctions @@ -278,6 +304,18 @@ void register_TwoAtomFunctions_class(){ , bp::release_gil_policy() , "Return the potential energy functions acting between the identified\npairs of atoms" ); + } + { //::SireMM::TwoAtomFunctions::potentials + + typedef ::QVector< SireMM::TwoAtomFunction > ( ::SireMM::TwoAtomFunctions::*potentials_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) const; + potentials_function_type potentials_function_value( &::SireMM::TwoAtomFunctions::potentials ); + + TwoAtomFunctions_exposer.def( + "potentials" + , potentials_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Return the potential energy functions acting between the identified\npairs of atoms - if exclusive is true then only return potentials where\nboth atoms are in the bond\n" ); + } { //::SireMM::TwoAtomFunctions::set diff --git a/wrapper/Mol/AmberParameters.pypp.cpp b/wrapper/Mol/AmberParameters.pypp.cpp index 5781e5329..f3c859120 100644 --- a/wrapper/Mol/AmberParameters.pypp.cpp +++ b/wrapper/Mol/AmberParameters.pypp.cpp @@ -7,10 +7,14 @@ namespace bp = boost::python; +#include "SireError/errors.h" + #include "SireMol/angleid.h" #include "SireMol/atomidx.h" +#include "SireMol/atomidxmapping.h" + #include "SireMol/bondid.h" #include "SireMol/dihedralid.h" @@ -259,6 +263,18 @@ void register_AmberParameters_class(){ , bp::release_gil_policy() , "Return whether or not this flexibility is compatible with the molecule\nwhose info is in molinfo" ); + } + { //::SireMol::AmberParameters::merge + + typedef ::SireBase::PropertyList ( ::SireMol::AmberParameters::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AmberParameters::merge ); + + AmberParameters_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } AmberParameters_exposer.def( bp::self != bp::self ); { //::SireMol::AmberParameters::operator= diff --git a/wrapper/Mol/Atom.pypp.cpp b/wrapper/Mol/Atom.pypp.cpp index dc5c15bc2..c9d207273 100644 --- a/wrapper/Mol/Atom.pypp.cpp +++ b/wrapper/Mol/Atom.pypp.cpp @@ -48,8 +48,12 @@ namespace bp = boost::python; #include "atom.h" +#include "SireBase/console.h" + #include "SireBase/incremint.h" +#include "SireBase/propertylist.h" + #include "SireBase/quickcopy.hpp" #include "SireStream/datastream.h" @@ -104,8 +108,6 @@ namespace bp = boost::python; #include "atomradii.h" -#include "SireBase/propertylist.h" - #include "SireMaths/vector.h" #include "atomproperty.hpp" @@ -292,6 +294,18 @@ void register_Atom_class(){ Atom_exposer.def( bp::init< SireMol::MoleculeView const &, SireMol::AtomID const & >(( bp::arg("molview"), bp::arg("atomid") ), "Construct the atom that that is identified by ID atomid\nin the view molview - this atom must be within this view\nThrow: SireMol::missing_atom\nThrow: SireMol::duplicate_atom\nThrow: SireError::invalid_index\n") ); Atom_exposer.def( bp::init< SireMol::MoleculeData const &, SireMol::AtomID const & >(( bp::arg("moldata"), bp::arg("atomid") ), "Construct the atom that is identified by ID atomid\nin the molecule whose data is in moldata\nThrow: SireMol::missing_atom\nThrow: SireMol::duplicate_atom\nThrow: SireError::invalid_index\n") ); Atom_exposer.def( bp::init< SireMol::Atom const & >(( bp::arg("other") ), "Copy constructor") ); + { //::SireMol::Atom::alternateName + + typedef ::SireMol::AtomName ( ::SireMol::Atom::*alternateName_function_type)( ) const; + alternateName_function_type alternateName_function_value( &::SireMol::Atom::alternateName ); + + Atom_exposer.def( + "alternateName" + , alternateName_function_value + , bp::release_gil_policy() + , "Return the alternate name of the atom" ); + + } { //::SireMol::Atom::assertContains typedef void ( ::SireMol::Atom::*assertContains_function_type)( ::SireMol::AtomIdx ) const; diff --git a/wrapper/Mol/AtomBeads.pypp.cpp b/wrapper/Mol/AtomBeads.pypp.cpp index 54d1a9c62..dbf52bdbd 100644 --- a/wrapper/Mol/AtomBeads.pypp.cpp +++ b/wrapper/Mol/AtomBeads.pypp.cpp @@ -16,6 +16,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -359,6 +361,19 @@ void register_AtomBeads_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMol::BeadNum >::merge + + typedef SireMol::AtomProperty< SireMol::BeadNum > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMol::BeadNum >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMol::BeadNum >::merge ); + + AtomBeads_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMol::BeadNum >::nAtoms diff --git a/wrapper/Mol/AtomCharges.pypp.cpp b/wrapper/Mol/AtomCharges.pypp.cpp index d7540a710..cbf972a50 100644 --- a/wrapper/Mol/AtomCharges.pypp.cpp +++ b/wrapper/Mol/AtomCharges.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomCharges_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 0, 0, 1, 0, 0, 0 > >::merge + + typedef SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 0, 0, 1, 0, 0, 0 > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 0, 0, 1, 0, 0, 0 > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 0, 0, 1, 0, 0, 0 > >::merge ); + + AtomCharges_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 0, 0, 1, 0, 0, 0 > >::nAtoms diff --git a/wrapper/Mol/AtomChiralities.pypp.cpp b/wrapper/Mol/AtomChiralities.pypp.cpp index d2d9ecc82..40993f820 100644 --- a/wrapper/Mol/AtomChiralities.pypp.cpp +++ b/wrapper/Mol/AtomChiralities.pypp.cpp @@ -23,6 +23,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -366,6 +368,19 @@ void register_AtomChiralities_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMol::Chirality >::merge + + typedef SireMol::AtomProperty< SireMol::Chirality > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMol::Chirality >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMol::Chirality >::merge ); + + AtomChiralities_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMol::Chirality >::nAtoms diff --git a/wrapper/Mol/AtomCoords.pypp.cpp b/wrapper/Mol/AtomCoords.pypp.cpp index e724577d2..b06a0f95b 100644 --- a/wrapper/Mol/AtomCoords.pypp.cpp +++ b/wrapper/Mol/AtomCoords.pypp.cpp @@ -29,6 +29,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + #include "SireMaths/quaternion.h" #include "SireMaths/matrix.h" @@ -403,6 +405,19 @@ void register_AtomCoords_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMaths::Vector >::merge + + typedef SireMol::AtomProperty< SireMaths::Vector > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMaths::Vector >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMaths::Vector >::merge ); + + AtomCoords_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMaths::Vector >::nAtoms diff --git a/wrapper/Mol/AtomDoubleArrayProperty.pypp.cpp b/wrapper/Mol/AtomDoubleArrayProperty.pypp.cpp index f721db282..7c896d51a 100644 --- a/wrapper/Mol/AtomDoubleArrayProperty.pypp.cpp +++ b/wrapper/Mol/AtomDoubleArrayProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomDoubleArrayProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireBase::DoubleArrayProperty >::merge + + typedef SireMol::AtomProperty< SireBase::DoubleArrayProperty > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireBase::DoubleArrayProperty >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireBase::DoubleArrayProperty >::merge ); + + AtomDoubleArrayProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireBase::DoubleArrayProperty >::nAtoms diff --git a/wrapper/Mol/AtomEditor.pypp.cpp b/wrapper/Mol/AtomEditor.pypp.cpp index 45bcdbb53..10539c4d4 100644 --- a/wrapper/Mol/AtomEditor.pypp.cpp +++ b/wrapper/Mol/AtomEditor.pypp.cpp @@ -67,6 +67,18 @@ void register_AtomEditor_class(){ bp::scope AtomEditor_scope( AtomEditor_exposer ); AtomEditor_exposer.def( bp::init< SireMol::Atom const & >(( bp::arg("atom") ), "Construct an editor that edits a copy of atom") ); AtomEditor_exposer.def( bp::init< SireMol::AtomEditor const & >(( bp::arg("other") ), "Copy constructor") ); + { //::SireMol::AtomEditor::alternateName + + typedef ::SireMol::AtomName ( ::SireMol::AtomEditor::*alternateName_function_type)( ) const; + alternateName_function_type alternateName_function_value( &::SireMol::AtomEditor::alternateName ); + + AtomEditor_exposer.def( + "alternateName" + , alternateName_function_value + , bp::release_gil_policy() + , "Return the alternate name for this atom" ); + + } { //::SireMol::AtomEditor::operator= typedef ::SireMol::AtomEditor & ( ::SireMol::AtomEditor::*assign_function_type)( ::SireMol::Atom const & ) ; @@ -105,6 +117,19 @@ void register_AtomEditor_class(){ , bp::release_gil_policy() , "Reindex this atom so that it lies at index newidx. Note\nthat if newidx is greater than the number of atoms, then\nthis will move this atom to be the last in the list" ); + } + { //::SireMol::AtomEditor::reindex + + typedef ::SireMol::AtomStructureEditor ( ::SireMol::AtomEditor::*reindex_function_type)( int ) const; + reindex_function_type reindex_function_value( &::SireMol::AtomEditor::reindex ); + + AtomEditor_exposer.def( + "reindex" + , reindex_function_value + , ( bp::arg("atomidx") ) + , bp::release_gil_policy() + , "Reindex this atom" ); + } { //::SireMol::AtomEditor::remove @@ -130,6 +155,19 @@ void register_AtomEditor_class(){ , bp::return_self< >() , "Rename this atom so that it is called newname" ); + } + { //::SireMol::AtomEditor::rename + + typedef ::SireMol::AtomEditor & ( ::SireMol::AtomEditor::*rename_function_type)( ::QString const & ) ; + rename_function_type rename_function_value( &::SireMol::AtomEditor::rename ); + + AtomEditor_exposer.def( + "rename" + , rename_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Rename this atom" ); + } { //::SireMol::AtomEditor::renumber @@ -143,6 +181,19 @@ void register_AtomEditor_class(){ , bp::return_self< >() , "Renumber this atom so that it has number newnum" ); + } + { //::SireMol::AtomEditor::renumber + + typedef ::SireMol::AtomEditor & ( ::SireMol::AtomEditor::*renumber_function_type)( int ) ; + renumber_function_type renumber_function_value( &::SireMol::AtomEditor::renumber ); + + AtomEditor_exposer.def( + "renumber" + , renumber_function_value + , ( bp::arg("number") ) + , bp::return_self< >() + , "Renumber this atom" ); + } { //::SireMol::AtomEditor::reparent @@ -221,6 +272,32 @@ void register_AtomEditor_class(){ , bp::release_gil_policy() , "Reparent this atom so that it will be placed into the segment\nwith ID segid - this returns the updated atom in\nan AtomStructureEditor, which is optimised for further\nediting of the molecule structure\nThrow: SireMol::missing_segment\nThrow: SireMol::duplicate_segment\nThrow: SireError::invalid_index\n" ); + } + { //::SireMol::AtomEditor::setAlternateName + + typedef ::SireMol::AtomEditor & ( ::SireMol::AtomEditor::*setAlternateName_function_type)( ::QString const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::AtomEditor::setAlternateName ); + + AtomEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate name for this atom" ); + + } + { //::SireMol::AtomEditor::setAlternateName + + typedef ::SireMol::AtomEditor & ( ::SireMol::AtomEditor::*setAlternateName_function_type)( ::SireMol::AtomName const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::AtomEditor::setAlternateName ); + + AtomEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate name for this atom" ); + } { //::SireMol::AtomEditor::toString diff --git a/wrapper/Mol/AtomEditorBase.pypp.cpp b/wrapper/Mol/AtomEditorBase.pypp.cpp index a62d338c5..e2daa4272 100644 --- a/wrapper/Mol/AtomEditorBase.pypp.cpp +++ b/wrapper/Mol/AtomEditorBase.pypp.cpp @@ -49,8 +49,12 @@ namespace bp = boost::python; #include "atomeditor.h" +#include "SireBase/console.h" + #include "SireBase/incremint.h" +#include "SireBase/propertylist.h" + #include "SireBase/quickcopy.hpp" #include "SireStream/datastream.h" @@ -105,8 +109,6 @@ namespace bp = boost::python; #include "atomradii.h" -#include "SireBase/propertylist.h" - #include "SireMaths/vector.h" #include "atomproperty.hpp" diff --git a/wrapper/Mol/AtomElements.pypp.cpp b/wrapper/Mol/AtomElements.pypp.cpp index 989c14cdd..cc4258d9b 100644 --- a/wrapper/Mol/AtomElements.pypp.cpp +++ b/wrapper/Mol/AtomElements.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomElements_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMol::Element >::merge + + typedef SireMol::AtomProperty< SireMol::Element > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMol::Element >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMol::Element >::merge ); + + AtomElements_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMol::Element >::nAtoms diff --git a/wrapper/Mol/AtomEnergies.pypp.cpp b/wrapper/Mol/AtomEnergies.pypp.cpp index cbe0b661c..08738545f 100644 --- a/wrapper/Mol/AtomEnergies.pypp.cpp +++ b/wrapper/Mol/AtomEnergies.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomEnergies_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 2, -2, 0, 0, -1, 0 > >::merge + + typedef SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 2, -2, 0, 0, -1, 0 > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 2, -2, 0, 0, -1, 0 > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 2, -2, 0, 0, -1, 0 > >::merge ); + + AtomEnergies_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 2, -2, 0, 0, -1, 0 > >::nAtoms diff --git a/wrapper/Mol/AtomFloatProperty.pypp.cpp b/wrapper/Mol/AtomFloatProperty.pypp.cpp index 76ad8c6d7..1c223ce55 100644 --- a/wrapper/Mol/AtomFloatProperty.pypp.cpp +++ b/wrapper/Mol/AtomFloatProperty.pypp.cpp @@ -43,6 +43,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -386,6 +388,19 @@ void register_AtomFloatProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< double >::merge + + typedef SireMol::AtomProperty< double > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< double >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< double >::merge ); + + AtomFloatProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< double >::nAtoms diff --git a/wrapper/Mol/AtomForces.pypp.cpp b/wrapper/Mol/AtomForces.pypp.cpp index 0daa08c2b..24f517c86 100644 --- a/wrapper/Mol/AtomForces.pypp.cpp +++ b/wrapper/Mol/AtomForces.pypp.cpp @@ -16,6 +16,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -359,6 +361,19 @@ void register_AtomForces_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Force > >::merge + + typedef SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Force > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Force > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Force > >::merge ); + + AtomForces_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Force > >::nAtoms diff --git a/wrapper/Mol/AtomHybridizations.pypp.cpp b/wrapper/Mol/AtomHybridizations.pypp.cpp index 3149a8e56..d4b5b7710 100644 --- a/wrapper/Mol/AtomHybridizations.pypp.cpp +++ b/wrapper/Mol/AtomHybridizations.pypp.cpp @@ -23,6 +23,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -366,6 +368,19 @@ void register_AtomHybridizations_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMol::Hybridization >::merge + + typedef SireMol::AtomProperty< SireMol::Hybridization > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMol::Hybridization >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMol::Hybridization >::merge ); + + AtomHybridizations_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMol::Hybridization >::nAtoms diff --git a/wrapper/Mol/AtomIdxMapping.pypp.cpp b/wrapper/Mol/AtomIdxMapping.pypp.cpp new file mode 100644 index 000000000..4a4118ace --- /dev/null +++ b/wrapper/Mol/AtomIdxMapping.pypp.cpp @@ -0,0 +1,428 @@ +// This file has been generated by Py++. + +// (C) Christopher Woods, GPL >= 3 License + +#include "boost/python.hpp" +#include "Helpers/clone_const_reference.hpp" +#include "AtomIdxMapping.pypp.hpp" + +namespace bp = boost::python; + +#include "SireError/errors.h" + +#include "SireID/index.h" + +#include "SireMol/errors.h" + +#include "SireStream/datastream.h" + +#include "SireStream/shareddatastream.h" + +#include "atomidxmapping.h" + +#include "moleculeinfodata.h" + +#include "atomidxmapping.h" + +SireMol::AtomIdxMapping __copy__(const SireMol::AtomIdxMapping &other){ return SireMol::AtomIdxMapping(other); } + +#include "Qt/qdatastream.hpp" + +#include "Helpers/str.hpp" + +#include "Helpers/release_gil_policy.hpp" + +#include "Helpers/len.hpp" + +void register_AtomIdxMapping_class(){ + + { //::SireMol::AtomIdxMapping + typedef bp::class_< SireMol::AtomIdxMapping, bp::bases< SireBase::Property > > AtomIdxMapping_exposer_t; + AtomIdxMapping_exposer_t AtomIdxMapping_exposer = AtomIdxMapping_exposer_t( "AtomIdxMapping", "This class holds the mapping from one set of atom indices to another.\nThis enables you to associate, atom by atom, atom indices in one set to\natom indices in another set. This is useful, e.g. for building perturbations,\nor for specifying mappings for alignments or RMSD calculations etc.\n\nThis is mainly designed to provide sufficient information to merge\nproperties together. It lists not just the atoms that map, but\nalso which atoms are the ghost atoms that map (i.e. were created\nas ghost equivalents)\n", bp::init< >("Null constructor") ); + bp::scope AtomIdxMapping_scope( AtomIdxMapping_exposer ); + AtomIdxMapping_exposer.def( bp::init< SireMol::AtomIdxMappingEntry const & >(( bp::arg("entry") ), "Construct from a single entry") ); + AtomIdxMapping_exposer.def( bp::init< QList< SireMol::AtomIdxMappingEntry > const & >(( bp::arg("entries") ), "Construct from a list of entries") ); + AtomIdxMapping_exposer.def( bp::init< SireMol::AtomIdxMapping const & >(( bp::arg("other") ), "Copy constructor") ); + { //::SireMol::AtomIdxMapping::append + + typedef void ( ::SireMol::AtomIdxMapping::*append_function_type)( ::SireMol::AtomIdxMappingEntry const & ) ; + append_function_type append_function_value( &::SireMol::AtomIdxMapping::append ); + + AtomIdxMapping_exposer.def( + "append" + , append_function_value + , ( bp::arg("entry") ) + , bp::release_gil_policy() + , "Append an entry to the list" ); + + } + { //::SireMol::AtomIdxMapping::append + + typedef void ( ::SireMol::AtomIdxMapping::*append_function_type)( ::SireMol::AtomIdxMapping const & ) ; + append_function_type append_function_value( &::SireMol::AtomIdxMapping::append ); + + AtomIdxMapping_exposer.def( + "append" + , append_function_value + , ( bp::arg("other") ) + , bp::release_gil_policy() + , "Append all of the passed entries of other onto this list" ); + + } + { //::SireMol::AtomIdxMapping::clear + + typedef void ( ::SireMol::AtomIdxMapping::*clear_function_type)( ) ; + clear_function_type clear_function_value( &::SireMol::AtomIdxMapping::clear ); + + AtomIdxMapping_exposer.def( + "clear" + , clear_function_value + , bp::release_gil_policy() + , "Clear the list" ); + + } + { //::SireMol::AtomIdxMapping::count + + typedef int ( ::SireMol::AtomIdxMapping::*count_function_type)( ) const; + count_function_type count_function_value( &::SireMol::AtomIdxMapping::count ); + + AtomIdxMapping_exposer.def( + "count" + , count_function_value + , bp::release_gil_policy() + , "Return the count of the list" ); + + } + { //::SireMol::AtomIdxMapping::isEmpty + + typedef bool ( ::SireMol::AtomIdxMapping::*isEmpty_function_type)( ) const; + isEmpty_function_type isEmpty_function_value( &::SireMol::AtomIdxMapping::isEmpty ); + + AtomIdxMapping_exposer.def( + "isEmpty" + , isEmpty_function_value + , bp::release_gil_policy() + , "Return whether or not the list is empty" ); + + } + { //::SireMol::AtomIdxMapping::isMappedIn0 + + typedef bool ( ::SireMol::AtomIdxMapping::*isMappedIn0_function_type)( ::SireMol::AtomIdx const & ) const; + isMappedIn0_function_type isMappedIn0_function_value( &::SireMol::AtomIdxMapping::isMappedIn0 ); + + AtomIdxMapping_exposer.def( + "isMappedIn0" + , isMappedIn0_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Return whether or not this atom is mapped in the reference state" ); + + } + { //::SireMol::AtomIdxMapping::isMappedIn1 + + typedef bool ( ::SireMol::AtomIdxMapping::*isMappedIn1_function_type)( ::SireMol::AtomIdx const & ) const; + isMappedIn1_function_type isMappedIn1_function_value( &::SireMol::AtomIdxMapping::isMappedIn1 ); + + AtomIdxMapping_exposer.def( + "isMappedIn1" + , isMappedIn1_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Return whether or not this atom is mapped in the perturbed state" ); + + } + { //::SireMol::AtomIdxMapping::isMappedInBoth + + typedef bool ( ::SireMol::AtomIdxMapping::*isMappedInBoth_function_type)( ::SireMol::AtomIdx const & ) const; + isMappedInBoth_function_type isMappedInBoth_function_value( &::SireMol::AtomIdxMapping::isMappedInBoth ); + + AtomIdxMapping_exposer.def( + "isMappedInBoth" + , isMappedInBoth_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Return whether or not this atom is mapped in both end states" ); + + } + { //::SireMol::AtomIdxMapping::isUnmappedIn0 + + typedef bool ( ::SireMol::AtomIdxMapping::*isUnmappedIn0_function_type)( ::SireMol::AtomIdx const & ) const; + isUnmappedIn0_function_type isUnmappedIn0_function_value( &::SireMol::AtomIdxMapping::isUnmappedIn0 ); + + AtomIdxMapping_exposer.def( + "isUnmappedIn0" + , isUnmappedIn0_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "" ); + + } + { //::SireMol::AtomIdxMapping::isUnmappedIn1 + + typedef bool ( ::SireMol::AtomIdxMapping::*isUnmappedIn1_function_type)( ::SireMol::AtomIdx const & ) const; + isUnmappedIn1_function_type isUnmappedIn1_function_value( &::SireMol::AtomIdxMapping::isUnmappedIn1 ); + + AtomIdxMapping_exposer.def( + "isUnmappedIn1" + , isUnmappedIn1_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "" ); + + } + { //::SireMol::AtomIdxMapping::isUnmappedInBoth + + typedef bool ( ::SireMol::AtomIdxMapping::*isUnmappedInBoth_function_type)( ::SireMol::AtomIdx const & ) const; + isUnmappedInBoth_function_type isUnmappedInBoth_function_value( &::SireMol::AtomIdxMapping::isUnmappedInBoth ); + + AtomIdxMapping_exposer.def( + "isUnmappedInBoth" + , isUnmappedInBoth_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Return whether or not this atom is unmapped in both end states" ); + + } + { //::SireMol::AtomIdxMapping::map0to1 + + typedef ::QHash< SireMol::AtomIdx, SireMol::AtomIdx > ( ::SireMol::AtomIdxMapping::*map0to1_function_type)( bool ) const; + map0to1_function_type map0to1_function_value( &::SireMol::AtomIdxMapping::map0to1 ); + + AtomIdxMapping_exposer.def( + "map0to1" + , map0to1_function_value + , ( bp::arg("include_unmapped")=(bool)(false) ) + , "Return the mapping for the atoms that exist in both the reference\n and perturbed states, from the index of the atom in the merged\n molecule to the index of the atom in the perturbed molecule.\n Note - the reference index is the index in the merged molecule.\n\n If include_unmapped is true, then also include atoms that are\n unmapped in either end state. In these cases, the reference index\n will be the index in the merged molecule (so will always be valid)\n but the perturbed index will be null for atoms that are unmapped\n in the perturbed state.\n" ); + + } + { //::SireMol::AtomIdxMapping::map1to0 + + typedef ::QHash< SireMol::AtomIdx, SireMol::AtomIdx > ( ::SireMol::AtomIdxMapping::*map1to0_function_type)( bool ) const; + map1to0_function_type map1to0_function_value( &::SireMol::AtomIdxMapping::map1to0 ); + + AtomIdxMapping_exposer.def( + "map1to0" + , map1to0_function_value + , ( bp::arg("include_unmapped")=(bool)(false) ) + , "Return the mapping for the atoms that exist in both the reference\n and perturbed states, from the index of the atom in the perturbed\n molecule to the index of the atom in the merged molecule.\n Note - the reference index is the index in the merged molecule.\n\n If include_unmapped is true, then also include atoms that are\n unmapped in either end state. In these cases, the reference index\n will be the index in the merged molecule (so will always be valid)\n and atoms that are unmapped in the perturbed state are not\n included in the returned dictionary.\n" ); + + } + { //::SireMol::AtomIdxMapping::mappedIn0 + + typedef ::QList< SireMol::AtomIdx > ( ::SireMol::AtomIdxMapping::*mappedIn0_function_type)( ) const; + mappedIn0_function_type mappedIn0_function_value( &::SireMol::AtomIdxMapping::mappedIn0 ); + + AtomIdxMapping_exposer.def( + "mappedIn0" + , mappedIn0_function_value + , bp::release_gil_policy() + , "Return the indexes, in the merged molecule, of atoms that\n are mapped in the reference state (i.e. they exist in the\n reference state, regardless of whether or not they exist\n in the perturbed state). Note - these are the indicies of\n these atoms in the merged molecule, not the reference molecule.\n" ); + + } + { //::SireMol::AtomIdxMapping::mappedIn1 + + typedef ::QList< SireMol::AtomIdx > ( ::SireMol::AtomIdxMapping::*mappedIn1_function_type)( ) const; + mappedIn1_function_type mappedIn1_function_value( &::SireMol::AtomIdxMapping::mappedIn1 ); + + AtomIdxMapping_exposer.def( + "mappedIn1" + , mappedIn1_function_value + , bp::release_gil_policy() + , "Return the indexes, in the merged molecule, of atoms that\n are mapped in the perturbed state (i.e. they exist in the\n perturbed state, regardless of whether or not they exist\n in the reference state). Note - these are the indicies of\n these atoms in the merged molecule, not the perturbed molecule.\n" ); + + } + AtomIdxMapping_exposer.def( bp::self != bp::self ); + AtomIdxMapping_exposer.def( bp::self + bp::self ); + AtomIdxMapping_exposer.def( bp::self + bp::other< SireMol::AtomIdxMappingEntry >() ); + { //::SireMol::AtomIdxMapping::operator= + + typedef ::SireMol::AtomIdxMapping & ( ::SireMol::AtomIdxMapping::*assign_function_type)( ::SireMol::AtomIdxMapping const & ) ; + assign_function_type assign_function_value( &::SireMol::AtomIdxMapping::operator= ); + + AtomIdxMapping_exposer.def( + "assign" + , assign_function_value + , ( bp::arg("other") ) + , bp::return_self< >() + , "" ); + + } + AtomIdxMapping_exposer.def( bp::self == bp::self ); + { //::SireMol::AtomIdxMapping::operator[] + + typedef ::SireMol::AtomIdxMappingEntry const & ( ::SireMol::AtomIdxMapping::*__getitem___function_type)( int ) const; + __getitem___function_type __getitem___function_value( &::SireMol::AtomIdxMapping::operator[] ); + + AtomIdxMapping_exposer.def( + "__getitem__" + , __getitem___function_value + , ( bp::arg("i") ) + , bp::return_value_policy() + , "" ); + + } + { //::SireMol::AtomIdxMapping::remove + + typedef void ( ::SireMol::AtomIdxMapping::*remove_function_type)( int ) ; + remove_function_type remove_function_value( &::SireMol::AtomIdxMapping::remove ); + + AtomIdxMapping_exposer.def( + "remove" + , remove_function_value + , ( bp::arg("i") ) + , bp::release_gil_policy() + , "Remove the entry at index i" ); + + } + { //::SireMol::AtomIdxMapping::remove + + typedef void ( ::SireMol::AtomIdxMapping::*remove_function_type)( ::SireMol::AtomIdx const & ) ; + remove_function_type remove_function_value( &::SireMol::AtomIdxMapping::remove ); + + AtomIdxMapping_exposer.def( + "remove" + , remove_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Remove the entry for atom atom" ); + + } + { //::SireMol::AtomIdxMapping::remove + + typedef void ( ::SireMol::AtomIdxMapping::*remove_function_type)( ::SireMol::CGAtomIdx const & ) ; + remove_function_type remove_function_value( &::SireMol::AtomIdxMapping::remove ); + + AtomIdxMapping_exposer.def( + "remove" + , remove_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Remove the entry for atom atom" ); + + } + { //::SireMol::AtomIdxMapping::size + + typedef int ( ::SireMol::AtomIdxMapping::*size_function_type)( ) const; + size_function_type size_function_value( &::SireMol::AtomIdxMapping::size ); + + AtomIdxMapping_exposer.def( + "size" + , size_function_value + , bp::release_gil_policy() + , "Return the size of the list" ); + + } + { //::SireMol::AtomIdxMapping::take + + typedef ::SireMol::AtomIdxMappingEntry ( ::SireMol::AtomIdxMapping::*take_function_type)( int ) ; + take_function_type take_function_value( &::SireMol::AtomIdxMapping::take ); + + AtomIdxMapping_exposer.def( + "take" + , take_function_value + , ( bp::arg("i") ) + , bp::release_gil_policy() + , "Take the entry at index i" ); + + } + { //::SireMol::AtomIdxMapping::take + + typedef ::SireMol::AtomIdxMappingEntry ( ::SireMol::AtomIdxMapping::*take_function_type)( ::SireMol::AtomIdx const & ) ; + take_function_type take_function_value( &::SireMol::AtomIdxMapping::take ); + + AtomIdxMapping_exposer.def( + "take" + , take_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Take the entry for atom atom" ); + + } + { //::SireMol::AtomIdxMapping::take + + typedef ::SireMol::AtomIdxMappingEntry ( ::SireMol::AtomIdxMapping::*take_function_type)( ::SireMol::CGAtomIdx const & ) ; + take_function_type take_function_value( &::SireMol::AtomIdxMapping::take ); + + AtomIdxMapping_exposer.def( + "take" + , take_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Take the entry for atom atom" ); + + } + { //::SireMol::AtomIdxMapping::toString + + typedef ::QString ( ::SireMol::AtomIdxMapping::*toString_function_type)( ) const; + toString_function_type toString_function_value( &::SireMol::AtomIdxMapping::toString ); + + AtomIdxMapping_exposer.def( + "toString" + , toString_function_value + , bp::release_gil_policy() + , "Convert this object to a string" ); + + } + { //::SireMol::AtomIdxMapping::typeName + + typedef char const * ( *typeName_function_type )( ); + typeName_function_type typeName_function_value( &::SireMol::AtomIdxMapping::typeName ); + + AtomIdxMapping_exposer.def( + "typeName" + , typeName_function_value + , bp::release_gil_policy() + , "" ); + + } + { //::SireMol::AtomIdxMapping::unmappedIn0 + + typedef ::QList< SireMol::AtomIdx > ( ::SireMol::AtomIdxMapping::*unmappedIn0_function_type)( ) const; + unmappedIn0_function_type unmappedIn0_function_value( &::SireMol::AtomIdxMapping::unmappedIn0 ); + + AtomIdxMapping_exposer.def( + "unmappedIn0" + , unmappedIn0_function_value + , bp::release_gil_policy() + , "Return the indexes, in the merged molecule, of atoms that\n are not mapped in the reference state (i.e. they only exist\n in the perturbed state). Note - these are the indicies of these\n atoms in the merged molecule, not the perturbed molecule.\n" ); + + } + { //::SireMol::AtomIdxMapping::unmappedIn1 + + typedef ::QList< SireMol::AtomIdx > ( ::SireMol::AtomIdxMapping::*unmappedIn1_function_type)( ) const; + unmappedIn1_function_type unmappedIn1_function_value( &::SireMol::AtomIdxMapping::unmappedIn1 ); + + AtomIdxMapping_exposer.def( + "unmappedIn1" + , unmappedIn1_function_value + , bp::release_gil_policy() + , "Return the indexes, in the merged molecule, of atoms that\n are not mapped in the perturbed state (i.e. they only exist\n in the reference state). Note - these are the indicies of these\n atoms in the merged molecule, not the reference molecule.\n" ); + + } + { //::SireMol::AtomIdxMapping::what + + typedef char const * ( ::SireMol::AtomIdxMapping::*what_function_type)( ) const; + what_function_type what_function_value( &::SireMol::AtomIdxMapping::what ); + + AtomIdxMapping_exposer.def( + "what" + , what_function_value + , bp::release_gil_policy() + , "" ); + + } + AtomIdxMapping_exposer.staticmethod( "typeName" ); + AtomIdxMapping_exposer.def( "__copy__", &__copy__); + AtomIdxMapping_exposer.def( "__deepcopy__", &__copy__); + AtomIdxMapping_exposer.def( "clone", &__copy__); + AtomIdxMapping_exposer.def( "__rlshift__", &__rlshift__QDataStream< ::SireMol::AtomIdxMapping >, + bp::return_internal_reference<1, bp::with_custodian_and_ward<1,2> >() ); + AtomIdxMapping_exposer.def( "__rrshift__", &__rrshift__QDataStream< ::SireMol::AtomIdxMapping >, + bp::return_internal_reference<1, bp::with_custodian_and_ward<1,2> >() ); + AtomIdxMapping_exposer.def_pickle(sire_pickle_suite< ::SireMol::AtomIdxMapping >()); + AtomIdxMapping_exposer.def( "__str__", &__str__< ::SireMol::AtomIdxMapping > ); + AtomIdxMapping_exposer.def( "__repr__", &__str__< ::SireMol::AtomIdxMapping > ); + AtomIdxMapping_exposer.def( "__len__", &__len_size< ::SireMol::AtomIdxMapping > ); + } + +} diff --git a/wrapper/Mol/AtomIdxMapping.pypp.hpp b/wrapper/Mol/AtomIdxMapping.pypp.hpp new file mode 100644 index 000000000..43f33b75f --- /dev/null +++ b/wrapper/Mol/AtomIdxMapping.pypp.hpp @@ -0,0 +1,10 @@ +// This file has been generated by Py++. + +// (C) Christopher Woods, GPL >= 3 License + +#ifndef AtomIdxMapping_hpp__pyplusplus_wrapper +#define AtomIdxMapping_hpp__pyplusplus_wrapper + +void register_AtomIdxMapping_class(); + +#endif//AtomIdxMapping_hpp__pyplusplus_wrapper diff --git a/wrapper/Mol/AtomIdxMappingEntry.pypp.cpp b/wrapper/Mol/AtomIdxMappingEntry.pypp.cpp new file mode 100644 index 000000000..91fed776b --- /dev/null +++ b/wrapper/Mol/AtomIdxMappingEntry.pypp.cpp @@ -0,0 +1,238 @@ +// This file has been generated by Py++. + +// (C) Christopher Woods, GPL >= 3 License + +#include "boost/python.hpp" +#include "AtomIdxMappingEntry.pypp.hpp" + +namespace bp = boost::python; + +#include "SireError/errors.h" + +#include "SireID/index.h" + +#include "SireMol/errors.h" + +#include "SireStream/datastream.h" + +#include "SireStream/shareddatastream.h" + +#include "atomidxmapping.h" + +#include "moleculeinfodata.h" + +#include "atomidxmapping.h" + +SireMol::AtomIdxMappingEntry __copy__(const SireMol::AtomIdxMappingEntry &other){ return SireMol::AtomIdxMappingEntry(other); } + +#include "Qt/qdatastream.hpp" + +#include "Helpers/str.hpp" + +#include "Helpers/release_gil_policy.hpp" + +void register_AtomIdxMappingEntry_class(){ + + { //::SireMol::AtomIdxMappingEntry + typedef bp::class_< SireMol::AtomIdxMappingEntry > AtomIdxMappingEntry_exposer_t; + AtomIdxMappingEntry_exposer_t AtomIdxMappingEntry_exposer = AtomIdxMappingEntry_exposer_t( "AtomIdxMappingEntry", "This is an individual mapping for a single atom", bp::init< >("Null constructor") ); + bp::scope AtomIdxMappingEntry_scope( AtomIdxMappingEntry_exposer ); + AtomIdxMappingEntry_exposer.def( bp::init< SireMol::AtomIdx const &, SireMol::AtomIdx const &, SireMol::MoleculeInfoData const &, SireMol::MoleculeInfoData const &, bool >(( bp::arg("index0"), bp::arg("index1"), bp::arg("molinfo0"), bp::arg("molinfo1"), bp::arg("is_unmapped_in_reference") ), "Construct to map from index0 in molinfo0 to index1 in molinfo1.\n There is no mapping in the perturbed state if index1 is null. There\n is no mapping in the reference state if is_unmapped_in_reference is true.\n It is an error to have index0 null, or if you cannot look up\n index0 in molinfo0 or index1 in molinfo1.\n") ); + AtomIdxMappingEntry_exposer.def( bp::init< SireMol::AtomIdxMappingEntry const & >(( bp::arg("other") ), "Copy constructor") ); + { //::SireMol::AtomIdxMappingEntry::atomIdx0 + + typedef ::SireMol::AtomIdx ( ::SireMol::AtomIdxMappingEntry::*atomIdx0_function_type)( ) const; + atomIdx0_function_type atomIdx0_function_value( &::SireMol::AtomIdxMappingEntry::atomIdx0 ); + + AtomIdxMappingEntry_exposer.def( + "atomIdx0" + , atomIdx0_function_value + , bp::release_gil_policy() + , "Return the atom index in the reference state. This will always have\n a value, even if the atom is unmapped in the reference state\n (this signals that any parameter with this index should be zero)\n" ); + + } + { //::SireMol::AtomIdxMappingEntry::atomIdx1 + + typedef ::SireMol::AtomIdx ( ::SireMol::AtomIdxMappingEntry::*atomIdx1_function_type)( ) const; + atomIdx1_function_type atomIdx1_function_value( &::SireMol::AtomIdxMappingEntry::atomIdx1 ); + + AtomIdxMappingEntry_exposer.def( + "atomIdx1" + , atomIdx1_function_value + , bp::release_gil_policy() + , "Return the atom index in the perturbed state, or a null index if\n the atom is unmapped in the perturbed state" ); + + } + { //::SireMol::AtomIdxMappingEntry::cgAtomIdx0 + + typedef ::SireMol::CGAtomIdx ( ::SireMol::AtomIdxMappingEntry::*cgAtomIdx0_function_type)( ) const; + cgAtomIdx0_function_type cgAtomIdx0_function_value( &::SireMol::AtomIdxMappingEntry::cgAtomIdx0 ); + + AtomIdxMappingEntry_exposer.def( + "cgAtomIdx0" + , cgAtomIdx0_function_value + , bp::release_gil_policy() + , "Return the atom index in the reference state. This will always have\n a value, even if the atom is unmapped in the reference state\n (this signals that any parameter with this index should be zero)\n" ); + + } + { //::SireMol::AtomIdxMappingEntry::cgAtomIdx1 + + typedef ::SireMol::CGAtomIdx ( ::SireMol::AtomIdxMappingEntry::*cgAtomIdx1_function_type)( ) const; + cgAtomIdx1_function_type cgAtomIdx1_function_value( &::SireMol::AtomIdxMappingEntry::cgAtomIdx1 ); + + AtomIdxMappingEntry_exposer.def( + "cgAtomIdx1" + , cgAtomIdx1_function_value + , bp::release_gil_policy() + , "Return the atom index in the perturbed state, or a null index if\n the atom is unmapped in the perturbed state" ); + + } + { //::SireMol::AtomIdxMappingEntry::isMappedIn0 + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isMappedIn0_function_type)( ) const; + isMappedIn0_function_type isMappedIn0_function_value( &::SireMol::AtomIdxMappingEntry::isMappedIn0 ); + + AtomIdxMappingEntry_exposer.def( + "isMappedIn0" + , isMappedIn0_function_value + , bp::release_gil_policy() + , "Return whether or not this atom is mapped in the reference state" ); + + } + { //::SireMol::AtomIdxMappingEntry::isMappedIn1 + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isMappedIn1_function_type)( ) const; + isMappedIn1_function_type isMappedIn1_function_value( &::SireMol::AtomIdxMappingEntry::isMappedIn1 ); + + AtomIdxMappingEntry_exposer.def( + "isMappedIn1" + , isMappedIn1_function_value + , bp::release_gil_policy() + , "Return whether or not this atom is mapped in the perturbed state" ); + + } + { //::SireMol::AtomIdxMappingEntry::isMappedInBoth + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isMappedInBoth_function_type)( ) const; + isMappedInBoth_function_type isMappedInBoth_function_value( &::SireMol::AtomIdxMappingEntry::isMappedInBoth ); + + AtomIdxMappingEntry_exposer.def( + "isMappedInBoth" + , isMappedInBoth_function_value + , bp::release_gil_policy() + , "Return whether or not this atom is mapped in both end states" ); + + } + { //::SireMol::AtomIdxMappingEntry::isNull + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isNull_function_type)( ) const; + isNull_function_type isNull_function_value( &::SireMol::AtomIdxMappingEntry::isNull ); + + AtomIdxMappingEntry_exposer.def( + "isNull" + , isNull_function_value + , bp::release_gil_policy() + , "Return whether or not this is a null entry" ); + + } + { //::SireMol::AtomIdxMappingEntry::isUnmappedIn0 + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isUnmappedIn0_function_type)( ) const; + isUnmappedIn0_function_type isUnmappedIn0_function_value( &::SireMol::AtomIdxMappingEntry::isUnmappedIn0 ); + + AtomIdxMappingEntry_exposer.def( + "isUnmappedIn0" + , isUnmappedIn0_function_value + , bp::release_gil_policy() + , "Return whether or not this atom is unmapped in the reference state" ); + + } + { //::SireMol::AtomIdxMappingEntry::isUnmappedIn1 + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isUnmappedIn1_function_type)( ) const; + isUnmappedIn1_function_type isUnmappedIn1_function_value( &::SireMol::AtomIdxMappingEntry::isUnmappedIn1 ); + + AtomIdxMappingEntry_exposer.def( + "isUnmappedIn1" + , isUnmappedIn1_function_value + , bp::release_gil_policy() + , "Return whether or not this atom is unmapped in the perturbed state" ); + + } + { //::SireMol::AtomIdxMappingEntry::isUnmappedInBoth + + typedef bool ( ::SireMol::AtomIdxMappingEntry::*isUnmappedInBoth_function_type)( ) const; + isUnmappedInBoth_function_type isUnmappedInBoth_function_value( &::SireMol::AtomIdxMappingEntry::isUnmappedInBoth ); + + AtomIdxMappingEntry_exposer.def( + "isUnmappedInBoth" + , isUnmappedInBoth_function_value + , bp::release_gil_policy() + , "Return whether or not this atom is unmapped in both end states" ); + + } + AtomIdxMappingEntry_exposer.def( bp::self != bp::self ); + { //::SireMol::AtomIdxMappingEntry::operator= + + typedef ::SireMol::AtomIdxMappingEntry & ( ::SireMol::AtomIdxMappingEntry::*assign_function_type)( ::SireMol::AtomIdxMappingEntry const & ) ; + assign_function_type assign_function_value( &::SireMol::AtomIdxMappingEntry::operator= ); + + AtomIdxMappingEntry_exposer.def( + "assign" + , assign_function_value + , ( bp::arg("other") ) + , bp::return_self< >() + , "" ); + + } + AtomIdxMappingEntry_exposer.def( bp::self == bp::self ); + { //::SireMol::AtomIdxMappingEntry::toString + + typedef ::QString ( ::SireMol::AtomIdxMappingEntry::*toString_function_type)( ) const; + toString_function_type toString_function_value( &::SireMol::AtomIdxMappingEntry::toString ); + + AtomIdxMappingEntry_exposer.def( + "toString" + , toString_function_value + , bp::release_gil_policy() + , "Convert this object to a string" ); + + } + { //::SireMol::AtomIdxMappingEntry::typeName + + typedef char const * ( *typeName_function_type )( ); + typeName_function_type typeName_function_value( &::SireMol::AtomIdxMappingEntry::typeName ); + + AtomIdxMappingEntry_exposer.def( + "typeName" + , typeName_function_value + , bp::release_gil_policy() + , "" ); + + } + { //::SireMol::AtomIdxMappingEntry::what + + typedef char const * ( ::SireMol::AtomIdxMappingEntry::*what_function_type)( ) const; + what_function_type what_function_value( &::SireMol::AtomIdxMappingEntry::what ); + + AtomIdxMappingEntry_exposer.def( + "what" + , what_function_value + , bp::release_gil_policy() + , "" ); + + } + AtomIdxMappingEntry_exposer.staticmethod( "typeName" ); + AtomIdxMappingEntry_exposer.def( "__copy__", &__copy__); + AtomIdxMappingEntry_exposer.def( "__deepcopy__", &__copy__); + AtomIdxMappingEntry_exposer.def( "clone", &__copy__); + AtomIdxMappingEntry_exposer.def( "__rlshift__", &__rlshift__QDataStream< ::SireMol::AtomIdxMappingEntry >, + bp::return_internal_reference<1, bp::with_custodian_and_ward<1,2> >() ); + AtomIdxMappingEntry_exposer.def( "__rrshift__", &__rrshift__QDataStream< ::SireMol::AtomIdxMappingEntry >, + bp::return_internal_reference<1, bp::with_custodian_and_ward<1,2> >() ); + AtomIdxMappingEntry_exposer.def_pickle(sire_pickle_suite< ::SireMol::AtomIdxMappingEntry >()); + AtomIdxMappingEntry_exposer.def( "__str__", &__str__< ::SireMol::AtomIdxMappingEntry > ); + AtomIdxMappingEntry_exposer.def( "__repr__", &__str__< ::SireMol::AtomIdxMappingEntry > ); + } + +} diff --git a/wrapper/Mol/AtomIdxMappingEntry.pypp.hpp b/wrapper/Mol/AtomIdxMappingEntry.pypp.hpp new file mode 100644 index 000000000..aa5d36d01 --- /dev/null +++ b/wrapper/Mol/AtomIdxMappingEntry.pypp.hpp @@ -0,0 +1,10 @@ +// This file has been generated by Py++. + +// (C) Christopher Woods, GPL >= 3 License + +#ifndef AtomIdxMappingEntry_hpp__pyplusplus_wrapper +#define AtomIdxMappingEntry_hpp__pyplusplus_wrapper + +void register_AtomIdxMappingEntry_class(); + +#endif//AtomIdxMappingEntry_hpp__pyplusplus_wrapper diff --git a/wrapper/Mol/AtomIntProperty.pypp.cpp b/wrapper/Mol/AtomIntProperty.pypp.cpp index 3aefcbdeb..ad28a47cd 100644 --- a/wrapper/Mol/AtomIntProperty.pypp.cpp +++ b/wrapper/Mol/AtomIntProperty.pypp.cpp @@ -43,6 +43,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -386,6 +388,19 @@ void register_AtomIntProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< long long >::merge + + typedef SireMol::AtomProperty< long long > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< long long >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< long long >::merge ); + + AtomIntProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< long long >::nAtoms diff --git a/wrapper/Mol/AtomIntegerArrayProperty.pypp.cpp b/wrapper/Mol/AtomIntegerArrayProperty.pypp.cpp index 4c3e0f0c0..25149c5e2 100644 --- a/wrapper/Mol/AtomIntegerArrayProperty.pypp.cpp +++ b/wrapper/Mol/AtomIntegerArrayProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomIntegerArrayProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireBase::IntegerArrayProperty >::merge + + typedef SireMol::AtomProperty< SireBase::IntegerArrayProperty > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireBase::IntegerArrayProperty >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireBase::IntegerArrayProperty >::merge ); + + AtomIntegerArrayProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireBase::IntegerArrayProperty >::nAtoms diff --git a/wrapper/Mol/AtomMapping.pypp.cpp b/wrapper/Mol/AtomMapping.pypp.cpp index ba79bd2ba..56684b55f 100644 --- a/wrapper/Mol/AtomMapping.pypp.cpp +++ b/wrapper/Mol/AtomMapping.pypp.cpp @@ -8,6 +8,10 @@ namespace bp = boost::python; +#include "SireMaths/align.h" + +#include "SireMol/core.h" + #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" @@ -34,10 +38,63 @@ void register_AtomMapping_class(){ typedef bp::class_< SireMol::AtomMapping, bp::bases< SireBase::Property > > AtomMapping_exposer_t; AtomMapping_exposer_t AtomMapping_exposer = AtomMapping_exposer_t( "AtomMapping", "This class holds the mapping from one set of atoms to another.\nThis enables you associate, atom by atom, atoms in one set to\natoms in another set. This is useful, e.g. for building perturbations,\nor for specifying mappings for alignments or RMSD calculations etc.\n", bp::init< >("") ); bp::scope AtomMapping_scope( AtomMapping_exposer ); - AtomMapping_exposer.def( bp::init< SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const & >(( bp::arg("atoms0"), bp::arg("atoms1") ), "") ); - AtomMapping_exposer.def( bp::init< SireMol::MoleculeView const &, SireMol::MoleculeView const & >(( bp::arg("mol0"), bp::arg("mol1") ), "") ); - AtomMapping_exposer.def( bp::init< SireMol::SelectorMol const &, SireMol::SelectorMol const & >(( bp::arg("mols0"), bp::arg("mols1") ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, bp::optional< SireBase::PropertyMap const & > >(( bp::arg("atoms0"), bp::arg("atoms1"), bp::arg("map")=SireBase::PropertyMap() ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, SireBase::PropertyMap const &, SireBase::PropertyMap const & >(( bp::arg("atoms0"), bp::arg("atoms1"), bp::arg("map0"), bp::arg("map1") ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::MoleculeView const &, SireMol::MoleculeView const &, bp::optional< SireBase::PropertyMap const & > >(( bp::arg("mol0"), bp::arg("mol1"), bp::arg("map")=SireBase::PropertyMap() ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::MoleculeView const &, SireMol::MoleculeView const &, SireBase::PropertyMap const &, SireBase::PropertyMap const & >(( bp::arg("mol0"), bp::arg("mol1"), bp::arg("map0"), bp::arg("map1") ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::SelectorMol const &, SireMol::SelectorMol const &, bp::optional< SireBase::PropertyMap const & > >(( bp::arg("mols0"), bp::arg("mols1"), bp::arg("map")=SireBase::PropertyMap() ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::SelectorMol const &, SireMol::SelectorMol const &, SireBase::PropertyMap const &, SireBase::PropertyMap const & >(( bp::arg("mols0"), bp::arg("mols1"), bp::arg("map0"), bp::arg("map1") ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, bp::optional< SireBase::PropertyMap const & > >(( bp::arg("atoms0"), bp::arg("atoms1"), bp::arg("matched_atoms0"), bp::arg("matched_atoms1"), bp::arg("map")=SireBase::PropertyMap() ), "") ); + AtomMapping_exposer.def( bp::init< SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, SireMol::SelectorM< SireMol::Atom > const &, SireBase::PropertyMap const &, SireBase::PropertyMap const & >(( bp::arg("atoms0"), bp::arg("atoms1"), bp::arg("matched_atoms0"), bp::arg("matched_atoms1"), bp::arg("map0"), bp::arg("map1") ), "") ); AtomMapping_exposer.def( bp::init< SireMol::AtomMapping const & >(( bp::arg("other") ), "") ); + { //::SireMol::AtomMapping::align + + typedef ::SireMol::AtomMapping ( ::SireMol::AtomMapping::*align_function_type)( ) const; + align_function_type align_function_value( &::SireMol::AtomMapping::align ); + + AtomMapping_exposer.def( + "align" + , align_function_value + , bp::release_gil_policy() + , "Return the mapping where the perturbed state (1) has been\n aligned against the reference state (0).\n" ); + + } + { //::SireMol::AtomMapping::alignTo0 + + typedef ::SireMol::AtomMapping ( ::SireMol::AtomMapping::*alignTo0_function_type)( ) const; + alignTo0_function_type alignTo0_function_value( &::SireMol::AtomMapping::alignTo0 ); + + AtomMapping_exposer.def( + "alignTo0" + , alignTo0_function_value + , bp::release_gil_policy() + , "Return the mapping where the perturbed state (1) has been\n aligned against the reference state (0).\n" ); + + } + { //::SireMol::AtomMapping::alignTo1 + + typedef ::SireMol::AtomMapping ( ::SireMol::AtomMapping::*alignTo1_function_type)( ) const; + alignTo1_function_type alignTo1_function_value( &::SireMol::AtomMapping::alignTo1 ); + + AtomMapping_exposer.def( + "alignTo1" + , alignTo1_function_value + , bp::release_gil_policy() + , "Return the mapping where the perturbed state (1) has been\n aligned against the reference state (0).\n" ); + + } + { //::SireMol::AtomMapping::assertSingleMolecule + + typedef void ( ::SireMol::AtomMapping::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::AtomMapping::assertSingleMolecule ); + + AtomMapping_exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "Assert that this mapping refers only to a single molecule" ); + + } { //::SireMol::AtomMapping::atoms0 typedef ::SireMol::SelectorM< SireMol::Atom > const & ( ::SireMol::AtomMapping::*atoms0_function_type)( ) const; @@ -47,7 +104,7 @@ void register_AtomMapping_class(){ "atoms0" , atoms0_function_value , bp::return_value_policy() - , "Return the reference atoms. We map from these atom to\n the mapped atoms (atoms1)" ); + , "Return the original reference atoms. This is the collection of both\n mapped and unmapped reference atoms\n" ); } { //::SireMol::AtomMapping::atoms1 @@ -59,7 +116,20 @@ void register_AtomMapping_class(){ "atoms1" , atoms1_function_value , bp::return_value_policy() - , "Return the mapped atoms. We map from the reference atoms (atoms0)\n to these atoms." ); + , "Return the original mapped atoms. This is the collection of both\n mapped and unmapped mapped atoms\n" ); + + } + { //::SireMol::AtomMapping::contains + + typedef bool ( ::SireMol::AtomMapping::*contains_function_type)( ::SireMol::Atom const & ) const; + contains_function_type contains_function_value( &::SireMol::AtomMapping::contains ); + + AtomMapping_exposer.def( + "contains" + , contains_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Return whether or not the forward mapping contains the\n passed atom - this returns true if the atom is contained\n in the original reference atoms, i.e. it doesnt guarantee\n that the atom is mapped. Use the isMapped method to\n check if the atom is mapped.\n" ); } { //::SireMol::AtomMapping::count @@ -157,6 +227,31 @@ void register_AtomMapping_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomMapping::isMapped + + typedef bool ( ::SireMol::AtomMapping::*isMapped_function_type)( ::SireMol::Atom const & ) const; + isMapped_function_type isMapped_function_value( &::SireMol::AtomMapping::isMapped ); + + AtomMapping_exposer.def( + "isMapped" + , isMapped_function_value + , ( bp::arg("atom") ) + , bp::release_gil_policy() + , "Return whether or not the passed reference atom has been\n mapped to a mapped atom\n" ); + + } + { //::SireMol::AtomMapping::isSingleMolecule + + typedef bool ( ::SireMol::AtomMapping::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::AtomMapping::isSingleMolecule ); + + AtomMapping_exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "Return whether or not this mapping refers to only a single molecule" ); + } { //::SireMol::AtomMapping::map @@ -193,6 +288,30 @@ void register_AtomMapping_class(){ , ( bp::arg("atoms"), bp::arg("find_all")=(bool)(true) ) , "Map from the passed atoms (which must all be in the reference\n atoms) to the corresponding atoms in the mapped atoms. The\n mapped atoms will be returned in the same order as the\n reference atoms appeared in atoms. If find_all` is false\n then this will use null atoms in the map when the mapped\n atom cannot be found" ); + } + { //::SireMol::AtomMapping::mappedAtoms0 + + typedef ::SireMol::SelectorM< SireMol::Atom > ( ::SireMol::AtomMapping::*mappedAtoms0_function_type)( ) const; + mappedAtoms0_function_type mappedAtoms0_function_value( &::SireMol::AtomMapping::mappedAtoms0 ); + + AtomMapping_exposer.def( + "mappedAtoms0" + , mappedAtoms0_function_value + , bp::release_gil_policy() + , "Return all of the reference atoms that have been mapped,\n in the same order as the mapped atoms they match with\n" ); + + } + { //::SireMol::AtomMapping::mappedAtoms1 + + typedef ::SireMol::SelectorM< SireMol::Atom > ( ::SireMol::AtomMapping::*mappedAtoms1_function_type)( ) const; + mappedAtoms1_function_type mappedAtoms1_function_value( &::SireMol::AtomMapping::mappedAtoms1 ); + + AtomMapping_exposer.def( + "mappedAtoms1" + , mappedAtoms1_function_value + , bp::release_gil_policy() + , "Return all of the mapped atoms that have been mapped,\n in the same order as the reference atoms they match with\n" ); + } AtomMapping_exposer.def( bp::self != bp::self ); { //::SireMol::AtomMapping::operator= @@ -280,6 +399,30 @@ void register_AtomMapping_class(){ , ( bp::arg("atoms") ) , "" ); + } + { //::SireMol::AtomMapping::propertyMap0 + + typedef ::SireBase::PropertyMap const & ( ::SireMol::AtomMapping::*propertyMap0_function_type)( ) const; + propertyMap0_function_type propertyMap0_function_value( &::SireMol::AtomMapping::propertyMap0 ); + + AtomMapping_exposer.def( + "propertyMap0" + , propertyMap0_function_value + , bp::return_value_policy< bp::copy_const_reference >() + , "Return the property map used to find properties of the\n reference molecule\n" ); + + } + { //::SireMol::AtomMapping::propertyMap1 + + typedef ::SireBase::PropertyMap const & ( ::SireMol::AtomMapping::*propertyMap1_function_type)( ) const; + propertyMap1_function_type propertyMap1_function_value( &::SireMol::AtomMapping::propertyMap1 ); + + AtomMapping_exposer.def( + "propertyMap1" + , propertyMap1_function_value + , bp::return_value_policy< bp::copy_const_reference >() + , "Return the property map used to find properties of the\n mapped molecule\n" ); + } { //::SireMol::AtomMapping::size @@ -328,6 +471,30 @@ void register_AtomMapping_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomMapping::unmappedAtoms0 + + typedef ::SireMol::SelectorM< SireMol::Atom > ( ::SireMol::AtomMapping::*unmappedAtoms0_function_type)( ) const; + unmappedAtoms0_function_type unmappedAtoms0_function_value( &::SireMol::AtomMapping::unmappedAtoms0 ); + + AtomMapping_exposer.def( + "unmappedAtoms0" + , unmappedAtoms0_function_value + , bp::release_gil_policy() + , "Return all of the reference atoms that havent been mapped,\n in the same order as they appear in the original reference\n" ); + + } + { //::SireMol::AtomMapping::unmappedAtoms1 + + typedef ::SireMol::SelectorM< SireMol::Atom > ( ::SireMol::AtomMapping::*unmappedAtoms1_function_type)( ) const; + unmappedAtoms1_function_type unmappedAtoms1_function_value( &::SireMol::AtomMapping::unmappedAtoms1 ); + + AtomMapping_exposer.def( + "unmappedAtoms1" + , unmappedAtoms1_function_value + , bp::release_gil_policy() + , "Return all of the mapped atoms that havent been mapped,\n in the same order as they appear in the original mapped atoms\n" ); + } { //::SireMol::AtomMapping::what diff --git a/wrapper/Mol/AtomMasses.pypp.cpp b/wrapper/Mol/AtomMasses.pypp.cpp index a80c8e4d6..72765da79 100644 --- a/wrapper/Mol/AtomMasses.pypp.cpp +++ b/wrapper/Mol/AtomMasses.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomMasses_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 0, 0, 0, 0, -1, 0 > >::merge + + typedef SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 0, 0, 0, 0, -1, 0 > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 0, 0, 0, 0, -1, 0 > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 0, 0, 0, 0, -1, 0 > >::merge ); + + AtomMasses_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 1, 0, 0, 0, 0, -1, 0 > >::nAtoms diff --git a/wrapper/Mol/AtomNumMatcher.pypp.cpp b/wrapper/Mol/AtomNumMatcher.pypp.cpp new file mode 100644 index 000000000..be2480507 --- /dev/null +++ b/wrapper/Mol/AtomNumMatcher.pypp.cpp @@ -0,0 +1,127 @@ +// This file has been generated by Py++. + +// (C) Christopher Woods, GPL >= 3 License + +#include "boost/python.hpp" +#include "AtomNumMatcher.pypp.hpp" + +namespace bp = boost::python; + +#include "SireError/errors.h" + +#include "SireMaths/vector.h" + +#include "SireStream/datastream.h" + +#include "SireUnits/units.h" + +#include "atom.h" + +#include "atomidentifier.h" + +#include "atomidx.h" + +#include "atommatcher.h" + +#include "atommatchers.h" + +#include "atomname.h" + +#include "atomselection.h" + +#include "evaluator.h" + +#include "moleculeinfodata.h" + +#include "moleculeview.h" + +#include "mover.h" + +#include "mover.hpp" + +#include "selector.hpp" + +#include "tostring.h" + +#include "atommatchers.h" + +SireMol::AtomNumMatcher __copy__(const SireMol::AtomNumMatcher &other){ return SireMol::AtomNumMatcher(other); } + +#include "Qt/qdatastream.hpp" + +#include "Helpers/str.hpp" + +#include "Helpers/release_gil_policy.hpp" + +void register_AtomNumMatcher_class(){ + + { //::SireMol::AtomNumMatcher + typedef bp::class_< SireMol::AtomNumMatcher, bp::bases< SireMol::AtomMatcher, SireBase::Property > > AtomNumMatcher_exposer_t; + AtomNumMatcher_exposer_t AtomNumMatcher_exposer = AtomNumMatcher_exposer_t( "AtomNumMatcher", "This is a simple atom matcher that matches the atoms based\non their numbers, so the atom with number 1 in molinfo0 will\nbe matched to the atom with number 1 in molinfo1\n", bp::init< >("Constructor") ); + bp::scope AtomNumMatcher_scope( AtomNumMatcher_exposer ); + AtomNumMatcher_exposer.def( bp::init< SireMol::AtomNumMatcher const & >(( bp::arg("arg0") ), "Copy constructor") ); + AtomNumMatcher_exposer.def( bp::self != bp::self ); + { //::SireMol::AtomNumMatcher::operator= + + typedef ::SireMol::AtomNumMatcher & ( ::SireMol::AtomNumMatcher::*assign_function_type)( ::SireMol::AtomNumMatcher const & ) ; + assign_function_type assign_function_value( &::SireMol::AtomNumMatcher::operator= ); + + AtomNumMatcher_exposer.def( + "assign" + , assign_function_value + , ( bp::arg("other") ) + , bp::return_self< >() + , "" ); + + } + AtomNumMatcher_exposer.def( bp::self == bp::self ); + { //::SireMol::AtomNumMatcher::toString + + typedef ::QString ( ::SireMol::AtomNumMatcher::*toString_function_type)( ) const; + toString_function_type toString_function_value( &::SireMol::AtomNumMatcher::toString ); + + AtomNumMatcher_exposer.def( + "toString" + , toString_function_value + , bp::release_gil_policy() + , "" ); + + } + { //::SireMol::AtomNumMatcher::typeName + + typedef char const * ( *typeName_function_type )( ); + typeName_function_type typeName_function_value( &::SireMol::AtomNumMatcher::typeName ); + + AtomNumMatcher_exposer.def( + "typeName" + , typeName_function_value + , bp::release_gil_policy() + , "" ); + + } + { //::SireMol::AtomNumMatcher::what + + typedef char const * ( ::SireMol::AtomNumMatcher::*what_function_type)( ) const; + what_function_type what_function_value( &::SireMol::AtomNumMatcher::what ); + + AtomNumMatcher_exposer.def( + "what" + , what_function_value + , bp::release_gil_policy() + , "" ); + + } + AtomNumMatcher_exposer.staticmethod( "typeName" ); + AtomNumMatcher_exposer.def( "__copy__", &__copy__); + AtomNumMatcher_exposer.def( "__deepcopy__", &__copy__); + AtomNumMatcher_exposer.def( "clone", &__copy__); + AtomNumMatcher_exposer.def( "__rlshift__", &__rlshift__QDataStream< ::SireMol::AtomNumMatcher >, + bp::return_internal_reference<1, bp::with_custodian_and_ward<1,2> >() ); + AtomNumMatcher_exposer.def( "__rrshift__", &__rrshift__QDataStream< ::SireMol::AtomNumMatcher >, + bp::return_internal_reference<1, bp::with_custodian_and_ward<1,2> >() ); + AtomNumMatcher_exposer.def_pickle(sire_pickle_suite< ::SireMol::AtomNumMatcher >()); + AtomNumMatcher_exposer.def( "__str__", &__str__< ::SireMol::AtomNumMatcher > ); + AtomNumMatcher_exposer.def( "__repr__", &__str__< ::SireMol::AtomNumMatcher > ); + } + +} diff --git a/wrapper/Mol/AtomNumMatcher.pypp.hpp b/wrapper/Mol/AtomNumMatcher.pypp.hpp new file mode 100644 index 000000000..25a905346 --- /dev/null +++ b/wrapper/Mol/AtomNumMatcher.pypp.hpp @@ -0,0 +1,10 @@ +// This file has been generated by Py++. + +// (C) Christopher Woods, GPL >= 3 License + +#ifndef AtomNumMatcher_hpp__pyplusplus_wrapper +#define AtomNumMatcher_hpp__pyplusplus_wrapper + +void register_AtomNumMatcher_class(); + +#endif//AtomNumMatcher_hpp__pyplusplus_wrapper diff --git a/wrapper/Mol/AtomPolarisabilities.pypp.cpp b/wrapper/Mol/AtomPolarisabilities.pypp.cpp index 3c5fd5c98..d635fc133 100644 --- a/wrapper/Mol/AtomPolarisabilities.pypp.cpp +++ b/wrapper/Mol/AtomPolarisabilities.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomPolarisabilities_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 3, 0, 0, 0, 0, 0 > >::merge + + typedef SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 3, 0, 0, 0, 0, 0 > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 3, 0, 0, 0, 0, 0 > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 3, 0, 0, 0, 0, 0 > >::merge ); + + AtomPolarisabilities_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 3, 0, 0, 0, 0, 0 > >::nAtoms diff --git a/wrapper/Mol/AtomProp.pypp.cpp b/wrapper/Mol/AtomProp.pypp.cpp index d69175be0..e8d2a4f88 100644 --- a/wrapper/Mol/AtomProp.pypp.cpp +++ b/wrapper/Mol/AtomProp.pypp.cpp @@ -154,6 +154,18 @@ void register_AtomProp_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProp::merge + + typedef ::SireBase::PropertyList ( ::SireMol::AtomProp::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProp::merge ); + + AtomProp_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProp::operator= diff --git a/wrapper/Mol/AtomPropertyList.pypp.cpp b/wrapper/Mol/AtomPropertyList.pypp.cpp index c50f6c871..5327e311b 100644 --- a/wrapper/Mol/AtomPropertyList.pypp.cpp +++ b/wrapper/Mol/AtomPropertyList.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomPropertyList_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireBase::PropertyList >::merge + + typedef SireMol::AtomProperty< SireBase::PropertyList > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireBase::PropertyList >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireBase::PropertyList >::merge ); + + AtomPropertyList_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireBase::PropertyList >::nAtoms diff --git a/wrapper/Mol/AtomPropertyProperty.pypp.cpp b/wrapper/Mol/AtomPropertyProperty.pypp.cpp index ec593be7b..b4620dac4 100644 --- a/wrapper/Mol/AtomPropertyProperty.pypp.cpp +++ b/wrapper/Mol/AtomPropertyProperty.pypp.cpp @@ -43,6 +43,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -386,6 +388,19 @@ void register_AtomPropertyProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireBase::PropPtr< SireBase::Property > >::merge + + typedef SireMol::AtomProperty< SireBase::PropPtr< SireBase::Property > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireBase::PropPtr< SireBase::Property > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireBase::PropPtr< SireBase::Property > >::merge ); + + AtomPropertyProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireBase::PropPtr< SireBase::Property > >::nAtoms diff --git a/wrapper/Mol/AtomRadicals.pypp.cpp b/wrapper/Mol/AtomRadicals.pypp.cpp index 6161d13da..afce09e6b 100644 --- a/wrapper/Mol/AtomRadicals.pypp.cpp +++ b/wrapper/Mol/AtomRadicals.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomRadicals_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMol::Radical >::merge + + typedef SireMol::AtomProperty< SireMol::Radical > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMol::Radical >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMol::Radical >::merge ); + + AtomRadicals_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMol::Radical >::nAtoms diff --git a/wrapper/Mol/AtomRadii.pypp.cpp b/wrapper/Mol/AtomRadii.pypp.cpp index f7464a4bb..0e4519b79 100644 --- a/wrapper/Mol/AtomRadii.pypp.cpp +++ b/wrapper/Mol/AtomRadii.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomRadii_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 1, 0, 0, 0, 0, 0 > >::merge + + typedef SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 1, 0, 0, 0, 0, 0 > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 1, 0, 0, 0, 0, 0 > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 1, 0, 0, 0, 0, 0 > >::merge ); + + AtomRadii_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireUnits::Dimension::PhysUnit< 0, 1, 0, 0, 0, 0, 0 > >::nAtoms diff --git a/wrapper/Mol/AtomSelection.pypp.cpp b/wrapper/Mol/AtomSelection.pypp.cpp index 965a79995..f726b517c 100644 --- a/wrapper/Mol/AtomSelection.pypp.cpp +++ b/wrapper/Mol/AtomSelection.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireStream/shareddatastream.h" +#include "atomidxmapping.h" + #include "atomselection.h" #include "moleculedata.h" @@ -1372,6 +1374,18 @@ void register_AtomSelection_class(){ , bp::return_self< >() , "Mask this selection by other\nThrow: SireError::incompatible_error\n" ); + } + { //::SireMol::AtomSelection::merge + + typedef ::SireBase::PropertyList ( ::SireMol::AtomSelection::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomSelection::merge ); + + AtomSelection_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomSelection::nAtoms diff --git a/wrapper/Mol/AtomStringArrayProperty.pypp.cpp b/wrapper/Mol/AtomStringArrayProperty.pypp.cpp index 578b25820..fa0f142d0 100644 --- a/wrapper/Mol/AtomStringArrayProperty.pypp.cpp +++ b/wrapper/Mol/AtomStringArrayProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -358,6 +360,19 @@ void register_AtomStringArrayProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireBase::StringArrayProperty >::merge + + typedef SireMol::AtomProperty< SireBase::StringArrayProperty > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireBase::StringArrayProperty >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireBase::StringArrayProperty >::merge ); + + AtomStringArrayProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireBase::StringArrayProperty >::nAtoms diff --git a/wrapper/Mol/AtomStringProperty.pypp.cpp b/wrapper/Mol/AtomStringProperty.pypp.cpp index 005a54d58..a14191a9a 100644 --- a/wrapper/Mol/AtomStringProperty.pypp.cpp +++ b/wrapper/Mol/AtomStringProperty.pypp.cpp @@ -43,6 +43,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -386,6 +388,19 @@ void register_AtomStringProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< QString >::merge + + typedef SireMol::AtomProperty< QString > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< QString >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< QString >::merge ); + + AtomStringProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< QString >::nAtoms diff --git a/wrapper/Mol/AtomStructureEditor.pypp.cpp b/wrapper/Mol/AtomStructureEditor.pypp.cpp index da595f49e..4cc96b5a0 100644 --- a/wrapper/Mol/AtomStructureEditor.pypp.cpp +++ b/wrapper/Mol/AtomStructureEditor.pypp.cpp @@ -67,6 +67,18 @@ void register_AtomStructureEditor_class(){ AtomStructureEditor_exposer.def( bp::init< SireMol::Atom const & >(( bp::arg("atom") ), "Construct from an Atom") ); AtomStructureEditor_exposer.def( bp::init< SireMol::StructureEditor const &, SireMol::AtomIdx >(( bp::arg("data"), bp::arg("atomidx") ), "Construct for the atom at index idx in the molecule whose data\nis being edited in moldata\nThrow: SireError::invalid_index\n") ); AtomStructureEditor_exposer.def( bp::init< SireMol::AtomStructureEditor const & >(( bp::arg("other") ), "Copy constructor") ); + { //::SireMol::AtomStructureEditor::alternateName + + typedef ::SireMol::AtomName const & ( ::SireMol::AtomStructureEditor::*alternateName_function_type)( ) const; + alternateName_function_type alternateName_function_value( &::SireMol::AtomStructureEditor::alternateName ); + + AtomStructureEditor_exposer.def( + "alternateName" + , alternateName_function_value + , bp::return_value_policy() + , "Return the alternate name for this atom" ); + + } { //::SireMol::AtomStructureEditor::chain typedef ::SireMol::ChainStructureEditor ( ::SireMol::AtomStructureEditor::*chain_function_type)( ) ; @@ -176,6 +188,19 @@ void register_AtomStructureEditor_class(){ , bp::return_self< >() , "" ); + } + { //::SireMol::AtomStructureEditor::reindex + + typedef ::SireMol::AtomStructureEditor & ( ::SireMol::AtomStructureEditor::*reindex_function_type)( int ) ; + reindex_function_type reindex_function_value( &::SireMol::AtomStructureEditor::reindex ); + + AtomStructureEditor_exposer.def( + "reindex" + , reindex_function_value + , ( bp::arg("idx") ) + , bp::return_self< >() + , "Reindex this atom" ); + } { //::SireMol::AtomStructureEditor::reindex @@ -201,6 +226,19 @@ void register_AtomStructureEditor_class(){ , bp::release_gil_policy() , "Completely remove this atom from the molecule and return\na MolStructureEditor that can be used to continue editing\nthe molecule" ); + } + { //::SireMol::AtomStructureEditor::rename + + typedef ::SireMol::AtomStructureEditor & ( ::SireMol::AtomStructureEditor::*rename_function_type)( ::QString const & ) ; + rename_function_type rename_function_value( &::SireMol::AtomStructureEditor::rename ); + + AtomStructureEditor_exposer.def( + "rename" + , rename_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Rename this atom" ); + } { //::SireMol::AtomStructureEditor::rename @@ -214,6 +252,19 @@ void register_AtomStructureEditor_class(){ , bp::return_self< >() , "Rename this atom to newname" ); + } + { //::SireMol::AtomStructureEditor::renumber + + typedef ::SireMol::AtomStructureEditor & ( ::SireMol::AtomStructureEditor::*renumber_function_type)( int ) ; + renumber_function_type renumber_function_value( &::SireMol::AtomStructureEditor::renumber ); + + AtomStructureEditor_exposer.def( + "renumber" + , renumber_function_value + , ( bp::arg("number") ) + , bp::return_self< >() + , "Renumber this atom" ); + } { //::SireMol::AtomStructureEditor::renumber @@ -341,6 +392,32 @@ void register_AtomStructureEditor_class(){ , bp::release_gil_policy() , "Return whether or not this contains the whole molecule" ); + } + { //::SireMol::AtomStructureEditor::setAlternateName + + typedef ::SireMol::AtomStructureEditor & ( ::SireMol::AtomStructureEditor::*setAlternateName_function_type)( ::QString const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::AtomStructureEditor::setAlternateName ); + + AtomStructureEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate name for this atom" ); + + } + { //::SireMol::AtomStructureEditor::setAlternateName + + typedef ::SireMol::AtomStructureEditor & ( ::SireMol::AtomStructureEditor::*setAlternateName_function_type)( ::SireMol::AtomName const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::AtomStructureEditor::setAlternateName ); + + AtomStructureEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate name for this atom" ); + } { //::SireMol::AtomStructureEditor::toString diff --git a/wrapper/Mol/AtomVariantProperty.pypp.cpp b/wrapper/Mol/AtomVariantProperty.pypp.cpp index 03d350f0c..d7bb721c3 100644 --- a/wrapper/Mol/AtomVariantProperty.pypp.cpp +++ b/wrapper/Mol/AtomVariantProperty.pypp.cpp @@ -43,6 +43,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty __copy__(const SireMol::AtomProperty &other){ return SireMol::AtomProperty(other); } #include "Qt/qdatastream.hpp" @@ -386,6 +388,19 @@ void register_AtomVariantProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< QVariant >::merge + + typedef SireMol::AtomProperty< QVariant > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< QVariant >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< QVariant >::merge ); + + AtomVariantProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< QVariant >::nAtoms diff --git a/wrapper/Mol/AtomVelocities.pypp.cpp b/wrapper/Mol/AtomVelocities.pypp.cpp index 6e8957222..d367098bf 100644 --- a/wrapper/Mol/AtomVelocities.pypp.cpp +++ b/wrapper/Mol/AtomVelocities.pypp.cpp @@ -16,6 +16,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::AtomProperty > __copy__(const SireMol::AtomProperty > &other){ return SireMol::AtomProperty >(other); } #include "Qt/qdatastream.hpp" @@ -359,6 +361,19 @@ void register_AtomVelocities_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Velocity > >::merge + + typedef SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Velocity > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Velocity > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Velocity > >::merge ); + + AtomVelocities_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::AtomProperty< SireMaths::Vector3D< SireUnits::Dimension::Velocity > >::nAtoms diff --git a/wrapper/Mol/BeadFloatProperty.pypp.cpp b/wrapper/Mol/BeadFloatProperty.pypp.cpp index d605af684..4d643353e 100644 --- a/wrapper/Mol/BeadFloatProperty.pypp.cpp +++ b/wrapper/Mol/BeadFloatProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::BeadProperty __copy__(const SireMol::BeadProperty &other){ return SireMol::BeadProperty(other); } #include "Qt/qdatastream.hpp" @@ -198,6 +200,19 @@ void register_BeadFloatProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::BeadProperty< double >::merge + + typedef SireMol::BeadProperty< double > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::BeadProperty< double >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::BeadProperty< double >::merge ); + + BeadFloatProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::BeadProperty< double >::nBeads diff --git a/wrapper/Mol/BeadIntProperty.pypp.cpp b/wrapper/Mol/BeadIntProperty.pypp.cpp index 2fe26469a..be6a0d3c8 100644 --- a/wrapper/Mol/BeadIntProperty.pypp.cpp +++ b/wrapper/Mol/BeadIntProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::BeadProperty __copy__(const SireMol::BeadProperty &other){ return SireMol::BeadProperty(other); } #include "Qt/qdatastream.hpp" @@ -198,6 +200,19 @@ void register_BeadIntProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::BeadProperty< long long >::merge + + typedef SireMol::BeadProperty< long long > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::BeadProperty< long long >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::BeadProperty< long long >::merge ); + + BeadIntProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::BeadProperty< long long >::nBeads diff --git a/wrapper/Mol/BeadPropertyProperty.pypp.cpp b/wrapper/Mol/BeadPropertyProperty.pypp.cpp index 2cccc3f0c..17b02ae8b 100644 --- a/wrapper/Mol/BeadPropertyProperty.pypp.cpp +++ b/wrapper/Mol/BeadPropertyProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::BeadProperty > __copy__(const SireMol::BeadProperty > &other){ return SireMol::BeadProperty >(other); } #include "Qt/qdatastream.hpp" @@ -198,6 +200,19 @@ void register_BeadPropertyProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::BeadProperty< SireBase::PropPtr< SireBase::Property > >::merge + + typedef SireMol::BeadProperty< SireBase::PropPtr< SireBase::Property > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::BeadProperty< SireBase::PropPtr< SireBase::Property > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::BeadProperty< SireBase::PropPtr< SireBase::Property > >::merge ); + + BeadPropertyProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::BeadProperty< SireBase::PropPtr< SireBase::Property > >::nBeads diff --git a/wrapper/Mol/BeadStringProperty.pypp.cpp b/wrapper/Mol/BeadStringProperty.pypp.cpp index 5afeab2cc..1cce2d11c 100644 --- a/wrapper/Mol/BeadStringProperty.pypp.cpp +++ b/wrapper/Mol/BeadStringProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::BeadProperty __copy__(const SireMol::BeadProperty &other){ return SireMol::BeadProperty(other); } #include "Qt/qdatastream.hpp" @@ -198,6 +200,19 @@ void register_BeadStringProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::BeadProperty< QString >::merge + + typedef SireMol::BeadProperty< QString > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::BeadProperty< QString >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::BeadProperty< QString >::merge ); + + BeadStringProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::BeadProperty< QString >::nBeads diff --git a/wrapper/Mol/BeadVariantProperty.pypp.cpp b/wrapper/Mol/BeadVariantProperty.pypp.cpp index 555f895a6..fc66d9610 100644 --- a/wrapper/Mol/BeadVariantProperty.pypp.cpp +++ b/wrapper/Mol/BeadVariantProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::BeadProperty __copy__(const SireMol::BeadProperty &other){ return SireMol::BeadProperty(other); } #include "Qt/qdatastream.hpp" @@ -198,6 +200,19 @@ void register_BeadVariantProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::BeadProperty< QVariant >::merge + + typedef SireMol::BeadProperty< QVariant > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::BeadProperty< QVariant >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::BeadProperty< QVariant >::merge ); + + BeadVariantProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::BeadProperty< QVariant >::nBeads diff --git a/wrapper/Mol/Beading.pypp.cpp b/wrapper/Mol/Beading.pypp.cpp index ac8b3efa7..1ee8e55e8 100644 --- a/wrapper/Mol/Beading.pypp.cpp +++ b/wrapper/Mol/Beading.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireError/errors.h" @@ -57,6 +59,18 @@ void register_Beading_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Beading::merge + + typedef ::SireBase::PropertyList ( ::SireMol::Beading::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::Beading::merge ); + + Beading_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMol::Beading::null diff --git a/wrapper/Mol/CGFloatProperty.pypp.cpp b/wrapper/Mol/CGFloatProperty.pypp.cpp index 35ff46ef6..d711bc735 100644 --- a/wrapper/Mol/CGFloatProperty.pypp.cpp +++ b/wrapper/Mol/CGFloatProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::CGProperty __copy__(const SireMol::CGProperty &other){ return SireMol::CGProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_CGFloatProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::CGProperty< double >::merge + + typedef SireMol::CGProperty< double > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::CGProperty< double >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::CGProperty< double >::merge ); + + CGFloatProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::CGProperty< double >::nCutGroups diff --git a/wrapper/Mol/CGIntProperty.pypp.cpp b/wrapper/Mol/CGIntProperty.pypp.cpp index 9df74a473..b668c6da6 100644 --- a/wrapper/Mol/CGIntProperty.pypp.cpp +++ b/wrapper/Mol/CGIntProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::CGProperty __copy__(const SireMol::CGProperty &other){ return SireMol::CGProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_CGIntProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::CGProperty< long long >::merge + + typedef SireMol::CGProperty< long long > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::CGProperty< long long >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::CGProperty< long long >::merge ); + + CGIntProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::CGProperty< long long >::nCutGroups diff --git a/wrapper/Mol/CGPropertyProperty.pypp.cpp b/wrapper/Mol/CGPropertyProperty.pypp.cpp index f976cc2aa..0df839d3f 100644 --- a/wrapper/Mol/CGPropertyProperty.pypp.cpp +++ b/wrapper/Mol/CGPropertyProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::CGProperty > __copy__(const SireMol::CGProperty > &other){ return SireMol::CGProperty >(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_CGPropertyProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::CGProperty< SireBase::PropPtr< SireBase::Property > >::merge + + typedef SireMol::CGProperty< SireBase::PropPtr< SireBase::Property > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::CGProperty< SireBase::PropPtr< SireBase::Property > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::CGProperty< SireBase::PropPtr< SireBase::Property > >::merge ); + + CGPropertyProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::CGProperty< SireBase::PropPtr< SireBase::Property > >::nCutGroups diff --git a/wrapper/Mol/CGStringProperty.pypp.cpp b/wrapper/Mol/CGStringProperty.pypp.cpp index 527b9e4d0..e635add52 100644 --- a/wrapper/Mol/CGStringProperty.pypp.cpp +++ b/wrapper/Mol/CGStringProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::CGProperty __copy__(const SireMol::CGProperty &other){ return SireMol::CGProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_CGStringProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::CGProperty< QString >::merge + + typedef SireMol::CGProperty< QString > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::CGProperty< QString >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::CGProperty< QString >::merge ); + + CGStringProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::CGProperty< QString >::nCutGroups diff --git a/wrapper/Mol/CGVariantProperty.pypp.cpp b/wrapper/Mol/CGVariantProperty.pypp.cpp index e225fa039..fa9585b4b 100644 --- a/wrapper/Mol/CGVariantProperty.pypp.cpp +++ b/wrapper/Mol/CGVariantProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::CGProperty __copy__(const SireMol::CGProperty &other){ return SireMol::CGProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_CGVariantProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::CGProperty< QVariant >::merge + + typedef SireMol::CGProperty< QVariant > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::CGProperty< QVariant >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::CGProperty< QVariant >::merge ); + + CGVariantProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::CGProperty< QVariant >::nCutGroups diff --git a/wrapper/Mol/CMakeAutogenFile.txt b/wrapper/Mol/CMakeAutogenFile.txt index 2a199e84c..67aa7f594 100644 --- a/wrapper/Mol/CMakeAutogenFile.txt +++ b/wrapper/Mol/CMakeAutogenFile.txt @@ -37,6 +37,7 @@ set ( PYPP_SOURCES ResNum.pypp.cpp Atom.pypp.cpp ResIntProperty.pypp.cpp + AtomIdxMappingEntry.pypp.cpp Frame.pypp.cpp Hybridization.pypp.cpp BondID.pypp.cpp @@ -145,6 +146,7 @@ set ( PYPP_SOURCES GeometryPerturbation.pypp.cpp VolumeMap.pypp.cpp Mover_Beads_.pypp.cpp + AtomIdxMapping.pypp.cpp MoverBase.pypp.cpp AtomPropertyList.pypp.cpp IDOrSet_CGID_.pypp.cpp @@ -257,6 +259,7 @@ set ( PYPP_SOURCES ChainIntProperty.pypp.cpp IDAndSet_CGID_.pypp.cpp Specify_SegID_.pypp.cpp + AtomNumMatcher.pypp.cpp Molecule.pypp.cpp Mover_Chain_.pypp.cpp ChainStructureEditor.pypp.cpp diff --git a/wrapper/Mol/ChainFloatProperty.pypp.cpp b/wrapper/Mol/ChainFloatProperty.pypp.cpp index 3c305f7f9..28d406758 100644 --- a/wrapper/Mol/ChainFloatProperty.pypp.cpp +++ b/wrapper/Mol/ChainFloatProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ChainProperty __copy__(const SireMol::ChainProperty &other){ return SireMol::ChainProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ChainFloatProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ChainProperty< double >::merge + + typedef SireMol::ChainProperty< double > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ChainProperty< double >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ChainProperty< double >::merge ); + + ChainFloatProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ChainProperty< double >::nChains diff --git a/wrapper/Mol/ChainIntProperty.pypp.cpp b/wrapper/Mol/ChainIntProperty.pypp.cpp index 2f46c9c30..e46b0649b 100644 --- a/wrapper/Mol/ChainIntProperty.pypp.cpp +++ b/wrapper/Mol/ChainIntProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ChainProperty __copy__(const SireMol::ChainProperty &other){ return SireMol::ChainProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ChainIntProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ChainProperty< long long >::merge + + typedef SireMol::ChainProperty< long long > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ChainProperty< long long >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ChainProperty< long long >::merge ); + + ChainIntProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ChainProperty< long long >::nChains diff --git a/wrapper/Mol/ChainPropertyProperty.pypp.cpp b/wrapper/Mol/ChainPropertyProperty.pypp.cpp index 87f1e9a26..41d1c5ae1 100644 --- a/wrapper/Mol/ChainPropertyProperty.pypp.cpp +++ b/wrapper/Mol/ChainPropertyProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ChainProperty > __copy__(const SireMol::ChainProperty > &other){ return SireMol::ChainProperty >(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ChainPropertyProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ChainProperty< SireBase::PropPtr< SireBase::Property > >::merge + + typedef SireMol::ChainProperty< SireBase::PropPtr< SireBase::Property > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ChainProperty< SireBase::PropPtr< SireBase::Property > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ChainProperty< SireBase::PropPtr< SireBase::Property > >::merge ); + + ChainPropertyProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ChainProperty< SireBase::PropPtr< SireBase::Property > >::nChains diff --git a/wrapper/Mol/ChainStringProperty.pypp.cpp b/wrapper/Mol/ChainStringProperty.pypp.cpp index a1d1e6651..a5a716994 100644 --- a/wrapper/Mol/ChainStringProperty.pypp.cpp +++ b/wrapper/Mol/ChainStringProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ChainProperty __copy__(const SireMol::ChainProperty &other){ return SireMol::ChainProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ChainStringProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ChainProperty< QString >::merge + + typedef SireMol::ChainProperty< QString > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ChainProperty< QString >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ChainProperty< QString >::merge ); + + ChainStringProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ChainProperty< QString >::nChains diff --git a/wrapper/Mol/ChainVariantProperty.pypp.cpp b/wrapper/Mol/ChainVariantProperty.pypp.cpp index 80408e949..2269dbe1c 100644 --- a/wrapper/Mol/ChainVariantProperty.pypp.cpp +++ b/wrapper/Mol/ChainVariantProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ChainProperty __copy__(const SireMol::ChainProperty &other){ return SireMol::ChainProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ChainVariantProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ChainProperty< QVariant >::merge + + typedef SireMol::ChainProperty< QVariant > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ChainProperty< QVariant >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ChainProperty< QVariant >::merge ); + + ChainVariantProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ChainProperty< QVariant >::nChains diff --git a/wrapper/Mol/Connectivity.pypp.cpp b/wrapper/Mol/Connectivity.pypp.cpp index 21fdd8d1f..da6ffb1aa 100644 --- a/wrapper/Mol/Connectivity.pypp.cpp +++ b/wrapper/Mol/Connectivity.pypp.cpp @@ -7,10 +7,14 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" +#include "SireError/errors.h" + #include "SireMol/errors.h" #include "SireStream/datastream.h" @@ -19,6 +23,8 @@ namespace bp = boost::python; #include "angleid.h" +#include "atomidxmapping.h" + #include "atommatcher.h" #include "atomselection.h" diff --git a/wrapper/Mol/ConnectivityBase.pypp.cpp b/wrapper/Mol/ConnectivityBase.pypp.cpp index 9aecbab9e..693b180a4 100644 --- a/wrapper/Mol/ConnectivityBase.pypp.cpp +++ b/wrapper/Mol/ConnectivityBase.pypp.cpp @@ -8,10 +8,14 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" +#include "SireError/errors.h" + #include "SireMol/errors.h" #include "SireStream/datastream.h" @@ -20,6 +24,8 @@ namespace bp = boost::python; #include "angleid.h" +#include "atomidxmapping.h" + #include "atommatcher.h" #include "atomselection.h" @@ -542,6 +548,18 @@ void register_ConnectivityBase_class(){ , bp::release_gil_policy() , "Return the list of bonds in the connectivity containing atom" ); + } + { //::SireMol::ConnectivityBase::getBonds + + typedef ::QList< SireMol::BondID > ( ::SireMol::ConnectivityBase::*getBonds_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) const; + getBonds_function_type getBonds_function_value( &::SireMol::ConnectivityBase::getBonds ); + + ConnectivityBase_exposer.def( + "getBonds" + , getBonds_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , "Return all of the connections that involve the passed atoms - if exclusive is true,\n then return only connections where both atoms are present in the list.\n" ); + } { //::SireMol::ConnectivityBase::getDihedrals @@ -813,6 +831,18 @@ void register_ConnectivityBase_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ConnectivityBase::merge + + typedef ::SireBase::PropertyList ( ::SireMol::ConnectivityBase::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ConnectivityBase::merge ); + + ConnectivityBase_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMol::ConnectivityBase::nConnections diff --git a/wrapper/Mol/ConnectivityEditor.pypp.cpp b/wrapper/Mol/ConnectivityEditor.pypp.cpp index c494b0c57..f3128db33 100644 --- a/wrapper/Mol/ConnectivityEditor.pypp.cpp +++ b/wrapper/Mol/ConnectivityEditor.pypp.cpp @@ -7,10 +7,14 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireBase/parallel.h" +#include "SireError/errors.h" + #include "SireMol/errors.h" #include "SireStream/datastream.h" @@ -19,6 +23,8 @@ namespace bp = boost::python; #include "angleid.h" +#include "atomidxmapping.h" + #include "atommatcher.h" #include "atomselection.h" @@ -104,6 +110,32 @@ void register_ConnectivityEditor_class(){ , bp::return_self< >() , "Record a connection between the atom identified by atom0 and\nthe atom identified by atom1\nThrow: SireMol::missing_atom\nThrow: SireMol::duplicate_atom\nThrow: SireError::invalid_index\n" ); + } + { //::SireMol::ConnectivityEditor::connect + + typedef ::SireMol::ConnectivityEditor & ( ::SireMol::ConnectivityEditor::*connect_function_type)( ::SireMol::BondID const & ) ; + connect_function_type connect_function_value( &::SireMol::ConnectivityEditor::connect ); + + ConnectivityEditor_exposer.def( + "connect" + , connect_function_value + , ( bp::arg("bond") ) + , bp::return_self< >() + , "Create a connection for the passed bond" ); + + } + { //::SireMol::ConnectivityEditor::connect + + typedef ::SireMol::ConnectivityEditor & ( ::SireMol::ConnectivityEditor::*connect_function_type)( ::QList< SireMol::BondID > const & ) ; + connect_function_type connect_function_value( &::SireMol::ConnectivityEditor::connect ); + + ConnectivityEditor_exposer.def( + "connect" + , connect_function_value + , ( bp::arg("bonds") ) + , bp::return_self< >() + , "Create a connection for the passed bonds" ); + } { //::SireMol::ConnectivityEditor::disconnect @@ -130,6 +162,45 @@ void register_ConnectivityEditor_class(){ , bp::return_self< >() , "Disconnect the atoms that are identified by atom0 and atom1 -\nthis does nothing if there isnt a connection between these atoms\nThrow: SireMol::missing_atom\nThrow: SireMol::duplicate_atom\nThrow: SireError::invalid_index\n" ); + } + { //::SireMol::ConnectivityEditor::disconnect + + typedef ::SireMol::ConnectivityEditor & ( ::SireMol::ConnectivityEditor::*disconnect_function_type)( ::SireMol::BondID const & ) ; + disconnect_function_type disconnect_function_value( &::SireMol::ConnectivityEditor::disconnect ); + + ConnectivityEditor_exposer.def( + "disconnect" + , disconnect_function_value + , ( bp::arg("bond") ) + , bp::return_self< >() + , "Disconnect the atoms in the passed bond - this does nothing if the\n atoms arent connected" ); + + } + { //::SireMol::ConnectivityEditor::disconnect + + typedef ::SireMol::ConnectivityEditor & ( ::SireMol::ConnectivityEditor::*disconnect_function_type)( ::QList< SireMol::BondID > const & ) ; + disconnect_function_type disconnect_function_value( &::SireMol::ConnectivityEditor::disconnect ); + + ConnectivityEditor_exposer.def( + "disconnect" + , disconnect_function_value + , ( bp::arg("bonds") ) + , bp::return_self< >() + , "Disconnect the atoms in the passed bonds - this does nothing for any\n of the atoms that arent connected" ); + + } + { //::SireMol::ConnectivityEditor::disconnect + + typedef ::SireMol::ConnectivityEditor & ( ::SireMol::ConnectivityEditor::*disconnect_function_type)( ::QList< SireMol::AtomIdx > const &,bool ) ; + disconnect_function_type disconnect_function_value( &::SireMol::ConnectivityEditor::disconnect ); + + ConnectivityEditor_exposer.def( + "disconnect" + , disconnect_function_value + , ( bp::arg("atoms"), bp::arg("exclusive")=(bool)(true) ) + , bp::return_self< >() + , "Disconnect any and all bonds involving the passed atoms. If exclusive is true,\n then this only removes connection where both atoms are in atoms, otherwise\n it removes connections which have one of more atoms in atoms\n" ); + } { //::SireMol::ConnectivityEditor::disconnectAll diff --git a/wrapper/Mol/Element.pypp.cpp b/wrapper/Mol/Element.pypp.cpp index 20e8fc4c7..f4f6db97c 100644 --- a/wrapper/Mol/Element.pypp.cpp +++ b/wrapper/Mol/Element.pypp.cpp @@ -88,7 +88,7 @@ void register_Element_class(){ , biologicalElement_function_value , ( bp::arg("name") ) , bp::release_gil_policy() - , "Return a biological element that has been guessed from the passed name.\nNote that if no biological element was guessed, then the nearest\nnon-biological element match is used. A biological element is one that\nis in the first couple of rows (proton number < 18) and is not a noble gas." ); + , "Return a biological element that has been guessed from the passed name.\nNote that if no biological element was guessed, then the nearest\nnon-biological element match is used. A biological element is one that\nis in the list of biological elements" ); } { //::SireMol::Element::blue @@ -149,7 +149,7 @@ void register_Element_class(){ "getBiologicalElements" , getBiologicalElements_function_value , bp::release_gil_policy() - , "" ); + , "Return a list of all of the elements that are considered\n to be biological\n" ); } { //::SireMol::Element::green @@ -343,7 +343,7 @@ void register_Element_class(){ , setElementIsBiological_function_value , ( bp::arg("element") ) , bp::release_gil_policy() - , "" ); + , "Set that the passed element should be considered to be biological" ); } { //::SireMol::Element::setElementIsNotBiological @@ -356,7 +356,7 @@ void register_Element_class(){ , setElementIsNotBiological_function_value , ( bp::arg("element") ) , bp::release_gil_policy() - , "" ); + , "Set that the passed element should considered to definitely\n not be biological\n" ); } { //::SireMol::Element::symbol diff --git a/wrapper/Mol/Frame.pypp.cpp b/wrapper/Mol/Frame.pypp.cpp index 5a817d414..eb5b6dc84 100644 --- a/wrapper/Mol/Frame.pypp.cpp +++ b/wrapper/Mol/Frame.pypp.cpp @@ -8,6 +8,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/generalunitproperty.h" #include "SireBase/lazyevaluator.h" @@ -32,6 +34,8 @@ namespace bp = boost::python; #include "SireVol/space.h" +#include "atomidxmapping.h" + #include "trajectory.h" #include "trajectoryaligner.h" @@ -180,6 +184,18 @@ void register_Frame_class(){ , ( bp::arg("frames"), bp::arg("use_parallel")=(bool)(true) ) , "Join the vector of passed frames into a single frame. The\n frames are joined in order, e.g. from the first atom in\n the first frame to the last atom in the last frame\n" ); + } + { //::SireMol::Frame::merge + + typedef ::SireBase::PropertyList ( ::SireMol::Frame::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::Frame::merge ); + + Frame_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMol::Frame::nAtoms @@ -268,7 +284,7 @@ void register_Frame_class(){ , reorder_function_value , ( bp::arg("order") ) , bp::release_gil_policy() - , "" ); + , "Return a copy of this frame which has been reordered according\n to order (i.e. atom i is moved to order[i]). This does nothing\n if the order is empty. It silently ignores invalid orders, and\n will leave atoms that arent referenced in their original\n positions\n" ); } { //::SireMol::Frame::reverse diff --git a/wrapper/Mol/MolEditor.pypp.cpp b/wrapper/Mol/MolEditor.pypp.cpp index 105683b9c..4593e4838 100644 --- a/wrapper/Mol/MolEditor.pypp.cpp +++ b/wrapper/Mol/MolEditor.pypp.cpp @@ -172,6 +172,18 @@ void register_MolEditor_class(){ , bp::release_gil_policy() , "Commit these changes and return a copy of the\nedited molecule" ); + } + { //::SireMol::MolEditor::makeSingleCutGroup + + typedef ::SireMol::MolStructureEditor ( ::SireMol::MolEditor::*makeSingleCutGroup_function_type)( ) const; + makeSingleCutGroup_function_type makeSingleCutGroup_function_value( &::SireMol::MolEditor::makeSingleCutGroup ); + + MolEditor_exposer.def( + "makeSingleCutGroup" + , makeSingleCutGroup_function_value + , bp::return_self< >() + , "Return an editor where all atoms have been moved into a\n single cutgroup\n" ); + } { //::SireMol::MolEditor::operator= @@ -335,6 +347,18 @@ void register_MolEditor_class(){ , bp::release_gil_policy() , "Remove all segments from this molecule. This returns an editor that\ncan be used to further edit the structure of this molecule" ); + } + { //::SireMol::MolEditor::removeAlternateNames + + typedef ::SireMol::MolEditor & ( ::SireMol::MolEditor::*removeAlternateNames_function_type)( ) ; + removeAlternateNames_function_type removeAlternateNames_function_value( &::SireMol::MolEditor::removeAlternateNames ); + + MolEditor_exposer.def( + "removeAlternateNames" + , removeAlternateNames_function_value + , bp::return_self< >() + , "Remove all alternate names from this molecule" ); + } { //::SireMol::MolEditor::removeLink @@ -425,6 +449,19 @@ void register_MolEditor_class(){ , bp::return_self< >() , "Renumber the atoms and residues in the molecule according to the passed maps" ); + } + { //::SireMol::MolEditor::switchToAlternateNames + + typedef ::SireMol::MolEditor & ( ::SireMol::MolEditor::*switchToAlternateNames_function_type)( bool ) ; + switchToAlternateNames_function_type switchToAlternateNames_function_value( &::SireMol::MolEditor::switchToAlternateNames ); + + MolEditor_exposer.def( + "switchToAlternateNames" + , switchToAlternateNames_function_value + , ( bp::arg("keep_originals")=(bool)(true) ) + , bp::return_self< >() + , "Switch to using the alternate names for all atoms and residues.\n If keep_originals is true, then the original names will be\n stored in the alternate names. If keep_originals is false,\n then the original names will be removed.\n" ); + } { //::SireMol::MolEditor::toString diff --git a/wrapper/Mol/MolStructureEditor.pypp.cpp b/wrapper/Mol/MolStructureEditor.pypp.cpp index 8430d65f2..be0e4d589 100644 --- a/wrapper/Mol/MolStructureEditor.pypp.cpp +++ b/wrapper/Mol/MolStructureEditor.pypp.cpp @@ -198,6 +198,18 @@ void register_MolStructureEditor_class(){ , bp::release_gil_policy() , "Return an editor for the CutGroup at ID cgid\nThrow: SireMol::missing_cutgroup\nThrow: SireMol::duplicate_cutgroup\nThrow: SireError::invalid_index\n" ); + } + { //::SireMol::MolStructureEditor::makeSingleCutGroup + + typedef ::SireMol::MolStructureEditor & ( ::SireMol::MolStructureEditor::*makeSingleCutGroup_function_type)( ) ; + makeSingleCutGroup_function_type makeSingleCutGroup_function_value( &::SireMol::MolStructureEditor::makeSingleCutGroup ); + + MolStructureEditor_exposer.def( + "makeSingleCutGroup" + , makeSingleCutGroup_function_value + , bp::return_self< >() + , "Move all atoms into a single CutGroup" ); + } { //::SireMol::MolStructureEditor::nAtoms @@ -446,6 +458,18 @@ void register_MolStructureEditor_class(){ , bp::return_self< >() , "Remove all segments from this molecule" ); + } + { //::SireMol::MolStructureEditor::removeAlternateNames + + typedef ::SireMol::MolStructureEditor ( ::SireMol::MolStructureEditor::*removeAlternateNames_function_type)( ) ; + removeAlternateNames_function_type removeAlternateNames_function_value( &::SireMol::MolStructureEditor::removeAlternateNames ); + + MolStructureEditor_exposer.def( + "removeAlternateNames" + , removeAlternateNames_function_value + , bp::return_self< >() + , "Remove all alternate names from this molecule" ); + } { //::SireMol::MolStructureEditor::rename @@ -587,6 +611,19 @@ void register_MolStructureEditor_class(){ , bp::release_gil_policy() , "Return whether or not this is a complete molecule" ); + } + { //::SireMol::MolStructureEditor::switchToAlternateNames + + typedef ::SireMol::MolStructureEditor ( ::SireMol::MolStructureEditor::*switchToAlternateNames_function_type)( bool ) ; + switchToAlternateNames_function_type switchToAlternateNames_function_value( &::SireMol::MolStructureEditor::switchToAlternateNames ); + + MolStructureEditor_exposer.def( + "switchToAlternateNames" + , switchToAlternateNames_function_value + , ( bp::arg("keep_originals")=(bool)(true) ) + , bp::return_self< >() + , "Switch to using the alternate names for all atoms and residues.\n If keep_originals is true, then the original names will be\n stored in the alternate names. If keep_originals is false,\n then the original names will be removed.\n" ); + } { //::SireMol::MolStructureEditor::toString diff --git a/wrapper/Mol/MolViewProperty.pypp.cpp b/wrapper/Mol/MolViewProperty.pypp.cpp index dcfa4909f..541d5fd96 100644 --- a/wrapper/Mol/MolViewProperty.pypp.cpp +++ b/wrapper/Mol/MolViewProperty.pypp.cpp @@ -9,6 +9,8 @@ namespace bp = boost::python; #include "SireError/errors.h" +#include "atomidxmapping.h" + #include "atommatcher.h" #include "atommatchers.h" @@ -160,6 +162,18 @@ void register_MolViewProperty_class(){ , bp::release_gil_policy() , "Do everything possible to make this property compatible with the\nMoleculeInfoData layout in info - otherwise raise an error\nThrow: SireError::incompatible_error\n" ); + } + { //::SireMol::MolViewProperty::merge + + typedef ::SireBase::PropertyList ( ::SireMol::MolViewProperty::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::MolViewProperty::merge ); + + MolViewProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::MolViewProperty::typeName diff --git a/wrapper/Mol/MoleculeBeading.pypp.cpp b/wrapper/Mol/MoleculeBeading.pypp.cpp index 7482cd847..4e48be71b 100644 --- a/wrapper/Mol/MoleculeBeading.pypp.cpp +++ b/wrapper/Mol/MoleculeBeading.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireError/errors.h" diff --git a/wrapper/Mol/MoleculeInfo.pypp.cpp b/wrapper/Mol/MoleculeInfo.pypp.cpp index 0ae183e49..3ed260992 100644 --- a/wrapper/Mol/MoleculeInfo.pypp.cpp +++ b/wrapper/Mol/MoleculeInfo.pypp.cpp @@ -54,6 +54,58 @@ void register_MoleculeInfo_class(){ , bp::return_value_policy< bp::copy_const_reference >() , "Return the unique ID of this layout. Each unique layout has its\nown unique ID. You can use this to quickly check if two molecules\nhave the same layout" ); + } + { //::SireMol::MoleculeInfo::alternateName + + typedef ::SireMol::AtomName const & ( ::SireMol::MoleculeInfo::*alternateName_function_type)( ::SireMol::AtomID const & ) const; + alternateName_function_type alternateName_function_value( &::SireMol::MoleculeInfo::alternateName ); + + MoleculeInfo_exposer.def( + "alternateName" + , alternateName_function_value + , ( bp::arg("atomid") ) + , bp::return_value_policy() + , "Return the alternate name of the specified atom" ); + + } + { //::SireMol::MoleculeInfo::alternateName + + typedef ::SireMol::AtomName const & ( ::SireMol::MoleculeInfo::*alternateName_function_type)( ::SireMol::AtomIdx ) const; + alternateName_function_type alternateName_function_value( &::SireMol::MoleculeInfo::alternateName ); + + MoleculeInfo_exposer.def( + "alternateName" + , alternateName_function_value + , ( bp::arg("atomidx") ) + , bp::return_value_policy() + , "Return the alternate name of the specified atom" ); + + } + { //::SireMol::MoleculeInfo::alternateName + + typedef ::SireMol::ResName const & ( ::SireMol::MoleculeInfo::*alternateName_function_type)( ::SireMol::ResID const & ) const; + alternateName_function_type alternateName_function_value( &::SireMol::MoleculeInfo::alternateName ); + + MoleculeInfo_exposer.def( + "alternateName" + , alternateName_function_value + , ( bp::arg("resid") ) + , bp::return_value_policy() + , "Return the alternate name of the specified residue" ); + + } + { //::SireMol::MoleculeInfo::alternateName + + typedef ::SireMol::ResName const & ( ::SireMol::MoleculeInfo::*alternateName_function_type)( ::SireMol::ResIdx ) const; + alternateName_function_type alternateName_function_value( &::SireMol::MoleculeInfo::alternateName ); + + MoleculeInfo_exposer.def( + "alternateName" + , alternateName_function_value + , ( bp::arg("residx") ) + , bp::return_value_policy() + , "Return the alternate name of the specified residue" ); + } { //::SireMol::MoleculeInfo::assertCompatibleWith @@ -2056,6 +2108,18 @@ void register_MoleculeInfo_class(){ , bp::release_gil_policy() , "Return the index of the parent segment of the identified atom" ); + } + { //::SireMol::MoleculeInfo::removeAlternateNames + + typedef ::SireMol::MoleculeInfo ( ::SireMol::MoleculeInfo::*removeAlternateNames_function_type)( ) const; + removeAlternateNames_function_type removeAlternateNames_function_value( &::SireMol::MoleculeInfo::removeAlternateNames ); + + MoleculeInfo_exposer.def( + "removeAlternateNames" + , removeAlternateNames_function_value + , bp::release_gil_policy() + , "Remove all alternate names from this molecule" ); + } { //::SireMol::MoleculeInfo::rename @@ -2173,6 +2237,32 @@ void register_MoleculeInfo_class(){ , bp::release_gil_policy() , "Return the index of the identified segment" ); + } + { //::SireMol::MoleculeInfo::setAlternateName + + typedef ::SireMol::MoleculeInfo ( ::SireMol::MoleculeInfo::*setAlternateName_function_type)( ::SireMol::AtomIdx,::SireMol::AtomName const & ) const; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::MoleculeInfo::setAlternateName ); + + MoleculeInfo_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("atomidx"), bp::arg("name") ) + , bp::release_gil_policy() + , "Set the alternate name of the passed atom" ); + + } + { //::SireMol::MoleculeInfo::setAlternateName + + typedef ::SireMol::MoleculeInfo ( ::SireMol::MoleculeInfo::*setAlternateName_function_type)( ::SireMol::ResIdx,::SireMol::ResName const & ) const; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::MoleculeInfo::setAlternateName ); + + MoleculeInfo_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("residx"), bp::arg("name") ) + , bp::release_gil_policy() + , "Set the alternate name of the passed atom" ); + } { //::SireMol::MoleculeInfo::squeeze @@ -2186,6 +2276,18 @@ void register_MoleculeInfo_class(){ , bp::release_gil_policy() , "Use this function to minimise memory usage - this function\ncompares the shared data in this info with other, and where\nthey are equal it copies the data from other, thereby reducing\nwastage caused by duplicated storage\n" ); + } + { //::SireMol::MoleculeInfo::switchToAlternateNames + + typedef ::SireMol::MoleculeInfo ( ::SireMol::MoleculeInfo::*switchToAlternateNames_function_type)( bool ) const; + switchToAlternateNames_function_type switchToAlternateNames_function_value( &::SireMol::MoleculeInfo::switchToAlternateNames ); + + MoleculeInfo_exposer.def( + "switchToAlternateNames" + , switchToAlternateNames_function_value + , ( bp::arg("keep_originals")=(bool)(true) ) + , "Switch to using the alternate names for all atoms and residues.\n If keep_originals is true, then the original names will be\n stored in the alternate names. If keep_originals is false,\n then the original names will be removed.\n" ); + } { //::SireMol::MoleculeInfo::typeName diff --git a/wrapper/Mol/MoleculeProperty.pypp.cpp b/wrapper/Mol/MoleculeProperty.pypp.cpp index fda91a530..90b44777d 100644 --- a/wrapper/Mol/MoleculeProperty.pypp.cpp +++ b/wrapper/Mol/MoleculeProperty.pypp.cpp @@ -9,6 +9,8 @@ namespace bp = boost::python; #include "SireError/errors.h" +#include "atomidxmapping.h" + #include "atommatcher.h" #include "atommatchers.h" diff --git a/wrapper/Mol/MoleculeView.pypp.cpp b/wrapper/Mol/MoleculeView.pypp.cpp index 5dc1e56d6..42bbd56df 100644 --- a/wrapper/Mol/MoleculeView.pypp.cpp +++ b/wrapper/Mol/MoleculeView.pypp.cpp @@ -673,7 +673,7 @@ void register_MoleculeView_class(){ "extract" , extract_function_value , ( bp::arg("to_same_molecule")=(bool)(false) ) - , "" ); + , "Extract a copy of this view which contains only the currently\nselected atoms. This allows the used to pull out parts of a larger molecule,\ne.g. if they want to have only selected residues in a protein and do not\nwant to have to store or manipulate the larger protein molecule" ); } { //::SireMol::MoleculeView::getLink diff --git a/wrapper/Mol/NullBeading.pypp.cpp b/wrapper/Mol/NullBeading.pypp.cpp index 71e678af2..3b6ffb4ea 100644 --- a/wrapper/Mol/NullBeading.pypp.cpp +++ b/wrapper/Mol/NullBeading.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireError/errors.h" diff --git a/wrapper/Mol/ResEditor.pypp.cpp b/wrapper/Mol/ResEditor.pypp.cpp index 8bff8cee9..6c961b701 100644 --- a/wrapper/Mol/ResEditor.pypp.cpp +++ b/wrapper/Mol/ResEditor.pypp.cpp @@ -84,6 +84,18 @@ void register_ResEditor_class(){ , bp::release_gil_policy() , "Add a new atom with the number number to this residue - this\nreturns an editor that can be used to further edit this atom" ); + } + { //::SireMol::ResEditor::alternateName + + typedef ::SireMol::ResName ( ::SireMol::ResEditor::*alternateName_function_type)( ) const; + alternateName_function_type alternateName_function_value( &::SireMol::ResEditor::alternateName ); + + ResEditor_exposer.def( + "alternateName" + , alternateName_function_value + , bp::release_gil_policy() + , "Return the alternate name for this residue" ); + } { //::SireMol::ResEditor::commit @@ -135,6 +147,19 @@ void register_ResEditor_class(){ , bp::release_gil_policy() , "Change the index of this residue to newidx. If this\nis larger than the number of residues in the molecule\nthen this residue is moved to the end" ); + } + { //::SireMol::ResEditor::reindex + + typedef ::SireMol::ResStructureEditor ( ::SireMol::ResEditor::*reindex_function_type)( int ) const; + reindex_function_type reindex_function_value( &::SireMol::ResEditor::reindex ); + + ResEditor_exposer.def( + "reindex" + , reindex_function_value + , ( bp::arg("index") ) + , bp::release_gil_policy() + , "Reindex this residue to newidx" ); + } { //::SireMol::ResEditor::remove @@ -186,6 +211,19 @@ void register_ResEditor_class(){ , bp::return_self< >() , "Rename this residue to newname" ); + } + { //::SireMol::ResEditor::rename + + typedef ::SireMol::ResEditor & ( ::SireMol::ResEditor::*rename_function_type)( ::QString const & ) ; + rename_function_type rename_function_value( &::SireMol::ResEditor::rename ); + + ResEditor_exposer.def( + "rename" + , rename_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Rename this residue to newname" ); + } { //::SireMol::ResEditor::renumber @@ -199,6 +237,19 @@ void register_ResEditor_class(){ , bp::return_self< >() , "Renumber this residue to newnum" ); + } + { //::SireMol::ResEditor::renumber + + typedef ::SireMol::ResEditor & ( ::SireMol::ResEditor::*renumber_function_type)( int ) ; + renumber_function_type renumber_function_value( &::SireMol::ResEditor::renumber ); + + ResEditor_exposer.def( + "renumber" + , renumber_function_value + , ( bp::arg("number") ) + , bp::return_self< >() + , "Renumber this residue to newnum" ); + } { //::SireMol::ResEditor::reparent @@ -212,6 +263,32 @@ void register_ResEditor_class(){ , bp::release_gil_policy() , "Move this residue into the chain with ID chainid\nThrow: SireMol::missing_chain\nThrow: SireMol::duplicate_chain\nThrow: SireError::invalid_index\n" ); + } + { //::SireMol::ResEditor::setAlternateName + + typedef ::SireMol::ResEditor & ( ::SireMol::ResEditor::*setAlternateName_function_type)( ::SireMol::ResName const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::ResEditor::setAlternateName ); + + ResEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate residue name for this residue" ); + + } + { //::SireMol::ResEditor::setAlternateName + + typedef ::SireMol::ResEditor & ( ::SireMol::ResEditor::*setAlternateName_function_type)( ::QString const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::ResEditor::setAlternateName ); + + ResEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate name for this residue" ); + } { //::SireMol::ResEditor::toString diff --git a/wrapper/Mol/ResFloatProperty.pypp.cpp b/wrapper/Mol/ResFloatProperty.pypp.cpp index 53fd22615..5d8652d4d 100644 --- a/wrapper/Mol/ResFloatProperty.pypp.cpp +++ b/wrapper/Mol/ResFloatProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ResProperty __copy__(const SireMol::ResProperty &other){ return SireMol::ResProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ResFloatProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ResProperty< double >::merge + + typedef SireMol::ResProperty< double > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ResProperty< double >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ResProperty< double >::merge ); + + ResFloatProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ResProperty< double >::nResidues diff --git a/wrapper/Mol/ResIntProperty.pypp.cpp b/wrapper/Mol/ResIntProperty.pypp.cpp index 0514e645d..b51ac84bf 100644 --- a/wrapper/Mol/ResIntProperty.pypp.cpp +++ b/wrapper/Mol/ResIntProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ResProperty __copy__(const SireMol::ResProperty &other){ return SireMol::ResProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ResIntProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ResProperty< long long >::merge + + typedef SireMol::ResProperty< long long > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ResProperty< long long >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ResProperty< long long >::merge ); + + ResIntProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ResProperty< long long >::nResidues diff --git a/wrapper/Mol/ResPropertyProperty.pypp.cpp b/wrapper/Mol/ResPropertyProperty.pypp.cpp index 926bc3611..0f07c299a 100644 --- a/wrapper/Mol/ResPropertyProperty.pypp.cpp +++ b/wrapper/Mol/ResPropertyProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ResProperty > __copy__(const SireMol::ResProperty > &other){ return SireMol::ResProperty >(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ResPropertyProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ResProperty< SireBase::PropPtr< SireBase::Property > >::merge + + typedef SireMol::ResProperty< SireBase::PropPtr< SireBase::Property > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ResProperty< SireBase::PropPtr< SireBase::Property > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ResProperty< SireBase::PropPtr< SireBase::Property > >::merge ); + + ResPropertyProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ResProperty< SireBase::PropPtr< SireBase::Property > >::nResidues diff --git a/wrapper/Mol/ResStringProperty.pypp.cpp b/wrapper/Mol/ResStringProperty.pypp.cpp index 8a0ec0ec5..688925b05 100644 --- a/wrapper/Mol/ResStringProperty.pypp.cpp +++ b/wrapper/Mol/ResStringProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ResProperty __copy__(const SireMol::ResProperty &other){ return SireMol::ResProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ResStringProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ResProperty< QString >::merge + + typedef SireMol::ResProperty< QString > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ResProperty< QString >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ResProperty< QString >::merge ); + + ResStringProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ResProperty< QString >::nResidues diff --git a/wrapper/Mol/ResStructureEditor.pypp.cpp b/wrapper/Mol/ResStructureEditor.pypp.cpp index 2f9418ba1..bb9f085b5 100644 --- a/wrapper/Mol/ResStructureEditor.pypp.cpp +++ b/wrapper/Mol/ResStructureEditor.pypp.cpp @@ -84,6 +84,18 @@ void register_ResStructureEditor_class(){ , bp::release_gil_policy() , "Add a new atom with the number number to this residue - this\nreturns an editor that can be used to further edit this atom" ); + } + { //::SireMol::ResStructureEditor::alternateName + + typedef ::SireMol::ResName const & ( ::SireMol::ResStructureEditor::*alternateName_function_type)( ) const; + alternateName_function_type alternateName_function_value( &::SireMol::ResStructureEditor::alternateName ); + + ResStructureEditor_exposer.def( + "alternateName" + , alternateName_function_value + , bp::return_value_policy() + , "Return the alternate name for this residue" ); + } { //::SireMol::ResStructureEditor::atom @@ -233,6 +245,19 @@ void register_ResStructureEditor_class(){ , bp::return_self< >() , "Change the index of this residue to newidx. If this\nis larger than the number of residues in the molecule\nthen this residue is moved to the end" ); + } + { //::SireMol::ResStructureEditor::reindex + + typedef ::SireMol::ResStructureEditor & ( ::SireMol::ResStructureEditor::*reindex_function_type)( int ) ; + reindex_function_type reindex_function_value( &::SireMol::ResStructureEditor::reindex ); + + ResStructureEditor_exposer.def( + "reindex" + , reindex_function_value + , ( bp::arg("index") ) + , bp::return_self< >() + , "Reindex this residue to newidx" ); + } { //::SireMol::ResStructureEditor::remove @@ -284,6 +309,19 @@ void register_ResStructureEditor_class(){ , bp::return_self< >() , "Rename this residue to newname" ); + } + { //::SireMol::ResStructureEditor::rename + + typedef ::SireMol::ResStructureEditor & ( ::SireMol::ResStructureEditor::*rename_function_type)( ::QString const & ) ; + rename_function_type rename_function_value( &::SireMol::ResStructureEditor::rename ); + + ResStructureEditor_exposer.def( + "rename" + , rename_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Rename this residue to newname" ); + } { //::SireMol::ResStructureEditor::renumber @@ -297,6 +335,19 @@ void register_ResStructureEditor_class(){ , bp::return_self< >() , "Renumber this residue to newnum" ); + } + { //::SireMol::ResStructureEditor::renumber + + typedef ::SireMol::ResStructureEditor & ( ::SireMol::ResStructureEditor::*renumber_function_type)( int ) ; + renumber_function_type renumber_function_value( &::SireMol::ResStructureEditor::renumber ); + + ResStructureEditor_exposer.def( + "renumber" + , renumber_function_value + , ( bp::arg("number") ) + , bp::return_self< >() + , "Renumber this residue to newnum" ); + } { //::SireMol::ResStructureEditor::reparent @@ -348,6 +399,32 @@ void register_ResStructureEditor_class(){ , bp::release_gil_policy() , "Is this editor editing the entire molecule?" ); + } + { //::SireMol::ResStructureEditor::setAlternateName + + typedef ::SireMol::ResStructureEditor & ( ::SireMol::ResStructureEditor::*setAlternateName_function_type)( ::SireMol::ResName const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::ResStructureEditor::setAlternateName ); + + ResStructureEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate residue name for this residue" ); + + } + { //::SireMol::ResStructureEditor::setAlternateName + + typedef ::SireMol::ResStructureEditor & ( ::SireMol::ResStructureEditor::*setAlternateName_function_type)( ::QString const & ) ; + setAlternateName_function_type setAlternateName_function_value( &::SireMol::ResStructureEditor::setAlternateName ); + + ResStructureEditor_exposer.def( + "setAlternateName" + , setAlternateName_function_value + , ( bp::arg("name") ) + , bp::return_self< >() + , "Set the alternate name for this residue" ); + } { //::SireMol::ResStructureEditor::toString diff --git a/wrapper/Mol/ResVariantProperty.pypp.cpp b/wrapper/Mol/ResVariantProperty.pypp.cpp index bdc098bb3..48e50158c 100644 --- a/wrapper/Mol/ResVariantProperty.pypp.cpp +++ b/wrapper/Mol/ResVariantProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::ResProperty __copy__(const SireMol::ResProperty &other){ return SireMol::ResProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_ResVariantProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::ResProperty< QVariant >::merge + + typedef SireMol::ResProperty< QVariant > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::ResProperty< QVariant >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::ResProperty< QVariant >::merge ); + + ResVariantProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::ResProperty< QVariant >::nResidues diff --git a/wrapper/Mol/Residue.pypp.cpp b/wrapper/Mol/Residue.pypp.cpp index 3ccf64a64..e393c68ac 100644 --- a/wrapper/Mol/Residue.pypp.cpp +++ b/wrapper/Mol/Residue.pypp.cpp @@ -98,6 +98,18 @@ void register_Residue_class(){ bp::scope Residue_scope( Residue_exposer ); Residue_exposer.def( bp::init< SireMol::MoleculeData const &, SireMol::ResID const & >(( bp::arg("moldata"), bp::arg("resid") ), "Construct as a specified residue") ); Residue_exposer.def( bp::init< SireMol::Residue const & >(( bp::arg("other") ), "Copy constructor") ); + { //::SireMol::Residue::alternateName + + typedef ::SireMol::ResName ( ::SireMol::Residue::*alternateName_function_type)( ) const; + alternateName_function_type alternateName_function_value( &::SireMol::Residue::alternateName ); + + Residue_exposer.def( + "alternateName" + , alternateName_function_value + , bp::release_gil_policy() + , "Return the alternate name of this residue" ); + + } { //::SireMol::Residue::assertContainsMetadata typedef void ( ::SireMol::Residue::*assertContainsMetadata_function_type)( ::SireBase::PropertyName const & ) const; diff --git a/wrapper/Mol/ResidueBeading.pypp.cpp b/wrapper/Mol/ResidueBeading.pypp.cpp index 484f79e51..f467b357c 100644 --- a/wrapper/Mol/ResidueBeading.pypp.cpp +++ b/wrapper/Mol/ResidueBeading.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireError/errors.h" diff --git a/wrapper/Mol/SegFloatProperty.pypp.cpp b/wrapper/Mol/SegFloatProperty.pypp.cpp index 354e83ff9..9800ae7d7 100644 --- a/wrapper/Mol/SegFloatProperty.pypp.cpp +++ b/wrapper/Mol/SegFloatProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::SegProperty __copy__(const SireMol::SegProperty &other){ return SireMol::SegProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_SegFloatProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SegProperty< double >::merge + + typedef SireMol::SegProperty< double > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::SegProperty< double >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::SegProperty< double >::merge ); + + SegFloatProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::SegProperty< double >::nSegments diff --git a/wrapper/Mol/SegIntProperty.pypp.cpp b/wrapper/Mol/SegIntProperty.pypp.cpp index c32f054a9..aca4cdd1e 100644 --- a/wrapper/Mol/SegIntProperty.pypp.cpp +++ b/wrapper/Mol/SegIntProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::SegProperty __copy__(const SireMol::SegProperty &other){ return SireMol::SegProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_SegIntProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SegProperty< long long >::merge + + typedef SireMol::SegProperty< long long > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::SegProperty< long long >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::SegProperty< long long >::merge ); + + SegIntProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::SegProperty< long long >::nSegments diff --git a/wrapper/Mol/SegPropertyProperty.pypp.cpp b/wrapper/Mol/SegPropertyProperty.pypp.cpp index 3f5e6d649..f39176194 100644 --- a/wrapper/Mol/SegPropertyProperty.pypp.cpp +++ b/wrapper/Mol/SegPropertyProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::SegProperty > __copy__(const SireMol::SegProperty > &other){ return SireMol::SegProperty >(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_SegPropertyProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SegProperty< SireBase::PropPtr< SireBase::Property > >::merge + + typedef SireMol::SegProperty< SireBase::PropPtr< SireBase::Property > > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::SegProperty< SireBase::PropPtr< SireBase::Property > >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::SegProperty< SireBase::PropPtr< SireBase::Property > >::merge ); + + SegPropertyProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::SegProperty< SireBase::PropPtr< SireBase::Property > >::nSegments diff --git a/wrapper/Mol/SegStringProperty.pypp.cpp b/wrapper/Mol/SegStringProperty.pypp.cpp index 0aa1fecec..ea018af56 100644 --- a/wrapper/Mol/SegStringProperty.pypp.cpp +++ b/wrapper/Mol/SegStringProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::SegProperty __copy__(const SireMol::SegProperty &other){ return SireMol::SegProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_SegStringProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SegProperty< QString >::merge + + typedef SireMol::SegProperty< QString > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::SegProperty< QString >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::SegProperty< QString >::merge ); + + SegStringProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::SegProperty< QString >::nSegments diff --git a/wrapper/Mol/SegVariantProperty.pypp.cpp b/wrapper/Mol/SegVariantProperty.pypp.cpp index 7aad41a51..aa156b22e 100644 --- a/wrapper/Mol/SegVariantProperty.pypp.cpp +++ b/wrapper/Mol/SegVariantProperty.pypp.cpp @@ -15,6 +15,8 @@ namespace bp = boost::python; #include "SireMol/moleculeview.h" +#include "SireMol/atomidxmapping.h" + SireMol::SegProperty __copy__(const SireMol::SegProperty &other){ return SireMol::SegProperty(other); } #include "Qt/qdatastream.hpp" @@ -226,6 +228,19 @@ void register_SegVariantProperty_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SegProperty< QVariant >::merge + + typedef SireMol::SegProperty< QVariant > exported_class_t; + typedef ::SireBase::PropertyList ( ::SireMol::SegProperty< QVariant >::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::SegProperty< QVariant >::merge ); + + SegVariantProperty_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMol::SegProperty< QVariant >::nSegments diff --git a/wrapper/Mol/SelectorM_Atom_.pypp.cpp b/wrapper/Mol/SelectorM_Atom_.pypp.cpp index 4946cdbf8..438ad2b83 100644 --- a/wrapper/Mol/SelectorM_Atom_.pypp.cpp +++ b/wrapper/Mol/SelectorM_Atom_.pypp.cpp @@ -137,6 +137,19 @@ void register_SelectorM_Atom__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Atom >::assertSingleMolecule + + typedef SireMol::SelectorM< SireMol::Atom > exported_class_t; + typedef void ( ::SireMol::SelectorM< SireMol::Atom >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Atom >::assertSingleMolecule ); + + SelectorM_Atom__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Atom >::atom @@ -886,6 +899,19 @@ void register_SelectorM_Atom__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Atom >::isSingleMolecule + + typedef SireMol::SelectorM< SireMol::Atom > exported_class_t; + typedef bool ( ::SireMol::SelectorM< SireMol::Atom >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Atom >::isSingleMolecule ); + + SelectorM_Atom__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Atom >::loadFrame @@ -1780,6 +1806,19 @@ void register_SelectorM_Atom__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Atom >::toSingleMolecule + + typedef SireMol::SelectorM< SireMol::Atom > exported_class_t; + typedef ::SireMol::Selector< SireMol::Atom > ( ::SireMol::SelectorM< SireMol::Atom >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Atom >::toSingleMolecule ); + + SelectorM_Atom__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Atom >::toString diff --git a/wrapper/Mol/SelectorM_Chain_.pypp.cpp b/wrapper/Mol/SelectorM_Chain_.pypp.cpp index a3eb7da28..3e143957f 100644 --- a/wrapper/Mol/SelectorM_Chain_.pypp.cpp +++ b/wrapper/Mol/SelectorM_Chain_.pypp.cpp @@ -137,6 +137,19 @@ void register_SelectorM_Chain__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Chain >::assertSingleMolecule + + typedef SireMol::SelectorM< SireMol::Chain > exported_class_t; + typedef void ( ::SireMol::SelectorM< SireMol::Chain >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Chain >::assertSingleMolecule ); + + SelectorM_Chain__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Chain >::atom @@ -886,6 +899,19 @@ void register_SelectorM_Chain__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Chain >::isSingleMolecule + + typedef SireMol::SelectorM< SireMol::Chain > exported_class_t; + typedef bool ( ::SireMol::SelectorM< SireMol::Chain >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Chain >::isSingleMolecule ); + + SelectorM_Chain__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Chain >::loadFrame @@ -1780,6 +1806,19 @@ void register_SelectorM_Chain__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Chain >::toSingleMolecule + + typedef SireMol::SelectorM< SireMol::Chain > exported_class_t; + typedef ::SireMol::Selector< SireMol::Chain > ( ::SireMol::SelectorM< SireMol::Chain >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Chain >::toSingleMolecule ); + + SelectorM_Chain__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Chain >::toString diff --git a/wrapper/Mol/SelectorM_CutGroup_.pypp.cpp b/wrapper/Mol/SelectorM_CutGroup_.pypp.cpp index a6ff84c4e..5cdba2efd 100644 --- a/wrapper/Mol/SelectorM_CutGroup_.pypp.cpp +++ b/wrapper/Mol/SelectorM_CutGroup_.pypp.cpp @@ -137,6 +137,19 @@ void register_SelectorM_CutGroup__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::CutGroup >::assertSingleMolecule + + typedef SireMol::SelectorM< SireMol::CutGroup > exported_class_t; + typedef void ( ::SireMol::SelectorM< SireMol::CutGroup >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::CutGroup >::assertSingleMolecule ); + + SelectorM_CutGroup__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::CutGroup >::atom @@ -886,6 +899,19 @@ void register_SelectorM_CutGroup__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::CutGroup >::isSingleMolecule + + typedef SireMol::SelectorM< SireMol::CutGroup > exported_class_t; + typedef bool ( ::SireMol::SelectorM< SireMol::CutGroup >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::CutGroup >::isSingleMolecule ); + + SelectorM_CutGroup__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::CutGroup >::loadFrame @@ -1780,6 +1806,19 @@ void register_SelectorM_CutGroup__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::CutGroup >::toSingleMolecule + + typedef SireMol::SelectorM< SireMol::CutGroup > exported_class_t; + typedef ::SireMol::Selector< SireMol::CutGroup > ( ::SireMol::SelectorM< SireMol::CutGroup >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::CutGroup >::toSingleMolecule ); + + SelectorM_CutGroup__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::CutGroup >::toString diff --git a/wrapper/Mol/SelectorM_Residue_.pypp.cpp b/wrapper/Mol/SelectorM_Residue_.pypp.cpp index 2d6beff74..84f98f675 100644 --- a/wrapper/Mol/SelectorM_Residue_.pypp.cpp +++ b/wrapper/Mol/SelectorM_Residue_.pypp.cpp @@ -137,6 +137,19 @@ void register_SelectorM_Residue__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Residue >::assertSingleMolecule + + typedef SireMol::SelectorM< SireMol::Residue > exported_class_t; + typedef void ( ::SireMol::SelectorM< SireMol::Residue >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Residue >::assertSingleMolecule ); + + SelectorM_Residue__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Residue >::atom @@ -886,6 +899,19 @@ void register_SelectorM_Residue__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Residue >::isSingleMolecule + + typedef SireMol::SelectorM< SireMol::Residue > exported_class_t; + typedef bool ( ::SireMol::SelectorM< SireMol::Residue >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Residue >::isSingleMolecule ); + + SelectorM_Residue__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Residue >::loadFrame @@ -1780,6 +1806,19 @@ void register_SelectorM_Residue__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Residue >::toSingleMolecule + + typedef SireMol::SelectorM< SireMol::Residue > exported_class_t; + typedef ::SireMol::Selector< SireMol::Residue > ( ::SireMol::SelectorM< SireMol::Residue >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Residue >::toSingleMolecule ); + + SelectorM_Residue__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Residue >::toString diff --git a/wrapper/Mol/SelectorM_Segment_.pypp.cpp b/wrapper/Mol/SelectorM_Segment_.pypp.cpp index e4c006625..481aa5986 100644 --- a/wrapper/Mol/SelectorM_Segment_.pypp.cpp +++ b/wrapper/Mol/SelectorM_Segment_.pypp.cpp @@ -137,6 +137,19 @@ void register_SelectorM_Segment__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Segment >::assertSingleMolecule + + typedef SireMol::SelectorM< SireMol::Segment > exported_class_t; + typedef void ( ::SireMol::SelectorM< SireMol::Segment >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Segment >::assertSingleMolecule ); + + SelectorM_Segment__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Segment >::atom @@ -886,6 +899,19 @@ void register_SelectorM_Segment__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Segment >::isSingleMolecule + + typedef SireMol::SelectorM< SireMol::Segment > exported_class_t; + typedef bool ( ::SireMol::SelectorM< SireMol::Segment >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Segment >::isSingleMolecule ); + + SelectorM_Segment__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Segment >::loadFrame @@ -1780,6 +1806,19 @@ void register_SelectorM_Segment__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::SelectorM< SireMol::Segment >::toSingleMolecule + + typedef SireMol::SelectorM< SireMol::Segment > exported_class_t; + typedef ::SireMol::Selector< SireMol::Segment > ( ::SireMol::SelectorM< SireMol::Segment >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::SelectorM< SireMol::Segment >::toSingleMolecule ); + + SelectorM_Segment__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::SelectorM< SireMol::Segment >::toString diff --git a/wrapper/Mol/Selector_Atom_.pypp.cpp b/wrapper/Mol/Selector_Atom_.pypp.cpp index d1b7ff4e4..ca3dd7ee3 100644 --- a/wrapper/Mol/Selector_Atom_.pypp.cpp +++ b/wrapper/Mol/Selector_Atom_.pypp.cpp @@ -125,6 +125,19 @@ void register_Selector_Atom__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Atom >::assertSingleMolecule + + typedef SireMol::Selector< SireMol::Atom > exported_class_t; + typedef void ( ::SireMol::Selector< SireMol::Atom >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::Selector< SireMol::Atom >::assertSingleMolecule ); + + Selector_Atom__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Atom >::contains @@ -442,6 +455,19 @@ void register_Selector_Atom__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Atom >::isSingleMolecule + + typedef SireMol::Selector< SireMol::Atom > exported_class_t; + typedef bool ( ::SireMol::Selector< SireMol::Atom >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::Selector< SireMol::Atom >::isSingleMolecule ); + + Selector_Atom__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Atom >::metadataKeys @@ -1036,6 +1062,19 @@ void register_Selector_Atom__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Atom >::toSingleMolecule + + typedef SireMol::Selector< SireMol::Atom > exported_class_t; + typedef ::SireMol::Selector< SireMol::Atom > ( ::SireMol::Selector< SireMol::Atom >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::Selector< SireMol::Atom >::toSingleMolecule ); + + Selector_Atom__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Atom >::toString diff --git a/wrapper/Mol/Selector_Chain_.pypp.cpp b/wrapper/Mol/Selector_Chain_.pypp.cpp index eb96863df..36bb2dc7d 100644 --- a/wrapper/Mol/Selector_Chain_.pypp.cpp +++ b/wrapper/Mol/Selector_Chain_.pypp.cpp @@ -117,6 +117,19 @@ void register_Selector_Chain__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Chain >::assertSingleMolecule + + typedef SireMol::Selector< SireMol::Chain > exported_class_t; + typedef void ( ::SireMol::Selector< SireMol::Chain >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::Selector< SireMol::Chain >::assertSingleMolecule ); + + Selector_Chain__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Chain >::contains @@ -434,6 +447,19 @@ void register_Selector_Chain__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Chain >::isSingleMolecule + + typedef SireMol::Selector< SireMol::Chain > exported_class_t; + typedef bool ( ::SireMol::Selector< SireMol::Chain >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::Selector< SireMol::Chain >::isSingleMolecule ); + + Selector_Chain__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Chain >::metadataKeys @@ -1028,6 +1054,19 @@ void register_Selector_Chain__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Chain >::toSingleMolecule + + typedef SireMol::Selector< SireMol::Chain > exported_class_t; + typedef ::SireMol::Selector< SireMol::Chain > ( ::SireMol::Selector< SireMol::Chain >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::Selector< SireMol::Chain >::toSingleMolecule ); + + Selector_Chain__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Chain >::toString diff --git a/wrapper/Mol/Selector_CutGroup_.pypp.cpp b/wrapper/Mol/Selector_CutGroup_.pypp.cpp index d31875923..62449a5b9 100644 --- a/wrapper/Mol/Selector_CutGroup_.pypp.cpp +++ b/wrapper/Mol/Selector_CutGroup_.pypp.cpp @@ -117,6 +117,19 @@ void register_Selector_CutGroup__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::CutGroup >::assertSingleMolecule + + typedef SireMol::Selector< SireMol::CutGroup > exported_class_t; + typedef void ( ::SireMol::Selector< SireMol::CutGroup >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::Selector< SireMol::CutGroup >::assertSingleMolecule ); + + Selector_CutGroup__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::CutGroup >::contains @@ -434,6 +447,19 @@ void register_Selector_CutGroup__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::CutGroup >::isSingleMolecule + + typedef SireMol::Selector< SireMol::CutGroup > exported_class_t; + typedef bool ( ::SireMol::Selector< SireMol::CutGroup >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::Selector< SireMol::CutGroup >::isSingleMolecule ); + + Selector_CutGroup__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::CutGroup >::metadataKeys @@ -1028,6 +1054,19 @@ void register_Selector_CutGroup__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::CutGroup >::toSingleMolecule + + typedef SireMol::Selector< SireMol::CutGroup > exported_class_t; + typedef ::SireMol::Selector< SireMol::CutGroup > ( ::SireMol::Selector< SireMol::CutGroup >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::Selector< SireMol::CutGroup >::toSingleMolecule ); + + Selector_CutGroup__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::CutGroup >::toString diff --git a/wrapper/Mol/Selector_Residue_.pypp.cpp b/wrapper/Mol/Selector_Residue_.pypp.cpp index edb91a1b1..0919f52c7 100644 --- a/wrapper/Mol/Selector_Residue_.pypp.cpp +++ b/wrapper/Mol/Selector_Residue_.pypp.cpp @@ -119,6 +119,19 @@ void register_Selector_Residue__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Residue >::assertSingleMolecule + + typedef SireMol::Selector< SireMol::Residue > exported_class_t; + typedef void ( ::SireMol::Selector< SireMol::Residue >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::Selector< SireMol::Residue >::assertSingleMolecule ); + + Selector_Residue__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Residue >::contains @@ -436,6 +449,19 @@ void register_Selector_Residue__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Residue >::isSingleMolecule + + typedef SireMol::Selector< SireMol::Residue > exported_class_t; + typedef bool ( ::SireMol::Selector< SireMol::Residue >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::Selector< SireMol::Residue >::isSingleMolecule ); + + Selector_Residue__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Residue >::metadataKeys @@ -1030,6 +1056,19 @@ void register_Selector_Residue__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Residue >::toSingleMolecule + + typedef SireMol::Selector< SireMol::Residue > exported_class_t; + typedef ::SireMol::Selector< SireMol::Residue > ( ::SireMol::Selector< SireMol::Residue >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::Selector< SireMol::Residue >::toSingleMolecule ); + + Selector_Residue__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Residue >::toString diff --git a/wrapper/Mol/Selector_Segment_.pypp.cpp b/wrapper/Mol/Selector_Segment_.pypp.cpp index 2da624c09..13a5159d7 100644 --- a/wrapper/Mol/Selector_Segment_.pypp.cpp +++ b/wrapper/Mol/Selector_Segment_.pypp.cpp @@ -113,6 +113,19 @@ void register_Selector_Segment__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Segment >::assertSingleMolecule + + typedef SireMol::Selector< SireMol::Segment > exported_class_t; + typedef void ( ::SireMol::Selector< SireMol::Segment >::*assertSingleMolecule_function_type)( ) const; + assertSingleMolecule_function_type assertSingleMolecule_function_value( &::SireMol::Selector< SireMol::Segment >::assertSingleMolecule ); + + Selector_Segment__exposer.def( + "assertSingleMolecule" + , assertSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Segment >::contains @@ -430,6 +443,19 @@ void register_Selector_Segment__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Segment >::isSingleMolecule + + typedef SireMol::Selector< SireMol::Segment > exported_class_t; + typedef bool ( ::SireMol::Selector< SireMol::Segment >::*isSingleMolecule_function_type)( ) const; + isSingleMolecule_function_type isSingleMolecule_function_value( &::SireMol::Selector< SireMol::Segment >::isSingleMolecule ); + + Selector_Segment__exposer.def( + "isSingleMolecule" + , isSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Segment >::metadataKeys @@ -1024,6 +1050,19 @@ void register_Selector_Segment__class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Selector< SireMol::Segment >::toSingleMolecule + + typedef SireMol::Selector< SireMol::Segment > exported_class_t; + typedef ::SireMol::Selector< SireMol::Segment > ( ::SireMol::Selector< SireMol::Segment >::*toSingleMolecule_function_type)( ) const; + toSingleMolecule_function_type toSingleMolecule_function_value( &::SireMol::Selector< SireMol::Segment >::toSingleMolecule ); + + Selector_Segment__exposer.def( + "toSingleMolecule" + , toSingleMolecule_function_value + , bp::release_gil_policy() + , "" ); + } { //::SireMol::Selector< SireMol::Segment >::toString diff --git a/wrapper/Mol/SireMol_containers.cpp b/wrapper/Mol/SireMol_containers.cpp index 8b72cee54..6f3c55649 100644 --- a/wrapper/Mol/SireMol_containers.cpp +++ b/wrapper/Mol/SireMol_containers.cpp @@ -40,6 +40,7 @@ #include "Base/convertpackedarray.hpp" #include "SireMol/atom.h" +#include "SireMol/atomidxmapping.h" #include "SireMol/beadnum.h" #include "SireMol/element.h" #include "SireMol/atomidentifier.h" @@ -86,122 +87,123 @@ using boost::python::register_tuple; void register_SireMol_containers() { - register_viewsofmol_list(); + register_viewsofmol_list(); - register_list>(); - register_list>>(); - register_list>(); + register_list>(); + register_list>>(); + register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); + register_list>(); - register_list>(); + register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); - register_list>>(); - register_list>>(); + register_list>>(); + register_list>>(); - register_list>>(); + register_list>>(); - register_list>>(); + register_list>>(); - register_list>(); - register_list>>(); + register_list>(); + register_list>>(); - register_list>(); + register_list>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); - register_list>>(); + register_list>>(); - register_list>(); - register_list>(); + register_list>(); + register_list>(); - register_list>(); + register_list>(); - register_tuple>(); - register_tuple>(); - register_tuple>(); + register_tuple>(); + register_tuple>(); + register_tuple>(); - register_tuple>(); - register_tuple>(); + register_tuple>(); + register_tuple>(); - register_tuple>(); + register_tuple>(); - register_tuple>(); + register_tuple>(); - register_tuple>(); + register_tuple>(); - register_tuple>(); + register_tuple>(); - register_tuple>(); - register_tuple>(); - register_tuple, SireBase::PropertyMap>>(); - register_tuple, SireBase::PropertyMap>>(); + register_tuple>(); + register_tuple>(); + register_tuple, SireBase::PropertyMap>>(); + register_tuple, SireBase::PropertyMap>>(); - register_PackedArray>(); - register_PackedArray>(); + register_PackedArray>(); + register_PackedArray>(); - register_dict>(); + register_dict>(); - register_dict>(); - register_dict>(); + register_dict>(); + register_dict>(); - register_dict>>(); + register_dict>>(); - register_dict>>(); - register_dict>>(); - register_dict>>(); - register_dict>>(); - register_dict>>(); - register_dict>(); - register_dict>(); - register_dict>(); + register_dict>>(); + register_dict>>(); + register_dict>>(); + register_dict>>(); + register_dict>>(); + register_dict>(); + register_dict>(); + register_dict>(); + register_dict>(); - register_set>(); - register_set>(); + register_set>(); + register_set>(); - register_set>(); - register_set>(); + register_set>(); + register_set>(); } diff --git a/wrapper/Mol/SireMol_properties.cpp b/wrapper/Mol/SireMol_properties.cpp index 55a7f93a7..1481c317f 100644 --- a/wrapper/Mol/SireMol_properties.cpp +++ b/wrapper/Mol/SireMol_properties.cpp @@ -77,6 +77,7 @@ #include "trajectoryaligner.h" #include #include "moleculeview.h" +#include "SireBase/console.h" #include "SireBase/errors.h" #include "SireError/errors.h" #include "SireStream/datastream.h" diff --git a/wrapper/Mol/SireMol_registrars.cpp b/wrapper/Mol/SireMol_registrars.cpp index 0792a37aa..c0072a575 100644 --- a/wrapper/Mol/SireMol_registrars.cpp +++ b/wrapper/Mol/SireMol_registrars.cpp @@ -98,6 +98,7 @@ #include "hybridization.h" #include "atomeditor.h" #include "volumemap.h" +#include "atomidxmapping.h" #include "resname.h" #include "atompropertylist.h" #include "chaineditor.h" @@ -243,6 +244,7 @@ void register_SireMol_objects() ObjectRegistry::registerConverterFor< SireMol::AtomCoordMatcher >(); ObjectRegistry::registerConverterFor< SireMol::AtomIdxMatcher >(); ObjectRegistry::registerConverterFor< SireMol::AtomNameMatcher >(); + ObjectRegistry::registerConverterFor< SireMol::AtomNumMatcher >(); ObjectRegistry::registerConverterFor< SireMol::AtomIDMatcher >(); ObjectRegistry::registerConverterFor< SireMol::AtomMultiMatcher >(); ObjectRegistry::registerConverterFor< SireMol::AtomMCSMatcher >(); @@ -316,6 +318,8 @@ void register_SireMol_objects() ObjectRegistry::registerConverterFor< SireMol::AtomEditor >(); ObjectRegistry::registerConverterFor< SireMol::AtomStructureEditor >(); ObjectRegistry::registerConverterFor< SireMol::VolumeMap >(); + ObjectRegistry::registerConverterFor< SireMol::AtomIdxMappingEntry >(); + ObjectRegistry::registerConverterFor< SireMol::AtomIdxMapping >(); ObjectRegistry::registerConverterFor< SireMol::ResName >(); ObjectRegistry::registerConverterFor< SireMol::AtomPropertyList >(); ObjectRegistry::registerConverterFor< SireMol::AtomDoubleArrayProperty >(); diff --git a/wrapper/Mol/Trajectory.pypp.cpp b/wrapper/Mol/Trajectory.pypp.cpp index b34717614..0921e0e02 100644 --- a/wrapper/Mol/Trajectory.pypp.cpp +++ b/wrapper/Mol/Trajectory.pypp.cpp @@ -7,6 +7,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/generalunitproperty.h" #include "SireBase/lazyevaluator.h" @@ -31,6 +33,8 @@ namespace bp = boost::python; #include "SireVol/space.h" +#include "atomidxmapping.h" + #include "trajectory.h" #include "trajectoryaligner.h" @@ -185,6 +189,18 @@ void register_Trajectory_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMol::Trajectory::merge + + typedef ::SireBase::PropertyList ( ::SireMol::Trajectory::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMol::Trajectory::merge ); + + Trajectory_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "Merge this property with another property" ); + } { //::SireMol::Trajectory::nAtoms diff --git a/wrapper/Mol/UserBeading.pypp.cpp b/wrapper/Mol/UserBeading.pypp.cpp index eb2c6f025..373e91219 100644 --- a/wrapper/Mol/UserBeading.pypp.cpp +++ b/wrapper/Mol/UserBeading.pypp.cpp @@ -8,6 +8,8 @@ namespace bp = boost::python; +#include "SireBase/console.h" + #include "SireBase/errors.h" #include "SireError/errors.h" diff --git a/wrapper/Mol/_Mol.main.cpp b/wrapper/Mol/_Mol.main.cpp index 346070212..c0973b1e0 100644 --- a/wrapper/Mol/_Mol.main.cpp +++ b/wrapper/Mol/_Mol.main.cpp @@ -53,6 +53,10 @@ #include "AtomIdx.pypp.hpp" +#include "AtomIdxMapping.pypp.hpp" + +#include "AtomIdxMappingEntry.pypp.hpp" + #include "AtomIdxMatcher.pypp.hpp" #include "AtomIntProperty.pypp.hpp" @@ -81,6 +85,8 @@ #include "AtomNum.pypp.hpp" +#include "AtomNumMatcher.pypp.hpp" + #include "AtomPolarisabilities.pypp.hpp" #include "AtomProp.pypp.hpp" @@ -710,6 +716,10 @@ BOOST_PYTHON_MODULE(_Mol){ register_AtomIdx_class(); + register_AtomIdxMapping_class(); + + register_AtomIdxMappingEntry_class(); + register_AtomIdxMatcher_class(); register_AtomMCSMatcher_class(); @@ -732,6 +742,8 @@ BOOST_PYTHON_MODULE(_Mol){ register_AtomNum_class(); + register_AtomNumMatcher_class(); + register_AtomProp_class(); register_AtomStringProperty_class(); diff --git a/wrapper/Mol/active_headers.h b/wrapper/Mol/active_headers.h index ff3789391..79a12c77f 100644 --- a/wrapper/Mol/active_headers.h +++ b/wrapper/Mol/active_headers.h @@ -17,6 +17,7 @@ #include "atomid.h" #include "atomidentifier.h" #include "atomidx.h" +#include "atomidxmapping.h" #include "atommapping.h" #include "atommasses.h" #include "atommatch.h" diff --git a/wrapper/Mol/special_code.py b/wrapper/Mol/special_code.py index 87e6e390b..810ccd1c3 100644 --- a/wrapper/Mol/special_code.py +++ b/wrapper/Mol/special_code.py @@ -205,6 +205,7 @@ def fix_BeadEditorBase(c): def fix_AtomEditor(c): + c.decls("setAlternateName").call_policies = call_policies.return_self() c.decls("rename").call_policies = call_policies.return_self() c.decls("renumber").call_policies = call_policies.return_self() @@ -251,6 +252,7 @@ def fix_CGStructureEditor(c): def fix_ResEditor(c): + c.decls("setAlternateName").call_policies = call_policies.return_self() c.decls("renumber").call_policies = call_policies.return_self() c.decls("rename").call_policies = call_policies.return_self() @@ -268,6 +270,9 @@ def fix_ResStructureEditor(c): def fix_MolEditor(c, include_links=True): c.decls("renumber").call_policies = call_policies.return_self() c.decls("rename").call_policies = call_policies.return_self() + c.decls("makeSingleCutGroup").call_policies = call_policies.return_self() + c.decls("switchToAlternateNames").call_policies = call_policies.return_self() + c.decls("removeAlternateNames").call_policies = call_policies.return_self() if include_links: c.decls("addLink").call_policies = call_policies.return_self() @@ -346,6 +351,7 @@ def fix_Mover(c): def fix_MolViewProperty(c): c.add_declaration_code('#include "SireMaths/vector.h"') c.add_declaration_code('#include "SireMol/moleculeview.h"') + c.add_declaration_code('#include "SireMol/atomidxmapping.h"') c.decls("set").call_policies = call_policies.return_self() @@ -538,6 +544,7 @@ def fix_SelectResultMover(c): } implicitly_convertible = [ + ("QString", "SireMol::Element"), ("SireMol::AtomID", "SireMol::AtomIdentifier"), ("SireMol::CGID", "SireMol::CGIdentifier"), ("SireMol::ChainID", "SireMol::ChainIdentifier"), @@ -578,3 +585,4 @@ def fixMB(mb): mb.add_declaration_code('#include "SireMol/moleculeinfo.h"') mb.add_declaration_code('#include "SireMol/selector.hpp"') mb.add_declaration_code('#include "SireMol/selectorm.hpp"') + mb.add_declaration_code('#include "SireMol/element.h"') diff --git a/wrapper/Move/CMakeAutogenFile.txt b/wrapper/Move/CMakeAutogenFile.txt index 8f4afa1af..41147f875 100644 --- a/wrapper/Move/CMakeAutogenFile.txt +++ b/wrapper/Move/CMakeAutogenFile.txt @@ -1,84 +1,84 @@ # WARNING - AUTOGENERATED FILE - CONTENTS WILL BE OVERWRITTEN! set ( PYPP_SOURCES + SupraSubMoves.pypp.cpp + OpenMMFrEnergyST.pypp.cpp + SameMoves.pypp.cpp DLMRigidBody.pypp.cpp - DofID.pypp.cpp - Dynamics.pypp.cpp - Ensemble.pypp.cpp - Flexibility.pypp.cpp - GetCOGPoint.pypp.cpp + WeightedMoves.pypp.cpp + SameSupraSubMoves.pypp.cpp + ScaleVolumeFromCenter.pypp.cpp + Sampler.pypp.cpp + ZMatrix.pypp.cpp + VelocityGenerator.pypp.cpp + SimStore.pypp.cpp + MolDeleter.pypp.cpp + SupraSim.pypp.cpp + ZMatrixLine.pypp.cpp + NullDeleter.pypp.cpp + ZMatrixCoordsLine.pypp.cpp GetCOMPoint.pypp.cpp - GetCentroidPoint.pypp.cpp + TitrationMove.pypp.cpp + SupraMove.pypp.cpp + MolecularDynamics.pypp.cpp + Flexibility.pypp.cpp + Replicas.pypp.cpp + NullVolumeChanger.pypp.cpp GetPoint.pypp.cpp - HMCGenerator.pypp.cpp HMCVelGen.pypp.cpp - HybridMC.pypp.cpp - Integrator.pypp.cpp - InternalMove.pypp.cpp - InternalMoveSingle.pypp.cpp - MTSMC.pypp.cpp - MaxwellBoltzmann.pypp.cpp - MolDeleter.pypp.cpp - MolInserter.pypp.cpp - MolecularDynamics.pypp.cpp - MonteCarlo.pypp.cpp - Move.pypp.cpp + GetCOGPoint.pypp.cpp + ZMatMove.pypp.cpp + UniformInserter.pypp.cpp + VelocityVerlet.pypp.cpp + OpenMMPMEFEP.pypp.cpp Moves.pypp.cpp - NullDeleter.pypp.cpp - NullGetPoint.pypp.cpp - NullInserter.pypp.cpp + MaxwellBoltzmann.pypp.cpp + HybridMC.pypp.cpp + RBWorkspaceJM.pypp.cpp NullIntegrator.pypp.cpp - NullMove.pypp.cpp - NullSupraMove.pypp.cpp - NullSupraSubMove.pypp.cpp + SystemWideDeleter.pypp.cpp + SupraSimPacket.pypp.cpp NullVelocityGenerator.pypp.cpp - NullVolumeChanger.pypp.cpp - OpenMMFrEnergyDT.pypp.cpp - OpenMMFrEnergyST.pypp.cpp - OpenMMMDIntegrator.pypp.cpp - OpenMMPMEFEP.pypp.cpp - PrefSampler.pypp.cpp - RBWorkspaceJM.pypp.cpp + VolumeChanger.pypp.cpp RepExMove.pypp.cpp - RepExMove2.pypp.cpp + SupraSubMove.pypp.cpp + SupraSubSim.pypp.cpp + Titrator.pypp.cpp RepExSubMove.pypp.cpp - Replica.pypp.cpp - Replicas.pypp.cpp - RigidBodyMC.pypp.cpp - SameMoves.pypp.cpp + SupraMoves.pypp.cpp + OpenMMFrEnergyDT.pypp.cpp + NullSupraMove.pypp.cpp + Dynamics.pypp.cpp + MolInserter.pypp.cpp SameSupraMoves.pypp.cpp - SameSupraSubMoves.pypp.cpp - Sampler.pypp.cpp - ScaleVolumeFromCenter.pypp.cpp - SimPacket.pypp.cpp - SimStore.pypp.cpp - Simulation.pypp.cpp + PrefSampler.pypp.cpp + OpenMMMDIntegrator.pypp.cpp + HMCGenerator.pypp.cpp + VolumeMove.pypp.cpp + SupraSubSystem.pypp.cpp SpecifiedGroupsDeleter.pypp.cpp - SupraMove.pypp.cpp - SupraMoves.pypp.cpp - SupraSim.pypp.cpp - SupraSimPacket.pypp.cpp - SupraSubMove.pypp.cpp - SupraSubMoves.pypp.cpp - SupraSubSim.pypp.cpp + NullInserter.pypp.cpp + Integrator.pypp.cpp SupraSubSimPacket.pypp.cpp - SupraSubSystem.pypp.cpp - SupraSystem.pypp.cpp - SystemWideDeleter.pypp.cpp - TitrationMove.pypp.cpp - Titrator.pypp.cpp - UniformInserter.pypp.cpp - UniformSampler.pypp.cpp + RepExMove2.pypp.cpp + MonteCarlo.pypp.cpp + Simulation.pypp.cpp + NullGetPoint.pypp.cpp + RigidBodyMC.pypp.cpp + SimPacket.pypp.cpp + NullMove.pypp.cpp VelocitiesFromProperty.pypp.cpp - VelocityGenerator.pypp.cpp - VelocityVerlet.pypp.cpp - VolumeChanger.pypp.cpp - VolumeMove.pypp.cpp - WeightedMoves.pypp.cpp - ZMatMove.pypp.cpp - ZMatrix.pypp.cpp + DofID.pypp.cpp + UniformSampler.pypp.cpp + NullSupraSubMove.pypp.cpp + Ensemble.pypp.cpp + MTSMC.pypp.cpp + InternalMove.pypp.cpp + InternalMoveSingle.pypp.cpp + SupraSystem.pypp.cpp + Replica.pypp.cpp + GetCentroidPoint.pypp.cpp + Move.pypp.cpp ZMatrixCoords.pypp.cpp - ZMatrixCoordsLine.pypp.cpp - ZMatrixLine.pypp.cpp SireMove_containers.cpp SireMove_properties.cpp SireMove_registrars.cpp diff --git a/wrapper/Move/Flexibility.pypp.cpp b/wrapper/Move/Flexibility.pypp.cpp index 0bef087ac..89f4827c9 100644 --- a/wrapper/Move/Flexibility.pypp.cpp +++ b/wrapper/Move/Flexibility.pypp.cpp @@ -270,6 +270,18 @@ void register_Flexibility_class(){ , bp::release_gil_policy() , "" ); + } + { //::SireMove::Flexibility::merge + + typedef ::SireBase::PropertyList ( ::SireMove::Flexibility::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMove::Flexibility::merge ); + + Flexibility_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } Flexibility_exposer.def( bp::self != bp::self ); { //::SireMove::Flexibility::operator= diff --git a/wrapper/Move/SireMove_properties.cpp b/wrapper/Move/SireMove_properties.cpp index 69d3787c4..76008f006 100644 --- a/wrapper/Move/SireMove_properties.cpp +++ b/wrapper/Move/SireMove_properties.cpp @@ -4,31 +4,46 @@ #include "Base/convertproperty.hpp" #include "SireMove_properties.h" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "suprasubsystem.h" +#include "suprasubsystem.h" +#include "SireMol/molecule.h" +#include "SireMol/partialmolecule.h" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "SireSystem/system.h" +#include "sampler.h" +#include "uniformsampler.h" +#include "sampler.h" #include "SireError/errors.h" -#include "SireMaths/vector.h" -#include "SireMol/atom.h" -#include "SireMol/atomcoords.h" -#include "SireMol/evaluator.h" -#include "SireMol/moleculeview.h" -#include "SireMol/mover.hpp" -#include "SireMol/selector.hpp" #include "SireStream/datastream.h" #include "SireStream/shareddatastream.h" -#include "getpoint.h" -#include -#include "getpoint.h" -#include "SireCAS/symbol.h" -#include "SireFF/forcefields.h" -#include "SireFF/forcetable.h" -#include "SireMaths/rangenerator.h" -#include "SireMol/moleculegroup.h" -#include "SireMol/moleculeview.h" +#include "suprasubmoves.h" +#include "suprasubsystem.h" +#include "suprasubmoves.h" +#include "SireError/errors.h" +#include "SireID/index.h" #include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" #include "SireSystem/system.h" -#include "ensemble.h" -#include "integrator.h" -#include "integratorworkspace.h" -#include "integrator.h" +#include "SireSystem/systemmonitor.h" +#include "moves.h" +#include "simstore.h" +#include "suprasystem.h" +#include "suprasystem.h" +#include "SireError/errors.h" +#include "SireID/index.h" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "supramoves.h" +#include "suprasystem.h" +#include "supramoves.h" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "supramove.h" +#include "suprasystem.h" +#include "supramove.h" #include "SireMol/molecule.h" #include "SireMol/moleculegroup.h" #include "SireStream/datastream.h" @@ -50,6 +65,45 @@ #include "molinserter.h" #include "molinserter.h" #include "SireError/errors.h" +#include "SireMaths/vector.h" +#include "SireMol/atom.h" +#include "SireMol/atomcoords.h" +#include "SireMol/evaluator.h" +#include "SireMol/moleculeview.h" +#include "SireMol/mover.hpp" +#include "SireMol/selector.hpp" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "getpoint.h" +#include +#include "getpoint.h" +#include "SireCAS/symbol.h" +#include "SireMol/atomelements.h" +#include "SireMol/atommasses.h" +#include "SireMol/atomvelocities.h" +#include "SireMol/moleculedata.h" +#include "SireMol/moleculeinfodata.h" +#include "SireMol/moleculeview.h" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "SireUnits/dimensions.h" +#include "SireUnits/temperature.h" +#include "SireUnits/units.h" +#include "velocitygenerator.h" +#include "velocitygenerator.h" +#include "SireCAS/symbol.h" +#include "SireFF/forcefields.h" +#include "SireFF/forcetable.h" +#include "SireMaths/rangenerator.h" +#include "SireMol/moleculegroup.h" +#include "SireMol/moleculeview.h" +#include "SireStream/datastream.h" +#include "SireSystem/system.h" +#include "ensemble.h" +#include "integrator.h" +#include "integratorworkspace.h" +#include "integrator.h" +#include "SireError/errors.h" #include "SireMaths/rangenerator.h" #include "SireMol/core.h" #include "SireStream/datastream.h" @@ -61,6 +115,11 @@ #include "move.h" #include #include "move.h" +#include "SireStream/datastream.h" +#include "SireStream/shareddatastream.h" +#include "suprasubmove.h" +#include "suprasubsystem.h" +#include "suprasubmove.h" #include "SireError/errors.h" #include "SireMaths/rangenerator.h" #include "SireStream/datastream.h" @@ -78,79 +137,20 @@ #include #include #include "moves.h" -#include "SireMol/molecule.h" -#include "SireMol/partialmolecule.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "SireSystem/system.h" -#include "sampler.h" -#include "uniformsampler.h" -#include "sampler.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "supramove.h" -#include "suprasystem.h" -#include "supramove.h" -#include "SireError/errors.h" -#include "SireID/index.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "supramoves.h" -#include "suprasystem.h" -#include "supramoves.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "suprasubmove.h" -#include "suprasubsystem.h" -#include "suprasubmove.h" -#include "SireError/errors.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "suprasubmoves.h" -#include "suprasubsystem.h" -#include "suprasubmoves.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "suprasubsystem.h" -#include "suprasubsystem.h" -#include "SireError/errors.h" -#include "SireID/index.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "SireSystem/system.h" -#include "SireSystem/systemmonitor.h" -#include "moves.h" -#include "simstore.h" -#include "suprasystem.h" -#include "suprasystem.h" -#include "SireCAS/symbol.h" -#include "SireMol/atomelements.h" -#include "SireMol/atommasses.h" -#include "SireMol/atomvelocities.h" -#include "SireMol/moleculedata.h" -#include "SireMol/moleculeinfodata.h" -#include "SireMol/moleculeview.h" -#include "SireStream/datastream.h" -#include "SireStream/shareddatastream.h" -#include "SireUnits/dimensions.h" -#include "SireUnits/temperature.h" -#include "SireUnits/units.h" -#include "velocitygenerator.h" -#include "velocitygenerator.h" void register_SireMove_properties() { - register_property_container< SireMove::GetPointPtr, SireMove::GetPoint >(); - register_property_container< SireMove::IntegratorPtr, SireMove::Integrator >(); - register_property_container< SireMove::MolDeleterPtr, SireMove::MolDeleter >(); - register_property_container< SireMove::MolInserterPtr, SireMove::MolInserter >(); - register_property_container< SireMove::MovePtr, SireMove::Move >(); - register_property_container< SireMove::MovesPtr, SireMove::Moves >(); + register_property_container< SireMove::SupraSubSystemPtr, SireMove::SupraSubSystem >(); register_property_container< SireMove::SamplerPtr, SireMove::Sampler >(); - register_property_container< SireMove::SupraMovePtr, SireMove::SupraMove >(); - register_property_container< SireMove::SupraMovesPtr, SireMove::SupraMoves >(); - register_property_container< SireMove::SupraSubMovePtr, SireMove::SupraSubMove >(); register_property_container< SireMove::SupraSubMovesPtr, SireMove::SupraSubMoves >(); - register_property_container< SireMove::SupraSubSystemPtr, SireMove::SupraSubSystem >(); register_property_container< SireMove::SupraSystemPtr, SireMove::SupraSystem >(); + register_property_container< SireMove::SupraMovesPtr, SireMove::SupraMoves >(); + register_property_container< SireMove::SupraMovePtr, SireMove::SupraMove >(); + register_property_container< SireMove::MolDeleterPtr, SireMove::MolDeleter >(); + register_property_container< SireMove::MolInserterPtr, SireMove::MolInserter >(); + register_property_container< SireMove::GetPointPtr, SireMove::GetPoint >(); register_property_container< SireMove::VelGenPtr, SireMove::VelocityGenerator >(); + register_property_container< SireMove::IntegratorPtr, SireMove::Integrator >(); + register_property_container< SireMove::MovePtr, SireMove::Move >(); + register_property_container< SireMove::SupraSubMovePtr, SireMove::SupraSubMove >(); + register_property_container< SireMove::MovesPtr, SireMove::Moves >(); } diff --git a/wrapper/Move/SireMove_registrars.cpp b/wrapper/Move/SireMove_registrars.cpp index 1734f7429..a1fcf7391 100644 --- a/wrapper/Move/SireMove_registrars.cpp +++ b/wrapper/Move/SireMove_registrars.cpp @@ -3,131 +3,129 @@ #include "SireMove_registrars.h" - - -#include "dlmrigidbody.h" -#include "ensemble.h" -#include "flexibility.h" -#include "getpoint.h" -#include "hybridmc.h" -#include "integrator.h" -#include "integratorworkspace.h" +#include "zmatrix.h" #include "integratorworkspacejm.h" #include "internalmove.h" +#include "simpacket.h" +#include "weightedmoves.h" +#include "openmmmdintegrator.h" +#include "zmatmove.h" +#include "replicas.h" +#include "mtsmc.h" +#include "uniformsampler.h" +#include "suprasubsystem.h" +#include "simstore.h" +#include "suprasubsimpacket.h" +#include "suprasubmoves.h" +#include "prefsampler.h" +#include "velocityverlet.h" +#include "openmmpmefep.h" +#include "suprasystem.h" +#include "rbworkspace.h" +#include "suprasimpacket.h" +#include "supramoves.h" +#include "volumemove.h" +#include "repexmove.h" +#include "supramove.h" #include "internalmovesingle.h" #include "moldeleter.h" +#include "repexmove2.h" #include "moleculardynamics.h" #include "molinserter.h" -#include "move.h" -#include "moves.h" -#include "mtsmc.h" -#include "openmmfrenergydt.h" +#include "dlmrigidbody.h" #include "openmmfrenergyst.h" -#include "openmmmdintegrator.h" -#include "openmmpmefep.h" -#include "prefsampler.h" -#include "rbworkspace.h" +#include "integratorworkspace.h" #include "rbworkspacejm.h" -#include "repexmove.h" -#include "repexmove2.h" +#include "getpoint.h" +#include "velocitygenerator.h" +#include "volumechanger.h" +#include "flexibility.h" +#include "integrator.h" +#include "titrator.h" +#include "move.h" #include "replica.h" -#include "replicas.h" +#include "hybridmc.h" #include "rigidbodymc.h" -#include "simpacket.h" -#include "simstore.h" -#include "supramove.h" -#include "supramoves.h" -#include "suprasimpacket.h" -#include "suprasubmove.h" -#include "suprasubmoves.h" -#include "suprasubsimpacket.h" -#include "suprasubsystem.h" -#include "suprasystem.h" +#include "ensemble.h" #include "titrationmove.h" -#include "titrator.h" -#include "uniformsampler.h" -#include "velocitygenerator.h" -#include "velocityverlet.h" -#include "volumechanger.h" -#include "volumemove.h" -#include "weightedmoves.h" -#include "zmatmove.h" -#include "zmatrix.h" +#include "openmmfrenergydt.h" +#include "suprasubmove.h" +#include "moves.h" #include "Helpers/objectregistry.hpp" void register_SireMove_objects() { - ObjectRegistry::registerConverterFor< SireMove::DLMRigidBody >(); - ObjectRegistry::registerConverterFor< SireMove::Ensemble >(); - ObjectRegistry::registerConverterFor< SireMove::DofID >(); - ObjectRegistry::registerConverterFor< SireMove::Flexibility >(); - ObjectRegistry::registerConverterFor< SireMove::NullGetPoint >(); - ObjectRegistry::registerConverterFor< SireMove::GetCOMPoint >(); - ObjectRegistry::registerConverterFor< SireMove::GetCOGPoint >(); - ObjectRegistry::registerConverterFor< SireMove::GetCentroidPoint >(); - ObjectRegistry::registerConverterFor< SireMove::HybridMC >(); - ObjectRegistry::registerConverterFor< SireMove::HMCGenerator >(); - ObjectRegistry::registerConverterFor< SireMove::NullIntegrator >(); - ObjectRegistry::registerConverterFor< SireMove::NullIntegratorWorkspace >(); - ObjectRegistry::registerConverterFor< SireMove::AtomicVelocityWorkspace >(); + ObjectRegistry::registerConverterFor< SireMove::ZMatrix >(); + ObjectRegistry::registerConverterFor< SireMove::ZMatrixLine >(); + ObjectRegistry::registerConverterFor< SireMove::ZMatrixCoords >(); + ObjectRegistry::registerConverterFor< SireMove::ZMatrixCoordsLine >(); ObjectRegistry::registerConverterFor< SireMove::NullIntegratorWorkspaceJM >(); ObjectRegistry::registerConverterFor< SireMove::AtomicVelocityWorkspaceJM >(); ObjectRegistry::registerConverterFor< SireMove::InternalMove >(); + ObjectRegistry::registerConverterFor< SireMove::SimPacket >(); + ObjectRegistry::registerConverterFor< SireMove::WeightedMoves >(); + ObjectRegistry::registerConverterFor< SireMove::OpenMMMDIntegrator >(); + ObjectRegistry::registerConverterFor< SireMove::OpenMMMDIntegrator >(); + ObjectRegistry::registerConverterFor< SireMove::ZMatMove >(); + ObjectRegistry::registerConverterFor< SireMove::Replicas >(); + ObjectRegistry::registerConverterFor< SireMove::MTSMC >(); + ObjectRegistry::registerConverterFor< SireMove::UniformSampler >(); + ObjectRegistry::registerConverterFor< SireMove::SupraSubSystem >(); + ObjectRegistry::registerConverterFor< SireMove::SimStore >(); + ObjectRegistry::registerConverterFor< SireMove::SupraSubSimPacket >(); + ObjectRegistry::registerConverterFor< SireMove::SameSupraSubMoves >(); + ObjectRegistry::registerConverterFor< SireMove::PrefSampler >(); + ObjectRegistry::registerConverterFor< SireMove::VelocityVerlet >(); + ObjectRegistry::registerConverterFor< SireMove::OpenMMPMEFEP >(); + ObjectRegistry::registerConverterFor< SireMove::OpenMMPMEFEP >(); + ObjectRegistry::registerConverterFor< SireMove::SupraSystem >(); + ObjectRegistry::registerConverterFor< SireMove::RBWorkspace >(); + ObjectRegistry::registerConverterFor< SireMove::SupraSimPacket >(); + ObjectRegistry::registerConverterFor< SireMove::SameSupraMoves >(); + ObjectRegistry::registerConverterFor< SireMove::VolumeMove >(); + ObjectRegistry::registerConverterFor< SireMove::RepExMove >(); + ObjectRegistry::registerConverterFor< SireMove::RepExSubMove >(); + ObjectRegistry::registerConverterFor< SireMove::NullSupraMove >(); ObjectRegistry::registerConverterFor< SireMove::InternalMoveSingle >(); ObjectRegistry::registerConverterFor< SireMove::NullDeleter >(); ObjectRegistry::registerConverterFor< SireMove::SpecifiedGroupsDeleter >(); ObjectRegistry::registerConverterFor< SireMove::SystemWideDeleter >(); + ObjectRegistry::registerConverterFor< SireMove::RepExMove2 >(); ObjectRegistry::registerConverterFor< SireMove::MolecularDynamics >(); ObjectRegistry::registerConverterFor< SireMove::NullInserter >(); ObjectRegistry::registerConverterFor< SireMove::UniformInserter >(); - ObjectRegistry::registerConverterFor< SireMove::NullMove >(); - ObjectRegistry::registerConverterFor< SireMove::SameMoves >(); - ObjectRegistry::registerConverterFor< SireMove::MTSMC >(); - ObjectRegistry::registerConverterFor< SireMove::OpenMMFrEnergyDT >(); - ObjectRegistry::registerConverterFor< SireMove::OpenMMFrEnergyDT >(); + ObjectRegistry::registerConverterFor< SireMove::DLMRigidBody >(); ObjectRegistry::registerConverterFor< SireMove::OpenMMFrEnergyST >(); ObjectRegistry::registerConverterFor< SireMove::OpenMMFrEnergyST >(); - ObjectRegistry::registerConverterFor< SireMove::OpenMMMDIntegrator >(); - ObjectRegistry::registerConverterFor< SireMove::OpenMMMDIntegrator >(); - ObjectRegistry::registerConverterFor< SireMove::OpenMMPMEFEP >(); - ObjectRegistry::registerConverterFor< SireMove::OpenMMPMEFEP >(); - ObjectRegistry::registerConverterFor< SireMove::PrefSampler >(); - ObjectRegistry::registerConverterFor< SireMove::RBWorkspace >(); + ObjectRegistry::registerConverterFor< SireMove::NullIntegratorWorkspace >(); + ObjectRegistry::registerConverterFor< SireMove::AtomicVelocityWorkspace >(); ObjectRegistry::registerConverterFor< SireMove::RBWorkspaceJM >(); - ObjectRegistry::registerConverterFor< SireMove::RepExMove >(); - ObjectRegistry::registerConverterFor< SireMove::RepExSubMove >(); - ObjectRegistry::registerConverterFor< SireMove::RepExMove2 >(); - ObjectRegistry::registerConverterFor< SireMove::Replica >(); - ObjectRegistry::registerConverterFor< SireMove::Replicas >(); - ObjectRegistry::registerConverterFor< SireMove::RigidBodyMC >(); - ObjectRegistry::registerConverterFor< SireMove::SimPacket >(); - ObjectRegistry::registerConverterFor< SireMove::SimStore >(); - ObjectRegistry::registerConverterFor< SireMove::NullSupraMove >(); - ObjectRegistry::registerConverterFor< SireMove::SameSupraMoves >(); - ObjectRegistry::registerConverterFor< SireMove::SupraSimPacket >(); - ObjectRegistry::registerConverterFor< SireMove::NullSupraSubMove >(); - ObjectRegistry::registerConverterFor< SireMove::SameSupraSubMoves >(); - ObjectRegistry::registerConverterFor< SireMove::SupraSubSimPacket >(); - ObjectRegistry::registerConverterFor< SireMove::SupraSubSystem >(); - ObjectRegistry::registerConverterFor< SireMove::SupraSystem >(); - ObjectRegistry::registerConverterFor< SireMove::TitrationMove >(); - ObjectRegistry::registerConverterFor< SireMove::Titrator >(); - ObjectRegistry::registerConverterFor< SireMove::UniformSampler >(); + ObjectRegistry::registerConverterFor< SireMove::NullGetPoint >(); + ObjectRegistry::registerConverterFor< SireMove::GetCOMPoint >(); + ObjectRegistry::registerConverterFor< SireMove::GetCOGPoint >(); + ObjectRegistry::registerConverterFor< SireMove::GetCentroidPoint >(); ObjectRegistry::registerConverterFor< SireMove::NullVelocityGenerator >(); ObjectRegistry::registerConverterFor< SireMove::VelocitiesFromProperty >(); ObjectRegistry::registerConverterFor< SireMove::MaxwellBoltzmann >(); - ObjectRegistry::registerConverterFor< SireMove::VelocityVerlet >(); ObjectRegistry::registerConverterFor< SireMove::NullVolumeChanger >(); ObjectRegistry::registerConverterFor< SireMove::ScaleVolumeFromCenter >(); - ObjectRegistry::registerConverterFor< SireMove::VolumeMove >(); - ObjectRegistry::registerConverterFor< SireMove::WeightedMoves >(); - ObjectRegistry::registerConverterFor< SireMove::ZMatMove >(); - ObjectRegistry::registerConverterFor< SireMove::ZMatrix >(); - ObjectRegistry::registerConverterFor< SireMove::ZMatrixLine >(); - ObjectRegistry::registerConverterFor< SireMove::ZMatrixCoords >(); - ObjectRegistry::registerConverterFor< SireMove::ZMatrixCoordsLine >(); + ObjectRegistry::registerConverterFor< SireMove::DofID >(); + ObjectRegistry::registerConverterFor< SireMove::Flexibility >(); + ObjectRegistry::registerConverterFor< SireMove::NullIntegrator >(); + ObjectRegistry::registerConverterFor< SireMove::Titrator >(); + ObjectRegistry::registerConverterFor< SireMove::NullMove >(); + ObjectRegistry::registerConverterFor< SireMove::Replica >(); + ObjectRegistry::registerConverterFor< SireMove::HybridMC >(); + ObjectRegistry::registerConverterFor< SireMove::HMCGenerator >(); + ObjectRegistry::registerConverterFor< SireMove::RigidBodyMC >(); + ObjectRegistry::registerConverterFor< SireMove::Ensemble >(); + ObjectRegistry::registerConverterFor< SireMove::TitrationMove >(); + ObjectRegistry::registerConverterFor< SireMove::OpenMMFrEnergyDT >(); + ObjectRegistry::registerConverterFor< SireMove::OpenMMFrEnergyDT >(); + ObjectRegistry::registerConverterFor< SireMove::NullSupraSubMove >(); + ObjectRegistry::registerConverterFor< SireMove::SameMoves >(); } diff --git a/wrapper/Move/ZMatrix.pypp.cpp b/wrapper/Move/ZMatrix.pypp.cpp index b9dc4d77b..30c44ca72 100644 --- a/wrapper/Move/ZMatrix.pypp.cpp +++ b/wrapper/Move/ZMatrix.pypp.cpp @@ -488,6 +488,18 @@ void register_ZMatrix_class(){ , bp::release_gil_policy() , "Return a z-matrix that only contains lines that involve the atoms\nthat are in selection" ); + } + { //::SireMove::ZMatrix::merge + + typedef ::SireBase::PropertyList ( ::SireMove::ZMatrix::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMove::ZMatrix::merge ); + + ZMatrix_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMove::ZMatrix::nLines diff --git a/wrapper/Move/ZMatrixCoords.pypp.cpp b/wrapper/Move/ZMatrixCoords.pypp.cpp index 0ea9229a7..1478e4b07 100644 --- a/wrapper/Move/ZMatrixCoords.pypp.cpp +++ b/wrapper/Move/ZMatrixCoords.pypp.cpp @@ -607,6 +607,18 @@ void register_ZMatrixCoords_class(){ , bp::release_gil_policy() , "Return a z-matrix that only contains lines that involve the atoms\nthat are in selection" ); + } + { //::SireMove::ZMatrixCoords::merge + + typedef ::SireBase::PropertyList ( ::SireMove::ZMatrixCoords::*merge_function_type)( ::SireMol::MolViewProperty const &,::SireMol::AtomIdxMapping const &,::QString const &,::SireBase::PropertyMap const & ) const; + merge_function_type merge_function_value( &::SireMove::ZMatrixCoords::merge ); + + ZMatrixCoords_exposer.def( + "merge" + , merge_function_value + , ( bp::arg("other"), bp::arg("mapping"), bp::arg("ghost")=::QString( ), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + } { //::SireMove::ZMatrixCoords::move diff --git a/wrapper/System/CMakeAutogenFile.txt b/wrapper/System/CMakeAutogenFile.txt index 32c7048c6..3ddf80616 100644 --- a/wrapper/System/CMakeAutogenFile.txt +++ b/wrapper/System/CMakeAutogenFile.txt @@ -1,53 +1,53 @@ # WARNING - AUTOGENERATED FILE - CONTENTS WILL BE OVERWRITTEN! set ( PYPP_SOURCES - AngleComponent.pypp.cpp - AssignerGroup.pypp.cpp - ChargeConstraint.pypp.cpp - CheckPoint.pypp.cpp - CloseMols.pypp.cpp ComponentConstraint.pypp.cpp - Constraint.pypp.cpp - Constraints.pypp.cpp - DihedralComponent.pypp.cpp - DistanceComponent.pypp.cpp - DoubleDistanceComponent.pypp.cpp + TripleDistanceComponent.pypp.cpp EnergyMonitor.pypp.cpp - ForceFieldInfo.pypp.cpp - FreeEnergyMonitor.pypp.cpp - GeometryComponent.pypp.cpp - IDAndSet_MonitorID_.pypp.cpp - IDAndSet_SysID_.pypp.cpp - IDAssigner.pypp.cpp - IDOrSet_MonitorID_.pypp.cpp + PropertyConstraint.pypp.cpp + PolariseCharges.pypp.cpp + NullConstraint.pypp.cpp + Specify_MonitorID_.pypp.cpp + SpaceWrapper.pypp.cpp + WindowedComponent.pypp.cpp + CloseMols.pypp.cpp + CheckPoint.pypp.cpp + MonitorMonitor.pypp.cpp + MonitorIdx.pypp.cpp + DihedralComponent.pypp.cpp + System.pypp.cpp IDOrSet_SysID_.pypp.cpp - IdentityConstraint.pypp.cpp - MoleculeConstraint.pypp.cpp + DoubleDistanceComponent.pypp.cpp + Constraints.pypp.cpp + AssignerGroup.pypp.cpp + SysID.pypp.cpp MonitorComponent.pypp.cpp + ForceFieldInfo.pypp.cpp MonitorComponents.pypp.cpp MonitorID.pypp.cpp - MonitorIdx.pypp.cpp - MonitorMonitor.pypp.cpp - MonitorName.pypp.cpp - MonitorProperty.pypp.cpp - NullConstraint.pypp.cpp + IdentityConstraint.pypp.cpp + SystemMonitors.pypp.cpp + IDOrSet_MonitorID_.pypp.cpp + _System_free_functions.pypp.cpp + SysName.pypp.cpp NullMonitor.pypp.cpp PerturbationConstraint.pypp.cpp - PolariseCharges.pypp.cpp - PolariseChargesFF.pypp.cpp - PropertyConstraint.pypp.cpp - SpaceWrapper.pypp.cpp - Specify_MonitorID_.pypp.cpp - Specify_SysID_.pypp.cpp - SysID.pypp.cpp - SysIdx.pypp.cpp - SysName.pypp.cpp - System.pypp.cpp + MonitorName.pypp.cpp + FreeEnergyMonitor.pypp.cpp SystemMonitor.pypp.cpp - SystemMonitors.pypp.cpp - TripleDistanceComponent.pypp.cpp + SysIdx.pypp.cpp + MoleculeConstraint.pypp.cpp + AngleComponent.pypp.cpp + DistanceComponent.pypp.cpp VolMapMonitor.pypp.cpp - WindowedComponent.pypp.cpp - _System_free_functions.pypp.cpp + ChargeConstraint.pypp.cpp + Specify_SysID_.pypp.cpp + Constraint.pypp.cpp + IDAndSet_MonitorID_.pypp.cpp + GeometryComponent.pypp.cpp + IDAndSet_SysID_.pypp.cpp + MonitorProperty.pypp.cpp + PolariseChargesFF.pypp.cpp + IDAssigner.pypp.cpp SireSystem_containers.cpp SireSystem_properties.cpp SireSystem_registrars.cpp diff --git a/wrapper/System/SireSystem_registrars.cpp b/wrapper/System/SireSystem_registrars.cpp index 55a0a3e82..78bae3b56 100644 --- a/wrapper/System/SireSystem_registrars.cpp +++ b/wrapper/System/SireSystem_registrars.cpp @@ -3,83 +3,83 @@ #include "SireSystem_registrars.h" -#include "anglecomponent.h" +#include "systemmonitors.h" +#include "sysidentifier.h" #include "checkpoint.h" -#include "closemols.h" -#include "constraint.h" -#include "constraints.h" +#include "monitorcomponent.h" #include "dihedralcomponent.h" -#include "distancecomponent.h" #include "energymonitor.h" -#include "forcefieldinfo.h" -#include "freeenergymonitor.h" +#include "constraints.h" +#include "perturbationconstraint.h" +#include "sysidx.h" #include "idassigner.h" -#include "identityconstraint.h" -#include "monitorcomponent.h" +#include "spacewrapper.h" +#include "freeenergymonitor.h" +#include "forcefieldinfo.h" +#include "monitormonitor.h" #include "monitorcomponents.h" -#include "monitoridentifier.h" #include "monitoridx.h" -#include "monitormonitor.h" -#include "monitorname.h" -#include "monitorproperty.h" -#include "perturbationconstraint.h" -#include "polarisecharges.h" -#include "spacewrapper.h" -#include "sysidentifier.h" -#include "sysidx.h" +#include "identityconstraint.h" +#include "monitoridentifier.h" +#include "constraint.h" +#include "anglecomponent.h" #include "sysname.h" +#include "distancecomponent.h" +#include "closemols.h" #include "system.h" -#include "systemmonitor.h" -#include "systemmonitors.h" +#include "monitorproperty.h" #include "volmapmonitor.h" +#include "monitorname.h" +#include "polarisecharges.h" +#include "systemmonitor.h" #include "Helpers/objectregistry.hpp" void register_SireSystem_objects() { - ObjectRegistry::registerConverterFor< SireSystem::AngleComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::SystemMonitors >(); + ObjectRegistry::registerConverterFor< SireID::Specify >(); + ObjectRegistry::registerConverterFor< SireID::IDAndSet >(); + ObjectRegistry::registerConverterFor< SireID::IDOrSet >(); + ObjectRegistry::registerConverterFor< SireSystem::SysIdentifier >(); ObjectRegistry::registerConverterFor< SireSystem::CheckPoint >(); - ObjectRegistry::registerConverterFor< SireSystem::CloseMols >(); - ObjectRegistry::registerConverterFor< SireSystem::NullConstraint >(); - ObjectRegistry::registerConverterFor< SireSystem::PropertyConstraint >(); - ObjectRegistry::registerConverterFor< SireSystem::ComponentConstraint >(); - ObjectRegistry::registerConverterFor< SireSystem::WindowedComponent >(); - ObjectRegistry::registerConverterFor< SireSystem::Constraints >(); + ObjectRegistry::registerConverterFor< SireSystem::MonitorComponent >(); ObjectRegistry::registerConverterFor< SireSystem::DihedralComponent >(); - ObjectRegistry::registerConverterFor< SireSystem::DistanceComponent >(); - ObjectRegistry::registerConverterFor< SireSystem::DoubleDistanceComponent >(); - ObjectRegistry::registerConverterFor< SireSystem::TripleDistanceComponent >(); ObjectRegistry::registerConverterFor< SireSystem::EnergyMonitor >(); - ObjectRegistry::registerConverterFor< SireSystem::ForceFieldInfo >(); + ObjectRegistry::registerConverterFor< SireSystem::Constraints >(); + ObjectRegistry::registerConverterFor< SireSystem::PerturbationConstraint >(); + ObjectRegistry::registerConverterFor< SireSystem::SysIdx >(); + ObjectRegistry::registerConverterFor< SireSystem::IDAssigner >(); + ObjectRegistry::registerConverterFor< SireSystem::SpaceWrapper >(); ObjectRegistry::registerConverterFor< SireSystem::FreeEnergyMonitor >(); ObjectRegistry::registerConverterFor< SireSystem::AssignerGroup >(); - ObjectRegistry::registerConverterFor< SireSystem::IDAssigner >(); - ObjectRegistry::registerConverterFor< SireSystem::IdentityConstraint >(); - ObjectRegistry::registerConverterFor< SireSystem::MonitorComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::ForceFieldInfo >(); + ObjectRegistry::registerConverterFor< SireSystem::MonitorMonitor >(); ObjectRegistry::registerConverterFor< SireSystem::MonitorComponents >(); + ObjectRegistry::registerConverterFor< SireSystem::MonitorIdx >(); + ObjectRegistry::registerConverterFor< SireSystem::IdentityConstraint >(); ObjectRegistry::registerConverterFor< SireID::Specify >(); ObjectRegistry::registerConverterFor< SireID::IDAndSet >(); ObjectRegistry::registerConverterFor< SireID::IDOrSet >(); ObjectRegistry::registerConverterFor< SireSystem::MonitorIdentifier >(); - ObjectRegistry::registerConverterFor< SireSystem::MonitorIdx >(); - ObjectRegistry::registerConverterFor< SireSystem::MonitorMonitor >(); - ObjectRegistry::registerConverterFor< SireSystem::MonitorName >(); + ObjectRegistry::registerConverterFor< SireSystem::NullConstraint >(); + ObjectRegistry::registerConverterFor< SireSystem::PropertyConstraint >(); + ObjectRegistry::registerConverterFor< SireSystem::ComponentConstraint >(); + ObjectRegistry::registerConverterFor< SireSystem::WindowedComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::AngleComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::SysName >(); + ObjectRegistry::registerConverterFor< SireSystem::DistanceComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::DoubleDistanceComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::TripleDistanceComponent >(); + ObjectRegistry::registerConverterFor< SireSystem::CloseMols >(); + ObjectRegistry::registerConverterFor< SireSystem::System >(); ObjectRegistry::registerConverterFor< SireSystem::MonitorProperty >(); - ObjectRegistry::registerConverterFor< SireSystem::PerturbationConstraint >(); + ObjectRegistry::registerConverterFor< SireSystem::VolMapMonitor >(); + ObjectRegistry::registerConverterFor< SireSystem::MonitorName >(); ObjectRegistry::registerConverterFor< SireSystem::PolariseCharges >(); ObjectRegistry::registerConverterFor< SireSystem::PolariseChargesFF >(); - ObjectRegistry::registerConverterFor< SireSystem::SpaceWrapper >(); - ObjectRegistry::registerConverterFor< SireID::Specify >(); - ObjectRegistry::registerConverterFor< SireID::IDAndSet >(); - ObjectRegistry::registerConverterFor< SireID::IDOrSet >(); - ObjectRegistry::registerConverterFor< SireSystem::SysIdentifier >(); - ObjectRegistry::registerConverterFor< SireSystem::SysIdx >(); - ObjectRegistry::registerConverterFor< SireSystem::SysName >(); - ObjectRegistry::registerConverterFor< SireSystem::System >(); ObjectRegistry::registerConverterFor< SireSystem::NullMonitor >(); - ObjectRegistry::registerConverterFor< SireSystem::SystemMonitors >(); - ObjectRegistry::registerConverterFor< SireSystem::VolMapMonitor >(); } diff --git a/wrapper/System/_System_free_functions.pypp.cpp b/wrapper/System/_System_free_functions.pypp.cpp index 51ab0031a..19a7794de 100644 --- a/wrapper/System/_System_free_functions.pypp.cpp +++ b/wrapper/System/_System_free_functions.pypp.cpp @@ -721,6 +721,20 @@ namespace bp = boost::python; #include "create_test_molecule.h" +#include "SireMM/mmdetail.h" + +#include "SireMol/atomidxmapping.h" + +#include "SireMol/core.h" + +#include "SireMol/moleditor.h" + +#include "SireSystem/merge.h" + +#include "merge.h" + +#include "merge.h" + void register_free_functions(){ { //::SireSystem::calculate_energy @@ -969,4 +983,17 @@ void register_free_functions(){ } + { //::SireSystem::merge + + typedef ::SireMol::Molecule ( *merge_function_type )( ::SireMol::AtomMapping const &,::QStringList const &,bool,bool,bool,bool,::SireBase::PropertyMap const & ); + merge_function_type merge_function_value( &::SireSystem::merge ); + + bp::def( + "merge" + , merge_function_value + , ( bp::arg("mols"), bp::arg("properties")=::QStringList( ), bp::arg("as_new_molecule")=(bool)(true), bp::arg("allow_ring_breaking")=(bool)(false), bp::arg("allow_ring_size_change")=(bool)(false), bp::arg("force")=(bool)(false), bp::arg("map")=SireBase::PropertyMap() ) + , "" ); + + } + } diff --git a/wrapper/System/active_headers.h b/wrapper/System/active_headers.h index 923425a8b..a532f983f 100644 --- a/wrapper/System/active_headers.h +++ b/wrapper/System/active_headers.h @@ -19,6 +19,7 @@ #include "geometrycomponent.h" #include "idassigner.h" #include "identityconstraint.h" +#include "merge.h" #include "moleculeconstraint.h" #include "monitorcomponent.h" #include "monitorcomponents.h"