Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make atomic displacement parameters optional #451

Merged
merged 7 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/_docs/moves.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ Upon MC movement, the mean squared displacement will be tracked.
`molecule` | Molecule name to operate on
`dir=[1,1,1]` | Translational directions
`energy_resolution` | If set to a non-zero value (kT), an energy histogram will be generated.
`dp=0` | Default translational displacement parameter (Å)
`dprot=0` | Default rotational displacement parameter (radians)

As `moltransrot` but instead of operating on the molecular mass center, this translates
and rotates individual atoms in the group. The repeat is set to the number of atoms in the specified group and the
and rotates individual atoms in the group.
The repeat is set to the number of atoms in the specified group and the
displacement parameters `dp` and `dprot` for the individual atoms are taken from
the atom properties defined in the [topology](topology).
If `dp` and `dprot` are not defined for an atom, the default values for the move are used.
Atomic _rotation_ affects only anisotropic particles such as dipoles, spherocylinders, quadrupoles etc.

An energy histogram of each participating species will be written to disk if the `energy_resolution`
Expand Down
4 changes: 2 additions & 2 deletions docs/_docs/topology.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ Atoms are the smallest possible particle entities with properties defined below.
`activity=0` | Chemical activity for grand canonical MC [mol/l]
`pactivity` | −log10 of chemical activity (will be converted to activity)
`alphax=0` | Excess polarizability (unit-less)
`dp=0` | Translational displacement parameter [Å]
`dprot=0` | Rotational displacement parameter [radians]
`dp` | Translational displacement parameter [Å] (optional)
`dprot` | Rotational displacement parameter [radians] (optional)
`eps=0` | Lennard-Jones/WCA energy parameter [kJ/mol]
`mu=[0,0,0]` | Dipole moment vector [eÅ]
`mulen=|mu|` | Dipole moment scalar [eÅ]
Expand Down
2 changes: 2 additions & 0 deletions docs/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,8 @@ properties:
minItems: 3
maxItems: 3
default: [1,1,1]
dp: {type: number, minimum: 0.0, description: "default translational displacement", default: 0.0}
dprot: {type: number, minimum: 0.0, description: "default rotational displacement", default: 0.0}
required: [molecule]
additionalProperties: false
type: object
Expand Down
29 changes: 22 additions & 7 deletions src/atomdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,18 @@ void to_json(json& j, const AtomData& a)
{"alphax", a.alphax},
{"mw", a.mw},
{"q", a.charge},
{"dp", a.dp / 1.0_angstrom},
{"dprot", a.dprot / 1.0_rad},
{"tension", a.tension * 1.0_angstrom * 1.0_angstrom / 1.0_kJmol},
{"tfe", a.tfe * 1.0_angstrom * 1.0_angstrom * 1.0_molar / 1.0_kJmol},
{"mu", a.mu},
{"mulen", a.mulen},
{"psc", a.sphero_cylinder},
{"id", a.id()}};
if (a.dp.has_value()) {
_j["dp"] = a.dp.value() / 1.0_angstrom;
}
if (a.dprot.has_value()) {
_j["dprot"] = a.dprot.value() / 1.0_rad;
}
to_json(_j, a.interaction); // append other interactions
if (a.hydrophobic) {
_j["hydrophobic"] = a.hydrophobic;
Expand All @@ -110,6 +114,21 @@ void to_json(json& j, const AtomData& a)
}
}

/// Handles optional translational and rotational displacement
void set_dp_and_dprot(const json& j, AtomData& atomdata)
{
// todo: use `std::optional::and_then()` when C++23 is available
if (const auto dp = get_optional<double>(j, "dp")) {
atomdata.dp = dp.value() * 1.0_angstrom;
}
if (const auto dprot = get_optional<double>(j, "dprot")) {
atomdata.dprot = dprot.value() * 1.0_rad;
if (std::fabs(atomdata.dprot.value()) > 2.0 * pc::pi) {
faunus_logger->warn("rotational displacement should be between [0:2π]");
}
}
}

