From 6e2637a12be95c56d6ba01dcf439bb8f841f5f6e Mon Sep 17 00:00:00 2001 From: Tristan Youngs Date: Mon, 22 Jun 2026 16:34:56 +0100 Subject: [PATCH 1/5] Start. --- CMakeLists.txt | 1 - src/classes/configuration.h | 22 ----- src/classes/configurationAtom.h | 16 --- src/kernels/CMakeLists.txt | 1 - src/kernels/potentials/CMakeLists.txt | 15 --- src/kernels/potentials/base.cpp | 129 ------------------------- src/kernels/potentials/base.h | 96 ------------------ src/kernels/potentials/cylindrical.cpp | 108 --------------------- src/kernels/potentials/cylindrical.h | 51 ---------- src/kernels/potentials/producer.cpp | 25 ----- src/kernels/potentials/producer.h | 17 ---- src/kernels/potentials/spherical.cpp | 63 ------------ src/kernels/potentials/spherical.h | 48 --------- src/kernels/potentials/types.cpp | 24 ----- src/kernels/potentials/types.h | 23 ----- 15 files changed, 639 deletions(-) delete mode 100644 src/kernels/potentials/CMakeLists.txt delete mode 100644 src/kernels/potentials/base.cpp delete mode 100644 src/kernels/potentials/base.h delete mode 100644 src/kernels/potentials/cylindrical.cpp delete mode 100644 src/kernels/potentials/cylindrical.h delete mode 100644 src/kernels/potentials/producer.cpp delete mode 100644 src/kernels/potentials/producer.h delete mode 100644 src/kernels/potentials/spherical.cpp delete mode 100644 src/kernels/potentials/spherical.h delete mode 100644 src/kernels/potentials/types.cpp delete mode 100644 src/kernels/potentials/types.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dec8cf477..abccc79fcf 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,7 +293,6 @@ set(BASIC_LINK_LIBS main classes kernels - potentials neta analyser keywords diff --git a/src/classes/configuration.h b/src/classes/configuration.h index da491da7cd..df0030b4b4 100644 --- a/src/classes/configuration.h +++ b/src/classes/configuration.h @@ -10,7 +10,6 @@ #include "classes/configurationAtom.h" #include "classes/molecule.h" #include "classes/siteStack.h" -#include "kernels/potentials/base.h" #include #include #include @@ -177,27 +176,6 @@ class Configuration : public Serialisable // Scale Box, Cells, and Molecule geometric centres according to current size factor void applySizeFactor(const EnergyKernel *kernel); - /* - * External Potentials - */ - private: - // Defined global potentials - std::vector> globalPotentials_; - // Defined targeted potentials - std::vector> targetedPotentials_; - - public: - // Add global potential - void addGlobalPotential(std::unique_ptr potential); - // Return vector of defined global potentials - const std::vector> &globalPotentials() const; - // Add targeted potential - void addTargetedPotential(std::unique_ptr potential); - // Return vector of defined targeted potentials - const std::vector> &targetedPotentials() const; - // Link targeted potentials to atoms - void linkTargetedPotentials(); - /* * Upkeep */ diff --git a/src/classes/configurationAtom.h b/src/classes/configurationAtom.h index 45801beb41..07598e34d1 100644 --- a/src/classes/configurationAtom.h +++ b/src/classes/configurationAtom.h @@ -6,7 +6,6 @@ #include "classes/atom.h" #include "classes/speciesAtom.h" #include "classes/speciesBond.h" -#include "kernels/potentials/base.h" #include #include @@ -48,19 +47,4 @@ class ConfigurationAtom : public Atom public: // Return scaling type and factors (electrostatic, van der Waals) to employ with specified Atom SpeciesAtom::ScaledInteractionDefinition scaling(const ConfigurationAtom *j) const; - - /* - * Targeted External Potentials - */ - private: - // Vector of targeted potentials affecting this atom - std::vector targetedPotentials_; - - public: - // Add targeted potential to this atom - void addTargetedPotential(const ExternalPotential *potential); - // Clear all targeted potentials from this Atom - void clearTargetedPotentials(); - // Return list of targeted potentials for this atom - const std::vector &targetedPotentials() const; }; diff --git a/src/kernels/CMakeLists.txt b/src/kernels/CMakeLists.txt index c046e1c36d..bc497d027d 100644 --- a/src/kernels/CMakeLists.txt +++ b/src/kernels/CMakeLists.txt @@ -20,4 +20,3 @@ add_library( target_include_directories(kernels PRIVATE ${PROJECT_SOURCE_DIR}/src) target_link_libraries(kernels PUBLIC base ${THREADING_LINK_LIBS}) -add_subdirectory(potentials) diff --git a/src/kernels/potentials/CMakeLists.txt b/src/kernels/potentials/CMakeLists.txt deleted file mode 100644 index d07084e59e..0000000000 --- a/src/kernels/potentials/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_library( - potentials - base.cpp - cylindrical.cpp - producer.cpp - spherical.cpp - types.cpp - base.h - cylindrical.h - producer.h - spherical.h - types.h -) - -target_include_directories(potentials PRIVATE ${PROJECT_SOURCE_DIR}/src ${CONAN_INCLUDE_DIRS}) diff --git a/src/kernels/potentials/base.cpp b/src/kernels/potentials/base.cpp deleted file mode 100644 index 3cdc2353d9..0000000000 --- a/src/kernels/potentials/base.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/potentials/base.h" -#include "classes/atomType.h" -#include "classes/species.h" -#include "templates/algorithms.h" -#include "types.h" - -ExternalPotential::ExternalPotential(ExternalPotentialTypes::ExternalPotentialType type) : type_(type) {} - -// Create and return a copy of this potential -std::unique_ptr ExternalPotential::duplicate() const -{ - Messenger::exception("Can't duplicate() an ExternalPotential of this type.\n"); -} - -/* - * Target Information - */ - -// Set atom indices targeted by the potential -void ExternalPotential::setTargetAtomIndices(const std::vector &targets) { targetAtomIndices_ = targets; } - -// Add target atom index -void ExternalPotential::addTargetAtomIndex(int index) { targetAtomIndices_.push_back(index); } - -// Return atom indices targeted by the potential -const std::vector &ExternalPotential::targetAtomIndices() const { return targetAtomIndices_; } - -ExternalPotentialTypes::ExternalPotentialType ExternalPotential::type() const { return type_; } - -// Atom types targeted by the potential -void ExternalPotential::setTargetAtomTypes(const std::vector &targets) { targetAtomTypes_ = targets; } - -// Add target atom type -void ExternalPotential::addTargetAtomType(const AtomType *target) { targetAtomTypes_.emplace_back(target); } - -// Return atom types targeted by the potential -const std::vector &ExternalPotential::targetAtomTypes() const { return targetAtomTypes_; } - -// Species targeted by the potential -void ExternalPotential::setTargetSpecies(const std::vector &targets) { targetSpecies_ = targets; } - -// Add target species -void ExternalPotential::addTargetSpecies(const Species *target) { targetSpecies_.emplace_back(target); } - -// Return species targeted by the potential -const std::vector &ExternalPotential::targetSpecies() const { return targetSpecies_; } - -/* - * Keywords - */ - -// Return keywords for this potential -KeywordStore &ExternalPotential::keywords() { return keywords_; } -const KeywordStore &ExternalPotential::keywords() const { return keywords_; } - -/* - * Potential Calculation - */ - -// Calculate energy on specified atom -double ExternalPotential::energy(const ConfigurationAtom &i, const Box &box) const { return 0.0; } - -// Calculate force on specified atom, summing in to supplied vector -void ExternalPotential::force(const ConfigurationAtom &i, const Box &box, Vector3 &f) const {} - -/* - * Read / Write - */ - -// Read data from specified LineParser -bool ExternalPotential::deserialise(LineParser &parser, const CoreData &coreData) -{ - // Read until we encounter the ending keyword (derived from the potential type), or we fail for some reason - while (!parser.eofOrBlank()) - { - // Read and parse the next line - if (parser.getArgsDelim() != LineParser::Success) - return false; - - // Is this the end of the block? - if (DissolveSys::sameString(parser.argsv(0), std::format("End{}", ExternalPotentialTypes::keyword(type_)))) - return true; - - // Try to parse this line as a keyword - KeywordBase::ParseResult result = keywords_.deserialise(parser, coreData); - if (result == KeywordBase::ParseResult::Unrecognised) - return Messenger::error("Unrecognised keyword '{}' found while parsing {} additional potential.\n", parser.argsv(0), - ExternalPotentialTypes::keyword(type_)); - else if (result == KeywordBase::ParseResult::Deprecated) - Messenger::warn("The '{}' keyword is deprecated and will be removed in a future version.\n", parser.argsv(0)); - else if (result == KeywordBase::ParseResult::Failed) - return Messenger::error("Failed to parse keyword '{}'.\n", parser.argsv(0)); - } - - return true; -} - -// Write data to specified LineParser -bool ExternalPotential::serialise(LineParser &parser, std::string_view prefix) const -{ - // Assemble target strings - std::string targets; - if (!targetAtomIndices_.empty()) - targets += std::format(" {}", joinStrings(targetAtomIndices_, " ")); - if (!targetAtomTypes_.empty()) - targets += std::format(" {}", joinStrings(targetAtomTypes_, " ", [](const auto &at) { return at->name(); })); - if (!targetSpecies_.empty()) - targets += std::format(" {}", joinStrings(targetSpecies_, " ", [](const auto &sp) { return sp->name(); })); - - // Block Start - if (!parser.writeLineF("{}{}{}\n", prefix, ExternalPotentialTypes::keyword(type_), targets)) - return false; - - // Create new prefix - std::string newPrefix = std::format(" {}", prefix); - - // Write keywords - if (!keywords_.serialise(parser, newPrefix, true)) - return false; - - // Block End - if (!parser.writeLineF("{}End{}\n", prefix, ExternalPotentialTypes::keyword(type_))) - return false; - - return true; -} diff --git a/src/kernels/potentials/base.h b/src/kernels/potentials/base.h deleted file mode 100644 index 39519b6aca..0000000000 --- a/src/kernels/potentials/base.h +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/interactionPotential.h" -#include "kernels/potentials/types.h" -#include "keywords/store.h" - -// Forward Declarations -class ConfigurationAtom; -class Box; -class LineParser; - -// Extended Potential Base Class -class ExternalPotential -{ - public: - explicit ExternalPotential(ExternalPotentialTypes::ExternalPotentialType type); - virtual ~ExternalPotential() = default; - // Create and return a copy of this potential - virtual std::unique_ptr duplicate() const; - - /* - * Type - */ - protected: - // Additional potential type - ExternalPotentialTypes::ExternalPotentialType type_; - - /* - * Target Information - */ - protected: - // Atom indices targeted by the potential - std::vector targetAtomIndices_; - // Atom types targeted by the potential - std::vector targetAtomTypes_; - // Species targeted by the potential - std::vector targetSpecies_; - - public: - ExternalPotentialTypes::ExternalPotentialType type() const; - // Set atom indices targeted by the potential - void setTargetAtomIndices(const std::vector &targets); - // Add target atom index - void addTargetAtomIndex(int index); - // Return atom indices targeted by the potential - const std::vector &targetAtomIndices() const; - // Atom types targeted by the potential - void setTargetAtomTypes(const std::vector &targets); - // Add target atom type - void addTargetAtomType(const AtomType *target); - // Return atom types targeted by the potential - const std::vector &targetAtomTypes() const; - // Species targeted by the potential - void setTargetSpecies(const std::vector &targets); - // Add target species - void addTargetSpecies(const Species *target); - // Return species targeted by the potential - const std::vector &targetSpecies() const; - // Return functional form of the potential, as a string - virtual const std::string formString() const = 0; - // Return parameters of the potential, as a string - virtual const std::string formParametersString() const = 0; - - /* - * Keywords - */ - protected: - // Keywords for the potential - KeywordStore keywords_; - - public: - // Return keywords for this potential - KeywordStore &keywords(); - const KeywordStore &keywords() const; - - /* - * Potential Calculation - */ - public: - // Calculate energy on specified atom - virtual double energy(const ConfigurationAtom &i, const Box &box) const; - // Calculate force on specified atom, summing in to supplied vector - virtual void force(const ConfigurationAtom &i, const Box &box, Vector3 &f) const; - - /* - * Read / Write - */ - public: - // Read data from specified LineParser - bool deserialise(LineParser &parser, const CoreData &coreData); - // Write data to specified LineParser - bool serialise(LineParser &parser, std::string_view prefix) const; -}; diff --git a/src/kernels/potentials/cylindrical.cpp b/src/kernels/potentials/cylindrical.cpp deleted file mode 100644 index 0b87bd4095..0000000000 --- a/src/kernels/potentials/cylindrical.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/potentials/cylindrical.h" -#include "classes/box.h" -#include "classes/configurationAtom.h" -#include "keywords/interactionPotential.h" -#include "keywords/vec3Double.h" -#include "keywords/vec3Labels.h" -#include "types.h" - -CylindricalPotential::CylindricalPotential(const InteractionPotential &interactionPotential, const Vector3 &origin, - const Vector3 &vector) - : ExternalPotential(ExternalPotentialTypes::ExternalPotentialType::Cylindrical), origin_(origin), vector_(vector) -{ - keywords_.add("Origin", "Reference origin point", origin_, Vec3Labels::LabelType::XYZLabels); - keywords_.add>("Form", "Functional form and parameters for the potential", - interactionPotential_); - keywords_.add("Vector", "Direction vector", vector_, Vec3Labels::LabelType::XYZLabels); - - setPotential(interactionPotential); -} - -// Create and return a copy of this potential -std::unique_ptr CylindricalPotential::duplicate() const -{ - return std::make_unique(interactionPotential_, origin_, vector_); -} - -/* - * Definition - */ - -// Set potential form -void CylindricalPotential::setPotential(const InteractionPotential &potential) -{ - interactionPotential_ = potential; - potentialFunction_.setFormAndParameters(interactionPotential_.form(), interactionPotential_.parameters()); -} - -// Set coordinate origin of potential -void CylindricalPotential::setOrigin(const Vector3 &origin) { origin_ = origin; } - -// Set vector of potential -void CylindricalPotential::setVector(const Vector3 &vector) { vector_ = vector; } - -// Return functional form of the potential, as a string -const std::string CylindricalPotential::formString() const -{ - return Functions1D::forms().keyword(interactionPotential_.form()); -} - -// Return parameters of the potential, as a string -const std::string CylindricalPotential::formParametersString() const { return interactionPotential_.parametersAsString(); } - -/* - * Potential Calculation - */ - -// Calculate energy on specified atom -double CylindricalPotential::energy(const ConfigurationAtom &i, const Box &box) const -{ - // Vector between the position of the atom and the origin - auto v = box.minimumVector(i.r(), origin_); - - // See: A Programmers Geometry, Bowyer and Woodwark, Butterworths (pub.), 1983, p99 - - // Cross product between the line and the position of the atom in the xy plane - auto xyyx = vector_.x * v.y - vector_.y * v.x; - // Cross product between the line and the position of the atom in the xz plane - auto zxxz = vector_.z * v.x - vector_.x * v.z; - // Cross product between the line and the position of the atom in the yz plane - auto yzzy = vector_.y * v.z - vector_.z * v.y; - - // Compute new components - v.x = vector_.y * xyyx - vector_.z * zxxz; - v.y = vector_.z * yzzy - vector_.x * xyyx; - v.z = vector_.x * zxxz - vector_.y * yzzy; - - // Return energy at minimum distance between the atom and a point on the line - return potentialFunction_.y(v.magnitude()); -} - -// Calculate force on specified atom, summing in to supplied vector -void CylindricalPotential::force(const ConfigurationAtom &i, const Box &box, Vector3 &f) const -{ - // Vector between the position of the atom and the origin - auto v = box.minimumVector(i.r(), origin_); - - // See: A Programmers Geometry, Bowyer and Woodwark, Butterworths (pub.), 1983, p99 - - // Cross product between the line and the position of the atom in the xy plane - auto xyyx = vector_.x * v.y - vector_.y * v.x; - // Cross product between the line and the position of the atom in the xz plane - auto zxxz = vector_.z * v.x - vector_.x * v.z; - // Cross product between the line and the position of the atom in the yz plane - auto yzzy = vector_.y * v.z - vector_.z * v.y; - - // Compute new components - v.x = vector_.y * xyyx - vector_.z * zxxz; - v.y = vector_.z * yzzy - vector_.x * xyyx; - v.z = vector_.x * zxxz - vector_.y * yzzy; - - auto r = v.magAndNormalise(); - - // Get force at minimum distance between the atom and a point on the line - f = v * -potentialFunction_.dYdX(r); -} diff --git a/src/kernels/potentials/cylindrical.h b/src/kernels/potentials/cylindrical.h deleted file mode 100644 index d22d36e836..0000000000 --- a/src/kernels/potentials/cylindrical.h +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/interactionPotential.h" -#include "kernels/potentials/base.h" - -// Cylindrical Potential -class CylindricalPotential : public ExternalPotential -{ - public: - CylindricalPotential(const InteractionPotential &interactionPotential = {Functions1D::Form::LennardJones126}, - const Vector3 &origin = {0.0, 0.0, 0.0}, const Vector3 &vector = {0.0, 0.0, 1.0}); - ~CylindricalPotential() = default; - // Create and return a copy of this potential - std::unique_ptr duplicate() const override; - - /* - * Definition - */ - private: - // Potential function - InteractionPotential interactionPotential_; - Function1DWrapper potentialFunction_; - // Coordinate origin of potential - Vector3 origin_; - // Direction of potential - Vector3 vector_; - - public: - // Set potential form - void setPotential(const InteractionPotential &potential); - // Set coordinate origin of potential - void setOrigin(const Vector3 &origin); - // Set vector of potential - void setVector(const Vector3 &vector); - // Return functional form of the potential, as a string - const std::string formString() const override; - // Return parameters of the potential, as a string - const std::string formParametersString() const override; - - /* - * Potential Calculation - */ - public: - // Calculate energy on specified atom - double energy(const ConfigurationAtom &i, const Box &box) const override; - // Calculate force on specified atom, summing in to supplied vector - void force(const ConfigurationAtom &i, const Box &box, Vector3 &f) const override; -}; diff --git a/src/kernels/potentials/producer.cpp b/src/kernels/potentials/producer.cpp deleted file mode 100644 index 1b09e2fdcf..0000000000 --- a/src/kernels/potentials/producer.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/potentials/producer.h" -#include "kernels/potentials/cylindrical.h" -#include "kernels/potentials/spherical.h" - -// External Potential Producer -namespace ExternalPotentialProducer -{ -// Create an external potential of the specified type -std::unique_ptr create(ExternalPotentialTypes::ExternalPotentialType type) -{ - switch (type) - { - case (ExternalPotentialTypes::ExternalPotentialType::Spherical): - return std::make_unique(); - case (ExternalPotentialTypes::ExternalPotentialType::Cylindrical): - return std::make_unique(); - default: - Messenger::exception("Creation of external potential type '{}' not implemented.", - ExternalPotentialTypes::keyword(type)); - } -} -}; // namespace ExternalPotentialProducer diff --git a/src/kernels/potentials/producer.h b/src/kernels/potentials/producer.h deleted file mode 100644 index 2c95cabc07..0000000000 --- a/src/kernels/potentials/producer.h +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "kernels/potentials/types.h" -#include - -// Forward Declarations -class ExternalPotential; - -// External Potential Producer -namespace ExternalPotentialProducer -{ -// Create an external potential of the specified type -std::unique_ptr create(ExternalPotentialTypes::ExternalPotentialType type); -}; // namespace ExternalPotentialProducer diff --git a/src/kernels/potentials/spherical.cpp b/src/kernels/potentials/spherical.cpp deleted file mode 100644 index 1335cef844..0000000000 --- a/src/kernels/potentials/spherical.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/potentials/spherical.h" -#include "classes/box.h" -#include "classes/configurationAtom.h" -#include "keywords/interactionPotential.h" -#include "keywords/vec3Double.h" - -SphericalPotential::SphericalPotential(const InteractionPotential &interactionPotential, const Vector3 &origin) - : ExternalPotential(ExternalPotentialTypes::ExternalPotentialType::Spherical), interactionPotential_(interactionPotential), - origin_(origin) -{ - keywords_.add("Origin", "Reference origin point", origin_, Vec3Labels::LabelType::XYZLabels); - keywords_.add>("Form", "Functional form and parameters for the potential", - interactionPotential_); -} - -// Create and return a copy of this potential -std::unique_ptr SphericalPotential::duplicate() const -{ - return std::make_unique(interactionPotential_, origin_); -} - -/* - * Definition - */ - -// Set potential form -void SphericalPotential::setPotential(const InteractionPotential &potential) -{ - interactionPotential_ = potential; - potentialFunction_.setFormAndParameters(interactionPotential_.form(), interactionPotential_.parameters()); -} - -// Set coordinate origin of potential -void SphericalPotential::setOrigin(const Vector3 &origin) { origin_ = origin; } - -// Return functional form of the potential, as a string -const std::string SphericalPotential::formString() const { return Functions1D::forms().keyword(interactionPotential_.form()); } - -// Return parameters of the potential, as a string -const std::string SphericalPotential::formParametersString() const { return interactionPotential_.parametersAsString(); } - -/* - * Potential Calculation - */ - -// Calculate energy on specified atom -double SphericalPotential::energy(const ConfigurationAtom &i, const Box &box) const -{ - return potentialFunction_.y(box.minimumDistanceSquared(i.r(), origin_)); -} - -// Calculate force on specified atom, summing in to supplied vector -void SphericalPotential::force(const ConfigurationAtom &i, const Box &box, Vector3 &f) const -{ - // Get normalised vector and distance - auto v = box.minimumVector(i.r(), origin_); - auto r = v.magAndNormalise(); - - f = v * -potentialFunction_.dYdX(r); -} diff --git a/src/kernels/potentials/spherical.h b/src/kernels/potentials/spherical.h deleted file mode 100644 index e291085c76..0000000000 --- a/src/kernels/potentials/spherical.h +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/interactionPotential.h" -#include "kernels/potentials/base.h" - -// Spherical Potential -class SphericalPotential : public ExternalPotential -{ - public: - SphericalPotential(const InteractionPotential &interactionPotential = {Functions1D::Form::Harmonic}, - const Vector3 &origin = {0.0, 0.0, 0.0}); - ~SphericalPotential() = default; - // Create and return a copy of this potential - std::unique_ptr duplicate() const override; - - /* - * Definition - */ - - private: - // Potential form - InteractionPotential interactionPotential_; - Function1DWrapper potentialFunction_; - // Coordinate origin of potential - Vector3 origin_; - - public: - // Set potential form - void setPotential(const InteractionPotential &potential); - // Set coordinate origin of potential - void setOrigin(const Vector3 &origin); - // Return functional form of the potential, as a string - const std::string formString() const override; - // Return parameters of the potential, as a string - const std::string formParametersString() const override; - - /* - * Potential Calculation - */ - public: - // Calculate energy on specified atom - double energy(const ConfigurationAtom &i, const Box &box) const override; - // Calculate force on specified atom, summing in to supplied vector - void force(const ConfigurationAtom &i, const Box &box, Vector3 &f) const override; -}; diff --git a/src/kernels/potentials/types.cpp b/src/kernels/potentials/types.cpp deleted file mode 100644 index da28214aa8..0000000000 --- a/src/kernels/potentials/types.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/potentials/types.h" - -// External Potential Types -namespace ExternalPotentialTypes -{ -// External Potential Types -EnumOptions types_("ExternalPotential", {{ExternalPotentialType::Spherical, "Spherical"}, - {ExternalPotentialType::Cylindrical, "Cylindrical"}, - {ExternalPotentialType::Regional, "Regional"}}); - -// Return whether the supplied external potential type is valid -std::optional isType(std::string_view name) -{ - if (types_.isValid(name)) - return types_.enumeration(name); - return {}; -} - -// Return whether the supplied external potential type is valid -std::string keyword(ExternalPotentialType type) { return types_.keyword(type); } -}; // namespace ExternalPotentialTypes diff --git a/src/kernels/potentials/types.h b/src/kernels/potentials/types.h deleted file mode 100644 index b3bd2afbbd..0000000000 --- a/src/kernels/potentials/types.h +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "base/enumOptions.h" -#include - -// External Potential Types -namespace ExternalPotentialTypes -{ -// External Potential Types -enum class ExternalPotentialType -{ - Spherical, - Cylindrical, - Regional -}; -// Return whether the supplied external potential type is valid -std::optional isType(std::string_view name); -// Return whether the supplied external potential type is valid -std::string keyword(ExternalPotentialType type); -}; // namespace ExternalPotentialTypes From 708d7fb93c5d49ef90449c892d7b86fa64558302 Mon Sep 17 00:00:00 2001 From: Tristan Youngs Date: Mon, 22 Jun 2026 16:41:10 +0100 Subject: [PATCH 2/5] More, but need to also rebase onto old I/O removal. --- src/classes/CMakeLists.txt | 1 - src/classes/configuration_io.cpp | 19 ----- src/classes/configuration_potentials.cpp | 52 ------------- src/gui/models/CMakeLists.txt | 1 - src/gui/models/externalPotentialModel.cpp | 93 ----------------------- src/gui/models/externalPotentialModel.h | 40 ---------- src/kernels/CMakeLists.txt | 4 - src/kernels/energy.h | 6 +- src/kernels/externalPotentials.cpp | 57 -------------- src/kernels/externalPotentials.h | 64 ---------------- src/kernels/force.h | 6 +- src/kernels/producer.cpp | 32 -------- src/kernels/producer.h | 28 ------- src/main/simulation.cpp | 1 - src/nodes/dissolve.cpp | 3 +- 15 files changed, 3 insertions(+), 404 deletions(-) delete mode 100644 src/classes/configuration_potentials.cpp delete mode 100644 src/gui/models/externalPotentialModel.cpp delete mode 100644 src/gui/models/externalPotentialModel.h delete mode 100644 src/kernels/externalPotentials.cpp delete mode 100644 src/kernels/externalPotentials.h delete mode 100644 src/kernels/producer.cpp delete mode 100644 src/kernels/producer.h diff --git a/src/classes/CMakeLists.txt b/src/classes/CMakeLists.txt index dd3c99d74d..a347ea261f 100644 --- a/src/classes/CMakeLists.txt +++ b/src/classes/CMakeLists.txt @@ -13,7 +13,6 @@ add_library( configuration_box.cpp configuration_contents.cpp configuration_io.cpp - configuration_potentials.cpp configuration_sites.cpp configuration_upkeep.cpp configurationAtom.cpp diff --git a/src/classes/configuration_io.cpp b/src/classes/configuration_io.cpp index 1ca0bd3851..a894684b05 100644 --- a/src/classes/configuration_io.cpp +++ b/src/classes/configuration_io.cpp @@ -8,7 +8,6 @@ #include "classes/coreData.h" #include "classes/pairPotential.h" #include "classes/species.h" -#include "kernels/potentials/producer.h" #include // Write through specified LineParser @@ -62,24 +61,6 @@ bool Configuration::serialise(LineParser &parser) const return false; } - // If there are no defined external potentials we are done - if (globalPotentials_.empty() && targetedPotentials_.empty()) - return true; - - // Write global potentials - if (!parser.writeLineF("{} # nGlobalPotentials\n", globalPotentials_.size())) - return false; - for (auto &pot : globalPotentials_) - if (!pot->serialise(parser, "")) - return false; - - // Write targeted potentials - if (!parser.writeLineF("{} # nTargetedPotentials\n", targetedPotentials_.size())) - return false; - for (auto &pot : targetedPotentials_) - if (!pot->serialise(parser, "")) - return false; - return true; } diff --git a/src/classes/configuration_potentials.cpp b/src/classes/configuration_potentials.cpp deleted file mode 100644 index 23d9ee743b..0000000000 --- a/src/classes/configuration_potentials.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "classes/configuration.h" -#include "kernels/potentials/base.h" - -// Add global potential -void Configuration::addGlobalPotential(std::unique_ptr potential) -{ - globalPotentials_.emplace_back(std::move(potential)); -} - -// Return vector of defined global potentials -const std::vector> &Configuration::globalPotentials() const { return globalPotentials_; } - -// Add targeted potential -void Configuration::addTargetedPotential(std::unique_ptr potential) -{ - targetedPotentials_.emplace_back(std::move(potential)); -} - -// Return vector of defined targeted potentials -const std::vector> &Configuration::targetedPotentials() const { return targetedPotentials_; } - -// Link targeted potentials to atoms -void Configuration::linkTargetedPotentials() -{ - // Clear any existing targeted potentials from atoms - std::for_each(atoms_.begin(), atoms_.end(), [](auto &atom) { atom.clearTargetedPotentials(); }); - - for (const auto &pot : targetedPotentials_) - { - // Individual atoms - for (auto i : pot->targetAtomIndices()) - atoms_[i].addTargetedPotential(pot.get()); - - // Atom types - for (const auto &at : pot->targetAtomTypes()) - for (auto &atom : atoms_) - if (atom.speciesAtom()->atomType() == at) - atom.addTargetedPotential(pot.get()); - - // Species - for (const auto &sp : pot->targetSpecies()) - { - for (auto &mol : molecules_) - if (mol->species() == sp) - std::for_each(mol->atoms().begin(), mol->atoms().end(), - [&pot](auto &atom) { atom->addTargetedPotential(pot.get()); }); - } - } -} diff --git a/src/gui/models/CMakeLists.txt b/src/gui/models/CMakeLists.txt index 4c21c6c8ba..7a4ca21827 100644 --- a/src/gui/models/CMakeLists.txt +++ b/src/gui/models/CMakeLists.txt @@ -55,7 +55,6 @@ set(models_SRCS dissolveModel.cpp dissolveModelImageProvider.cpp dissolveModelImageProvider.h - externalPotentialModel.cpp ffSortFilterModel.cpp forcefieldModel.cpp globalPotentialFilterProxy.cpp diff --git a/src/gui/models/externalPotentialModel.cpp b/src/gui/models/externalPotentialModel.cpp deleted file mode 100644 index 355c675d5b..0000000000 --- a/src/gui/models/externalPotentialModel.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/models/externalPotentialModel.h" -#include "kernels/potentials/cylindrical.h" - -ExternalPotentialModel::ExternalPotentialModel(const std::vector> &externalPotentials) - : externalPotentials_(externalPotentials) -{ -} - -int ExternalPotentialModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return externalPotentials_.size(); -} - -int ExternalPotentialModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return 4; -} - -const ExternalPotential *ExternalPotentialModel::rawData(const QModelIndex index) const -{ - return externalPotentials_[index.row()].get(); -} - -ExternalPotential *ExternalPotentialModel::rawData(const QModelIndex index) { return externalPotentials_[index.row()].get(); } - -QVariant ExternalPotentialModel::data(const QModelIndex &index, int role) const -{ - auto *p = rawData(index); - if (!p) - return {}; - - if (role == Qt::DisplayRole || role == Qt::EditRole) - { - switch (index.column()) - { - // Type - case (0): - return QString::fromStdString(keyword(p->type())); - // Functional form - case (1): - return QString::fromStdString(p->formString()); - // Parameters - case (2): - return QString::fromStdString(p->formParametersString()); - // Target atom indices - case (3): - return QString::fromStdString(joinStrings(p->targetAtomIndices(), " ", [](const auto i) { return i + 1; })); - default: - return {}; - } - } - else if (role == Qt::UserRole) - return QVariant::fromValue(p); - - return {}; -} - -Qt::ItemFlags ExternalPotentialModel::flags(const QModelIndex &index) const { return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } - -QVariant ExternalPotentialModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role != Qt::DisplayRole) - return {}; - - if (orientation == Qt::Horizontal) - switch (section) - { - case (0): - return "Type"; - case (1): - return "Form"; - case (2): - return "Parameters"; - case (3): - return "Targets"; - default: - return {}; - } - - return {}; -} - -// Set source AtomType data -void ExternalPotentialModel::reset() -{ - beginResetModel(); - endResetModel(); -} diff --git a/src/gui/models/externalPotentialModel.h b/src/gui/models/externalPotentialModel.h deleted file mode 100644 index 67cd1dacb9..0000000000 --- a/src/gui/models/externalPotentialModel.h +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/interactionPotential.h" -#include "kernels/potentials/base.h" -#include -#include -#include - -#include - -class ExternalPotentialModel : public QAbstractListModel -{ - Q_OBJECT - - private: - // Source AtomType data - const std::vector> &externalPotentials_; - - public: - // Set source AtomType data - ExternalPotentialModel(const std::vector> &externalPotentials); - ~ExternalPotentialModel() = default; - const ExternalPotential *rawData(const QModelIndex index) const; - ExternalPotential *rawData(const QModelIndex index); - // Update the table contents - void reset(); - - /* - * QAbstractItemModel overrides - */ - public: - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; -}; diff --git a/src/kernels/CMakeLists.txt b/src/kernels/CMakeLists.txt index bc497d027d..dcf10b12e1 100644 --- a/src/kernels/CMakeLists.txt +++ b/src/kernels/CMakeLists.txt @@ -2,18 +2,14 @@ add_library( kernels base.cpp energy.cpp - externalPotentials.cpp force.cpp geometry.cpp - producer.cpp species.cpp base.h common.h energy.h - externalPotentials.h force.h geometry.h - producer.h species.h ) diff --git a/src/kernels/energy.h b/src/kernels/energy.h index 96bf9ffeb1..d1496f3fe1 100644 --- a/src/kernels/energy.h +++ b/src/kernels/energy.h @@ -16,12 +16,8 @@ class Molecule; // Standard Energy Kernel, inheriting GeometryKernel class EnergyKernel : public GeometryKernel { - private: - friend class KernelProducer; - friend class ExternalPotentialsEnergyKernel; - EnergyKernel(const Configuration *cfg, const PotentialMap &potentialMap); - public: + EnergyKernel(const Configuration *cfg, const PotentialMap &potentialMap); ~EnergyKernel() = default; private: diff --git a/src/kernels/externalPotentials.cpp b/src/kernels/externalPotentials.cpp deleted file mode 100644 index f970570021..0000000000 --- a/src/kernels/externalPotentials.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/externalPotentials.h" -#include "classes/configuration.h" -#include - -/* - * Energy - */ - -ExternalPotentialsEnergyKernel::ExternalPotentialsEnergyKernel(const Configuration *cfg, const PotentialMap &potentialMap) - : EnergyKernel(cfg, potentialMap), globalPotentials_(cfg->globalPotentials()) -{ -} - -// Return external energy of supplied atom -double ExternalPotentialsEnergyKernel::extendedEnergy(const ConfigurationAtom &i) const -{ - return std::accumulate(globalPotentials_.begin(), globalPotentials_.end(), 0.0, - [&](const auto acc, const auto &pot) { return acc + pot->energy(i, box_); }) + - std::accumulate(i.targetedPotentials().begin(), i.targetedPotentials().end(), 0.0, - [&](const auto acc, const auto &pot) { return acc + pot->energy(i, box_); }); -} - -// Return external energy of supplied molecule -double ExternalPotentialsEnergyKernel::extendedEnergy(const Molecule &mol) const -{ - return std::accumulate(mol.atoms().begin(), mol.atoms().end(), 0.0, - [&](const auto acc, const auto &i) { return acc + extendedEnergy(*i); }); -} - -/* - * Force - */ - -ExternalPotentialsForceKernel::ExternalPotentialsForceKernel(const Configuration *cfg, const PotentialMap &potentialMap) - : ForceKernel(cfg, potentialMap), globalPotentials_(cfg->globalPotentials()) -{ -} - -// Calculate extended forces on supplied atom -void ExternalPotentialsForceKernel::extendedForces(const ConfigurationAtom &i, Vector3 &fVec) const -{ - for (const auto &pot : globalPotentials_) - pot->force(i, box_, fVec); - for (const auto &pot : i.targetedPotentials()) - pot->force(i, box_, fVec); -} - -// Calculate extended forces on supplied molecule -void ExternalPotentialsForceKernel::extendedForces(const Molecule &mol, std::vector &f) const -{ - auto offset = mol.globalAtomOffset(); - for (const auto &i : mol.atoms()) - extendedForces(*i, f[offset++]); -} diff --git a/src/kernels/externalPotentials.h b/src/kernels/externalPotentials.h deleted file mode 100644 index afe548eda9..0000000000 --- a/src/kernels/externalPotentials.h +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "kernels/energy.h" -#include "kernels/force.h" - -// Forward Declarations -class ExternalPotential; - -// Energy Kernel with External Potentials -class ExternalPotentialsEnergyKernel : public EnergyKernel -{ - private: - friend class KernelProducer; - ExternalPotentialsEnergyKernel(const Configuration *cfg, const PotentialMap &potentialMap); - - public: - ~ExternalPotentialsEnergyKernel() = default; - - /* - * Source External Potentials - */ - private: - // Global potentials acting on all atoms - const std::vector> &globalPotentials_; - - /* - * Extended Terms - */ - private: - // Return extended energy of supplied atom - double extendedEnergy(const ConfigurationAtom &i) const override; - // Return extended energy of supplied molecule - double extendedEnergy(const Molecule &mol) const override; -}; - -// Force Kernel with External Potentials -class ExternalPotentialsForceKernel : public ForceKernel -{ - private: - friend class KernelProducer; - ExternalPotentialsForceKernel(const Configuration *cfg, const PotentialMap &potentialMap); - - public: - ~ExternalPotentialsForceKernel() = default; - - /* - * Source External Potentials - */ - private: - // Global potentials acting on all atoms - const std::vector> &globalPotentials_; - - /* - * Extended Terms - */ - private: - // Calculate extended forces on supplied atom - void extendedForces(const ConfigurationAtom &i, Vector3 &fVec) const override; - // Calculate extended forces on supplied molecule - void extendedForces(const Molecule &mol, std::vector &f) const override; -}; diff --git a/src/kernels/force.h b/src/kernels/force.h index 08849ca1dc..5ad7d499ce 100644 --- a/src/kernels/force.h +++ b/src/kernels/force.h @@ -17,12 +17,8 @@ class PotentialMap; // ForceKernel class ForceKernel : public GeometryKernel { - private: - friend class KernelProducer; - friend class ExternalPotentialsForceKernel; - ForceKernel(const Configuration *cfg, const PotentialMap &potentialMap); - public: + ForceKernel(const Configuration *cfg, const PotentialMap &potentialMap); ~ForceKernel() = default; private: diff --git a/src/kernels/producer.cpp b/src/kernels/producer.cpp deleted file mode 100644 index 3873b68867..0000000000 --- a/src/kernels/producer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "kernels/producer.h" -#include "classes/configuration.h" -#include "kernels/energy.h" -#include "kernels/externalPotentials.h" -#include "kernels/force.h" - -// Create energy kernel for specified configuration -std::unique_ptr KernelProducer::energyKernel(const Configuration *cfg, const PotentialMap &potentialMap) -{ - if (!cfg->globalPotentials().empty() || !cfg->targetedPotentials().empty()) - return std::unique_ptr(new ExternalPotentialsEnergyKernel(cfg, potentialMap)); - else - return std::unique_ptr(new EnergyKernel(cfg, potentialMap)); -} - -// Create force kernel for specified configuration -std::unique_ptr KernelProducer::forceKernel(const Configuration *cfg, const PotentialMap &potentialMap) -{ - if (!cfg->globalPotentials().empty() || !cfg->targetedPotentials().empty()) - return std::unique_ptr(new ExternalPotentialsForceKernel(cfg, potentialMap)); - else - return std::unique_ptr(new ForceKernel(cfg, potentialMap)); -} - -// Create species kernel -std::unique_ptr KernelProducer::speciesKernel(const Species *sp, const PotentialMap &potentialMap) -{ - return std::unique_ptr(new SpeciesKernel(sp, potentialMap)); -} diff --git a/src/kernels/producer.h b/src/kernels/producer.h deleted file mode 100644 index be5b338667..0000000000 --- a/src/kernels/producer.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "kernels/energy.h" -#include "kernels/force.h" -#include "kernels/species.h" -#include - -// Forward Declarations -class Configuration; -class PotentialMap; -class ProcessPool; - -// Kernel Factory -class KernelProducer -{ - public: - // Create energy kernel for specified configuration - static std::unique_ptr energyKernel(const Configuration *cfg, const PotentialMap &potentialMap); - // Create force kernel for specified configuration - static std::unique_ptr forceKernel(const Configuration *cfg, const PotentialMap &potentialMap); - // Create force kernel using the specified Box - static std::unique_ptr forceKernel(const Box *box, const PotentialMap &potentialMap); - // Create species kernel - static std::unique_ptr speciesKernel(const Species *sp, const PotentialMap &potentialMap); -}; diff --git a/src/main/simulation.cpp b/src/main/simulation.cpp index 2403bf9666..6d8c89485e 100644 --- a/src/main/simulation.cpp +++ b/src/main/simulation.cpp @@ -4,7 +4,6 @@ #include "base/lineParser.h" #include "base/sysFunc.h" #include "classes/species.h" -#include "kernels/producer.h" #include "main/dissolve.h" #include diff --git a/src/nodes/dissolve.cpp b/src/nodes/dissolve.cpp index 17f4de01cd..bed5a0d9cf 100644 --- a/src/nodes/dissolve.cpp +++ b/src/nodes/dissolve.cpp @@ -2,7 +2,6 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/dissolve.h" -#include "kernels/producer.h" DissolveGraph::DissolveGraph() : Graph(nullptr) {} @@ -143,7 +142,7 @@ std::unique_ptr DissolveGraph::createEnergyKernel(Configuration *c [&](int i, const auto &atI, int j, const auto &atJ) { updatePairPotential(*atI, *atJ); }); // Generate and return kernel - return KernelProducer::energyKernel(cfg, PotentialMap(atomTypes, pairPotentials_)); + return std::make_unique(cfg, PotentialMap(atomTypes, pairPotentials_)); } // Create a force kernel suitable for the supplied Configuration From bf7bcc847bf1fc2ca46ab98b4f8d9adc0679cc9a Mon Sep 17 00:00:00 2001 From: Tristan Youngs Date: Tue, 23 Jun 2026 09:18:30 +0100 Subject: [PATCH 3/5] More. --- src/classes/configurationAtom.cpp | 16 ------ src/classes/configuration_contents.cpp | 2 - src/classes/configuration_io.cpp | 72 -------------------------- src/nodes/dissolve.cpp | 1 + src/nodes/insert.cpp | 5 +- src/nodes/intraAngle.h | 1 + 6 files changed, 4 insertions(+), 93 deletions(-) diff --git a/src/classes/configurationAtom.cpp b/src/classes/configurationAtom.cpp index 6450164495..af4af168ca 100644 --- a/src/classes/configurationAtom.cpp +++ b/src/classes/configurationAtom.cpp @@ -42,19 +42,3 @@ SpeciesAtom::ScaledInteractionDefinition ConfigurationAtom::scaling(const Config return speciesAtom_->scaling(j->speciesAtom()); } - -/* - * Targeted Potentials - */ - -// Add targeted potential to this atom -void ConfigurationAtom::addTargetedPotential(const ExternalPotential *potential) -{ - targetedPotentials_.emplace_back(potential); -} - -// Clear all targeted potentials from this Atom -void ConfigurationAtom::clearTargetedPotentials() { targetedPotentials_.clear(); } - -// Return list of targeted potentials for this atom -const std::vector &ConfigurationAtom::targetedPotentials() const { return targetedPotentials_; } diff --git a/src/classes/configuration_contents.cpp b/src/classes/configuration_contents.cpp index bd8d856ba7..8e51f38b39 100644 --- a/src/classes/configuration_contents.cpp +++ b/src/classes/configuration_contents.cpp @@ -41,8 +41,6 @@ void Configuration::empty() atoms_.clear(); appliedSizeFactor_ = std::nullopt; speciesPopulations_.clear(); - globalPotentials_.clear(); - targetedPotentials_.clear(); cells_.clear(); ++version_; diff --git a/src/classes/configuration_io.cpp b/src/classes/configuration_io.cpp index a894684b05..83ec8e2e42 100644 --- a/src/classes/configuration_io.cpp +++ b/src/classes/configuration_io.cpp @@ -149,77 +149,5 @@ bool Configuration::deserialise(LineParser &parser, const CoreData &coreData, bo if (!hasPotentials) return true; - // Read in global potentials - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return false; - globalPotentials_.resize(parser.argi(0)); - for (auto &pot : globalPotentials_) - { - // First line contains potential type - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return false; - auto potentialType = ExternalPotentialTypes::isType(parser.argsv(0)); - if (!potentialType) - return Messenger::error("Unrecognised external potential type '{}' found in Configuration '{}' in restart file.\n", - parser.argsv(0), name()); - - // Create new external potential - pot = ExternalPotentialProducer::create(*potentialType); - if (!pot->deserialise(parser, coreData)) - return false; - } - - // Get atom types present in configuration - auto atomTypes = atomTypeVector(); - - // Read in targeted potentials - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return false; - targetedPotentials_.resize(parser.argi(0)); - for (auto &pot : targetedPotentials_) - { - // First line contains potential type - if (parser.getArgsDelim(LineParser::Defaults) != LineParser::Success) - return false; - auto potentialType = ExternalPotentialTypes::isType(parser.argsv(0)); - if (!potentialType) - return Messenger::error("Unrecognised external potential type '{}' found in Configuration '{}' in restart file.\n", - parser.argsv(0), name()); - - // Create new external potential - pot = ExternalPotentialProducer::create(*potentialType); - - // Additional arguments after the potential type correspond to targets for the potential - for (auto n = 1; n < parser.nArgs(); ++n) - { - // Plain number - corresponds to a specific atom in the configuration - if (DissolveSys::isNumber(parser.args(n))) - { - auto i = parser.argi(n); - if (i < 0 || i >= atoms_.size()) - Messenger::exception("Atom index {} for targeted potential is out of range.\n", i); - pot->addTargetAtomIndex(i); - } - else if (std::ranges::find_if(atomTypes, [&](const auto at) - { return DissolveSys::sameString(at->name(), parser.args(n)); }) != atomTypes.end()) - { - auto it = std::ranges::find_if(atomTypes, [&](const auto at) - { return DissolveSys::sameString(at->name(), parser.args(n)); }); - pot->addTargetAtomType(*it); - } - else if (coreData.findSpecies(DissolveSys::niceName(parser.args(n)))) - pot->addTargetSpecies(coreData.findSpecies(DissolveSys::niceName(parser.args(n)))); - else - Messenger::exception("Unrecognised target '{}' for potential.\n", parser.args(n)); - } - - // Read in the rest of the potential - if (!pot->deserialise(parser, coreData)) - return false; - } - - // Link targeted potentials to atoms - linkTargetedPotentials(); - return true; } diff --git a/src/nodes/dissolve.cpp b/src/nodes/dissolve.cpp index bed5a0d9cf..d6d883efd2 100644 --- a/src/nodes/dissolve.cpp +++ b/src/nodes/dissolve.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "nodes/dissolve.h" +#include "classes/potentialMap.h" DissolveGraph::DissolveGraph() : Graph(nullptr) {} diff --git a/src/nodes/insert.cpp b/src/nodes/insert.cpp index b5b1075d0b..6460eacfb0 100644 --- a/src/nodes/insert.cpp +++ b/src/nodes/insert.cpp @@ -5,10 +5,9 @@ #include "classes/box.h" #include "classes/configuration.h" #include "classes/species.h" -#include "dissolve.h" -#include "kernels/externalPotentials.h" -#include "kernels/producer.h" +#include "kernels/energy.h" #include "math/mathFunc.h" +#include "nodes/dissolve.h" InsertNode::InsertNode(Graph *parentGraph) : Node(parentGraph) { diff --git a/src/nodes/intraAngle.h b/src/nodes/intraAngle.h index 8f3a996294..3fe34d1a7f 100644 --- a/src/nodes/intraAngle.h +++ b/src/nodes/intraAngle.h @@ -5,6 +5,7 @@ #include "classes/speciesSites.h" #include "math/histogram1D.h" +#include "math/range.h" #include "nodes/node.h" class IntraAngleNode : public Node From d0f6c4bc62f8d767f9ad28fd1336e76f83d4caf4 Mon Sep 17 00:00:00 2001 From: Tristan Youngs Date: Wed, 24 Jun 2026 14:12:24 +0100 Subject: [PATCH 4/5] Handle the rest. --- src/kernels/CMakeLists.txt | 1 - src/nodes/dissolve.cpp | 4 +++- src/nodes/orientedSDF.h | 1 + tests/classes/cells.cpp | 3 +-- tests/classes/cells3.cpp | 2 +- tests/classes/cells4.cpp | 1 - 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/CMakeLists.txt b/src/kernels/CMakeLists.txt index dcf10b12e1..e01af07ba9 100644 --- a/src/kernels/CMakeLists.txt +++ b/src/kernels/CMakeLists.txt @@ -15,4 +15,3 @@ add_library( target_include_directories(kernels PRIVATE ${PROJECT_SOURCE_DIR}/src) target_link_libraries(kernels PUBLIC base ${THREADING_LINK_LIBS}) - diff --git a/src/nodes/dissolve.cpp b/src/nodes/dissolve.cpp index d6d883efd2..59c640735e 100644 --- a/src/nodes/dissolve.cpp +++ b/src/nodes/dissolve.cpp @@ -3,6 +3,8 @@ #include "nodes/dissolve.h" #include "classes/potentialMap.h" +#include "kernels/energy.h" +#include "kernels/force.h" DissolveGraph::DissolveGraph() : Graph(nullptr) {} @@ -158,7 +160,7 @@ std::unique_ptr DissolveGraph::createForceKernel(Configuration *cfg [&](int i, const auto &atI, int j, const auto &atJ) { updatePairPotential(*atI, *atJ); }); // Generate and return kernel - return KernelProducer::forceKernel(cfg, PotentialMap(atomTypes, pairPotentials_)); + return std::make_unique(cfg, PotentialMap(atomTypes, pairPotentials_)); } /* diff --git a/src/nodes/orientedSDF.h b/src/nodes/orientedSDF.h index 0b1af2bc52..c4833885cd 100644 --- a/src/nodes/orientedSDF.h +++ b/src/nodes/orientedSDF.h @@ -5,6 +5,7 @@ #include "classes/speciesSites.h" #include "math/histogram3D.h" +#include "math/range.h" #include "nodes/node.h" // OrientedSDF diff --git a/tests/classes/cells.cpp b/tests/classes/cells.cpp index 4c17ad581e..788b490642 100644 --- a/tests/classes/cells.cpp +++ b/tests/classes/cells.cpp @@ -3,10 +3,9 @@ #include "classes/atomType.h" #include "classes/species.h" -#include "kernels/producer.h" +#include "kernels/energy.h" #include "main/dissolve.h" #include "math/mathFunc.h" -#include "templates/algorithms.h" #include "tests/graphData.h" #include diff --git a/tests/classes/cells3.cpp b/tests/classes/cells3.cpp index 4848fa5540..8908ed9a55 100644 --- a/tests/classes/cells3.cpp +++ b/tests/classes/cells3.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later // Copyright (c) 2026 Team Dissolve and contributors -#include "kernels/producer.h" +#include "kernels/energy.h" #include "templates/algorithms.h" #include "tests/graphData.h" #include diff --git a/tests/classes/cells4.cpp b/tests/classes/cells4.cpp index 6259c826bf..6742c039fb 100644 --- a/tests/classes/cells4.cpp +++ b/tests/classes/cells4.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later // Copyright (c) 2026 Team Dissolve and contributors -#include "kernels/producer.h" #include "tests/graphData.h" #include From 94f2a4ce016c44d58f94c839b8453be4ea82b5b5 Mon Sep 17 00:00:00 2001 From: Tristan Youngs Date: Wed, 24 Jun 2026 14:20:19 +0100 Subject: [PATCH 5/5] Remove SpeciesSite and Species keyword-based export functions. --- src/classes/CMakeLists.txt | 1 - src/classes/species.h | 34 -- src/classes/speciesSite.cpp | 231 +-------- src/classes/speciesSite.h | 30 +- src/classes/species_io.cpp | 958 ------------------------------------ 5 files changed, 6 insertions(+), 1248 deletions(-) delete mode 100644 src/classes/species_io.cpp diff --git a/src/classes/CMakeLists.txt b/src/classes/CMakeLists.txt index a347ea261f..b1da41bfee 100644 --- a/src/classes/CMakeLists.txt +++ b/src/classes/CMakeLists.txt @@ -48,7 +48,6 @@ add_library( species_atomic.cpp species_common.cpp species_intra.cpp - species_io.cpp species_isotopologues.cpp species_site.cpp species_transform.cpp diff --git a/src/classes/species.h b/src/classes/species.h index d7259fdce0..1c1cf3718f 100644 --- a/src/classes/species.h +++ b/src/classes/species.h @@ -304,40 +304,6 @@ class Species : public Serialisable<> * Serialisation */ public: - // Species Block Keyword Enum - enum class SpeciesKeyword - { - Angle, /* 'Angle' - Defines an Angle joining three atoms */ - Atom, /* 'Atom' - Specifies an Atom in the Species */ - Bond, /* 'Bond' - Defines a Bond joining two atoms */ - BondType, /* 'BondType' - Sets the type of a specific bond */ - BoxAngles, /* 'BoxAngles' - Specify unit cell angles for the species */ - BoxLengths, /* 'BoxLengths' - Specify unit cell lengths for the species */ - Charge, /* 'Charge' - Specifies the atomic charge for an individual atom */ - CommonAngle, /* 'CommonAngle' - Define a common angle (added for transition to Dissolve2) */ - CommonBond, /* 'CommonBond' - Define a common angle (added for transition to Dissolve2) */ - CommonImproper, /* 'CommonImproper' - Define a common angle (added for transition to Dissolve2) */ - CommonTorsion, /* 'CommonTorsion' - Define a common angle (added for transition to Dissolve2) */ - EndSpecies, /* 'EndSpecies' - Signals the end of the current Species */ - Forcefield, /* 'Forcefield' - Sets the Forcefield from which to (re)generate or set terms */ - Improper, /* 'Improper' - Define an Improper interaction between four atoms */ - Isotopologue, /* 'Isotopologue' - Add an isotopologue to the Species */ - NAngles, /* 'NAngles' - Hint at the total number of angles in the Species */ - NAtoms, /* 'NAtoms' - Hint at the total number of atoms in the Species */ - NBonds, /* 'NBonds' - Hint at the total number of bonds in the Species */ - NImpropers, /* 'NImpropers' - Hint at the total number of impropers in the Species */ - NTorsions, /* 'NTorsions' - Hint at the total number of torsions in the Species */ - Scaling14, /* 'Scaling14' - Specify 1-4 scaling factors for torsion terms */ - Site, /* 'Site' - Define an analysis site within the Species */ - Torsion /* 'Torsion' - Define a Torsion interaction between four atoms */ - }; - // Return enum option info for SpeciesKeyword - static EnumOptions keywords(); - // Read Species definition from specified LineParser - bool read(LineParser &parser, CoreData &coreData); - // Write Species definition to specified LineParser - bool write(LineParser &parser, std::string_view prefix); - // Express as a serialisable value void serialise(std::string tag, SerialisedValue &target) const override; // Read values from a serialisable value diff --git a/src/classes/speciesSite.cpp b/src/classes/speciesSite.cpp index bf1ecc11ac..262d1590bd 100644 --- a/src/classes/speciesSite.cpp +++ b/src/classes/speciesSite.cpp @@ -501,237 +501,9 @@ std::vector> SpeciesSite::createFromParent() const } /* - * Read / Write + * Serialisation */ -// Return enum option info for SiteKeyword -EnumOptions SpeciesSite::keywords() -{ - return EnumOptions("SiteKeyword", - {{SpeciesSite::AtomTypeKeyword, "AtomType", OptionArguments::OneOrMore}, - {SpeciesSite::DynamicKeyword, "Dynamic"}, - {SpeciesSite::ElementKeyword, "Element", OptionArguments::OneOrMore}, - {SpeciesSite::FragmentKeyword, "Fragment"}, - {SpeciesSite::DescriptionKeyword, "Description", 1}, - {SpeciesSite::EndSiteKeyword, "EndSite"}, - {SpeciesSite::OriginKeyword, "Origin", OptionArguments::OneOrMore}, - {SpeciesSite::OriginMassWeightedKeyword, "OriginMassWeighted", 1}, - {SpeciesSite::XAxisKeyword, "XAxis", OptionArguments::OneOrMore}, - {SpeciesSite::YAxisKeyword, "YAxis", OptionArguments::OneOrMore}}); -} - -// Read site definition from specified LineParser -bool SpeciesSite::read(LineParser &parser, const CoreData &coreData) -{ - Messenger::printVerbose("\nReading information for Site '{}'...\n", name()); - - auto blockDone = false, errorsEncountered = false; - - while (!parser.eofOrBlank()) - { - // Read in a line, which should contain a keyword and a minimum number of arguments - if (parser.getArgsDelim() != LineParser::Success) - return false; - - // Do we recognise this keyword and, if so, do we have an appropriate number of arguments? - if (!keywords().isValid(parser.argsv(0))) - { - keywords().errorAndPrintValid(parser.argsv(0)); - errorsEncountered = true; - continue; - } - auto kwd = keywords().enumeration(parser.argsv(0)); - if (!keywords().validNArgs(kwd, parser.nArgs() - 1)) - { - errorsEncountered = true; - continue; - } - - // All OK, so process the keyword - switch (kwd) - { - case (SpeciesSite::AtomTypeKeyword): - for (auto n = 1; n < parser.nArgs(); ++n) - { - auto at = parent_->findAtomType(parser.args(n)); - if (!at || !addDynamicAtomType(at)) - { - Messenger::error("Failed to add target atom type for site '{}'.\n", name()); - errorsEncountered = true; - break; - } - } - break; - case (SpeciesSite::DynamicKeyword): - if (staticOriginAtoms_.empty() && staticXAxisAtoms_.empty() && staticYAxisAtoms_.empty()) - type_ = SiteType::Dynamic; - else - { - Messenger::error( - "Can't set '{}' to be dynamic as origin, x-axis, or y-axis atoms have already been defined.\n", name()); - errorsEncountered = true; - } - break; - case (SpeciesSite::ElementKeyword): - for (auto n = 1; n < parser.nArgs(); ++n) - { - auto el = Elements::element(parser.args(n)); - if (el == Elements::Unknown || !addDynamicElement(el)) - { - Messenger::error("Failed to add target element for site '{}'.\n", name()); - errorsEncountered = true; - break; - } - } - break; - case (SpeciesSite::FragmentKeyword): - type_ = SiteType::Fragment; - break; - case (SpeciesSite::DescriptionKeyword): - if (!fragment_.create(parser.args(1))) - { - Messenger::error("Failed to parse NETA description for site '{}'.\n", name()); - errorsEncountered = true; - } - break; - case (SpeciesSite::EndSiteKeyword): - if (type_ == SiteType::Fragment || type_ == SiteType::Dynamic) - { - if (!generateInstances()) - { - Messenger::error("Failed to generate unique sites for site '{}'.\n", name()); - errorsEncountered = true; - } - } - Messenger::print("Found end of Site '{}'.\n", name()); - blockDone = true; - break; - case (SpeciesSite::OriginKeyword): - for (auto n = 1; n < parser.nArgs(); ++n) - { - if (!addStaticOriginAtom(parser.argi(n) - 1)) - { - Messenger::error("Failed to add origin atom for site '{}'.\n", name()); - errorsEncountered = true; - break; - } - } - break; - case (SpeciesSite::OriginMassWeightedKeyword): - setOriginMassWeighted(parser.argb(1)); - break; - case (SpeciesSite::XAxisKeyword): - for (int n = 1; n < parser.nArgs(); ++n) - { - if (!addStaticXAxisAtom(parser.argi(n) - 1)) - { - Messenger::error("Failed to add x-axis atom for site '{}'.\n", name()); - errorsEncountered = true; - break; - } - } - break; - case (SpeciesSite::YAxisKeyword): - for (int n = 1; n < parser.nArgs(); ++n) - { - if (!addStaticYAxisAtom(parser.argi(n) - 1)) - { - Messenger::error("Failed to add y-axis atom for site '{}'.\n", name()); - errorsEncountered = true; - break; - } - } - break; - default: - Messenger::error("Site block keyword '{}' not accounted for.\n", keywords().keyword(kwd)); - errorsEncountered = true; - break; - } - - // Error encountered? - if (errorsEncountered) - break; - - // End of block? - if (blockDone) - break; - } - - // If there's no errorsEncountered and the blockDone flag isn't set, return an errorsEncountered - if (!errorsEncountered && !blockDone) - { - Messenger::error("Unterminated Site block found.\n"); - errorsEncountered = true; - } - - return (!errorsEncountered); -} - -// Write site definition to specified LineParser -bool SpeciesSite::write(LineParser &parser, std::string_view prefix) -{ - // Write start of site definition - if (!parser.writeLineF("{}Site '{}'\n", prefix, name())) - return false; - - // Site type - if (type_ == SiteType::Dynamic) - { - if (!parser.writeLineF("{} {}\n", prefix, keywords().keyword(DynamicKeyword))) - return false; - } - else if (type_ == SiteType::Fragment) - { - if (!parser.writeLineF("{} {}\n", prefix, keywords().keyword(FragmentKeyword))) - return false; - } - - // Origin atom indices - if (!staticOriginAtoms_.empty() && - !parser.writeLineF("{} {} {}\n", prefix, keywords().keyword(OriginKeyword), - joinStrings(staticOriginAtomIndices(), " ", [](const auto i) { return i + 1; }))) - return false; - - // Origin mass weighted? - if (originMassWeighted_ && (!parser.writeLineF("{} {} True\n", prefix, keywords().keyword(OriginMassWeightedKeyword)))) - return false; - - // X-Axis atom indices - if (!staticXAxisAtoms_.empty() && - !parser.writeLineF("{} {} {}\n", prefix, keywords().keyword(XAxisKeyword), - joinStrings(staticXAxisAtomIndices(), " ", [](const auto i) { return i + 1; }))) - return false; - - // Y-Axis atom indices - if (!staticYAxisAtoms_.empty() && - !parser.writeLineF("{} {} {}\n", prefix, keywords().keyword(YAxisKeyword), - joinStrings(staticYAxisAtomIndices(), " ", [](const auto i) { return i + 1; }))) - return false; - - // Elements - if (!dynamicElements_.empty() && - !parser.writeLineF("{} {} {}\n", prefix, keywords().keyword(ElementKeyword), - joinStrings(dynamicElements_, " ", [](const auto el) { return Elements::symbol(el); }))) - return false; - - // Atom Types - if (!dynamicAtomTypes_.empty() && - !parser.writeLineF("{} {} {}\n", prefix, keywords().keyword(AtomTypeKeyword), - joinStrings(dynamicAtomTypes_, " ", [](const auto &at) { return at->name(); }))) - return false; - - // Fragment definition string - if (!fragment_.definitionString().empty() && - !parser.writeLineF("{} {} \"{}\"\n", prefix, keywords().keyword(DescriptionKeyword), fragment_.definitionString())) - return false; - - // Write end of site definition - if (!parser.writeLineF("{}{}\n", prefix, keywords().keyword(EndSiteKeyword))) - return false; - - return true; -} - // Express as a serialisable value void SpeciesSite::serialise(std::string tag, SerialisedValue &target) const { @@ -759,6 +531,7 @@ void SpeciesSite::serialise(std::string tag, SerialisedValue &target) const } } +// Read values from a serialisable value void SpeciesSite::deserialise(const SerialisedValue &node) { type_ = siteTypes().deserialise(toml::find_or(node, "type", "static")); diff --git a/src/classes/speciesSite.h b/src/classes/speciesSite.h index cfe31d18f3..f80a0f0def 100644 --- a/src/classes/speciesSite.h +++ b/src/classes/speciesSite.h @@ -181,35 +181,13 @@ class SpeciesSite : public Serialisable<> const std::vector &instances() const; /* - * Read / Write + * Serialisation */ public: - // Site Block Keyword Enum - enum SiteKeyword - { - AtomTypeKeyword, /* 'AtomType' - Specify allowed atom type(s) for dynamic sites */ - DynamicKeyword, /* 'Dynamic' - States that this is a dynamic site */ - ElementKeyword, /* 'Element' - Specify allowed element(s) for dynamic sites */ - FragmentKeyword, /* 'Fragment' - States that this is a fragment site */ - DescriptionKeyword, /* 'Description' - Defines the NETA description for fragment sites */ - EndSiteKeyword, /* 'EndSite' - Signals the end of the Site */ - OriginKeyword, /* 'Origin' - Set the atom indices whose average coordinates reflect the site origin */ - OriginMassWeightedKeyword, /* 'OriginMassWeighted' - Control whether the origin should be calculated with - mass-weighted coordinates */ - XAxisKeyword, /* 'XAxis' - Define one or more atoms whose average coordinates reflect the direction of the x - axis */ - YAxisKeyword /* 'YAxis' - Define one or more atoms whose average coordinates reflect the direction of the y - axis */ - }; - // Return enum option info for SiteKeyword - static EnumOptions keywords(); - // Read site definition from specified LineParser - bool read(LineParser &parser, const CoreData &coreData); - // Write site definition to specified LineParser - bool write(LineParser &parser, std::string_view prefix); - + // Express as a serialisable value void serialise(std::string tag, SerialisedValue &target) const override; - void deserialise(const SerialisedValue &node) override; + // Read values from a serialisable value + void deserialise(const SerialisedValue &node); }; template <> struct Context diff --git a/src/classes/species_io.cpp b/src/classes/species_io.cpp deleted file mode 100644 index c158678747..0000000000 --- a/src/classes/species_io.cpp +++ /dev/null @@ -1,958 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "base/lineParser.h" -#include "base/sysFunc.h" -#include "classes/atomType.h" -#include "classes/coreData.h" -#include "classes/species.h" -#include "data/elements.h" -#include "data/ff/library.h" -#include "data/isotopes.h" -#include - -/* - * Read / Write - */ - -// Return enum option info for SpeciesKeyword -EnumOptions Species::keywords() -{ - return EnumOptions( - "SpeciesKeyword", {{Species::SpeciesKeyword::Angle, "Angle", 3, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::Atom, "Atom", 6, 7}, - {Species::SpeciesKeyword::Bond, "Bond", 2, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::BondType, "BondType", 3}, - {Species::SpeciesKeyword::BoxAngles, "BoxAngles", 3}, - {Species::SpeciesKeyword::BoxLengths, "BoxLengths", 3}, - {Species::SpeciesKeyword::Charge, "Charge", 2}, - {Species::SpeciesKeyword::CommonAngle, "CommonAngle", 2, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::CommonBond, "CommonBond", 2, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::CommonImproper, "CommonImproper", 2, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::CommonTorsion, "CommonTorsion", 2, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::EndSpecies, "EndSpecies"}, - {Species::SpeciesKeyword::Forcefield, "Forcefield", 1}, - {Species::SpeciesKeyword::Improper, "Improper", 5, OptionArguments::AnyNumber}, - {Species::SpeciesKeyword::Isotopologue, "Isotopologue", OptionArguments::OneOrMore}, - {Species::SpeciesKeyword::NAngles, "NAngles", 1}, - {Species::SpeciesKeyword::NAtoms, "NAtoms", 1}, - {Species::SpeciesKeyword::NBonds, "NBonds", 1}, - {Species::SpeciesKeyword::NImpropers, "NImpropers", 1}, - {Species::SpeciesKeyword::NTorsions, "NTorsions", 1}, - {Species::SpeciesKeyword::Scaling14, "Scaling14", 2, 2}, - {Species::SpeciesKeyword::Site, "Site", 1}, - {Species::SpeciesKeyword::Torsion, "Torsion", 4, OptionArguments::AnyNumber}}); -} - -// Read Species definition from specified LineParser -bool Species::read(LineParser &parser, CoreData &coreData) -{ - Messenger::print("\nParsing Species '{}'\n", name()); - - Elements::Element Z; - const AtomType *at; - Isotopologue *iso; - OptionalReferenceWrapper a; - OptionalReferenceWrapper b; - OptionalReferenceWrapper imp; - OptionalReferenceWrapper torsion; - SpeciesSite *site; - BondFunctions::Form bf; - AngleFunctions::Form af; - TorsionFunctions::Form tf; - Vector3 boxAngles(90.0, 90.0, 90.0); - std::optional boxLengths; - auto elec14Scaling = 0.5, vdw14Scaling = 0.5; - auto blockDone = false, errorsEncountered = false; - auto atomVectorFixed = false, bondVectorFixed = false, angleVectorFixed = false, torsionVectorFixed = false, - improperVectorFixed = false; - auto atomIndex = 0, bondIndex = 0, angleIndex = 0, torsionIndex = 0, improperIndex = 0; - - while (!parser.eofOrBlank()) - { - // Read in a line, which should contain a keyword and a minimum number of arguments - if (parser.getArgsDelim() != LineParser::Success) - return false; - - // Do we recognise this keyword and, if so, do we have an appropriate number of arguments? - if (!keywords().isValid(parser.argsv(0))) - { - keywords().errorAndPrintValid(parser.argsv(0)); - errorsEncountered = true; - continue; - } - auto kwd = keywords().enumeration(parser.argsv(0)); - if (!keywords().validNArgs(kwd, parser.nArgs() - 1)) - { - errorsEncountered = true; - continue; - } - - // All OK, so process the keyword - switch (kwd) - { - case (Species::SpeciesKeyword::Angle): - // Create a new angle definition between the specified atoms - if (angleVectorFixed && angleIndex < angles_.size()) - { - if (getAngle(&atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], &atoms_[parser.argi(3) - 1])) - return false; - angles_[angleIndex] = SpeciesAngle(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], - &atoms_[parser.argi(3) - 1]); - a = angles_[angleIndex++]; - } - else - a = angles_.emplace_back(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], - &atoms_[parser.argi(3) - 1]); - - /* - * If only the indices were given, create an angle without a specified functional form (a - * Forcefield is presumably going to be specified). Otherwise, check the functional form - * specified - if it starts with - * '@' it is a reference to common parameters - */ - if (parser.nArgs() == 4) - a->get().setInteractionForm(AngleFunctions::Form::None); - else if (parser.argsv(4)[0] == '@') - { - // Search through common Angle parameters to see if this name exists - auto common = getCommonAngle(parser.argsv(4)); - if (!common) - { - Messenger::error("No common Angle parameters named '{}' exist.\n", &parser.argsv(4)[1]); - errorsEncountered = true; - break; - } - - a->get().setCommonTerm(&common->get()); - } - else - { - if (!AngleFunctions::forms().isValid(parser.argsv(4))) - { - Messenger::error("Functional form of Angle ({}) not recognised.\n", parser.argsv(4)); - errorsEncountered = true; - break; - } - af = AngleFunctions::forms().enumeration(parser.argsv(4)); - a->get().setInteractionForm(af); - - // Check number of args provided - if (!AngleFunctions::forms().validNArgs(af, parser.nArgs() - 5)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!a->get().setInteractionParameters(parser, 5)) - { - errorsEncountered = true; - break; - } - } - break; - case (Species::SpeciesKeyword::Atom): - Z = Elements::element(parser.argsv(2)); - if (Z == Elements::Unknown) - { - Messenger::error("Unrecognised element symbol '{}' found in {} keyword.\n", parser.argsv(2), - Species::keywords().keyword(Species::SpeciesKeyword::Atom)); - errorsEncountered = true; - break; - } - if (atomVectorFixed && atomIndex < atoms_.size()) - { - atoms_[atomIndex].set(Z, parser.arg3d(3), parser.hasArg(7) ? parser.argd(7) : 0.0); - atoms_[atomIndex].setIndex(atomIndex); - } - else - { - auto &i = atoms_.emplace_back(this); - i.set(Z, parser.arg3d(3), parser.hasArg(7) ? parser.argd(7) : 0.0); - i.setIndex(atoms_.size() - 1); - atomIndex = i.index(); - } - - // Locate the AtomType assigned to the Atom - if (DissolveSys::sameString("None", parser.argsv(6))) - at = nullptr; - else - { - at = findAtomType(parser.argsv(6)); - if (!at) - { - Messenger::printVerbose("Creating AtomType '{}'...\n", parser.argsv(6)); - at = addAtomType(Z, parser.argsv(6)); - } - } - - // Finally, set AtomType for the Atom - atoms_[atomIndex++].setAtomType(at); - break; - case (Species::SpeciesKeyword::Bond): - // Create a new bond definition between the specified atoms - if (bondVectorFixed && bondIndex < bonds_.size()) - { - if (getBond(&atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1])) - return false; - bonds_[bondIndex] = SpeciesBond(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1]); - b = bonds_[bondIndex++]; - } - else - { - auto i = parser.argi(1) - 1; - auto j = parser.argi(2) - 1; - // Check for existence of Bond already - auto bondRef = getBond(&atoms_[i], &atoms_[j]); - if (bondRef) - { - Messenger::warn("Refused to add a new SpeciesBond between atoms {} and {} in Species '{}' since it " - "already exists.\n", - i + 1, j + 1, name_); - b = *bondRef; - } - else - b = bonds_.emplace_back(this, &atom(i), &atom(j)); - } - - /* - * If only the indices were given, create a bond without a specified functional form (a - * Forcefield is presumably going to be specified). Otherwise, check the functional form - * specified - if it starts with - * '@' it is a reference to common parameters - */ - if (parser.nArgs() == 3) - b->get().setInteractionForm(BondFunctions::Form::None); - else if (parser.argsv(3)[0] == '@') - { - // Search through common Bond parameters to see if this name exists - auto common = getCommonBond(parser.argsv(3)); - if (!common) - { - Messenger::error("No common Bond parameters named '{}' exist.\n", &parser.argsv(3)[1]); - errorsEncountered = true; - break; - } - - b->get().setCommonTerm(&common->get()); - } - else - { - // Check the functional form specified - if (!BondFunctions::forms().isValid(parser.argsv(3))) - { - Messenger::error("Functional form of Bond ({}) not recognised.\n", parser.argsv(3)); - errorsEncountered = true; - break; - } - bf = BondFunctions::forms().enumeration(parser.argsv(3)); - b->get().setInteractionForm(bf); - - // Check number of args provided - if (!BondFunctions::forms().validNArgs(bf, parser.nArgs() - 4)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!b->get().setInteractionParameters(parser, 4)) - { - errorsEncountered = true; - break; - } - } - break; - case (Species::SpeciesKeyword::BondType): - // Find the specified bond - b = getBond(&atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1]); - if (!b) - { - Messenger::error("Tried to set the bond type of bond between atoms {} and {}, but this bond " - "does not exist.\n", - parser.argi(1), parser.argi(2)); - errorsEncountered = true; - break; - } - break; - case (Species::SpeciesKeyword::BoxAngles): - boxAngles = parser.arg3d(1); - break; - case (Species::SpeciesKeyword::BoxLengths): - boxLengths = parser.arg3d(1); - break; - case (Species::SpeciesKeyword::Charge): - { - auto index = parser.argi(1) - 1; - if (index >= nAtoms()) - { - Messenger::error("Specified Atom index ({}) for Charge keyword is out of range.\n", parser.argi(1)); - errorsEncountered = true; - } - auto &i = atom(index); - i.setQ(parser.argd(2)); - break; - } - case (Species::SpeciesKeyword::EndSpecies): - // Set periodic box? - if (boxLengths) - { - // Generate Box - box_ = Box::generate(*boxLengths, boxAngles); - - // Fold atoms - for (auto &i : atoms_) - i.setR(box_.fold(i.r())); - } - updateIsotopologues(); - Messenger::print("Found end of Species '{}'.\n", name()); - blockDone = true; - break; - case (Species::SpeciesKeyword::Forcefield): - Messenger::warn("The 'Forcefield' keyword has been removed.\n"); - break; - case (Species::SpeciesKeyword::Improper): - // Create a new improper definition - if (improperVectorFixed && improperIndex < impropers_.size()) - { - if (getImproper(&atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], &atoms_[parser.argi(3) - 1], - &atoms_[parser.argi(4) - 1])) - return false; - impropers_[improperIndex] = SpeciesImproper(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], - &atoms_[parser.argi(3) - 1], &atoms_[parser.argi(4) - 1]); - imp = impropers_[improperIndex++]; - } - else - imp = impropers_.emplace_back(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], - &atoms_[parser.argi(3) - 1], &atoms_[parser.argi(4) - 1]); - - // Check the functional form specified - if it starts with '@' it is a reference to common - // parameters - if (parser.argsv(5)[0] == '@') - { - // Search through common Improper parameters to see if this name exists - auto common = getCommonImproper(parser.argsv(5)); - if (!common) - { - Messenger::error("No common Improper parameters named '{}' exist.\n", &parser.argsv(5)[1]); - errorsEncountered = true; - break; - } - - imp->get().setCommonTerm(&common->get()); - } - else - { - // Check the functional form specified - if (!TorsionFunctions::forms().isValid(parser.argsv(5))) - { - Messenger::error("Functional form of Improper ({}) not recognised.\n", parser.argsv(5)); - errorsEncountered = true; - break; - } - tf = TorsionFunctions::forms().enumeration(parser.argsv(5)); - imp->get().setInteractionForm(tf); - - // Check number of args provided - if (!TorsionFunctions::forms().validNArgs(tf, parser.nArgs() - 6)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!imp->get().setInteractionParameters(parser, 6)) - { - errorsEncountered = true; - break; - } - } - break; - case (Species::SpeciesKeyword::Isotopologue): - iso = addIsotopologue(DissolveSys::uniqueName(DissolveSys::niceName(parser.argsv(1)), isotopologues_, - [](const auto &i) { return i->name(); })); - Messenger::printVerbose("Added Isotopologue '{}' to Species '{}'\n", iso->name(), name()); - // Each parser argument is a string of the form ATOMTYPE=ISO - for (auto n = 2; n < parser.nArgs(); ++n) - { - // Split argument into parts before and after '=' - std::string_view arg1 = DissolveSys::beforeChar(parser.argsv(n), '='); - std::string_view arg2 = DissolveSys::afterChar(parser.argsv(n), '='); - - at = findAtomType(arg1); - if (!at) - { - Messenger::error("Failed to find AtomType '{}', referred to in Isotopologue '{}', " - "Species '{}'\n", - arg1, iso->name(), name()); - errorsEncountered = true; - break; - } - - // Is the supplied isotope valid for the AtomType's element? - auto A = std::stoi(std::string(arg2)); - if (!Sears91::hasIsotope(at->Z(), A)) - { - Messenger::error("No such Isotope ({}) for element {} (AtomType '{}') in Isotopologue " - "'{}', Species '{}'\n", - A, Elements::symbol(at->Z()), at->name(), iso->name(), name()); - errorsEncountered = true; - break; - } - - // Assign isotope to AtomType - iso->setAtomTypeIsotope(at, Sears91::isotope(at->Z(), A)); - } - break; - case (Species::SpeciesKeyword::NAngles): - if (angleVectorFixed) - return Messenger::error("{} keyword can't be specified more than once.\n", - keywords().keyword(Species::SpeciesKeyword::NAngles)); - if (angleIndex != 0) - return Messenger::error("{} keyword must specified before the first angle definition.\n", - keywords().keyword(Species::SpeciesKeyword::NAngles)); - angleVectorFixed = true; - angles_.resize(parser.argi(1)); - break; - case (Species::SpeciesKeyword::NAtoms): - if (atomVectorFixed) - return Messenger::error("{} keyword can't be specified more than once.\n", - keywords().keyword(Species::SpeciesKeyword::NAtoms)); - if (atomIndex != 0) - return Messenger::error("{} keyword must specified before the first atom definition.\n", - keywords().keyword(Species::SpeciesKeyword::NAtoms)); - atomVectorFixed = true; - atoms_.clear(); - atoms_.reserve(parser.argi(1)); - for (auto i = 0; i < atoms_.size(); ++i) - atoms_.emplace_back(this).setIndex(i); - break; - case (Species::SpeciesKeyword::NBonds): - if (bondVectorFixed) - return Messenger::error("{} keyword can't be specified more than once.\n", - keywords().keyword(Species::SpeciesKeyword::NBonds)); - if (bondIndex != 0) - return Messenger::error("{} keyword must specified before the first bond definition.\n", - keywords().keyword(Species::SpeciesKeyword::NBonds)); - bondVectorFixed = true; - bonds_.resize(parser.argi(1)); - break; - case (Species::SpeciesKeyword::NImpropers): - if (improperVectorFixed) - return Messenger::error("{} keyword can't be specified more than once.\n", - keywords().keyword(Species::SpeciesKeyword::NImpropers)); - if (improperIndex != 0) - return Messenger::error("{} keyword must specified before the first improper definition.\n", - keywords().keyword(Species::SpeciesKeyword::NImpropers)); - improperVectorFixed = true; - impropers_.resize(parser.argi(1)); - break; - case (Species::SpeciesKeyword::NTorsions): - if (torsionVectorFixed) - return Messenger::error("{} keyword can't be specified more than once.\n", - keywords().keyword(Species::SpeciesKeyword::NTorsions)); - if (torsionIndex != 0) - return Messenger::error("{} keyword must specified before the first torsion definition.\n", - keywords().keyword(Species::SpeciesKeyword::NTorsions)); - torsionVectorFixed = true; - torsions_.resize(parser.argi(1)); - break; - case (Species::SpeciesKeyword::Scaling14): - elec14Scaling = parser.argd(1); - vdw14Scaling = parser.argd(2); - break; - case (Species::SpeciesKeyword::Site): - // First argument is the name of the site to create - make sure it doesn't exist already - site = findSite(DissolveSys::niceName(parser.argsv(1))); - if (site) - { - Messenger::error("The site '{}' already exists on Species '{}', and cannot be redefined.\n", - parser.argsv(1), name()); - errorsEncountered = true; - break; - } - - site = addSite(parser.argsv(1)); - if (!site->read(parser, coreData)) - errorsEncountered = true; - break; - case (Species::SpeciesKeyword::Torsion): - // Create a new angle definition between the specified atoms - if (torsionVectorFixed && torsionIndex < torsions_.size()) - { - if (getTorsion(&atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], &atoms_[parser.argi(3) - 1], - &atoms_[parser.argi(4) - 1])) - return false; - torsions_[torsionIndex] = SpeciesTorsion(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], - &atoms_[parser.argi(3) - 1], &atoms_[parser.argi(4) - 1]); - torsion = torsions_[torsionIndex++]; - } - else - torsion = torsions_.emplace_back(this, &atoms_[parser.argi(1) - 1], &atoms_[parser.argi(2) - 1], - &atoms_[parser.argi(3) - 1], &atoms_[parser.argi(4) - 1]); - - /* - * If only the indices were given, create an angle without a specified functional form (a - * Forcefield is presumably going to be specified). Otherwise, check the functional form - * specified - if it starts with - * '@' it is a reference to common parameters - */ - if (parser.nArgs() == 5) - torsion->get().setInteractionForm(TorsionFunctions::Form::None); - else if (parser.argsv(5)[0] == '@') - { - // Search through common Torsion parameters to see if this name exists - auto common = getCommonTorsion(parser.argsv(5)); - if (!common) - { - Messenger::error("No common Torsion parameters named '{}' exist.\n", &parser.argsv(5)[1]); - errorsEncountered = true; - break; - } - - torsion->get().setCommonTerm(&common->get()); - } - else - { - // Check the functional form specified - if (!TorsionFunctions::forms().isValid(parser.argsv(5))) - { - Messenger::error("Functional form of Torsion ({}) not recognised.\n", parser.argsv(5)); - errorsEncountered = true; - break; - } - tf = TorsionFunctions::forms().enumeration(parser.argsv(5)); - torsion->get().setInteractionForm(tf); - - // Check number of args provided - if (!TorsionFunctions::forms().validNArgs(tf, parser.nArgs() - 6)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!torsion->get().setInteractionParameters(parser, 6)) - { - errorsEncountered = true; - break; - } - - // Set 1-4 scale factors - torsion->get().set14ScalingFactors(elec14Scaling, vdw14Scaling); - } - break; - - case (Species::SpeciesKeyword::CommonAngle): - // Check the functional form specified - if (!AngleFunctions::forms().isValid(parser.argsv(2))) - { - Messenger::error("Functional form of angle ({}) not recognised.\n", parser.argsv(2)); - errorsEncountered = true; - break; - } - af = AngleFunctions::forms().enumeration(parser.argsv(2)); - - // Create a new common angle definition - try - { - auto &commonAngle = addCommonAngle(parser.argsv(1)); - commonAngle.setInteractionForm(af); - - // Check number of args provided - if (!AngleFunctions::forms().validNArgs(af, parser.nArgs() - 3)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!commonAngle.setInteractionParameters(parser, 3)) - { - errorsEncountered = true; - break; - } - - Messenger::printVerbose("Defined common angle term: {:<10} {:<12} {}\n", commonAngle.name(), - AngleFunctions::forms().keyword(commonAngle.interactionForm()), - commonAngle.interactionPotential().parametersAsString()); - } - catch (const std::runtime_error &e) - { - Messenger::error("{}", e.what()); - errorsEncountered = true; - } - break; - case (Species::SpeciesKeyword::CommonBond): - // Check the functional form specified - if (!BondFunctions::forms().isValid(parser.argsv(2))) - { - Messenger::error("Functional form of bond ({}) not recognised.\n", parser.argsv(2)); - errorsEncountered = true; - break; - } - bf = BondFunctions::forms().enumeration(parser.argsv(2)); - - // Create a new common bond definition - try - { - auto &commonBond = addCommonBond(parser.argsv(1)); - commonBond.setInteractionForm(bf); - - // Check number of args provided - if (!BondFunctions::forms().validNArgs(bf, parser.nArgs() - 3)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!commonBond.setInteractionParameters(parser, 3)) - { - errorsEncountered = true; - break; - } - - Messenger::printVerbose("Defined common bond term: {:<10} {:<12} {}\n", commonBond.name(), - BondFunctions::forms().keyword(commonBond.interactionForm()), - commonBond.interactionPotential().parametersAsString()); - } - catch (const std::runtime_error &e) - { - Messenger::error("{}", e.what()); - errorsEncountered = true; - } - break; - case (Species::SpeciesKeyword::CommonImproper): - // Check the functional form specified - if (!TorsionFunctions::forms().isValid(parser.argsv(2))) - { - Messenger::error("Functional form of improper ({}) not recognised.\n", parser.argsv(2)); - errorsEncountered = true; - break; - } - tf = TorsionFunctions::forms().enumeration(parser.argsv(2)); - - // Create a new common improper definition - try - { - auto &commonImproper = addCommonImproper(parser.argsv(1)); - commonImproper.setInteractionForm(tf); - - // Check number of args provided - if (!TorsionFunctions::forms().validNArgs(tf, parser.nArgs() - 3)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!commonImproper.setInteractionParameters(parser, 3)) - { - errorsEncountered = true; - break; - } - - Messenger::printVerbose("Defined common improper term: {:<10} {:<12} {}\n", commonImproper.name(), - TorsionFunctions::forms().keyword(commonImproper.interactionForm()), - commonImproper.interactionPotential().parametersAsString()); - } - catch (const std::runtime_error &e) - { - Messenger::error("{}", e.what()); - errorsEncountered = true; - } - break; - case (Species::SpeciesKeyword::CommonTorsion): - // Check the functional form specified - if (!TorsionFunctions::forms().isValid(parser.argsv(2))) - { - Messenger::error("Functional form of torsion ({}) not recognised.\n", parser.argsv(2)); - errorsEncountered = true; - break; - } - tf = TorsionFunctions::forms().enumeration(parser.argsv(2)); - - // Create a new common torsion definition - try - { - auto &commonTorsion = addCommonTorsion(parser.argsv(1)); - commonTorsion.setInteractionForm(tf); - - // Check number of args provided - if (!TorsionFunctions::forms().validNArgs(tf, parser.nArgs() - 3)) - { - errorsEncountered = true; - break; - } - - // Set parameters - if (!commonTorsion.setInteractionParameters(parser, 3)) - { - errorsEncountered = true; - break; - } - - // Set scaling factors - commonTorsion.set14ScalingFactors(elec14Scaling, vdw14Scaling); - - Messenger::printVerbose("Defined common torsion term: {:<10} {:<12} {}\n", commonTorsion.name(), - TorsionFunctions::forms().keyword(commonTorsion.interactionForm()), - commonTorsion.interactionPotential().parametersAsString()); - } - catch (const std::runtime_error &e) - { - Messenger::error("{}", e.what()); - errorsEncountered = true; - } - break; - default: - Messenger::error("Species block keyword '{}' not accounted for.\n", keywords().keyword(kwd)); - errorsEncountered = true; - break; - } - - // End of block? - if (blockDone) - break; - } - - // If there's no errorsEncountered and the blockDone flag isn't set, return an errorsEncountered - if (!errorsEncountered && !blockDone) - { - Messenger::error("Unterminated Species block found.\n"); - errorsEncountered = true; - } - - finaliseIntramolecularData(false); - - return (!errorsEncountered); -} - -// Write Species definition to specified LineParser -bool Species::write(LineParser &parser, std::string_view prefix) -{ - if (!parser.writeLineF("{}Species '{}'\n", prefix, name())) - return false; - - // Create new prefix - std::string newPrefix = std::format("{} ", prefix); - - // Atoms - if (!parser.writeLineF("{}# Atoms\n", newPrefix)) - return false; - if (!parser.writeLineF("{}{} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::NAtoms), atoms_.size())) - return false; - auto count = 0; - for (const auto &i : atoms_) - { - if (!parser.writeLineF("{}{} {:3d} {:3} {:12.6e} {:12.6e} {:12.6e} '{}' {:12.6e}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Atom), ++count, Elements::symbol(i.Z()), i.r().x, - i.r().y, i.r().z, i.atomType() == nullptr ? "None" : i.atomType()->name(), i.q())) - return false; - } - - // Write master terms - for (auto &b : commonBonds_) - if (!parser.writeLineF(" {} '{}' {} {}\n", keywords().keyword(SpeciesKeyword::CommonBond), b->name(), - BondFunctions::forms().keyword(b->interactionForm()), - b->interactionPotential().parametersAsString())) - return false; - - for (auto &a : commonAngles_) - if (!parser.writeLineF(" {} '{}' {} {}\n", keywords().keyword(SpeciesKeyword::CommonAngle), a->name(), - AngleFunctions::forms().keyword(a->interactionForm()), - a->interactionPotential().parametersAsString())) - return false; - - auto elec14Scaling = 0.5, vdw14Scaling = 0.5; - for (auto &t : commonTorsions_) - { - if (!parser.writeLineF(" {} '{}' {} {}\n", keywords().keyword(SpeciesKeyword::CommonTorsion), t->name(), - TorsionFunctions::forms().keyword(t->interactionForm()), - t->interactionPotential().parametersAsString())) - return false; - - elec14Scaling = t->electrostatic14Scaling(); - vdw14Scaling = t->vanDerWaals14Scaling(); - } - - for (auto &imp : commonImpropers_) - if (!parser.writeLineF(" {} '{}' {} {}\n", keywords().keyword(SpeciesKeyword::CommonImproper), imp->name(), - TorsionFunctions::forms().keyword(imp->interactionForm()), - imp->interactionPotential().parametersAsString())) - return false; - - // Bonds - if (!bonds_.empty()) - { - if (!parser.writeLineF("\n{}# Bonds\n", newPrefix)) - return false; - if (!parser.writeLineF("{}{} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::NBonds), bonds_.size())) - return false; - for (const auto &bond : bonds_) - { - if (bond.commonTerm()) - { - if (!parser.writeLineF("{}{} {:3d} {:3d} @{}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Bond), bond.i()->index() + 1, - bond.j()->index() + 1, bond.commonTerm()->name())) - return false; - } - else if (!parser.writeLineF("{}{} {:3d} {:3d} {} {}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Bond), bond.i()->index() + 1, - bond.j()->index() + 1, BondFunctions::forms().keyword(bond.interactionForm()), - bond.interactionPotential().parametersAsString())) - return false; - } - } - - // Angles - if (!angles_.empty()) - { - if (!parser.writeLineF("\n{}# Angles\n", newPrefix)) - return false; - if (!parser.writeLineF("{}{} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::NAngles), angles_.size())) - return false; - for (const auto &angle : angles()) - { - if (angle.commonTerm()) - { - if (!parser.writeLineF("{}{} {:3d} {:3d} {:3d} @{}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Angle), angle.i()->index() + 1, - angle.j()->index() + 1, angle.k()->index() + 1, angle.commonTerm()->name())) - return false; - } - else if (!parser.writeLineF("{}{} {:3d} {:3d} {:3d} {} {}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Angle), angle.i()->index() + 1, - angle.j()->index() + 1, angle.k()->index() + 1, - AngleFunctions::forms().keyword(angle.interactionForm()), - angle.interactionPotential().parametersAsString())) - return false; - } - } - - // Torsions - if (!torsions_.empty()) - { - if (!parser.writeLineF("\n{}# Torsions\n", newPrefix)) - return false; - if (!parser.writeLineF("{}{} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::NTorsions), - torsions_.size())) - return false; - - // Set default scaling factors - auto elec14Scaling = 0.5, vdw14Scaling = 0.5; - - for (const auto &torsion : torsions()) - { - if (torsion.commonTerm()) - { - if (!parser.writeLineF("{}{} {:3d} {:3d} {:3d} {:3d} @{}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Torsion), torsion.i()->index() + 1, - torsion.j()->index() + 1, torsion.k()->index() + 1, torsion.l()->index() + 1, - torsion.commonTerm()->name())) - return false; - } - else - { - // Write new 1-4 scale factor line if this torsion has different values - if ((torsion.electrostatic14Scaling() != elec14Scaling || torsion.vanDerWaals14Scaling() != vdw14Scaling) && - !parser.writeLineF("{}{} {} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::Scaling14), - torsion.electrostatic14Scaling(), torsion.vanDerWaals14Scaling())) - return false; - - if (!parser.writeLineF("{}{} {:3d} {:3d} {:3d} {:3d} {} {}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Torsion), torsion.i()->index() + 1, - torsion.j()->index() + 1, torsion.k()->index() + 1, torsion.l()->index() + 1, - TorsionFunctions::forms().keyword(torsion.interactionForm()), - torsion.interactionPotential().parametersAsString())) - return false; - - elec14Scaling = torsion.electrostatic14Scaling(); - vdw14Scaling = torsion.vanDerWaals14Scaling(); - } - } - } - - // Impropers - if (!impropers_.empty()) - { - if (!parser.writeLineF("\n{}# Impropers\n", newPrefix)) - return false; - if (!parser.writeLineF("{}{} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::NImpropers), - impropers_.size())) - return false; - for (auto &imp : impropers()) - { - if (imp.commonTerm()) - { - if (!parser.writeLineF("{}{} {:3d} {:3d} {:3d} {:3d} @{}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Improper), imp.i()->index() + 1, - imp.j()->index() + 1, imp.k()->index() + 1, imp.l()->index() + 1, - imp.commonTerm()->name())) - return false; - } - else if (!parser.writeLineF("{}{} {:3d} {:3d} {:3d} {:3d} {} {}\n", newPrefix, - keywords().keyword(Species::SpeciesKeyword::Improper), imp.i()->index() + 1, - imp.j()->index() + 1, imp.k()->index() + 1, imp.l()->index() + 1, - TorsionFunctions::forms().keyword(imp.interactionForm()), - imp.interactionPotential().parametersAsString())) - return false; - } - } - - // Box - if (box_.type() != Box::BoxType::None) - { - if (!parser.writeLineF("{}{} {} {} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::BoxAngles), - box_.axisAngles().x, box_.axisAngles().y, box_.axisAngles().z)) - return false; - if (!parser.writeLineF("{}{} {} {} {}\n", newPrefix, keywords().keyword(Species::SpeciesKeyword::BoxLengths), - box_.axisLengths().x, box_.axisLengths().y, box_.axisLengths().z)) - return false; - } - - // Isotopologues - if (nIsotopologues() > 0) - { - if (!parser.writeLineF("\n{}# Isotopologues\n", newPrefix)) - return false; - - for (auto &iso : isotopologues_) - { - if (!parser.writeLineF("{}{} '{}'", newPrefix, keywords().keyword(Species::SpeciesKeyword::Isotopologue), - iso->name())) - return false; - for (auto [atomType, isotope] : iso->isotopes()) - { - // No need to write anything that's the natural isotope... - if (Sears91::A(isotope) == 0) - continue; - - if (!parser.writeLineF(" {}={}", atomType->name(), Sears91::A(isotope))) - return false; - } - if (!parser.writeLineF("\n")) - return false; - } - } - - // Sites - if (nSites() > 0) - { - if (!parser.writeLineF("\n{}# Sites\n", newPrefix)) - return false; - - for (auto &site : sites()) - if (!site->write(parser, newPrefix)) - return false; - } - - // Done with this species - if (!parser.writeLineF("{}{}\n", prefix, keywords().keyword(Species::SpeciesKeyword::EndSpecies))) - return false; - - return true; -}