Skip to content

Commit 371cb7c

Browse files
authored
Make atomic displacement parameters optional (#451)
* Add get_optional json function * Make dp and dprot optional * Add default dp and dprot to atomtransrot move * Clang format * Update schema.yml with dp/dprot
1 parent 6e85032 commit 371cb7c

File tree

8 files changed

+69
-28
lines changed

8 files changed

+69
-28
lines changed

Diff for: docs/_docs/moves.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,15 @@ Upon MC movement, the mean squared displacement will be tracked.
7777
`molecule` | Molecule name to operate on
7878
`dir=[1,1,1]` | Translational directions
7979
`energy_resolution` | If set to a non-zero value (kT), an energy histogram will be generated.
80+
`dp=0` | Default translational displacement parameter (Å)
81+
`dprot=0` | Default rotational displacement parameter (radians)
8082

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

8791
An energy histogram of each participating species will be written to disk if the `energy_resolution`

Diff for: docs/_docs/topology.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ Atoms are the smallest possible particle entities with properties defined below.
6161
`activity=0` | Chemical activity for grand canonical MC [mol/l]
6262
`pactivity` | −log10 of chemical activity (will be converted to activity)
6363
`alphax=0` | Excess polarizability (unit-less)
64-
`dp=0` | Translational displacement parameter [Å]
65-
`dprot=0` | Rotational displacement parameter [radians]
64+
`dp` | Translational displacement parameter [Å] (optional)
65+
`dprot` | Rotational displacement parameter [radians] (optional)
6666
`eps=0` | Lennard-Jones/WCA energy parameter [kJ/mol]
6767
`mu=[0,0,0]` | Dipole moment vector [eÅ]
6868
`mulen=|mu|` | Dipole moment scalar [eÅ]

Diff for: docs/schema.yml

+2
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,8 @@ properties:
775775
minItems: 3
776776
maxItems: 3
777777
default: [1,1,1]
778+
dp: {type: number, minimum: 0.0, description: "default translational displacement", default: 0.0}
779+
dprot: {type: number, minimum: 0.0, description: "default rotational displacement", default: 0.0}
778780
required: [molecule]
779781
additionalProperties: false
780782
type: object

Diff for: src/atomdata.cpp

+22-7
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,18 @@ void to_json(json& j, const AtomData& a)
9393
{"alphax", a.alphax},
9494
{"mw", a.mw},
9595
{"q", a.charge},
96-
{"dp", a.dp / 1.0_angstrom},
97-
{"dprot", a.dprot / 1.0_rad},
9896
{"tension", a.tension * 1.0_angstrom * 1.0_angstrom / 1.0_kJmol},
9997
{"tfe", a.tfe * 1.0_angstrom * 1.0_angstrom * 1.0_molar / 1.0_kJmol},
10098
{"mu", a.mu},
10199
{"mulen", a.mulen},
102100
{"psc", a.sphero_cylinder},
103101
{"id", a.id()}};
102+
if (a.dp.has_value()) {
103+
_j["dp"] = a.dp.value() / 1.0_angstrom;
104+
}
105+
if (a.dprot.has_value()) {
106+
_j["dprot"] = a.dprot.value() / 1.0_rad;
107+
}
104108
to_json(_j, a.interaction); // append other interactions
105109
if (a.hydrophobic) {
106110
_j["hydrophobic"] = a.hydrophobic;
@@ -110,6 +114,21 @@ void to_json(json& j, const AtomData& a)
110114
}
111115
}
112116

