ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
script_interface/thermostat/thermostat.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
24#include "core/thermostat.hpp"
25
29#ifdef WALBERLA
31#endif
32
33#include <cassert>
34#include <limits>
35#include <memory>
36#include <stdexcept>
37#include <string>
38
39namespace ScriptInterface {
40namespace Thermostat {
41
42template <typename CoreClass>
43class Interface : public AutoParameters<Interface<CoreClass>, System::Leaf> {
45
46public:
47 using CoreThermostat = CoreClass;
51
52protected:
57
58 bool is_active = false;
59 std::shared_ptr<CoreThermostat> m_handle;
60 /** @brief Basic lock mechanism that follows RAII. */
61 std::weak_ptr<bool> m_edit_lock;
62
63 void check_lock() {
64 if (m_edit_lock.expired()) {
66 }
67 }
68
70 get_member_handle(*system.thermostat) = m_handle;
71 system.on_thermostat_param_change();
72 is_active = true;
73 }
74
76 get_member_handle(*system.thermostat).reset();
77 system.on_thermostat_param_change();
78 is_active = false;
79 }
80
81 void sanity_checks_positive(double value, std::string const &name) const {
82 if (value < 0.) {
83 throw std::domain_error("Parameter '" + name + "' cannot be negative");
84 }
85 }
86
88 std::string const &name) const {
89 if (not(value >= Utils::Vector3d::broadcast(0.))) {
90 throw std::domain_error("Parameter '" + name + "' cannot be negative");
91 }
92 }
93
94 virtual bool invalid_rng_state(VariantMap const &params) const {
95 return (not params.count("seed") or is_none(params.at("seed"))) and
97 }
98
99private:
100 virtual std::shared_ptr<CoreThermostat> &
102
103 void set_new_parameters(VariantMap const &params) {
104 if (params.count("__check_rng_state") and invalid_rng_state(params)) {
106 throw std::invalid_argument("Parameter 'seed' is needed on first "
107 "activation of the thermostat");
108 });
109 }
110 for (auto const &key : get_parameter_insertion_order()) {
111 if (params.count(key)) {
112 auto const &v = params.at(key);
113 if (key == "is_active") {
115 } else {
116 do_set_parameter(key.c_str(), v);
117 }
118 }
119 }
120 }
121
122protected:
123 template <typename T>
125 return AutoParameter{
126 name,
127 [this, member, name = std::string(name)](Variant const &v) {
128 check_lock();
129 auto const value = get_value<T>(v);
131 [&]() { sanity_checks_positive(value, name); });
132 m_handle.get()->*member = std::move(value);
133 },
134 [this, member]() { return m_handle.get()->*member; }};
135 }
136
137 template <typename T>
139 return AutoParameter{
140 name,
141 [this, member, name = std::string(name)](Variant const &v) {
142 check_lock();
143 if (is_none(v)) {
144 return;
145 }
146#ifdef PARTICLE_ANISOTROPY
147 static_assert(std::is_same_v<T, Utils::Vector3d>);
148 T gamma{};
149 if (is_type<int>(v) or is_type<double>(v)) {
150 gamma = T::broadcast(get_value<double>(v));
151 } else {
152 gamma = get_value<T>(v);
153 }
154#else
155 auto const gamma = get_value<T>(v);
156#endif // PARTICLE_ANISOTROPY
158 [&]() { sanity_checks_positive(gamma, name); });
159 m_handle.get()->*member = gamma;
160 },
161 [this, member]() {
162 auto constexpr gamma_null = ::Thermostat::gamma_null;
163 auto const gamma = m_handle.get()->*member;
164 return (gamma >= gamma_null) ? Variant{gamma} : Variant{None{}};
165 }};
166 }
167
169 auto params = parameters;
170 if (not is_seed_required()) {
171 for (auto key : {std::string("seed"), std::string("philox_counter")}) {
172 if (params.count(key) == 0ul) {
174 }
175 }
176 }
177 return params;
178 }
179
180 Variant do_call_method(std::string const &name,
181 VariantMap const &params) override {
182 if (name == "override_philox_counter") {
183 // only call this method if you know what you are doing
184 set_rng_counter(params.at("counter"));
185 return {};
186 }
187 return {};
188 }
189
190public:
193 {"seed",
194 [this](Variant const &v) {
195 check_lock();
196 context()->parallel_try_catch([&]() {
197 if (not is_none(v))
198 set_rng_seed(v);
199 });
200 },
201 [this]() {
202 return m_handle->is_seed_required() ? Variant{None{}}
204 }},
205 {"philox_counter",
206 [this](Variant const &v) {
207 check_lock();
208 context()->parallel_try_catch([&]() {
209 if (not is_none(v))
211 });
212 },
213 [this]() { return get_rng_counter(); }},
214 {"is_active", AutoParameter::read_only, [this]() { return is_active; }},
215 });
216 }
217
218 virtual std::optional<double> extract_kT(VariantMap const &params) const {
219 if (params.count("kT")) {
220 auto const value = get_value<double>(params, "kT");
221 sanity_checks_positive(value, "kT");
222 return value;
223 }
224 return {std::nullopt};
225 }
226
228 auto lock = std::make_shared<bool>(false);
230 return lock;
231 }
232
233 auto is_activated() const { return is_active; }
234
235 virtual bool is_seed_required() const { return m_handle->is_seed_required(); }
236
237 auto get_rng_seed() const {
238 auto const seed = m_handle->rng_seed();
239 assert(seed <= static_cast<uint32_t>(std::numeric_limits<int>::max()));
240 return static_cast<int>(seed);
241 }
242
243 auto get_rng_counter() const {
244 auto const counter = m_handle->rng_counter();
245 assert(counter <= static_cast<uint64_t>(std::numeric_limits<int>::max()));
246 return static_cast<int>(counter);
247 }
248
249 void set_rng_seed(Variant const &value) {
250 auto const seed = get_value<int>(value);
251 if (seed < 0) {
252 throw std::domain_error("Parameter 'seed' must be a positive integer");
253 }
254 assert(static_cast<uint64_t>(seed) <=
255 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
256 m_handle->rng_initialize(static_cast<uint32_t>(seed));
257 }
258
259 void set_rng_counter(Variant const &value) {
260 auto const counter = get_value<int>(value);
261 assert(counter >= 0);
262 assert(static_cast<uint64_t>(counter) <=
263 std::numeric_limits<uint64_t>::max());
264 m_handle->set_rng_counter(static_cast<uint64_t>(counter));
265 }
266
267 void do_construct(VariantMap const &params) override {
268 m_handle = std::make_shared<CoreThermostat>();
269 if (not params.empty()) {
270 auto const read_write_lock = release_lock();
271 set_new_parameters(params);
272 }
273 }
274
276 std::shared_ptr<::System::System> system) {
277 auto const old_handle = m_handle;
279 new_params["__global_kT"] = system->thermostat->kT;
280 new_params["__check_rng_state"] = true;
281 try {
282 m_handle = std::make_shared<CoreThermostat>();
283 set_new_parameters(new_params);
285 } catch (...) {
288 if (was_active) {
290 }
291 throw;
292 }
293 }
294
295 virtual ::ThermostatFlags get_thermo_flag() const = 0;
296};
297
298class Langevin : public Interface<::LangevinThermostat> {
299 std::shared_ptr<CoreThermostat> &
301 return thermostat.langevin;
302 }
303
304public:
308#ifdef ROTATION
310#endif
311 });
312 }
313
315
316protected:
318 auto params =
320#ifdef ROTATION
321 // If gamma_rotation is not set explicitly, use the translational one.
322 if (params.count("gamma_rotation") == 0ul and params.count("gamma")) {
323 params["gamma_rotation"] = params.at("gamma");
324 }
325#endif // ROTATION
326 return params;
327 }
328};
329
330class Brownian : public Interface<::BrownianThermostat> {
331 std::shared_ptr<CoreThermostat> &
333 return thermostat.brownian;
334 }
335
336public:
340#ifdef ROTATION
342#endif
343 });
344 }
345
347
348protected:
350 auto params =
352#ifdef ROTATION
353 // If gamma_rotation is not set explicitly, use the translational one.
354 if (params.count("gamma_rotation") == 0ul and params.count("gamma")) {
355 params["gamma_rotation"] = params.at("gamma");
356 }
357#endif // ROTATION
358 return params;
359 }
360};
361
362#ifdef NPT
363class IsotropicNpt : public Interface<::IsotropicNptThermostat> {
364 std::shared_ptr<CoreThermostat> &
366 return thermostat.npt_iso;
367 }
368
369public:
376
378};
379#endif // NPT
380
381#ifdef WALBERLA
382class LBThermostat : public Interface<::LBThermostat> {
383 std::shared_ptr<CoreThermostat> &
385 return thermostat.lb;
386 }
387
388public:
391 {"gamma",
392 [this](Variant const &v) {
393 check_lock();
394 if (is_none(v)) {
395 return;
396 }
397 auto const gamma = get_value<double>(v);
399 [&]() { sanity_checks_positive(gamma, "gamma"); });
400 m_handle->gamma = gamma;
401 },
402 [this]() {
403 auto const gamma = m_handle->gamma;
404 return (gamma >= 0.) ? Variant{gamma} : Variant{None{}};
405 }},
406 });
407 }
408
410
411 std::optional<double> extract_kT(VariantMap const &params) const override {
412 auto const obj =
414 auto const value = get_value<double>(obj->get_parameter("kT"));
415 sanity_checks_positive(value, "kT");
416 return value;
417 }
418
419protected:
420 bool invalid_rng_state(VariantMap const &params) const override {
421 return (not params.count("seed") or is_none(params.at("seed"))) and
422 params.count("__global_kT") and is_seed_required() and
423 get_value<double>(params, "__global_kT") != 0.;
424 }
425};
426#endif // WALBERLA
427
428#ifdef DPD
429class DPDThermostat : public Interface<::DPDThermostat> {
430 std::shared_ptr<CoreThermostat> &
432 return thermostat.dpd;
433 }
434
435public:
437};
438#endif
439
440#ifdef STOKESIAN_DYNAMICS
441class Stokesian : public Interface<::StokesianThermostat> {
442 std::shared_ptr<CoreThermostat> &
444 return thermostat.stokesian;
445 }
446
447public:
449};
450#endif
451
452class ThermalizedBond : public Interface<::ThermalizedBondThermostat> {
453 std::shared_ptr<CoreThermostat> &
455 return thermostat.thermalized_bond;
456 }
457
458public:
460};
461
462class Thermostat : public AutoParameters<Thermostat, System::Leaf> {
463 std::shared_ptr<Langevin> langevin;
464 std::shared_ptr<Brownian> brownian;
465#ifdef NPT
466 std::shared_ptr<IsotropicNpt> npt_iso;
467#endif
468#ifdef WALBERLA
469 std::shared_ptr<LBThermostat> lb;
470#endif
471#ifdef DPD
472 std::shared_ptr<DPDThermostat> dpd;
473#endif
474#ifdef STOKESIAN_DYNAMICS
475 std::shared_ptr<Stokesian> stokesian;
476#endif
477 std::shared_ptr<ThermalizedBond> thermalized_bond;
478 std::shared_ptr<::Thermostat::Thermostat> m_handle;
479 std::unique_ptr<VariantMap> m_params;
480
481 template <typename Fun> void apply(Fun fun) {
482 fun(*langevin);
483 fun(*brownian);
484#ifdef NPT
485 fun(*npt_iso);
486#endif
487#ifdef WALBERLA
488 fun(*lb);
489#endif
490#ifdef DPD
491 fun(*dpd);
492#endif
493#ifdef STOKESIAN_DYNAMICS
494 fun(*stokesian);
495#endif
496 fun(*thermalized_bond);
497 }
498
499protected:
500 template <typename T>
502 return AutoParameter{
503 name,
504 [this, member, name = std::string(name)](Variant const &v) {
505 auto &thermostat = this->*member;
506 if (thermostat) {
507 throw WriteError{name};
508 }
509 thermostat = get_value<T>(v);
510 },
511 [this, member]() { return this->*member; }};
512 }
513
514 template <typename T>
515 void setup_thermostat(std::shared_ptr<T> &thermostat,
516 VariantMap const &params) {
517 auto const original_kT = m_handle->kT;
518 std::optional<double> new_kT;
520 [&]() { new_kT = thermostat->extract_kT(params); });
521 auto const thermo_flag = thermostat->get_thermo_flag();
522 if (new_kT) {
525 }
526 auto const was_active = thermostat->is_activated();
527 turn_thermostat_off(*thermostat);
528 auto read_write_lock = thermostat->release_lock();
529 context()->parallel_try_catch([&]() {
530 try {
531 if (new_kT) {
532 m_handle->kT = *new_kT;
533 }
534 thermostat->update_and_bind(params, was_active, m_system.lock());
535 m_handle->thermo_switch |= thermo_flag;
536 } catch (...) {
537 auto success = false;
538 try {
539 m_handle->kT = original_kT;
540 if (was_active) {
541 m_handle->thermo_switch |= thermo_flag;
542 thermostat->bind_system(m_system.lock());
543 }
544 success = true;
545 throw success;
546 } catch (...) {
547 assert(success &&
548 "An exception occurred when setting up the thermostat. "
549 "An exception also occurred when attempting to restore the "
550 "original thermostat. The system is now in an invalid state.");
551 }
552 throw;
553 }
554 });
555 }
556
557 template <typename T> void turn_thermostat_off(T &thermostat) {
558 auto const thermo_flag = thermostat.get_thermo_flag();
559 if (m_handle->thermo_switch & thermo_flag) {
560 thermostat.detach_system();
561 m_handle->thermo_switch &= ~thermo_flag;
562 if (m_handle->thermo_switch == 0) {
563 m_handle->kT = -1.;
564 }
565 }
566 }
567
568 void update_global_kT(double old_kT, double new_kT, int thermo_flag) {
569 if (new_kT >= 0.) {
571 auto const thermo_switch = m_handle->thermo_switch;
572 if (thermo_switch != THERMO_OFF and thermo_switch != thermo_flag and
573 thermo_switch != THERMO_BOND and not same_kT and old_kT >= 0.) {
574 throw std::runtime_error(
575 "Cannot set parameter 'kT' to " + std::to_string(new_kT) +
576 ": there are currently active thermostats with kT=" +
577 std::to_string(old_kT));
578 }
579 get_system().check_kT(new_kT);
580 if (not same_kT) {
581 m_handle->kT = new_kT;
582 get_system().on_temperature_change();
583 }
584 }
585 }
586
587public:
591 [this]() {
592 return (m_handle->kT >= 0.) ? Variant{m_handle->kT}
593 : Variant{None{}};
594 }},
595 make_autoparameter(&Thermostat::langevin, "langevin"),
596 make_autoparameter(&Thermostat::brownian, "brownian"),
597#ifdef NPT
598 make_autoparameter(&Thermostat::npt_iso, "npt_iso"),
599#endif
600#ifdef WALBERLA
601 make_autoparameter(&Thermostat::lb, "lb"),
602#endif
603#ifdef DPD
604 make_autoparameter(&Thermostat::dpd, "dpd"),
605#endif
606#ifdef STOKESIAN_DYNAMICS
607 make_autoparameter(&Thermostat::stokesian, "stokesian"),
608#endif
609 make_autoparameter(&Thermostat::thermalized_bond, "thermalized_bond"),
610 });
611 }
612
613 Variant do_call_method(std::string const &name,
614 VariantMap const &params) override {
615 if (params.contains("act_on_virtual")) {
616 context()->parallel_try_catch([&]() {
617 throw std::runtime_error(
618 name + "() got an unexpected keyword argument 'act_on_virtual'");
619 });
620 }
621 if (name == "set_langevin") {
622 setup_thermostat(langevin, params);
623 return {};
624 }
625 if (name == "set_brownian") {
626 setup_thermostat(brownian, params);
627 return {};
628 }
629#ifdef NPT
630 if (name == "set_npt") {
631 setup_thermostat(npt_iso, params);
632 return {};
633 }
634#endif // NPT
635#ifdef WALBERLA
636 if (name == "set_lb") {
638 return {};
639 }
640#endif // WALBERLA
641#ifdef DPD
642 if (name == "set_dpd") {
644 return {};
645 }
646#endif // DPD
647#ifdef STOKESIAN_DYNAMICS
648 if (name == "set_stokesian") {
649 setup_thermostat(stokesian, params);
650 return {};
651 }
652#endif // STOKESIAN_DYNAMICS
653 if (name == "set_thermalized_bond") {
654 setup_thermostat(thermalized_bond, params);
655 return {};
656 }
657 if (name == "turn_off") {
658 apply([this](auto &thermostat) { turn_thermostat_off(thermostat); });
659 assert(m_handle->thermo_switch == THERMO_OFF);
660 get_system().on_temperature_change();
661 return {};
662 }
663 return {};
664 }
665
666 void do_construct(VariantMap const &params) override {
667 m_params = std::make_unique<VariantMap>(params);
668 }
669
671 assert(m_params != nullptr);
672 m_handle = system.thermostat;
673 auto const &params = *m_params;
674 if (not params.empty()) {
675 reload_checkpointed_thermostats(params);
676 m_params.reset();
677 return;
678 }
679 m_params.reset();
680 if (not context()->is_head_node()) {
681 return;
682 }
683 make_default_constructed_thermostats();
684 }
685
686private:
687 /**
688 * @brief Reload thermostats from checkpointed data.
689 */
690 void reload_checkpointed_thermostats(VariantMap const &params) {
691 for (auto const &key : get_parameter_insertion_order()) {
692 if (key != "kT") {
693 auto const &v = params.at(key);
694 do_set_parameter(key.c_str(), v);
695 }
696 }
697 if (not is_none(params.at("kT"))) {
698 m_handle->kT = get_value<double>(params, "kT");
699 }
700 apply([this](auto &thermostat) {
701 if (get_value<bool>(thermostat.get_parameter("is_active"))) {
702 thermostat.bind_system(m_system.lock());
703 m_handle->thermo_switch |= thermostat.get_thermo_flag();
704 }
705 });
706 get_system().on_thermostat_param_change();
707 }
708
709 /**
710 * @brief Instantiate default-constructed thermostats.
711 * Can only be run on the head node!
712 */
713 void make_default_constructed_thermostats() {
714 assert(context()->is_head_node());
715 auto const make_thermostat = [this](char const *name, char const *so_name) {
717 };
718 make_thermostat("langevin", "Thermostat::Langevin");
719 make_thermostat("brownian", "Thermostat::Brownian");
720#ifdef NPT
721 make_thermostat("npt_iso", "Thermostat::IsotropicNpt");
722#endif
723#ifdef WALBERLA
724 make_thermostat("lb", "Thermostat::LB");
725#endif
726#ifdef DPD
727 make_thermostat("dpd", "Thermostat::DPD");
728#endif
729#ifdef STOKESIAN_DYNAMICS
730 make_thermostat("stokesian", "Thermostat::Stokesian");
731#endif
732 make_thermostat("thermalized_bond", "Thermostat::ThermalizedBond");
733 }
734};
735
736} // namespace Thermostat
737} // namespace ScriptInterface
ScriptInterface::Context decorates ScriptInterface::ObjectHandle objects with a context: a creation p...
ThermostatFlags
Thermostat flags.
@ THERMO_SD
@ THERMO_BROWNIAN
@ THERMO_BOND
@ THERMO_LB
@ THERMO_LANGEVIN
@ THERMO_DPD
@ THERMO_NPT_ISO
@ THERMO_OFF
Data structures for bonded interactions.
Bind parameters in the script interface.
void do_set_parameter(const std::string &name, const Variant &value) final
virtual void parallel_try_catch(std::function< void()> const &cb) const =0
virtual std::shared_ptr< ObjectHandle > make_shared(std::string const &name, const VariantMap &parameters)=0
Get a new reference counted instance of a script interface by name.
Type to indicate no value in Variant.
boost::string_ref name() const
Context * context() const
Responsible context.
void set_parameter(const std::string &name, const Variant &value)
Set single parameter.
Script interface wrapper for a component of the system class.
std::weak_ptr<::System::System > m_system
void bind_system(std::shared_ptr<::System::System > const &system)
VariantMap extend_parameters(VariantMap const &parameters) const override
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
void sanity_checks_positive(double value, std::string const &name) const
void update_and_bind(VariantMap const &params, bool was_active, std::shared_ptr<::System::System > system)
virtual ::ThermostatFlags get_thermo_flag() const =0
virtual std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat)=0
virtual bool invalid_rng_state(VariantMap const &params) const
auto make_autoparameter(T CoreThermostat::*member, char const *name)
Variant do_call_method(std::string const &name, VariantMap const &params) override
virtual std::optional< double > extract_kT(VariantMap const &params) const
auto make_autogamma(T CoreThermostat::*member, char const *name)
virtual VariantMap extend_parameters(VariantMap const &parameters) const
std::weak_ptr< bool > m_edit_lock
Basic lock mechanism that follows RAII.
void sanity_checks_positive(Utils::Vector3d const &value, std::string const &name) const
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
bool invalid_rng_state(VariantMap const &params) const override
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
std::optional< double > extract_kT(VariantMap const &params) const override
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
VariantMap extend_parameters(VariantMap const &parameters) const override
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
std::shared_ptr< CoreThermostat > & get_member_handle(::Thermostat::Thermostat &thermostat) override
void update_global_kT(double old_kT, double new_kT, int thermo_flag)
auto make_autoparameter(T Thermostat::*member, char const *name)
void setup_thermostat(std::shared_ptr< T > &thermostat, VariantMap const &params)
Variant do_call_method(std::string const &name, VariantMap const &params) override
Main system class.
std::shared_ptr< BrownianThermostat > brownian
std::shared_ptr< ThermalizedBondThermostat > thermalized_bond
std::shared_ptr< LangevinThermostat > langevin
std::shared_ptr< DPDThermostat > dpd
std::shared_ptr< LBThermostat > lb
std::shared_ptr< IsotropicNptThermostat > npt_iso
std::shared_ptr< StokesianThermostat > stokesian
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value)
Create a vector that has all entries set to the same value.
Definition Vector.hpp:110
Implementation in thermostat.cpp.
T get_value(Variant const &v)
Extract value of specific type T from a Variant.
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:69
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectRef, Utils::Vector3b, Utils::Vector3i, Utils::Vector2d, Utils::Vector3d, Utils::Vector4d, std::vector< int >, std::vector< double >, std::vector< boost::recursive_variant_ >, std::unordered_map< int, boost::recursive_variant_ >, std::unordered_map< std::string, boost::recursive_variant_ > >::type Variant
Possible types for parameters.
Definition Variant.hpp:67
bool is_none(Variant const &v)
Definition Variant.hpp:115
bool are_kT_equal(double old_kT, double new_kT)
Check that two kT values are close up to a small tolerance.
constexpr GammaType gamma_null
Value for a null friction coefficient.
static SteepestDescentParameters params
Currently active steepest descent instance.
GammaType gamma
Translational friction coefficient .
GammaType gamma_rotation
Rotational friction coefficient .
double gamma0
Friction coefficient of the particles .
double gammav
Friction coefficient for the box .
GammaType gamma_rotation
Rotational friction coefficient .
GammaType gamma
Translational friction coefficient .
Description and getter/setter for a parameter.
static constexpr const ReadOnly read_only