void from_json(const json& j, AtomData& a)
{
if (!j.is_object() || j.size() != 1) {
Expand All @@ -120,11 +139,6 @@ void from_json(const json& j, AtomData& a)
auto val = SingleUseJSON(atom_iter.value());
a.alphax = val.value("alphax", a.alphax);
a.charge = val.value("q", a.charge);
a.dp = val.value("dp", a.dp) * 1.0_angstrom;
a.dprot = val.value("dprot", a.dprot) * 1.0_rad;
if (std::fabs(a.dprot) > 2.0 * pc::pi) {
faunus_logger->warn("rotational displacement should be between [0:2π]");
}
a.id() = val.value("id", a.id());
a.mu = val.value("mu", a.mu);
a.mulen = val.value("mulen", a.mulen);
Expand All @@ -140,6 +154,7 @@ void from_json(const json& j, AtomData& a)
a.tfe = val.value("tfe", a.tfe) * 1.0_kJmol / (1.0_angstrom * 1.0_angstrom * 1.0_molar);
a.hydrophobic = val.value("hydrophobic", false);
a.implicit = val.value("implicit", false);
set_dp_and_dprot(val, a);
if (val.contains("activity")) {
a.activity = val.at("activity").get<double>() * 1.0_molar;
}
Expand Down
31 changes: 16 additions & 15 deletions src/atomdata.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "core.h"
#include <optional>
#include <range/v3/range/concepts.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/algorithm/any_of.hpp>
Expand Down Expand Up @@ -79,21 +80,21 @@ class AtomData
friend void from_json(const json&, AtomData&);

public:
std::string name; //!< Name
double charge = 0; //!< Particle charge [e]
double mw = 1; //!< Weight
double sigma = 0; //!< Diameter for e.g Lennard-Jones etc. [angstrom]
//!< Do not set! Only a temporal class member during the refactorization
double activity = 0; //!< Chemical activity [mol/l]
double alphax = 0; //!< Excess polarisability (unit-less)
double dp = 0; //!< Translational displacement parameter [angstrom]
double dprot = 0; //!< Rotational displacement parameter [degrees]
double tension = 0; //!< Surface tension [kT/Å^2]
double tfe = 0; //!< Transfer free energy [J/mol/angstrom^2/M]
Point mu = {0, 0, 0}; //!< Dipole moment unit vector
double mulen = 0; //!< Dipole moment length
bool hydrophobic = false; //!< Is the particle hydrophobic?
bool implicit = false; //!< Is the particle implicit (e.g. proton)?
std::string name; //!< Name
double charge = 0; //!< Particle charge [e]
double mw = 1; //!< Weight
double sigma = 0; //!< Diameter for e.g Lennard-Jones etc. [angstrom]
//!< Do not set! Only a temporal class member during the refactorization
double activity = 0; //!< Chemical activity [mol/l]
double alphax = 0; //!< Excess polarisability (unit-less)
std::optional<double> dp = std::nullopt; //!< Translational displacement parameter [angstrom]
std::optional<double> dprot = std::nullopt; //!< Rotational displacement parameter [degrees]
double tension = 0; //!< Surface tension [kT/Å^2]
double tfe = 0; //!< Transfer free energy [J/mol/angstrom^2/M]
Point mu = {0, 0, 0}; //!< Dipole moment unit vector
double mulen = 0; //!< Dipole moment length
bool hydrophobic = false; //!< Is the particle hydrophobic?
bool implicit = false; //!< Is the particle implicit (e.g. proton)?
InteractionData
interaction; //!< Arbitrary interaction parameters, e.g., epsilons in various potentials
SpheroCylinderData sphero_cylinder; //!< Data for patchy sphero cylinders (PSCs)
Expand Down
13 changes: 13 additions & 0 deletions src/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,17 @@ class Electrolyte
void to_json(json& j, const Electrolyte& electrolyte);
std::optional<Electrolyte> makeElectrolyte(const json& j); //!< Create ionic salt object from json

/// Extract JSON value associated with `key` into `std::optional`
///
/// If the value does not exist, return `std::nullopt`
///
/// @throws If value exists but cannot be extracted as `T`.
template <typename T> std::optional<T> get_optional(const json& j, std::string_view key)
{
if (const auto it = j.find(key); it != j.end()) {
return it->get<T>(); // may throw exception
}
return std::nullopt;
}

} // namespace Faunus
8 changes: 6 additions & 2 deletions src/move.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ void AtomicTranslateRotate::_to_json(json& j) const
{
j = {{"dir", directions},
{"molid", molid},
{"dp", default_dp},
{"dprot", default_dprot},
{unicode::rootof + unicode::bracket("r" + unicode::squared),
std::sqrt(mean_square_displacement.avg())},
{"molecule", molecule_name}};
Expand All @@ -214,6 +216,8 @@ void AtomicTranslateRotate::_from_json(const json& j)
}
}
energy_resolution = j.value("energy_resolution", 0.0);
default_dp = j.value("dp", 0.0);
default_dprot = j.value("dprot", 0.0);
}

void AtomicTranslateRotate::translateParticle(ParticleVector::iterator particle,
Expand Down Expand Up @@ -262,8 +266,8 @@ void AtomicTranslateRotate::_move(Change& change)
{
if (auto particle = randomAtom(); particle != spc.particles.end()) {
latest_particle = particle;
const auto translational_displacement = particle->traits().dp;
const auto rotational_displacement = particle->traits().dprot;
const double translational_displacement = particle->traits().dp.value_or(default_dp);
const double rotational_displacement = particle->traits().dprot.value_or(default_dprot);

if (translational_displacement > 0.0) { // translate
translateParticle(particle, translational_displacement);
Expand Down
4 changes: 3 additions & 1 deletion src/move.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class [[maybe_unused]] AtomicSwapCharge : public Move
};

/**
* @brief Translate and rotate a molecular group
* @brief Translate and rotate individual atoms
*/
class AtomicTranslateRotate : public Move
{
Expand All @@ -149,6 +149,8 @@ class AtomicTranslateRotate : public Move
energy_histogram; //!< Energy histogram (value) for each particle type (key)
double energy_resolution = 0.0; //!< Resolution of sampled energy histogram
double latest_displacement_squared; //!< temporary squared displacement
double default_dp = 0.0; //!< Default translational displacement (Å)
double default_dprot = 0.0; //!< Default rotational displacement (rad)
void sampleEnergyHistogram(); //!< Update energy histogram based on latest move
void saveHistograms(); //!< Write histograms for file
void checkMassCenter(
Expand Down
Loading