117+
/// Handles optional translational and rotational displacement
118+
void set_dp_and_dprot(const json& j, AtomData& atomdata)
119+
{
120+
// todo: use `std::optional::and_then()` when C++23 is available
121+
if (const auto dp = get_optional<double>(j, "dp")) {
122+
atomdata.dp = dp.value() * 1.0_angstrom;
123+
}
124+
if (const auto dprot = get_optional<double>(j, "dprot")) {
125+
atomdata.dprot = dprot.value() * 1.0_rad;
126+
if (std::fabs(atomdata.dprot.value()) > 2.0 * pc::pi) {
127+
faunus_logger->warn("rotational displacement should be between [0:2π]");
128+
}
129+
}
130+
}
131+
113132
void from_json(const json& j, AtomData& a)
114133
{
115134
if (!j.is_object() || j.size() != 1) {
@@ -120,11 +139,6 @@ void from_json(const json& j, AtomData& a)
120139
auto val = SingleUseJSON(atom_iter.value());
121140
a.alphax = val.value("alphax", a.alphax);
122141
a.charge = val.value("q", a.charge);
123-
a.dp = val.value("dp", a.dp) * 1.0_angstrom;
124-
a.dprot = val.value("dprot", a.dprot) * 1.0_rad;
125-
if (std::fabs(a.dprot) > 2.0 * pc::pi) {
126-
faunus_logger->warn("rotational displacement should be between [0:2π]");
127-
}
128142
a.id() = val.value("id", a.id());
129143
a.mu = val.value("mu", a.mu);
130144
a.mulen = val.value("mulen", a.mulen);
@@ -140,6 +154,7 @@ void from_json(const json& j, AtomData& a)
140154
a.tfe = val.value("tfe", a.tfe) * 1.0_kJmol / (1.0_angstrom * 1.0_angstrom * 1.0_molar);
141155
a.hydrophobic = val.value("hydrophobic", false);
142156
a.implicit = val.value("implicit", false);
157+
set_dp_and_dprot(val, a);
143158
if (val.contains("activity")) {
144159
a.activity = val.at("activity").get<double>() * 1.0_molar;
145160
}

Diff for: src/atomdata.h

+16-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include "core.h"
3+
#include <optional>
34
#include <range/v3/range/concepts.hpp>
45
#include <range/v3/view/transform.hpp>
56
#include <range/v3/algorithm/any_of.hpp>
@@ -79,21 +80,21 @@ class AtomData
7980
friend void from_json(const json&, AtomData&);
8081

8182
public:
82-
std::string name; //!< Name
83-
double charge = 0; //!< Particle charge [e]
84-
double mw = 1; //!< Weight
85-
double sigma = 0; //!< Diameter for e.g Lennard-Jones etc. [angstrom]
86-
//!< Do not set! Only a temporal class member during the refactorization
87-
double activity = 0; //!< Chemical activity [mol/l]
88-
double alphax = 0; //!< Excess polarisability (unit-less)
89-
double dp = 0; //!< Translational displacement parameter [angstrom]
90-
double dprot = 0; //!< Rotational displacement parameter [degrees]
91-
double tension = 0; //!< Surface tension [kT/Å^2]
92-
double tfe = 0; //!< Transfer free energy [J/mol/angstrom^2/M]
93-
Point mu = {0, 0, 0}; //!< Dipole moment unit vector
94-
double mulen = 0; //!< Dipole moment length
95-
bool hydrophobic = false; //!< Is the particle hydrophobic?
96-
bool implicit = false; //!< Is the particle implicit (e.g. proton)?
83+
std::string name; //!< Name
84+
double charge = 0; //!< Particle charge [e]
85+
double mw = 1; //!< Weight
86+
double sigma = 0; //!< Diameter for e.g Lennard-Jones etc. [angstrom]
87+
//!< Do not set! Only a temporal class member during the refactorization
88+
double activity = 0; //!< Chemical activity [mol/l]
89+
double alphax = 0; //!< Excess polarisability (unit-less)
90+
std::optional<double> dp = std::nullopt; //!< Translational displacement parameter [angstrom]
91+
std::optional<double> dprot = std::nullopt; //!< Rotational displacement parameter [degrees]
92+
double tension = 0; //!< Surface tension [kT/Å^2]
93+
double tfe = 0; //!< Transfer free energy [J/mol/angstrom^2/M]
94+
Point mu = {0, 0, 0}; //!< Dipole moment unit vector
95+
double mulen = 0; //!< Dipole moment length
96+
bool hydrophobic = false; //!< Is the particle hydrophobic?
97+
bool implicit = false; //!< Is the particle implicit (e.g. proton)?
9798
InteractionData
9899
interaction; //!< Arbitrary interaction parameters, e.g., epsilons in various potentials
99100
SpheroCylinderData sphero_cylinder; //!< Data for patchy sphero cylinders (PSCs)

Diff for: src/core.h

+13
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,17 @@ class Electrolyte
254254
void to_json(json& j, const Electrolyte& electrolyte);
255255
std::optional<Electrolyte> makeElectrolyte(const json& j); //!< Create ionic salt object from json
256256

257+
/// Extract JSON value associated with `key` into `std::optional`
258+
///
259+
/// If the value does not exist, return `std::nullopt`
260+
///
261+
/// @throws If value exists but cannot be extracted as `T`.
262+
template <typename T> std::optional<T> get_optional(const json& j, std::string_view key)
263+
{
264+
if (const auto it = j.find(key); it != j.end()) {
265+
return it->get<T>(); // may throw exception
266+
}
267+
return std::nullopt;
268+
}
269+
257270
} // namespace Faunus

Diff for: src/move.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ void AtomicTranslateRotate::_to_json(json& j) const
189189
{
190190
j = {{"dir", directions},
191191
{"molid", molid},
192+
{"dp", default_dp},
193+
{"dprot", default_dprot},
192194
{unicode::rootof + unicode::bracket("r" + unicode::squared),
193195
std::sqrt(mean_square_displacement.avg())},
194196
{"molecule", molecule_name}};
@@ -214,6 +216,8 @@ void AtomicTranslateRotate::_from_json(const json& j)
214216
}
215217
}
216218
energy_resolution = j.value("energy_resolution", 0.0);
219+
default_dp = j.value("dp", 0.0);
220+
default_dprot = j.value("dprot", 0.0);
217221
}
218222

219223
void AtomicTranslateRotate::translateParticle(ParticleVector::iterator particle,
@@ -262,8 +266,8 @@ void AtomicTranslateRotate::_move(Change& change)
262266
{
263267
if (auto particle = randomAtom(); particle != spc.particles.end()) {
264268
latest_particle = particle;
265-
const auto translational_displacement = particle->traits().dp;
266-
const auto rotational_displacement = particle->traits().dprot;
269+
const double translational_displacement = particle->traits().dp.value_or(default_dp);
270+
const double rotational_displacement = particle->traits().dprot.value_or(default_dprot);
267271

268272
if (translational_displacement > 0.0) { // translate
269273
translateParticle(particle, translational_displacement);

Diff for: src/move.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ class [[maybe_unused]] AtomicSwapCharge : public Move
139139
};
140140

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

0 commit comments

Comments
 (0)