diff --git a/doc/sphinx/inter_non-bonded.rst b/doc/sphinx/inter_non-bonded.rst index 4a0de03ef31..877b07eb59d 100644 --- a/doc/sphinx/inter_non-bonded.rst +++ b/doc/sphinx/inter_non-bonded.rst @@ -18,23 +18,41 @@ explicitly set. A bonded interaction between a set of particles has to be specified explicitly by the command, while the command is used to define the interaction parameters. -.. _Isotropic non-bonded interactions: +Non-bonded interaction are configured via the +:class:`espressomd.interactions.NonBondedInteraction` class, +which is a member of :class:`espressomd.system.System`:: -Isotropic non-bonded interactions ---------------------------------- + system.non_bonded_inter[type1, type2] -Non-bonded interaction are configured via the :class:`espressomd.interactions.NonBondedInteraction` class, which is a member of :class:`espressomd.system.System`:: +This command defines an interaction between all particles of type ``type1`` +and ``type2``. All available interaction potentials and their parameters are +listed below. For example, the following adds a WCA potential between +particles of type 0:: - system.non_bonded_inter[type1, type2] + system.non_bonded_inter[0, 0].wca.set_params(epsilon=1., sigma=2.) + +Each type pair can have multiple potentials active at the same time. +To deactivate a specific potential for a given type pair, do:: + + system.non_bonded_inter[0, 0].wca.deactivate() + +To deactivate all potentials for a given type pair, do:: -This command defines an interaction between all particles of type ``type1`` and -``type2``. Possible interaction types and their parameters are -listed below. + system.non_bonded_inter[0, 0].reset() + +To deactivate all potentials between all type pairs, do:: + + system.non_bonded_inter.reset() For many non-bonded interactions, it is possible to artificially cap the forces, which often allows to equilibrate the system much faster. See the subsection :ref:`Capping the force during warmup` for more details. +.. _Isotropic non-bonded interactions: + +Isotropic non-bonded interactions +--------------------------------- + .. _Tabulated interaction: Tabulated interaction diff --git a/src/core/nonbonded_interactions/bmhtf-nacl.cpp b/src/core/nonbonded_interactions/bmhtf-nacl.cpp index e89fbf193df..df7975415d2 100644 --- a/src/core/nonbonded_interactions/bmhtf-nacl.cpp +++ b/src/core/nonbonded_interactions/bmhtf-nacl.cpp @@ -43,6 +43,9 @@ BMHTF_Parameters::BMHTF_Parameters(double a, double b, double c, double d, if (d < 0.) { throw std::domain_error("BMHTF parameter 'd' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("BMHTF parameter 'cutoff' has to be >= 0"); + } computed_shift = C / Utils::int_pow<6>(cut) + D / Utils::int_pow<8>(cut) - A * std::exp(B * (sig - cut)); } diff --git a/src/core/nonbonded_interactions/buckingham.cpp b/src/core/nonbonded_interactions/buckingham.cpp index e8febf5ff32..7fd90cdad50 100644 --- a/src/core/nonbonded_interactions/buckingham.cpp +++ b/src/core/nonbonded_interactions/buckingham.cpp @@ -45,6 +45,9 @@ Buckingham_Parameters::Buckingham_Parameters(double a, double b, double c, if (d < 0.) { throw std::domain_error("Buckingham parameter 'd' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("Buckingham parameter 'cutoff' has to be >= 0"); + } /* Replace the Buckingham potential for interatomic distance less than or equal to discontinuity by a straight line (F1+F2*r) */ diff --git a/src/core/nonbonded_interactions/gaussian.cpp b/src/core/nonbonded_interactions/gaussian.cpp index 97f0e8c20aa..76821cf4c11 100644 --- a/src/core/nonbonded_interactions/gaussian.cpp +++ b/src/core/nonbonded_interactions/gaussian.cpp @@ -29,13 +29,16 @@ #include -Gaussian_Parameters::Gaussian_Parameters(double eps, double sig, double cut) - : eps{eps}, sig{sig}, cut{cut} { +Gaussian_Parameters::Gaussian_Parameters(double eps, double sig, double cutoff) + : eps{eps}, sig{sig}, cut{cutoff} { if (eps < 0.) { throw std::domain_error("Gaussian parameter 'eps' has to be >= 0"); } if (sig < 0.) { throw std::domain_error("Gaussian parameter 'sig' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("Gaussian parameter 'cutoff' has to be >= 0"); + } } #endif // GAUSSIAN diff --git a/src/core/nonbonded_interactions/hat.cpp b/src/core/nonbonded_interactions/hat.cpp index ede5d20066e..00dd4661ecc 100644 --- a/src/core/nonbonded_interactions/hat.cpp +++ b/src/core/nonbonded_interactions/hat.cpp @@ -34,6 +34,9 @@ Hat_Parameters::Hat_Parameters(double F_max, double cutoff) if (F_max < 0.) { throw std::domain_error("Hat parameter 'F_max' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("Hat parameter 'cutoff' has to be >= 0"); + } } #endif // HAT diff --git a/src/core/nonbonded_interactions/hertzian.cpp b/src/core/nonbonded_interactions/hertzian.cpp index 4b3439f4982..9ee911d0757 100644 --- a/src/core/nonbonded_interactions/hertzian.cpp +++ b/src/core/nonbonded_interactions/hertzian.cpp @@ -34,6 +34,9 @@ Hertzian_Parameters::Hertzian_Parameters(double eps, double sig) if (eps < 0.) { throw std::domain_error("Hertzian parameter 'eps' has to be >= 0"); } + if (sig < 0.) { + throw std::domain_error("Hertzian parameter 'sig' has to be >= 0"); + } } #endif // HERTZIAN diff --git a/src/core/nonbonded_interactions/lj.cpp b/src/core/nonbonded_interactions/lj.cpp index f915e4acfba..afb8a63b341 100644 --- a/src/core/nonbonded_interactions/lj.cpp +++ b/src/core/nonbonded_interactions/lj.cpp @@ -27,31 +27,22 @@ #ifdef LENNARD_JONES #include "nonbonded_interaction_data.hpp" -#include - #include #include -LJ_Parameters::LJ_Parameters(double eps, double sig, double cut, double offset, - double min) - : LJ_Parameters(eps, sig, cut, offset, min, 0.) { - if (cut != 0.) { - auto const sig_cut = sig / cut; - shift = Utils::int_pow<6>(sig_cut) - Utils::int_pow<12>(sig_cut); - } -} - -LJ_Parameters::LJ_Parameters(double eps, double sig, double cut, double offset, - double min, double shift) - : eps{eps}, sig{sig}, cut{cut}, shift{shift}, offset{offset}, min{std::max( - min, - 0.)} { - if (eps < 0.) { +LJ_Parameters::LJ_Parameters(double epsilon, double sigma, double cutoff, + double offset, double min, double shift) + : eps{epsilon}, sig{sigma}, cut{cutoff}, shift{shift}, offset{offset}, + min{std::max(min, 0.)} { + if (epsilon < 0.) { throw std::domain_error("LJ parameter 'epsilon' has to be >= 0"); } - if (sig < 0.) { + if (sigma < 0.) { throw std::domain_error("LJ parameter 'sigma' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("LJ parameter 'cutoff' has to be >= 0"); + } } #endif /* ifdef LENNARD_JONES */ diff --git a/src/core/nonbonded_interactions/lj.hpp b/src/core/nonbonded_interactions/lj.hpp index b6651943e72..d95aaaea3ae 100644 --- a/src/core/nonbonded_interactions/lj.hpp +++ b/src/core/nonbonded_interactions/lj.hpp @@ -40,8 +40,7 @@ /** Calculate Lennard-Jones force factor */ inline double lj_pair_force_factor(IA_parameters const &ia_params, double dist) { - if ((dist < ia_params.lj.cut + ia_params.lj.offset) && - (dist > ia_params.lj.min + ia_params.lj.offset)) { + if (dist < ia_params.lj.max_cutoff() and dist > ia_params.lj.min_cutoff()) { auto const r_off = dist - ia_params.lj.offset; auto const frac6 = Utils::int_pow<6>(ia_params.lj.sig / r_off); return 48.0 * ia_params.lj.eps * frac6 * (frac6 - 0.5) / (r_off * dist); @@ -51,8 +50,7 @@ inline double lj_pair_force_factor(IA_parameters const &ia_params, /** Calculate Lennard-Jones energy */ inline double lj_pair_energy(IA_parameters const &ia_params, double dist) { - if ((dist < ia_params.lj.cut + ia_params.lj.offset) && - (dist > ia_params.lj.min + ia_params.lj.offset)) { + if (dist < ia_params.lj.max_cutoff() and dist > ia_params.lj.min_cutoff()) { auto const r_off = dist - ia_params.lj.offset; auto const frac6 = Utils::int_pow<6>(ia_params.lj.sig / r_off); return 4.0 * ia_params.lj.eps * diff --git a/src/core/nonbonded_interactions/ljcos.cpp b/src/core/nonbonded_interactions/ljcos.cpp index ba33702b446..1fa4d75e266 100644 --- a/src/core/nonbonded_interactions/ljcos.cpp +++ b/src/core/nonbonded_interactions/ljcos.cpp @@ -32,15 +32,18 @@ #include -LJcos_Parameters::LJcos_Parameters(double eps, double sig, double cut, +LJcos_Parameters::LJcos_Parameters(double epsilon, double sigma, double cutoff, double offset) - : eps{eps}, sig{sig}, cut{cut}, offset{offset} { - if (eps < 0.) { + : eps{epsilon}, sig{sigma}, cut{cutoff}, offset{offset} { + if (epsilon < 0.) { throw std::domain_error("LJcos parameter 'epsilon' has to be >= 0"); } - if (sig < 0.) { + if (sigma < 0.) { throw std::domain_error("LJcos parameter 'sigma' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("LJcos parameter 'cutoff' has to be >= 0"); + } auto const facsq = Utils::cbrt_2() * Utils::sqr(sig); rmin = sqrt(Utils::cbrt_2()) * sig; diff --git a/src/core/nonbonded_interactions/ljcos2.cpp b/src/core/nonbonded_interactions/ljcos2.cpp index 31ccb14196b..1f4539e26f0 100644 --- a/src/core/nonbonded_interactions/ljcos2.cpp +++ b/src/core/nonbonded_interactions/ljcos2.cpp @@ -30,18 +30,21 @@ #include #include -LJcos2_Parameters::LJcos2_Parameters(double eps, double sig, double offset, - double w) - : eps{eps}, sig{sig}, offset{offset}, w{w} { - if (eps < 0.) { +LJcos2_Parameters::LJcos2_Parameters(double epsilon, double sigma, + double offset, double width) + : eps{epsilon}, sig{sigma}, offset{offset}, w{width} { + if (epsilon < 0.) { throw std::domain_error("LJcos2 parameter 'epsilon' has to be >= 0"); } - if (sig < 0.) { + if (sigma < 0.) { throw std::domain_error("LJcos2 parameter 'sigma' has to be >= 0"); } - if (sig != 0.) { - rchange = std::pow(2., 1. / 6.) * sig; - cut = w + rchange; + if (width < 0.) { + throw std::domain_error("LJcos2 parameter 'width' has to be >= 0"); + } + if (sigma != 0.) { + rchange = std::pow(2., 1. / 6.) * sigma; + cut = width + rchange; } } diff --git a/src/core/nonbonded_interactions/ljgen.cpp b/src/core/nonbonded_interactions/ljgen.cpp index 51feb1bc448..d97e80f7258 100644 --- a/src/core/nonbonded_interactions/ljgen.cpp +++ b/src/core/nonbonded_interactions/ljgen.cpp @@ -46,6 +46,9 @@ LJGen_Parameters::LJGen_Parameters(double epsilon, double sigma, double cutoff, if (sigma < 0.) { throw std::domain_error("Generic LJ parameter 'sigma' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("Generic LJ parameter 'cutoff' has to be >= 0"); + } #ifdef LJGEN_SOFTCORE if (delta < 0.) { throw std::domain_error("Generic LJ parameter 'delta' has to be >= 0"); diff --git a/src/core/nonbonded_interactions/morse.cpp b/src/core/nonbonded_interactions/morse.cpp index f4465491b54..a4e4cfe0212 100644 --- a/src/core/nonbonded_interactions/morse.cpp +++ b/src/core/nonbonded_interactions/morse.cpp @@ -36,6 +36,9 @@ Morse_Parameters::Morse_Parameters(double eps, double alpha, double rmin, if (eps < 0.) { throw std::domain_error("Morse parameter 'eps' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("Morse parameter 'cutoff' has to be >= 0"); + } auto const add1 = std::exp(-2.0 * alpha * (cut - rmin)); auto const add2 = 2.0 * std::exp(-alpha * (cut - rmin)); rest = eps * (add1 - add2); diff --git a/src/core/nonbonded_interactions/nonbonded_interaction_data.hpp b/src/core/nonbonded_interactions/nonbonded_interaction_data.hpp index b778530f051..48a89767b33 100644 --- a/src/core/nonbonded_interactions/nonbonded_interaction_data.hpp +++ b/src/core/nonbonded_interactions/nonbonded_interaction_data.hpp @@ -28,6 +28,7 @@ #include "config.hpp" #include +#include #include #include @@ -49,10 +50,17 @@ struct LJ_Parameters { double offset = 0.0; double min = 0.0; LJ_Parameters() = default; - LJ_Parameters(double eps, double sig, double cut, double offset, double min); - LJ_Parameters(double eps, double sig, double cut, double offset, double min, - double shift); + LJ_Parameters(double epsilon, double sigma, double cutoff, double offset, + double min, double shift); + double get_auto_shift() const { + auto auto_shift = 0.; + if (cut != 0.) { + auto_shift = Utils::int_pow<6>(sig / cut) - Utils::int_pow<12>(sig / cut); + } + return auto_shift; + } double max_cutoff() const { return cut + offset; } + double min_cutoff() const { return min + offset; } }; /** WCA potential */ @@ -61,7 +69,7 @@ struct WCA_Parameters { double sig = 0.0; double cut = INACTIVE_CUTOFF; WCA_Parameters() = default; - WCA_Parameters(double eps, double sig); + WCA_Parameters(double epsilon, double sigma); double max_cutoff() const { return cut; } }; @@ -124,7 +132,7 @@ struct Gaussian_Parameters { double sig = 1.0; double cut = INACTIVE_CUTOFF; Gaussian_Parameters() = default; - Gaussian_Parameters(double eps, double sig, double cut); + Gaussian_Parameters(double eps, double sig, double cutoff); double max_cutoff() const { return cut; } }; @@ -202,7 +210,7 @@ struct LJcos_Parameters { double beta = 0.0; double rmin = 0.0; LJcos_Parameters() = default; - LJcos_Parameters(double eps, double sig, double cut, double offset); + LJcos_Parameters(double epsilon, double sigma, double cutoff, double offset); double max_cutoff() const { return cut + offset; } }; @@ -215,7 +223,7 @@ struct LJcos2_Parameters { double w = 0.0; double rchange = 0.0; LJcos2_Parameters() = default; - LJcos2_Parameters(double eps, double sig, double offset, double w); + LJcos2_Parameters(double epsilon, double sigma, double offset, double width); double max_cutoff() const { return cut + offset; } }; diff --git a/src/core/nonbonded_interactions/smooth_step.cpp b/src/core/nonbonded_interactions/smooth_step.cpp index fd9d8f16e0d..6c1b9ee7f93 100644 --- a/src/core/nonbonded_interactions/smooth_step.cpp +++ b/src/core/nonbonded_interactions/smooth_step.cpp @@ -36,6 +36,12 @@ SmoothStep_Parameters::SmoothStep_Parameters(double eps, double sig, if (eps < 0.) { throw std::domain_error("SmoothStep parameter 'eps' has to be >= 0"); } + if (sig < 0.) { + throw std::domain_error("SmoothStep parameter 'sig' has to be >= 0"); + } + if (cutoff < 0.) { + throw std::domain_error("SmoothStep parameter 'cutoff' has to be >= 0"); + } } #endif // SMOOTH_STEP diff --git a/src/core/nonbonded_interactions/soft_sphere.cpp b/src/core/nonbonded_interactions/soft_sphere.cpp index bfa8e44d928..84812c1f4f0 100644 --- a/src/core/nonbonded_interactions/soft_sphere.cpp +++ b/src/core/nonbonded_interactions/soft_sphere.cpp @@ -36,6 +36,9 @@ SoftSphere_Parameters::SoftSphere_Parameters(double a, double n, double cutoff, if (a < 0.) { throw std::domain_error("SoftSphere parameter 'a' has to be >= 0"); } + if (cutoff < 0.) { + throw std::domain_error("SoftSphere parameter 'cutoff' has to be >= 0"); + } if (offset < 0.) { throw std::domain_error("SoftSphere parameter 'offset' has to be >= 0"); } diff --git a/src/core/nonbonded_interactions/wca.cpp b/src/core/nonbonded_interactions/wca.cpp index 389bc65544a..4de3020b2ed 100644 --- a/src/core/nonbonded_interactions/wca.cpp +++ b/src/core/nonbonded_interactions/wca.cpp @@ -28,15 +28,16 @@ #include #include -WCA_Parameters::WCA_Parameters(double eps, double sig) : eps{eps}, sig{sig} { - if (eps < 0.) { +WCA_Parameters::WCA_Parameters(double epsilon, double sigma) + : eps{epsilon}, sig{sigma} { + if (epsilon < 0.) { throw std::domain_error("WCA parameter 'epsilon' has to be >= 0"); } - if (sig < 0.) { + if (sigma < 0.) { throw std::domain_error("WCA parameter 'sigma' has to be >= 0"); } - if (sig != 0.) { - cut = sig * std::pow(2., 1. / 6.); + if (sigma != 0.) { + cut = sigma * std::pow(2., 1. / 6.); } } diff --git a/src/python/espressomd/interactions.pyx b/src/python/espressomd/interactions.pyx index dda684e5983..36c2b25d1df 100644 --- a/src/python/espressomd/interactions.pyx +++ b/src/python/espressomd/interactions.pyx @@ -27,39 +27,50 @@ class NonBondedInteraction(ScriptInterfaceHelper): """ Represents an instance of a non-bonded interaction, such as Lennard-Jones. + Methods + ------- + deactivate() + Reset parameters for the interaction. + """ + _so_bind_methods = ("deactivate",) def __init__(self, **kwargs): if "sip" in kwargs: super().__init__(**kwargs) else: - self._validate(params=kwargs, check_required=True) + self._validate(kwargs) params = self.default_params() params.update(kwargs) super().__init__(**params) + self._validate_post(params) def __str__(self): return f'{self.__class__.__name__}({self.get_params()})' - def _validate(self, params, check_required=False): - # Check, if any key was passed, which is not known - keys = {x for x in params.keys() if x != "_types"} - utils.check_valid_keys(self.valid_keys(), keys) - # When an interaction is newly activated, all required keys must be - # given - if check_required: - utils.check_required_keys(self.required_keys(), params.keys()) + def _validate(self, params): + for key in self.required_keys(): + if key not in params: + raise RuntimeError( + f"{self.__class__.__name__} parameter '{key}' is missing") + + def _validate_post(self, params): + valid_parameters = self.valid_keys() + for key in params: + if key != "_types" and key not in valid_parameters: + raise RuntimeError( + f"Parameter '{key}' is not a valid {self.__class__.__name__} parameter") def set_params(self, **kwargs): - """Update the given parameters. + """Set new parameters. """ - self._validate(params=kwargs, check_required=not self.is_active()) - - params = self.get_params() + self._validate(kwargs) + params = self.default_params() params.update(kwargs) + self._validate_post(params) - err_msg = f"setting {self.type_name()} raised an error" + err_msg = f"setting {self.__class__.__name__} raised an error" self.call_method("set_params", handle_errors_message=err_msg, **params) def _serialize(self): @@ -72,26 +83,11 @@ class NonBondedInteraction(ScriptInterfaceHelper): raise Exception( "Subclasses of NonBondedInteraction must define the default_params() method.") - def is_active(self): - """Virtual method. - - """ - raise Exception( - "Subclasses of NonBondedInteraction must define the is_active() method.") - - def type_name(self): - """Virtual method. - - """ - raise Exception( - "Subclasses of NonBondedInteraction must define the type_name() method.") - def valid_keys(self): - """Virtual method. + """All parameters that can be set. """ - raise Exception( - "Subclasses of NonBondedInteraction must define the valid_keys() method.") + return set(self._valid_parameters()) def required_keys(self): """Virtual method. @@ -111,10 +107,7 @@ IF LENNARD_JONES == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -137,30 +130,12 @@ IF LENNARD_JONES == 1: _so_name = "Interactions::InteractionLJ" - def is_active(self): - """Check if interaction is active. - - """ - return self.epsilon > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"offset": 0., "min": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "LennardJones" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"epsilon", "sigma", "cutoff", "shift", "offset", "min"} - def required_keys(self): """Parameters that have to be set. @@ -177,10 +152,7 @@ IF WCA == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -193,27 +165,12 @@ IF WCA == 1: _so_name = "Interactions::InteractionWCA" - def is_active(self): - return self.epsilon > 0. - def default_params(self): """Python dictionary of default parameters. """ return {} - def type_name(self): - """Name of interaction type. - - """ - return "WCA" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"epsilon", "sigma"} - def required_keys(self): """Parameters that have to be set. @@ -234,10 +191,7 @@ IF LENNARD_JONES_GENERIC == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -272,12 +226,6 @@ IF LENNARD_JONES_GENERIC == 1: _so_name = "Interactions::InteractionLJGen" - def is_active(self): - """Check if interaction is active. - - """ - return self.epsilon > 0. - def default_params(self): """Python dictionary of default parameters. @@ -287,23 +235,6 @@ IF LENNARD_JONES_GENERIC == 1: ELSE: return {} - def type_name(self): - """Name of interaction type. - - """ - return "GenericLennardJones" - - def valid_keys(self): - """All parameters that can be set. - - """ - IF LJGEN_SOFTCORE: - return {"epsilon", "sigma", "cutoff", "shift", - "offset", "e1", "e2", "b1", "b2", "delta", "lam"} - ELSE: - return {"epsilon", "sigma", "cutoff", - "shift", "offset", "e1", "e2", "b1", "b2"} - def required_keys(self): """Parameters that have to be set. @@ -339,30 +270,12 @@ IF LJCOS == 1: _so_name = "Interactions::InteractionLJcos" - def is_active(self): - """Check if interactions is active. - - """ - return self.epsilon > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"offset": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "LennardJonesCos" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"epsilon", "sigma", "cutoff", "offset"} - def required_keys(self): """Parameters that have to be set. @@ -378,10 +291,7 @@ IF LJCOS2 == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -397,30 +307,12 @@ IF LJCOS2 == 1: _so_name = "Interactions::InteractionLJcos2" - def is_active(self): - """Check if interactions is active. - - """ - return self.epsilon > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"offset": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "LennardJonesCos2" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"epsilon", "sigma", "width", "offset"} - def required_keys(self): """Parameters that have to be set. @@ -440,10 +332,7 @@ IF HAT == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -456,18 +345,9 @@ IF HAT == 1: _so_name = "Interactions::InteractionHat" - def is_active(self): - return self.F_max > 0. - def default_params(self): return {} - def type_name(self): - return "Hat" - - def valid_keys(self): - return {"F_max", "cutoff"} - def required_keys(self): return {"F_max", "cutoff"} @@ -480,10 +360,7 @@ IF GAY_BERNE: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -507,30 +384,12 @@ IF GAY_BERNE: _so_name = "Interactions::InteractionGayBerne" - def is_active(self): - """Check if interaction is active. - - """ - return self.eps > 0. - def default_params(self): """Python dictionary of default parameters. """ return {} - def type_name(self): - """Name of interaction type. - - """ - return "GayBerne" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"eps", "sig", "cut", "k1", "k2", "mu", "nu"} - def required_keys(self): """Parameters that have to be set. @@ -546,10 +405,7 @@ IF TABULATED: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -566,30 +422,12 @@ IF TABULATED: _so_name = "Interactions::InteractionTabulated" - def is_active(self): - """Check if interaction is active. - - """ - return self.cutoff > 0 - def default_params(self): """Python dictionary of default parameters. """ return {} - def type_name(self): - """Name of the potential. - - """ - return "Tabulated" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"min", "max", "energy", "force"} - def required_keys(self): """Parameters that have to be set. @@ -609,10 +447,7 @@ IF DPD: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -637,9 +472,6 @@ IF DPD: _so_name = "Interactions::InteractionDPD" - def is_active(self): - return self.r_cut > 0. or self.trans_r_cut > 0. - def default_params(self): return { "weight_function": 0, @@ -650,13 +482,6 @@ IF DPD: "trans_gamma": 0.0, "trans_r_cut": -1.0} - def type_name(self): - return "DPD" - - def valid_keys(self): - return {"weight_function", "gamma", "k", "r_cut", - "trans_weight_function", "trans_gamma", "trans_r_cut"} - def required_keys(self): return set() @@ -669,10 +494,7 @@ IF SMOOTH_STEP == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -693,30 +515,12 @@ IF SMOOTH_STEP == 1: _so_name = "Interactions::InteractionSmoothStep" - def is_active(self): - """Check if interaction is active. - - """ - return self.eps > 0. and self.sig > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"n": 10, "k0": 0., "sig": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "SmoothStep" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"d", "n", "eps", "k0", "sig", "cutoff"} - def required_keys(self): """Parameters that have to be set. @@ -732,10 +536,7 @@ IF BMHTF_NACL == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -755,30 +556,12 @@ IF BMHTF_NACL == 1: _so_name = "Interactions::InteractionBMHTF" - def is_active(self): - """Check if interaction is active. - - """ - return self.a > 0. and self.c > 0. and self.d > 0. - def default_params(self): """Python dictionary of default parameters. """ return {} - def type_name(self): - """Name of interaction type. - - """ - return "BMHTF" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"a", "b", "c", "d", "sig", "cutoff"} - def required_keys(self): """Parameters that have to be set. @@ -794,10 +577,7 @@ IF MORSE == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -813,30 +593,12 @@ IF MORSE == 1: _so_name = "Interactions::InteractionMorse" - def is_active(self): - """Check if interaction is active. - - """ - return self.eps > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"cutoff": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "Morse" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"eps", "alpha", "rmin", "cutoff"} - def required_keys(self): """Parameters that have to be set. @@ -852,10 +614,7 @@ IF BUCKINGHAM == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -877,30 +636,12 @@ IF BUCKINGHAM == 1: _so_name = "Interactions::InteractionBuckingham" - def is_active(self): - """Check if interaction is active. - - """ - return self.a > 0. or self.b > 0. or self.d > 0. or self.shift > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"b": 0., "shift": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "Buckingham" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"a", "b", "c", "d", "discont", "cutoff", "shift"} - def required_keys(self): """Parameters that have to be set. @@ -916,10 +657,7 @@ IF SOFT_SPHERE == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -935,30 +673,12 @@ IF SOFT_SPHERE == 1: _so_name = "Interactions::InteractionSoftSphere" - def is_active(self): - """Check if interaction is active. - - """ - return self.a > 0. - def default_params(self): """Python dictionary of default parameters. """ return {"offset": 0.} - def type_name(self): - """Name of interaction type. - - """ - return "SoftSphere" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"a", "n", "cutoff", "offset"} - def required_keys(self): """Parameters that have to be set. @@ -974,10 +694,7 @@ IF HERTZIAN == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -989,30 +706,12 @@ IF HERTZIAN == 1: _so_name = "Interactions::InteractionHertzian" - def is_active(self): - """Check if interaction is active. - - """ - return self.eps > 0. - def default_params(self): """Python dictionary of default parameters. """ return {} - def type_name(self): - """Name of interaction type. - - """ - return "Hertzian" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"eps", "sig"} - def required_keys(self): """Parameters that have to be set. @@ -1028,10 +727,7 @@ IF GAUSSIAN == 1: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -1045,30 +741,12 @@ IF GAUSSIAN == 1: _so_name = "Interactions::InteractionGaussian" - def is_active(self): - """Check if interaction is active. - - """ - return self.eps > 0. - def default_params(self): """Python dictionary of default parameters. """ return {} - def type_name(self): - """Name of interaction type. - - """ - return "Gaussian" - - def valid_keys(self): - """All parameters that can be set. - - """ - return {"eps", "sig", "cutoff"} - def required_keys(self): """Parameters that have to be set. @@ -1084,10 +762,7 @@ IF THOLE: Methods ------- set_params() - Set or update parameters for the interaction. - Parameters marked as required become optional once the - interaction has been activated for the first time; - subsequent calls to this method update the existing values. + Set new parameters for the interaction. Parameters ---------- @@ -1106,18 +781,9 @@ IF THOLE: _so_name = "Interactions::InteractionThole" - def is_active(self): - return self.scaling_coeff != 0. - def default_params(self): return {} - def type_name(self): - return "Thole" - - def valid_keys(self): - return {"scaling_coeff", "q1q2"} - def required_keys(self): return {"scaling_coeff", "q1q2"} @@ -1155,6 +821,10 @@ class NonBondedInteractionHandle(ScriptInterfaceHelper): serialized.append((name, *obj._serialize())) return serialized + def reset(self): + for key in self._valid_parameters(): + getattr(self, key).deactivate() + @script_interface_register class NonBondedInteractions(ScriptInterfaceHelper): diff --git a/src/script_interface/interactions/NonBondedInteraction.hpp b/src/script_interface/interactions/NonBondedInteraction.hpp index fd76e16b4c3..effd77a3d26 100644 --- a/src/script_interface/interactions/NonBondedInteraction.hpp +++ b/src/script_interface/interactions/NonBondedInteraction.hpp @@ -47,6 +47,7 @@ namespace Interactions { template class InteractionPotentialInterface : public AutoParameters> { + /** @brief Particle type pair. */ std::array m_types = {-1, -1}; public: @@ -54,9 +55,16 @@ class InteractionPotentialInterface protected: using AutoParameters>::context; + /** @brief Managed object. */ std::shared_ptr m_ia_si; + /** @brief Pointer to the corresponding member in a handle. */ virtual CoreInteraction IA_parameters::*get_ptr_offset() const = 0; + /** @brief Create a new instance using the constructor with range checks. */ virtual void make_new_instance(VariantMap const ¶ms) = 0; + /** @brief Which parameter indicates whether the potential is inactive. */ + virtual std::string inactive_parameter() const { return "cutoff"; } + /** @brief Which magic value indicates the potential is inactive. */ + virtual double inactive_cutoff() const { return INACTIVE_CUTOFF; } template auto make_autoparameter(T CoreInteraction::*ptr, char const *name) { @@ -76,6 +84,14 @@ class InteractionPotentialInterface } return {}; } + if (name == "deactivate") { + m_ia_si = std::make_shared(); + if (m_types[0] != -1) { + copy_si_to_core(); + on_non_bonded_ia_change(); + } + return {}; + } if (name == "bind_types") { auto types = get_value>(params, "_types"); if (types[0] > types[1]) { @@ -99,20 +115,21 @@ class InteractionPotentialInterface } void do_construct(VariantMap const ¶ms) final { - if (params.empty()) { - m_ia_si = std::make_shared(); - } else if (params.count("_types") != 0) { + if (params.count("_types") != 0) { do_call_method("bind_types", params); m_ia_si = std::make_shared(); copy_core_to_si(); } else { - context()->parallel_try_catch( - [this, ¶ms]() { make_new_instance(params); }); + if (std::abs(get_value(params, inactive_parameter()) - + inactive_cutoff()) < 1e-9) { + m_ia_si = std::make_shared(); + } else { + context()->parallel_try_catch( + [this, ¶ms]() { make_new_instance(params); }); + } } } - auto const &get_ia() const { return *m_ia_si; } - void copy_si_to_core() { assert(m_ia_si != nullptr); auto const key = get_ia_param_key(m_types[0], m_types[1]); @@ -143,6 +160,9 @@ class InteractionWCA : public InteractionPotentialInterface<::WCA_Parameters> { }); } + std::string inactive_parameter() const override { return "sigma"; } + double inactive_cutoff() const override { return 0.; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( params, "epsilon", "sigma"); @@ -179,18 +199,20 @@ class InteractionLJ : public InteractionPotentialInterface<::LJ_Parameters> { } void make_new_instance(VariantMap const ¶ms) override { - if (auto const *shift = boost::get(¶ms.at("shift"))) { - if (*shift != "auto") { + auto new_params = params; + auto const *shift_string = boost::get(¶ms.at("shift")); + if (shift_string != nullptr) { + if (*shift_string != "auto") { throw std::invalid_argument( "LJ parameter 'shift' has to be 'auto' or a float"); } - m_ia_si = make_shared_from_args( - params, "epsilon", "sigma", "cutoff", "offset", "min"); - } else { - m_ia_si = make_shared_from_args( - params, "epsilon", "sigma", "cutoff", "offset", "min", "shift"); + new_params["shift"] = 0.; + } + m_ia_si = make_shared_from_args( + new_params, "epsilon", "sigma", "cutoff", "offset", "min", "shift"); + if (shift_string != nullptr) { + m_ia_si->shift = m_ia_si->get_auto_shift(); } } }; @@ -295,6 +317,9 @@ class InteractionLJcos2 }); } + std::string inactive_parameter() const override { return "sigma"; } + double inactive_cutoff() const override { return 0.; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( @@ -327,6 +352,9 @@ class InteractionHertzian make_autoparameter(&CoreInteraction::sig, "sig"), }); } + + std::string inactive_parameter() const override { return "sig"; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( params, "eps", "sig"); @@ -350,6 +378,7 @@ class InteractionGaussian make_autoparameter(&CoreInteraction::cut, "cutoff"), }); } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( params, "eps", "sig", "cutoff"); @@ -509,6 +538,8 @@ class InteractionGayBerne }); } + std::string inactive_parameter() const override { return "cut"; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( @@ -535,6 +566,8 @@ class InteractionTabulated }); } + std::string inactive_parameter() const override { return "max"; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args, std::vector>( @@ -580,6 +613,8 @@ class InteractionDPD : public InteractionPotentialInterface<::DPD_Parameters> { std::ignore = get_ptr_offset(); // for code coverage } + std::string inactive_parameter() const override { return "r_cut"; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( @@ -604,6 +639,10 @@ class InteractionThole make_autoparameter(&CoreInteraction::q1q2, "q1q2"), }); } + + std::string inactive_parameter() const override { return "scaling_coeff"; } + double inactive_cutoff() const override { return 0.; } + void make_new_instance(VariantMap const ¶ms) override { m_ia_si = make_shared_from_args( params, "scaling_coeff", "q1q2"); @@ -801,75 +840,65 @@ class NonBondedInteractionHandle auto const key = get_ia_param_key(m_types[0], m_types[1]); m_interaction = ::nonbonded_ia_params[key]; #ifdef WCA - set_member(m_wca, "wca", "Interactions::InteractionWCA", - params); + set_member(m_wca, "wca", "Interactions::InteractionWCA", params); #endif #ifdef LENNARD_JONES - set_member(m_lj, "lennard_jones", - "Interactions::InteractionLJ", params); + set_member(m_lj, "lennard_jones", "Interactions::InteractionLJ", params); #endif #ifdef LENNARD_JONES_GENERIC - set_member(m_ljgen, "generic_lennard_jones", - "Interactions::InteractionLJGen", params); + set_member(m_ljgen, "generic_lennard_jones", + "Interactions::InteractionLJGen", params); #endif #ifdef LJCOS - set_member(m_ljcos, "lennard_jones_cos", - "Interactions::InteractionLJcos", params); + set_member(m_ljcos, "lennard_jones_cos", "Interactions::InteractionLJcos", + params); #endif #ifdef LJCOS2 - set_member(m_ljcos2, "lennard_jones_cos2", - "Interactions::InteractionLJcos2", params); + set_member(m_ljcos2, "lennard_jones_cos2", + "Interactions::InteractionLJcos2", params); #endif #ifdef HERTZIAN - set_member( - m_hertzian, "hertzian", "Interactions::InteractionHertzian", params); + set_member(m_hertzian, "hertzian", "Interactions::InteractionHertzian", + params); #endif #ifdef GAUSSIAN - set_member( - m_gaussian, "gaussian", "Interactions::InteractionGaussian", params); + set_member(m_gaussian, "gaussian", "Interactions::InteractionGaussian", + params); #endif #ifdef BMHTF_NACL - set_member(m_bmhtf, "bmhtf", - "Interactions::InteractionBMHTF", params); + set_member(m_bmhtf, "bmhtf", "Interactions::InteractionBMHTF", params); #endif #ifdef MORSE - set_member(m_morse, "morse", - "Interactions::InteractionMorse", params); + set_member(m_morse, "morse", "Interactions::InteractionMorse", params); #endif #ifdef BUCKINGHAM - set_member(m_buckingham, "buckingham", - "Interactions::InteractionBuckingham", - params); + set_member(m_buckingham, "buckingham", + "Interactions::InteractionBuckingham", params); #endif #ifdef SOFT_SPHERE - set_member(m_soft_sphere, "soft_sphere", - "Interactions::InteractionSoftSphere", - params); + set_member(m_soft_sphere, "soft_sphere", + "Interactions::InteractionSoftSphere", params); #endif #ifdef HAT - set_member(m_hat, "hat", "Interactions::InteractionHat", - params); + set_member(m_hat, "hat", "Interactions::InteractionHat", params); #endif #ifdef GAY_BERNE - set_member( - m_gay_berne, "gay_berne", "Interactions::InteractionGayBerne", params); + set_member(m_gay_berne, "gay_berne", "Interactions::InteractionGayBerne", + params); #endif #ifdef TABULATED - set_member( - m_tabulated, "tabulated", "Interactions::InteractionTabulated", params); + set_member(m_tabulated, "tabulated", "Interactions::InteractionTabulated", + params); #endif #ifdef DPD - set_member(m_dpd, "dpd", "Interactions::InteractionDPD", - params); + set_member(m_dpd, "dpd", "Interactions::InteractionDPD", params); #endif #ifdef THOLE - set_member(m_thole, "thole", - "Interactions::InteractionThole", params); + set_member(m_thole, "thole", "Interactions::InteractionThole", params); #endif #ifdef SMOOTH_STEP - set_member(m_smooth_step, "smooth_step", - "Interactions::InteractionSmoothStep", - params); + set_member(m_smooth_step, "smooth_step", + "Interactions::InteractionSmoothStep", params); #endif } diff --git a/testsuite/python/collision_detection.py b/testsuite/python/collision_detection.py index 16b4236d332..308dddf28d0 100644 --- a/testsuite/python/collision_detection.py +++ b/testsuite/python/collision_detection.py @@ -309,8 +309,7 @@ def test_bind_at_point_of_collision_random(self): self.assertIn(base_particles, bonds) # Tidy - system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0, sigma=0, cutoff=0) + system.non_bonded_inter[0, 0].lennard_jones.deactivate() def run_test_glue_to_surface_for_pos(self, *positions): system = self.system @@ -578,8 +577,7 @@ def test_glue_to_surface_random(self): self.assertEqual(p.type, self.part_type_vs) # Tidy - system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0, sigma=0, cutoff=0) + system.non_bonded_inter[0, 0].lennard_jones.deactivate() def test_bind_three_particles(self): system = self.system diff --git a/testsuite/python/constraint_shape_based.py b/testsuite/python/constraint_shape_based.py index 48233a9b6df..775669ef745 100644 --- a/testsuite/python/constraint_shape_based.py +++ b/testsuite/python/constraint_shape_based.py @@ -383,8 +383,7 @@ def test_ellipsoid(self): energy = system.analysis.energy() self.assertAlmostEqual(energy["total"], r - 1.) # Reset the interaction to zero - system.non_bonded_inter[0, 1].generic_lennard_jones.set_params( - epsilon=0., sigma=0., cutoff=0., shift=0., offset=0., e1=0, e2=0, b1=0., b2=0.) + system.non_bonded_inter[0, 1].generic_lennard_jones.deactivate() def test_cylinder(self): """Tests if shape based constraints can be added to a system both by diff --git a/testsuite/python/cutoffs.py b/testsuite/python/cutoffs.py index 8afacd6c0bd..51c4ca0522e 100644 --- a/testsuite/python/cutoffs.py +++ b/testsuite/python/cutoffs.py @@ -56,8 +56,6 @@ def test(self): self.assertEqual(system.cell_system.interaction_range, -1) if espressomd.has_features("LENNARD_JONES"): - lj_off_params = system.non_bonded_inter[0, - 0].lennard_jones.get_params() system.non_bonded_inter[0, 0].lennard_jones.set_params( sigma=1, epsilon=1, cutoff=2.5, shift="auto") self.assertEqual( @@ -66,8 +64,7 @@ def test(self): system.cell_system.max_cut_nonbonded + system.cell_system.skin) - system.non_bonded_inter[0, - 0].lennard_jones.set_params(**lj_off_params) + system.non_bonded_inter[0, 0].lennard_jones.deactivate() self.assertEqual(system.cell_system.max_cut_nonbonded, -1) self.assertEqual(system.cell_system.interaction_range, -1) diff --git a/testsuite/python/dawaanr-and-bh-gpu.py b/testsuite/python/dawaanr-and-bh-gpu.py index 5f7d0fbacd3..f79ac3db0cb 100644 --- a/testsuite/python/dawaanr-and-bh-gpu.py +++ b/testsuite/python/dawaanr-and-bh-gpu.py @@ -67,8 +67,7 @@ def test(self): g.kill_particle_motion(rotation=True) system.integrator.set_vv() - system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0.0, sigma=0.0, cutoff=-1, shift=0.0) + system.non_bonded_inter[0, 0].lennard_jones.deactivate() system.cell_system.skin = 0.0 system.time_step = 0.01 diff --git a/testsuite/python/dawaanr-and-dds-gpu.py b/testsuite/python/dawaanr-and-dds-gpu.py index 37f386bbc8d..4e3a6499909 100644 --- a/testsuite/python/dawaanr-and-dds-gpu.py +++ b/testsuite/python/dawaanr-and-dds-gpu.py @@ -63,8 +63,7 @@ def test(self): g.kill_particle_motion(rotation=True) self.system.integrator.set_vv() - self.system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0.0, sigma=0.0, cutoff=0.0, shift=0.0) + self.system.non_bonded_inter[0, 0].lennard_jones.deactivate() self.system.cell_system.skin = 0.0 self.system.time_step = 0.01 diff --git a/testsuite/python/dds-and-bh-gpu.py b/testsuite/python/dds-and-bh-gpu.py index 4f3b19a8d10..99af4c509b9 100644 --- a/testsuite/python/dds-and-bh-gpu.py +++ b/testsuite/python/dds-and-bh-gpu.py @@ -68,8 +68,7 @@ def test(self): g.kill_particle_motion(rotation=True) system.integrator.set_vv() - system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0.0, sigma=0.0, cutoff=-1, shift=0.0) + system.non_bonded_inter[0, 0].lennard_jones.deactivate() system.cell_system.skin = 0.0 system.time_step = 0.01 diff --git a/testsuite/python/dipolar_direct_summation.py b/testsuite/python/dipolar_direct_summation.py index b39f9d9466d..3c2993502cd 100644 --- a/testsuite/python/dipolar_direct_summation.py +++ b/testsuite/python/dipolar_direct_summation.py @@ -150,8 +150,7 @@ def gen_reference_data(self, filepath_energy=OPEN_BOUNDARIES_REF_ENERGY, system.integrator.set_steepest_descent( f_max=1, gamma=0.001, max_displacement=0.01) system.integrator.run(100) - system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0.0, sigma=0, cutoff=0, shift=0) + system.non_bonded_inter[0, 0].lennard_jones.deactivate() system.integrator.set_vv() assert system.analysis.energy()["total"] == 0 diff --git a/testsuite/python/interactions_non-bonded_interface.py b/testsuite/python/interactions_non-bonded_interface.py index e04c0b509f4..793dac07572 100644 --- a/testsuite/python/interactions_non-bonded_interface.py +++ b/testsuite/python/interactions_non-bonded_interface.py @@ -28,9 +28,7 @@ class Test(ut.TestCase): system = espressomd.System(box_l=[30.0, 30.0, 30.0]) def tearDown(self): - if espressomd.has_features(["LENNARD_JONES"]): - self.system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0., sigma=0., cutoff=0., shift=0.) + self.system.non_bonded_inter.reset() def intersMatch(self, inType, outInter, inParams, outParams, msg_long): """Check, if the interaction type set and gotten back as well as the @@ -114,9 +112,9 @@ def func(self): self.intersMatch( interClass, outInter, params, outParams, - "{}: value set and value gotten back differ for particle types {} and {}: {} vs. {}" - .format(interClass(**params).type_name(), partType1, partType2, - params, outParams)) + f"{interClass.__name__}: value set and value gotten back " + f"differ for particle types {partType1} and {partType2}: " + f"{params} vs. {outParams}") self.parameterKeys(outInter) return func @@ -162,27 +160,42 @@ def func(self): "k2": 5.0, "mu": 2.0, "nu": 1.0}, "gay_berne") - @utx.skipIfMissingFeatures(["LENNARD_JONES", "WCA"]) - def test_set_params(self): + @utx.skipIfMissingFeatures(["LENNARD_JONES"]) + def test_reset(self): + lj_params_inactive = {"shift": 0., "sigma": 0., "epsilon": 0., + "cutoff": -1., "offset": 0., "min": 0.} + # global reset self.system.non_bonded_inter[0, 0].lennard_jones.set_params( epsilon=1., sigma=2., cutoff=3., shift="auto") self.system.non_bonded_inter.reset() self.assertEqual(self.system.non_bonded_inter[0, 0].lennard_jones.get_params(), - {'shift': 0., 'sigma': 0., 'epsilon': 0., - 'cutoff': -1., 'offset': 0., 'min': 0.}) + lj_params_inactive) + # handle reset + self.system.non_bonded_inter[0, 0].lennard_jones.set_params( + epsilon=1., sigma=2., cutoff=3., shift="auto") + self.system.non_bonded_inter[0, 0].reset() + self.assertEqual(self.system.non_bonded_inter[0, 0].lennard_jones.get_params(), + lj_params_inactive) + # potential reset + self.system.non_bonded_inter[0, 0].lennard_jones.set_params( + epsilon=1., sigma=2., cutoff=3., shift="auto") + self.system.non_bonded_inter[0, 0].lennard_jones.deactivate() + self.assertEqual(self.system.non_bonded_inter[0, 0].lennard_jones.get_params(), + lj_params_inactive) + + @utx.skipIfMissingFeatures(["WCA"]) + def test_set_params(self): wca = espressomd.interactions.WCAInteraction(epsilon=1., sigma=2.) - wca.set_params(epsilon=2.) + wca.set_params(epsilon=2., sigma=3.) self.assertEqual(wca.get_params()["epsilon"], 2.) + self.assertEqual(wca.get_params()["sigma"], 3.) self.system.non_bonded_inter[0, 0].wca = wca self.assertEqual( self.system.non_bonded_inter[0, 0].wca.get_params()["epsilon"], 2.) self.assertEqual(wca.get_params()["epsilon"], 2.) - wca.set_params(epsilon=3.) - self.assertEqual( - self.system.non_bonded_inter[0, 0].wca.get_params()["epsilon"], 3.) - self.assertEqual(wca.get_params()["epsilon"], 3.) + self.assertEqual(wca.get_params()["sigma"], 3.) self.system.non_bonded_inter.reset() - wca.set_params(epsilon=4.) + wca.set_params(epsilon=4., sigma=3.) self.assertEqual( self.system.non_bonded_inter[0, 0].wca.get_params()["epsilon"], 4.) self.assertEqual(wca.get_params()["epsilon"], 4.) @@ -191,22 +204,16 @@ def test_set_params(self): @utx.skipIfMissingFeatures("LENNARD_JONES") def test_exceptions(self): - err_msg_required = (r"The following keys have to be given as keyword arguments: " - r"\['cutoff', 'epsilon', 'shift', 'sigma'\], got " - r"\['epsilon', 'sigma'\] \(missing \['cutoff', 'shift'\]\)") - err_msg_valid = (r"Only the following keys can be given as keyword arguments: " - r"\['cutoff', 'epsilon', 'min', 'offset', 'shift', 'sigma'\], got " - r"\['cutoff', 'epsilon', 'shift', 'sigma', 'unknown'\] \(unknown \['unknown'\]\)") - with self.assertRaisesRegex(ValueError, err_msg_required): + with self.assertRaisesRegex(RuntimeError, "LennardJonesInteraction parameter 'shift' is missing"): espressomd.interactions.LennardJonesInteraction( - epsilon=1., sigma=2.) - with self.assertRaisesRegex(ValueError, err_msg_required): + epsilon=1., sigma=2., cutoff=2.) + with self.assertRaisesRegex(RuntimeError, "LennardJonesInteraction parameter 'shift' is missing"): self.system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=1., sigma=2.) - with self.assertRaisesRegex(ValueError, err_msg_valid): + epsilon=1., sigma=2., cutoff=2.) + with self.assertRaisesRegex(RuntimeError, "Parameter 'unknown' is not a valid LennardJonesInteraction parameter"): espressomd.interactions.LennardJonesInteraction( epsilon=1., sigma=2., cutoff=3., shift=4., unknown=5.) - with self.assertRaisesRegex(ValueError, err_msg_valid): + with self.assertRaisesRegex(RuntimeError, "Parameter 'unknown' is not a valid LennardJonesInteraction parameter"): self.system.non_bonded_inter[0, 0].lennard_jones.set_params( epsilon=1., sigma=2., cutoff=3., shift=4., unknown=5.) with self.assertRaisesRegex(ValueError, "LJ parameter 'shift' has to be 'auto' or a float"): @@ -220,11 +227,14 @@ def test_exceptions(self): max_ia_cutoff = min(box_l / node_grid) - skin * (n_nodes > 1) wrong_cutoff = 1.01 * max_ia_cutoff lennard_jones = self.system.non_bonded_inter[0, 0].lennard_jones - with self.assertRaisesRegex(Exception, "setting LennardJones raised an error: ERROR: interaction range .+ in direction [0-2] is larger than the local box size"): + with self.assertRaisesRegex(Exception, "setting LennardJonesInteraction raised an error: ERROR: interaction range .+ in direction [0-2] is larger than the local box size"): lennard_jones.set_params( epsilon=1., sigma=1., cutoff=wrong_cutoff, shift="auto") self.assertAlmostEqual( lennard_jones.get_params()['cutoff'], wrong_cutoff, delta=1e-10) + inter_00_obj = self.system.non_bonded_inter[0, 0] + self.assertEqual(inter_00_obj.call_method("get_types"), [0, 0]) + self.assertIsNone(inter_00_obj.call_method("unknown")) def check_potential_exceptions(self, ia_class, params, check_keys): for key in check_keys: @@ -235,6 +245,7 @@ def check_potential_exceptions(self, ia_class, params, check_keys): @utx.skipIfMissingFeatures("WCA") def test_wca_exceptions(self): + self.assertEqual(self.system.non_bonded_inter[0, 0].wca.cutoff, -1.) self.check_potential_exceptions( espressomd.interactions.WCAInteraction, {"epsilon": 1., "sigma": 1.}, @@ -245,11 +256,11 @@ def test_lj_exceptions(self): self.check_potential_exceptions( espressomd.interactions.LennardJonesInteraction, {"epsilon": 1., "sigma": 1., "cutoff": 1.5, "shift": 0.2}, - ("epsilon", "sigma")) + ("epsilon", "sigma", "cutoff")) @utx.skipIfMissingFeatures("LENNARD_JONES_GENERIC") def test_ljgen_exceptions(self): - check_keys = ("epsilon", "sigma") + check_keys = ("epsilon", "sigma", "cutoff") params = {"epsilon": 1., "sigma": 1., "cutoff": 1.5, "shift": 0.2, "offset": 0.1, "b1": 1., "b2": 1., "e1": 12., "e2": 6.} if espressomd.has_features(["LJGEN_SOFTCORE"]): @@ -260,7 +271,7 @@ def test_ljgen_exceptions(self): espressomd.interactions.GenericLennardJonesInteraction, params, check_keys) - with self.assertRaisesRegex(ValueError, f"Generic LJ parameter 'shift' has to be 'auto' or a float"): + with self.assertRaisesRegex(ValueError, "Generic LJ parameter 'shift' has to be 'auto' or a float"): invalid_params = params.copy() invalid_params["shift"] = "unknown" espressomd.interactions.GenericLennardJonesInteraction( @@ -271,21 +282,23 @@ def test_lj_cos_exceptions(self): self.check_potential_exceptions( espressomd.interactions.LennardJonesCosInteraction, {"epsilon": 1., "sigma": 1., "cutoff": 1.5, "offset": 0.2}, - ("epsilon", "sigma")) + ("epsilon", "sigma", "cutoff")) @utx.skipIfMissingFeatures("LJCOS2") def test_lj_cos2_exceptions(self): + self.assertEqual( + self.system.non_bonded_inter[0, 0].lennard_jones_cos2.cutoff, -1.) self.check_potential_exceptions( espressomd.interactions.LennardJonesCos2Interaction, {"epsilon": 1., "sigma": 1., "width": 1.5, "offset": 0.2}, - ("epsilon", "sigma")) + ("epsilon", "sigma", "width")) @utx.skipIfMissingFeatures("HERTZIAN") def test_hertzian_exceptions(self): self.check_potential_exceptions( espressomd.interactions.HertzianInteraction, {"eps": 1., "sig": 1.}, - ("eps",) + ("eps", "sig") ) @utx.skipIfMissingFeatures("GAUSSIAN") @@ -293,7 +306,7 @@ def test_gaussian_exceptions(self): self.check_potential_exceptions( espressomd.interactions.GaussianInteraction, {"eps": 1., "sig": 1., "cutoff": 1.5}, - ("eps", "sig") + ("eps", "sig", "cutoff") ) @utx.skipIfMissingFeatures("BMHTF_NACL") @@ -301,7 +314,7 @@ def test_bmhtf_exceptions(self): self.check_potential_exceptions( espressomd.interactions.BMHTFInteraction, {"a": 3., "b": 2., "c": 1., "d": 4., "sig": 0.13, "cutoff": 1.2}, - ("a", "c", "d") + ("a", "c", "d", "cutoff") ) @utx.skipIfMissingFeatures("MORSE") @@ -309,7 +322,7 @@ def test_morse_exceptions(self): self.check_potential_exceptions( espressomd.interactions.MorseInteraction, {"eps": 1., "alpha": 3., "rmin": 0.1, "cutoff": 1.2}, - ("eps",) + ("eps", "cutoff") ) @utx.skipIfMissingFeatures("BUCKINGHAM") @@ -318,7 +331,7 @@ def test_buckingham_exceptions(self): espressomd.interactions.BuckinghamInteraction, {"a": 2., "b": 3., "c": 5., "d": 4., "discont": 1., "cutoff": 2., "shift": 0.1}, - ("a", "b", "c", "d") + ("a", "b", "c", "d", "cutoff") ) @utx.skipIfMissingFeatures("SOFT_SPHERE") @@ -326,7 +339,7 @@ def test_soft_sphere_exceptions(self): self.check_potential_exceptions( espressomd.interactions.SoftSphereInteraction, {"a": 1., "n": 3., "cutoff": 1.1, "offset": 0.1}, - ("a", "offset") + ("a", "offset", "cutoff") ) @utx.skipIfMissingFeatures("HAT") @@ -334,7 +347,7 @@ def test_hat_exceptions(self): self.check_potential_exceptions( espressomd.interactions.HatInteraction, {"F_max": 10., "cutoff": 1.}, - ("F_max",) + ("F_max", "cutoff") ) @utx.skipIfMissingFeatures("SMOOTH_STEP") @@ -342,7 +355,7 @@ def test_smooth_step_exceptions(self): self.check_potential_exceptions( espressomd.interactions.SmoothStepInteraction, {"eps": 4., "sig": 3., "cutoff": 1., "d": 2., "n": 11, "k0": 2.}, - ("eps",) + ("eps", "sig", "cutoff") ) diff --git a/testsuite/python/p3m_fft.py b/testsuite/python/p3m_fft.py index 481fc865c4f..21f63440e16 100644 --- a/testsuite/python/p3m_fft.py +++ b/testsuite/python/p3m_fft.py @@ -65,7 +65,7 @@ def minimize(self): self.system.integrator.run(100) self.system.integrator.set_vv() self.system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0.0, sigma=1.0, cutoff=2) + epsilon=0.0, sigma=1.0, cutoff=2, shift="auto") def add_charged_particles(self): np.random.seed(seed=42) diff --git a/testsuite/python/save_checkpoint.py b/testsuite/python/save_checkpoint.py index aef41515bc5..1dd3047feef 100644 --- a/testsuite/python/save_checkpoint.py +++ b/testsuite/python/save_checkpoint.py @@ -161,7 +161,7 @@ # constraints system.constraints.add(shape=espressomd.shapes.Sphere(center=system.box_l / 2, radius=0.1), - particle_type=17) + particle_type=7) system.constraints.add( shape=espressomd.shapes.Wall( normal=[1. / np.sqrt(3)] * 3, dist=0.5)) @@ -231,12 +231,8 @@ epsilon=1.2, sigma=1.3, cutoff=2.0, shift=0.1) system.non_bonded_inter[3, 0].lennard_jones.set_params( epsilon=1.2, sigma=1.7, cutoff=2.0, shift=0.1) - system.non_bonded_inter[1, 17].lennard_jones.set_params( + system.non_bonded_inter[1, 7].lennard_jones.set_params( epsilon=1.2e5, sigma=1.7, cutoff=2.0, shift=0.1) - # add inactive interaction - system.non_bonded_inter[4, 4].lennard_jones.set_params( - epsilon=1.4, sigma=1.2, cutoff=1.5, shift=0.2, offset=0.1, min=0.2) - system.non_bonded_inter[4, 4].lennard_jones.set_params(cutoff=-2.) # bonded interactions harmonic_bond = espressomd.interactions.HarmonicBond(r_0=0.0, k=1.0) diff --git a/testsuite/python/test_checkpoint.py b/testsuite/python/test_checkpoint.py index 0aaba75e277..e9182c9bc7d 100644 --- a/testsuite/python/test_checkpoint.py +++ b/testsuite/python/test_checkpoint.py @@ -333,16 +333,12 @@ def test_integrator_SDM(self): def test_non_bonded_inter(self): params1 = system.non_bonded_inter[0, 0].lennard_jones.get_params() params2 = system.non_bonded_inter[3, 0].lennard_jones.get_params() - params3 = system.non_bonded_inter[4, 4].lennard_jones.get_params() reference1 = {'shift': 0.1, 'sigma': 1.3, 'epsilon': 1.2, 'cutoff': 2.0, 'offset': 0.0, 'min': 0.0} reference2 = {'shift': 0.1, 'sigma': 1.7, 'epsilon': 1.2, 'cutoff': 2.0, 'offset': 0.0, 'min': 0.0} - reference3 = {'shift': 0.2, 'sigma': 1.2, 'epsilon': 1.4, - 'cutoff': -2.0, 'offset': 0.1, 'min': 0.2} self.assertEqual(params1, reference1) self.assertEqual(params2, reference2) - self.assertEqual(params3, reference3) def test_bonded_inter(self): # check the ObjectHandle was correctly initialized (including MPI) @@ -630,7 +626,7 @@ def test_constraints(self): self.assertIsInstance(c[0].shape, espressomd.shapes.Sphere) self.assertAlmostEqual(c[0].shape.radius, 0.1, delta=1E-10) - self.assertEqual(c[0].particle_type, 17) + self.assertEqual(c[0].particle_type, 7) self.assertIsInstance(c[1].shape, espressomd.shapes.Wall) np.testing.assert_allclose(np.copy(c[1].shape.normal), diff --git a/testsuite/python/virtual_sites_relative.py b/testsuite/python/virtual_sites_relative.py index 78c5c4a3743..aa0a3b055af 100644 --- a/testsuite/python/virtual_sites_relative.py +++ b/testsuite/python/virtual_sites_relative.py @@ -37,8 +37,7 @@ def tearDown(self): self.system.part.clear() self.system.thermostat.turn_off() self.system.integrator.set_vv() - self.system.non_bonded_inter[0, 0].lennard_jones.set_params( - epsilon=0., sigma=0., cutoff=0., shift=0.) + self.system.non_bonded_inter[0, 0].lennard_jones.deactivate() self.system.virtual_sites = espressomd.virtual_sites.VirtualSitesOff() def multiply_quaternions(self, a, b):