From c93269fd2cf1b9f8dd26517f4ce0fd0315741a34 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:48:54 +0800 Subject: [PATCH 01/24] test(pt/dp): add universal uts for all models --- .../atomic_model/linear_atomic_model.py | 13 +- deepmd/dpmodel/descriptor/se_r.py | 2 +- deepmd/dpmodel/fitting/dipole_fitting.py | 1 + .../dpmodel/fitting/polarizability_fitting.py | 1 + deepmd/dpmodel/model/__init__.py | 4 + deepmd/dpmodel/output_def.py | 15 +- .../model/atomic_model/linear_atomic_model.py | 4 +- deepmd/pt/model/descriptor/se_r.py | 7 +- deepmd/pt/model/model/__init__.py | 3 + deepmd/pt/model/model/dipole_model.py | 29 +- deepmd/pt/model/model/dos_model.py | 13 + deepmd/pt/model/model/dp_zbl_model.py | 21 + deepmd/pt/model/model/ener_model.py | 21 + deepmd/pt/model/model/polar_model.py | 13 + deepmd/pt/model/task/dipole.py | 1 + deepmd/pt/model/task/polarizability.py | 1 + .../tests/common/dpmodel/test_output_def.py | 48 +- .../common/cases/atomic_model/atomic_model.py | 128 +++ .../common/cases/atomic_model/ener_model.py | 19 - .../common/cases/atomic_model/utils.py | 407 ++++++- .../zbl_tab_potential/H2O_tab_potential.txt | 1000 +++++++++++++++++ .../common/cases/descriptor/utils.py | 7 - .../common/cases/model/ener_model.py | 19 - .../universal/common/cases/model/model.py | 131 +++ .../universal/common/cases/model/utils.py | 405 ++++++- .../dpmodel/atomc_model/test_atomic_model.py | 254 +++++ .../atomc_model/test_ener_atomic_model.py | 39 - .../dpmodel/descriptor/test_descriptor.py | 238 ++-- .../universal/dpmodel/fitting/test_fitting.py | 82 +- .../dpmodel/model/test_ener_model.py | 39 - .../universal/dpmodel/model/test_model.py | 76 ++ .../pt/atomc_model/test_atomic_model.py | 254 +++++ .../pt/atomc_model/test_ener_atomic_model.py | 39 - .../pt/descriptor/test_descriptor.py | 127 +-- .../universal/pt/fitting/test_fitting.py | 58 +- .../universal/pt/model/test_ener_model.py | 48 - source/tests/universal/pt/model/test_model.py | 296 +++++ 37 files changed, 3370 insertions(+), 493 deletions(-) create mode 100644 source/tests/universal/common/cases/atomic_model/atomic_model.py delete mode 100644 source/tests/universal/common/cases/atomic_model/ener_model.py create mode 100644 source/tests/universal/common/cases/data/zbl_tab_potential/H2O_tab_potential.txt delete mode 100644 source/tests/universal/common/cases/model/ener_model.py create mode 100644 source/tests/universal/common/cases/model/model.py create mode 100644 source/tests/universal/dpmodel/atomc_model/test_atomic_model.py delete mode 100644 source/tests/universal/dpmodel/atomc_model/test_ener_atomic_model.py delete mode 100644 source/tests/universal/dpmodel/model/test_ener_model.py create mode 100644 source/tests/universal/dpmodel/model/test_model.py create mode 100644 source/tests/universal/pt/atomc_model/test_atomic_model.py delete mode 100644 source/tests/universal/pt/atomc_model/test_ener_atomic_model.py delete mode 100644 source/tests/universal/pt/model/test_ener_model.py create mode 100644 source/tests/universal/pt/model/test_model.py diff --git a/deepmd/dpmodel/atomic_model/linear_atomic_model.py b/deepmd/dpmodel/atomic_model/linear_atomic_model.py index c923be67b7..3751974291 100644 --- a/deepmd/dpmodel/atomic_model/linear_atomic_model.py +++ b/deepmd/dpmodel/atomic_model/linear_atomic_model.py @@ -196,11 +196,11 @@ def forward_atomic( ] ener_list = [] for i, model in enumerate(self.models): - mapping = self.mapping_list[i] + type_map_model = self.mapping_list[i] ener_list.append( model.forward_atomic( extended_coord, - mapping[extended_atype], + type_map_model[extended_atype], nlists_[i], mapping, fparam, @@ -414,7 +414,12 @@ def _compute_weight( ) numerator = np.sum( - pairwise_rr * np.exp(-pairwise_rr / self.smin_alpha), axis=-1 + np.where( + nlist_larger != -1, + pairwise_rr * np.exp(-pairwise_rr / self.smin_alpha), + np.zeros_like(nlist_larger), + ), + axis=-1, ) # masked nnei will be zero, no need to handle denominator = np.sum( np.where( @@ -436,5 +441,7 @@ def _compute_weight( smooth = -6 * u**5 + 15 * u**4 - 10 * u**3 + 1 coef[mid_mask] = smooth[mid_mask] coef[right_mask] = 0 + # to handle masked atoms + coef = np.where(sigma != 0, coef, np.zeros_like(coef)) self.zbl_weight = coef return [1 - np.expand_dims(coef, -1), np.expand_dims(coef, -1)] diff --git a/deepmd/dpmodel/descriptor/se_r.py b/deepmd/dpmodel/descriptor/se_r.py index 938826d16c..5a037f5060 100644 --- a/deepmd/dpmodel/descriptor/se_r.py +++ b/deepmd/dpmodel/descriptor/se_r.py @@ -194,7 +194,7 @@ def get_dim_out(self): def get_dim_emb(self): """Returns the embedding (g2) dimension of this descriptor.""" - raise NotImplementedError + return self.neuron[-1] def get_rcut(self): """Returns cutoff radius.""" diff --git a/deepmd/dpmodel/fitting/dipole_fitting.py b/deepmd/dpmodel/fitting/dipole_fitting.py index f922b57367..ed42638f86 100644 --- a/deepmd/dpmodel/fitting/dipole_fitting.py +++ b/deepmd/dpmodel/fitting/dipole_fitting.py @@ -175,6 +175,7 @@ def output_def(self): reduciable=True, r_differentiable=self.r_differentiable, c_differentiable=self.c_differentiable, + rot_invariant=False, ), ] ) diff --git a/deepmd/dpmodel/fitting/polarizability_fitting.py b/deepmd/dpmodel/fitting/polarizability_fitting.py index 67b4888c67..4b31f2ba07 100644 --- a/deepmd/dpmodel/fitting/polarizability_fitting.py +++ b/deepmd/dpmodel/fitting/polarizability_fitting.py @@ -218,6 +218,7 @@ def output_def(self): reduciable=True, r_differentiable=False, c_differentiable=False, + rot_invariant=False, ), ] ) diff --git a/deepmd/dpmodel/model/__init__.py b/deepmd/dpmodel/model/__init__.py index 7cd68dea60..431c0da6ee 100644 --- a/deepmd/dpmodel/model/__init__.py +++ b/deepmd/dpmodel/model/__init__.py @@ -15,6 +15,9 @@ from .dp_model import ( DPModelCommon, ) +from .ener_model import ( + EnergyModel, +) from .make_model import ( make_model, ) @@ -23,6 +26,7 @@ ) __all__ = [ + "EnergyModel", "DPModelCommon", "SpinModel", "make_model", diff --git a/deepmd/dpmodel/output_def.py b/deepmd/dpmodel/output_def.py index 1c17fae432..df9350d876 100644 --- a/deepmd/dpmodel/output_def.py +++ b/deepmd/dpmodel/output_def.py @@ -186,6 +186,8 @@ class OutputVariableDef: If hessian is requred magnetic : bool If the derivatives of variable have magnetic parts. + rot_invariant : bool + If the variable is rotationally invariant. """ def __init__( @@ -199,6 +201,7 @@ def __init__( category: int = OutputVariableCategory.OUT.value, r_hessian: bool = False, magnetic: bool = False, + rot_invariant: bool = True, ): self.name = name self.shape = list(shape) @@ -218,6 +221,7 @@ def __init__( self.category = category self.r_hessian = r_hessian self.magnetic = magnetic + self.rot_invariant = rot_invariant if self.r_hessian: if not self.reduciable: raise ValueError("only reduciable variable can calculate hessian") @@ -228,6 +232,11 @@ def __init__( def size(self): return self.output_size + def squeeze(self, dim): + # squeeze the shape on given dimension + if -len(self.shape) <= dim < len(self.shape) != 1 and self.shape[dim] == 1: + self.shape.pop(dim) + class FittingOutputDef: """Defines the shapes and other properties of the fitting network outputs. @@ -306,7 +315,6 @@ def __getitem__( def get_data( self, - key: str, ) -> Dict[str, OutputVariableDef]: return self.var_defs @@ -417,6 +425,7 @@ def do_reduce( c_differentiable=False, atomic=False, category=apply_operation(vv, OutputVariableOperation.REDU), + rot_invariant=vv.rot_invariant, ) return def_redu @@ -465,6 +474,7 @@ def do_derivative( c_differentiable=False, atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_R), + rot_invariant=False, ) if vv.magnetic: def_derv_r[rkrm] = OutputVariableDef( @@ -478,6 +488,7 @@ def do_derivative( atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_R), magnetic=True, + rot_invariant=False, ) if vv.c_differentiable: @@ -490,6 +501,7 @@ def do_derivative( c_differentiable=False, atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_C), + rot_invariant=False, ) if vv.magnetic: def_derv_r[rkcm] = OutputVariableDef( @@ -501,5 +513,6 @@ def do_derivative( atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_C), magnetic=True, + rot_invariant=False, ) return def_derv_r, def_derv_c diff --git a/deepmd/pt/model/atomic_model/linear_atomic_model.py b/deepmd/pt/model/atomic_model/linear_atomic_model.py index 7c619a0424..1e1c60dcd3 100644 --- a/deepmd/pt/model/atomic_model/linear_atomic_model.py +++ b/deepmd/pt/model/atomic_model/linear_atomic_model.py @@ -224,12 +224,12 @@ def forward_atomic( ener_list = [] for i, model in enumerate(self.models): - mapping = self.mapping_list[i] + type_map_model = self.mapping_list[i] # apply bias to each individual model ener_list.append( model.forward_common_atomic( extended_coord, - mapping[extended_atype], + type_map_model[extended_atype], nlists_[i], mapping, fparam, diff --git a/deepmd/pt/model/descriptor/se_r.py b/deepmd/pt/model/descriptor/se_r.py index e6ebe53c26..eb0c42f8df 100644 --- a/deepmd/pt/model/descriptor/se_r.py +++ b/deepmd/pt/model/descriptor/se_r.py @@ -157,8 +157,8 @@ def get_dim_out(self) -> int: return self.neuron[-1] def get_dim_emb(self) -> int: - """Returns the output dimension.""" - raise NotImplementedError + """Returns the embedding (g2) dimension of this descriptor.""" + return self.neuron[-1] def get_dim_in(self) -> int: """Returns the input dimension.""" @@ -305,6 +305,7 @@ def forward( atype_ext: torch.Tensor, nlist: torch.Tensor, mapping: Optional[torch.Tensor] = None, + comm_dict: Optional[Dict[str, torch.Tensor]] = None, ): """Compute the descriptor. @@ -318,6 +319,8 @@ def forward( The neighbor list. shape: nf x nloc x nnei mapping The index mapping, not required by this descriptor. + comm_dict + The data needed for communication for parallel inference. Returns ------- diff --git a/deepmd/pt/model/model/__init__.py b/deepmd/pt/model/model/__init__.py index 586e3f4a6e..75883ffcdc 100644 --- a/deepmd/pt/model/model/__init__.py +++ b/deepmd/pt/model/model/__init__.py @@ -210,6 +210,9 @@ def get_model(model_params): "get_model", "DPModelCommon", "EnergyModel", + "DipoleModel", + "PolarModel", + "DOSModel", "FrozenModel", "SpinModel", "SpinEnergyModel", diff --git a/deepmd/pt/model/model/dipole_model.py b/deepmd/pt/model/model/dipole_model.py index b73976432b..2d732c2800 100644 --- a/deepmd/pt/model/model/dipole_model.py +++ b/deepmd/pt/model/model/dipole_model.py @@ -1,4 +1,7 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Dict, Optional, @@ -35,6 +38,24 @@ def __init__( DPModelCommon.__init__(self) DPDOSModel_.__init__(self, *args, **kwargs) + def translated_output_def(self): + out_def_data = self.model_output_def().get_data() + output_def = { + "dipole": deepcopy(out_def_data["dipole"]), + "global_dipole": deepcopy(out_def_data["dipole_redu"]), + } + if self.do_grad_r("dipole"): + output_def["force"] = deepcopy(out_def_data["dipole_derv_r"]) + output_def["force"].squeeze(-2) + if self.do_grad_c("dipole"): + output_def["virial"] = deepcopy(out_def_data["dipole_derv_c_redu"]) + output_def["virial"].squeeze(-2) + output_def["atom_virial"] = deepcopy(out_def_data["dipole_derv_c"]) + output_def["atom_virial"].squeeze(-3) + if "mask" in out_def_data: + output_def["mask"] = deepcopy(out_def_data["mask"]) + return output_def + def forward( self, coord, @@ -96,13 +117,13 @@ def forward_lower( model_predict["dipole"] = model_ret["dipole"] model_predict["global_dipole"] = model_ret["dipole_redu"] if self.do_grad_r("dipole"): - model_predict["force"] = model_ret["dipole_derv_r"].squeeze(-2) + model_predict["extended_force"] = model_ret["dipole_derv_r"].squeeze(-2) if self.do_grad_c("dipole"): model_predict["virial"] = model_ret["dipole_derv_c_redu"].squeeze(-2) if do_atomic_virial: - model_predict["atom_virial"] = model_ret["dipole_derv_c"].squeeze( - -3 - ) + model_predict["extended_virial"] = model_ret[ + "dipole_derv_c" + ].squeeze(-3) else: model_predict = model_ret return model_predict diff --git a/deepmd/pt/model/model/dos_model.py b/deepmd/pt/model/model/dos_model.py index 24095002d1..0dd6af7b80 100644 --- a/deepmd/pt/model/model/dos_model.py +++ b/deepmd/pt/model/model/dos_model.py @@ -1,4 +1,7 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Dict, Optional, @@ -35,6 +38,16 @@ def __init__( DPModelCommon.__init__(self) DPDOSModel_.__init__(self, *args, **kwargs) + def translated_output_def(self): + out_def_data = self.model_output_def().get_data() + output_def = { + "atom_dos": deepcopy(out_def_data["dos"]), + "dos": deepcopy(out_def_data["dos_redu"]), + } + if "mask" in out_def_data: + output_def["mask"] = deepcopy(out_def_data["mask"]) + return output_def + def forward( self, coord, diff --git a/deepmd/pt/model/model/dp_zbl_model.py b/deepmd/pt/model/model/dp_zbl_model.py index 45b76d1da6..4d7c16eb7d 100644 --- a/deepmd/pt/model/model/dp_zbl_model.py +++ b/deepmd/pt/model/model/dp_zbl_model.py @@ -1,4 +1,7 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Dict, List, @@ -39,6 +42,24 @@ def __init__( ): super().__init__(*args, **kwargs) + def translated_output_def(self): + out_def_data = self.model_output_def().get_data() + output_def = { + "atom_energy": deepcopy(out_def_data["energy"]), + "energy": deepcopy(out_def_data["energy_redu"]), + } + if self.do_grad_r("energy"): + output_def["force"] = deepcopy(out_def_data["energy_derv_r"]) + output_def["force"].squeeze(-2) + if self.do_grad_c("energy"): + output_def["virial"] = deepcopy(out_def_data["energy_derv_c_redu"]) + output_def["virial"].squeeze(-2) + output_def["atom_virial"] = deepcopy(out_def_data["energy_derv_c"]) + output_def["atom_virial"].squeeze(-3) + if "mask" in out_def_data: + output_def["mask"] = deepcopy(out_def_data["mask"]) + return output_def + def forward( self, coord, diff --git a/deepmd/pt/model/model/ener_model.py b/deepmd/pt/model/model/ener_model.py index 5256e42bb3..fb16478bc0 100644 --- a/deepmd/pt/model/model/ener_model.py +++ b/deepmd/pt/model/model/ener_model.py @@ -1,4 +1,7 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Dict, Optional, @@ -35,6 +38,24 @@ def __init__( DPModelCommon.__init__(self) DPEnergyModel_.__init__(self, *args, **kwargs) + def translated_output_def(self): + out_def_data = self.model_output_def().get_data() + output_def = { + "atom_energy": deepcopy(out_def_data["energy"]), + "energy": deepcopy(out_def_data["energy_redu"]), + } + if self.do_grad_r("energy"): + output_def["force"] = deepcopy(out_def_data["energy_derv_r"]) + output_def["force"].squeeze(-2) + if self.do_grad_c("energy"): + output_def["virial"] = deepcopy(out_def_data["energy_derv_c_redu"]) + output_def["virial"].squeeze(-2) + output_def["atom_virial"] = deepcopy(out_def_data["energy_derv_c"]) + output_def["atom_virial"].squeeze(-3) + if "mask" in out_def_data: + output_def["mask"] = deepcopy(out_def_data["mask"]) + return output_def + def forward( self, coord, diff --git a/deepmd/pt/model/model/polar_model.py b/deepmd/pt/model/model/polar_model.py index aa2a90aa4d..449fdbe700 100644 --- a/deepmd/pt/model/model/polar_model.py +++ b/deepmd/pt/model/model/polar_model.py @@ -1,4 +1,7 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Dict, Optional, @@ -35,6 +38,16 @@ def __init__( DPModelCommon.__init__(self) DPDOSModel_.__init__(self, *args, **kwargs) + def translated_output_def(self): + out_def_data = self.model_output_def().get_data() + output_def = { + "polar": deepcopy(out_def_data["polarizability"]), + "global_polar": deepcopy(out_def_data["polarizability_redu"]), + } + if "mask" in out_def_data: + output_def["mask"] = deepcopy(out_def_data["mask"]) + return output_def + def forward( self, coord, diff --git a/deepmd/pt/model/task/dipole.py b/deepmd/pt/model/task/dipole.py index 917af1bdcc..dcc16c12c9 100644 --- a/deepmd/pt/model/task/dipole.py +++ b/deepmd/pt/model/task/dipole.py @@ -145,6 +145,7 @@ def output_def(self) -> FittingOutputDef: reduciable=True, r_differentiable=self.r_differentiable, c_differentiable=self.c_differentiable, + rot_invariant=False, ), ] ) diff --git a/deepmd/pt/model/task/polarizability.py b/deepmd/pt/model/task/polarizability.py index 66120a1523..e3f5cb180a 100644 --- a/deepmd/pt/model/task/polarizability.py +++ b/deepmd/pt/model/task/polarizability.py @@ -219,6 +219,7 @@ def output_def(self) -> FittingOutputDef: reduciable=True, r_differentiable=False, c_differentiable=False, + rot_invariant=False, ), ] ) diff --git a/source/tests/common/dpmodel/test_output_def.py b/source/tests/common/dpmodel/test_output_def.py index 27fa54ea4c..9430799213 100644 --- a/source/tests/common/dpmodel/test_output_def.py +++ b/source/tests/common/dpmodel/test_output_def.py @@ -80,10 +80,19 @@ def test_model_output_def(self): c_differentiable=False, atomic=True, ), + OutputVariableDef( + "foo2", + [3], + reduciable=False, + r_differentiable=False, + c_differentiable=False, + atomic=True, + rot_invariant=False, + ), ] # fitting definition fd = FittingOutputDef(defs) - expected_keys = ["energy", "energy2", "energy3", "dos", "foo"] + expected_keys = ["energy", "energy2", "energy3", "dos", "foo", "foo2"] self.assertEqual( set(expected_keys), set(fd.keys()), @@ -94,18 +103,21 @@ def test_model_output_def(self): self.assertEqual(fd["energy3"].shape, [1]) self.assertEqual(fd["dos"].shape, [10]) self.assertEqual(fd["foo"].shape, [3]) + self.assertEqual(fd["foo2"].shape, [3]) # atomic self.assertEqual(fd["energy"].atomic, True) self.assertEqual(fd["energy2"].atomic, True) self.assertEqual(fd["energy3"].atomic, True) self.assertEqual(fd["dos"].atomic, True) self.assertEqual(fd["foo"].atomic, True) + self.assertEqual(fd["foo2"].atomic, True) # reduce self.assertEqual(fd["energy"].reduciable, True) self.assertEqual(fd["energy2"].reduciable, True) self.assertEqual(fd["energy3"].reduciable, True) self.assertEqual(fd["dos"].reduciable, True) self.assertEqual(fd["foo"].reduciable, False) + self.assertEqual(fd["foo2"].reduciable, False) # derivative self.assertEqual(fd["energy"].r_differentiable, True) self.assertEqual(fd["energy"].c_differentiable, True) @@ -118,14 +130,24 @@ def test_model_output_def(self): self.assertEqual(fd["energy3"].r_hessian, False) self.assertEqual(fd["dos"].r_differentiable, False) self.assertEqual(fd["foo"].r_differentiable, False) + self.assertEqual(fd["foo2"].r_differentiable, False) self.assertEqual(fd["dos"].c_differentiable, False) self.assertEqual(fd["foo"].c_differentiable, False) + self.assertEqual(fd["foo2"].c_differentiable, False) # magnetic self.assertEqual(fd["energy"].magnetic, False) self.assertEqual(fd["energy2"].magnetic, False) self.assertEqual(fd["energy3"].magnetic, True) self.assertEqual(fd["dos"].magnetic, False) self.assertEqual(fd["foo"].magnetic, False) + self.assertEqual(fd["foo2"].magnetic, False) + # rot_invariant + self.assertEqual(fd["energy"].rot_invariant, True) + self.assertEqual(fd["energy2"].rot_invariant, True) + self.assertEqual(fd["energy3"].rot_invariant, True) + self.assertEqual(fd["dos"].rot_invariant, True) + self.assertEqual(fd["foo"].rot_invariant, True) + self.assertEqual(fd["foo2"].rot_invariant, False) # model definition md = ModelOutputDef(fd) expected_keys = [ @@ -134,6 +156,7 @@ def test_model_output_def(self): "energy3", "dos", "foo", + "foo2", "energy_redu", "energy_derv_r", "energy_derv_c", @@ -165,6 +188,7 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].reduciable, True) self.assertEqual(md["dos"].reduciable, True) self.assertEqual(md["foo"].reduciable, False) + self.assertEqual(md["foo2"].reduciable, False) # derivative self.assertEqual(md["energy"].r_differentiable, True) self.assertEqual(md["energy"].c_differentiable, True) @@ -177,8 +201,10 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].r_hessian, False) self.assertEqual(md["dos"].r_differentiable, False) self.assertEqual(md["foo"].r_differentiable, False) + self.assertEqual(md["foo2"].r_differentiable, False) self.assertEqual(md["dos"].c_differentiable, False) self.assertEqual(md["foo"].c_differentiable, False) + self.assertEqual(md["foo2"].c_differentiable, False) # shape self.assertEqual(md["mask"].shape, [1]) self.assertEqual(md["mask_mag"].shape, [1]) @@ -187,6 +213,7 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].shape, [1]) self.assertEqual(md["dos"].shape, [10]) self.assertEqual(md["foo"].shape, [3]) + self.assertEqual(md["foo2"].shape, [3]) self.assertEqual(md["energy_redu"].shape, [1]) self.assertEqual(md["energy_derv_r"].shape, [1, 3]) self.assertEqual(md["energy_derv_c"].shape, [1, 9]) @@ -206,6 +233,7 @@ def test_model_output_def(self): self.assertEqual(md["energy2"].atomic, True) self.assertEqual(md["dos"].atomic, True) self.assertEqual(md["foo"].atomic, True) + self.assertEqual(md["foo2"].atomic, True) self.assertEqual(md["energy_redu"].atomic, False) self.assertEqual(md["energy_derv_r"].atomic, True) self.assertEqual(md["energy_derv_c"].atomic, True) @@ -229,6 +257,7 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].category, OutputVariableCategory.OUT) self.assertEqual(md["dos"].category, OutputVariableCategory.OUT) self.assertEqual(md["foo"].category, OutputVariableCategory.OUT) + self.assertEqual(md["foo2"].category, OutputVariableCategory.OUT) self.assertEqual(md["energy_redu"].category, OutputVariableCategory.REDU) self.assertEqual(md["energy_derv_r"].category, OutputVariableCategory.DERV_R) self.assertEqual(md["energy_derv_c"].category, OutputVariableCategory.DERV_C) @@ -273,6 +302,9 @@ def test_model_output_def(self): self.assertEqual(md["foo"].category & OVO.REDU, 0) self.assertEqual(md["foo"].category & OVO.DERV_R, 0) self.assertEqual(md["foo"].category & OVO.DERV_C, 0) + self.assertEqual(md["foo2"].category & OVO.REDU, 0) + self.assertEqual(md["foo2"].category & OVO.DERV_R, 0) + self.assertEqual(md["foo2"].category & OVO.DERV_C, 0) # flag: energy self.assertEqual( md["energy_redu"].category & OVO.REDU, @@ -759,3 +791,17 @@ def test_check_var(self): check_var(np.zeros([2, 3, 4]), var_def) self.assertIn("shape not matching", context.exception) check_var(np.zeros([2, 2, 8]), var_def) + + def test_squeeze(self): + out_var = OutputVariableDef("foo", [1]) + out_var.squeeze(0) + self.assertEqual(out_var.shape, [1]) + out_var = OutputVariableDef("foo", [1, 1]) + out_var.squeeze(0) + self.assertEqual(out_var.shape, [1]) + out_var = OutputVariableDef("foo", [1, 3]) + out_var.squeeze(0) + self.assertEqual(out_var.shape, [3]) + out_var = OutputVariableDef("foo", [3, 3]) + out_var.squeeze(0) + self.assertEqual(out_var.shape, [3, 3]) diff --git a/source/tests/universal/common/cases/atomic_model/atomic_model.py b/source/tests/universal/common/cases/atomic_model/atomic_model.py new file mode 100644 index 0000000000..6c1790483e --- /dev/null +++ b/source/tests/universal/common/cases/atomic_model/atomic_model.py @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later + +import os + +from .....seed import ( + GLOBAL_SEED, +) +from .utils import ( + AtomicModelTestCase, +) + +CUR_DIR = os.path.dirname(__file__) + + +class EnerAtomicModelTest(AtomicModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["energy", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + + +class DipoleAtomicModelTest(AtomicModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["dipole", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + + +class PolarAtomicModelTest(AtomicModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["polarizability", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + + +class DosAtomicModelTest(AtomicModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["dos", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + + +class ZBLAtomicModelTest(AtomicModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["O", "H", "B"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [] + self.expected_aparam_nall = False + self.expected_model_output_type = ["energy", "mask"] + self.expected_sel = [46, 92, 10] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + self.tab_file = { + "use_srtab": f"{CUR_DIR}/../data/zbl_tab_potential/H2O_tab_potential.txt", + "smin_alpha": 0.1, + "sw_rmin": 0.2, + "sw_rmax": 4.0, + } diff --git a/source/tests/universal/common/cases/atomic_model/ener_model.py b/source/tests/universal/common/cases/atomic_model/ener_model.py deleted file mode 100644 index b1e2f75cc7..0000000000 --- a/source/tests/universal/common/cases/atomic_model/ener_model.py +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later - - -from .utils import ( - AtomicModelTestCase, -) - - -class EnerAtomicModelTest(AtomicModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.expected_sel = [8, 12] - self.expected_has_message_passing = False diff --git a/source/tests/universal/common/cases/atomic_model/utils.py b/source/tests/universal/common/cases/atomic_model/utils.py index 39e38cdfdd..bbf22e10a4 100644 --- a/source/tests/universal/common/cases/atomic_model/utils.py +++ b/source/tests/universal/common/cases/atomic_model/utils.py @@ -1,8 +1,13 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Any, Callable, + Dict, List, + Optional, ) import numpy as np @@ -11,6 +16,10 @@ extend_input_and_build_neighbor_list, ) +from .....seed import ( + GLOBAL_SEED, +) + class AtomicModelTestCase: """Common test case for atomic model.""" @@ -35,6 +44,12 @@ class AtomicModelTestCase: """Expected whether having message passing.""" forward_wrapper: Callable[[Any], Any] """Calss wrapper for forward method.""" + aprec_dict: Dict[str, Optional[float]] + """Dictionary of absolute precision in each test.""" + rprec_dict: Dict[str, Optional[float]] + """Dictionary of relative precision in each test.""" + epsilon_dict: Dict[str, Optional[float]] + """Dictionary of epsilons in each test.""" def test_get_type_map(self): """Test get_type_map.""" @@ -77,6 +92,13 @@ def test_get_ntypes(self): for module in self.modules_to_test: self.assertEqual(module.get_ntypes(), len(self.expected_type_map)) + def test_has_message_passing(self): + """Test has_message_passing.""" + for module in self.modules_to_test: + self.assertEqual( + module.has_message_passing(), self.expected_has_message_passing + ) + def test_forward(self): """Test forward.""" nf = 1 @@ -95,14 +117,14 @@ def test_forward(self): atype, self.expected_rcut, self.expected_sel, - mixed_types=True, + mixed_types=self.module.mixed_types(), box=cell, ) ret_lower = [] for module in self.modules_to_test: module = self.forward_wrapper(module) - ret_lower.append(module(coord_ext, atype_ext, nlist)) + ret_lower.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) for kk in ret_lower[0].keys(): subret = [] for rr in ret_lower: @@ -116,3 +138,384 @@ def test_forward(self): np.testing.assert_allclose( subret[0], rr, err_msg=f"compare {kk} between 0 and {ii}" ) + + def test_permutation(self): + """Test permutation.""" + if getattr(self, "skip_test_permutation", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + idx_perm = [1, 0, 4, 3, 2] + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + coord_perm = coord[idx_perm] + atype_perm = atype[idx_perm] + + # reshape for input + coord = coord.reshape([nf, -1]) + coord_perm = coord_perm.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + atype_perm = atype_perm.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( + coord, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + # permutation + coord_ext_perm, atype_ext_perm, mapping_perm, nlist_perm = ( + extend_input_and_build_neighbor_list( + coord_perm, + atype_perm, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ) + ret.append( + module(coord_ext_perm, atype_ext_perm, nlist_perm, mapping=mapping_perm) + ) + + for kk in ret[0].keys(): + if kk in self.expected_model_output_type: + atomic = self.output_def[kk].atomic + if atomic: + np.testing.assert_allclose( + ret[0][kk][:, idx_perm], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_trans(self): + """Test translation.""" + if getattr(self, "skip_test_trans", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + shift = (rng.random([3]) - 0.5) * 2.0 + coord_s = np.matmul( + np.remainder(np.matmul(coord + shift, np.linalg.inv(cell)), 1.0), cell + ) + + # reshape for input + coord = coord.reshape([nf, -1]) + coord_s = coord_s.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( + coord, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + # translation + coord_ext_trans, atype_ext_trans, mapping_trans, nlist_trans = ( + extend_input_and_build_neighbor_list( + coord_s, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ) + ret.append( + module(coord_ext_trans, atype_ext_trans, nlist_trans, mapping=mapping_trans) + ) + + for kk in ret[0].keys(): + if kk in self.expected_model_output_type: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_rot(self): + """Test rotation.""" + if getattr(self, "skip_test_rot", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + + # rotate only coord and shift to the center of cell + cell = 10.0 * np.eye(3) + coord = 2.0 * rng.random([natoms, 3]) + atype = np.array([0, 0, 0, 1, 1]) + shift = np.array([4.0, 4.0, 4.0]) + from scipy.stats import ( + special_ortho_group, + ) + + rmat = special_ortho_group.rvs(3) + coord_rot = np.matmul(coord, rmat) + + # reshape for input + coord = (coord + shift).reshape([nf, -1]) + coord_rot = (coord_rot + shift).reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( + coord, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + # rotation + coord_ext_rot, atype_ext_rot, mapping_rot, nlist_rot = ( + extend_input_and_build_neighbor_list( + coord_rot, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ) + ret.append(module(coord_ext_rot, atype_ext_rot, nlist_rot, mapping=mapping_rot)) + + for kk in ret[0].keys(): + if kk in self.expected_model_output_type: + rot_invariant = self.output_def[kk].rot_invariant + if rot_invariant: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + v_shape = self.output_def[kk].shape + rotated_ret_0 = ( + np.matmul(ret[0][kk], rmat) + if len(v_shape) == 1 + else np.matmul(rmat.T, np.matmul(ret[0][kk], rmat)) + ) + np.testing.assert_allclose( + rotated_ret_0, + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + # rotate coord and cell + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + coord_rot = np.matmul(coord, rmat) + cell_rot = np.matmul(cell, rmat) + + # reshape for input + coord = coord.reshape([nf, -1]) + coord_rot = coord_rot.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + cell_rot = cell_rot.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( + coord, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + # rotation + coord_ext_rot, atype_ext_rot, mapping_rot, nlist_rot = ( + extend_input_and_build_neighbor_list( + coord_rot, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell_rot, + ) + ) + ret.append(module(coord_ext_rot, atype_ext_rot, nlist_rot, mapping=mapping_rot)) + + for kk in ret[0].keys(): + if kk in self.expected_model_output_type: + rot_invariant = self.output_def[kk].rot_invariant + if rot_invariant: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + v_shape = self.output_def[kk].shape + rotated_ret_0 = ( + np.matmul(ret[0][kk], rmat) + if len(v_shape) == 1 + else np.matmul(rmat.T, np.matmul(ret[0][kk], rmat)) + ) + np.testing.assert_allclose( + rotated_ret_0, + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_smooth(self): + """Test smooth.""" + if getattr(self, "skip_test_smooth", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + epsilon = ( + 1e-5 + if self.epsilon_dict.get("test_smooth", None) is None + else self.epsilon_dict["test_smooth"] + ) + # required prec. + rprec = ( + 1e-5 + if self.rprec_dict.get("test_smooth", None) is None + else self.rprec_dict["test_smooth"] + ) + aprec = ( + 1e-5 + if self.aprec_dict.get("test_smooth", None) is None + else self.aprec_dict["test_smooth"] + ) + natoms = 10 + nf = 1 + cell = 10.0 * np.eye(3) + atype0 = np.arange(2) + atype1 = rng.integers(0, 2, size=natoms - 2) + atype = np.concatenate([atype0, atype1]).reshape(natoms) + coord0 = np.array( + [ + 0.0, + 0.0, + 0.0, + self.expected_rcut - 0.5 * epsilon, + 0.0, + 0.0, + 0.0, + self.expected_rcut - 0.5 * epsilon, + 0.0, + ] + ).reshape(-1, 3) + coord1 = rng.random([natoms - coord0.shape[0], 3]) + coord1 = np.matmul(coord1, cell) + coord = np.concatenate([coord0, coord1], axis=0) + + coord0 = deepcopy(coord) + coord1 = deepcopy(coord) + coord1[1][0] += epsilon + coord2 = deepcopy(coord) + coord2[2][1] += epsilon + coord3 = deepcopy(coord) + coord3[1][0] += epsilon + coord3[2][1] += epsilon + + # reshape for input + coord0 = coord0.reshape([nf, -1]) + coord1 = coord1.reshape([nf, -1]) + coord2 = coord2.reshape([nf, -1]) + coord3 = coord3.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + # coord0 + coord_ext0, atype_ext0, mapping0, nlist0 = extend_input_and_build_neighbor_list( + coord0, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext0, atype_ext0, nlist0, mapping=mapping0)) + # coord1 + coord_ext1, atype_ext1, mapping1, nlist1 = extend_input_and_build_neighbor_list( + coord1, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext1, atype_ext1, nlist1, mapping=mapping1)) + # coord2 + coord_ext2, atype_ext2, mapping2, nlist2 = extend_input_and_build_neighbor_list( + coord2, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext2, atype_ext2, nlist2, mapping=mapping2)) + # coord3 + coord_ext3, atype_ext3, mapping3, nlist3 = extend_input_and_build_neighbor_list( + coord3, + atype, + self.expected_rcut, + self.expected_sel, + mixed_types=self.module.mixed_types(), + box=cell, + ) + ret.append(module(coord_ext3, atype_ext3, nlist3, mapping=mapping3)) + + for kk in ret[0].keys(): + if kk in self.expected_model_output_type: + for ii in range(len(ret) - 1): + np.testing.assert_allclose( + ret[0][kk], + ret[ii + 1][kk], + err_msg=f"compare {kk} before and after transform", + atol=aprec, + rtol=rprec, + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") diff --git a/source/tests/universal/common/cases/data/zbl_tab_potential/H2O_tab_potential.txt b/source/tests/universal/common/cases/data/zbl_tab_potential/H2O_tab_potential.txt new file mode 100644 index 0000000000..b4d146017f --- /dev/null +++ b/source/tests/universal/common/cases/data/zbl_tab_potential/H2O_tab_potential.txt @@ -0,0 +1,1000 @@ +0.001 913709.625838 114389.26607 14320.660836 913709.625838 114389.26607 14320.660836 +0.002 453190.075792 56822.165078 7124.559066 453190.075792 56822.165078 7124.559066 +0.003 299716.609389 37635.860646 4726.059712 299716.609389 37635.860646 4726.059712 +0.004 223004.208152 28044.724786 3526.959232 223004.208152 28044.724786 3526.959232 +0.005 176995.875921 22291.63231 2807.616935 176995.875921 22291.63231 2807.616935 +0.006 146339.286793 18457.541826 2328.152606 146339.286793 18457.541826 2328.152606 +0.007 124454.877677 15720.007305 1985.760451 124454.877677 15720.007305 1985.760451 +0.008 108052.871443 13667.805976 1729.037583 108052.871443 13667.805976 1729.037583 +0.009 95305.6179694 12072.480958 1529.426853 95305.6179694 12072.480958 1529.426853 +0.01 85116.5305655 10796.958308 1369.793979 85116.5305655 10796.958308 1369.793979 +0.011 76787.7843454 9754.009324 1239.235334 76787.7843454 9754.009324 1239.235334 +0.012 69854.1654175 8885.4816862 1130.481842 69854.1654175 8885.4816862 1130.481842 +0.013 63993.6050636 8151.1162355 1038.501071 63993.6050636 8151.1162355 1038.501071 +0.014 58976.0564146 7522.1565542 959.6984312 58976.0564146 7522.1565542 959.6984312 +0.015 54632.8204564 6977.5147177 891.4378965 54632.8204564 6977.5147177 891.4378965 +0.016 50837.3747846 6501.3748881 831.7424519 50837.3747846 6501.3748881 831.7424519 +0.017 47492.968682 6081.6426991 779.1002669 47492.968682 6081.6426991 779.1002669 +0.018 44524.3531708 5708.9115119 732.3354774 44524.3531708 5708.9115119 732.3354774 +0.019 41872.1226283 5375.7551174 690.5197734 41872.1226283 5375.7551174 690.5197734 +0.02 39488.7539185 5076.2326272 652.9105109 39488.7539185 5076.2326272 652.9105109 +0.021 37335.7772003 4805.5348243 618.9065049 37335.7772003 4805.5348243 618.9065049 +0.022 35381.7183353 4559.7269643 588.0158802 35381.7183353 4559.7269643 588.0158802 +0.023 33600.5780582 4335.5586712 559.8323083 33600.5780582 4335.5586712 559.8323083 +0.024 31970.6913556 4130.3213594 534.0171847 31970.6913556 4130.3213594 534.0171847 +0.025 30473.8605947 3941.739875 510.2860845 30473.8605947 3941.739875 510.2860845 +0.026 29094.6886984 3767.8891424 488.398343 29094.6886984 3767.8891424 488.398343 +0.027 27820.0605059 3607.1293341 468.1489521 27820.0605059 3607.1293341 468.1489521 +0.028 26638.7352692 3458.0549325 449.3621928 26638.7352692 3458.0549325 449.3621928 +0.029 25541.023462 3319.4543312 431.8865855 25541.023462 3319.4543312 431.8865855 +0.03 24518.5282265 3190.2775152 415.5908499 24518.5282265 3190.2775152 415.5908499 +0.031 23563.9368637 3069.6099976 400.3606472 23563.9368637 3069.6099976 400.3606472 +0.032 22670.8514191 2956.651642 386.0959329 22670.8514191 2956.651642 386.0959329 +0.033 21833.6500715 2850.6993366 372.708791 21833.6500715 2850.6993366 372.708791 +0.034 21047.372983 2751.1327248 360.1216502 21047.372983 2751.1327248 360.1216502 +0.035 20307.6277175 2657.4023825 348.2658062 20307.6277175 2657.4023825 348.2658062 +0.036 19610.5104235 2569.0199661 337.0801904 19610.5104235 2569.0199661 337.0801904 +0.037 18952.5397978 2485.5499575 326.5103374 18952.5397978 2485.5499575 326.5103374 +0.038 18330.6014769 2406.6027127 316.5075168 18330.6014769 2406.6027127 316.5075168 +0.039 17741.9009829 2331.8285805 307.0279975 17741.9009829 2331.8285805 307.0279975 +0.04 17183.9237284 2260.9129024 298.0324229 17183.9237284 2260.9129024 298.0324229 +0.041 16654.4008745 2193.5717452 289.4852776 16654.4008745 2193.5717452 289.4852776 +0.042 16151.2800661 2129.5482423 281.3544296 16151.2800661 2129.5482423 281.3544296 +0.043 15672.7002509 2068.6094464 273.6107373 15672.7002509 2068.6094464 273.6107373 +0.044 15216.9699328 2010.5436107 266.2277097 15216.9699328 2010.5436107 266.2277097 +0.045 14782.5483242 1955.1578329 259.1812115 14782.5483242 1955.1578329 259.1812115 +0.046 14368.028958 1902.2760069 252.4492073 14368.028958 1902.2760069 252.4492073 +0.047 13972.1253902 1851.737035 246.0115383 13972.1253902 1851.737035 246.0115383 +0.048 13593.6586918 1803.3932646 239.8497262 13593.6586918 1803.3932646 239.8497262 +0.049 13231.5464708 1757.1091159 233.9468027 13231.5464708 1757.1091159 233.9468027 +0.05 12884.7932124 1712.759874 228.2871576 12884.7932124 1712.759874 228.2871576 +0.051 12552.4817558 1670.2306236 222.856406 12552.4817558 1670.2306236 222.856406 +0.052 12233.7657548 1629.4153064 217.6412705 12233.7657548 1629.4153064 217.6412705 +0.053 11927.862991 1590.2158855 212.6294767 11927.862991 1590.2158855 212.6294767 +0.054 11634.0494314 1552.5416017 207.8096602 11634.0494314 1552.5416017 207.8096602 +0.055 11351.6539336 1516.3083123 203.1712838 11351.6539336 1516.3083123 203.1712838 +0.056 11080.0535186 1481.4378999 198.7045641 11080.0535186 1481.4378999 198.7045641 +0.057 10818.6691413 1447.8577434 194.4004048 10818.6691413 1447.8577434 194.4004048 +0.058 10566.9618984 1415.5002442 190.2503376 10566.9618984 1415.5002442 190.2503376 +0.059 10324.4296227 1384.3024001 186.2464693 10324.4296227 1384.3024001 186.2464693 +0.06 10090.6038173 1354.2054222 182.3814335 10090.6038173 1354.2054222 182.3814335 +0.061 9865.0468917 1325.1543893 178.6483475 9865.0468917 1325.1543893 178.6483475 +0.062 9647.3496659 1297.0979357 175.0407734 9647.3496659 1297.0979357 175.0407734 +0.063 9437.1291115 1269.9879689 171.5526826 9437.1291115 1269.9879689 171.5526826 +0.064 9234.0263053 1243.7794136 168.178424 9234.0263053 1243.7794136 168.178424 +0.065 9037.7045714 1218.4299795 164.9126949 9037.7045714 1218.4299795 164.9126949 +0.066 8847.8477928 1193.8999501 161.7505145 8847.8477928 1193.8999501 161.7505145 +0.067 8664.1588738 1170.1519903 158.6871999 8664.1588738 1170.1519903 158.6871999 +0.068 8486.3583383 1147.1509714 155.7183444 8486.3583383 1147.1509714 155.7183444 +0.069 8314.1830501 1124.8638108 152.8397972 8314.1830501 1124.8638108 152.8397972 +0.07 8147.3850427 1103.2593259 150.0476452 8147.3850427 1103.2593259 150.0476452 +0.071 7985.7304489 1082.3080999 147.3381963 7985.7304489 1082.3080999 147.3381963 +0.072 7828.9985183 1061.9823592 144.707964 7828.9985183 1061.9823592 144.707964 +0.073 7676.9807165 1042.2558606 142.1536534 7676.9807165 1042.2558606 142.1536534 +0.074 7529.4798977 1023.1037878 139.6721482 7529.4798977 1023.1037878 139.6721482 +0.075 7386.3095424 1004.5026562 137.2604986 7386.3095424 1004.5026562 137.2604986 +0.076 7247.2930565 986.430225 134.9159107 7247.2930565 986.430225 134.9159107 +0.077 7112.2631243 968.8654164 132.6357361 7112.2631243 968.8654164 132.6357361 +0.078 6981.0611116 951.7882409 130.4174626 6981.0611116 951.7882409 130.4174626 +0.079 6853.5365143 935.1797284 128.2587056 6853.5365143 935.1797284 128.2587056 +0.08 6729.5464483 919.0218641 126.1572004 6729.5464483 919.0218641 126.1572004 +0.081 6608.9551768 903.2975297 124.1107942 6608.9551768 903.2975297 124.1107942 +0.082 6491.6336731 887.9904484 122.1174397 6491.6336731 887.9904484 122.1174397 +0.083 6377.4592142 873.0851342 120.1751889 6377.4592142 873.0851342 120.1751889 +0.084 6266.3150042 858.5668449 118.2821865 6266.3150042 858.5668449 118.2821865 +0.085 6158.0898234 844.4215378 116.4366651 6158.0898234 844.4215378 116.4366651 +0.086 6052.677703 830.6358295 114.63694 6052.677703 830.6358295 114.63694 +0.087 5949.9776216 817.1969572 112.881404 5949.9776216 817.1969572 112.881404 +0.088 5849.8932223 804.0927442 111.1685235 5849.8932223 804.0927442 111.1685235 +0.089 5752.3325494 791.311566 109.4968341 5752.3325494 791.311566 109.4968341 +0.09 5657.2078026 778.8423203 107.8649368 5657.2078026 778.8423203 107.8649368 +0.091 5564.4351069 766.6743978 106.2714943 5564.4351069 766.6743978 106.2714943 +0.092 5473.9342981 754.7976551 104.7152279 5473.9342981 754.7976551 104.7152279 +0.093 5385.6287222 743.2023904 103.1949141 5385.6287222 743.2023904 103.1949141 +0.094 5299.4450471 731.879319 101.7093819 5299.4450471 731.879319 101.7093819 +0.095 5215.3130867 720.8195518 100.2575097 5215.3130867 720.8195518 100.2575097 +0.096 5133.1656359 710.0145745 98.8382229 5133.1656359 710.0145745 98.8382229 +0.097 5052.9383157 699.4562281 97.4504918 5052.9383157 699.4562281 97.4504918 +0.098 4974.5694279 689.1366911 96.0933285 4974.5694279 689.1366911 96.0933285 +0.099 4897.9998188 679.0484617 94.7657857 4897.9998188 679.0484617 94.7657857 +0.1 4823.1727507 669.1843423 93.466954 4823.1727507 669.1843423 93.466954 +0.101 4750.0337815 659.5374244 92.1959604 4750.0337815 659.5374244 92.1959604 +0.102 4678.530651 650.1010737 90.9519663 4678.530651 650.1010737 90.9519663 +0.103 4608.6131741 640.8689177 89.7341659 4608.6131741 640.8689177 89.7341659 +0.104 4540.2331402 631.8348323 88.5417846 4540.2331402 631.8348323 88.5417846 +0.105 4473.3442182 622.9929301 87.3740776 4473.3442182 622.9929301 87.3740776 +0.106 4407.9018671 614.3375495 86.2303284 4407.9018671 614.3375495 86.2303284 +0.107 4343.8632512 605.8632435 85.1098475 4343.8632512 605.8632435 85.1098475 +0.108 4281.1871608 597.5647703 84.0119712 4281.1871608 597.5647703 84.0119712 +0.109 4219.8339365 589.4370834 82.9360602 4219.8339365 589.4370834 82.9360602 +0.11 4159.7653981 581.475323 81.8814988 4159.7653981 581.475323 81.8814988 +0.111 4100.944777 573.6748074 80.8476936 4100.944777 573.6748074 80.8476936 +0.112 4043.3366528 566.0310249 79.8340726 4043.3366528 566.0310249 79.8340726 +0.113 3986.9068928 558.5396262 78.8400844 3986.9068928 558.5396262 78.8400844 +0.114 3931.6225949 551.1964175 77.8651968 3931.6225949 551.1964175 77.8651968 +0.115 3877.4520333 543.9973537 76.9088966 3877.4520333 543.9973537 76.9088966 +0.116 3824.3646071 536.9385314 75.9706883 3824.3646071 536.9385314 75.9706883 +0.117 3772.3307921 530.0161836 75.0500935 3772.3307921 530.0161836 75.0500935 +0.118 3721.3220939 523.2266731 74.1466504 3721.3220939 523.2266731 74.1466504 +0.119 3671.3110047 516.5664876 73.2599126 3671.3110047 516.5664876 73.2599126 +0.12 3622.270961 510.0322343 72.3894489 3622.270961 510.0322343 72.3894489 +0.121 3574.1763045 503.6206346 71.5348425 3574.1763045 503.6206346 71.5348425 +0.122 3527.0022444 497.3285198 70.6956904 3527.0022444 497.3285198 70.6956904 +0.123 3480.7248214 491.1528264 69.8716028 3480.7248214 491.1528264 69.8716028 +0.124 3435.3208739 485.0905919 69.0622028 3435.3208739 485.0905919 69.0622028 +0.125 3390.7680053 479.1389505 68.2671256 3390.7680053 479.1389505 68.2671256 +0.126 3347.0445536 473.2951298 67.486018 3347.0445536 473.2951298 67.486018 +0.127 3304.1295618 467.5564462 66.7185382 3304.1295618 467.5564462 66.7185382 +0.128 3262.0027498 461.9203022 65.9643553 3262.0027498 461.9203022 65.9643553 +0.129 3220.6444879 456.3841826 65.2231486 3220.6444879 456.3841826 65.2231486 +0.13 3180.0357713 450.9456517 64.4946075 3180.0357713 450.9456517 64.4946075 +0.131 3140.1581958 445.6023495 63.778431 3140.1581958 445.6023495 63.778431 +0.132 3100.9939349 440.3519898 63.0743273 3100.9939349 440.3519898 63.0743273 +0.133 3062.5257173 435.1923563 62.3820136 3062.5257173 435.1923563 62.3820136 +0.134 3024.736806 430.1213011 61.7012156 3024.736806 430.1213011 61.7012156 +0.135 2987.6109783 425.1367411 61.0316673 2987.6109783 425.1367411 61.0316673 +0.136 2951.1325064 420.2366563 60.3731105 2951.1325064 420.2366563 60.3731105 +0.137 2915.2861387 415.4190873 59.7252948 2915.2861387 415.4190873 59.7252948 +0.138 2880.0570829 410.6821328 59.0879771 2880.0570829 410.6821328 59.0879771 +0.139 2845.4309885 406.0239478 58.4609214 2845.4309885 406.0239478 58.4609214 +0.14 2811.3939311 401.4427415 57.8438986 2811.3939311 401.4427415 57.8438986 +0.141 2777.9323966 396.9367752 57.2366861 2777.9323966 396.9367752 57.2366861 +0.142 2745.0332671 392.5043608 56.6390678 2745.0332671 392.5043608 56.6390678 +0.143 2712.683806 388.1438584 56.0508336 2712.683806 388.1438584 56.0508336 +0.144 2680.871645 383.8536753 55.4717796 2680.871645 383.8536753 55.4717796 +0.145 2649.584771 379.6322639 54.9017073 2649.584771 379.6322639 54.9017073 +0.146 2618.8115134 375.4781203 54.3404239 2618.8115134 375.4781203 54.3404239 +0.147 2588.5405327 371.3897825 53.787742 2588.5405327 371.3897825 53.787742 +0.148 2558.7608086 367.3658297 53.2434792 2558.7608086 367.3658297 53.2434792 +0.149 2529.4616294 363.40488 52.7074581 2529.4616294 363.40488 52.7074581 +0.15 2500.6325811 359.5055896 52.1795062 2500.6325811 359.5055896 52.1795062 +0.151 2472.2635377 355.6666516 51.6594557 2472.2635377 355.6666516 51.6594557 +0.152 2444.3446512 351.8867943 51.1471432 2444.3446512 351.8867943 51.1471432 +0.153 2416.8663423 348.1647806 50.6424097 2416.8663423 348.1647806 50.6424097 +0.154 2389.8192919 344.4994064 50.1451003 2389.8192919 344.4994064 50.1451003 +0.155 2363.1944319 340.8894997 49.6550644 2363.1944319 340.8894997 49.6550644 +0.156 2336.9829372 337.3339196 49.1721551 2336.9829372 337.3339196 49.1721551 +0.157 2311.1762181 333.8315552 48.6962295 2311.1762181 333.8315552 48.6962295 +0.158 2285.765912 330.3813249 48.2271484 2285.765912 330.3813249 48.2271484 +0.159 2260.7438767 326.9821749 47.7647759 2260.7438767 326.9821749 47.7647759 +0.16 2236.1021827 323.6330788 47.3089799 2236.1021827 323.6330788 47.3089799 +0.161 2211.8331072 320.3330368 46.8596315 2211.8331072 320.3330368 46.8596315 +0.162 2187.9291268 317.0810744 46.416605 2187.9291268 317.0810744 46.416605 +0.163 2164.3829117 313.8762419 45.9797781 2164.3829117 313.8762419 45.9797781 +0.164 2141.1873194 310.7176137 45.5490312 2141.1873194 310.7176137 45.5490312 +0.165 2118.335389 307.6042874 45.1242479 2118.335389 307.6042874 45.1242479 +0.166 2095.8203354 304.5353832 44.7053147 2095.8203354 304.5353832 44.7053147 +0.167 2073.6355442 301.5100431 44.2921206 2073.6355442 301.5100431 44.2921206 +0.168 2051.774566 298.5274302 43.8845577 2051.774566 298.5274302 43.8845577 +0.169 2030.2311119 295.5867284 43.4825203 2030.2311119 295.5867284 43.4825203 +0.17 2008.9990482 292.6871414 43.0859057 2008.9990482 292.6871414 43.0859057 +0.171 1988.0723922 289.8278921 42.6946132 1988.0723922 289.8278921 42.6946132 +0.172 1967.445307 287.0082225 42.3085448 1967.445307 287.0082225 42.3085448 +0.173 1947.1120979 284.2273926 41.9276048 1947.1120979 284.2273926 41.9276048 +0.174 1927.0672078 281.48468 41.5516997 1927.0672078 281.48468 41.5516997 +0.175 1907.3052129 278.7793797 41.180738 1907.3052129 278.7793797 41.180738 +0.176 1887.8208195 276.1108033 40.8146308 1887.8208195 276.1108033 40.8146308 +0.177 1868.6088596 273.4782784 40.4532907 1868.6088596 273.4782784 40.4532907 +0.178 1849.6642873 270.8811486 40.0966328 1849.6642873 270.8811486 40.0966328 +0.179 1830.9821758 268.3187725 39.7445739 1830.9821758 268.3187725 39.7445739 +0.18 1812.5577133 265.7905239 39.3970327 1812.5577133 265.7905239 39.3970327 +0.181 1794.3862002 263.2957906 39.0539298 1794.3862002 263.2957906 39.0539298 +0.182 1776.4630458 260.8339748 38.7151877 1776.4630458 260.8339748 38.7151877 +0.183 1758.7837651 258.404492 38.3807303 1758.7837651 258.404492 38.3807303 +0.184 1741.3439759 256.0067712 38.0504836 1741.3439759 256.0067712 38.0504836 +0.185 1724.139396 253.6402542 37.724375 1724.139396 253.6402542 37.724375 +0.186 1707.1658404 251.3043952 37.4023336 1707.1658404 251.3043952 37.4023336 +0.187 1690.4192185 248.9986608 37.08429 1690.4192185 248.9986608 37.08429 +0.188 1673.8955316 246.7225293 36.7701764 1673.8955316 246.7225293 36.7701764 +0.189 1657.5908704 244.4754905 36.4599264 1657.5908704 244.4754905 36.4599264 +0.19 1641.5014126 242.2570456 36.1534752 1641.5014126 242.2570456 36.1534752 +0.191 1625.6234204 240.0667066 35.850759 1625.6234204 240.0667066 35.850759 +0.192 1609.9532382 237.903996 35.5517159 1609.9532382 237.903996 35.5517159 +0.193 1594.4872906 235.768447 35.256285 1594.4872906 235.768447 35.256285 +0.194 1579.2220803 233.6596024 34.9644066 1579.2220803 233.6596024 34.9644066 +0.195 1564.1541856 231.5770153 34.6760226 1564.1541856 231.5770153 34.6760226 +0.196 1549.2802589 229.520248 34.3910759 1549.2802589 229.520248 34.3910759 +0.197 1534.5970244 227.4888722 34.1095106 1534.5970244 227.4888722 34.1095106 +0.198 1520.1012763 225.4824686 33.831272 1520.1012763 225.4824686 33.831272 +0.199 1505.7898772 223.5006269 33.5563066 1505.7898772 223.5006269 33.5563066 +0.2 1491.6597561 221.5429453 33.2845619 1491.6597561 221.5429453 33.2845619 +0.201 1477.7079067 219.6090303 33.0159865 1477.7079067 219.6090303 33.0159865 +0.202 1463.9313857 217.6984967 32.7505301 1463.9313857 217.6984967 32.7505301 +0.203 1450.3273114 215.8109671 32.4881435 1450.3273114 215.8109671 32.4881435 +0.204 1436.892862 213.946072 32.2287782 1436.892862 213.946072 32.2287782 +0.205 1423.6252739 212.1034495 31.972387 1423.6252739 212.1034495 31.972387 +0.206 1410.5218407 210.2827449 31.7189234 1410.5218407 210.2827449 31.7189234 +0.207 1397.5799113 208.4836109 31.4683421 1397.5799113 208.4836109 31.4683421 +0.208 1384.7968886 206.7057069 31.2205985 1384.7968886 206.7057069 31.2205985 +0.209 1372.1702286 204.9486995 30.975649 1372.1702286 204.9486995 30.975649 +0.21 1359.6974383 203.2122618 30.7334506 1359.6974383 203.2122618 30.7334506 +0.211 1347.3760753 201.4960735 30.4939616 1347.3760753 201.4960735 30.4939616 +0.212 1335.2037458 199.7998204 30.2571406 1335.2037458 199.7998204 30.2571406 +0.213 1323.178104 198.1231947 30.0229474 1323.178104 198.1231947 30.0229474 +0.214 1311.2968506 196.4658948 29.7913425 1311.2968506 196.4658948 29.7913425 +0.215 1299.5577318 194.8276247 29.5622869 1299.5577318 194.8276247 29.5622869 +0.216 1287.958538 193.2080943 29.3357428 1287.958538 193.2080943 29.3357428 +0.217 1276.4971033 191.6070192 29.1116726 1276.4971033 191.6070192 29.1116726 +0.218 1265.1713036 190.0241204 28.8900399 1265.1713036 190.0241204 28.8900399 +0.219 1253.9790564 188.4591242 28.6708087 1253.9790564 188.4591242 28.6708087 +0.22 1242.9183194 186.9117623 28.4539438 1242.9183194 186.9117623 28.4539438 +0.221 1231.9870896 185.3817715 28.2394106 1231.9870896 185.3817715 28.2394106 +0.222 1221.1834024 183.8688934 28.0271751 1221.1834024 183.8688934 28.0271751 +0.223 1210.5053309 182.3728746 27.817204 1210.5053309 182.3728746 27.817204 +0.224 1199.9509845 180.8934666 27.6094647 1199.9509845 180.8934666 27.6094647 +0.225 1189.5185088 179.4304255 27.4039251 1189.5185088 179.4304255 27.4039251 +0.226 1179.2060841 177.9835117 27.2005537 1179.2060841 177.9835117 27.2005537 +0.227 1169.0119251 176.5524904 26.9993196 1169.0119251 176.5524904 26.9993196 +0.228 1158.9342796 175.1371309 26.8001924 1158.9342796 175.1371309 26.8001924 +0.229 1148.9714282 173.7372069 26.6031423 1148.9714282 173.7372069 26.6031423 +0.23 1139.1216834 172.3524963 26.4081402 1139.1216834 172.3524963 26.4081402 +0.231 1129.3833889 170.9827808 26.2151571 1129.3833889 170.9827808 26.2151571 +0.232 1119.7549187 169.6278463 26.024165 1119.7549187 169.6278463 26.024165 +0.233 1110.2346768 168.2874825 25.8351362 1110.2346768 168.2874825 25.8351362 +0.234 1100.8210961 166.9614829 25.6480433 1100.8210961 166.9614829 25.6480433 +0.235 1091.5126382 165.6496448 25.4628597 1091.5126382 165.6496448 25.4628597 +0.236 1082.3077924 164.3517691 25.2795591 1082.3077924 164.3517691 25.2795591 +0.237 1073.2050753 163.0676601 25.0981157 1073.2050753 163.0676601 25.0981157 +0.238 1064.20303 161.7971257 24.9185042 1064.20303 161.7971257 24.9185042 +0.239 1055.3002259 160.5399772 24.7406996 1055.3002259 160.5399772 24.7406996 +0.24 1046.4952577 159.2960293 24.5646775 1046.4952577 159.2960293 24.5646775 +0.241 1037.786745 158.0650998 24.3904138 1037.786745 158.0650998 24.3904138 +0.242 1029.1733319 156.8470097 24.2178849 1029.1733319 156.8470097 24.2178849 +0.243 1020.6536864 155.6415833 24.0470676 1020.6536864 155.6415833 24.0470676 +0.244 1012.2264998 154.4486478 23.877939 1012.2264998 154.4486478 23.877939 +0.245 1003.8904862 153.2680334 23.7104767 1003.8904862 153.2680334 23.7104767 +0.246 995.6443822 152.0995732 23.5446586 995.6443822 152.0995732 23.5446586 +0.247 987.4869462 150.9431032 23.3804631 987.4869462 150.9431032 23.3804631 +0.248 979.416958 149.7984622 23.2178688 979.416958 149.7984622 23.2178688 +0.249 971.4332186 148.6654918 23.0568547 971.4332186 148.6654918 23.0568547 +0.25 963.5345494 147.5440362 22.8974003 963.5345494 147.5440362 22.8974003 +0.251 955.7197919 146.4339423 22.7394853 955.7197919 146.4339423 22.7394853 +0.252 947.9878073 145.3350596 22.5830897 947.9878073 145.3350596 22.5830897 +0.253 940.3374762 144.2472399 22.4281939 940.3374762 144.2472399 22.4281939 +0.254 932.7676981 143.1703377 22.2747787 932.7676981 143.1703377 22.2747787 +0.255 925.2773908 142.1042099 22.1228251 925.2773908 142.1042099 22.1228251 +0.256 917.8654906 141.0487157 21.9723144 917.8654906 141.0487157 21.9723144 +0.257 910.5309511 140.0037168 21.8232283 910.5309511 140.0037168 21.8232283 +0.258 903.2727438 138.9690768 21.6755488 903.2727438 138.9690768 21.6755488 +0.259 896.0898568 137.9446619 21.529258 896.0898568 137.9446619 21.529258 +0.26 888.9812952 136.9303404 21.3843385 888.9812952 136.9303404 21.3843385 +0.261 881.9460805 135.9259827 21.2407731 881.9460805 135.9259827 21.2407731 +0.262 874.9832499 134.9314613 21.0985449 874.9832499 134.9314613 21.0985449 +0.263 868.0918568 133.9466506 20.9576372 868.0918568 133.9466506 20.9576372 +0.264 861.2709696 132.9714274 20.8180337 861.2709696 132.9714274 20.8180337 +0.265 854.5196721 132.0056702 20.6797182 854.5196721 132.0056702 20.6797182 +0.266 847.8370627 131.0492595 20.5426748 847.8370627 131.0492595 20.5426748 +0.267 841.2222545 130.1020778 20.406888 841.2222545 130.1020778 20.406888 +0.268 834.6743747 129.1640092 20.2723424 834.6743747 129.1640092 20.2723424 +0.269 828.1925646 128.2349399 20.1390228 828.1925646 128.2349399 20.1390228 +0.27 821.775979 127.3147578 20.0069143 821.775979 127.3147578 20.0069143 +0.271 815.4237863 126.4033526 19.8760022 815.4237863 126.4033526 19.8760022 +0.272 809.135168 125.5006157 19.7462722 809.135168 125.5006157 19.7462722 +0.273 802.9093184 124.6064402 19.6177099 802.9093184 124.6064402 19.6177099 +0.274 796.7454448 123.7207207 19.4903015 796.7454448 123.7207207 19.4903015 +0.275 790.6427665 122.8433537 19.364033 790.6427665 122.8433537 19.364033 +0.276 784.6005152 121.9742372 19.2388909 784.6005152 121.9742372 19.2388909 +0.277 778.6179347 121.1132707 19.1148619 778.6179347 121.1132707 19.1148619 +0.278 772.6942802 120.2603553 18.9919327 772.6942802 120.2603553 18.9919327 +0.279 766.8288187 119.4153936 18.8700905 766.8288187 119.4153936 18.8700905 +0.28 761.0208283 118.5782897 18.7493224 761.0208283 118.5782897 18.7493224 +0.281 755.2695984 117.748949 18.6296158 755.2695984 117.748949 18.6296158 +0.282 749.5744291 116.9272787 18.5109583 749.5744291 116.9272787 18.5109583 +0.283 743.9346311 116.113187 18.3933378 743.9346311 116.113187 18.3933378 +0.284 738.3495259 115.3065837 18.2767421 738.3495259 115.3065837 18.2767421 +0.285 732.818445 114.50738 18.1611595 732.818445 114.50738 18.1611595 +0.286 727.34073 113.7154881 18.0465783 727.34073 113.7154881 18.0465783 +0.287 721.9157327 112.9308219 17.9329869 721.9157327 112.9308219 17.9329869 +0.288 716.5428142 112.1532963 17.820374 716.5428142 112.1532963 17.820374 +0.289 711.2213456 111.3828276 17.7087284 711.2213456 111.3828276 17.7087284 +0.29 705.9507071 110.6193334 17.5980392 705.9507071 110.6193334 17.5980392 +0.291 700.7302882 109.8627322 17.4882954 700.7302882 109.8627322 17.4882954 +0.292 695.5594874 109.1129441 17.3794864 695.5594874 109.1129441 17.3794864 +0.293 690.4377121 108.36989 17.2716016 690.4377121 108.36989 17.2716016 +0.294 685.3643785 107.6334922 17.1646306 685.3643785 107.6334922 17.1646306 +0.295 680.3389114 106.9036741 17.0585633 680.3389114 106.9036741 17.0585633 +0.296 675.3607438 106.18036 16.9533894 675.3607438 106.18036 16.9533894 +0.297 670.4293171 105.4634755 16.8490991 670.4293171 105.4634755 16.8490991 +0.298 665.5440809 104.7529472 16.7456826 665.5440809 104.7529472 16.7456826 +0.299 660.7044927 104.0487027 16.64313 660.7044927 104.0487027 16.64313 +0.3 655.9100179 103.3506708 16.541432 655.9100179 103.3506708 16.541432 +0.301 651.1601295 102.6587812 16.4405792 651.1601295 102.6587812 16.4405792 +0.302 646.4543081 101.9729644 16.3405621 646.4543081 101.9729644 16.3405621 +0.303 641.7920419 101.2931523 16.2413718 641.7920419 101.2931523 16.2413718 +0.304 637.1728262 100.6192774 16.1429992 637.1728262 100.6192774 16.1429992 +0.305 632.5961636 99.9512734 16.0454353 632.5961636 99.9512734 16.0454353 +0.306 628.0615636 99.2890746 15.9486715 628.0615636 99.2890746 15.9486715 +0.307 623.568543 98.6326167 15.8526991 623.568543 98.6326167 15.8526991 +0.308 619.116625 97.9818358 15.7575095 619.116625 97.9818358 15.7575095 +0.309 614.7053397 97.3366692 15.6630943 614.7053397 97.3366692 15.6630943 +0.31 610.3342239 96.697055 15.5694453 610.3342239 96.697055 15.5694453 +0.311 606.0028208 96.0629321 15.4765543 606.0028208 96.0629321 15.4765543 +0.312 601.7106798 95.4342402 15.3844132 601.7106798 95.4342402 15.3844132 +0.313 597.4573568 94.81092 15.2930139 597.4573568 94.81092 15.2930139 +0.314 593.2424137 94.1929129 15.2023488 593.2424137 94.1929129 15.2023488 +0.315 589.0654185 93.580161 15.1124099 589.0654185 93.580161 15.1124099 +0.316 584.9259453 92.9726074 15.0231897 584.9259453 92.9726074 15.0231897 +0.317 580.8235739 92.3701958 14.9346807 580.8235739 92.3701958 14.9346807 +0.318 576.7578898 91.7728708 14.8468753 576.7578898 91.7728708 14.8468753 +0.319 572.7284843 91.1805775 14.7597662 572.7284843 91.1805775 14.7597662 +0.32 568.7349543 90.593262 14.6733463 568.7349543 90.593262 14.6733463 +0.321 564.776902 90.0108711 14.5876082 564.776902 90.0108711 14.5876082 +0.322 560.8539351 89.4333521 14.5025451 560.8539351 89.4333521 14.5025451 +0.323 556.9656667 88.8606532 14.4181498 556.9656667 88.8606532 14.4181498 +0.324 553.111715 88.2927232 14.3344156 553.111715 88.2927232 14.3344156 +0.325 549.2917033 87.7295116 14.2513356 549.2917033 87.7295116 14.2513356 +0.326 545.50526 87.1709686 14.1689032 545.50526 87.1709686 14.1689032 +0.327 541.7520185 86.617045 14.0871117 541.7520185 86.617045 14.0871117 +0.328 538.031617 86.0676922 14.0059546 538.031617 86.0676922 14.0059546 +0.329 534.3436986 85.5228624 13.9254255 534.3436986 85.5228624 13.9254255 +0.33 530.6879111 84.9825082 13.845518 530.6879111 84.9825082 13.845518 +0.331 527.0639069 84.4465831 13.7662258 527.0639069 84.4465831 13.7662258 +0.332 523.4713431 83.9150409 13.6875428 523.4713431 83.9150409 13.6875428 +0.333 519.9098812 83.3878361 13.6094628 519.9098812 83.3878361 13.6094628 +0.334 516.3791872 82.864924 13.5319798 516.3791872 82.864924 13.5319798 +0.335 512.8789315 82.3462602 13.4550878 512.8789315 82.3462602 13.4550878 +0.336 509.4087887 81.831801 13.3787809 509.4087887 81.831801 13.3787809 +0.337 505.9684377 81.3215032 13.3030534 505.9684377 81.3215032 13.3030534 +0.338 502.5575616 80.8153242 13.2278994 502.5575616 80.8153242 13.2278994 +0.339 499.1758475 80.3132218 13.1533134 499.1758475 80.3132218 13.1533134 +0.34 495.8229866 79.8151546 13.0792897 495.8229866 79.8151546 13.0792897 +0.341 492.4986741 79.3210816 13.0058227 492.4986741 79.3210816 13.0058227 +0.342 489.2026091 78.8309622 12.9329071 489.2026091 78.8309622 12.9329071 +0.343 485.9344945 78.3447564 12.8605374 485.9344945 78.3447564 12.8605374 +0.344 482.6940372 77.8624247 12.7887084 482.6940372 77.8624247 12.7887084 +0.345 479.4809474 77.3839282 12.7174147 479.4809474 77.3839282 12.7174147 +0.346 476.2949395 76.9092283 12.6466511 476.2949395 76.9092283 12.6466511 +0.347 473.1357312 76.438287 12.5764126 473.1357312 76.438287 12.5764126 +0.348 470.0030438 75.9710667 12.5066941 470.0030438 75.9710667 12.5066941 +0.349 466.8966023 75.5075304 12.4374905 466.8966023 75.5075304 12.4374905 +0.35 463.8161349 75.0476413 12.3687969 463.8161349 75.0476413 12.3687969 +0.351 460.7613734 74.5913633 12.3006084 460.7613734 74.5913633 12.3006084 +0.352 457.7320529 74.1386607 12.2329203 457.7320529 74.1386607 12.2329203 +0.353 454.7279118 73.6894981 12.1657276 454.7279118 73.6894981 12.1657276 +0.354 451.7486918 73.2438407 12.0990258 451.7486918 73.2438407 12.0990258 +0.355 448.7941378 72.801654 12.0328101 448.7941378 72.801654 12.0328101 +0.356 445.8639978 72.362904 11.9670761 445.8639978 72.362904 11.9670761 +0.357 442.958023 71.927557 11.901819 442.958023 71.927557 11.901819 +0.358 440.0759676 71.4955799 11.8370344 440.0759676 71.4955799 11.8370344 +0.359 437.2175888 71.0669398 11.772718 437.2175888 71.0669398 11.772718 +0.36 434.382647 70.6416043 11.7088653 434.382647 70.6416043 11.7088653 +0.361 431.5709052 70.2195415 11.6454719 431.5709052 70.2195415 11.6454719 +0.362 428.7821296 69.8007195 11.5825337 428.7821296 69.8007195 11.5825337 +0.363 426.0160891 69.3851072 11.5200463 426.0160891 69.3851072 11.5200463 +0.364 423.2725553 68.9726737 11.4580056 423.2725553 68.9726737 11.4580056 +0.365 420.5513029 68.5633884 11.3964074 420.5513029 68.5633884 11.3964074 +0.366 417.852109 68.1572211 11.3352478 417.852109 68.1572211 11.3352478 +0.367 415.1747536 67.7541421 11.2745225 415.1747536 67.7541421 11.2745225 +0.368 412.5190192 67.3541219 11.2142277 412.5190192 67.3541219 11.2142277 +0.369 409.884691 66.9571314 11.1543594 409.884691 66.9571314 11.1543594 +0.37 407.2715568 66.5631417 11.0949137 407.2715568 66.5631417 11.0949137 +0.371 404.6794069 66.1721246 11.0358867 404.6794069 66.1721246 11.0358867 +0.372 402.1080341 65.7840517 10.9772747 402.1080341 65.7840517 10.9772747 +0.373 399.5572337 65.3988954 10.9190739 399.5572337 65.3988954 10.9190739 +0.374 397.0268033 65.0166283 10.8612804 397.0268033 65.0166283 10.8612804 +0.375 394.5165432 64.6372231 10.8038908 394.5165432 64.6372231 10.8038908 +0.376 392.0262556 64.260653 10.7469013 392.0262556 64.260653 10.7469013 +0.377 389.5557456 63.8868916 10.6903083 389.5557456 63.8868916 10.6903083 +0.378 387.10482 63.5159126 10.6341083 387.10482 63.5159126 10.6341083 +0.379 384.6732884 63.1476901 10.5782978 384.6732884 63.1476901 10.5782978 +0.38 382.2609623 62.7821985 10.5228732 382.2609623 62.7821985 10.5228732 +0.381 379.8676555 62.4194124 10.4678312 379.8676555 62.4194124 10.4678312 +0.382 377.493184 62.0593069 10.4131683 377.493184 62.0593069 10.4131683 +0.383 375.1373659 61.7018572 10.3588812 375.1373659 61.7018572 10.3588812 +0.384 372.8000214 61.3470387 10.3049666 372.8000214 61.3470387 10.3049666 +0.385 370.4809729 60.9948274 10.2514211 370.4809729 60.9948274 10.2514211 +0.386 368.1800447 60.6451993 10.1982415 368.1800447 60.6451993 10.1982415 +0.387 365.8970633 60.2981307 10.1454247 365.8970633 60.2981307 10.1454247 +0.388 363.631857 59.9535983 10.0929674 363.631857 59.9535983 10.0929674 +0.389 361.3842561 59.611579 10.0408664 361.3842561 59.611579 10.0408664 +0.39 359.1540931 59.2720498 9.9891187 359.1540931 59.2720498 9.9891187 +0.391 356.9412021 58.9349881 9.9377213 356.9412021 58.9349881 9.9377213 +0.392 354.7454193 58.6003717 9.8866709 354.7454193 58.6003717 9.8866709 +0.393 352.5665826 58.2681784 9.8359647 352.5665826 58.2681784 9.8359647 +0.394 350.4045319 57.9383862 9.7855997 350.4045319 57.9383862 9.7855997 +0.395 348.2591089 57.6109737 9.7355729 348.2591089 57.6109737 9.7355729 +0.396 346.1301569 57.2859194 9.6858814 346.1301569 57.2859194 9.6858814 +0.397 344.0175213 56.9632022 9.6365223 344.0175213 56.9632022 9.6365223 +0.398 341.9210489 56.6428011 9.5874928 341.9210489 56.6428011 9.5874928 +0.399 339.8405885 56.3246954 9.5387901 339.8405885 56.3246954 9.5387901 +0.4 337.7759903 56.0088648 9.4904113 337.7759903 56.0088648 9.4904113 +0.401 335.7271066 55.6952889 9.4423537 335.7271066 55.6952889 9.4423537 +0.402 333.6937909 55.3839477 9.3946146 333.6937909 55.3839477 9.3946146 +0.403 331.6758987 55.0748214 9.3471913 331.6758987 55.0748214 9.3471913 +0.404 329.6732868 54.7678904 9.3000811 329.6732868 54.7678904 9.3000811 +0.405 327.6858138 54.4631355 9.2532814 327.6858138 54.4631355 9.2532814 +0.406 325.7133399 54.1605373 9.2067894 325.7133399 54.1605373 9.2067894 +0.407 323.7557266 53.8600769 9.1606028 323.7557266 53.8600769 9.1606028 +0.408 321.8128372 53.5617355 9.1147188 321.8128372 53.5617355 9.1147188 +0.409 319.8845364 53.2654947 9.069135 319.8845364 53.2654947 9.069135 +0.41 317.9706903 52.971336 9.0238489 317.9706903 52.971336 9.0238489 +0.411 316.0711666 52.6792413 8.9788579 316.0711666 52.6792413 8.9788579 +0.412 314.1858343 52.3891926 8.9341596 314.1858343 52.3891926 8.9341596 +0.413 312.3145641 52.1011721 8.8897516 312.3145641 52.1011721 8.8897516 +0.414 310.4572279 51.8151622 8.8456315 310.4572279 51.8151622 8.8456315 +0.415 308.6136989 51.5311456 8.8017969 308.6136989 51.5311456 8.8017969 +0.416 306.783852 51.2491049 8.7582454 306.783852 51.2491049 8.7582454 +0.417 304.9675631 50.9690232 8.7149747 304.9675631 50.9690232 8.7149747 +0.418 303.1647097 50.6908836 8.6719826 303.1647097 50.6908836 8.6719826 +0.419 301.3751706 50.4146694 8.6292666 301.3751706 50.4146694 8.6292666 +0.42 299.5988257 50.1403641 8.5868246 299.5988257 50.1403641 8.5868246 +0.421 297.8355565 49.8679514 8.5446543 297.8355565 49.8679514 8.5446543 +0.422 296.0852455 49.597415 8.5027536 296.0852455 49.597415 8.5027536 +0.423 294.3477765 49.328739 8.4611201 294.3477765 49.328739 8.4611201 +0.424 292.6230348 49.0619075 8.4197518 292.6230348 49.0619075 8.4197518 +0.425 290.9109067 48.7969049 8.3786464 290.9109067 48.7969049 8.3786464 +0.426 289.2112796 48.5337157 8.337802 289.2112796 48.5337157 8.337802 +0.427 287.5240424 48.2723245 8.2972163 287.5240424 48.2723245 8.2972163 +0.428 285.8490849 48.0127161 8.2568873 285.8490849 48.0127161 8.2568873 +0.429 284.1862984 47.7548755 8.2168129 284.1862984 47.7548755 8.2168129 +0.43 282.5355749 47.4987878 8.176991 282.5355749 47.4987878 8.176991 +0.431 280.8968079 47.2444382 8.1374197 280.8968079 47.2444382 8.1374197 +0.432 279.2698919 46.9918123 8.098097 279.2698919 46.9918123 8.098097 +0.433 277.6547226 46.7408954 8.0590208 277.6547226 46.7408954 8.0590208 +0.434 276.0511966 46.4916735 8.0201893 276.0511966 46.4916735 8.0201893 +0.435 274.4592117 46.2441323 7.9816004 274.4592117 46.2441323 7.9816004 +0.436 272.8786668 45.9982578 7.9432522 272.8786668 45.9982578 7.9432522 +0.437 271.3094618 45.7540362 7.9051429 271.3094618 45.7540362 7.9051429 +0.438 269.7514977 45.5114537 7.8672705 269.7514977 45.5114537 7.8672705 +0.439 268.2046764 45.2704969 7.8296332 268.2046764 45.2704969 7.8296332 +0.44 266.668901 45.0311521 7.7922291 266.668901 45.0311521 7.7922291 +0.441 265.1440755 44.7934062 7.7550565 265.1440755 44.7934062 7.7550565 +0.442 263.6301049 44.557246 7.7181134 263.6301049 44.557246 7.7181134 +0.443 262.1268953 44.3226583 7.6813981 262.1268953 44.3226583 7.6813981 +0.444 260.6343534 44.0896304 7.6449088 260.6343534 44.0896304 7.6449088 +0.445 259.1523873 43.8581493 7.6086438 259.1523873 43.8581493 7.6086438 +0.446 257.6809058 43.6282025 7.5726013 257.6809058 43.6282025 7.5726013 +0.447 256.2198188 43.3997775 7.5367796 256.2198188 43.3997775 7.5367796 +0.448 254.7690369 43.1728617 7.5011769 254.7690369 43.1728617 7.5011769 +0.449 253.3284718 42.947443 7.4657916 253.3284718 42.947443 7.4657916 +0.45 251.8980359 42.7235091 7.430622 251.8980359 42.7235091 7.430622 +0.451 250.4776428 42.501048 7.3956665 250.4776428 42.501048 7.3956665 +0.452 249.0672067 42.2800478 7.3609233 249.0672067 42.2800478 7.3609233 +0.453 247.6666428 42.0604967 7.3263909 247.6666428 42.0604967 7.3263909 +0.454 246.2758672 41.842383 7.2920677 246.2758672 41.842383 7.2920677 +0.455 244.8947966 41.625695 7.257952 244.8947966 41.625695 7.257952 +0.456 243.5233489 41.4104214 7.2240422 243.5233489 41.4104214 7.2240422 +0.457 242.1614425 41.1965508 7.1903369 242.1614425 41.1965508 7.1903369 +0.458 240.8089969 40.9840718 7.1568344 240.8089969 40.9840718 7.1568344 +0.459 239.4659322 40.7729735 7.1235332 239.4659322 40.7729735 7.1235332 +0.46 238.1321693 40.5632447 7.0904317 238.1321693 40.5632447 7.0904317 +0.461 236.8076301 40.3548745 7.0575286 236.8076301 40.3548745 7.0575286 +0.462 235.4922372 40.1478521 7.0248222 235.4922372 40.1478521 7.0248222 +0.463 234.1859137 39.9421668 6.992311 234.1859137 39.9421668 6.992311 +0.464 232.8885838 39.7378079 6.9599937 232.8885838 39.7378079 6.9599937 +0.465 231.6001723 39.5347651 6.9278688 231.6001723 39.5347651 6.9278688 +0.466 230.3206049 39.3330277 6.8959348 230.3206049 39.3330277 6.8959348 +0.467 229.0498078 39.1325857 6.8641902 229.0498078 39.1325857 6.8641902 +0.468 227.787708 38.9334286 6.8326338 227.787708 38.9334286 6.8326338 +0.469 226.5342334 38.7355464 6.801264 226.5342334 38.7355464 6.801264 +0.47 225.2893125 38.5389292 6.7700794 225.2893125 38.5389292 6.7700794 +0.471 224.0528743 38.3435668 6.7390788 224.0528743 38.3435668 6.7390788 +0.472 222.8248488 38.1494496 6.7082608 222.8248488 38.1494496 6.7082608 +0.473 221.6051665 37.9565678 6.6776239 221.6051665 37.9565678 6.6776239 +0.474 220.3937588 37.7649118 6.6471669 220.3937588 37.7649118 6.6471669 +0.475 219.1905574 37.5744719 6.6168884 219.1905574 37.5744719 6.6168884 +0.476 217.995495 37.3852387 6.5867871 217.995495 37.3852387 6.5867871 +0.477 216.8085049 37.1972029 6.5568617 216.8085049 37.1972029 6.5568617 +0.478 215.6295208 37.0103551 6.5271109 215.6295208 37.0103551 6.5271109 +0.479 214.4584774 36.8246861 6.4975335 214.4584774 36.8246861 6.4975335 +0.48 213.2953097 36.6401869 6.4681281 213.2953097 36.6401869 6.4681281 +0.481 212.1399536 36.4568483 6.4388935 212.1399536 36.4568483 6.4388935 +0.482 210.9923455 36.2746615 6.4098286 210.9923455 36.2746615 6.4098286 +0.483 209.8524225 36.0936176 6.3809319 209.8524225 36.0936176 6.3809319 +0.484 208.720122 35.9137077 6.3522023 208.720122 35.9137077 6.3522023 +0.485 207.5953824 35.7349232 6.3236387 207.5953824 35.7349232 6.3236387 +0.486 206.4781425 35.5572555 6.2952397 206.4781425 35.5572555 6.2952397 +0.487 205.3683417 35.3806959 6.2670043 205.3683417 35.3806959 6.2670043 +0.488 204.26592 35.2052361 6.2389312 204.26592 35.2052361 6.2389312 +0.489 203.1708179 35.0308677 6.2110192 203.1708179 35.0308677 6.2110192 +0.49 202.0829765 34.8575823 6.1832672 202.0829765 34.8575823 6.1832672 +0.491 201.0023376 34.6853717 6.1556741 201.0023376 34.6853717 6.1556741 +0.492 199.9288434 34.5142278 6.1282387 199.9288434 34.5142278 6.1282387 +0.493 198.8624366 34.3441424 6.1009599 198.8624366 34.3441424 6.1009599 +0.494 197.8030607 34.1751076 6.0738365 197.8030607 34.1751076 6.0738365 +0.495 196.7506594 34.0071154 6.0468675 196.7506594 34.0071154 6.0468675 +0.496 195.7051773 33.8401579 6.0200517 195.7051773 33.8401579 6.0200517 +0.497 194.6665591 33.6742273 5.9933881 194.6665591 33.6742273 5.9933881 +0.498 193.6347503 33.509316 5.9668756 193.6347503 33.509316 5.9668756 +0.499 192.6096969 33.3454163 5.9405131 192.6096969 33.3454163 5.9405131 +0.5 191.5913454 33.1825205 5.9142996 191.5913454 33.1825205 5.9142996 +0.501 190.5796426 33.0206211 5.888234 190.5796426 33.0206211 5.888234 +0.502 189.5745362 32.8597108 5.8623152 189.5745362 32.8597108 5.8623152 +0.503 188.5759739 32.6997821 5.8365423 188.5759739 32.6997821 5.8365423 +0.504 187.5839043 32.5408276 5.8109141 187.5839043 32.5408276 5.8109141 +0.505 186.5982763 32.3828402 5.7854298 186.5982763 32.3828402 5.7854298 +0.506 185.6190392 32.2258127 5.7600882 185.6190392 32.2258127 5.7600882 +0.507 184.646143 32.0697379 5.7348884 184.646143 32.0697379 5.7348884 +0.508 183.6795379 31.9146087 5.7098294 183.6795379 31.9146087 5.7098294 +0.509 182.7191747 31.7604183 5.6849101 182.7191747 31.7604183 5.6849101 +0.51 181.7650046 31.6071595 5.6601298 181.7650046 31.6071595 5.6601298 +0.511 180.8169795 31.4548256 5.6354873 180.8169795 31.4548256 5.6354873 +0.512 179.8750513 31.3034097 5.6109817 179.8750513 31.3034097 5.6109817 +0.513 178.9391727 31.1529051 5.586612 178.9391727 31.1529051 5.586612 +0.514 178.0092967 31.0033051 5.5623774 178.0092967 31.0033051 5.5623774 +0.515 177.0853767 30.8546031 5.5382769 177.0853767 30.8546031 5.5382769 +0.516 176.1673666 30.7067924 5.5143096 176.1673666 30.7067924 5.5143096 +0.517 175.2552207 30.5598666 5.4904745 175.2552207 30.5598666 5.4904745 +0.518 174.3488937 30.4138191 5.4667707 174.3488937 30.4138191 5.4667707 +0.519 173.4483407 30.2686436 5.4431974 173.4483407 30.2686436 5.4431974 +0.52 172.5535172 30.1243337 5.4197536 172.5535172 30.1243337 5.4197536 +0.521 171.6643793 29.9808832 5.3964385 171.6643793 29.9808832 5.3964385 +0.522 170.7808831 29.8382858 5.3732511 170.7808831 29.8382858 5.3732511 +0.523 169.9029855 29.6965352 5.3501907 169.9029855 29.6965352 5.3501907 +0.524 169.0306436 29.5556254 5.3272563 169.0306436 29.5556254 5.3272563 +0.525 168.1638148 29.4155503 5.3044471 168.1638148 29.4155503 5.3044471 +0.526 167.3024571 29.2763038 5.2817622 167.3024571 29.2763038 5.2817622 +0.527 166.4465288 29.1378801 5.2592009 166.4465288 29.1378801 5.2592009 +0.528 165.5959885 29.000273 5.2367621 165.5959885 29.000273 5.2367621 +0.529 164.7507952 28.8634769 5.2144453 164.7507952 28.8634769 5.2144453 +0.53 163.9109083 28.7274858 5.1922494 163.9109083 28.7274858 5.1922494 +0.531 163.0762876 28.5922939 5.1701737 163.0762876 28.5922939 5.1701737 +0.532 162.2468931 28.4578957 5.1482173 162.2468931 28.4578957 5.1482173 +0.533 161.4226854 28.3242853 5.1263796 161.4226854 28.3242853 5.1263796 +0.534 160.6036253 28.1914571 5.1046596 160.6036253 28.1914571 5.1046596 +0.535 159.7896739 28.0594056 5.0830567 159.7896739 28.0594056 5.0830567 +0.536 158.9807927 27.9281253 5.0615699 158.9807927 27.9281253 5.0615699 +0.537 158.1769437 27.7976106 5.0401986 158.1769437 27.7976106 5.0401986 +0.538 157.378089 27.6678562 5.018942 157.378089 27.6678562 5.018942 +0.539 156.5841911 27.5388565 4.9977992 156.5841911 27.5388565 4.9977992 +0.54 155.7952129 27.4106063 4.9767696 155.7952129 27.4106063 4.9767696 +0.541 155.0111177 27.2831003 4.9558524 155.0111177 27.2831003 4.9558524 +0.542 154.2318688 27.1563333 4.9350468 154.2318688 27.1563333 4.9350468 +0.543 153.4574302 27.0302999 4.9143522 153.4574302 27.0302999 4.9143522 +0.544 152.687766 26.904995 4.8937677 152.687766 26.904995 4.8937677 +0.545 151.9228407 26.7804136 4.8732926 151.9228407 26.7804136 4.8732926 +0.546 151.1626191 26.6565505 4.8529263 151.1626191 26.6565505 4.8529263 +0.547 150.4070662 26.5334007 4.832668 150.4070662 26.5334007 4.832668 +0.548 149.6561475 26.4109592 4.812517 149.6561475 26.4109592 4.812517 +0.549 148.9098286 26.289221 4.7924726 148.9098286 26.289221 4.7924726 +0.55 148.1680756 26.1681812 4.7725341 148.1680756 26.1681812 4.7725341 +0.551 147.4308547 26.0478349 4.7527008 147.4308547 26.0478349 4.7527008 +0.552 146.6981325 25.9281774 4.7329721 146.6981325 25.9281774 4.7329721 +0.553 145.969876 25.8092038 4.7133471 145.969876 25.8092038 4.7133471 +0.554 145.2460523 25.6909093 4.6938253 145.2460523 25.6909093 4.6938253 +0.555 144.5266287 25.5732893 4.674406 144.5266287 25.5732893 4.674406 +0.556 143.8115732 25.4563391 4.6550885 143.8115732 25.4563391 4.6550885 +0.557 143.1008536 25.340054 4.6358722 143.1008536 25.340054 4.6358722 +0.558 142.3944382 25.2244294 4.6167564 142.3944382 25.2244294 4.6167564 +0.559 141.6922957 25.1094608 4.5977404 141.6922957 25.1094608 4.5977404 +0.56 140.9943949 24.9951437 4.5788237 140.9943949 24.9951437 4.5788237 +0.561 140.3007048 24.8814735 4.5600055 140.3007048 24.8814735 4.5600055 +0.562 139.6111948 24.7684458 4.5412852 139.6111948 24.7684458 4.5412852 +0.563 138.9258345 24.6560562 4.5226623 138.9258345 24.6560562 4.5226623 +0.564 138.2445939 24.5443004 4.504136 138.2445939 24.5443004 4.504136 +0.565 137.567443 24.4331739 4.4857058 137.567443 24.4331739 4.4857058 +0.566 136.8943523 24.3226725 4.467371 136.8943523 24.3226725 4.467371 +0.567 136.2252924 24.2127919 4.4491311 136.2252924 24.2127919 4.4491311 +0.568 135.5602343 24.1035279 4.4309854 135.5602343 24.1035279 4.4309854 +0.569 134.899149 23.9948762 4.4129333 134.899149 23.9948762 4.4129333 +0.57 134.242008 23.8868327 4.3949742 134.242008 23.8868327 4.3949742 +0.571 133.5887829 23.7793933 4.3771076 133.5887829 23.7793933 4.3771076 +0.572 132.9394456 23.6725538 4.3593328 132.9394456 23.6725538 4.3593328 +0.573 132.2939681 23.5663102 4.3416493 132.2939681 23.5663102 4.3416493 +0.574 131.6523229 23.4606585 4.3240564 131.6523229 23.4606585 4.3240564 +0.575 131.0144825 23.3555946 4.3065537 131.0144825 23.3555946 4.3065537 +0.576 130.3804198 23.2511146 4.2891405 130.3804198 23.2511146 4.2891405 +0.577 129.7501078 23.1472146 4.2718163 129.7501078 23.1472146 4.2718163 +0.578 129.1235197 23.0438906 4.2545805 129.1235197 23.0438906 4.2545805 +0.579 128.500629 22.9411387 4.2374326 128.500629 22.9411387 4.2374326 +0.58 127.8814095 22.8389551 4.220372 127.8814095 22.8389551 4.220372 +0.581 127.2658351 22.7373361 4.2033981 127.2658351 22.7373361 4.2033981 +0.582 126.65388 22.6362777 4.1865105 126.65388 22.6362777 4.1865105 +0.583 126.0455185 22.5357763 4.1697085 126.0455185 22.5357763 4.1697085 +0.584 125.4407252 22.4358282 4.1529917 125.4407252 22.4358282 4.1529917 +0.585 124.8394749 22.3364296 4.1363594 124.8394749 22.3364296 4.1363594 +0.586 124.2417426 22.2375768 4.1198113 124.2417426 22.2375768 4.1198113 +0.587 123.6475035 22.1392663 4.1033467 123.6475035 22.1392663 4.1033467 +0.588 123.056733 22.0414944 4.0869651 123.056733 22.0414944 4.0869651 +0.589 122.4694068 21.9442576 4.0706661 122.4694068 21.9442576 4.0706661 +0.59 121.8855007 21.8475522 4.0544491 121.8855007 21.8475522 4.0544491 +0.591 121.3049907 21.7513748 4.0383135 121.3049907 21.7513748 4.0383135 +0.592 120.727853 21.6557219 4.022259 120.727853 21.6557219 4.022259 +0.593 120.154064 21.56059 4.0062849 120.154064 21.56059 4.0062849 +0.594 119.5836004 21.4659757 3.9903909 119.5836004 21.4659757 3.9903909 +0.595 119.016439 21.3718756 3.9745764 119.016439 21.3718756 3.9745764 +0.596 118.4525566 21.2782862 3.9588408 118.4525566 21.2782862 3.9588408 +0.597 117.8919307 21.1852042 3.9431838 117.8919307 21.1852042 3.9431838 +0.598 117.3345384 21.0926262 3.9276049 117.3345384 21.0926262 3.9276049 +0.599 116.7803573 21.0005491 3.9121035 116.7803573 21.0005491 3.9121035 +0.6 116.2293653 20.9089694 3.8966792 116.2293653 20.9089694 3.8966792 +0.601 115.6815402 20.8178839 3.8813315 115.6815402 20.8178839 3.8813315 +0.602 115.13686 20.7272894 3.86606 115.13686 20.7272894 3.86606 +0.603 114.5953032 20.6371827 3.8508642 114.5953032 20.6371827 3.8508642 +0.604 114.0568481 20.5475606 3.8357436 114.0568481 20.5475606 3.8357436 +0.605 113.5214734 20.45842 3.8206977 113.5214734 20.45842 3.8206977 +0.606 112.9891578 20.3697576 3.8057262 112.9891578 20.3697576 3.8057262 +0.607 112.4598804 20.2815705 3.7908285 112.4598804 20.2815705 3.7908285 +0.608 111.9336202 20.1938554 3.7760043 111.9336202 20.1938554 3.7760043 +0.609 111.4103567 20.1066094 3.761253 111.4103567 20.1066094 3.761253 +0.61 110.8900692 20.0198294 3.7465743 110.8900692 20.0198294 3.7465743 +0.611 110.3727375 19.9335124 3.7319676 110.3727375 19.9335124 3.7319676 +0.612 109.8583413 19.8476555 3.7174326 109.8583413 19.8476555 3.7174326 +0.613 109.3468606 19.7622555 3.7029688 109.3468606 19.7622555 3.7029688 +0.614 108.8382755 19.6773096 3.6885758 108.8382755 19.6773096 3.6885758 +0.615 108.3325663 19.592815 3.6742532 108.3325663 19.592815 3.6742532 +0.616 107.8297135 19.5087685 3.6600006 107.8297135 19.5087685 3.6600006 +0.617 107.3296977 19.4251675 3.6458174 107.3296977 19.4251675 3.6458174 +0.618 106.8324997 19.342009 3.6317034 106.8324997 19.342009 3.6317034 +0.619 106.3381002 19.2592901 3.6176581 106.3381002 19.2592901 3.6176581 +0.62 105.8464805 19.1770082 3.6036811 105.8464805 19.1770082 3.6036811 +0.621 105.3576217 19.0951603 3.5897719 105.3576217 19.0951603 3.5897719 +0.622 104.8715052 19.0137437 3.5759302 104.8715052 19.0137437 3.5759302 +0.623 104.3881125 18.9327557 3.5621556 104.3881125 18.9327557 3.5621556 +0.624 103.9074253 18.8521936 3.5484477 103.9074253 18.8521936 3.5484477 +0.625 103.4294254 18.7720545 3.534806 103.4294254 18.7720545 3.534806 +0.626 102.9540947 18.6923359 3.5212303 102.9540947 18.6923359 3.5212303 +0.627 102.4814152 18.613035 3.50772 102.4814152 18.613035 3.50772 +0.628 102.0113694 18.5341493 3.4942748 102.0113694 18.5341493 3.4942748 +0.629 101.5439394 18.455676 3.4808944 101.5439394 18.455676 3.4808944 +0.63 101.0791079 18.3776126 3.4675783 101.0791079 18.3776126 3.4675783 +0.631 100.6168575 18.2999565 3.4543261 100.6168575 18.2999565 3.4543261 +0.632 100.1571709 18.2227051 3.4411376 100.1571709 18.2227051 3.4411376 +0.633 99.7000311 18.1458558 3.4280123 99.7000311 18.1458558 3.4280123 +0.634 99.2454212 18.0694062 3.4149498 99.2454212 18.0694062 3.4149498 +0.635 98.7933242 17.9933537 3.4019497 98.7933242 17.9933537 3.4019497 +0.636 98.3437237 17.9176958 3.3890118 98.3437237 17.9176958 3.3890118 +0.637 97.8966029 17.8424301 3.3761357 97.8966029 17.8424301 3.3761357 +0.638 97.4519455 17.767554 3.3633209 97.4519455 17.767554 3.3633209 +0.639 97.0097351 17.6930652 3.3505671 97.0097351 17.6930652 3.3505671 +0.64 96.5699557 17.6189612 3.337874 96.5699557 17.6189612 3.337874 +0.641 96.1325912 17.5452397 3.3252412 96.1325912 17.5452397 3.3252412 +0.642 95.6976256 17.4718981 3.3126684 95.6976256 17.4718981 3.3126684 +0.643 95.2650431 17.3989342 3.3001551 95.2650431 17.3989342 3.3001551 +0.644 94.8348282 17.3263457 3.2877012 94.8348282 17.3263457 3.2877012 +0.645 94.4069651 17.2541301 3.2753062 94.4069651 17.2541301 3.2753062 +0.646 93.9814386 17.1822851 3.2629697 93.9814386 17.1822851 3.2629697 +0.647 93.5582333 17.1108086 3.2506915 93.5582333 17.1108086 3.2506915 +0.648 93.1373339 17.0396981 3.2384713 93.1373339 17.0396981 3.2384713 +0.649 92.7187255 16.9689514 3.2263085 92.7187255 16.9689514 3.2263085 +0.65 92.302393 16.8985663 3.2142031 92.302393 16.8985663 3.2142031 +0.651 91.8883217 16.8285405 3.2021545 91.8883217 16.8285405 3.2021545 +0.652 91.4764967 16.7588718 3.1901625 91.4764967 16.7588718 3.1901625 +0.653 91.0669035 16.689558 3.1782268 91.0669035 16.689558 3.1782268 +0.654 90.6595276 16.620597 3.166347 90.6595276 16.620597 3.166347 +0.655 90.2543545 16.5519865 3.1545229 90.2543545 16.5519865 3.1545229 +0.656 89.85137 16.4837244 3.142754 89.85137 16.4837244 3.142754 +0.657 89.4505599 16.4158086 3.1310401 89.4505599 16.4158086 3.1310401 +0.658 89.0519101 16.3482369 3.1193809 89.0519101 16.3482369 3.1193809 +0.659 88.6554066 16.2810073 3.1077761 88.6554066 16.2810073 3.1077761 +0.66 88.2610357 16.2141176 3.0962252 88.2610357 16.2141176 3.0962252 +0.661 87.8687835 16.1475658 3.0847282 87.8687835 16.1475658 3.0847282 +0.662 87.4786365 16.0813498 3.0732845 87.4786365 16.0813498 3.0732845 +0.663 87.090581 16.0154675 3.061894 87.090581 16.0154675 3.061894 +0.664 86.7046036 15.949917 3.0505563 86.7046036 15.949917 3.0505563 +0.665 86.320691 15.8846962 3.0392712 86.320691 15.8846962 3.0392712 +0.666 85.93883 15.8198031 3.0280382 85.93883 15.8198031 3.0280382 +0.667 85.5590074 15.7552357 3.0168572 85.5590074 15.7552357 3.0168572 +0.668 85.1812101 15.690992 3.0057279 85.1812101 15.690992 3.0057279 +0.669 84.8054253 15.6270702 2.9946499 84.8054253 15.6270702 2.9946499 +0.67 84.43164 15.5634682 2.983623 84.43164 15.5634682 2.983623 +0.671 84.0598416 15.500184 2.9726468 84.0598416 15.500184 2.9726468 +0.672 83.6900173 15.4372159 2.9617211 83.6900173 15.4372159 2.9617211 +0.673 83.3221547 15.3745619 2.9508456 83.3221547 15.3745619 2.9508456 +0.674 82.9562412 15.31222 2.9400201 82.9562412 15.31222 2.9400201 +0.675 82.5922645 15.2501885 2.9292442 82.5922645 15.2501885 2.9292442 +0.676 82.2302123 15.1884654 2.9185176 82.2302123 15.1884654 2.9185176 +0.677 81.8700724 15.1270489 2.9078402 81.8700724 15.1270489 2.9078402 +0.678 81.5118328 15.0659372 2.8972116 81.5118328 15.0659372 2.8972116 +0.679 81.1554813 15.0051284 2.8866315 81.1554813 15.0051284 2.8866315 +0.68 80.8010062 14.9446207 2.8760997 80.8010062 14.9446207 2.8760997 +0.681 80.4483955 14.8844124 2.8656158 80.4483955 14.8844124 2.8656158 +0.682 80.0976376 14.8245015 2.8551798 80.0976376 14.8245015 2.8551798 +0.683 79.7487207 14.7648865 2.8447912 79.7487207 14.7648865 2.8447912 +0.684 79.4016333 14.7055654 2.8344498 79.4016333 14.7055654 2.8344498 +0.685 79.0563639 14.6465366 2.8241553 79.0563639 14.6465366 2.8241553 +0.686 78.7129012 14.5877983 2.8139075 78.7129012 14.5877983 2.8139075 +0.687 78.3712338 14.5293488 2.8037062 78.3712338 14.5293488 2.8037062 +0.688 78.0313504 14.4711864 2.793551 78.0313504 14.4711864 2.793551 +0.689 77.69324 14.4133093 2.7834418 77.69324 14.4133093 2.7834418 +0.69 77.3568914 14.355716 2.7733782 77.3568914 14.355716 2.7733782 +0.691 77.0222938 14.2984046 2.76336 77.0222938 14.2984046 2.76336 +0.692 76.689436 14.2413736 2.753387 76.689436 14.2413736 2.753387 +0.693 76.3583075 14.1846212 2.7434589 76.3583075 14.1846212 2.7434589 +0.694 76.0288973 14.1281459 2.7335755 76.0288973 14.1281459 2.7335755 +0.695 75.7011949 14.0719461 2.7237365 75.7011949 14.0719461 2.7237365 +0.696 75.3751896 14.01602 2.7139416 75.3751896 14.01602 2.7139416 +0.697 75.0508709 13.9603661 2.7041907 75.0508709 13.9603661 2.7041907 +0.698 74.7282285 13.9049827 2.6944835 74.7282285 13.9049827 2.6944835 +0.699 74.4072519 13.8498684 2.6848198 74.4072519 13.8498684 2.6848198 +0.7 74.0879308 13.7950215 2.6751993 74.0879308 13.7950215 2.6751993 +0.701 73.7702551 13.7404405 2.6656217 73.7702551 13.7404405 2.6656217 +0.702 73.4542145 13.6861238 2.656087 73.4542145 13.6861238 2.656087 +0.703 73.1397992 13.6320698 2.6465947 73.1397992 13.6320698 2.6465947 +0.704 72.8269989 13.5782771 2.6371447 72.8269989 13.5782771 2.6371447 +0.705 72.5158039 13.5247441 2.6277368 72.5158039 13.5247441 2.6277368 +0.706 72.2062043 13.4714693 2.6183707 72.2062043 13.4714693 2.6183707 +0.707 71.8981904 13.4184512 2.6090463 71.8981904 13.4184512 2.6090463 +0.708 71.5917523 13.3656882 2.5997632 71.5917523 13.3656882 2.5997632 +0.709 71.2868805 13.3131791 2.5905212 71.2868805 13.3131791 2.5905212 +0.71 70.9835654 13.2609221 2.5813202 70.9835654 13.2609221 2.5813202 +0.711 70.6817975 13.208916 2.5721599 70.6817975 13.208916 2.5721599 +0.712 70.3815674 13.1571592 2.5630401 70.3815674 13.1571592 2.5630401 +0.713 70.0828658 13.1056503 2.5539606 70.0828658 13.1056503 2.5539606 +0.714 69.7856832 13.0543879 2.5449211 69.7856832 13.0543879 2.5449211 +0.715 69.4900106 13.0033705 2.5359215 69.4900106 13.0033705 2.5359215 +0.716 69.1958387 12.9525968 2.5269615 69.1958387 12.9525968 2.5269615 +0.717 68.9031585 12.9020653 2.5180409 68.9031585 12.9020653 2.5180409 +0.718 68.6119608 12.8517746 2.5091596 68.6119608 12.8517746 2.5091596 +0.719 68.3222368 12.8017234 2.5003172 68.3222368 12.8017234 2.5003172 +0.72 68.0339775 12.7519103 2.4915136 68.0339775 12.7519103 2.4915136 +0.721 67.7471742 12.702334 2.4827486 67.7471742 12.702334 2.4827486 +0.722 67.4618179 12.652993 2.474022 67.4618179 12.652993 2.474022 +0.723 67.1779001 12.603886 2.4653335 67.1779001 12.603886 2.4653335 +0.724 66.895412 12.5550117 2.456683 66.895412 12.5550117 2.456683 +0.725 66.614345 12.5063688 2.4480703 66.614345 12.5063688 2.4480703 +0.726 66.3346907 12.4579559 2.4394952 66.3346907 12.4579559 2.4394952 +0.727 66.0564406 12.4097717 2.4309574 66.0564406 12.4097717 2.4309574 +0.728 65.7795861 12.3618149 2.4224568 65.7795861 12.3618149 2.4224568 +0.729 65.5041191 12.3140843 2.4139931 65.5041191 12.3140843 2.4139931 +0.73 65.2300311 12.2665786 2.4055663 65.2300311 12.2665786 2.4055663 +0.731 64.9573141 12.2192964 2.397176 64.9573141 12.2192964 2.397176 +0.732 64.6859596 12.1722365 2.3888221 64.6859596 12.1722365 2.3888221 +0.733 64.4159598 12.1253977 2.3805044 64.4159598 12.1253977 2.3805044 +0.734 64.1473064 12.0787787 2.3722227 64.1473064 12.0787787 2.3722227 +0.735 63.8799915 12.0323782 2.3639768 63.8799915 12.0323782 2.3639768 +0.736 63.6140072 11.9861951 2.3557666 63.6140072 11.9861951 2.3557666 +0.737 63.3493455 11.940228 2.3475917 63.3493455 11.940228 2.3475917 +0.738 63.0859986 11.8944759 2.3394522 63.0859986 11.8944759 2.3394522 +0.739 62.8239587 11.8489374 2.3313477 62.8239587 11.8489374 2.3313477 +0.74 62.5632181 11.8036114 2.3232781 62.5632181 11.8036114 2.3232781 +0.741 62.303769 11.7584966 2.3152432 62.303769 11.7584966 2.3152432 +0.742 62.045604 11.713592 2.3072429 62.045604 11.713592 2.3072429 +0.743 61.7887153 11.6688963 2.2992769 61.7887153 11.6688963 2.2992769 +0.744 61.5330955 11.6244083 2.291345 61.5330955 11.6244083 2.291345 +0.745 61.2787372 11.5801269 2.2834471 61.2787372 11.5801269 2.2834471 +0.746 61.0256328 11.5360509 2.2755831 61.0256328 11.5360509 2.2755831 +0.747 60.7737751 11.4921792 2.2677526 60.7737751 11.4921792 2.2677526 +0.748 60.5231566 11.4485107 2.2599557 60.5231566 11.4485107 2.2599557 +0.749 60.2737703 11.4050442 2.252192 60.2737703 11.4050442 2.252192 +0.75 60.0256087 11.3617785 2.2444614 60.0256087 11.3617785 2.2444614 +0.751 59.7786649 11.3187127 2.2367638 59.7786649 11.3187127 2.2367638 +0.752 59.5329316 11.2758455 2.2290989 59.5329316 11.2758455 2.2290989 +0.753 59.2884018 11.2331758 2.2214666 59.2884018 11.2331758 2.2214666 +0.754 59.0450684 11.1907026 2.2138668 59.0450684 11.1907026 2.2138668 +0.755 58.8029246 11.1484248 2.2062993 58.8029246 11.1484248 2.2062993 +0.756 58.5619634 11.1063413 2.1987638 58.5619634 11.1063413 2.1987638 +0.757 58.3221779 11.064451 2.1912603 58.3221779 11.064451 2.1912603 +0.758 58.0835612 11.0227529 2.1837885 58.0835612 11.0227529 2.1837885 +0.759 57.8461067 10.9812459 2.1763483 57.8461067 10.9812459 2.1763483 +0.76 57.6098075 10.9399289 2.1689396 57.6098075 10.9399289 2.1689396 +0.761 57.374657 10.8988008 2.1615622 57.374657 10.8988008 2.1615622 +0.762 57.1406485 10.8578608 2.1542159 57.1406485 10.8578608 2.1542159 +0.763 56.9077755 10.8171077 2.1469005 56.9077755 10.8171077 2.1469005 +0.764 56.6760313 10.7765404 2.139616 56.6760313 10.7765404 2.139616 +0.765 56.4454095 10.7361581 2.1323621 56.4454095 10.7361581 2.1323621 +0.766 56.2159036 10.6959596 2.1251387 56.2159036 10.6959596 2.1251387 +0.767 55.9875072 10.655944 2.1179456 55.9875072 10.655944 2.1179456 +0.768 55.760214 10.6161102 2.1107827 55.760214 10.6161102 2.1107827 +0.769 55.5340174 10.5764573 2.1036499 55.5340174 10.5764573 2.1036499 +0.77 55.3089114 10.5369842 2.0965469 55.3089114 10.5369842 2.0965469 +0.771 55.0848896 10.4976901 2.0894736 55.0848896 10.4976901 2.0894736 +0.772 54.8619458 10.4585739 2.0824299 54.8619458 10.4585739 2.0824299 +0.773 54.6400739 10.4196346 2.0754157 54.6400739 10.4196346 2.0754157 +0.774 54.4192677 10.3808713 2.0684307 54.4192677 10.3808713 2.0684307 +0.775 54.1995211 10.3422831 2.0614748 54.1995211 10.3422831 2.0614748 +0.776 53.9808282 10.303869 2.0545479 53.9808282 10.303869 2.0545479 +0.777 53.7631829 10.265628 2.0476498 53.7631829 10.265628 2.0476498 +0.778 53.5465792 10.2275592 2.0407804 53.5465792 10.2275592 2.0407804 +0.779 53.3310112 10.1896616 2.0339396 53.3310112 10.1896616 2.0339396 +0.78 53.116473 10.1519345 2.0271272 53.116473 10.1519345 2.0271272 +0.781 52.9029589 10.1143767 2.020343 52.9029589 10.1143767 2.020343 +0.782 52.6904629 10.0769875 2.0135869 52.6904629 10.0769875 2.0135869 +0.783 52.4789794 10.0397659 2.0068588 52.4789794 10.0397659 2.0068588 +0.784 52.2685025 10.0027109 2.0001585 52.2685025 10.0027109 2.0001585 +0.785 52.0590267 9.9658218 1.9934859 52.0590267 9.9658218 1.9934859 +0.786 51.8505462 9.9290976 1.9868409 51.8505462 9.9290976 1.9868409 +0.787 51.6430554 9.8925374 1.9802232 51.6430554 9.8925374 1.9802232 +0.788 51.4365489 9.8561404 1.9736329 51.4365489 9.8561404 1.9736329 +0.789 51.2310209 9.8199057 1.9670697 51.2310209 9.8199057 1.9670697 +0.79 51.026466 9.7838323 1.9605335 51.026466 9.7838323 1.9605335 +0.791 50.8228788 9.7479195 1.9540241 50.8228788 9.7479195 1.9540241 +0.792 50.6202538 9.7121664 1.9475415 50.6202538 9.7121664 1.9475415 +0.793 50.4185857 9.6765721 1.9410855 50.4185857 9.6765721 1.9410855 +0.794 50.217869 9.6411358 1.934656 50.217869 9.6411358 1.934656 +0.795 50.0180984 9.6058567 1.9282528 50.0180984 9.6058567 1.9282528 +0.796 49.8192687 9.5707338 1.9218759 49.8192687 9.5707338 1.9218759 +0.797 49.6213746 9.5357665 1.915525 49.6213746 9.5357665 1.915525 +0.798 49.4244109 9.5009538 1.9092 49.4244109 9.5009538 1.9092 +0.799 49.2283723 9.4662949 1.9029009 49.2283723 9.4662949 1.9029009 +0.8 49.0332538 9.431789 1.8966275 49.0332538 9.431789 1.8966275 +0.801 48.8390502 9.3974354 1.8903796 48.8390502 9.3974354 1.8903796 +0.802 48.6457564 9.3632331 1.8841572 48.6457564 9.3632331 1.8841572 +0.803 48.4533674 9.3291814 1.87796 48.4533674 9.3291814 1.87796 +0.804 48.2618782 9.2952795 1.8717881 48.2618782 9.2952795 1.8717881 +0.805 48.0712838 9.2615267 1.8656413 48.0712838 9.2615267 1.8656413 +0.806 47.8815791 9.227922 1.8595194 47.8815791 9.227922 1.8595194 +0.807 47.6927594 9.1944649 1.8534223 47.6927594 9.1944649 1.8534223 +0.808 47.5048196 9.1611543 1.8473499 47.5048196 9.1611543 1.8473499 +0.809 47.317755 9.1279897 1.841302 47.317755 9.1279897 1.841302 +0.81 47.1315608 9.0949702 1.8352787 47.1315608 9.0949702 1.8352787 +0.811 46.946232 9.0620951 1.8292797 46.946232 9.0620951 1.8292797 +0.812 46.7617641 9.0293636 1.8233049 46.7617641 9.0293636 1.8233049 +0.813 46.5781521 8.9967749 1.8173541 46.5781521 8.9967749 1.8173541 +0.814 46.3953915 8.9643283 1.8114274 46.3953915 8.9643283 1.8114274 +0.815 46.2134775 8.9320232 1.8055246 46.2134775 8.9320232 1.8055246 +0.816 46.0324056 8.8998586 1.7996454 46.0324056 8.8998586 1.7996454 +0.817 45.852171 8.8678339 1.79379 45.852171 8.8678339 1.79379 +0.818 45.6727692 8.8359484 1.787958 45.6727692 8.8359484 1.787958 +0.819 45.4941957 8.8042014 1.7821494 45.4941957 8.8042014 1.7821494 +0.82 45.316446 8.772592 1.7763642 45.316446 8.772592 1.7763642 +0.821 45.1395155 8.7411197 1.7706021 45.1395155 8.7411197 1.7706021 +0.822 44.9633997 8.7097837 1.764863 44.9633997 8.7097837 1.764863 +0.823 44.7880943 8.6785832 1.759147 44.7880943 8.6785832 1.759147 +0.824 44.6135948 8.6475176 1.7534537 44.6135948 8.6475176 1.7534537 +0.825 44.4398968 8.6165862 1.7477832 44.4398968 8.6165862 1.7477832 +0.826 44.2669961 8.5857883 1.7421353 44.2669961 8.5857883 1.7421353 +0.827 44.0948882 8.5551232 1.73651 44.0948882 8.5551232 1.73651 +0.828 43.9235689 8.5245902 1.730907 43.9235689 8.5245902 1.730907 +0.829 43.7530338 8.4941886 1.7253263 43.7530338 8.4941886 1.7253263 +0.83 43.5832788 8.4639178 1.7197678 43.5832788 8.4639178 1.7197678 +0.831 43.4142997 8.4337771 1.7142314 43.4142997 8.4337771 1.7142314 +0.832 43.2460921 8.4037657 1.708717 43.2460921 8.4037657 1.708717 +0.833 43.0786521 8.3738831 1.7032245 43.0786521 8.3738831 1.7032245 +0.834 42.9119754 8.3441286 1.6977537 42.9119754 8.3441286 1.6977537 +0.835 42.7460579 8.3145015 1.6923045 42.7460579 8.3145015 1.6923045 +0.836 42.5808956 8.2850012 1.686877 42.5808956 8.2850012 1.686877 +0.837 42.4164843 8.2556269 1.6814708 42.4164843 8.2556269 1.6814708 +0.838 42.2528201 8.2263782 1.6760861 42.2528201 8.2263782 1.6760861 +0.839 42.0898989 8.1972543 1.6707225 42.0898989 8.1972543 1.6707225 +0.84 41.9277168 8.1682546 1.6653802 41.9277168 8.1682546 1.6653802 +0.841 41.7662698 8.1393784 1.6600588 41.7662698 8.1393784 1.6600588 +0.842 41.605554 8.1106252 1.6547585 41.605554 8.1106252 1.6547585 +0.843 41.4455654 8.0819943 1.6494789 41.4455654 8.0819943 1.6494789 +0.844 41.2863002 8.053485 1.6442201 41.2863002 8.053485 1.6442201 +0.845 41.1277545 8.0250968 1.638982 41.1277545 8.0250968 1.638982 +0.846 40.9699245 7.9968291 1.6337644 40.9699245 7.9968291 1.6337644 +0.847 40.8128063 7.9686812 1.6285673 40.8128063 7.9686812 1.6285673 +0.848 40.6563962 7.9406525 1.6233905 40.6563962 7.9406525 1.6233905 +0.849 40.5006904 7.9127424 1.618234 40.5006904 7.9127424 1.618234 +0.85 40.3456852 7.8849503 1.6130976 40.3456852 7.8849503 1.6130976 +0.851 40.1913769 7.8572757 1.6079813 40.1913769 7.8572757 1.6079813 +0.852 40.0377617 7.8297179 1.602885 40.0377617 7.8297179 1.602885 +0.853 39.884836 7.8022763 1.5978086 39.884836 7.8022763 1.5978086 +0.854 39.7325961 7.7749504 1.592752 39.7325961 7.7749504 1.592752 +0.855 39.5810385 7.7477396 1.587715 39.5810385 7.7477396 1.587715 +0.856 39.4301594 7.7206432 1.5826977 39.4301594 7.7206432 1.5826977 +0.857 39.2799554 7.6936608 1.5776998 39.2799554 7.6936608 1.5776998 +0.858 39.1304228 7.6667916 1.5727214 39.1304228 7.6667916 1.5727214 +0.859 38.9815582 7.6400353 1.5677623 38.9815582 7.6400353 1.5677623 +0.86 38.833358 7.6133912 1.5628224 38.833358 7.6133912 1.5628224 +0.861 38.6858187 7.5868587 1.5579017 38.6858187 7.5868587 1.5579017 +0.862 38.5389369 7.5604372 1.5530001 38.5389369 7.5604372 1.5530001 +0.863 38.3927091 7.5341263 1.5481174 38.3927091 7.5341263 1.5481174 +0.864 38.2471318 7.5079254 1.5432535 38.2471318 7.5079254 1.5432535 +0.865 38.1022017 7.4818339 1.5384085 38.1022017 7.4818339 1.5384085 +0.866 37.9579153 7.4558513 1.5335822 37.9579153 7.4558513 1.5335822 +0.867 37.8142694 7.429977 1.5287744 37.8142694 7.429977 1.5287744 +0.868 37.6712605 7.4042105 1.5239853 37.6712605 7.4042105 1.5239853 +0.869 37.5288854 7.3785512 1.5192145 37.5288854 7.3785512 1.5192145 +0.87 37.3871406 7.3529987 1.5144621 37.3871406 7.3529987 1.5144621 +0.871 37.2460231 7.3275524 1.509728 37.2460231 7.3275524 1.509728 +0.872 37.1055294 7.3022117 1.505012 37.1055294 7.3022117 1.505012 +0.873 36.9656563 7.2769761 1.5003142 36.9656563 7.2769761 1.5003142 +0.874 36.8264006 7.2518452 1.4956344 36.8264006 7.2518452 1.4956344 +0.875 36.6877592 7.2268184 1.4909725 36.6877592 7.2268184 1.4909725 +0.876 36.5497287 7.2018952 1.4863284 36.5497287 7.2018952 1.4863284 +0.877 36.4123061 7.177075 1.4817022 36.4123061 7.177075 1.4817022 +0.878 36.2754882 7.1523574 1.4770936 36.2754882 7.1523574 1.4770936 +0.879 36.1392719 7.1277418 1.4725026 36.1392719 7.1277418 1.4725026 +0.88 36.003654 7.1032278 1.4679291 36.003654 7.1032278 1.4679291 +0.881 35.8686315 7.0788149 1.4633731 35.8686315 7.0788149 1.4633731 +0.882 35.7342013 7.0545025 1.4588345 35.7342013 7.0545025 1.4588345 +0.883 35.6003603 7.0302902 1.4543131 35.6003603 7.0302902 1.4543131 +0.884 35.4671056 7.0061774 1.4498089 35.4671056 7.0061774 1.4498089 +0.885 35.334434 6.9821637 1.4453219 35.334434 6.9821637 1.4453219 +0.886 35.2023426 6.9582486 1.4408519 35.2023426 6.9582486 1.4408519 +0.887 35.0708284 6.9344316 1.4363988 35.0708284 6.9344316 1.4363988 +0.888 34.9398885 6.9107122 1.4319627 34.9398885 6.9107122 1.4319627 +0.889 34.8095199 6.88709 1.4275434 34.8095199 6.88709 1.4275434 +0.89 34.6797197 6.8635645 1.4231408 34.6797197 6.8635645 1.4231408 +0.891 34.5504849 6.8401351 1.4187548 34.5504849 6.8401351 1.4187548 +0.892 34.4218127 6.8168015 1.4143854 34.4218127 6.8168015 1.4143854 +0.893 34.2937002 6.7935632 1.4100326 34.2937002 6.7935632 1.4100326 +0.894 34.1661445 6.7704197 1.4056962 34.1661445 6.7704197 1.4056962 +0.895 34.0391429 6.7473705 1.4013761 34.0391429 6.7473705 1.4013761 +0.896 33.9126924 6.7244151 1.3970723 33.9126924 6.7244151 1.3970723 +0.897 33.7867903 6.7015532 1.3927847 33.7867903 6.7015532 1.3927847 +0.898 33.6614338 6.6787843 1.3885133 33.6614338 6.6787843 1.3885133 +0.899 33.53662 6.6561079 1.3842579 33.53662 6.6561079 1.3842579 +0.9 33.4123463 6.6335236 1.3800185 33.4123463 6.6335236 1.3800185 +0.901 33.28861 6.6110309 1.375795 33.28861 6.6110309 1.375795 +0.902 33.1654082 6.5886293 1.3715874 33.1654082 6.5886293 1.3715874 +0.903 33.0427382 6.5663185 1.3673955 33.0427382 6.5663185 1.3673955 +0.904 32.9205975 6.5440981 1.3632194 32.9205975 6.5440981 1.3632194 +0.905 32.7989833 6.5219674 1.3590588 32.7989833 6.5219674 1.3590588 +0.906 32.6778929 6.4999262 1.3549139 32.6778929 6.4999262 1.3549139 +0.907 32.5573237 6.4779741 1.3507844 32.5573237 6.4779741 1.3507844 +0.908 32.4372731 6.4561104 1.3466703 32.4372731 6.4561104 1.3466703 +0.909 32.3177384 6.434335 1.3425716 32.3177384 6.434335 1.3425716 +0.91 32.1987171 6.4126472 1.3384881 32.1987171 6.4126472 1.3384881 +0.911 32.0802066 6.3910468 1.3344199 32.0802066 6.3910468 1.3344199 +0.912 31.9622042 6.3695332 1.3303668 31.9622042 6.3695332 1.3303668 +0.913 31.8447076 6.3481061 1.3263288 31.8447076 6.3481061 1.3263288 +0.914 31.727714 6.3267651 1.3223058 31.727714 6.3267651 1.3223058 +0.915 31.6112211 6.3055096 1.3182978 31.6112211 6.3055096 1.3182978 +0.916 31.4952262 6.2843395 1.3143046 31.4952262 6.2843395 1.3143046 +0.917 31.3797269 6.2632541 1.3103262 31.3797269 6.2632541 1.3103262 +0.918 31.2647207 6.2422532 1.3063625 31.2647207 6.2422532 1.3063625 +0.919 31.1502052 6.2213362 1.3024136 31.1502052 6.2213362 1.3024136 +0.92 31.0361779 6.2005029 1.2984792 31.0361779 6.2005029 1.2984792 +0.921 30.9226363 6.1797528 1.2945594 30.9226363 6.1797528 1.2945594 +0.922 30.8095781 6.1590855 1.2906541 30.8095781 6.1590855 1.2906541 +0.923 30.6970008 6.1385007 1.2867632 30.6970008 6.1385007 1.2867632 +0.924 30.5849021 6.1179979 1.2828866 30.5849021 6.1179979 1.2828866 +0.925 30.4732795 6.0975767 1.2790243 30.4732795 6.0975767 1.2790243 +0.926 30.3621308 6.0772368 1.2751763 30.3621308 6.0772368 1.2751763 +0.927 30.2514534 6.0569777 1.2713424 30.2514534 6.0569777 1.2713424 +0.928 30.1412452 6.0367991 1.2675226 30.1412452 6.0367991 1.2675226 +0.929 30.0315037 6.0167007 1.2637168 30.0315037 6.0167007 1.2637168 +0.93 29.9222268 5.996682 1.259925 29.9222268 5.996682 1.259925 +0.931 29.813412 5.9767426 1.2561471 29.813412 5.9767426 1.2561471 +0.932 29.705057 5.9568822 1.2523831 29.705057 5.9568822 1.2523831 +0.933 29.5971597 5.9371004 1.2486328 29.5971597 5.9371004 1.2486328 +0.934 29.4897178 5.9173969 1.2448963 29.4897178 5.9173969 1.2448963 +0.935 29.382729 5.8977712 1.2411735 29.382729 5.8977712 1.2411735 +0.936 29.276191 5.878223 1.2374642 29.276191 5.878223 1.2374642 +0.937 29.1701017 5.858752 1.2337685 29.1701017 5.858752 1.2337685 +0.938 29.0644589 5.8393577 1.2300863 29.0644589 5.8393577 1.2300863 +0.939 28.9592603 5.8200398 1.2264175 28.9592603 5.8200398 1.2264175 +0.94 28.8545038 5.800798 1.2227621 28.8545038 5.800798 1.2227621 +0.941 28.7501872 5.7816319 1.21912 28.7501872 5.7816319 1.21912 +0.942 28.6463084 5.7625412 1.2154912 28.6463084 5.7625412 1.2154912 +0.943 28.5428651 5.7435254 1.2118755 28.5428651 5.7435254 1.2118755 +0.944 28.4398554 5.7245843 1.208273 28.4398554 5.7245843 1.208273 +0.945 28.337277 5.7057175 1.2046836 28.337277 5.7057175 1.2046836 +0.946 28.2351278 5.6869246 1.2011071 28.2351278 5.6869246 1.2011071 +0.947 28.1334058 5.6682053 1.1975437 28.1334058 5.6682053 1.1975437 +0.948 28.0321089 5.6495593 1.1939931 28.0321089 5.6495593 1.1939931 +0.949 27.931235 5.6309862 1.1904554 27.931235 5.6309862 1.1904554 +0.95 27.830782 5.6124856 1.1869305 27.830782 5.6124856 1.1869305 +0.951 27.7307479 5.5940574 1.1834183 27.7307479 5.5940574 1.1834183 +0.952 27.6311306 5.575701 1.1799189 27.6311306 5.575701 1.1799189 +0.953 27.5319282 5.5574162 1.176432 27.5319282 5.5574162 1.176432 +0.954 27.4331386 5.5392026 1.1729577 27.4331386 5.5392026 1.1729577 +0.955 27.3347598 5.52106 1.169496 27.3347598 5.52106 1.169496 +0.956 27.2367898 5.5029879 1.1660467 27.2367898 5.5029879 1.1660467 +0.957 27.1392266 5.4849861 1.1626098 27.1392266 5.4849861 1.1626098 +0.958 27.0420683 5.4670542 1.1591853 27.0420683 5.4670542 1.1591853 +0.959 26.945313 5.4491919 1.155773 26.945313 5.4491919 1.155773 +0.96 26.8489586 5.431399 1.1523731 26.8489586 5.431399 1.1523731 +0.961 26.7530032 5.4136749 1.1489853 26.7530032 5.4136749 1.1489853 +0.962 26.6574449 5.3960196 1.1456096 26.6574449 5.3960196 1.1456096 +0.963 26.5622819 5.3784326 1.1422461 26.5622819 5.3784326 1.1422461 +0.964 26.4675121 5.3609136 1.1388946 26.4675121 5.3609136 1.1388946 +0.965 26.3731337 5.3434623 1.1355551 26.3731337 5.3434623 1.1355551 +0.966 26.2791448 5.3260784 1.1322275 26.2791448 5.3260784 1.1322275 +0.967 26.1855436 5.3087616 1.1289118 26.1855436 5.3087616 1.1289118 +0.968 26.0923281 5.2915115 1.125608 26.0923281 5.2915115 1.125608 +0.969 25.9994966 5.274328 1.1223159 25.9994966 5.274328 1.1223159 +0.97 25.9070472 5.2572106 1.1190356 25.9070472 5.2572106 1.1190356 +0.971 25.814978 5.2401591 1.1157669 25.814978 5.2401591 1.1157669 +0.972 25.7232873 5.2231731 1.1125099 25.7232873 5.2231731 1.1125099 +0.973 25.6319732 5.2062525 1.1092644 25.6319732 5.2062525 1.1092644 +0.974 25.541034 5.1893967 1.1060305 25.541034 5.1893967 1.1060305 +0.975 25.4504678 5.1726057 1.1028081 25.4504678 5.1726057 1.1028081 +0.976 25.3602728 5.1558791 1.0995971 25.3602728 5.1558791 1.0995971 +0.977 25.2704474 5.1392165 1.0963975 25.2704474 5.1392165 1.0963975 +0.978 25.1809897 5.1226177 1.0932092 25.1809897 5.1226177 1.0932092 +0.979 25.091898 5.1060825 1.0900323 25.091898 5.1060825 1.0900323 +0.98 25.0031705 5.0896104 1.0868665 25.0031705 5.0896104 1.0868665 +0.981 24.9148055 5.0732013 1.083712 24.9148055 5.0732013 1.083712 +0.982 24.8268013 5.0568548 1.0805686 24.8268013 5.0568548 1.0805686 +0.983 24.7391563 5.0405707 1.0774363 24.7391563 5.0405707 1.0774363 +0.984 24.6518686 5.0243487 1.074315 24.6518686 5.0243487 1.074315 +0.985 24.5649365 5.0081885 1.0712048 24.5649365 5.0081885 1.0712048 +0.986 24.4783585 4.9920898 1.0681055 24.4783585 4.9920898 1.0681055 +0.987 24.3921328 4.9760523 1.0650171 24.3921328 4.9760523 1.0650171 +0.988 24.3062578 4.9600758 1.0619396 24.3062578 4.9600758 1.0619396 +0.989 24.2207318 4.94416 1.0588729 24.2207318 4.94416 1.0588729 +0.99 24.1355532 4.9283046 1.0558169 24.1355532 4.9283046 1.0558169 +0.991 24.0507203 4.9125093 1.0527717 24.0507203 4.9125093 1.0527717 +0.992 23.9662314 4.896774 1.0497372 23.9662314 4.896774 1.0497372 +0.993 23.8820851 4.8810982 1.0467134 23.8820851 4.8810982 1.0467134 +0.994 23.7982796 4.8654818 1.0437001 23.7982796 4.8654818 1.0437001 +0.995 23.7148134 4.8499244 1.0406973 23.7148134 4.8499244 1.0406973 +0.996 23.6316848 4.8344259 1.0377051 23.6316848 4.8344259 1.0377051 +0.997 23.5488924 4.8189859 1.0347233 23.5488924 4.8189859 1.0347233 +0.998 23.4664344 4.8036042 1.0317519 23.4664344 4.8036042 1.0317519 +0.999 23.3843094 4.7882805 1.0287909 23.3843094 4.7882805 1.0287909 +1.0 23.3025158 4.7730145 1.0258403 23.3025158 4.7730145 1.0258403 diff --git a/source/tests/universal/common/cases/descriptor/utils.py b/source/tests/universal/common/cases/descriptor/utils.py index e1c2b80c15..4c8219d347 100644 --- a/source/tests/universal/common/cases/descriptor/utils.py +++ b/source/tests/universal/common/cases/descriptor/utils.py @@ -26,13 +26,6 @@ class DescriptorTestCase(TestCaseSingleFrameWithNlist): def setUp(self): TestCaseSingleFrameWithNlist.setUp(self) - self.input_dict = { - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel, - "type_map": ["O", "H"], - } def test_forward_consistency(self): ret = [] diff --git a/source/tests/universal/common/cases/model/ener_model.py b/source/tests/universal/common/cases/model/ener_model.py deleted file mode 100644 index 54fc19073f..0000000000 --- a/source/tests/universal/common/cases/model/ener_model.py +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later - - -from .utils import ( - ModelTestCase, -) - - -class EnerModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.expected_sel = [8, 12] - self.expected_has_message_passing = False diff --git a/source/tests/universal/common/cases/model/model.py b/source/tests/universal/common/cases/model/model.py new file mode 100644 index 0000000000..c814ff38e5 --- /dev/null +++ b/source/tests/universal/common/cases/model/model.py @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later + +import os + +from .....seed import ( + GLOBAL_SEED, +) +from .utils import ( + ModelTestCase, +) + +CUR_DIR = os.path.dirname(__file__) + + +class EnerModelTest(ModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["energy", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + + +class DipoleModelTest(ModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["dipole", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + self.skip_test_autodiff = True + + +class PolarModelTest(ModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["polarizability", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + self.skip_test_autodiff = True + + +class DosModelTest(ModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["foo", "bar"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1] + self.expected_aparam_nall = False + self.expected_model_output_type = ["dos", "mask"] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + self.skip_test_autodiff = True + + +class ZBLModelTest(ModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 5.0 + self.expected_type_map = ["O", "H", "B"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [] + self.expected_aparam_nall = False + self.expected_model_output_type = ["energy", "mask"] + self.expected_sel = [46, 92, 10] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + self.tab_file = { + "use_srtab": f"{CUR_DIR}/../data/zbl_tab_potential/H2O_tab_potential.txt", + "smin_alpha": 0.1, + "sw_rmin": 0.2, + "sw_rmax": 4.0, + } diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index 30f9da3b14..1b3f46ccb9 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -1,8 +1,13 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from copy import ( + deepcopy, +) from typing import ( Any, Callable, + Dict, List, + Optional, ) import numpy as np @@ -11,6 +16,10 @@ extend_input_and_build_neighbor_list, ) +from .....seed import ( + GLOBAL_SEED, +) + class ModelTestCase: """Common test case for model.""" @@ -35,6 +44,12 @@ class ModelTestCase: """Expected whether having message passing.""" forward_wrapper: Callable[[Any], Any] """Calss wrapper for forward method.""" + aprec_dict: Dict[str, Optional[float]] + """Dictionary of absolute precision in each test.""" + rprec_dict: Dict[str, Optional[float]] + """Dictionary of relative precision in each test.""" + epsilon_dict: Dict[str, Optional[float]] + """Dictionary of epsilons in each test.""" def test_get_type_map(self): """Test get_type_map.""" @@ -118,7 +133,9 @@ def test_forward(self): module = self.forward_wrapper(module) ret.append(module(coord, atype, cell)) - ret_lower.append(module.forward_lower(coord_ext, atype_ext, nlist)) + ret_lower.append( + module.forward_lower(coord_ext, atype_ext, nlist, mapping=mapping) + ) for kk in ret[0].keys(): subret = [] for rr in ret: @@ -161,3 +178,389 @@ def test_forward(self): else: continue np.testing.assert_allclose(rr1, rr2) + + def test_permutation(self): + """Test permutation.""" + if getattr(self, "skip_test_permutation", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + idx_perm = [1, 0, 4, 3, 2] + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + coord_perm = coord[idx_perm] + atype_perm = atype[idx_perm] + + # reshape for input + coord = coord.reshape([nf, -1]) + coord_perm = coord_perm.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + atype_perm = atype_perm.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + ret.append(module(coord, atype, cell)) + # permutation + ret.append(module(coord_perm, atype_perm, cell)) + + for kk in ret[0].keys(): + if kk in self.output_def.keys(): + if ret[0][kk] is None: + assert ret[1][kk] is None + continue + atomic = self.output_def[kk].atomic + if atomic: + np.testing.assert_allclose( + ret[0][kk][:, idx_perm], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_trans(self): + """Test translation.""" + if getattr(self, "skip_test_trans", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + shift = (rng.random([3]) - 0.5) * 2.0 + coord_s = np.matmul( + np.remainder(np.matmul(coord + shift, np.linalg.inv(cell)), 1.0), cell + ) + + # reshape for input + coord = coord.reshape([nf, -1]) + coord_s = coord_s.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + ret.append(module(coord, atype, cell)) + # translation + ret.append(module(coord_s, atype, cell)) + + for kk in ret[0].keys(): + if kk in self.output_def.keys(): + if ret[0][kk] is None: + assert ret[1][kk] is None + continue + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_rot(self): + """Test rotation.""" + if getattr(self, "skip_test_rot", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + + # rotate only coord and shift to the center of cell + cell = 10.0 * np.eye(3) + coord = 2.0 * rng.random([natoms, 3]) + atype = np.array([0, 0, 0, 1, 1]) + shift = np.array([4.0, 4.0, 4.0]) + from scipy.stats import ( + special_ortho_group, + ) + + rmat = special_ortho_group.rvs(3) + coord_rot = np.matmul(coord, rmat) + + # reshape for input + coord = (coord + shift).reshape([nf, -1]) + coord_rot = (coord_rot + shift).reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + ret.append(module(coord, atype, cell)) + # rotation + ret.append(module(coord_rot, atype, cell)) + + for kk in ret[0].keys(): + if kk in self.output_def.keys(): + if ret[0][kk] is None: + assert ret[1][kk] is None + continue + rot_invariant = self.output_def[kk].rot_invariant + if rot_invariant: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + v_size = self.output_def[kk].size + if v_size == 3: + rotated_ret_0 = np.matmul(ret[0][kk], rmat) + ret_1 = ret[1][kk] + elif v_size == 9: + ret_0 = ret[0][kk].reshape(-1, 3, 3) + batch_rmat_T = np.repeat( + rmat.T.reshape(1, 3, 3), ret_0.shape[0], axis=0 + ) + batch_rmat = np.repeat( + rmat.reshape(1, 3, 3), ret_0.shape[0], axis=0 + ) + rotated_ret_0 = np.matmul( + batch_rmat_T, np.matmul(ret_0, batch_rmat) + ) + ret_1 = ret[1][kk].reshape(-1, 3, 3) + else: + # unsupported dim + continue + np.testing.assert_allclose( + rotated_ret_0, + ret_1, + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + # rotate coord and cell + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + coord_rot = np.matmul(coord, rmat) + cell_rot = np.matmul(cell, rmat) + + # reshape for input + coord = coord.reshape([nf, -1]) + coord_rot = coord_rot.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + cell_rot = cell_rot.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + ret.append(module(coord, atype, cell)) + # rotation + ret.append(module(coord_rot, atype, cell_rot)) + + for kk in ret[0].keys(): + if kk in self.output_def.keys(): + if ret[0][kk] is None: + assert ret[1][kk] is None + continue + rot_invariant = self.output_def[kk].rot_invariant + if rot_invariant: + np.testing.assert_allclose( + ret[0][kk], + ret[1][kk], + err_msg=f"compare {kk} before and after transform", + ) + else: + v_size = self.output_def[kk].size + if v_size == 3: + rotated_ret_0 = np.matmul(ret[0][kk], rmat) + ret_1 = ret[1][kk] + elif v_size == 9: + ret_0 = ret[0][kk].reshape(-1, 3, 3) + batch_rmat_T = np.repeat( + rmat.T.reshape(1, 3, 3), ret_0.shape[0], axis=0 + ) + batch_rmat = np.repeat( + rmat.reshape(1, 3, 3), ret_0.shape[0], axis=0 + ) + rotated_ret_0 = np.matmul( + batch_rmat_T, np.matmul(ret_0, batch_rmat) + ) + ret_1 = ret[1][kk].reshape(-1, 3, 3) + else: + # unsupported dim + continue + np.testing.assert_allclose( + rotated_ret_0, + ret_1, + err_msg=f"compare {kk} before and after transform", + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_smooth(self): + """Test smooth.""" + if getattr(self, "skip_test_smooth", False): + return + rng = np.random.default_rng(GLOBAL_SEED) + epsilon = ( + 1e-5 + if self.epsilon_dict.get("test_smooth", None) is None + else self.epsilon_dict["test_smooth"] + ) + # required prec. + rprec = ( + 1e-5 + if self.rprec_dict.get("test_smooth", None) is None + else self.rprec_dict["test_smooth"] + ) + aprec = ( + 1e-5 + if self.aprec_dict.get("test_smooth", None) is None + else self.aprec_dict["test_smooth"] + ) + natoms = 10 + nf = 1 + cell = 10.0 * np.eye(3) + atype0 = np.arange(2) + atype1 = rng.integers(0, 2, size=natoms - 2) + atype = np.concatenate([atype0, atype1]).reshape(natoms) + coord0 = np.array( + [ + 0.0, + 0.0, + 0.0, + self.expected_rcut - 0.5 * epsilon, + 0.0, + 0.0, + 0.0, + self.expected_rcut - 0.5 * epsilon, + 0.0, + ] + ).reshape(-1, 3) + coord1 = rng.random([natoms - coord0.shape[0], 3]) + coord1 = np.matmul(coord1, cell) + coord = np.concatenate([coord0, coord1], axis=0) + + coord0 = deepcopy(coord) + coord1 = deepcopy(coord) + coord1[1][0] += epsilon + coord2 = deepcopy(coord) + coord2[2][1] += epsilon + coord3 = deepcopy(coord) + coord3[1][0] += epsilon + coord3[2][1] += epsilon + + # reshape for input + coord0 = coord0.reshape([nf, -1]) + coord1 = coord1.reshape([nf, -1]) + coord2 = coord2.reshape([nf, -1]) + coord3 = coord3.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + + ret = [] + module = self.forward_wrapper(self.module) + # coord0 + ret.append(module(coord0, atype, cell)) + # coord1 + ret.append(module(coord1, atype, cell)) + # coord2 + ret.append(module(coord2, atype, cell)) + # coord3 + ret.append(module(coord3, atype, cell)) + + for kk in ret[0].keys(): + if kk in self.output_def.keys(): + if ret[0][kk] is None: + for ii in range(len(ret) - 1): + assert ret[ii + 1][kk] is None + continue + for ii in range(len(ret) - 1): + np.testing.assert_allclose( + ret[0][kk], + ret[ii + 1][kk], + err_msg=f"compare {kk} before and after transform", + atol=aprec, + rtol=rprec, + ) + else: + raise RuntimeError(f"Unknown output key: {kk}") + + def test_autodiff(self): + """Test autodiff.""" + if getattr(self, "skip_test_autodiff", False): + return + + places = 4 + delta = 1e-5 + + def finite_difference(f, x, delta=1e-6): + in_shape = x.shape + y0 = f(x) + out_shape = y0.shape + res = np.empty(out_shape + in_shape) + for idx in np.ndindex(*in_shape): + diff = np.zeros(in_shape) + diff[idx] += delta + y1p = f(x + diff) + y1n = f(x - diff) + res[(Ellipsis, *idx)] = (y1p - y1n) / (2 * delta) + return res + + def stretch_box(old_coord, old_box, new_box): + ocoord = old_coord.reshape(-1, 3) + obox = old_box.reshape(3, 3) + nbox = new_box.reshape(3, 3) + ncoord = ocoord @ np.linalg.inv(obox) @ nbox + return ncoord.reshape(old_coord.shape) + + rng = np.random.default_rng(GLOBAL_SEED) + natoms = 5 + nf = 1 + cell = rng.random([3, 3]) + cell = (cell + cell.T) + 5.0 * np.eye(3) + coord = rng.random([natoms, 3]) + coord = np.matmul(coord, cell) + atype = np.array([0, 0, 0, 1, 1]) + + # reshape for input + coord = coord.reshape([nf, -1]) + atype = atype.reshape([nf, -1]) + cell = cell.reshape([nf, 9]) + module = self.forward_wrapper(self.module) + + # only test force and virial for energy model + def ff_coord(_coord): + return module(_coord, atype, cell)["energy"] + + fdf = -finite_difference(ff_coord, coord, delta=delta).squeeze() + rff = module(coord, atype, cell)["force"] + np.testing.assert_almost_equal( + fdf.reshape(-1, 3), rff.reshape(-1, 3), decimal=places + ) + + def ff_cell(bb): + return module(stretch_box(coord, cell, bb), atype, bb)["energy"] + + fdv = ( + -( + finite_difference(ff_cell, cell, delta=delta) + .reshape(-1, 3, 3) + .transpose(0, 2, 1) + @ cell.reshape(-1, 3, 3) + ) + .squeeze() + .reshape(9) + ) + rfv = module(stretch_box(coord, cell, cell), atype, cell)["virial"] + np.testing.assert_almost_equal( + fdv.reshape(-1, 9), rfv.reshape(-1, 9), decimal=places + ) diff --git a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py new file mode 100644 index 0000000000..877bff19f5 --- /dev/null +++ b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py @@ -0,0 +1,254 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import unittest + +from deepmd.dpmodel.atomic_model import ( + DPAtomicModel, + DPZBLLinearEnergyAtomicModel, + PairTabAtomicModel, +) +from deepmd.dpmodel.descriptor import ( + DescrptDPA1, + DescrptDPA2, + DescrptHybrid, + DescrptSeA, + DescrptSeR, + DescrptSeT, +) +from deepmd.dpmodel.fitting import ( + DipoleFitting, + DOSFittingNet, + EnergyFittingNet, + PolarFitting, +) + +from ....consistent.common import ( + parameterized, +) +from ...common.cases.atomic_model.atomic_model import ( + DipoleAtomicModelTest, + DosAtomicModelTest, + EnerAtomicModelTest, + PolarAtomicModelTest, + ZBLAtomicModelTest, +) +from ..backend import ( + DPTestCase, +) +from ..descriptor.test_descriptor import ( + DescriptorParamDPA1, + DescriptorParamDPA2, + DescriptorParamHybrid, + DescriptorParamHybridMixed, + DescriptorParamSeA, + DescriptorParamSeR, + DescriptorParamSeT, +) + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestEnergyAtomicModelDP(unittest.TestCase, EnerAtomicModelTest, DPTestCase): + def setUp(self): + EnerAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDosAtomicModelDP(unittest.TestCase, DosAtomicModelTest, DPTestCase): + def setUp(self): + DosAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + self.aprec_dict["test_smooth"] = 1e-4 + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = DOSFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDipoleAtomicModelDP(unittest.TestCase, DipoleAtomicModelTest, DPTestCase): + def setUp(self): + DipoleAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = DipoleFitting( + **self.input_dict_ft, + embedding_width=ds.get_dim_emb(), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestPolarAtomicModelDP(unittest.TestCase, PolarAtomicModelTest, DPTestCase): + def setUp(self): + PolarAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = PolarFitting( + **self.input_dict_ft, + embedding_width=ds.get_dim_emb(), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestZBLAtomicModelDP(unittest.TestCase, ZBLAtomicModelTest, DPTestCase): + def setUp(self): + ZBLAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + # zbl weights not so smooth + self.aprec_dict["test_smooth"] = 5e-2 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + dp_model = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + pt_model = PairTabAtomicModel( + self.tab_file["use_srtab"], + self.expected_rcut, + self.expected_sel, + type_map=self.expected_type_map, + ) + self.module = DPZBLLinearEnergyAtomicModel( + dp_model, + pt_model, + sw_rmin=self.tab_file["sw_rmin"], + sw_rmax=self.tab_file["sw_rmax"], + smin_alpha=self.tab_file["smin_alpha"], + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() diff --git a/source/tests/universal/dpmodel/atomc_model/test_ener_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_ener_atomic_model.py deleted file mode 100644 index 6cf4598646..0000000000 --- a/source/tests/universal/dpmodel/atomc_model/test_ener_atomic_model.py +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -import unittest - -from deepmd.dpmodel.atomic_model.dp_atomic_model import ( - DPAtomicModel, -) -from deepmd.dpmodel.descriptor.se_e2_a import ( - DescrptSeA, -) -from deepmd.dpmodel.fitting.ener_fitting import ( - EnergyFittingNet, -) - -from ...common.cases.atomic_model.ener_model import ( - EnerAtomicModelTest, -) -from ..backend import ( - DPTestCase, -) - - -class TestEnergyAtomicModelDP(unittest.TestCase, EnerAtomicModelTest, DPTestCase): - def setUp(self): - EnerAtomicModelTest.setUp(self) - ds = DescrptSeA( - rcut=self.expected_rcut, - rcut_smth=self.expected_rcut / 2, - sel=self.expected_sel, - ) - ft = EnergyFittingNet( - ntypes=len(self.expected_type_map), - dim_descrpt=ds.get_dim_out(), - mixed_types=ds.mixed_types(), - ) - self.module = DPAtomicModel( - ds, - ft, - type_map=self.expected_type_map, - ) diff --git a/source/tests/universal/dpmodel/descriptor/test_descriptor.py b/source/tests/universal/dpmodel/descriptor/test_descriptor.py index 38c1672079..076adc8a31 100644 --- a/source/tests/universal/dpmodel/descriptor/test_descriptor.py +++ b/source/tests/universal/dpmodel/descriptor/test_descriptor.py @@ -10,6 +10,12 @@ DescrptSeT, ) +from ....consistent.common import ( + parameterized, +) +from ....seed import ( + GLOBAL_SEED, +) from ...common.cases.descriptor.descriptor import ( DescriptorTest, ) @@ -18,102 +24,140 @@ ) -class TestDescriptorSeADP(unittest.TestCase, DescriptorTest, DPTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptSeA - self.module = DescrptSeA(**self.input_dict) - - -class TestDescriptorSeRDP(unittest.TestCase, DescriptorTest, DPTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptSeR - self.module = DescrptSeR(**self.input_dict) - - -class TestDescriptorSeTDP(unittest.TestCase, DescriptorTest, DPTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptSeT - self.module = DescrptSeT(**self.input_dict) - - -class TestDescriptorDPA1DP(unittest.TestCase, DescriptorTest, DPTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptDPA1 - self.module = DescrptDPA1(**self.input_dict) - - -class TestDescriptorDPA2DP(unittest.TestCase, DescriptorTest, DPTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptDPA2 - self.input_dict = { - "ntypes": self.nt, - "repinit": { - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "nsel": self.sel_mix, - }, - "repformer": { - "rcut": self.rcut / 2, - "rcut_smth": self.rcut_smth, - "nsel": self.sel_mix[0] // 2, - }, - "type_map": ["O", "H"], - } - self.module = DescrptDPA2(**self.input_dict) - - -class TestDescriptorHybridDP(unittest.TestCase, DescriptorTest, DPTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptHybrid - ddsub0 = { - "type": "se_e2_a", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel, - "type_map": ["O", "H"], - } - ddsub1 = { - "type": "dpa1", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel_mix, - "type_map": ["O", "H"], - } - self.input_dict = { - "list": [ddsub0, ddsub1], - } - self.module = DescrptHybrid(**self.input_dict) - - -class TestDescriptorHybridMixedDP(unittest.TestCase, DescriptorTest, DPTestCase): +def DescriptorParamSeA(ntypes, rcut, rcut_smth, sel, type_map): + input_dict = { + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sel, + "type_map": type_map, + "seed": GLOBAL_SEED, + } + return input_dict + + +def DescriptorParamSeR(ntypes, rcut, rcut_smth, sel, type_map): + input_dict = { + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sel, + "type_map": type_map, + "seed": GLOBAL_SEED, + } + return input_dict + + +def DescriptorParamSeT(ntypes, rcut, rcut_smth, sel, type_map): + input_dict = { + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sel, + "type_map": type_map, + "seed": GLOBAL_SEED, + } + return input_dict + + +def DescriptorParamDPA1(ntypes, rcut, rcut_smth, sel, type_map): + input_dict = { + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sel, + "type_map": type_map, + "seed": GLOBAL_SEED, + } + return input_dict + + +def DescriptorParamDPA2(ntypes, rcut, rcut_smth, sel, type_map): + input_dict = { + "ntypes": ntypes, + "repinit": { + "rcut": rcut, + "rcut_smth": rcut_smth, + "nsel": sum(sel), + }, + "repformer": { + "rcut": rcut / 2, + "rcut_smth": rcut_smth / 2, + "nsel": sum(sel) // 2, + }, + "type_map": type_map, + "seed": GLOBAL_SEED, + } + return input_dict + + +def DescriptorParamHybrid(ntypes, rcut, rcut_smth, sel, type_map): + ddsub0 = { + "type": "se_e2_a", + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sel, + "type_map": type_map, + "seed": GLOBAL_SEED, + } + ddsub1 = { + "type": "dpa1", + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sum(sel), + "type_map": type_map, + "seed": GLOBAL_SEED, + } + input_dict = { + "list": [ddsub0, ddsub1], + } + return input_dict + + +def DescriptorParamHybridMixed(ntypes, rcut, rcut_smth, sel, type_map): + ddsub0 = { + "type": "dpa1", + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sum(sel), + "type_map": type_map, + "seed": GLOBAL_SEED, + } + ddsub1 = { + "type": "dpa1", + "ntypes": ntypes, + "rcut": rcut, + "rcut_smth": rcut_smth, + "sel": sum(sel), + "type_map": type_map, + "seed": GLOBAL_SEED, + } + input_dict = { + "list": [ddsub0, ddsub1], + } + return input_dict + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDescriptorDP(unittest.TestCase, DescriptorTest, DPTestCase): def setUp(self): DescriptorTest.setUp(self) - self.module_class = DescrptHybrid - ddsub0 = { - "type": "dpa1", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel_mix, - "type_map": ["O", "H"], - } - ddsub1 = { - "type": "dpa1", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel_mix, - "type_map": ["O", "H"], - } - self.input_dict = { - "list": [ddsub0, ddsub1], - } - self.module = DescrptHybrid(**self.input_dict) + (DescriptorParam, Descrpt) = self.param[0] + self.module_class = Descrpt + self.input_dict = DescriptorParam( + self.nt, self.rcut, self.rcut_smth, self.sel, ["O", "H"] + ) + self.module = Descrpt(**self.input_dict) diff --git a/source/tests/universal/dpmodel/fitting/test_fitting.py b/source/tests/universal/dpmodel/fitting/test_fitting.py index ab95fae6b8..6f780fe636 100644 --- a/source/tests/universal/dpmodel/fitting/test_fitting.py +++ b/source/tests/universal/dpmodel/fitting/test_fitting.py @@ -19,47 +19,63 @@ ) -@parameterized( - (True, False), # mixed_types -) -class TestFittingEnergyDP(unittest.TestCase, FittingTest, DPTestCase): - def setUp(self): - (self.mixed_types,) = self.param - FittingTest.setUp(self) - self.module_class = EnergyFittingNet - self.module = EnergyFittingNet(**self.input_dict) +def FittingParamEnergy(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): + input_dict = { + "ntypes": ntypes, + "dim_descrpt": dim_descrpt, + "mixed_types": mixed_types, + "type_map": type_map, + } + return input_dict -@parameterized( - (True, False), # mixed_types -) -class TestFittingDosDP(unittest.TestCase, FittingTest, DPTestCase): - def setUp(self): - (self.mixed_types,) = self.param - FittingTest.setUp(self) - self.module_class = DOSFittingNet - self.module = DOSFittingNet(**self.input_dict) +def FittingParamDos(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): + input_dict = { + "ntypes": ntypes, + "dim_descrpt": dim_descrpt, + "mixed_types": mixed_types, + "type_map": type_map, + } + return input_dict -@parameterized( - (True, False), # mixed_types -) -class TestFittingDipoleDP(unittest.TestCase, FittingTest, DPTestCase): - def setUp(self): - (self.mixed_types,) = self.param - FittingTest.setUp(self) - self.input_dict.update({"embedding_width": self.dim_embed}) - self.module_class = DipoleFitting - self.module = DipoleFitting(**self.input_dict) +def FittingParamDipole(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): + input_dict = { + "ntypes": ntypes, + "dim_descrpt": dim_descrpt, + "mixed_types": mixed_types, + "embedding_width": embedding_width, + "type_map": type_map, + } + return input_dict + + +def FittingParamPolar(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): + input_dict = { + "ntypes": ntypes, + "dim_descrpt": dim_descrpt, + "mixed_types": mixed_types, + "embedding_width": embedding_width, + "type_map": type_map, + } + return input_dict @parameterized( + ( + (FittingParamEnergy, EnergyFittingNet), + (FittingParamDos, DOSFittingNet), + (FittingParamDipole, DipoleFitting), + (FittingParamPolar, PolarFitting), + ), # class_param & class (True, False), # mixed_types ) -class TestFittingPolarDP(unittest.TestCase, FittingTest, DPTestCase): +class TestFittingDP(unittest.TestCase, FittingTest, DPTestCase): def setUp(self): - (self.mixed_types,) = self.param + ((FittingParam, Fitting), self.mixed_types) = self.param FittingTest.setUp(self) - self.input_dict.update({"embedding_width": self.dim_embed}) - self.module_class = PolarFitting - self.module = PolarFitting(**self.input_dict) + self.module_class = Fitting + self.input_dict = FittingParam( + self.nt, self.dim_descrpt, self.mixed_types, self.dim_embed, ["O", "H"] + ) + self.module = Fitting(**self.input_dict) diff --git a/source/tests/universal/dpmodel/model/test_ener_model.py b/source/tests/universal/dpmodel/model/test_ener_model.py deleted file mode 100644 index 506564260f..0000000000 --- a/source/tests/universal/dpmodel/model/test_ener_model.py +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -import unittest - -from deepmd.dpmodel.descriptor.se_e2_a import ( - DescrptSeA, -) -from deepmd.dpmodel.fitting.ener_fitting import ( - EnergyFittingNet, -) -from deepmd.dpmodel.model.ener_model import ( - EnergyModel, -) - -from ...common.cases.model.ener_model import ( - EnerModelTest, -) -from ..backend import ( - DPTestCase, -) - - -class TestEnergyModelDP(unittest.TestCase, EnerModelTest, DPTestCase): - def setUp(self): - EnerModelTest.setUp(self) - ds = DescrptSeA( - rcut=self.expected_rcut, - rcut_smth=self.expected_rcut / 2, - sel=self.expected_sel, - ) - ft = EnergyFittingNet( - ntypes=len(self.expected_type_map), - dim_descrpt=ds.get_dim_out(), - mixed_types=ds.mixed_types(), - ) - self.module = EnergyModel( - ds, - ft, - type_map=self.expected_type_map, - ) diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py new file mode 100644 index 0000000000..157cc03675 --- /dev/null +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import unittest + +from deepmd.dpmodel.descriptor import ( + DescrptDPA1, + DescrptDPA2, + DescrptHybrid, + DescrptSeA, + DescrptSeR, + DescrptSeT, +) +from deepmd.dpmodel.fitting import ( + EnergyFittingNet, +) +from deepmd.dpmodel.model import ( + EnergyModel, +) + +from ....consistent.common import ( + parameterized, +) +from ...common.cases.model.model import ( + EnerModelTest, +) +from ..backend import ( + DPTestCase, +) +from ..descriptor.test_descriptor import ( + DescriptorParamDPA1, + DescriptorParamDPA2, + DescriptorParamHybrid, + DescriptorParamHybridMixed, + DescriptorParamSeA, + DescriptorParamSeR, + DescriptorParamSeT, +) + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestEnergyModelDP(unittest.TestCase, EnerModelTest, DPTestCase): + def setUp(self): + EnerModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = EnergyModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.model_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() diff --git a/source/tests/universal/pt/atomc_model/test_atomic_model.py b/source/tests/universal/pt/atomc_model/test_atomic_model.py new file mode 100644 index 0000000000..6218fc6b42 --- /dev/null +++ b/source/tests/universal/pt/atomc_model/test_atomic_model.py @@ -0,0 +1,254 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import unittest + +from deepmd.pt.model.atomic_model import ( + DPAtomicModel, + DPZBLLinearEnergyAtomicModel, + PairTabAtomicModel, +) +from deepmd.pt.model.descriptor import ( + DescrptDPA1, + DescrptDPA2, + DescrptHybrid, + DescrptSeA, + DescrptSeR, + DescrptSeT, +) +from deepmd.pt.model.task import ( + DipoleFittingNet, + DOSFittingNet, + EnergyFittingNet, + PolarFittingNet, +) + +from ....consistent.common import ( + parameterized, +) +from ...common.cases.atomic_model.atomic_model import ( + DipoleAtomicModelTest, + DosAtomicModelTest, + EnerAtomicModelTest, + PolarAtomicModelTest, + ZBLAtomicModelTest, +) +from ..backend import ( + PTTestCase, +) +from ..descriptor.test_descriptor import ( + DescriptorParamDPA1, + DescriptorParamDPA2, + DescriptorParamHybrid, + DescriptorParamHybridMixed, + DescriptorParamSeA, + DescriptorParamSeR, + DescriptorParamSeT, +) + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestEnergyAtomicModelPT(unittest.TestCase, EnerAtomicModelTest, PTTestCase): + def setUp(self): + EnerAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDosAtomicModelPT(unittest.TestCase, DosAtomicModelTest, PTTestCase): + def setUp(self): + DosAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + self.aprec_dict["test_smooth"] = 1e-4 + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = DOSFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDipoleAtomicModelPT(unittest.TestCase, DipoleAtomicModelTest, PTTestCase): + def setUp(self): + DipoleAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = DipoleFittingNet( + **self.input_dict_ft, + embedding_width=ds.get_dim_emb(), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestPolarAtomicModelPT(unittest.TestCase, PolarAtomicModelTest, PTTestCase): + def setUp(self): + PolarAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = PolarFittingNet( + **self.input_dict_ft, + embedding_width=ds.get_dim_emb(), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestZBLAtomicModelPT(unittest.TestCase, ZBLAtomicModelTest, PTTestCase): + def setUp(self): + ZBLAtomicModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + # zbl weights not so smooth + self.aprec_dict["test_smooth"] = 5e-2 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + dp_model = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + pt_model = PairTabAtomicModel( + self.tab_file["use_srtab"], + self.expected_rcut, + self.expected_sel, + type_map=self.expected_type_map, + ) + self.module = DPZBLLinearEnergyAtomicModel( + dp_model, + pt_model, + sw_rmin=self.tab_file["sw_rmin"], + sw_rmax=self.tab_file["sw_rmax"], + smin_alpha=self.tab_file["smin_alpha"], + type_map=self.expected_type_map, + ) + self.output_def = self.module.atomic_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() diff --git a/source/tests/universal/pt/atomc_model/test_ener_atomic_model.py b/source/tests/universal/pt/atomc_model/test_ener_atomic_model.py deleted file mode 100644 index 5ba3be0fad..0000000000 --- a/source/tests/universal/pt/atomc_model/test_ener_atomic_model.py +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -import unittest - -from deepmd.pt.model.atomic_model.dp_atomic_model import ( - DPAtomicModel, -) -from deepmd.pt.model.descriptor.se_a import ( - DescrptSeA, -) -from deepmd.pt.model.task.ener import ( - EnergyFittingNet, -) - -from ...common.cases.atomic_model.ener_model import ( - EnerAtomicModelTest, -) -from ..backend import ( - PTTestCase, -) - - -class TestEnergyAtomicModelDP(unittest.TestCase, EnerAtomicModelTest, PTTestCase): - def setUp(self): - EnerAtomicModelTest.setUp(self) - ds = DescrptSeA( - rcut=self.expected_rcut, - rcut_smth=self.expected_rcut / 2, - sel=self.expected_sel, - ) - ft = EnergyFittingNet( - ntypes=len(self.expected_type_map), - dim_descrpt=ds.get_dim_out(), - mixed_types=ds.mixed_types(), - ) - self.module = DPAtomicModel( - ds, - ft, - type_map=self.expected_type_map, - ) diff --git a/source/tests/universal/pt/descriptor/test_descriptor.py b/source/tests/universal/pt/descriptor/test_descriptor.py index 9331ad12f5..7e2226feb6 100644 --- a/source/tests/universal/pt/descriptor/test_descriptor.py +++ b/source/tests/universal/pt/descriptor/test_descriptor.py @@ -10,110 +10,43 @@ DescrptSeT, ) +from ....consistent.common import ( + parameterized, +) from ...common.cases.descriptor.descriptor import ( DescriptorTest, ) +from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1, + DescriptorParamDPA2, + DescriptorParamHybrid, + DescriptorParamHybridMixed, + DescriptorParamSeA, + DescriptorParamSeR, + DescriptorParamSeT, +) from ..backend import ( PTTestCase, ) -class TestDescriptorSeAPT(unittest.TestCase, DescriptorTest, PTTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptSeA - self.module = DescrptSeA(**self.input_dict) - - -class TestDescriptorSeRPT(unittest.TestCase, DescriptorTest, PTTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptSeR - self.module = DescrptSeR(**self.input_dict) - - -class TestDescriptorSeTPT(unittest.TestCase, DescriptorTest, PTTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptSeT - self.module = DescrptSeT(**self.input_dict) - - -class TestDescriptorDPA1PT(unittest.TestCase, DescriptorTest, PTTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptDPA1 - self.module = DescrptDPA1(**self.input_dict) - - -class TestDescriptorDPA2PT(unittest.TestCase, DescriptorTest, PTTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptDPA2 - self.input_dict = { - "ntypes": self.nt, - "repinit": { - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "nsel": self.sel_mix, - }, - "repformer": { - "rcut": self.rcut / 2, - "rcut_smth": self.rcut_smth, - "nsel": self.sel_mix[0] // 2, - }, - "type_map": ["O", "H"], - } - self.module = DescrptDPA2(**self.input_dict) - - -class TestDescriptorHybridPT(unittest.TestCase, DescriptorTest, PTTestCase): - def setUp(self): - DescriptorTest.setUp(self) - self.module_class = DescrptHybrid - ddsub0 = { - "type": "se_e2_a", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel, - "type_map": ["O", "H"], - } - ddsub1 = { - "type": "dpa1", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel_mix, - "type_map": ["O", "H"], - } - self.input_dict = { - "list": [ddsub0, ddsub1], - } - self.module = DescrptHybrid(**self.input_dict) - - -class TestDescriptorHybridMixedPT(unittest.TestCase, DescriptorTest, PTTestCase): +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDescriptorPT(unittest.TestCase, DescriptorTest, PTTestCase): def setUp(self): DescriptorTest.setUp(self) - self.module_class = DescrptHybrid - ddsub0 = { - "type": "dpa1", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel_mix, - "type_map": ["O", "H"], - } - ddsub1 = { - "type": "dpa1", - "ntypes": self.nt, - "rcut": self.rcut, - "rcut_smth": self.rcut_smth, - "sel": self.sel_mix, - "type_map": ["O", "H"], - } - self.input_dict = { - "list": [ddsub0, ddsub1], - } - self.module = DescrptHybrid(**self.input_dict) + (DescriptorParam, Descrpt) = self.param[0] + self.module_class = Descrpt + self.input_dict = DescriptorParam( + self.nt, self.rcut, self.rcut_smth, self.sel, ["O", "H"] + ) + self.module = Descrpt(**self.input_dict) diff --git a/source/tests/universal/pt/fitting/test_fitting.py b/source/tests/universal/pt/fitting/test_fitting.py index 1b0ffd3eec..6551f49de6 100644 --- a/source/tests/universal/pt/fitting/test_fitting.py +++ b/source/tests/universal/pt/fitting/test_fitting.py @@ -14,52 +14,32 @@ from ...common.cases.fitting.fitting import ( FittingTest, ) +from ...dpmodel.fitting.test_fitting import ( + FittingParamDipole, + FittingParamDos, + FittingParamEnergy, + FittingParamPolar, +) from ..backend import ( PTTestCase, ) @parameterized( + ( + (FittingParamEnergy, EnergyFittingNet), + (FittingParamDos, DOSFittingNet), + (FittingParamDipole, DipoleFittingNet), + (FittingParamPolar, PolarFittingNet), + ), # class_param & class (True, False), # mixed_types ) -class TestFittingEnergyPT(unittest.TestCase, FittingTest, PTTestCase): - def setUp(self): - (self.mixed_types,) = self.param - FittingTest.setUp(self) - self.module_class = EnergyFittingNet - self.module = EnergyFittingNet(**self.input_dict) - - -@parameterized( - (True, False), # mixed_types -) -class TestFittingDosPT(unittest.TestCase, FittingTest, PTTestCase): - def setUp(self): - (self.mixed_types,) = self.param - FittingTest.setUp(self) - self.module_class = DOSFittingNet - self.module = DOSFittingNet(**self.input_dict) - - -@parameterized( - (True, False), # mixed_types -) -class TestFittingDipolePT(unittest.TestCase, FittingTest, PTTestCase): - def setUp(self): - (self.mixed_types,) = self.param - FittingTest.setUp(self) - self.input_dict.update({"embedding_width": self.dim_embed}) - self.module_class = DipoleFittingNet - self.module = DipoleFittingNet(**self.input_dict) - - -@parameterized( - (True, False), # mixed_types -) -class TestFittingPolarPT(unittest.TestCase, FittingTest, PTTestCase): +class TestFittingPT(unittest.TestCase, FittingTest, PTTestCase): def setUp(self): - (self.mixed_types,) = self.param + ((FittingParam, Fitting), self.mixed_types) = self.param FittingTest.setUp(self) - self.input_dict.update({"embedding_width": self.dim_embed}) - self.module_class = PolarFittingNet - self.module = PolarFittingNet(**self.input_dict) + self.module_class = Fitting + self.input_dict = FittingParam( + self.nt, self.dim_descrpt, self.mixed_types, self.dim_embed, ["O", "H"] + ) + self.module = Fitting(**self.input_dict) diff --git a/source/tests/universal/pt/model/test_ener_model.py b/source/tests/universal/pt/model/test_ener_model.py deleted file mode 100644 index af5d77d5b4..0000000000 --- a/source/tests/universal/pt/model/test_ener_model.py +++ /dev/null @@ -1,48 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -import unittest - -from deepmd.pt.model.descriptor.se_a import ( - DescrptSeA, -) -from deepmd.pt.model.model.ener_model import ( - EnergyModel, -) -from deepmd.pt.model.task.ener import ( - EnergyFittingNet, -) - -from ...common.cases.model.ener_model import ( - EnerModelTest, -) -from ..backend import ( - PTTestCase, -) - - -class TestEnergyModelDP(unittest.TestCase, EnerModelTest, PTTestCase): - @property - def modules_to_test(self): - # for Model, we can test script module API - modules = [ - *PTTestCase.modules_to_test.fget(self), - self.script_module, - ] - return modules - - def setUp(self): - EnerModelTest.setUp(self) - ds = DescrptSeA( - rcut=self.expected_rcut, - rcut_smth=self.expected_rcut / 2, - sel=self.expected_sel, - ) - ft = EnergyFittingNet( - ntypes=len(self.expected_type_map), - dim_descrpt=ds.get_dim_out(), - mixed_types=ds.mixed_types(), - ) - self.module = EnergyModel( - ds, - ft, - type_map=self.expected_type_map, - ) diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py new file mode 100644 index 0000000000..336bb9ad40 --- /dev/null +++ b/source/tests/universal/pt/model/test_model.py @@ -0,0 +1,296 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import unittest + +from deepmd.pt.model.atomic_model import ( + DPAtomicModel, + PairTabAtomicModel, +) +from deepmd.pt.model.descriptor import ( + DescrptDPA1, + DescrptDPA2, + DescrptHybrid, + DescrptSeA, + DescrptSeR, + DescrptSeT, +) +from deepmd.pt.model.model import ( + DipoleModel, + DOSModel, + DPZBLModel, + EnergyModel, + PolarModel, +) +from deepmd.pt.model.task import ( + DipoleFittingNet, + DOSFittingNet, + EnergyFittingNet, + PolarFittingNet, +) + +from ....consistent.common import ( + parameterized, +) +from ...common.cases.model.model import ( + DipoleModelTest, + DosModelTest, + EnerModelTest, + PolarModelTest, + ZBLModelTest, +) +from ..backend import ( + PTTestCase, +) +from ..descriptor.test_descriptor import ( + DescriptorParamDPA1, + DescriptorParamDPA2, + DescriptorParamHybrid, + DescriptorParamHybridMixed, + DescriptorParamSeA, + DescriptorParamSeR, + DescriptorParamSeT, +) + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestEnergyModelPT(unittest.TestCase, EnerModelTest, PTTestCase): + # @property + # def modules_to_test(self): + # # for Model, we can test script module API + # modules = [ + # *PTTestCase.modules_to_test.fget(self), + # self.script_module, + # ] + # return modules + + def setUp(self): + EnerModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = EnergyModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.translated_output_def() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDosModelPT(unittest.TestCase, DosModelTest, PTTestCase): + # @property + # def modules_to_test(self): + # # for Model, we can test script module API + # modules = [ + # *PTTestCase.modules_to_test.fget(self), + # self.script_module, + # ] + # return modules + + def setUp(self): + DosModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + self.aprec_dict["test_smooth"] = 1e-4 + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = DOSFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DOSModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.translated_output_def() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestDipoleModelPT(unittest.TestCase, DipoleModelTest, PTTestCase): + # @property + # def modules_to_test(self): + # # for Model, we can test script module API + # modules = [ + # *PTTestCase.modules_to_test.fget(self), + # self.script_module, + # ] + # return modules + + def setUp(self): + DipoleModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = DipoleFittingNet( + **self.input_dict_ft, + embedding_width=ds.get_dim_emb(), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = DipoleModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.translated_output_def() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestPolarModelPT(unittest.TestCase, PolarModelTest, PTTestCase): + # @property + # def modules_to_test(self): + # # for Model, we can test script module API + # modules = [ + # *PTTestCase.modules_to_test.fget(self), + # self.script_module, + # ] + # return modules + + def setUp(self): + PolarModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = PolarFittingNet( + **self.input_dict_ft, + embedding_width=ds.get_dim_emb(), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + self.module = PolarModel( + ds, + ft, + type_map=self.expected_type_map, + ) + self.output_def = self.module.translated_output_def() + self.expected_has_message_passing = ds.has_message_passing() + + +@parameterized( + ( + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + (DescriptorParamHybridMixed, DescrptHybrid), + ) # class_param & class +) +class TestZBLModelPT(unittest.TestCase, ZBLModelTest, PTTestCase): + def setUp(self): + ZBLModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + # set special precision + # zbl weights not so smooth + self.aprec_dict["test_smooth"] = 5e-2 + self.input_dict_ds = DescriptorParam( + len(self.expected_type_map), + self.expected_rcut, + self.expected_rcut / 2, + self.expected_sel, + self.expected_type_map, + ) + ds = Descrpt(**self.input_dict_ds) + ft = EnergyFittingNet( + **self.input_dict_ft, + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + ) + dp_model = DPAtomicModel( + ds, + ft, + type_map=self.expected_type_map, + ) + pt_model = PairTabAtomicModel( + self.tab_file["use_srtab"], + self.expected_rcut, + self.expected_sel, + type_map=self.expected_type_map, + ) + self.module = DPZBLModel( + dp_model, + pt_model, + sw_rmin=self.tab_file["sw_rmin"], + sw_rmax=self.tab_file["sw_rmax"], + smin_alpha=self.tab_file["smin_alpha"], + type_map=self.expected_type_map, + ) + self.output_def = self.module.translated_output_def() + self.expected_has_message_passing = ds.has_message_passing() From 108cdee70e3a47a5e9902ed7695ce229087d9750 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:20:39 +0800 Subject: [PATCH 02/24] update se_r --- deepmd/dpmodel/descriptor/se_r.py | 4 ++-- deepmd/pt/model/descriptor/se_r.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deepmd/dpmodel/descriptor/se_r.py b/deepmd/dpmodel/descriptor/se_r.py index 5a037f5060..7480416991 100644 --- a/deepmd/dpmodel/descriptor/se_r.py +++ b/deepmd/dpmodel/descriptor/se_r.py @@ -193,8 +193,8 @@ def get_dim_out(self): return self.neuron[-1] def get_dim_emb(self): - """Returns the embedding (g2) dimension of this descriptor.""" - return self.neuron[-1] + """Returns the output dimension.""" + raise NotImplementedError def get_rcut(self): """Returns cutoff radius.""" diff --git a/deepmd/pt/model/descriptor/se_r.py b/deepmd/pt/model/descriptor/se_r.py index eb0c42f8df..ec7f687211 100644 --- a/deepmd/pt/model/descriptor/se_r.py +++ b/deepmd/pt/model/descriptor/se_r.py @@ -157,8 +157,8 @@ def get_dim_out(self) -> int: return self.neuron[-1] def get_dim_emb(self) -> int: - """Returns the embedding (g2) dimension of this descriptor.""" - return self.neuron[-1] + """Returns the output dimension.""" + raise NotImplementedError def get_dim_in(self) -> int: """Returns the input dimension.""" From 5a5f9e284b38eb0345000592a6431872b2758982 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:28:16 +0800 Subject: [PATCH 03/24] fix ut --- .../common/cases/atomic_model/utils.py | 10 ++++----- .../universal/common/cases/model/utils.py | 22 +++++++++---------- .../universal/dpmodel/model/test_model.py | 1 + 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/source/tests/universal/common/cases/atomic_model/utils.py b/source/tests/universal/common/cases/atomic_model/utils.py index bbf22e10a4..f81b549ab6 100644 --- a/source/tests/universal/common/cases/atomic_model/utils.py +++ b/source/tests/universal/common/cases/atomic_model/utils.py @@ -188,7 +188,7 @@ def test_permutation(self): module(coord_ext_perm, atype_ext_perm, nlist_perm, mapping=mapping_perm) ) - for kk in ret[0].keys(): + for kk in ret[0]: if kk in self.expected_model_output_type: atomic = self.output_def[kk].atomic if atomic: @@ -255,7 +255,7 @@ def test_trans(self): module(coord_ext_trans, atype_ext_trans, nlist_trans, mapping=mapping_trans) ) - for kk in ret[0].keys(): + for kk in ret[0]: if kk in self.expected_model_output_type: np.testing.assert_allclose( ret[0][kk], @@ -315,7 +315,7 @@ def test_rot(self): ) ret.append(module(coord_ext_rot, atype_ext_rot, nlist_rot, mapping=mapping_rot)) - for kk in ret[0].keys(): + for kk in ret[0]: if kk in self.expected_model_output_type: rot_invariant = self.output_def[kk].rot_invariant if rot_invariant: @@ -379,7 +379,7 @@ def test_rot(self): ) ret.append(module(coord_ext_rot, atype_ext_rot, nlist_rot, mapping=mapping_rot)) - for kk in ret[0].keys(): + for kk in ret[0]: if kk in self.expected_model_output_type: rot_invariant = self.output_def[kk].rot_invariant if rot_invariant: @@ -507,7 +507,7 @@ def test_smooth(self): ) ret.append(module(coord_ext3, atype_ext3, nlist3, mapping=mapping3)) - for kk in ret[0].keys(): + for kk in ret[0]: if kk in self.expected_model_output_type: for ii in range(len(ret) - 1): np.testing.assert_allclose( diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index 1b3f46ccb9..754e708348 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -136,7 +136,7 @@ def test_forward(self): ret_lower.append( module.forward_lower(coord_ext, atype_ext, nlist, mapping=mapping) ) - for kk in ret[0].keys(): + for kk in ret[0]: subret = [] for rr in ret: if rr is not None: @@ -208,8 +208,8 @@ def test_permutation(self): # permutation ret.append(module(coord_perm, atype_perm, cell)) - for kk in ret[0].keys(): - if kk in self.output_def.keys(): + for kk in ret[0]: + if kk in self.output_def: if ret[0][kk] is None: assert ret[1][kk] is None continue @@ -258,8 +258,8 @@ def test_trans(self): # translation ret.append(module(coord_s, atype, cell)) - for kk in ret[0].keys(): - if kk in self.output_def.keys(): + for kk in ret[0]: + if kk in self.output_def: if ret[0][kk] is None: assert ret[1][kk] is None continue @@ -303,8 +303,8 @@ def test_rot(self): # rotation ret.append(module(coord_rot, atype, cell)) - for kk in ret[0].keys(): - if kk in self.output_def.keys(): + for kk in ret[0]: + if kk in self.output_def: if ret[0][kk] is None: assert ret[1][kk] is None continue @@ -365,8 +365,8 @@ def test_rot(self): # rotation ret.append(module(coord_rot, atype, cell_rot)) - for kk in ret[0].keys(): - if kk in self.output_def.keys(): + for kk in ret[0]: + if kk in self.output_def: if ret[0][kk] is None: assert ret[1][kk] is None continue @@ -477,8 +477,8 @@ def test_smooth(self): # coord3 ret.append(module(coord3, atype, cell)) - for kk in ret[0].keys(): - if kk in self.output_def.keys(): + for kk in ret[0]: + if kk in self.output_def: if ret[0][kk] is None: for ii in range(len(ret) - 1): assert ret[ii + 1][kk] is None diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 157cc03675..9e8ca71ea8 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -74,3 +74,4 @@ def setUp(self): ) self.output_def = self.module.model_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.skip_test_autodiff = True From 6f59a27bd752461b60f5a074838711a903da4a73 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:01:23 +0800 Subject: [PATCH 04/24] add parametrize to models --- deepmd/dpmodel/common.py | 2 + deepmd/dpmodel/fitting/dipole_fitting.py | 1 - .../dpmodel/fitting/polarizability_fitting.py | 1 - deepmd/dpmodel/model/spin_model.py | 47 ++- deepmd/dpmodel/output_def.py | 19 +- deepmd/pt/model/model/spin_model.py | 45 ++- deepmd/pt/model/task/dipole.py | 1 - deepmd/pt/model/task/polarizability.py | 1 - deepmd/pt/utils/env.py | 2 + deepmd/utils/path.py | 2 +- .../tests/common/dpmodel/test_output_def.py | 34 +- source/tests/consistent/common.py | 49 +++ .../common/cases/atomic_model/atomic_model.py | 41 +-- .../common/cases/atomic_model/utils.py | 203 +++++++++-- .../universal/common/cases/model/model.py | 41 ++- .../universal/common/cases/model/utils.py | 344 +++++++++++++++--- .../dpmodel/atomc_model/test_atomic_model.py | 169 ++++++--- .../dpmodel/descriptor/test_descriptor.py | 333 ++++++++++++++--- .../universal/dpmodel/fitting/test_fitting.py | 129 ++++++- .../universal/dpmodel/model/test_model.py | 154 +++++++- .../pt/atomc_model/test_atomic_model.py | 171 ++++++--- .../universal/pt/fitting/test_fitting.py | 6 +- source/tests/universal/pt/model/test_model.py | 266 +++++++++++--- 23 files changed, 1696 insertions(+), 365 deletions(-) diff --git a/deepmd/dpmodel/common.py b/deepmd/dpmodel/common.py index 8030432385..56cb8ec1e9 100644 --- a/deepmd/dpmodel/common.py +++ b/deepmd/dpmodel/common.py @@ -24,6 +24,7 @@ "double": np.float64, "int32": np.int32, "int64": np.int64, + "bool": bool, "default": GLOBAL_NP_FLOAT_PRECISION, # NumPy doesn't have bfloat16 (and does't plan to add) # ml_dtypes is a solution, but it seems not supporting np.save/np.load @@ -39,6 +40,7 @@ np.int32: "int32", np.int64: "int64", ml_dtypes.bfloat16: "bfloat16", + bool: "bool", } assert set(RESERVED_PRECISON_DICT.keys()) == set(PRECISION_DICT.values()) DEFAULT_PRECISION = "float64" diff --git a/deepmd/dpmodel/fitting/dipole_fitting.py b/deepmd/dpmodel/fitting/dipole_fitting.py index ed42638f86..f922b57367 100644 --- a/deepmd/dpmodel/fitting/dipole_fitting.py +++ b/deepmd/dpmodel/fitting/dipole_fitting.py @@ -175,7 +175,6 @@ def output_def(self): reduciable=True, r_differentiable=self.r_differentiable, c_differentiable=self.c_differentiable, - rot_invariant=False, ), ] ) diff --git a/deepmd/dpmodel/fitting/polarizability_fitting.py b/deepmd/dpmodel/fitting/polarizability_fitting.py index 4b31f2ba07..67b4888c67 100644 --- a/deepmd/dpmodel/fitting/polarizability_fitting.py +++ b/deepmd/dpmodel/fitting/polarizability_fitting.py @@ -218,7 +218,6 @@ def output_def(self): reduciable=True, r_differentiable=False, c_differentiable=False, - rot_invariant=False, ), ] ) diff --git a/deepmd/dpmodel/model/spin_model.py b/deepmd/dpmodel/model/spin_model.py index c2cea35d27..cd8587c7a4 100644 --- a/deepmd/dpmodel/model/spin_model.py +++ b/deepmd/dpmodel/model/spin_model.py @@ -10,15 +10,21 @@ from deepmd.dpmodel.atomic_model.dp_atomic_model import ( DPAtomicModel, ) +from deepmd.dpmodel.common import ( + NativeOP, +) from deepmd.dpmodel.model.make_model import ( make_model, ) +from deepmd.dpmodel.output_def import ( + ModelOutputDef, +) from deepmd.utils.spin import ( Spin, ) -class SpinModel: +class SpinModel(NativeOP): """A spin model wrapper, with spin input preprocess and output split.""" def __init__( @@ -152,15 +158,20 @@ def extend_nlist(extended_atype, nlist): nlist_shift = nlist + nall nlist[~nlist_mask] = -1 nlist_shift[~nlist_mask] = -1 - self_spin = np.arange(0, nloc, dtype=nlist.dtype) + nall - self_spin = self_spin.reshape(1, -1, 1).repeat(nframes, axis=0) - # self spin + real neighbor + virtual neighbor + self_real = ( + np.arange(0, nloc, dtype=nlist.dtype) + .reshape(1, -1, 1) + .repeat(nframes, axis=0) + ) + self_spin = self_real + nall + # real atom's neighbors: self spin + real neighbor + virtual neighbor # nf x nloc x (1 + nnei + nnei) - extended_nlist = np.concatenate([self_spin, nlist, nlist_shift], axis=-1) + real_nlist = np.concatenate([self_spin, nlist, nlist_shift], axis=-1) + # spin atom's neighbors: real + real neighbor + virtual neighbor + # nf x nloc x (1 + nnei + nnei) + spin_nlist = np.concatenate([self_real, nlist, nlist_shift], axis=-1) # nf x (nloc + nloc) x (1 + nnei + nnei) - extended_nlist = np.concatenate( - [extended_nlist, -1 * np.ones_like(extended_nlist)], axis=-2 - ) + extended_nlist = np.concatenate([real_nlist, spin_nlist], axis=-2) # update the index for switch first_part_index = (nloc <= extended_nlist) & (extended_nlist < nall) second_part_index = (nall <= extended_nlist) & (extended_nlist < (nall + nloc)) @@ -193,6 +204,10 @@ def get_type_map(self) -> List[str]: ntypes = len(tmap) // 2 # ignore the virtual type return tmap[:ntypes] + def get_ntypes(self): + """Returns the number of element types.""" + return len(self.get_type_map()) + def get_rcut(self): """Get the cut-off radius.""" return self.backbone_model.get_rcut() @@ -251,6 +266,16 @@ def has_spin() -> bool: """Returns whether it has spin input and output.""" return True + def model_output_def(self): + """Get the output def for the model.""" + model_output_type = self.backbone_model.model_output_type() + if "mask" in model_output_type: + model_output_type.pop(model_output_type.index("mask")) + var_name = model_output_type[0] + backbone_model_atomic_output_def = self.backbone_model.atomic_output_def() + backbone_model_atomic_output_def[var_name].magnetic = True + return ModelOutputDef(backbone_model_atomic_output_def) + def __getattr__(self, name): """Get attribute from the wrapped model.""" if name in self.__dict__: @@ -313,7 +338,9 @@ def call( The keys are defined by the `ModelOutputDef`. """ - nframes, nloc = coord.shape[:2] + nframes, nloc = atype.shape[:2] + coord = coord.reshape(nframes, nloc, 3) + spin = spin.reshape(nframes, nloc, 3) coord_updated, atype_updated = self.process_spin_input(coord, atype, spin) model_predict = self.backbone_model.call( coord_updated, @@ -401,3 +428,5 @@ def call_lower( )[0] # for now omit the grad output return model_predict + + forward_lower = call_lower diff --git a/deepmd/dpmodel/output_def.py b/deepmd/dpmodel/output_def.py index df9350d876..e16809130f 100644 --- a/deepmd/dpmodel/output_def.py +++ b/deepmd/dpmodel/output_def.py @@ -186,8 +186,6 @@ class OutputVariableDef: If hessian is requred magnetic : bool If the derivatives of variable have magnetic parts. - rot_invariant : bool - If the variable is rotationally invariant. """ def __init__( @@ -201,7 +199,6 @@ def __init__( category: int = OutputVariableCategory.OUT.value, r_hessian: bool = False, magnetic: bool = False, - rot_invariant: bool = True, ): self.name = name self.shape = list(shape) @@ -221,7 +218,6 @@ def __init__( self.category = category self.r_hessian = r_hessian self.magnetic = magnetic - self.rot_invariant = rot_invariant if self.r_hessian: if not self.reduciable: raise ValueError("only reduciable variable can calculate hessian") @@ -410,6 +406,16 @@ def check_operation_applied( return var_def.category & op.value == op.value +def check_deriv(var_def: OutputVariableDef) -> bool: + """Check if a variable is obtained by derivative.""" + deriv = ( + check_operation_applied(var_def, OutputVariableOperation.DERV_R) + or check_operation_applied(var_def, OutputVariableOperation._SEC_DERV_R) + or check_operation_applied(var_def, OutputVariableOperation.DERV_C) + ) + return deriv + + def do_reduce( def_outp_data: Dict[str, OutputVariableDef], ) -> Dict[str, OutputVariableDef]: @@ -425,7 +431,6 @@ def do_reduce( c_differentiable=False, atomic=False, category=apply_operation(vv, OutputVariableOperation.REDU), - rot_invariant=vv.rot_invariant, ) return def_redu @@ -474,7 +479,6 @@ def do_derivative( c_differentiable=False, atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_R), - rot_invariant=False, ) if vv.magnetic: def_derv_r[rkrm] = OutputVariableDef( @@ -488,7 +492,6 @@ def do_derivative( atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_R), magnetic=True, - rot_invariant=False, ) if vv.c_differentiable: @@ -501,7 +504,6 @@ def do_derivative( c_differentiable=False, atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_C), - rot_invariant=False, ) if vv.magnetic: def_derv_r[rkcm] = OutputVariableDef( @@ -513,6 +515,5 @@ def do_derivative( atomic=True, category=apply_operation(vv, OutputVariableOperation.DERV_C), magnetic=True, - rot_invariant=False, ) return def_derv_r, def_derv_c diff --git a/deepmd/pt/model/model/spin_model.py b/deepmd/pt/model/model/spin_model.py index 369a413f50..f51e5654ce 100644 --- a/deepmd/pt/model/model/spin_model.py +++ b/deepmd/pt/model/model/spin_model.py @@ -1,5 +1,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-later import functools +from copy import ( + deepcopy, +) from typing import ( Dict, List, @@ -8,6 +11,9 @@ import torch +from deepmd.dpmodel import ( + ModelOutputDef, +) from deepmd.pt.model.atomic_model import ( DPAtomicModel, ) @@ -43,7 +49,9 @@ def __init__( def process_spin_input(self, coord, atype, spin): """Generate virtual coordinates and types, concat into the input.""" - nframes, nloc = coord.shape[:-1] + nframes, nloc = atype.shape + coord = coord.reshape(nframes, nloc, 3) + spin = spin.reshape(nframes, nloc, 3) atype_spin = torch.concat([atype, atype + self.ntypes_real], dim=-1) virtual_coord = coord + spin * self.virtual_scale_mask[atype].reshape( [nframes, nloc, 1] @@ -250,6 +258,11 @@ def get_type_map(self) -> List[str]: ntypes = len(tmap) // 2 # ignore the virtual type return tmap[:ntypes] + @torch.jit.export + def get_ntypes(self): + """Returns the number of element types.""" + return len(self.get_type_map()) + @torch.jit.export def get_rcut(self): """Get the cut-off radius.""" @@ -318,6 +331,16 @@ def has_spin(self) -> bool: """Returns whether it has spin input and output.""" return True + def model_output_def(self): + """Get the output def for the model.""" + model_output_type = self.backbone_model.model_output_type() + if "mask" in model_output_type: + model_output_type.pop(model_output_type.index("mask")) + var_name = model_output_type[0] + backbone_model_atomic_output_def = self.backbone_model.atomic_output_def() + backbone_model_atomic_output_def[var_name].magnetic = True + return ModelOutputDef(backbone_model_atomic_output_def) + def __getattr__(self, name): """Get attribute from the wrapped model.""" if ( @@ -385,7 +408,7 @@ def forward_common( aparam: Optional[torch.Tensor] = None, do_atomic_virial: bool = False, ) -> Dict[str, torch.Tensor]: - nframes, nloc = coord.shape[:2] + nframes, nloc = atype.shape coord_updated, atype_updated = self.process_spin_input(coord, atype, spin) model_ret = self.backbone_model.forward_common( coord_updated, @@ -509,6 +532,20 @@ def __init__( ): super().__init__(backbone_model, spin) + def translated_output_def(self): + out_def_data = self.model_output_def().get_data() + output_def = { + "atom_energy": deepcopy(out_def_data["energy"]), + "energy": deepcopy(out_def_data["energy_redu"]), + "mask_mag": deepcopy(out_def_data["mask_mag"]), + } + if self.do_grad_r("energy"): + output_def["force"] = deepcopy(out_def_data["energy_derv_r"]) + output_def["force"].squeeze(-2) + output_def["force_mag"] = deepcopy(out_def_data["energy_derv_r_mag"]) + output_def["force_mag"].squeeze(-2) + return output_def + def forward( self, coord, @@ -520,7 +557,7 @@ def forward( do_atomic_virial: bool = False, ) -> Dict[str, torch.Tensor]: if aparam is not None: - aparam = self.expand_aparam(aparam, coord.shape[1]) + aparam = self.expand_aparam(aparam, atype.shape[1]) model_ret = self.forward_common( coord, atype, @@ -565,7 +602,7 @@ def forward_lower( model_predict = {} model_predict["atom_energy"] = model_ret["energy"] model_predict["energy"] = model_ret["energy_redu"] - model_predict["mask_mag"] = model_ret["mask_mag"] + model_predict["extended_mask_mag"] = model_ret["mask_mag"] if self.backbone_model.do_grad_r("energy"): model_predict["extended_force"] = model_ret["energy_derv_r"].squeeze(-2) model_predict["extended_force_mag"] = model_ret[ diff --git a/deepmd/pt/model/task/dipole.py b/deepmd/pt/model/task/dipole.py index dcc16c12c9..917af1bdcc 100644 --- a/deepmd/pt/model/task/dipole.py +++ b/deepmd/pt/model/task/dipole.py @@ -145,7 +145,6 @@ def output_def(self) -> FittingOutputDef: reduciable=True, r_differentiable=self.r_differentiable, c_differentiable=self.c_differentiable, - rot_invariant=False, ), ] ) diff --git a/deepmd/pt/model/task/polarizability.py b/deepmd/pt/model/task/polarizability.py index e3f5cb180a..66120a1523 100644 --- a/deepmd/pt/model/task/polarizability.py +++ b/deepmd/pt/model/task/polarizability.py @@ -219,7 +219,6 @@ def output_def(self) -> FittingOutputDef: reduciable=True, r_differentiable=False, c_differentiable=False, - rot_invariant=False, ), ] ) diff --git a/deepmd/pt/utils/env.py b/deepmd/pt/utils/env.py index d841a9b73c..3ee0b7b54d 100644 --- a/deepmd/pt/utils/env.py +++ b/deepmd/pt/utils/env.py @@ -44,6 +44,7 @@ "int32": torch.int32, "int64": torch.int64, "bfloat16": torch.bfloat16, + "bool": torch.bool, } GLOBAL_PT_FLOAT_PRECISION = PRECISION_DICT[np.dtype(GLOBAL_NP_FLOAT_PRECISION).name] GLOBAL_PT_ENER_FLOAT_PRECISION = PRECISION_DICT[ @@ -59,6 +60,7 @@ torch.int32: "int32", torch.int64: "int64", torch.bfloat16: "bfloat16", + torch.bool: "bool", } assert set(PRECISION_DICT.values()) == set(RESERVED_PRECISON_DICT.keys()) DEFAULT_PRECISION = "float64" diff --git a/deepmd/utils/path.py b/deepmd/utils/path.py index 377953cc35..1f9c4be3ef 100644 --- a/deepmd/utils/path.py +++ b/deepmd/utils/path.py @@ -320,7 +320,7 @@ def _load_h5py(cls, path: str, mode: str = "r") -> h5py.File: # this method has cache to avoid duplicated # loading from different DPH5Path # However the file will be never closed? - return h5py.File(path, mode) + return h5py.File(path, mode, locking=False) def load_numpy(self) -> np.ndarray: """Load NumPy array. diff --git a/source/tests/common/dpmodel/test_output_def.py b/source/tests/common/dpmodel/test_output_def.py index 9430799213..ca9461b0d3 100644 --- a/source/tests/common/dpmodel/test_output_def.py +++ b/source/tests/common/dpmodel/test_output_def.py @@ -80,19 +80,10 @@ def test_model_output_def(self): c_differentiable=False, atomic=True, ), - OutputVariableDef( - "foo2", - [3], - reduciable=False, - r_differentiable=False, - c_differentiable=False, - atomic=True, - rot_invariant=False, - ), ] # fitting definition fd = FittingOutputDef(defs) - expected_keys = ["energy", "energy2", "energy3", "dos", "foo", "foo2"] + expected_keys = ["energy", "energy2", "energy3", "dos", "foo"] self.assertEqual( set(expected_keys), set(fd.keys()), @@ -103,21 +94,18 @@ def test_model_output_def(self): self.assertEqual(fd["energy3"].shape, [1]) self.assertEqual(fd["dos"].shape, [10]) self.assertEqual(fd["foo"].shape, [3]) - self.assertEqual(fd["foo2"].shape, [3]) # atomic self.assertEqual(fd["energy"].atomic, True) self.assertEqual(fd["energy2"].atomic, True) self.assertEqual(fd["energy3"].atomic, True) self.assertEqual(fd["dos"].atomic, True) self.assertEqual(fd["foo"].atomic, True) - self.assertEqual(fd["foo2"].atomic, True) # reduce self.assertEqual(fd["energy"].reduciable, True) self.assertEqual(fd["energy2"].reduciable, True) self.assertEqual(fd["energy3"].reduciable, True) self.assertEqual(fd["dos"].reduciable, True) self.assertEqual(fd["foo"].reduciable, False) - self.assertEqual(fd["foo2"].reduciable, False) # derivative self.assertEqual(fd["energy"].r_differentiable, True) self.assertEqual(fd["energy"].c_differentiable, True) @@ -130,24 +118,14 @@ def test_model_output_def(self): self.assertEqual(fd["energy3"].r_hessian, False) self.assertEqual(fd["dos"].r_differentiable, False) self.assertEqual(fd["foo"].r_differentiable, False) - self.assertEqual(fd["foo2"].r_differentiable, False) self.assertEqual(fd["dos"].c_differentiable, False) self.assertEqual(fd["foo"].c_differentiable, False) - self.assertEqual(fd["foo2"].c_differentiable, False) # magnetic self.assertEqual(fd["energy"].magnetic, False) self.assertEqual(fd["energy2"].magnetic, False) self.assertEqual(fd["energy3"].magnetic, True) self.assertEqual(fd["dos"].magnetic, False) self.assertEqual(fd["foo"].magnetic, False) - self.assertEqual(fd["foo2"].magnetic, False) - # rot_invariant - self.assertEqual(fd["energy"].rot_invariant, True) - self.assertEqual(fd["energy2"].rot_invariant, True) - self.assertEqual(fd["energy3"].rot_invariant, True) - self.assertEqual(fd["dos"].rot_invariant, True) - self.assertEqual(fd["foo"].rot_invariant, True) - self.assertEqual(fd["foo2"].rot_invariant, False) # model definition md = ModelOutputDef(fd) expected_keys = [ @@ -156,7 +134,6 @@ def test_model_output_def(self): "energy3", "dos", "foo", - "foo2", "energy_redu", "energy_derv_r", "energy_derv_c", @@ -188,7 +165,6 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].reduciable, True) self.assertEqual(md["dos"].reduciable, True) self.assertEqual(md["foo"].reduciable, False) - self.assertEqual(md["foo2"].reduciable, False) # derivative self.assertEqual(md["energy"].r_differentiable, True) self.assertEqual(md["energy"].c_differentiable, True) @@ -201,10 +177,8 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].r_hessian, False) self.assertEqual(md["dos"].r_differentiable, False) self.assertEqual(md["foo"].r_differentiable, False) - self.assertEqual(md["foo2"].r_differentiable, False) self.assertEqual(md["dos"].c_differentiable, False) self.assertEqual(md["foo"].c_differentiable, False) - self.assertEqual(md["foo2"].c_differentiable, False) # shape self.assertEqual(md["mask"].shape, [1]) self.assertEqual(md["mask_mag"].shape, [1]) @@ -213,7 +187,6 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].shape, [1]) self.assertEqual(md["dos"].shape, [10]) self.assertEqual(md["foo"].shape, [3]) - self.assertEqual(md["foo2"].shape, [3]) self.assertEqual(md["energy_redu"].shape, [1]) self.assertEqual(md["energy_derv_r"].shape, [1, 3]) self.assertEqual(md["energy_derv_c"].shape, [1, 9]) @@ -233,7 +206,6 @@ def test_model_output_def(self): self.assertEqual(md["energy2"].atomic, True) self.assertEqual(md["dos"].atomic, True) self.assertEqual(md["foo"].atomic, True) - self.assertEqual(md["foo2"].atomic, True) self.assertEqual(md["energy_redu"].atomic, False) self.assertEqual(md["energy_derv_r"].atomic, True) self.assertEqual(md["energy_derv_c"].atomic, True) @@ -257,7 +229,6 @@ def test_model_output_def(self): self.assertEqual(md["energy3"].category, OutputVariableCategory.OUT) self.assertEqual(md["dos"].category, OutputVariableCategory.OUT) self.assertEqual(md["foo"].category, OutputVariableCategory.OUT) - self.assertEqual(md["foo2"].category, OutputVariableCategory.OUT) self.assertEqual(md["energy_redu"].category, OutputVariableCategory.REDU) self.assertEqual(md["energy_derv_r"].category, OutputVariableCategory.DERV_R) self.assertEqual(md["energy_derv_c"].category, OutputVariableCategory.DERV_C) @@ -302,9 +273,6 @@ def test_model_output_def(self): self.assertEqual(md["foo"].category & OVO.REDU, 0) self.assertEqual(md["foo"].category & OVO.DERV_R, 0) self.assertEqual(md["foo"].category & OVO.DERV_C, 0) - self.assertEqual(md["foo2"].category & OVO.REDU, 0) - self.assertEqual(md["foo2"].category & OVO.DERV_R, 0) - self.assertEqual(md["foo2"].category & OVO.DERV_C, 0) # flag: energy self.assertEqual( md["energy_redu"].category & OVO.REDU, diff --git a/source/tests/consistent/common.py b/source/tests/consistent/common.py index cbcb987c89..dc80a83f8c 100644 --- a/source/tests/consistent/common.py +++ b/source/tests/consistent/common.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +import inspect import itertools import os import sys @@ -6,6 +7,9 @@ ABC, abstractmethod, ) +from collections import ( + OrderedDict, +) from enum import ( Enum, ) @@ -413,3 +417,48 @@ class TestClass(base_class): return object return decorator + + +def parameterize_func( + func: Callable, + param_dict_list: OrderedDict[str, Tuple], +): + """Parameterize functions with different default values. + + Parameters + ---------- + func : Callable + The base function. + param_dict_list : OrderedDict[str, Tuple] + Dictionary of parameters with default values to be changed in base function, each of which is a tuple of choices. + + Returns + ------- + list_func + List of parameterized functions with changed default values. + + """ + + def create_wrapper(_func, _new_sig, _pp): + def wrapper(*args, **kwargs): + bound_args = _new_sig.bind(*args, **kwargs) + bound_args.apply_defaults() + return _func(*bound_args.args, **bound_args.kwargs) + + wrapper.__name__ = f"{_func.__name__}_{'_'.join(str(x) for x in _pp)}" + wrapper.__qualname__ = wrapper.__name__ + return wrapper + + list_func = [] + param_keys = list(param_dict_list.keys()) + for pp in itertools.product(*[param_dict_list[kk] for kk in param_keys]): + sig = inspect.signature(func) + new_params = dict(sig.parameters) + for ii, val in enumerate(pp): + val_name = param_keys[ii] + # only change the default value of func + new_params[val_name] = sig.parameters[val_name].replace(default=val) + new_sig = sig.replace(parameters=list(new_params.values())) + list_func.append(create_wrapper(func, new_sig, pp)) + + return list_func diff --git a/source/tests/universal/common/cases/atomic_model/atomic_model.py b/source/tests/universal/common/cases/atomic_model/atomic_model.py index 6c1790483e..d341c59af6 100644 --- a/source/tests/universal/common/cases/atomic_model/atomic_model.py +++ b/source/tests/universal/common/cases/atomic_model/atomic_model.py @@ -2,9 +2,6 @@ import os -from .....seed import ( - GLOBAL_SEED, -) from .utils import ( AtomicModelTestCase, ) @@ -15,89 +12,73 @@ class EnerAtomicModelTest(AtomicModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["energy", "mask"] + self.model_output_equivariant = [] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } class DipoleAtomicModelTest(AtomicModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["dipole", "mask"] + self.model_output_equivariant = ["dipole"] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } class PolarAtomicModelTest(AtomicModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["polarizability", "mask"] + self.model_output_equivariant = ["polarizability"] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } class DosAtomicModelTest(AtomicModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["dos", "mask"] + self.model_output_equivariant = [] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } class ZBLAtomicModelTest(AtomicModelTestCase): @@ -109,17 +90,13 @@ def setUp(self) -> None: self.expected_sel_type = [] self.expected_aparam_nall = False self.expected_model_output_type = ["energy", "mask"] + self.model_output_equivariant = [] self.expected_sel = [46, 92, 10] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } self.tab_file = { "use_srtab": f"{CUR_DIR}/../data/zbl_tab_potential/H2O_tab_potential.txt", "smin_alpha": 0.1, diff --git a/source/tests/universal/common/cases/atomic_model/utils.py b/source/tests/universal/common/cases/atomic_model/utils.py index f81b549ab6..17af932183 100644 --- a/source/tests/universal/common/cases/atomic_model/utils.py +++ b/source/tests/universal/common/cases/atomic_model/utils.py @@ -12,6 +12,9 @@ import numpy as np +from deepmd.dpmodel.output_def import ( + check_deriv, +) from deepmd.dpmodel.utils.nlist import ( extend_input_and_build_neighbor_list, ) @@ -38,6 +41,8 @@ class AtomicModelTestCase: """Expected shape of atomic parameters.""" expected_model_output_type: List[str] """Expected output type for the model.""" + model_output_equivariant: List[str] + """Outputs that are equivariant to the input rotation.""" expected_sel: List[int] """Expected number of neighbors.""" expected_has_message_passing: bool @@ -102,6 +107,7 @@ def test_has_message_passing(self): def test_forward(self): """Test forward.""" nf = 1 + rng = np.random.default_rng(GLOBAL_SEED) coord = np.array( [ [0, 0, 0], @@ -121,10 +127,24 @@ def test_forward(self): box=cell, ) ret_lower = [] + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, 3, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) for module in self.modules_to_test: module = self.forward_wrapper(module) - - ret_lower.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + ret_lower.append( + module( + coord_ext, + atype_ext, + nlist, + mapping=mapping, + fparam=fparam, + aparam=aparam, + ) + ) for kk in ret_lower[0].keys(): subret = [] for rr in ret_lower: @@ -142,7 +162,7 @@ def test_forward(self): def test_permutation(self): """Test permutation.""" if getattr(self, "skip_test_permutation", False): - return + self.skipTest("Skip test permutation.") rng = np.random.default_rng(GLOBAL_SEED) natoms = 5 nf = 1 @@ -161,6 +181,14 @@ def test_permutation(self): atype = atype.reshape([nf, -1]) atype_perm = atype_perm.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + aparam_perm = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + aparam_perm = aparam[:, idx_perm, :] + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) ret = [] module = self.forward_wrapper(self.module) @@ -172,7 +200,16 @@ def test_permutation(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + ret.append( + module( + coord_ext, + atype_ext, + nlist, + mapping=mapping, + fparam=fparam, + aparam=aparam, + ) + ) # permutation coord_ext_perm, atype_ext_perm, mapping_perm, nlist_perm = ( extend_input_and_build_neighbor_list( @@ -185,7 +222,14 @@ def test_permutation(self): ) ) ret.append( - module(coord_ext_perm, atype_ext_perm, nlist_perm, mapping=mapping_perm) + module( + coord_ext_perm, + atype_ext_perm, + nlist_perm, + mapping=mapping_perm, + fparam=fparam, + aparam=aparam_perm, + ) ) for kk in ret[0]: @@ -209,7 +253,7 @@ def test_permutation(self): def test_trans(self): """Test translation.""" if getattr(self, "skip_test_trans", False): - return + self.skipTest("Skip test translation.") rng = np.random.default_rng(GLOBAL_SEED) natoms = 5 nf = 1 @@ -229,6 +273,13 @@ def test_trans(self): atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( @@ -239,7 +290,16 @@ def test_trans(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + ret.append( + module( + coord_ext, + atype_ext, + nlist, + mapping=mapping, + fparam=fparam, + aparam=aparam, + ) + ) # translation coord_ext_trans, atype_ext_trans, mapping_trans, nlist_trans = ( extend_input_and_build_neighbor_list( @@ -252,7 +312,14 @@ def test_trans(self): ) ) ret.append( - module(coord_ext_trans, atype_ext_trans, nlist_trans, mapping=mapping_trans) + module( + coord_ext_trans, + atype_ext_trans, + nlist_trans, + mapping=mapping_trans, + fparam=fparam, + aparam=aparam, + ) ) for kk in ret[0]: @@ -268,7 +335,7 @@ def test_trans(self): def test_rot(self): """Test rotation.""" if getattr(self, "skip_test_rot", False): - return + self.skipTest("Skip test rotation.") rng = np.random.default_rng(GLOBAL_SEED) natoms = 5 nf = 1 @@ -291,6 +358,13 @@ def test_rot(self): atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( @@ -301,7 +375,16 @@ def test_rot(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + ret.append( + module( + coord_ext, + atype_ext, + nlist, + mapping=mapping, + fparam=fparam, + aparam=aparam, + ) + ) # rotation coord_ext_rot, atype_ext_rot, mapping_rot, nlist_rot = ( extend_input_and_build_neighbor_list( @@ -313,12 +396,24 @@ def test_rot(self): box=cell, ) ) - ret.append(module(coord_ext_rot, atype_ext_rot, nlist_rot, mapping=mapping_rot)) + ret.append( + module( + coord_ext_rot, + atype_ext_rot, + nlist_rot, + mapping=mapping_rot, + fparam=fparam, + aparam=aparam, + ) + ) for kk in ret[0]: if kk in self.expected_model_output_type: - rot_invariant = self.output_def[kk].rot_invariant - if rot_invariant: + rot_equivariant = ( + check_deriv(self.output_def[kk]) + or kk in self.model_output_equivariant + ) + if not rot_equivariant: np.testing.assert_allclose( ret[0][kk], ret[1][kk], @@ -365,7 +460,16 @@ def test_rot(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext, atype_ext, nlist, mapping=mapping)) + ret.append( + module( + coord_ext, + atype_ext, + nlist, + mapping=mapping, + fparam=fparam, + aparam=aparam, + ) + ) # rotation coord_ext_rot, atype_ext_rot, mapping_rot, nlist_rot = ( extend_input_and_build_neighbor_list( @@ -377,12 +481,24 @@ def test_rot(self): box=cell_rot, ) ) - ret.append(module(coord_ext_rot, atype_ext_rot, nlist_rot, mapping=mapping_rot)) + ret.append( + module( + coord_ext_rot, + atype_ext_rot, + nlist_rot, + mapping=mapping_rot, + fparam=fparam, + aparam=aparam, + ) + ) for kk in ret[0]: if kk in self.expected_model_output_type: - rot_invariant = self.output_def[kk].rot_invariant - if rot_invariant: + rot_equivariant = ( + check_deriv(self.output_def[kk]) + or kk in self.model_output_equivariant + ) + if not rot_equivariant: np.testing.assert_allclose( ret[0][kk], ret[1][kk], @@ -406,7 +522,7 @@ def test_rot(self): def test_smooth(self): """Test smooth.""" if getattr(self, "skip_test_smooth", False): - return + self.skipTest("Skip test smooth.") rng = np.random.default_rng(GLOBAL_SEED) epsilon = ( 1e-5 @@ -464,6 +580,13 @@ def test_smooth(self): atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) # coord0 @@ -475,7 +598,16 @@ def test_smooth(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext0, atype_ext0, nlist0, mapping=mapping0)) + ret.append( + module( + coord_ext0, + atype_ext0, + nlist0, + mapping=mapping0, + fparam=fparam, + aparam=aparam, + ) + ) # coord1 coord_ext1, atype_ext1, mapping1, nlist1 = extend_input_and_build_neighbor_list( coord1, @@ -485,7 +617,16 @@ def test_smooth(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext1, atype_ext1, nlist1, mapping=mapping1)) + ret.append( + module( + coord_ext1, + atype_ext1, + nlist1, + mapping=mapping1, + fparam=fparam, + aparam=aparam, + ) + ) # coord2 coord_ext2, atype_ext2, mapping2, nlist2 = extend_input_and_build_neighbor_list( coord2, @@ -495,7 +636,16 @@ def test_smooth(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext2, atype_ext2, nlist2, mapping=mapping2)) + ret.append( + module( + coord_ext2, + atype_ext2, + nlist2, + mapping=mapping2, + fparam=fparam, + aparam=aparam, + ) + ) # coord3 coord_ext3, atype_ext3, mapping3, nlist3 = extend_input_and_build_neighbor_list( coord3, @@ -505,7 +655,16 @@ def test_smooth(self): mixed_types=self.module.mixed_types(), box=cell, ) - ret.append(module(coord_ext3, atype_ext3, nlist3, mapping=mapping3)) + ret.append( + module( + coord_ext3, + atype_ext3, + nlist3, + mapping=mapping3, + fparam=fparam, + aparam=aparam, + ) + ) for kk in ret[0]: if kk in self.expected_model_output_type: diff --git a/source/tests/universal/common/cases/model/model.py b/source/tests/universal/common/cases/model/model.py index c814ff38e5..0c90f3d92a 100644 --- a/source/tests/universal/common/cases/model/model.py +++ b/source/tests/universal/common/cases/model/model.py @@ -15,12 +15,13 @@ class EnerModelTest(ModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["energy", "mask"] + self.model_output_equivariant = [] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False @@ -37,12 +38,13 @@ def setUp(self) -> None: class DipoleModelTest(ModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["dipole", "mask"] + self.model_output_equivariant = ["dipole", "global_dipole"] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False @@ -60,12 +62,13 @@ def setUp(self) -> None: class PolarModelTest(ModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["polarizability", "mask"] + self.model_output_equivariant = ["polar", "global_polar"] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False @@ -83,12 +86,13 @@ def setUp(self) -> None: class DosModelTest(ModelTestCase): def setUp(self) -> None: self.expected_rcut = 5.0 - self.expected_type_map = ["foo", "bar"] + self.expected_type_map = ["O", "H"] self.expected_dim_fparam = 0 self.expected_dim_aparam = 0 self.expected_sel_type = [0, 1] self.expected_aparam_nall = False self.expected_model_output_type = ["dos", "mask"] + self.model_output_equivariant = [] self.expected_sel = [46, 92] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False @@ -112,6 +116,7 @@ def setUp(self) -> None: self.expected_sel_type = [] self.expected_aparam_nall = False self.expected_model_output_type = ["energy", "mask"] + self.model_output_equivariant = [] self.expected_sel = [46, 92, 10] self.expected_sel_mix = sum(self.expected_sel) self.expected_has_message_passing = False @@ -129,3 +134,31 @@ def setUp(self) -> None: "sw_rmin": 0.2, "sw_rmax": 4.0, } + + +class SpinEnerModelTest(ModelTestCase): + def setUp(self) -> None: + self.expected_rcut = 4.0 + self.expected_type_map = ["Ni", "O"] + self.expected_dim_fparam = 0 + self.expected_dim_aparam = 0 + self.expected_sel_type = [0, 1, 2, 3] + self.expected_aparam_nall = False + self.expected_model_output_type = ["energy", "mask"] + self.model_output_equivariant = [] + self.expected_sel = [46, 92] + self.expected_sel_mix = sum(self.expected_sel) + self.expected_has_message_passing = False + self.aprec_dict = {} + self.rprec_dict = {} + self.epsilon_dict = {} + self.spin_dict = { + "use_spin": [True, False], + "virtual_scale": [0.3140], + } + self.input_dict_ft = { + "ntypes": len(self.expected_type_map), + "type_map": self.expected_type_map, + "seed": GLOBAL_SEED, + } + self.test_spin = True diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index 754e708348..312efc2dc9 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -12,6 +12,9 @@ import numpy as np +from deepmd.dpmodel.output_def import ( + check_deriv, +) from deepmd.dpmodel.utils.nlist import ( extend_input_and_build_neighbor_list, ) @@ -38,6 +41,8 @@ class ModelTestCase: """Expected shape of atomic parameters.""" expected_model_output_type: List[str] """Expected output type for the model.""" + model_output_equivariant: List[str] + """Outputs that are equivariant to the input rotation.""" expected_sel: List[int] """Expected number of neighbors.""" expected_has_message_passing: bool @@ -108,34 +113,60 @@ def test_has_message_passing(self): def test_forward(self): """Test forward and forward_lower.""" + test_spin = getattr(self, "test_spin", False) nf = 1 - coord = np.array( - [ - [0, 0, 0], - [0, 1, 0], - [0, 0, 1], - ], - dtype=np.float64, - ).reshape([nf, -1]) - atype = np.array([0, 0, 1], dtype=int).reshape([nf, -1]) + natoms = 5 + rng = np.random.default_rng(GLOBAL_SEED) + coord = 4.0 * rng.random([natoms, 3]).reshape([nf, -1]) + atype = np.array([0, 0, 0, 1, 1], dtype=int).reshape([nf, -1]) + spin = 0.5 * rng.random([natoms, 3]).reshape([nf, -1]) cell = 6.0 * np.eye(3).reshape([nf, 9]) coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( coord, atype, - self.expected_rcut, + self.expected_rcut + 1.0 if test_spin else self.expected_rcut, self.expected_sel, - mixed_types=True, + mixed_types=self.module.mixed_types(), box=cell, ) + spin_ext = np.take_along_axis( + spin.reshape(nf, -1, 3), + np.repeat(np.expand_dims(mapping, axis=-1), 3, axis=-1), + axis=1, + ) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) ret = [] ret_lower = [] for module in self.modules_to_test: module = self.forward_wrapper(module) - ret.append(module(coord, atype, cell)) - - ret_lower.append( - module.forward_lower(coord_ext, atype_ext, nlist, mapping=mapping) - ) + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + ret.append(module(**input_dict)) + + input_dict_lower = { + "extended_coord": coord_ext, + "extended_atype": atype_ext, + "nlist": nlist, + "mapping": mapping, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict_lower["extended_spin"] = spin_ext + + ret_lower.append(module.forward_lower(**input_dict_lower)) for kk in ret[0]: subret = [] for rr in ret: @@ -182,31 +213,64 @@ def test_forward(self): def test_permutation(self): """Test permutation.""" if getattr(self, "skip_test_permutation", False): - return + self.skipTest("Skip test permutation.") + test_spin = getattr(self, "test_spin", False) rng = np.random.default_rng(GLOBAL_SEED) natoms = 5 nf = 1 + aprec = ( + 0 + if self.aprec_dict.get("test_permutation", None) is None + else self.aprec_dict["test_permutation"] + ) + idx = [0, 1, 2, 3, 4] idx_perm = [1, 0, 4, 3, 2] cell = rng.random([3, 3]) cell = (cell + cell.T) + 5.0 * np.eye(3) coord = rng.random([natoms, 3]) coord = np.matmul(coord, cell) + spin = 0.1 * rng.random([natoms, 3]) atype = np.array([0, 0, 0, 1, 1]) coord_perm = coord[idx_perm] + spin_perm = spin[idx_perm] atype_perm = atype[idx_perm] # reshape for input coord = coord.reshape([nf, -1]) coord_perm = coord_perm.reshape([nf, -1]) + spin_perm = spin_perm.reshape([nf, -1]) atype = atype.reshape([nf, -1]) atype_perm = atype_perm.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + aparam_perm = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + aparam_perm = aparam[:, idx_perm, :] + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) - ret.append(module(coord, atype, cell)) + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + ret.append(module(**input_dict)) # permutation - ret.append(module(coord_perm, atype_perm, cell)) + input_dict["coord"] = coord_perm + input_dict["atype"] = atype_perm + input_dict["aparam"] = aparam_perm + if test_spin: + input_dict["spin"] = spin_perm + ret.append(module(**input_dict)) for kk in ret[0]: if kk in self.output_def: @@ -217,14 +281,16 @@ def test_permutation(self): if atomic: np.testing.assert_allclose( ret[0][kk][:, idx_perm], - ret[1][kk], + ret[1][kk][:, idx], # for extended output err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: np.testing.assert_allclose( ret[0][kk], ret[1][kk], err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: raise RuntimeError(f"Unknown output key: {kk}") @@ -232,14 +298,21 @@ def test_permutation(self): def test_trans(self): """Test translation.""" if getattr(self, "skip_test_trans", False): - return + self.skipTest("Skip test translation.") + test_spin = getattr(self, "test_spin", False) rng = np.random.default_rng(GLOBAL_SEED) natoms = 5 nf = 1 + aprec = ( + 0 + if self.aprec_dict.get("test_rot", None) is None + else self.aprec_dict["test_rot"] + ) cell = rng.random([3, 3]) cell = (cell + cell.T) + 5.0 * np.eye(3) coord = rng.random([natoms, 3]) coord = np.matmul(coord, cell) + spin = 0.1 * rng.random([natoms, 3]) atype = np.array([0, 0, 0, 1, 1]) shift = (rng.random([3]) - 0.5) * 2.0 coord_s = np.matmul( @@ -248,15 +321,33 @@ def test_trans(self): # reshape for input coord = coord.reshape([nf, -1]) + spin = spin.reshape([nf, -1]) coord_s = coord_s.reshape([nf, -1]) atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) - ret.append(module(coord, atype, cell)) + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + ret.append(module(**input_dict)) # translation - ret.append(module(coord_s, atype, cell)) + input_dict["coord"] = coord_s + ret.append(module(**input_dict)) for kk in ret[0]: if kk in self.output_def: @@ -267,6 +358,7 @@ def test_trans(self): ret[0][kk], ret[1][kk], err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: raise RuntimeError(f"Unknown output key: {kk}") @@ -274,14 +366,20 @@ def test_trans(self): def test_rot(self): """Test rotation.""" if getattr(self, "skip_test_rot", False): - return + self.skipTest("Skip test rotation.") + test_spin = getattr(self, "test_spin", False) rng = np.random.default_rng(GLOBAL_SEED) natoms = 5 nf = 1 - + aprec = ( + 0 + if self.aprec_dict.get("test_rot", None) is None + else self.aprec_dict["test_rot"] + ) # rotate only coord and shift to the center of cell cell = 10.0 * np.eye(3) coord = 2.0 * rng.random([natoms, 3]) + spin = 0.1 * rng.random([natoms, 3]) atype = np.array([0, 0, 0, 1, 1]) shift = np.array([4.0, 4.0, 4.0]) from scipy.stats import ( @@ -290,30 +388,56 @@ def test_rot(self): rmat = special_ortho_group.rvs(3) coord_rot = np.matmul(coord, rmat) + spin_rot = np.matmul(spin, rmat) # reshape for input coord = (coord + shift).reshape([nf, -1]) + spin = spin.reshape([nf, -1]) coord_rot = (coord_rot + shift).reshape([nf, -1]) + spin_rot = spin_rot.reshape([nf, -1]) atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) - ret.append(module(coord, atype, cell)) + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + ret.append(module(**input_dict)) # rotation - ret.append(module(coord_rot, atype, cell)) + input_dict["coord"] = coord_rot + if test_spin: + input_dict["spin"] = spin_rot + ret.append(module(**input_dict)) for kk in ret[0]: if kk in self.output_def: if ret[0][kk] is None: assert ret[1][kk] is None continue - rot_invariant = self.output_def[kk].rot_invariant - if rot_invariant: + rot_equivariant = ( + check_deriv(self.output_def[kk]) + or kk in self.model_output_equivariant + ) + if not rot_equivariant: np.testing.assert_allclose( ret[0][kk], ret[1][kk], err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: v_size = self.output_def[kk].size @@ -339,6 +463,7 @@ def test_rot(self): rotated_ret_0, ret_1, err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: raise RuntimeError(f"Unknown output key: {kk}") @@ -348,34 +473,55 @@ def test_rot(self): cell = (cell + cell.T) + 5.0 * np.eye(3) coord = rng.random([natoms, 3]) coord = np.matmul(coord, cell) + spin = 0.1 * rng.random([natoms, 3]) atype = np.array([0, 0, 0, 1, 1]) coord_rot = np.matmul(coord, rmat) cell_rot = np.matmul(cell, rmat) + spin_rot = np.matmul(spin, rmat) # reshape for input coord = coord.reshape([nf, -1]) + spin = spin.reshape([nf, -1]) coord_rot = coord_rot.reshape([nf, -1]) + spin_rot = spin_rot.reshape([nf, -1]) atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) cell_rot = cell_rot.reshape([nf, 9]) ret = [] module = self.forward_wrapper(self.module) - ret.append(module(coord, atype, cell)) + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + ret.append(module(**input_dict)) # rotation - ret.append(module(coord_rot, atype, cell_rot)) + input_dict["coord"] = coord_rot + input_dict["box"] = cell_rot + if test_spin: + input_dict["spin"] = spin_rot + ret.append(module(**input_dict)) for kk in ret[0]: if kk in self.output_def: if ret[0][kk] is None: assert ret[1][kk] is None continue - rot_invariant = self.output_def[kk].rot_invariant - if rot_invariant: + rot_equivariant = ( + check_deriv(self.output_def[kk]) + or kk in self.model_output_equivariant + ) + if not rot_equivariant: np.testing.assert_allclose( ret[0][kk], ret[1][kk], err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: v_size = self.output_def[kk].size @@ -401,6 +547,7 @@ def test_rot(self): rotated_ret_0, ret_1, err_msg=f"compare {kk} before and after transform", + atol=aprec, ) else: raise RuntimeError(f"Unknown output key: {kk}") @@ -408,7 +555,8 @@ def test_rot(self): def test_smooth(self): """Test smooth.""" if getattr(self, "skip_test_smooth", False): - return + self.skipTest("Skip test smooth.") + test_spin = getattr(self, "test_spin", False) rng = np.random.default_rng(GLOBAL_SEED) epsilon = ( 1e-5 @@ -432,6 +580,7 @@ def test_smooth(self): atype0 = np.arange(2) atype1 = rng.integers(0, 2, size=natoms - 2) atype = np.concatenate([atype0, atype1]).reshape(natoms) + spin = 0.1 * rng.random([natoms, 3]) coord0 = np.array( [ 0.0, @@ -463,19 +612,34 @@ def test_smooth(self): coord1 = coord1.reshape([nf, -1]) coord2 = coord2.reshape([nf, -1]) coord3 = coord3.reshape([nf, -1]) + spin = spin.reshape([nf, -1]) atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] module = self.forward_wrapper(self.module) + input_dict = {"atype": atype, "box": cell, "aparam": aparam, "fparam": fparam} + if test_spin: + input_dict["spin"] = spin # coord0 - ret.append(module(coord0, atype, cell)) + input_dict["coord"] = coord0 + ret.append(module(**input_dict)) # coord1 - ret.append(module(coord1, atype, cell)) + input_dict["coord"] = coord1 + ret.append(module(**input_dict)) # coord2 - ret.append(module(coord2, atype, cell)) + input_dict["coord"] = coord2 + ret.append(module(**input_dict)) # coord3 - ret.append(module(coord3, atype, cell)) + input_dict["coord"] = coord3 + ret.append(module(**input_dict)) for kk in ret[0]: if kk in self.output_def: @@ -497,7 +661,8 @@ def test_smooth(self): def test_autodiff(self): """Test autodiff.""" if getattr(self, "skip_test_autodiff", False): - return + self.skipTest("Skip test autodiff.") + test_spin = getattr(self, "test_spin", False) places = 4 delta = 1e-5 @@ -529,38 +694,105 @@ def stretch_box(old_coord, old_box, new_box): cell = (cell + cell.T) + 5.0 * np.eye(3) coord = rng.random([natoms, 3]) coord = np.matmul(coord, cell) + spin = 0.1 * rng.random([natoms, 3]) atype = np.array([0, 0, 0, 1, 1]) # reshape for input coord = coord.reshape([nf, -1]) + spin = spin.reshape([nf, -1]) atype = atype.reshape([nf, -1]) cell = cell.reshape([nf, 9]) + + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + module = self.forward_wrapper(self.module) # only test force and virial for energy model def ff_coord(_coord): - return module(_coord, atype, cell)["energy"] + input_dict = { + "coord": _coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + return module(**input_dict)["energy"] + + def ff_spin(_spin): + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = _spin + return module(**input_dict)["energy"] fdf = -finite_difference(ff_coord, coord, delta=delta).squeeze() - rff = module(coord, atype, cell)["force"] + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + rff = module(**input_dict)["force"] np.testing.assert_almost_equal( fdf.reshape(-1, 3), rff.reshape(-1, 3), decimal=places ) - def ff_cell(bb): - return module(stretch_box(coord, cell, bb), atype, bb)["energy"] + if test_spin: + # magnetic force + fdf = -finite_difference(ff_spin, spin, delta=delta).squeeze() + rff = module(**input_dict)["force_mag"] + np.testing.assert_almost_equal( + fdf.reshape(-1, 3), rff.reshape(-1, 3), decimal=places + ) - fdv = ( - -( - finite_difference(ff_cell, cell, delta=delta) - .reshape(-1, 3, 3) - .transpose(0, 2, 1) - @ cell.reshape(-1, 3, 3) + if not test_spin: + + def ff_cell(bb): + input_dict = { + "coord": stretch_box(coord, cell, bb), + "atype": atype, + "box": bb, + "aparam": aparam, + "fparam": fparam, + } + return module(**input_dict)["energy"] + + fdv = ( + -( + finite_difference(ff_cell, cell, delta=delta) + .reshape(-1, 3, 3) + .transpose(0, 2, 1) + @ cell.reshape(-1, 3, 3) + ) + .squeeze() + .reshape(9) ) - .squeeze() - .reshape(9) - ) - rfv = module(stretch_box(coord, cell, cell), atype, cell)["virial"] - np.testing.assert_almost_equal( - fdv.reshape(-1, 9), rfv.reshape(-1, 9), decimal=places - ) + input_dict = { + "coord": stretch_box(coord, cell, cell), + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + rfv = module(**input_dict)["virial"] + np.testing.assert_almost_equal( + fdv.reshape(-1, 9), rfv.reshape(-1, 9), decimal=places + ) + else: + # not support virial by far + pass diff --git a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py index 877bff19f5..589e2dda59 100644 --- a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py +++ b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py @@ -31,35 +31,48 @@ PolarAtomicModelTest, ZBLAtomicModelTest, ) +from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1List, + DescriptorParamDPA2List, + DescriptorParamHybrid, + DescriptorParamHybridMixed, + DescriptorParamSeAList, + DescriptorParamSeRList, + DescriptorParamSeTList, +) +from ...dpmodel.model.test_model import ( + skip_model_tests, +) from ..backend import ( DPTestCase, ) -from ..descriptor.test_descriptor import ( - DescriptorParamDPA1, - DescriptorParamDPA2, - DescriptorParamHybrid, - DescriptorParamHybridMixed, - DescriptorParamSeA, - DescriptorParamSeR, - DescriptorParamSeT, +from ..fitting.test_fitting import ( + FittingParamDipoleList, + FittingParamDosList, + FittingParamEnergyList, + FittingParamPolarList, ) @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestEnergyAtomicModelDP(unittest.TestCase, EnerAtomicModelTest, DPTestCase): def setUp(self): EnerAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -70,11 +83,19 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -83,23 +104,30 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], + ), # fitting_class_param & class ) class TestDosAtomicModelDP(unittest.TestCase, DosAtomicModelTest, DPTestCase): def setUp(self): DosAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision self.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: @@ -111,11 +139,19 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = DOSFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -124,21 +160,28 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, DipoleFitting) for param_func in FittingParamDipoleList], + ), # fitting_class_param & class ) class TestDipoleAtomicModelDP(unittest.TestCase, DipoleAtomicModelTest, DPTestCase): def setUp(self): DipoleAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -149,12 +192,20 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = DipoleFitting( - **self.input_dict_ft, - embedding_width=ds.get_dim_emb(), + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + embedding_width=ds.get_dim_emb(), + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -163,21 +214,28 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, PolarFitting) for param_func in FittingParamPolarList], + ), # fitting_class_param & class ) class TestPolarAtomicModelDP(unittest.TestCase, PolarAtomicModelTest, DPTestCase): def setUp(self): PolarAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -188,12 +246,20 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = PolarFitting( - **self.input_dict_ft, - embedding_width=ds.get_dim_emb(), + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + embedding_width=ds.get_dim_emb(), + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -202,19 +268,26 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestZBLAtomicModelDP(unittest.TestCase, ZBLAtomicModelTest, DPTestCase): def setUp(self): ZBLAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision # zbl weights not so smooth self.aprec_dict["test_smooth"] = 5e-2 @@ -225,11 +298,19 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) dp_model = DPAtomicModel( ds, @@ -252,3 +333,5 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() diff --git a/source/tests/universal/dpmodel/descriptor/test_descriptor.py b/source/tests/universal/dpmodel/descriptor/test_descriptor.py index 076adc8a31..6ef92d28d7 100644 --- a/source/tests/universal/dpmodel/descriptor/test_descriptor.py +++ b/source/tests/universal/dpmodel/descriptor/test_descriptor.py @@ -1,5 +1,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-later import unittest +from collections import ( + OrderedDict, +) from deepmd.dpmodel.descriptor import ( DescrptDPA1, @@ -9,8 +12,13 @@ DescrptSeR, DescrptSeT, ) +from deepmd.dpmodel.descriptor.dpa2 import ( + RepformerArgs, + RepinitArgs, +) from ....consistent.common import ( + parameterize_func, parameterized, ) from ....seed import ( @@ -24,7 +32,18 @@ ) -def DescriptorParamSeA(ntypes, rcut, rcut_smth, sel, type_map): +def DescriptorParamSeA( + ntypes, + rcut, + rcut_smth, + sel, + type_map, + env_protection=0.0, + exclude_types=[], + resnet_dt=False, + type_one_side=True, + precision="float64", +): input_dict = { "ntypes": ntypes, "rcut": rcut, @@ -32,11 +51,41 @@ def DescriptorParamSeA(ntypes, rcut, rcut_smth, sel, type_map): "sel": sel, "type_map": type_map, "seed": GLOBAL_SEED, + "env_protection": env_protection, + "resnet_dt": resnet_dt, + "type_one_side": type_one_side, + "exclude_types": exclude_types, + "precision": precision, } return input_dict -def DescriptorParamSeR(ntypes, rcut, rcut_smth, sel, type_map): +DescriptorParamSeAList = parameterize_func( + DescriptorParamSeA, + OrderedDict( + { + "resnet_dt": (True, False), + "type_one_side": (True, False), + "exclude_types": ([], [[0, 1]]), + "env_protection": (0.0, 1e-8, 1e-2), + "precision": ("float64",), + } + ), +) + + +def DescriptorParamSeR( + ntypes, + rcut, + rcut_smth, + sel, + type_map, + env_protection=0.0, + exclude_types=[], + resnet_dt=False, + type_one_side=True, + precision="float64", +): input_dict = { "ntypes": ntypes, "rcut": rcut, @@ -44,11 +93,40 @@ def DescriptorParamSeR(ntypes, rcut, rcut_smth, sel, type_map): "sel": sel, "type_map": type_map, "seed": GLOBAL_SEED, + "env_protection": env_protection, + "resnet_dt": resnet_dt, + "type_one_side": type_one_side, + "exclude_types": exclude_types, + "precision": precision, } return input_dict -def DescriptorParamSeT(ntypes, rcut, rcut_smth, sel, type_map): +DescriptorParamSeRList = parameterize_func( + DescriptorParamSeR, + OrderedDict( + { + "resnet_dt": (True, False), + "type_one_side": (True,), # type_one_side == False not implemented + "exclude_types": ([], [[0, 1]]), + "env_protection": (0.0, 1e-8), + "precision": ("float64",), + } + ), +) + + +def DescriptorParamSeT( + ntypes, + rcut, + rcut_smth, + sel, + type_map, + env_protection=0.0, + exclude_types=[], + resnet_dt=False, + precision="float64", +): input_dict = { "ntypes": ntypes, "rcut": rcut, @@ -56,11 +134,52 @@ def DescriptorParamSeT(ntypes, rcut, rcut_smth, sel, type_map): "sel": sel, "type_map": type_map, "seed": GLOBAL_SEED, + "env_protection": env_protection, + "resnet_dt": resnet_dt, + "exclude_types": exclude_types, + "precision": precision, } return input_dict -def DescriptorParamDPA1(ntypes, rcut, rcut_smth, sel, type_map): +DescriptorParamSeTList = parameterize_func( + DescriptorParamSeT, + OrderedDict( + { + "resnet_dt": (True, False), + "exclude_types": ([], [[0, 1]]), + "env_protection": (0.0, 1e-8), + "precision": ("float64",), + } + ), +) + + +def DescriptorParamDPA1( + ntypes, + rcut, + rcut_smth, + sel, + type_map, + env_protection=0.0, + exclude_types=[], + tebd_dim=4, + tebd_input_mode="concat", + attn=20, + attn_layer=2, + attn_dotr=True, + scaling_factor=1.0, + normalize=True, + temperature=None, + ln_eps=1e-5, + concat_output_tebd=True, + resnet_dt=True, + type_one_side=True, + set_davg_zero=True, + smooth_type_embedding=True, + use_econf_tebd=False, + precision="float64", +): input_dict = { "ntypes": ntypes, "rcut": rcut, @@ -68,47 +187,189 @@ def DescriptorParamDPA1(ntypes, rcut, rcut_smth, sel, type_map): "sel": sel, "type_map": type_map, "seed": GLOBAL_SEED, + "tebd_dim": tebd_dim, + "tebd_input_mode": tebd_input_mode, + "attn": attn, + "attn_layer": attn_layer, + "attn_dotr": attn_dotr, + "attn_mask": False, + "scaling_factor": scaling_factor, + "normalize": normalize, + "temperature": temperature, + "ln_eps": ln_eps, + "concat_output_tebd": concat_output_tebd, + "resnet_dt": resnet_dt, + "type_one_side": type_one_side, + "exclude_types": exclude_types, + "env_protection": env_protection, + "set_davg_zero": set_davg_zero, + "smooth_type_embedding": smooth_type_embedding, + "use_econf_tebd": use_econf_tebd, + "precision": precision, } return input_dict -def DescriptorParamDPA2(ntypes, rcut, rcut_smth, sel, type_map): +DescriptorParamDPA1List = parameterize_func( + DescriptorParamDPA1, + OrderedDict( + { + "tebd_dim": (4,), + "tebd_input_mode": ("concat", "strip"), + "resnet_dt": (True,), + "type_one_side": (False,), + "attn": (20,), + "attn_layer": (0, 2), + "attn_dotr": (True,), + "exclude_types": ([], [[0, 1]]), + "env_protection": (0.0,), + "set_davg_zero": (False,), + "scaling_factor": (1.0,), + "normalize": (True,), + "temperature": (None, 1.0), + "ln_eps": (1e-5,), + "smooth_type_embedding": (True, False), + "concat_output_tebd": (True,), + "use_econf_tebd": (True, False), + "precision": ("float64",), + } + ), +) + + +def DescriptorParamDPA2( + ntypes, + rcut, + rcut_smth, + sel, + type_map, + repinit_tebd_input_mode="concat", + repinit_set_davg_zero=False, + repinit_type_one_side=False, + repformer_direct_dist=False, + repformer_update_g1_has_conv=True, + repformer_update_g1_has_drrd=True, + repformer_update_g1_has_grrg=True, + repformer_update_g1_has_attn=True, + repformer_update_g2_has_g1g1=True, + repformer_update_g2_has_attn=True, + repformer_update_h2=False, + repformer_attn2_has_gate=True, + repformer_update_style="res_avg", + repformer_update_residual_init="norm", + repformer_set_davg_zero=False, + repformer_trainable_ln=True, + repformer_ln_eps=1e-5, + smooth=True, + add_tebd_to_repinit_out=True, + use_econf_tebd=False, + env_protection=0.0, + exclude_types=[], + precision="float64", +): input_dict = { "ntypes": ntypes, - "repinit": { - "rcut": rcut, - "rcut_smth": rcut_smth, - "nsel": sum(sel), - }, - "repformer": { - "rcut": rcut / 2, - "rcut_smth": rcut_smth / 2, - "nsel": sum(sel) // 2, - }, + # kwargs for repinit + "repinit": RepinitArgs( + **{ + "rcut": rcut, + "rcut_smth": rcut_smth, + "nsel": sum(sel), + "neuron": [6, 12, 24], + "axis_neuron": 3, + "tebd_dim": 4, + "tebd_input_mode": repinit_tebd_input_mode, + "set_davg_zero": repinit_set_davg_zero, + "activation_function": "tanh", + "type_one_side": repinit_type_one_side, + } + ), + # kwargs for repformer + "repformer": RepformerArgs( + **{ + "rcut": rcut / 2, + "rcut_smth": rcut_smth / 2, + "nsel": sum(sel) // 2, + "nlayers": 3, + "g1_dim": 20, + "g2_dim": 10, + "axis_neuron": 3, + "direct_dist": repformer_direct_dist, + "update_g1_has_conv": repformer_update_g1_has_conv, + "update_g1_has_drrd": repformer_update_g1_has_drrd, + "update_g1_has_grrg": repformer_update_g1_has_grrg, + "update_g1_has_attn": repformer_update_g1_has_attn, + "update_g2_has_g1g1": repformer_update_g2_has_g1g1, + "update_g2_has_attn": repformer_update_g2_has_attn, + "update_h2": repformer_update_h2, + "attn1_hidden": 12, + "attn1_nhead": 2, + "attn2_hidden": 10, + "attn2_nhead": 2, + "attn2_has_gate": repformer_attn2_has_gate, + "activation_function": "tanh", + "update_style": repformer_update_style, + "update_residual": 0.001, + "update_residual_init": repformer_update_residual_init, + "set_davg_zero": repformer_set_davg_zero, + "trainable_ln": repformer_trainable_ln, + "ln_eps": repformer_ln_eps, + } + ), + # kwargs for descriptor + "concat_output_tebd": True, + "precision": precision, + "smooth": smooth, + "exclude_types": exclude_types, + "env_protection": env_protection, + "trainable": True, + "use_econf_tebd": use_econf_tebd, "type_map": type_map, "seed": GLOBAL_SEED, + "add_tebd_to_repinit_out": add_tebd_to_repinit_out, } return input_dict -def DescriptorParamHybrid(ntypes, rcut, rcut_smth, sel, type_map): +DescriptorParamDPA2List = parameterize_func( + DescriptorParamDPA2, + OrderedDict( + { + "repinit_tebd_input_mode": ("concat", "strip"), + "repinit_set_davg_zero": (True,), + "repinit_type_one_side": (False,), + "repformer_direct_dist": (False,), + "repformer_update_g1_has_conv": (True,), + "repformer_update_g1_has_drrd": (True,), + "repformer_update_g1_has_grrg": (True,), + "repformer_update_g1_has_attn": (True,), + "repformer_update_g2_has_g1g1": (True,), + "repformer_update_g2_has_attn": (True,), + "repformer_update_h2": (False,), + "repformer_attn2_has_gate": (True,), + "repformer_update_style": ("res_avg", "res_residual"), + "repformer_update_residual_init": ("norm",), + "repformer_set_davg_zero": (True,), + "repformer_trainable_ln": (True,), + "repformer_ln_eps": (1e-5,), + "smooth": (True, False), + "exclude_types": ([], [[0, 1]]), + "precision": ("float64",), + "add_tebd_to_repinit_out": (True, False), + "use_econf_tebd": (False,), + } + ), +) + + +def DescriptorParamHybrid(ntypes, rcut, rcut_smth, sel, type_map, **kwargs): ddsub0 = { "type": "se_e2_a", - "ntypes": ntypes, - "rcut": rcut, - "rcut_smth": rcut_smth, - "sel": sel, - "type_map": type_map, - "seed": GLOBAL_SEED, + **DescriptorParamSeA(ntypes, rcut, rcut_smth, sel, type_map, **kwargs), } ddsub1 = { "type": "dpa1", - "ntypes": ntypes, - "rcut": rcut, - "rcut_smth": rcut_smth, - "sel": sum(sel), - "type_map": type_map, - "seed": GLOBAL_SEED, + **DescriptorParamDPA1(ntypes, rcut, rcut_smth, sum(sel), type_map, **kwargs), } input_dict = { "list": [ddsub0, ddsub1], @@ -116,24 +377,14 @@ def DescriptorParamHybrid(ntypes, rcut, rcut_smth, sel, type_map): return input_dict -def DescriptorParamHybridMixed(ntypes, rcut, rcut_smth, sel, type_map): +def DescriptorParamHybridMixed(ntypes, rcut, rcut_smth, sel, type_map, **kwargs): ddsub0 = { "type": "dpa1", - "ntypes": ntypes, - "rcut": rcut, - "rcut_smth": rcut_smth, - "sel": sum(sel), - "type_map": type_map, - "seed": GLOBAL_SEED, + **DescriptorParamDPA1(ntypes, rcut, rcut_smth, sum(sel), type_map, **kwargs), } ddsub1 = { "type": "dpa1", - "ntypes": ntypes, - "rcut": rcut, - "rcut_smth": rcut_smth, - "sel": sum(sel), - "type_map": type_map, - "seed": GLOBAL_SEED, + **DescriptorParamDPA1(ntypes, rcut, rcut_smth, sum(sel), type_map, **kwargs), } input_dict = { "list": [ddsub0, ddsub1], diff --git a/source/tests/universal/dpmodel/fitting/test_fitting.py b/source/tests/universal/dpmodel/fitting/test_fitting.py index 6f780fe636..c20fb1660e 100644 --- a/source/tests/universal/dpmodel/fitting/test_fitting.py +++ b/source/tests/universal/dpmodel/fitting/test_fitting.py @@ -1,5 +1,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-later import unittest +from collections import ( + OrderedDict, +) from deepmd.dpmodel.fitting import ( DipoleFitting, @@ -9,8 +12,12 @@ ) from ....consistent.common import ( + parameterize_func, parameterized, ) +from ....seed import ( + GLOBAL_SEED, +) from ...common.cases.fitting.fitting import ( FittingTest, ) @@ -19,48 +26,156 @@ ) -def FittingParamEnergy(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): +def FittingParamEnergy( + ntypes, + dim_descrpt, + mixed_types, + type_map, + exclude_types=[], + precision="float64", + embedding_width=None, + numb_param=0, # test numb_fparam and numb_aparam together +): input_dict = { "ntypes": ntypes, "dim_descrpt": dim_descrpt, "mixed_types": mixed_types, "type_map": type_map, + "exclude_types": exclude_types, + "seed": GLOBAL_SEED, + "precision": precision, + "numb_fparam": numb_param, + "numb_aparam": numb_param, } return input_dict -def FittingParamDos(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): +FittingParamEnergyList = parameterize_func( + FittingParamEnergy, + OrderedDict( + { + "exclude_types": ([], [0]), + "precision": ("float64",), + "numb_param": (0, 2), + } + ), +) + + +def FittingParamDos( + ntypes, + dim_descrpt, + mixed_types, + type_map, + exclude_types=[], + precision="float64", + embedding_width=None, + numb_param=0, # test numb_fparam and numb_aparam together +): input_dict = { "ntypes": ntypes, "dim_descrpt": dim_descrpt, "mixed_types": mixed_types, "type_map": type_map, + "exclude_types": exclude_types, + "seed": GLOBAL_SEED, + "precision": precision, + "numb_fparam": numb_param, + "numb_aparam": numb_param, } return input_dict -def FittingParamDipole(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): +FittingParamDosList = parameterize_func( + FittingParamDos, + OrderedDict( + { + "exclude_types": ([], [0]), + "precision": ("float64",), + "numb_param": (0, 2), + } + ), +) + + +def FittingParamDipole( + ntypes, + dim_descrpt, + mixed_types, + type_map, + exclude_types=[], + precision="float64", + embedding_width=None, + numb_param=0, # test numb_fparam and numb_aparam together +): + assert ( + embedding_width is not None + ), "embedding_width for dipole fitting is required." input_dict = { "ntypes": ntypes, "dim_descrpt": dim_descrpt, "mixed_types": mixed_types, "embedding_width": embedding_width, "type_map": type_map, + "exclude_types": exclude_types, + "seed": GLOBAL_SEED, + "precision": precision, + "numb_fparam": numb_param, + "numb_aparam": numb_param, } return input_dict -def FittingParamPolar(ntypes, dim_descrpt, mixed_types, embedding_width, type_map): +FittingParamDipoleList = parameterize_func( + FittingParamDipole, + OrderedDict( + { + "exclude_types": ([], [0]), + "precision": ("float64",), + "numb_param": (0, 2), + } + ), +) + + +def FittingParamPolar( + ntypes, + dim_descrpt, + mixed_types, + type_map, + exclude_types=[], + precision="float64", + embedding_width=None, + numb_param=0, # test numb_fparam and numb_aparam together +): + assert embedding_width is not None, "embedding_width for polar fitting is required." input_dict = { "ntypes": ntypes, "dim_descrpt": dim_descrpt, "mixed_types": mixed_types, "embedding_width": embedding_width, "type_map": type_map, + "exclude_types": exclude_types, + "seed": GLOBAL_SEED, + "precision": precision, + "numb_fparam": numb_param, + "numb_aparam": numb_param, } return input_dict +FittingParamPolarList = parameterize_func( + FittingParamPolar, + OrderedDict( + { + "exclude_types": ([], [0]), + "precision": ("float64",), + "numb_param": (0, 2), + } + ), +) + + @parameterized( ( (FittingParamEnergy, EnergyFittingNet), @@ -76,6 +191,10 @@ def setUp(self): FittingTest.setUp(self) self.module_class = Fitting self.input_dict = FittingParam( - self.nt, self.dim_descrpt, self.mixed_types, self.dim_embed, ["O", "H"] + self.nt, + self.dim_descrpt, + self.mixed_types, + ["O", "H"], + embedding_width=self.dim_embed, ) self.module = Fitting(**self.input_dict) diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 9e8ca71ea8..e3067faf16 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -14,6 +14,10 @@ ) from deepmd.dpmodel.model import ( EnergyModel, + SpinModel, +) +from deepmd.utils.spin import ( + Spin, ) from ....consistent.common import ( @@ -21,36 +25,67 @@ ) from ...common.cases.model.model import ( EnerModelTest, + SpinEnerModelTest, ) from ..backend import ( DPTestCase, ) from ..descriptor.test_descriptor import ( - DescriptorParamDPA1, - DescriptorParamDPA2, + DescriptorParamDPA1List, + DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, - DescriptorParamSeA, - DescriptorParamSeR, - DescriptorParamSeT, + DescriptorParamSeAList, + DescriptorParamSeRList, + DescriptorParamSeTList, +) +from ..fitting.test_fitting import ( + FittingParamEnergyList, ) +def skip_model_tests(test_obj): + if not test_obj.input_dict_ds.get( + "smooth_type_embedding", True + ) or not test_obj.input_dict_ds.get("smooth", True): + test_obj.skip_test_smooth = True + test_obj.skip_test_autodiff = True + if hasattr(test_obj, "spin_dict") and test_obj.input_dict_ds.get( + "use_econf_tebd", False + ): + return True, "Spin model do not support electronic configuration type embedding" + if ( + "attn_layer" in test_obj.input_dict_ds + and test_obj.input_dict_ds["attn_layer"] == 0 + and ( + test_obj.input_dict_ds["attn_dotr"] + or test_obj.input_dict_ds["normalize"] + or test_obj.input_dict_ds["temperature"] is not None + ) + ): + return True, "Meaningless for zero attention test in DPA1." + return False, None + + @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestEnergyModelDP(unittest.TestCase, EnerModelTest, DPTestCase): def setUp(self): EnerModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -61,11 +96,22 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = EnergyModel( ds, @@ -74,4 +120,86 @@ def setUp(self): ) self.output_def = self.module.model_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() + self.skip_test_autodiff = True + + +@parameterized( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + # (DescriptorParamHybrid, DescrptHybrid), + # unsupported for SpinModel to hybrid both mixed_types and no-mixed_types descriptor + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class +) +class TestSpinEnergyModelDP(unittest.TestCase, SpinEnerModelTest, DPTestCase): + def setUp(self): + SpinEnerModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] + self.epsilon_dict["test_smooth"] = 1e-6 + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + + spin = Spin( + use_spin=self.spin_dict["use_spin"], + virtual_scale=self.spin_dict["virtual_scale"], + ) + spin_type_map = self.expected_type_map + [ + item + "_spin" for item in self.expected_type_map + ] + if Descrpt in [DescrptSeA, DescrptSeR, DescrptSeT]: + spin_sel = self.expected_sel + self.expected_sel + else: + spin_sel = self.expected_sel + pair_exclude_types = spin.get_pair_exclude_types() + atom_exclude_types = spin.get_atom_exclude_types() + self.input_dict_ds = DescriptorParam( + len(spin_type_map), + self.expected_rcut, + self.expected_rcut / 2, + spin_sel, + spin_type_map, + env_protection=1e-6, + exclude_types=pair_exclude_types, + ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + + ds = Descrpt(**self.input_dict_ds) + self.input_dict_ft = FittingParam( + ntypes=len(spin_type_map), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + type_map=spin_type_map, + ) + ft = Fitting( + **self.input_dict_ft, + ) + backbone_model = EnergyModel( + ds, + ft, + type_map=spin_type_map, + atom_exclude_types=atom_exclude_types, + pair_exclude_types=pair_exclude_types, + ) + self.module = SpinModel(backbone_model=backbone_model, spin=spin) + self.output_def = self.module.model_output_def().get_data() + self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() self.skip_test_autodiff = True diff --git a/source/tests/universal/pt/atomc_model/test_atomic_model.py b/source/tests/universal/pt/atomc_model/test_atomic_model.py index 6218fc6b42..b82eb96984 100644 --- a/source/tests/universal/pt/atomc_model/test_atomic_model.py +++ b/source/tests/universal/pt/atomc_model/test_atomic_model.py @@ -31,35 +31,48 @@ PolarAtomicModelTest, ZBLAtomicModelTest, ) -from ..backend import ( - PTTestCase, -) -from ..descriptor.test_descriptor import ( - DescriptorParamDPA1, - DescriptorParamDPA2, +from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1List, + DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, - DescriptorParamSeA, - DescriptorParamSeR, - DescriptorParamSeT, + DescriptorParamSeAList, + DescriptorParamSeRList, + DescriptorParamSeTList, +) +from ...dpmodel.fitting.test_fitting import ( + FittingParamDipoleList, + FittingParamDosList, + FittingParamEnergyList, + FittingParamPolarList, +) +from ...dpmodel.model.test_model import ( + skip_model_tests, +) +from ..backend import ( + PTTestCase, ) @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestEnergyAtomicModelPT(unittest.TestCase, EnerAtomicModelTest, PTTestCase): def setUp(self): EnerAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -70,11 +83,19 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -83,23 +104,30 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], + ), # fitting_class_param & class ) class TestDosAtomicModelPT(unittest.TestCase, DosAtomicModelTest, PTTestCase): def setUp(self): DosAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision self.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: @@ -111,11 +139,19 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = DOSFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -124,21 +160,28 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, DipoleFittingNet) for param_func in FittingParamDipoleList], + ), # fitting_class_param & class ) class TestDipoleAtomicModelPT(unittest.TestCase, DipoleAtomicModelTest, PTTestCase): def setUp(self): DipoleAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -149,12 +192,20 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = DipoleFittingNet( - **self.input_dict_ft, - embedding_width=ds.get_dim_emb(), + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + embedding_width=ds.get_dim_emb(), + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -163,21 +214,28 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, PolarFittingNet) for param_func in FittingParamPolarList], + ), # fitting_class_param & class ) class TestPolarAtomicModelPT(unittest.TestCase, PolarAtomicModelTest, PTTestCase): def setUp(self): PolarAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -188,12 +246,20 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = PolarFittingNet( - **self.input_dict_ft, - embedding_width=ds.get_dim_emb(), + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + embedding_width=ds.get_dim_emb(), + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DPAtomicModel( ds, @@ -202,19 +268,26 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestZBLAtomicModelPT(unittest.TestCase, ZBLAtomicModelTest, PTTestCase): def setUp(self): ZBLAtomicModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision # zbl weights not so smooth self.aprec_dict["test_smooth"] = 5e-2 @@ -225,11 +298,19 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) dp_model = DPAtomicModel( ds, @@ -252,3 +333,5 @@ def setUp(self): ) self.output_def = self.module.atomic_output_def().get_data() self.expected_has_message_passing = ds.has_message_passing() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() diff --git a/source/tests/universal/pt/fitting/test_fitting.py b/source/tests/universal/pt/fitting/test_fitting.py index 6551f49de6..eb16e74fe3 100644 --- a/source/tests/universal/pt/fitting/test_fitting.py +++ b/source/tests/universal/pt/fitting/test_fitting.py @@ -40,6 +40,10 @@ def setUp(self): FittingTest.setUp(self) self.module_class = Fitting self.input_dict = FittingParam( - self.nt, self.dim_descrpt, self.mixed_types, self.dim_embed, ["O", "H"] + self.nt, + self.dim_descrpt, + self.mixed_types, + ["O", "H"], + embedding_width=self.dim_embed, ) self.module = Fitting(**self.input_dict) diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py index 336bb9ad40..a5e80eb066 100644 --- a/source/tests/universal/pt/model/test_model.py +++ b/source/tests/universal/pt/model/test_model.py @@ -19,6 +19,7 @@ DPZBLModel, EnergyModel, PolarModel, + SpinEnergyModel, ) from deepmd.pt.model.task import ( DipoleFittingNet, @@ -26,6 +27,9 @@ EnergyFittingNet, PolarFittingNet, ) +from deepmd.utils.spin import ( + Spin, +) from ....consistent.common import ( parameterized, @@ -35,32 +39,45 @@ DosModelTest, EnerModelTest, PolarModelTest, + SpinEnerModelTest, ZBLModelTest, ) -from ..backend import ( - PTTestCase, -) -from ..descriptor.test_descriptor import ( - DescriptorParamDPA1, - DescriptorParamDPA2, +from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1List, + DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, - DescriptorParamSeA, - DescriptorParamSeR, - DescriptorParamSeT, + DescriptorParamSeAList, + DescriptorParamSeRList, + DescriptorParamSeTList, +) +from ...dpmodel.fitting.test_fitting import ( + FittingParamDipoleList, + FittingParamDosList, + FittingParamEnergyList, + FittingParamPolarList, +) +from ...dpmodel.model.test_model import ( + skip_model_tests, +) +from ..backend import ( + PTTestCase, ) @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestEnergyModelPT(unittest.TestCase, EnerModelTest, PTTestCase): # @property @@ -75,6 +92,7 @@ class TestEnergyModelPT(unittest.TestCase, EnerModelTest, PTTestCase): def setUp(self): EnerModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -85,11 +103,21 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = EnergyModel( ds, @@ -98,18 +126,24 @@ def setUp(self): ) self.output_def = self.module.translated_output_def() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamSeR, DescrptSeR), - (DescriptorParamSeT, DescrptSeT), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], + ), # fitting_class_param & class ) class TestDosModelPT(unittest.TestCase, DosModelTest, PTTestCase): # @property @@ -124,6 +158,7 @@ class TestDosModelPT(unittest.TestCase, DosModelTest, PTTestCase): def setUp(self): DosModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision self.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: @@ -135,11 +170,21 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + ds = Descrpt(**self.input_dict_ds) - ft = DOSFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DOSModel( ds, @@ -148,16 +193,22 @@ def setUp(self): ) self.output_def = self.module.translated_output_def() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, DipoleFittingNet) for param_func in FittingParamDipoleList], + ), # fitting_class_param & class ) class TestDipoleModelPT(unittest.TestCase, DipoleModelTest, PTTestCase): # @property @@ -172,9 +223,13 @@ class TestDipoleModelPT(unittest.TestCase, DipoleModelTest, PTTestCase): def setUp(self): DipoleModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 + self.aprec_dict["test_rot"] = 1e-10 # for dipole force when near zero + self.aprec_dict["test_trans"] = 1e-10 # for dipole force when near zero + self.aprec_dict["test_permutation"] = 1e-10 # for dipole force when near zero self.input_dict_ds = DescriptorParam( len(self.expected_type_map), self.expected_rcut, @@ -182,12 +237,22 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + ds = Descrpt(**self.input_dict_ds) - ft = DipoleFittingNet( - **self.input_dict_ft, - embedding_width=ds.get_dim_emb(), + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + embedding_width=ds.get_dim_emb(), + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = DipoleModel( ds, @@ -196,16 +261,22 @@ def setUp(self): ) self.output_def = self.module.translated_output_def() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamSeA, DescrptSeA), - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybrid, DescrptHybrid), (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, PolarFittingNet) for param_func in FittingParamPolarList], + ), # fitting_class_param & class ) class TestPolarModelPT(unittest.TestCase, PolarModelTest, PTTestCase): # @property @@ -220,6 +291,7 @@ class TestPolarModelPT(unittest.TestCase, PolarModelTest, PTTestCase): def setUp(self): PolarModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 @@ -230,12 +302,22 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + ds = Descrpt(**self.input_dict_ds) - ft = PolarFittingNet( - **self.input_dict_ft, - embedding_width=ds.get_dim_emb(), + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + embedding_width=ds.get_dim_emb(), + ) + ft = Fitting( + **self.input_dict_ft, ) self.module = PolarModel( ds, @@ -244,19 +326,26 @@ def setUp(self): ) self.output_def = self.module.translated_output_def() self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() @parameterized( ( - (DescriptorParamDPA1, DescrptDPA1), - (DescriptorParamDPA2, DescrptDPA2), + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], (DescriptorParamHybridMixed, DescrptHybrid), - ) # class_param & class + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class ) class TestZBLModelPT(unittest.TestCase, ZBLModelTest, PTTestCase): def setUp(self): ZBLModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] # set special precision # zbl weights not so smooth self.aprec_dict["test_smooth"] = 5e-2 @@ -267,11 +356,21 @@ def setUp(self): self.expected_sel, self.expected_type_map, ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + ds = Descrpt(**self.input_dict_ds) - ft = EnergyFittingNet( - **self.input_dict_ft, + self.input_dict_ft = FittingParam( + ntypes=len(self.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), + type_map=self.expected_type_map, + ) + ft = Fitting( + **self.input_dict_ft, ) dp_model = DPAtomicModel( ds, @@ -294,3 +393,82 @@ def setUp(self): ) self.output_def = self.module.translated_output_def() self.expected_has_message_passing = ds.has_message_passing() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() + + +@parameterized( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + # (DescriptorParamHybrid, DescrptHybrid), + # unsupported for SpinModel to hybrid both mixed_types and no-mixed_types descriptor + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class +) +class TestSpinEnergyModelDP(unittest.TestCase, SpinEnerModelTest, PTTestCase): + def setUp(self): + SpinEnerModelTest.setUp(self) + (DescriptorParam, Descrpt) = self.param[0] + (FittingParam, Fitting) = self.param[1] + # set special precision + if Descrpt in [DescrptDPA2]: + self.epsilon_dict["test_smooth"] = 1e-8 + + spin = Spin( + use_spin=self.spin_dict["use_spin"], + virtual_scale=self.spin_dict["virtual_scale"], + ) + spin_type_map = self.expected_type_map + [ + item + "_spin" for item in self.expected_type_map + ] + if Descrpt in [DescrptSeA, DescrptSeR, DescrptSeT]: + spin_sel = self.expected_sel + self.expected_sel + else: + spin_sel = self.expected_sel + pair_exclude_types = spin.get_pair_exclude_types() + atom_exclude_types = spin.get_atom_exclude_types() + self.input_dict_ds = DescriptorParam( + len(spin_type_map), + self.expected_rcut, + self.expected_rcut / 2, + spin_sel, + spin_type_map, + env_protection=1e-6, + exclude_types=pair_exclude_types, + ) + + # set skip tests + skiptest, skip_reason = skip_model_tests(self) + if skiptest: + raise self.skipTest(skip_reason) + + ds = Descrpt(**self.input_dict_ds) + self.input_dict_ft = FittingParam( + ntypes=len(spin_type_map), + dim_descrpt=ds.get_dim_out(), + mixed_types=ds.mixed_types(), + type_map=spin_type_map, + ) + ft = Fitting( + **self.input_dict_ft, + ) + backbone_model = EnergyModel( + ds, + ft, + type_map=spin_type_map, + atom_exclude_types=atom_exclude_types, + pair_exclude_types=pair_exclude_types, + ) + self.module = SpinEnergyModel(backbone_model=backbone_model, spin=spin) + self.output_def = self.module.translated_output_def() + self.expected_has_message_passing = ds.has_message_passing() + self.expected_sel_type = ft.get_sel_type() + self.expected_dim_fparam = ft.get_dim_fparam() + self.expected_dim_aparam = ft.get_dim_aparam() From 14ae51f1094aec660b93a1f31eae3c64e451e89f Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:10:25 +0800 Subject: [PATCH 05/24] fix squeeze --- deepmd/dpmodel/output_def.py | 2 +- source/tests/common/dpmodel/test_output_def.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/deepmd/dpmodel/output_def.py b/deepmd/dpmodel/output_def.py index e16809130f..1d6e8f3638 100644 --- a/deepmd/dpmodel/output_def.py +++ b/deepmd/dpmodel/output_def.py @@ -230,7 +230,7 @@ def size(self): def squeeze(self, dim): # squeeze the shape on given dimension - if -len(self.shape) <= dim < len(self.shape) != 1 and self.shape[dim] == 1: + if -len(self.shape) <= dim < len(self.shape) and self.shape[dim] == 1: self.shape.pop(dim) diff --git a/source/tests/common/dpmodel/test_output_def.py b/source/tests/common/dpmodel/test_output_def.py index ca9461b0d3..4c831fdf55 100644 --- a/source/tests/common/dpmodel/test_output_def.py +++ b/source/tests/common/dpmodel/test_output_def.py @@ -761,9 +761,12 @@ def test_check_var(self): check_var(np.zeros([2, 2, 8]), var_def) def test_squeeze(self): + out_var = OutputVariableDef("foo", []) + out_var.squeeze(0) + self.assertEqual(out_var.shape, []) out_var = OutputVariableDef("foo", [1]) out_var.squeeze(0) - self.assertEqual(out_var.shape, [1]) + self.assertEqual(out_var.shape, []) out_var = OutputVariableDef("foo", [1, 1]) out_var.squeeze(0) self.assertEqual(out_var.shape, [1]) From b6afbb17bfabb14771f0da331d4cb3edd86fa536 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:14:46 +0800 Subject: [PATCH 06/24] Update se_r.py --- deepmd/dpmodel/descriptor/se_r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/dpmodel/descriptor/se_r.py b/deepmd/dpmodel/descriptor/se_r.py index b98c6c1068..20a6fe49dd 100644 --- a/deepmd/dpmodel/descriptor/se_r.py +++ b/deepmd/dpmodel/descriptor/se_r.py @@ -198,7 +198,7 @@ def get_dim_out(self): return self.neuron[-1] def get_dim_emb(self): - """Returns the output dimension.""" + """Returns the embedding (g2) dimension of this descriptor.""" raise NotImplementedError def get_rcut(self): From 5584432d7f9d29136fe72017cceb2a2d737dc949 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:17:50 +0800 Subject: [PATCH 07/24] Update path.py --- deepmd/utils/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/utils/path.py b/deepmd/utils/path.py index 1f9c4be3ef..377953cc35 100644 --- a/deepmd/utils/path.py +++ b/deepmd/utils/path.py @@ -320,7 +320,7 @@ def _load_h5py(cls, path: str, mode: str = "r") -> h5py.File: # this method has cache to avoid duplicated # loading from different DPH5Path # However the file will be never closed? - return h5py.File(path, mode, locking=False) + return h5py.File(path, mode) def load_numpy(self) -> np.ndarray: """Load NumPy array. From 16a15c3f468562d484695b5d2b16bf857d154a7f Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:20:28 +0800 Subject: [PATCH 08/24] Update model.py --- .../universal/common/cases/model/model.py | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/source/tests/universal/common/cases/model/model.py b/source/tests/universal/common/cases/model/model.py index 0c90f3d92a..b41b198f08 100644 --- a/source/tests/universal/common/cases/model/model.py +++ b/source/tests/universal/common/cases/model/model.py @@ -2,9 +2,6 @@ import os -from .....seed import ( - GLOBAL_SEED, -) from .utils import ( ModelTestCase, ) @@ -28,11 +25,6 @@ def setUp(self) -> None: self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } class DipoleModelTest(ModelTestCase): @@ -51,11 +43,6 @@ def setUp(self) -> None: self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } self.skip_test_autodiff = True @@ -75,11 +62,6 @@ def setUp(self) -> None: self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } self.skip_test_autodiff = True @@ -99,11 +81,6 @@ def setUp(self) -> None: self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } self.skip_test_autodiff = True @@ -123,11 +100,6 @@ def setUp(self) -> None: self.aprec_dict = {} self.rprec_dict = {} self.epsilon_dict = {} - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } self.tab_file = { "use_srtab": f"{CUR_DIR}/../data/zbl_tab_potential/H2O_tab_potential.txt", "smin_alpha": 0.1, @@ -156,9 +128,4 @@ def setUp(self) -> None: "use_spin": [True, False], "virtual_scale": [0.3140], } - self.input_dict_ft = { - "ntypes": len(self.expected_type_map), - "type_map": self.expected_type_map, - "seed": GLOBAL_SEED, - } self.test_spin = True From 25426519136f02ff851d67fad581c8f493d086a4 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:27:27 +0800 Subject: [PATCH 09/24] Update common.py --- source/tests/consistent/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/consistent/common.py b/source/tests/consistent/common.py index dc80a83f8c..7e055ecae7 100644 --- a/source/tests/consistent/common.py +++ b/source/tests/consistent/common.py @@ -421,7 +421,7 @@ class TestClass(base_class): def parameterize_func( func: Callable, - param_dict_list: OrderedDict[str, Tuple], + param_dict_list: OrderedDict, ): """Parameterize functions with different default values. From 264718bc3fcd36fcab9cb1e92b284ec0e4d6cc58 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:28:54 +0800 Subject: [PATCH 10/24] Update common.py --- source/tests/consistent/common.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/tests/consistent/common.py b/source/tests/consistent/common.py index 7e055ecae7..c533ef01c0 100644 --- a/source/tests/consistent/common.py +++ b/source/tests/consistent/common.py @@ -7,9 +7,6 @@ ABC, abstractmethod, ) -from collections import ( - OrderedDict, -) from enum import ( Enum, ) @@ -17,6 +14,7 @@ Any, Callable, ClassVar, + Dict, List, Optional, Tuple, @@ -421,7 +419,7 @@ class TestClass(base_class): def parameterize_func( func: Callable, - param_dict_list: OrderedDict, + param_dict_list: Dict[str, Tuple], ): """Parameterize functions with different default values. @@ -429,7 +427,7 @@ def parameterize_func( ---------- func : Callable The base function. - param_dict_list : OrderedDict[str, Tuple] + param_dict_list : Dict[str, Tuple] Dictionary of parameters with default values to be changed in base function, each of which is a tuple of choices. Returns From 0098ac56356339d674c4bd64bca55f748dc320d6 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Fri, 21 Jun 2024 00:05:59 +0800 Subject: [PATCH 11/24] fix spin aparam --- deepmd/dpmodel/model/spin_model.py | 28 ++++++++++++++++++++++++++++ deepmd/pt/model/model/spin_model.py | 8 +++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/deepmd/dpmodel/model/spin_model.py b/deepmd/dpmodel/model/spin_model.py index cd8587c7a4..d9c96a979e 100644 --- a/deepmd/dpmodel/model/spin_model.py +++ b/deepmd/dpmodel/model/spin_model.py @@ -198,6 +198,30 @@ def concat_switch_virtual(extended_tensor, extended_tensor_virtual, nloc: int): extended_tensor_updated[:, nloc + nall :] = extended_tensor_virtual[:, nloc:] return extended_tensor_updated.reshape(out_shape) + @staticmethod + def expand_aparam(aparam, nloc: int): + """Expand the atom parameters for virtual atoms if necessary.""" + nframes, natom, numb_aparam = aparam.shape + if natom == nloc: # good + pass + elif natom < nloc: # for spin with virtual atoms + aparam = np.concatenate( + [ + aparam, + np.zeros( + [nframes, nloc - natom, numb_aparam], + dtype=aparam.dtype, + ), + ], + axis=1, + ) + else: + raise ValueError( + f"get an input aparam with {aparam.shape[1]} inputs, ", + f"which is larger than {nloc} atoms.", + ) + return aparam + def get_type_map(self) -> List[str]: """Get the type map.""" tmap = self.backbone_model.get_type_map() @@ -342,6 +366,8 @@ def call( coord = coord.reshape(nframes, nloc, 3) spin = spin.reshape(nframes, nloc, 3) coord_updated, atype_updated = self.process_spin_input(coord, atype, spin) + if aparam is not None: + aparam = self.expand_aparam(aparam, nloc * 2) model_predict = self.backbone_model.call( coord_updated, atype_updated, @@ -410,6 +436,8 @@ def call_lower( ) = self.process_spin_input_lower( extended_coord, extended_atype, extended_spin, nlist, mapping=mapping ) + if aparam is not None: + aparam = self.expand_aparam(aparam, nloc * 2) model_predict = self.backbone_model.call_lower( extended_coord_updated, extended_atype_updated, diff --git a/deepmd/pt/model/model/spin_model.py b/deepmd/pt/model/model/spin_model.py index f51e5654ce..b2723279b9 100644 --- a/deepmd/pt/model/model/spin_model.py +++ b/deepmd/pt/model/model/spin_model.py @@ -229,7 +229,7 @@ def concat_switch_virtual(extended_tensor, extended_tensor_virtual, nloc: int): @staticmethod def expand_aparam(aparam, nloc: int): """Expand the atom parameters for virtual atoms if necessary.""" - nframes, natom, numb_aparam = aparam.shape[1:] + nframes, natom, numb_aparam = aparam.shape if natom == nloc: # good pass elif natom < nloc: # for spin with virtual atoms @@ -410,6 +410,8 @@ def forward_common( ) -> Dict[str, torch.Tensor]: nframes, nloc = atype.shape coord_updated, atype_updated = self.process_spin_input(coord, atype, spin) + if aparam is not None: + aparam = self.expand_aparam(aparam, nloc * 2) model_ret = self.backbone_model.forward_common( coord_updated, atype_updated, @@ -464,6 +466,8 @@ def forward_common_lower( ) = self.process_spin_input_lower( extended_coord, extended_atype, extended_spin, nlist, mapping=mapping ) + if aparam is not None: + aparam = self.expand_aparam(aparam, nloc * 2) model_ret = self.backbone_model.forward_common_lower( extended_coord_updated, extended_atype_updated, @@ -556,8 +560,6 @@ def forward( aparam: Optional[torch.Tensor] = None, do_atomic_virial: bool = False, ) -> Dict[str, torch.Tensor]: - if aparam is not None: - aparam = self.expand_aparam(aparam, atype.shape[1]) model_ret = self.forward_common( coord, atype, From 569d5266d51e42a3538a14f42d5217eb5c35b0ef Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:45:21 +0800 Subject: [PATCH 12/24] fix ut --- source/tests/universal/common/cases/model/utils.py | 7 ++++++- source/tests/universal/dpmodel/model/test_model.py | 2 +- source/tests/universal/pt/model/test_model.py | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index 312efc2dc9..fabf623362 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -116,6 +116,11 @@ def test_forward(self): test_spin = getattr(self, "test_spin", False) nf = 1 natoms = 5 + aprec = ( + 0 + if self.aprec_dict.get("test_forward", None) is None + else self.aprec_dict["test_forward"] + ) rng = np.random.default_rng(GLOBAL_SEED) coord = 4.0 * rng.random([natoms, 3]).reshape([nf, -1]) atype = np.array([0, 0, 0, 1, 1], dtype=int).reshape([nf, -1]) @@ -208,7 +213,7 @@ def test_forward(self): break else: continue - np.testing.assert_allclose(rr1, rr2) + np.testing.assert_allclose(rr1, rr2, atol=aprec) def test_permutation(self): """Test permutation.""" diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index e3067faf16..0a94733b80 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -148,7 +148,7 @@ def setUp(self): (FittingParam, Fitting) = self.param[1] self.epsilon_dict["test_smooth"] = 1e-6 # set special precision - if Descrpt in [DescrptDPA2]: + if Descrpt in [DescrptDPA2, DescrptHybrid]: self.epsilon_dict["test_smooth"] = 1e-8 spin = Spin( diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py index a5e80eb066..3bbe9e8203 100644 --- a/source/tests/universal/pt/model/test_model.py +++ b/source/tests/universal/pt/model/test_model.py @@ -227,6 +227,7 @@ def setUp(self): # set special precision if Descrpt in [DescrptDPA2]: self.epsilon_dict["test_smooth"] = 1e-8 + self.aprec_dict["test_forward"] = 1e-10 # for dipole force when near zero self.aprec_dict["test_rot"] = 1e-10 # for dipole force when near zero self.aprec_dict["test_trans"] = 1e-10 # for dipole force when near zero self.aprec_dict["test_permutation"] = 1e-10 # for dipole force when near zero @@ -417,8 +418,9 @@ def setUp(self): SpinEnerModelTest.setUp(self) (DescriptorParam, Descrpt) = self.param[0] (FittingParam, Fitting) = self.param[1] + self.epsilon_dict["test_smooth"] = 1e-6 # set special precision - if Descrpt in [DescrptDPA2]: + if Descrpt in [DescrptDPA2, DescrptHybrid]: self.epsilon_dict["test_smooth"] = 1e-8 spin = Spin( From 4e71bba8763829420954ae5b017d5bff8f3c5231 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Fri, 21 Jun 2024 18:09:33 +0800 Subject: [PATCH 13/24] split tests for descriptor and fitting --- source/tests/consistent/common.py | 11 +- .../common/cases/atomic_model/atomic_model.py | 157 ++--- .../universal/common/cases/model/model.py | 198 +++--- .../dpmodel/atomc_model/test_atomic_model.py | 437 +++++++------ .../universal/dpmodel/model/test_model.py | 192 +++--- .../pt/atomc_model/test_atomic_model.py | 437 +++++++------ source/tests/universal/pt/backend.py | 4 +- source/tests/universal/pt/model/test_model.py | 572 ++++++++++-------- 8 files changed, 1145 insertions(+), 863 deletions(-) diff --git a/source/tests/consistent/common.py b/source/tests/consistent/common.py index c533ef01c0..ad889ab144 100644 --- a/source/tests/consistent/common.py +++ b/source/tests/consistent/common.py @@ -365,7 +365,7 @@ def tearDown(self) -> None: clear_session() -def parameterized(*attrs: tuple) -> Callable: +def parameterized(*attrs: tuple, **kwargs: Dict[str, tuple]) -> Callable: """Parameterized test. Orginal class will not be actually generated. Avoid inherbiting from it. @@ -376,6 +376,8 @@ def parameterized(*attrs: tuple) -> Callable: ---------- *attrs : tuple The attributes to be parameterized. + **kwargs : Dict[str, tuple] + The sub-blocked attributes to be parameterized separately. Returns ------- @@ -400,10 +402,15 @@ def parameterized(*attrs: tuple) -> Callable: ... "param2": param2, ... } """ + global_combine = list(itertools.product(*attrs)) if len(attrs) else [] + block_combine = [] + for kk in kwargs: + block_combine += list(itertools.product(*kwargs[kk])) if len(kwargs[kk]) else [] + full_parameterized = global_combine + block_combine def decorator(base_class: type): class_module = sys.modules[base_class.__module__].__dict__ - for pp in itertools.product(*attrs): + for pp in full_parameterized: class TestClass(base_class): param: ClassVar = pp diff --git a/source/tests/universal/common/cases/atomic_model/atomic_model.py b/source/tests/universal/common/cases/atomic_model/atomic_model.py index d341c59af6..64c6a4caa0 100644 --- a/source/tests/universal/common/cases/atomic_model/atomic_model.py +++ b/source/tests/universal/common/cases/atomic_model/atomic_model.py @@ -10,94 +10,99 @@ class EnerAtomicModelTest(AtomicModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["energy", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} class DipoleAtomicModelTest(AtomicModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["dipole", "mask"] - self.model_output_equivariant = ["dipole"] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["dipole", "mask"] + cls.model_output_equivariant = ["dipole"] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} class PolarAtomicModelTest(AtomicModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["polarizability", "mask"] - self.model_output_equivariant = ["polarizability"] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["polarizability", "mask"] + cls.model_output_equivariant = ["polarizability"] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} class DosAtomicModelTest(AtomicModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["dos", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["dos", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} class ZBLAtomicModelTest(AtomicModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H", "B"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92, 10] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} - self.tab_file = { + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H", "B"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["energy", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92, 10] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} + cls.tab_file = { "use_srtab": f"{CUR_DIR}/../data/zbl_tab_potential/H2O_tab_potential.txt", "smin_alpha": 0.1, "sw_rmin": 0.2, diff --git a/source/tests/universal/common/cases/model/model.py b/source/tests/universal/common/cases/model/model.py index b41b198f08..f4a546fa5f 100644 --- a/source/tests/universal/common/cases/model/model.py +++ b/source/tests/universal/common/cases/model/model.py @@ -10,97 +10,102 @@ class EnerModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["energy", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} class DipoleModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["dipole", "mask"] - self.model_output_equivariant = ["dipole", "global_dipole"] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} - self.skip_test_autodiff = True + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["dipole", "mask"] + cls.model_output_equivariant = ["dipole", "global_dipole"] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} + cls.skip_test_autodiff = True class PolarModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["polarizability", "mask"] - self.model_output_equivariant = ["polar", "global_polar"] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} - self.skip_test_autodiff = True + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["polarizability", "mask"] + cls.model_output_equivariant = ["polar", "global_polar"] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} + cls.skip_test_autodiff = True class DosModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1] - self.expected_aparam_nall = False - self.expected_model_output_type = ["dos", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} - self.skip_test_autodiff = True + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["dos", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} + cls.skip_test_autodiff = True class ZBLModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 5.0 - self.expected_type_map = ["O", "H", "B"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92, 10] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} - self.tab_file = { + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 5.0 + cls.expected_type_map = ["O", "H", "B"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["energy", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92, 10] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} + cls.tab_file = { "use_srtab": f"{CUR_DIR}/../data/zbl_tab_potential/H2O_tab_potential.txt", "smin_alpha": 0.1, "sw_rmin": 0.2, @@ -109,23 +114,24 @@ def setUp(self) -> None: class SpinEnerModelTest(ModelTestCase): - def setUp(self) -> None: - self.expected_rcut = 4.0 - self.expected_type_map = ["Ni", "O"] - self.expected_dim_fparam = 0 - self.expected_dim_aparam = 0 - self.expected_sel_type = [0, 1, 2, 3] - self.expected_aparam_nall = False - self.expected_model_output_type = ["energy", "mask"] - self.model_output_equivariant = [] - self.expected_sel = [46, 92] - self.expected_sel_mix = sum(self.expected_sel) - self.expected_has_message_passing = False - self.aprec_dict = {} - self.rprec_dict = {} - self.epsilon_dict = {} - self.spin_dict = { + @classmethod + def setUpClass(cls) -> None: + cls.expected_rcut = 4.0 + cls.expected_type_map = ["Ni", "O"] + cls.expected_dim_fparam = 0 + cls.expected_dim_aparam = 0 + cls.expected_sel_type = [0, 1, 2, 3] + cls.expected_aparam_nall = False + cls.expected_model_output_type = ["energy", "mask"] + cls.model_output_equivariant = [] + cls.expected_sel = [46, 92] + cls.expected_sel_mix = sum(cls.expected_sel) + cls.expected_has_message_passing = False + cls.aprec_dict = {} + cls.rprec_dict = {} + cls.epsilon_dict = {} + cls.spin_dict = { "use_spin": [True, False], "virtual_scale": [0.3140], } - self.test_spin = True + cls.test_spin = True diff --git a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py index 589e2dda59..fc9b96e377 100644 --- a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py +++ b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py @@ -32,12 +32,17 @@ ZBLAtomicModelTest, ) from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1, DescriptorParamDPA1List, + DescriptorParamDPA2, DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, + DescriptorParamSeA, DescriptorParamSeAList, + DescriptorParamSeR, DescriptorParamSeRList, + DescriptorParamSeT, DescriptorParamSeTList, ) from ...dpmodel.model.test_model import ( @@ -47,291 +52,353 @@ DPTestCase, ) from ..fitting.test_fitting import ( + FittingParamDipole, FittingParamDipoleList, + FittingParamDos, FittingParamDosList, + FittingParamEnergy, FittingParamEnergyList, + FittingParamPolar, FittingParamPolarList, ) @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestEnergyAtomicModelDP(unittest.TestCase, EnerAtomicModelTest, DPTestCase): - def setUp(self): - EnerAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + EnerAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamDos, DOSFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], + ), # fitting_class_param & class + ), ) class TestDosAtomicModelDP(unittest.TestCase, DosAtomicModelTest, DPTestCase): - def setUp(self): - DosAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + DosAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision - self.aprec_dict["test_smooth"] = 1e-4 + cls.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, DipoleFitting) for param_func in FittingParamDipoleList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamDipole, DipoleFitting),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, DipoleFitting) for param_func in FittingParamDipoleList], + ), # fitting_class_param & class + ), ) class TestDipoleAtomicModelDP(unittest.TestCase, DipoleAtomicModelTest, DPTestCase): - def setUp(self): - DipoleAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + DipoleAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, embedding_width=ds.get_dim_emb(), ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, PolarFitting) for param_func in FittingParamPolarList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamPolar, PolarFitting),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, PolarFitting) for param_func in FittingParamPolarList], + ), # fitting_class_param & class + ), ) class TestPolarAtomicModelDP(unittest.TestCase, PolarAtomicModelTest, DPTestCase): - def setUp(self): - PolarAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + PolarAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, embedding_width=ds.get_dim_emb(), ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestZBLAtomicModelDP(unittest.TestCase, ZBLAtomicModelTest, DPTestCase): - def setUp(self): - ZBLAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + ZBLAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision # zbl weights not so smooth - self.aprec_dict["test_smooth"] = 5e-2 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.aprec_dict["test_smooth"] = 5e-2 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) dp_model = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) pt_model = PairTabAtomicModel( - self.tab_file["use_srtab"], - self.expected_rcut, - self.expected_sel, - type_map=self.expected_type_map, + cls.tab_file["use_srtab"], + cls.expected_rcut, + cls.expected_sel, + type_map=cls.expected_type_map, ) - self.module = DPZBLLinearEnergyAtomicModel( + cls.module = DPZBLLinearEnergyAtomicModel( dp_model, pt_model, - sw_rmin=self.tab_file["sw_rmin"], - sw_rmax=self.tab_file["sw_rmax"], - smin_alpha=self.tab_file["smin_alpha"], - type_map=self.expected_type_map, + sw_rmin=cls.tab_file["sw_rmin"], + sw_rmax=cls.tab_file["sw_rmax"], + smin_alpha=cls.tab_file["smin_alpha"], + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 0a94733b80..188e00ad9b 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -31,15 +31,21 @@ DPTestCase, ) from ..descriptor.test_descriptor import ( + DescriptorParamDPA1, DescriptorParamDPA1List, + DescriptorParamDPA2, DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, + DescriptorParamSeA, DescriptorParamSeAList, + DescriptorParamSeR, DescriptorParamSeRList, + DescriptorParamSeT, DescriptorParamSeTList, ) from ..fitting.test_fitting import ( + FittingParamEnergy, FittingParamEnergyList, ) @@ -58,8 +64,8 @@ def skip_model_tests(test_obj): "attn_layer" in test_obj.input_dict_ds and test_obj.input_dict_ds["attn_layer"] == 0 and ( - test_obj.input_dict_ds["attn_dotr"] - or test_obj.input_dict_ds["normalize"] + not test_obj.input_dict_ds["attn_dotr"] + or not test_obj.input_dict_ds["normalize"] or test_obj.input_dict_ds["temperature"] is not None ) ): @@ -68,106 +74,132 @@ def skip_model_tests(test_obj): @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestEnergyModelDP(unittest.TestCase, EnerModelTest, DPTestCase): - def setUp(self): - EnerModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + EnerModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) + ds = Descrpt(**cls.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = EnergyModel( + cls.module = EnergyModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.model_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() - self.skip_test_autodiff = True + cls.output_def = cls.module.model_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() + cls.skip_test_autodiff = True @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - # (DescriptorParamHybrid, DescrptHybrid), - # unsupported for SpinModel to hybrid both mixed_types and no-mixed_types descriptor - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + # (DescriptorParamHybrid, DescrptHybrid), + # unsupported for SpinModel to hybrid both mixed_types and no-mixed_types descriptor + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestSpinEnergyModelDP(unittest.TestCase, SpinEnerModelTest, DPTestCase): - def setUp(self): - SpinEnerModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] - self.epsilon_dict["test_smooth"] = 1e-6 + @classmethod + def setUpClass(cls): + SpinEnerModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] + cls.epsilon_dict["test_smooth"] = 1e-6 # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: - self.epsilon_dict["test_smooth"] = 1e-8 + cls.epsilon_dict["test_smooth"] = 1e-8 spin = Spin( - use_spin=self.spin_dict["use_spin"], - virtual_scale=self.spin_dict["virtual_scale"], + use_spin=cls.spin_dict["use_spin"], + virtual_scale=cls.spin_dict["virtual_scale"], ) - spin_type_map = self.expected_type_map + [ - item + "_spin" for item in self.expected_type_map + spin_type_map = cls.expected_type_map + [ + item + "_spin" for item in cls.expected_type_map ] if Descrpt in [DescrptSeA, DescrptSeR, DescrptSeT]: - spin_sel = self.expected_sel + self.expected_sel + spin_sel = cls.expected_sel + cls.expected_sel else: - spin_sel = self.expected_sel + spin_sel = cls.expected_sel pair_exclude_types = spin.get_pair_exclude_types() atom_exclude_types = spin.get_atom_exclude_types() - self.input_dict_ds = DescriptorParam( + cls.input_dict_ds = DescriptorParam( len(spin_type_map), - self.expected_rcut, - self.expected_rcut / 2, + cls.expected_rcut, + cls.expected_rcut / 2, spin_sel, spin_type_map, env_protection=1e-6, @@ -175,19 +207,19 @@ def setUp(self): ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( ntypes=len(spin_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), type_map=spin_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) backbone_model = EnergyModel( ds, @@ -196,10 +228,10 @@ def setUp(self): atom_exclude_types=atom_exclude_types, pair_exclude_types=pair_exclude_types, ) - self.module = SpinModel(backbone_model=backbone_model, spin=spin) - self.output_def = self.module.model_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() - self.skip_test_autodiff = True + cls.module = SpinModel(backbone_model=backbone_model, spin=spin) + cls.output_def = cls.module.model_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() + cls.skip_test_autodiff = True diff --git a/source/tests/universal/pt/atomc_model/test_atomic_model.py b/source/tests/universal/pt/atomc_model/test_atomic_model.py index b82eb96984..55e9bf9aa3 100644 --- a/source/tests/universal/pt/atomc_model/test_atomic_model.py +++ b/source/tests/universal/pt/atomc_model/test_atomic_model.py @@ -32,18 +32,27 @@ ZBLAtomicModelTest, ) from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1, DescriptorParamDPA1List, + DescriptorParamDPA2, DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, + DescriptorParamSeA, DescriptorParamSeAList, + DescriptorParamSeR, DescriptorParamSeRList, + DescriptorParamSeT, DescriptorParamSeTList, ) from ...dpmodel.fitting.test_fitting import ( + FittingParamDipole, FittingParamDipoleList, + FittingParamDos, FittingParamDosList, + FittingParamEnergy, FittingParamEnergyList, + FittingParamPolar, FittingParamPolarList, ) from ...dpmodel.model.test_model import ( @@ -55,283 +64,341 @@ @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestEnergyAtomicModelPT(unittest.TestCase, EnerAtomicModelTest, PTTestCase): - def setUp(self): - EnerAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + EnerAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamDos, DOSFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], + ), # fitting_class_param & class + ), ) class TestDosAtomicModelPT(unittest.TestCase, DosAtomicModelTest, PTTestCase): - def setUp(self): - DosAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + DosAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision - self.aprec_dict["test_smooth"] = 1e-4 + cls.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, DipoleFittingNet) for param_func in FittingParamDipoleList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamDipole, DipoleFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, DipoleFittingNet) for param_func in FittingParamDipoleList], + ), # fitting_class_param & class + ), ) class TestDipoleAtomicModelPT(unittest.TestCase, DipoleAtomicModelTest, PTTestCase): - def setUp(self): - DipoleAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + DipoleAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, embedding_width=ds.get_dim_emb(), ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, PolarFittingNet) for param_func in FittingParamPolarList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamPolar, PolarFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, PolarFittingNet) for param_func in FittingParamPolarList], + ), # fitting_class_param & class + ), ) class TestPolarAtomicModelPT(unittest.TestCase, PolarAtomicModelTest, PTTestCase): - def setUp(self): - PolarAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + PolarAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, embedding_width=ds.get_dim_emb(), ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DPAtomicModel( + cls.module = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestZBLAtomicModelPT(unittest.TestCase, ZBLAtomicModelTest, PTTestCase): - def setUp(self): - ZBLAtomicModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + ZBLAtomicModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision # zbl weights not so smooth - self.aprec_dict["test_smooth"] = 5e-2 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.aprec_dict["test_smooth"] = 5e-2 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + raise cls.skipTest(cls, skip_reason) + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) dp_model = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) pt_model = PairTabAtomicModel( - self.tab_file["use_srtab"], - self.expected_rcut, - self.expected_sel, - type_map=self.expected_type_map, + cls.tab_file["use_srtab"], + cls.expected_rcut, + cls.expected_sel, + type_map=cls.expected_type_map, ) - self.module = DPZBLLinearEnergyAtomicModel( + cls.module = DPZBLLinearEnergyAtomicModel( dp_model, pt_model, - sw_rmin=self.tab_file["sw_rmin"], - sw_rmax=self.tab_file["sw_rmax"], - smin_alpha=self.tab_file["smin_alpha"], - type_map=self.expected_type_map, + sw_rmin=cls.tab_file["sw_rmin"], + sw_rmax=cls.tab_file["sw_rmax"], + smin_alpha=cls.tab_file["smin_alpha"], + type_map=cls.expected_type_map, ) - self.output_def = self.module.atomic_output_def().get_data() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.atomic_output_def().get_data() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() diff --git a/source/tests/universal/pt/backend.py b/source/tests/universal/pt/backend.py index 5ee4791ec8..a8be2f9050 100644 --- a/source/tests/universal/pt/backend.py +++ b/source/tests/universal/pt/backend.py @@ -30,8 +30,8 @@ def modules_to_test(self): ] return modules - def test_jit(self): - self.script_module + # def test_jit(self): + # self.script_module @classmethod def convert_to_numpy(cls, xx: torch.Tensor) -> np.ndarray: diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py index 3bbe9e8203..b740fe5261 100644 --- a/source/tests/universal/pt/model/test_model.py +++ b/source/tests/universal/pt/model/test_model.py @@ -43,18 +43,27 @@ ZBLModelTest, ) from ...dpmodel.descriptor.test_descriptor import ( + DescriptorParamDPA1, DescriptorParamDPA1List, + DescriptorParamDPA2, DescriptorParamDPA2List, DescriptorParamHybrid, DescriptorParamHybridMixed, + DescriptorParamSeA, DescriptorParamSeAList, + DescriptorParamSeR, DescriptorParamSeRList, + DescriptorParamSeT, DescriptorParamSeTList, ) from ...dpmodel.fitting.test_fitting import ( + FittingParamDipole, FittingParamDipoleList, + FittingParamDos, FittingParamDosList, + FittingParamEnergy, FittingParamEnergyList, + FittingParamPolar, FittingParamPolarList, ) from ...dpmodel.model.test_model import ( @@ -66,18 +75,30 @@ @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestEnergyModelPT(unittest.TestCase, EnerModelTest, PTTestCase): # @property @@ -89,357 +110,434 @@ class TestEnergyModelPT(unittest.TestCase, EnerModelTest, PTTestCase): # ] # return modules - def setUp(self): - EnerModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + EnerModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = EnergyModel( + cls.module = EnergyModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.translated_output_def() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.translated_output_def() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamDos, DOSFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, DOSFittingNet) for param_func in FittingParamDosList], + ), # fitting_class_param & class + ), ) class TestDosModelPT(unittest.TestCase, DosModelTest, PTTestCase): # @property - # def modules_to_test(self): + # def modules_to_test(cls): # # for Model, we can test script module API # modules = [ - # *PTTestCase.modules_to_test.fget(self), - # self.script_module, + # *PTTestCase.modules_to_test.fget(cls), + # cls.script_module, # ] # return modules - def setUp(self): - DosModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + DosModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision - self.aprec_dict["test_smooth"] = 1e-4 + cls.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DOSModel( + cls.module = DOSModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.translated_output_def() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.translated_output_def() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, DipoleFittingNet) for param_func in FittingParamDipoleList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamDipole, DipoleFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, DipoleFittingNet) for param_func in FittingParamDipoleList], + ), # fitting_class_param & class + ), ) class TestDipoleModelPT(unittest.TestCase, DipoleModelTest, PTTestCase): # @property - # def modules_to_test(self): + # def modules_to_test(cls): # # for Model, we can test script module API # modules = [ - # *PTTestCase.modules_to_test.fget(self), - # self.script_module, + # *PTTestCase.modules_to_test.fget(cls), + # cls.script_module, # ] # return modules - def setUp(self): - DipoleModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + DipoleModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.aprec_dict["test_forward"] = 1e-10 # for dipole force when near zero - self.aprec_dict["test_rot"] = 1e-10 # for dipole force when near zero - self.aprec_dict["test_trans"] = 1e-10 # for dipole force when near zero - self.aprec_dict["test_permutation"] = 1e-10 # for dipole force when near zero - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.aprec_dict["test_forward"] = 1e-10 # for dipole force when near zero + cls.aprec_dict["test_rot"] = 1e-10 # for dipole force when near zero + cls.aprec_dict["test_trans"] = 1e-10 # for dipole force when near zero + cls.aprec_dict["test_permutation"] = 1e-10 # for dipole force when near zero + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, embedding_width=ds.get_dim_emb(), ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = DipoleModel( + cls.module = DipoleModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.translated_output_def() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.translated_output_def() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybrid, DescrptHybrid), - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, PolarFittingNet) for param_func in FittingParamPolarList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybrid, DescrptHybrid), + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamPolar, PolarFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, PolarFittingNet) for param_func in FittingParamPolarList], + ), # fitting_class_param & class + ), ) class TestPolarModelPT(unittest.TestCase, PolarModelTest, PTTestCase): # @property - # def modules_to_test(self): + # def modules_to_test(cls): # # for Model, we can test script module API # modules = [ - # *PTTestCase.modules_to_test.fget(self), - # self.script_module, + # *PTTestCase.modules_to_test.fget(cls), + # cls.script_module, # ] # return modules - def setUp(self): - PolarModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + @classmethod + def setUpClass(cls): + PolarModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision if Descrpt in [DescrptDPA2]: - self.epsilon_dict["test_smooth"] = 1e-8 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.epsilon_dict["test_smooth"] = 1e-8 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, embedding_width=ds.get_dim_emb(), ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) - self.module = PolarModel( + cls.module = PolarModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) - self.output_def = self.module.translated_output_def() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.translated_output_def() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestZBLModelPT(unittest.TestCase, ZBLModelTest, PTTestCase): - def setUp(self): - ZBLModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] + # @property + # def modules_to_test(cls): + # # for Model, we can test script module API + # modules = [ + # *PTTestCase.modules_to_test.fget(cls), + # cls.script_module, + # ] + # return modules + + @classmethod + def setUpClass(cls): + ZBLModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] # set special precision # zbl weights not so smooth - self.aprec_dict["test_smooth"] = 5e-2 - self.input_dict_ds = DescriptorParam( - len(self.expected_type_map), - self.expected_rcut, - self.expected_rcut / 2, - self.expected_sel, - self.expected_type_map, + cls.aprec_dict["test_smooth"] = 5e-2 + cls.input_dict_ds = DescriptorParam( + len(cls.expected_type_map), + cls.expected_rcut, + cls.expected_rcut / 2, + cls.expected_sel, + cls.expected_type_map, ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( - ntypes=len(self.expected_type_map), + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( + ntypes=len(cls.expected_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) dp_model = DPAtomicModel( ds, ft, - type_map=self.expected_type_map, + type_map=cls.expected_type_map, ) pt_model = PairTabAtomicModel( - self.tab_file["use_srtab"], - self.expected_rcut, - self.expected_sel, - type_map=self.expected_type_map, + cls.tab_file["use_srtab"], + cls.expected_rcut, + cls.expected_sel, + type_map=cls.expected_type_map, ) - self.module = DPZBLModel( + cls.module = DPZBLModel( dp_model, pt_model, - sw_rmin=self.tab_file["sw_rmin"], - sw_rmax=self.tab_file["sw_rmax"], - smin_alpha=self.tab_file["smin_alpha"], - type_map=self.expected_type_map, + sw_rmin=cls.tab_file["sw_rmin"], + sw_rmax=cls.tab_file["sw_rmax"], + smin_alpha=cls.tab_file["smin_alpha"], + type_map=cls.expected_type_map, ) - self.output_def = self.module.translated_output_def() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.output_def = cls.module.translated_output_def() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() @parameterized( - ( - *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], - *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], - *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], - *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], - *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], - # (DescriptorParamHybrid, DescrptHybrid), - # unsupported for SpinModel to hybrid both mixed_types and no-mixed_types descriptor - (DescriptorParamHybridMixed, DescrptHybrid), - ), # descrpt_class_param & class - ( - *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], - ), # fitting_class_param & class + des_parameterized=( + ( + *[(param_func, DescrptSeA) for param_func in DescriptorParamSeAList], + *[(param_func, DescrptSeR) for param_func in DescriptorParamSeRList], + *[(param_func, DescrptSeT) for param_func in DescriptorParamSeTList], + *[(param_func, DescrptDPA1) for param_func in DescriptorParamDPA1List], + *[(param_func, DescrptDPA2) for param_func in DescriptorParamDPA2List], + # (DescriptorParamHybrid, DescrptHybrid), + # unsupported for SpinModel to hybrid both mixed_types and no-mixed_types descriptor + (DescriptorParamHybridMixed, DescrptHybrid), + ), # descrpt_class_param & class + ((FittingParamEnergy, EnergyFittingNet),), # fitting_class_param & class + ), + fit_parameterized=( + ( + (DescriptorParamSeA, DescrptSeA), + (DescriptorParamSeR, DescrptSeR), + (DescriptorParamSeT, DescrptSeT), + (DescriptorParamDPA1, DescrptDPA1), + (DescriptorParamDPA2, DescrptDPA2), + ), # descrpt_class_param & class + ( + *[(param_func, EnergyFittingNet) for param_func in FittingParamEnergyList], + ), # fitting_class_param & class + ), ) class TestSpinEnergyModelDP(unittest.TestCase, SpinEnerModelTest, PTTestCase): - def setUp(self): - SpinEnerModelTest.setUp(self) - (DescriptorParam, Descrpt) = self.param[0] - (FittingParam, Fitting) = self.param[1] - self.epsilon_dict["test_smooth"] = 1e-6 + # @property + # def modules_to_test(cls): + # # for Model, we can test script module API + # modules = [ + # *PTTestCase.modules_to_test.fget(cls), + # cls.script_module, + # ] + # return modules + + @classmethod + def setUpClass(cls): + SpinEnerModelTest.setUpClass() + (DescriptorParam, Descrpt) = cls.param[0] + (FittingParam, Fitting) = cls.param[1] + cls.epsilon_dict["test_smooth"] = 1e-6 # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: - self.epsilon_dict["test_smooth"] = 1e-8 + cls.epsilon_dict["test_smooth"] = 1e-8 spin = Spin( - use_spin=self.spin_dict["use_spin"], - virtual_scale=self.spin_dict["virtual_scale"], + use_spin=cls.spin_dict["use_spin"], + virtual_scale=cls.spin_dict["virtual_scale"], ) - spin_type_map = self.expected_type_map + [ - item + "_spin" for item in self.expected_type_map + spin_type_map = cls.expected_type_map + [ + item + "_spin" for item in cls.expected_type_map ] if Descrpt in [DescrptSeA, DescrptSeR, DescrptSeT]: - spin_sel = self.expected_sel + self.expected_sel + spin_sel = cls.expected_sel + cls.expected_sel else: - spin_sel = self.expected_sel + spin_sel = cls.expected_sel pair_exclude_types = spin.get_pair_exclude_types() atom_exclude_types = spin.get_atom_exclude_types() - self.input_dict_ds = DescriptorParam( + cls.input_dict_ds = DescriptorParam( len(spin_type_map), - self.expected_rcut, - self.expected_rcut / 2, + cls.expected_rcut, + cls.expected_rcut / 2, spin_sel, spin_type_map, env_protection=1e-6, @@ -447,19 +545,19 @@ def setUp(self): ) # set skip tests - skiptest, skip_reason = skip_model_tests(self) + skiptest, skip_reason = skip_model_tests(cls) if skiptest: - raise self.skipTest(skip_reason) + raise cls.skipTest(cls, skip_reason) - ds = Descrpt(**self.input_dict_ds) - self.input_dict_ft = FittingParam( + ds = Descrpt(**cls.input_dict_ds) + cls.input_dict_ft = FittingParam( ntypes=len(spin_type_map), dim_descrpt=ds.get_dim_out(), mixed_types=ds.mixed_types(), type_map=spin_type_map, ) ft = Fitting( - **self.input_dict_ft, + **cls.input_dict_ft, ) backbone_model = EnergyModel( ds, @@ -468,9 +566,9 @@ def setUp(self): atom_exclude_types=atom_exclude_types, pair_exclude_types=pair_exclude_types, ) - self.module = SpinEnergyModel(backbone_model=backbone_model, spin=spin) - self.output_def = self.module.translated_output_def() - self.expected_has_message_passing = ds.has_message_passing() - self.expected_sel_type = ft.get_sel_type() - self.expected_dim_fparam = ft.get_dim_fparam() - self.expected_dim_aparam = ft.get_dim_aparam() + cls.module = SpinEnergyModel(backbone_model=backbone_model, spin=spin) + cls.output_def = cls.module.translated_output_def() + cls.expected_has_message_passing = ds.has_message_passing() + cls.expected_sel_type = ft.get_sel_type() + cls.expected_dim_fparam = ft.get_dim_fparam() + cls.expected_dim_aparam = ft.get_dim_aparam() From faa62ed52070bdea6846bae35bcd5d0f853cd47e Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:20:49 +0800 Subject: [PATCH 14/24] Update common.py --- source/tests/consistent/common.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source/tests/consistent/common.py b/source/tests/consistent/common.py index ad889ab144..edafc7c02e 100644 --- a/source/tests/consistent/common.py +++ b/source/tests/consistent/common.py @@ -365,7 +365,7 @@ def tearDown(self) -> None: clear_session() -def parameterized(*attrs: tuple, **kwargs: Dict[str, tuple]) -> Callable: +def parameterized(*attrs: tuple, **subblock_attrs: tuple) -> Callable: """Parameterized test. Orginal class will not be actually generated. Avoid inherbiting from it. @@ -376,7 +376,7 @@ def parameterized(*attrs: tuple, **kwargs: Dict[str, tuple]) -> Callable: ---------- *attrs : tuple The attributes to be parameterized. - **kwargs : Dict[str, tuple] + **subblock_attrs : tuple The sub-blocked attributes to be parameterized separately. Returns @@ -404,8 +404,12 @@ def parameterized(*attrs: tuple, **kwargs: Dict[str, tuple]) -> Callable: """ global_combine = list(itertools.product(*attrs)) if len(attrs) else [] block_combine = [] - for kk in kwargs: - block_combine += list(itertools.product(*kwargs[kk])) if len(kwargs[kk]) else [] + for kk in subblock_attrs: + block_combine += ( + list(itertools.product(*subblock_attrs[kk])) + if len(subblock_attrs[kk]) + else [] + ) full_parameterized = global_combine + block_combine def decorator(base_class: type): From 50cffda65ece5d56fe76c7676002134d1f0dd12a Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:30:30 +0800 Subject: [PATCH 15/24] fix conversations --- .../common/cases/atomic_model/utils.py | 525 +----------------- .../dpmodel/atomc_model/test_atomic_model.py | 16 - .../dpmodel/descriptor/test_descriptor.py | 18 +- .../universal/dpmodel/fitting/test_fitting.py | 8 + .../universal/dpmodel/model/test_model.py | 10 + .../pt/atomc_model/test_atomic_model.py | 16 - source/tests/universal/pt/backend.py | 6 +- source/tests/universal/pt/model/test_model.py | 198 +++++-- 8 files changed, 187 insertions(+), 610 deletions(-) diff --git a/source/tests/universal/common/cases/atomic_model/utils.py b/source/tests/universal/common/cases/atomic_model/utils.py index 17af932183..b63563e237 100644 --- a/source/tests/universal/common/cases/atomic_model/utils.py +++ b/source/tests/universal/common/cases/atomic_model/utils.py @@ -1,7 +1,4 @@ # SPDX-License-Identifier: LGPL-3.0-or-later -from copy import ( - deepcopy, -) from typing import ( Any, Callable, @@ -12,9 +9,6 @@ import numpy as np -from deepmd.dpmodel.output_def import ( - check_deriv, -) from deepmd.dpmodel.utils.nlist import ( extend_input_and_build_neighbor_list, ) @@ -159,522 +153,5 @@ def test_forward(self): subret[0], rr, err_msg=f"compare {kk} between 0 and {ii}" ) - def test_permutation(self): - """Test permutation.""" - if getattr(self, "skip_test_permutation", False): - self.skipTest("Skip test permutation.") - rng = np.random.default_rng(GLOBAL_SEED) - natoms = 5 - nf = 1 - idx_perm = [1, 0, 4, 3, 2] - cell = rng.random([3, 3]) - cell = (cell + cell.T) + 5.0 * np.eye(3) - coord = rng.random([natoms, 3]) - coord = np.matmul(coord, cell) - atype = np.array([0, 0, 0, 1, 1]) - coord_perm = coord[idx_perm] - atype_perm = atype[idx_perm] - - # reshape for input - coord = coord.reshape([nf, -1]) - coord_perm = coord_perm.reshape([nf, -1]) - atype = atype.reshape([nf, -1]) - atype_perm = atype_perm.reshape([nf, -1]) - cell = cell.reshape([nf, 9]) - aparam = None - fparam = None - aparam_perm = None - if self.module.get_dim_aparam() > 0: - aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) - aparam_perm = aparam[:, idx_perm, :] - if self.module.get_dim_fparam() > 0: - fparam = rng.random([nf, self.module.get_dim_fparam()]) - - ret = [] - module = self.forward_wrapper(self.module) - coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( - coord, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext, - atype_ext, - nlist, - mapping=mapping, - fparam=fparam, - aparam=aparam, - ) - ) - # permutation - coord_ext_perm, atype_ext_perm, mapping_perm, nlist_perm = ( - extend_input_and_build_neighbor_list( - coord_perm, - atype_perm, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ) - ret.append( - module( - coord_ext_perm, - atype_ext_perm, - nlist_perm, - mapping=mapping_perm, - fparam=fparam, - aparam=aparam_perm, - ) - ) - - for kk in ret[0]: - if kk in self.expected_model_output_type: - atomic = self.output_def[kk].atomic - if atomic: - np.testing.assert_allclose( - ret[0][kk][:, idx_perm], - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - np.testing.assert_allclose( - ret[0][kk], - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - raise RuntimeError(f"Unknown output key: {kk}") - - def test_trans(self): - """Test translation.""" - if getattr(self, "skip_test_trans", False): - self.skipTest("Skip test translation.") - rng = np.random.default_rng(GLOBAL_SEED) - natoms = 5 - nf = 1 - cell = rng.random([3, 3]) - cell = (cell + cell.T) + 5.0 * np.eye(3) - coord = rng.random([natoms, 3]) - coord = np.matmul(coord, cell) - atype = np.array([0, 0, 0, 1, 1]) - shift = (rng.random([3]) - 0.5) * 2.0 - coord_s = np.matmul( - np.remainder(np.matmul(coord + shift, np.linalg.inv(cell)), 1.0), cell - ) - - # reshape for input - coord = coord.reshape([nf, -1]) - coord_s = coord_s.reshape([nf, -1]) - atype = atype.reshape([nf, -1]) - cell = cell.reshape([nf, 9]) - - aparam = None - fparam = None - if self.module.get_dim_aparam() > 0: - aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) - if self.module.get_dim_fparam() > 0: - fparam = rng.random([nf, self.module.get_dim_fparam()]) - - ret = [] - module = self.forward_wrapper(self.module) - coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( - coord, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext, - atype_ext, - nlist, - mapping=mapping, - fparam=fparam, - aparam=aparam, - ) - ) - # translation - coord_ext_trans, atype_ext_trans, mapping_trans, nlist_trans = ( - extend_input_and_build_neighbor_list( - coord_s, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ) - ret.append( - module( - coord_ext_trans, - atype_ext_trans, - nlist_trans, - mapping=mapping_trans, - fparam=fparam, - aparam=aparam, - ) - ) - - for kk in ret[0]: - if kk in self.expected_model_output_type: - np.testing.assert_allclose( - ret[0][kk], - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - raise RuntimeError(f"Unknown output key: {kk}") - - def test_rot(self): - """Test rotation.""" - if getattr(self, "skip_test_rot", False): - self.skipTest("Skip test rotation.") - rng = np.random.default_rng(GLOBAL_SEED) - natoms = 5 - nf = 1 - - # rotate only coord and shift to the center of cell - cell = 10.0 * np.eye(3) - coord = 2.0 * rng.random([natoms, 3]) - atype = np.array([0, 0, 0, 1, 1]) - shift = np.array([4.0, 4.0, 4.0]) - from scipy.stats import ( - special_ortho_group, - ) - - rmat = special_ortho_group.rvs(3) - coord_rot = np.matmul(coord, rmat) - - # reshape for input - coord = (coord + shift).reshape([nf, -1]) - coord_rot = (coord_rot + shift).reshape([nf, -1]) - atype = atype.reshape([nf, -1]) - cell = cell.reshape([nf, 9]) - - aparam = None - fparam = None - if self.module.get_dim_aparam() > 0: - aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) - if self.module.get_dim_fparam() > 0: - fparam = rng.random([nf, self.module.get_dim_fparam()]) - - ret = [] - module = self.forward_wrapper(self.module) - coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( - coord, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext, - atype_ext, - nlist, - mapping=mapping, - fparam=fparam, - aparam=aparam, - ) - ) - # rotation - coord_ext_rot, atype_ext_rot, mapping_rot, nlist_rot = ( - extend_input_and_build_neighbor_list( - coord_rot, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ) - ret.append( - module( - coord_ext_rot, - atype_ext_rot, - nlist_rot, - mapping=mapping_rot, - fparam=fparam, - aparam=aparam, - ) - ) - - for kk in ret[0]: - if kk in self.expected_model_output_type: - rot_equivariant = ( - check_deriv(self.output_def[kk]) - or kk in self.model_output_equivariant - ) - if not rot_equivariant: - np.testing.assert_allclose( - ret[0][kk], - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - v_shape = self.output_def[kk].shape - rotated_ret_0 = ( - np.matmul(ret[0][kk], rmat) - if len(v_shape) == 1 - else np.matmul(rmat.T, np.matmul(ret[0][kk], rmat)) - ) - np.testing.assert_allclose( - rotated_ret_0, - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - raise RuntimeError(f"Unknown output key: {kk}") - - # rotate coord and cell - cell = rng.random([3, 3]) - cell = (cell + cell.T) + 5.0 * np.eye(3) - coord = rng.random([natoms, 3]) - coord = np.matmul(coord, cell) - atype = np.array([0, 0, 0, 1, 1]) - coord_rot = np.matmul(coord, rmat) - cell_rot = np.matmul(cell, rmat) - - # reshape for input - coord = coord.reshape([nf, -1]) - coord_rot = coord_rot.reshape([nf, -1]) - atype = atype.reshape([nf, -1]) - cell = cell.reshape([nf, 9]) - cell_rot = cell_rot.reshape([nf, 9]) - - ret = [] - module = self.forward_wrapper(self.module) - coord_ext, atype_ext, mapping, nlist = extend_input_and_build_neighbor_list( - coord, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext, - atype_ext, - nlist, - mapping=mapping, - fparam=fparam, - aparam=aparam, - ) - ) - # rotation - coord_ext_rot, atype_ext_rot, mapping_rot, nlist_rot = ( - extend_input_and_build_neighbor_list( - coord_rot, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell_rot, - ) - ) - ret.append( - module( - coord_ext_rot, - atype_ext_rot, - nlist_rot, - mapping=mapping_rot, - fparam=fparam, - aparam=aparam, - ) - ) - - for kk in ret[0]: - if kk in self.expected_model_output_type: - rot_equivariant = ( - check_deriv(self.output_def[kk]) - or kk in self.model_output_equivariant - ) - if not rot_equivariant: - np.testing.assert_allclose( - ret[0][kk], - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - v_shape = self.output_def[kk].shape - rotated_ret_0 = ( - np.matmul(ret[0][kk], rmat) - if len(v_shape) == 1 - else np.matmul(rmat.T, np.matmul(ret[0][kk], rmat)) - ) - np.testing.assert_allclose( - rotated_ret_0, - ret[1][kk], - err_msg=f"compare {kk} before and after transform", - ) - else: - raise RuntimeError(f"Unknown output key: {kk}") - - def test_smooth(self): - """Test smooth.""" - if getattr(self, "skip_test_smooth", False): - self.skipTest("Skip test smooth.") - rng = np.random.default_rng(GLOBAL_SEED) - epsilon = ( - 1e-5 - if self.epsilon_dict.get("test_smooth", None) is None - else self.epsilon_dict["test_smooth"] - ) - # required prec. - rprec = ( - 1e-5 - if self.rprec_dict.get("test_smooth", None) is None - else self.rprec_dict["test_smooth"] - ) - aprec = ( - 1e-5 - if self.aprec_dict.get("test_smooth", None) is None - else self.aprec_dict["test_smooth"] - ) - natoms = 10 - nf = 1 - cell = 10.0 * np.eye(3) - atype0 = np.arange(2) - atype1 = rng.integers(0, 2, size=natoms - 2) - atype = np.concatenate([atype0, atype1]).reshape(natoms) - coord0 = np.array( - [ - 0.0, - 0.0, - 0.0, - self.expected_rcut - 0.5 * epsilon, - 0.0, - 0.0, - 0.0, - self.expected_rcut - 0.5 * epsilon, - 0.0, - ] - ).reshape(-1, 3) - coord1 = rng.random([natoms - coord0.shape[0], 3]) - coord1 = np.matmul(coord1, cell) - coord = np.concatenate([coord0, coord1], axis=0) - - coord0 = deepcopy(coord) - coord1 = deepcopy(coord) - coord1[1][0] += epsilon - coord2 = deepcopy(coord) - coord2[2][1] += epsilon - coord3 = deepcopy(coord) - coord3[1][0] += epsilon - coord3[2][1] += epsilon - - # reshape for input - coord0 = coord0.reshape([nf, -1]) - coord1 = coord1.reshape([nf, -1]) - coord2 = coord2.reshape([nf, -1]) - coord3 = coord3.reshape([nf, -1]) - atype = atype.reshape([nf, -1]) - cell = cell.reshape([nf, 9]) - - aparam = None - fparam = None - if self.module.get_dim_aparam() > 0: - aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) - if self.module.get_dim_fparam() > 0: - fparam = rng.random([nf, self.module.get_dim_fparam()]) - - ret = [] - module = self.forward_wrapper(self.module) - # coord0 - coord_ext0, atype_ext0, mapping0, nlist0 = extend_input_and_build_neighbor_list( - coord0, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext0, - atype_ext0, - nlist0, - mapping=mapping0, - fparam=fparam, - aparam=aparam, - ) - ) - # coord1 - coord_ext1, atype_ext1, mapping1, nlist1 = extend_input_and_build_neighbor_list( - coord1, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext1, - atype_ext1, - nlist1, - mapping=mapping1, - fparam=fparam, - aparam=aparam, - ) - ) - # coord2 - coord_ext2, atype_ext2, mapping2, nlist2 = extend_input_and_build_neighbor_list( - coord2, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext2, - atype_ext2, - nlist2, - mapping=mapping2, - fparam=fparam, - aparam=aparam, - ) - ) - # coord3 - coord_ext3, atype_ext3, mapping3, nlist3 = extend_input_and_build_neighbor_list( - coord3, - atype, - self.expected_rcut, - self.expected_sel, - mixed_types=self.module.mixed_types(), - box=cell, - ) - ret.append( - module( - coord_ext3, - atype_ext3, - nlist3, - mapping=mapping3, - fparam=fparam, - aparam=aparam, - ) - ) - for kk in ret[0]: - if kk in self.expected_model_output_type: - for ii in range(len(ret) - 1): - np.testing.assert_allclose( - ret[0][kk], - ret[ii + 1][kk], - err_msg=f"compare {kk} before and after transform", - atol=aprec, - rtol=rprec, - ) - else: - raise RuntimeError(f"Unknown output key: {kk}") +# other properties are tested in the model level diff --git a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py index fc9b96e377..ceabb8505b 100644 --- a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py +++ b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py @@ -95,9 +95,6 @@ def setUpClass(cls): EnerAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -163,10 +160,6 @@ def setUpClass(cls): DosAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - cls.aprec_dict["test_smooth"] = 1e-4 - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -228,9 +221,6 @@ def setUpClass(cls): DipoleAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -293,9 +283,6 @@ def setUpClass(cls): PolarAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -355,9 +342,6 @@ def setUpClass(cls): ZBLAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - # zbl weights not so smooth - cls.aprec_dict["test_smooth"] = 5e-2 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, diff --git a/source/tests/universal/dpmodel/descriptor/test_descriptor.py b/source/tests/universal/dpmodel/descriptor/test_descriptor.py index 6ef92d28d7..2e42f070bf 100644 --- a/source/tests/universal/dpmodel/descriptor/test_descriptor.py +++ b/source/tests/universal/dpmodel/descriptor/test_descriptor.py @@ -64,7 +64,7 @@ def DescriptorParamSeA( DescriptorParamSeA, OrderedDict( { - "resnet_dt": (True, False), + "resnet_dt": (False, True), "type_one_side": (True, False), "exclude_types": ([], [[0, 1]]), "env_protection": (0.0, 1e-8, 1e-2), @@ -72,6 +72,8 @@ def DescriptorParamSeA( } ), ) +# to get name for the default function +DescriptorParamSeA = DescriptorParamSeAList[0] def DescriptorParamSeR( @@ -106,7 +108,7 @@ def DescriptorParamSeR( DescriptorParamSeR, OrderedDict( { - "resnet_dt": (True, False), + "resnet_dt": (False, True), "type_one_side": (True,), # type_one_side == False not implemented "exclude_types": ([], [[0, 1]]), "env_protection": (0.0, 1e-8), @@ -114,6 +116,8 @@ def DescriptorParamSeR( } ), ) +# to get name for the default function +DescriptorParamSeR = DescriptorParamSeRList[0] def DescriptorParamSeT( @@ -146,13 +150,15 @@ def DescriptorParamSeT( DescriptorParamSeT, OrderedDict( { - "resnet_dt": (True, False), + "resnet_dt": (False, True), "exclude_types": ([], [[0, 1]]), "env_protection": (0.0, 1e-8), "precision": ("float64",), } ), ) +# to get name for the default function +DescriptorParamSeT = DescriptorParamSeTList[0] def DescriptorParamDPA1( @@ -230,11 +236,13 @@ def DescriptorParamDPA1( "ln_eps": (1e-5,), "smooth_type_embedding": (True, False), "concat_output_tebd": (True,), - "use_econf_tebd": (True, False), + "use_econf_tebd": (False, True), "precision": ("float64",), } ), ) +# to get name for the default function +DescriptorParamDPA1 = DescriptorParamDPA1List[0] def DescriptorParamDPA2( @@ -360,6 +368,8 @@ def DescriptorParamDPA2( } ), ) +# to get name for the default function +DescriptorParamDPA2 = DescriptorParamDPA2List[0] def DescriptorParamHybrid(ntypes, rcut, rcut_smth, sel, type_map, **kwargs): diff --git a/source/tests/universal/dpmodel/fitting/test_fitting.py b/source/tests/universal/dpmodel/fitting/test_fitting.py index c20fb1660e..a4ff01253a 100644 --- a/source/tests/universal/dpmodel/fitting/test_fitting.py +++ b/source/tests/universal/dpmodel/fitting/test_fitting.py @@ -60,6 +60,8 @@ def FittingParamEnergy( } ), ) +# to get name for the default function +FittingParamEnergy = FittingParamEnergyList[0] def FittingParamDos( @@ -96,6 +98,8 @@ def FittingParamDos( } ), ) +# to get name for the default function +FittingParamDos = FittingParamDosList[0] def FittingParamDipole( @@ -136,6 +140,8 @@ def FittingParamDipole( } ), ) +# to get name for the default function +FittingParamDipole = FittingParamDipoleList[0] def FittingParamPolar( @@ -174,6 +180,8 @@ def FittingParamPolar( } ), ) +# to get name for the default function +FittingParamPolar = FittingParamPolarList[0] @parameterized( diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 188e00ad9b..9909abeb13 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -108,6 +108,12 @@ def setUpClass(cls): # set special precision if Descrpt in [DescrptDPA2]: cls.epsilon_dict["test_smooth"] = 1e-8 + if Descrpt in [DescrptDPA1]: + cls.epsilon_dict["test_smooth"] = 1e-6 + if Descrpt in [DescrptSeT]: + # computational expensive + cls.expected_sel = [i // 4 for i in cls.expected_sel] + cls.expected_rcut = cls.expected_rcut / 2 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -182,6 +188,10 @@ def setUpClass(cls): # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: cls.epsilon_dict["test_smooth"] = 1e-8 + if Descrpt in [DescrptSeT]: + # computational expensive + cls.expected_sel = [i // 4 for i in cls.expected_sel] + cls.expected_rcut = cls.expected_rcut / 2 spin = Spin( use_spin=cls.spin_dict["use_spin"], diff --git a/source/tests/universal/pt/atomc_model/test_atomic_model.py b/source/tests/universal/pt/atomc_model/test_atomic_model.py index 55e9bf9aa3..f0eff421b7 100644 --- a/source/tests/universal/pt/atomc_model/test_atomic_model.py +++ b/source/tests/universal/pt/atomc_model/test_atomic_model.py @@ -95,9 +95,6 @@ def setUpClass(cls): EnerAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -163,10 +160,6 @@ def setUpClass(cls): DosAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - cls.aprec_dict["test_smooth"] = 1e-4 - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -228,9 +221,6 @@ def setUpClass(cls): DipoleAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -293,9 +283,6 @@ def setUpClass(cls): PolarAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - if Descrpt in [DescrptDPA2]: - cls.epsilon_dict["test_smooth"] = 1e-8 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -355,9 +342,6 @@ def setUpClass(cls): ZBLAtomicModelTest.setUpClass() (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] - # set special precision - # zbl weights not so smooth - cls.aprec_dict["test_smooth"] = 5e-2 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, diff --git a/source/tests/universal/pt/backend.py b/source/tests/universal/pt/backend.py index a8be2f9050..10f5e2e29c 100644 --- a/source/tests/universal/pt/backend.py +++ b/source/tests/universal/pt/backend.py @@ -30,8 +30,10 @@ def modules_to_test(self): ] return modules - # def test_jit(self): - # self.script_module + def test_jit(self): + if getattr(self, "skip_test_jit", False): + self.skipTest("Skip test jit.") + self.script_module @classmethod def convert_to_numpy(cls, xx: torch.Tensor) -> np.ndarray: diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py index b740fe5261..2df7dd857f 100644 --- a/source/tests/universal/pt/model/test_model.py +++ b/source/tests/universal/pt/model/test_model.py @@ -1,6 +1,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-later import unittest +import torch + from deepmd.pt.model.atomic_model import ( DPAtomicModel, PairTabAtomicModel, @@ -73,6 +75,22 @@ PTTestCase, ) +defalut_des_param = [ + DescriptorParamSeA, + DescriptorParamSeR, + DescriptorParamSeT, + DescriptorParamDPA1, + DescriptorParamDPA2, + DescriptorParamHybrid, + DescriptorParamHybridMixed, +] +defalut_fit_param = [ + FittingParamEnergy, + FittingParamDos, + FittingParamDipole, + FittingParamPolar, +] + @parameterized( des_parameterized=( @@ -101,14 +119,18 @@ ), ) class TestEnergyModelPT(unittest.TestCase, EnerModelTest, PTTestCase): - # @property - # def modules_to_test(self): - # # for Model, we can test script module API - # modules = [ - # *PTTestCase.modules_to_test.fget(self), - # self.script_module, - # ] - # return modules + @property + def modules_to_test(self): + skip_test_jit = getattr(self, "skip_test_jit", False) + modules = PTTestCase.modules_to_test.fget(self) + if not skip_test_jit: + # for Model, we can test script module API + modules += [ + self._script_module + if hasattr(self, "_script_module") + else self.script_module + ] + return modules @classmethod def setUpClass(cls): @@ -118,6 +140,10 @@ def setUpClass(cls): # set special precision if Descrpt in [DescrptDPA2]: cls.epsilon_dict["test_smooth"] = 1e-8 + if Descrpt in [DescrptSeT]: + # computational expensive + cls.expected_sel = [i // 4 for i in cls.expected_sel] + cls.expected_rcut = cls.expected_rcut / 2 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -146,6 +172,14 @@ def setUpClass(cls): ft, type_map=cls.expected_type_map, ) + # only test jit API once for different models + if ( + DescriptorParam not in defalut_des_param + or FittingParam not in defalut_fit_param + ): + cls.skip_test_jit = True + else: + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -180,14 +214,18 @@ def setUpClass(cls): ), ) class TestDosModelPT(unittest.TestCase, DosModelTest, PTTestCase): - # @property - # def modules_to_test(cls): - # # for Model, we can test script module API - # modules = [ - # *PTTestCase.modules_to_test.fget(cls), - # cls.script_module, - # ] - # return modules + @property + def modules_to_test(self): + skip_test_jit = getattr(self, "skip_test_jit", False) + modules = PTTestCase.modules_to_test.fget(self) + if not skip_test_jit: + # for Model, we can test script module API + modules += [ + self._script_module + if hasattr(self, "_script_module") + else self.script_module + ] + return modules @classmethod def setUpClass(cls): @@ -198,6 +236,10 @@ def setUpClass(cls): cls.aprec_dict["test_smooth"] = 1e-4 if Descrpt in [DescrptDPA2]: cls.epsilon_dict["test_smooth"] = 1e-8 + if Descrpt in [DescrptSeT]: + # computational expensive + cls.expected_sel = [i // 4 for i in cls.expected_sel] + cls.expected_rcut = cls.expected_rcut / 2 cls.input_dict_ds = DescriptorParam( len(cls.expected_type_map), cls.expected_rcut, @@ -226,6 +268,14 @@ def setUpClass(cls): ft, type_map=cls.expected_type_map, ) + # only test jit API once for different models + if ( + DescriptorParam not in defalut_des_param + or FittingParam not in defalut_fit_param + ): + cls.skip_test_jit = True + else: + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -256,14 +306,18 @@ def setUpClass(cls): ), ) class TestDipoleModelPT(unittest.TestCase, DipoleModelTest, PTTestCase): - # @property - # def modules_to_test(cls): - # # for Model, we can test script module API - # modules = [ - # *PTTestCase.modules_to_test.fget(cls), - # cls.script_module, - # ] - # return modules + @property + def modules_to_test(self): + skip_test_jit = getattr(self, "skip_test_jit", False) + modules = PTTestCase.modules_to_test.fget(self) + if not skip_test_jit: + # for Model, we can test script module API + modules += [ + self._script_module + if hasattr(self, "_script_module") + else self.script_module + ] + return modules @classmethod def setUpClass(cls): @@ -306,6 +360,14 @@ def setUpClass(cls): ft, type_map=cls.expected_type_map, ) + # only test jit API once for different models + if ( + DescriptorParam not in defalut_des_param + or FittingParam not in defalut_fit_param + ): + cls.skip_test_jit = True + else: + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -336,14 +398,18 @@ def setUpClass(cls): ), ) class TestPolarModelPT(unittest.TestCase, PolarModelTest, PTTestCase): - # @property - # def modules_to_test(cls): - # # for Model, we can test script module API - # modules = [ - # *PTTestCase.modules_to_test.fget(cls), - # cls.script_module, - # ] - # return modules + @property + def modules_to_test(self): + skip_test_jit = getattr(self, "skip_test_jit", False) + modules = PTTestCase.modules_to_test.fget(self) + if not skip_test_jit: + # for Model, we can test script module API + modules += [ + self._script_module + if hasattr(self, "_script_module") + else self.script_module + ] + return modules @classmethod def setUpClass(cls): @@ -382,6 +448,14 @@ def setUpClass(cls): ft, type_map=cls.expected_type_map, ) + # only test jit API once for different models + if ( + DescriptorParam not in defalut_des_param + or FittingParam not in defalut_fit_param + ): + cls.skip_test_jit = True + else: + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -409,14 +483,18 @@ def setUpClass(cls): ), ) class TestZBLModelPT(unittest.TestCase, ZBLModelTest, PTTestCase): - # @property - # def modules_to_test(cls): - # # for Model, we can test script module API - # modules = [ - # *PTTestCase.modules_to_test.fget(cls), - # cls.script_module, - # ] - # return modules + @property + def modules_to_test(self): + skip_test_jit = getattr(self, "skip_test_jit", False) + modules = PTTestCase.modules_to_test.fget(self) + if not skip_test_jit: + # for Model, we can test script module API + modules += [ + self._script_module + if hasattr(self, "_script_module") + else self.script_module + ] + return modules @classmethod def setUpClass(cls): @@ -468,6 +546,14 @@ def setUpClass(cls): smin_alpha=cls.tab_file["smin_alpha"], type_map=cls.expected_type_map, ) + # only test jit API once for different models + if ( + DescriptorParam not in defalut_des_param + or FittingParam not in defalut_fit_param + ): + cls.skip_test_jit = True + else: + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_dim_fparam = ft.get_dim_fparam() @@ -502,14 +588,18 @@ def setUpClass(cls): ), ) class TestSpinEnergyModelDP(unittest.TestCase, SpinEnerModelTest, PTTestCase): - # @property - # def modules_to_test(cls): - # # for Model, we can test script module API - # modules = [ - # *PTTestCase.modules_to_test.fget(cls), - # cls.script_module, - # ] - # return modules + @property + def modules_to_test(self): + skip_test_jit = getattr(self, "skip_test_jit", False) + modules = PTTestCase.modules_to_test.fget(self) + if not skip_test_jit: + # for Model, we can test script module API + modules += [ + self._script_module + if hasattr(self, "_script_module") + else self.script_module + ] + return modules @classmethod def setUpClass(cls): @@ -520,6 +610,10 @@ def setUpClass(cls): # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: cls.epsilon_dict["test_smooth"] = 1e-8 + if Descrpt in [DescrptSeT]: + # computational expensive + cls.expected_sel = [i // 4 for i in cls.expected_sel] + cls.expected_rcut = cls.expected_rcut / 2 spin = Spin( use_spin=cls.spin_dict["use_spin"], @@ -567,6 +661,14 @@ def setUpClass(cls): pair_exclude_types=pair_exclude_types, ) cls.module = SpinEnergyModel(backbone_model=backbone_model, spin=spin) + # only test jit API once for different models + if ( + DescriptorParam not in defalut_des_param + or FittingParam not in defalut_fit_param + ): + cls.skip_test_jit = True + else: + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() From e6fcb5857c8138f5fca2fb002a98a1b7a667ec58 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Mon, 24 Jun 2024 23:58:34 +0800 Subject: [PATCH 16/24] Update spin_model.py --- deepmd/pt/model/model/spin_model.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deepmd/pt/model/model/spin_model.py b/deepmd/pt/model/model/spin_model.py index b2723279b9..d9517a2feb 100644 --- a/deepmd/pt/model/model/spin_model.py +++ b/deepmd/pt/model/model/spin_model.py @@ -331,6 +331,11 @@ def has_spin(self) -> bool: """Returns whether it has spin input and output.""" return True + @torch.jit.export + def has_message_passing(self) -> bool: + """Returns whether the model has message passing.""" + return self.backbone_model.has_message_passing() + def model_output_def(self): """Get the output def for the model.""" model_output_type = self.backbone_model.model_output_type() From 733b9a4c5bc1f3b898bf8ffd6661bcf4f6575686 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Tue, 25 Jun 2024 00:47:30 +0800 Subject: [PATCH 17/24] fix ut --- source/tests/universal/dpmodel/model/test_model.py | 1 + source/tests/universal/pt/model/test_model.py | 1 + 2 files changed, 2 insertions(+) diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 9909abeb13..cdfce285e3 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -185,6 +185,7 @@ def setUpClass(cls): (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] cls.epsilon_dict["test_smooth"] = 1e-6 + cls.aprec_dict["test_smooth"] = 5e-5 # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: cls.epsilon_dict["test_smooth"] = 1e-8 diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py index 2df7dd857f..1a82c05b1e 100644 --- a/source/tests/universal/pt/model/test_model.py +++ b/source/tests/universal/pt/model/test_model.py @@ -607,6 +607,7 @@ def setUpClass(cls): (DescriptorParam, Descrpt) = cls.param[0] (FittingParam, Fitting) = cls.param[1] cls.epsilon_dict["test_smooth"] = 1e-6 + cls.aprec_dict["test_smooth"] = 5e-5 # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: cls.epsilon_dict["test_smooth"] = 1e-8 From 481d08cab84b8378f6fcedaf8769d5d5fb43cfc5 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Wed, 26 Jun 2024 00:14:23 +0800 Subject: [PATCH 18/24] fix warnings --- deepmd/dpmodel/descriptor/dpa1.py | 1 + deepmd/pt/model/descriptor/hybrid.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/deepmd/dpmodel/descriptor/dpa1.py b/deepmd/dpmodel/descriptor/dpa1.py index b633bc6807..a0227e13c9 100644 --- a/deepmd/dpmodel/descriptor/dpa1.py +++ b/deepmd/dpmodel/descriptor/dpa1.py @@ -61,6 +61,7 @@ def np_softmax(x, axis=-1): + x = np.nan_to_num(x) # to avoid value warning e_x = np.exp(x - np.max(x, axis=axis, keepdims=True)) return e_x / np.sum(e_x, axis=axis, keepdims=True) diff --git a/deepmd/pt/model/descriptor/hybrid.py b/deepmd/pt/model/descriptor/hybrid.py index d486cda399..2f5f1bd786 100644 --- a/deepmd/pt/model/descriptor/hybrid.py +++ b/deepmd/pt/model/descriptor/hybrid.py @@ -43,6 +43,8 @@ class DescrptHybrid(BaseDescriptor, torch.nn.Module): The descriptor can be either an object or a dictionary. """ + nlist_cut_idx: List[torch.Tensor] + def __init__( self, list: List[Union[BaseDescriptor, Dict[str, Any]]], From 151edb6c41dec76a9a01e20efb84eb906e72fdeb Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:53:00 +0800 Subject: [PATCH 19/24] Update test_model.py --- source/tests/universal/dpmodel/model/test_model.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index cdfce285e3..42eaf876cb 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -108,6 +108,8 @@ def setUpClass(cls): # set special precision if Descrpt in [DescrptDPA2]: cls.epsilon_dict["test_smooth"] = 1e-8 + cls.rprec_dict["test_smooth"] = 5e-5 + cls.aprec_dict["test_smooth"] = 5e-5 if Descrpt in [DescrptDPA1]: cls.epsilon_dict["test_smooth"] = 1e-6 if Descrpt in [DescrptSeT]: @@ -186,6 +188,7 @@ def setUpClass(cls): (FittingParam, Fitting) = cls.param[1] cls.epsilon_dict["test_smooth"] = 1e-6 cls.aprec_dict["test_smooth"] = 5e-5 + cls.rprec_dict["test_smooth"] = 5e-5 # set special precision if Descrpt in [DescrptDPA2, DescrptHybrid]: cls.epsilon_dict["test_smooth"] = 1e-8 From 84956596f54b2c6a47cd5e94eb73c5df439e3037 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Wed, 26 Jun 2024 20:28:29 +0800 Subject: [PATCH 20/24] skip uts on cpu and gpu --- deepmd/pt/model/network/network.py | 2 +- deepmd/pt/utils/exclude_mask.py | 4 +- source/tests/universal/common/backend.py | 4 ++ .../universal/common/cases/model/utils.py | 59 ++++++++++++++++++- .../dpmodel/atomc_model/test_atomic_model.py | 8 +++ source/tests/universal/dpmodel/backend.py | 3 + .../dpmodel/descriptor/test_descriptor.py | 4 ++ .../universal/dpmodel/fitting/test_fitting.py | 4 ++ .../universal/dpmodel/model/test_model.py | 5 ++ .../dpmodel/utils/test_type_embed.py | 4 ++ source/tests/universal/pt/backend.py | 23 +++++++- source/tests/universal/pt/model/test_model.py | 18 ++++-- source/tests/universal/pt/utils/utils.py | 10 ++++ 13 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 source/tests/universal/pt/utils/utils.py diff --git a/deepmd/pt/model/network/network.py b/deepmd/pt/model/network/network.py index 0879daf6ec..13599a77dd 100644 --- a/deepmd/pt/model/network/network.py +++ b/deepmd/pt/model/network/network.py @@ -718,7 +718,7 @@ def forward(self, device: torch.device): ) else: assert self.econf_tebd is not None - embed = self.embedding_net(self.econf_tebd) + embed = self.embedding_net(self.econf_tebd.to(device)) if self.padding: embed = torch.cat( [embed, torch.zeros(1, embed.shape[1], dtype=self.prec, device=device)] diff --git a/deepmd/pt/utils/exclude_mask.py b/deepmd/pt/utils/exclude_mask.py index 9ddae3a416..c3f3f8eb2f 100644 --- a/deepmd/pt/utils/exclude_mask.py +++ b/deepmd/pt/utils/exclude_mask.py @@ -63,7 +63,7 @@ def forward( """ nf, natom = atype.shape - return self.type_mask[atype].view(nf, natom) + return self.type_mask[atype].view(nf, natom).to(atype.device) class PairExcludeMask(torch.nn.Module): @@ -150,5 +150,5 @@ def forward( type_ij = type_i[:, :, None] + type_j # nf x (nloc x nnei) type_ij = type_ij.view(nf, nloc * nnei) - mask = self.type_mask[type_ij].view(nf, nloc, nnei) + mask = self.type_mask[type_ij].view(nf, nloc, nnei).to(atype_ext.device) return mask diff --git a/source/tests/universal/common/backend.py b/source/tests/universal/common/backend.py index 44532a4d68..6173dee3a9 100644 --- a/source/tests/universal/common/backend.py +++ b/source/tests/universal/common/backend.py @@ -22,6 +22,10 @@ def modules_to_test(self) -> list: def forward_wrapper(self, x): pass + @abstractmethod + def forward_wrapper_cpu_ref(self, module): + pass + @classmethod @abstractmethod def convert_to_numpy(cls, xx): diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index fabf623362..7b26068659 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +import unittest from copy import ( deepcopy, ) @@ -22,6 +23,9 @@ from .....seed import ( GLOBAL_SEED, ) +from ....pt.utils.utils import ( + TEST_DEVICE, +) class ModelTestCase: @@ -48,7 +52,9 @@ class ModelTestCase: expected_has_message_passing: bool """Expected whether having message passing.""" forward_wrapper: Callable[[Any], Any] - """Calss wrapper for forward method.""" + """Class wrapper for forward method.""" + forward_wrapper_cpu_ref: Callable[[Any], Any] + """Convert model to CPU method.""" aprec_dict: Dict[str, Optional[float]] """Dictionary of absolute precision in each test.""" rprec_dict: Dict[str, Optional[float]] @@ -215,6 +221,7 @@ def test_forward(self): continue np.testing.assert_allclose(rr1, rr2, atol=aprec) + @unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") def test_permutation(self): """Test permutation.""" if getattr(self, "skip_test_permutation", False): @@ -300,6 +307,7 @@ def test_permutation(self): else: raise RuntimeError(f"Unknown output key: {kk}") + @unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") def test_trans(self): """Test translation.""" if getattr(self, "skip_test_trans", False): @@ -368,6 +376,7 @@ def test_trans(self): else: raise RuntimeError(f"Unknown output key: {kk}") + @unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") def test_rot(self): """Test rotation.""" if getattr(self, "skip_test_rot", False): @@ -557,6 +566,7 @@ def test_rot(self): else: raise RuntimeError(f"Unknown output key: {kk}") + @unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") def test_smooth(self): """Test smooth.""" if getattr(self, "skip_test_smooth", False): @@ -663,6 +673,7 @@ def test_smooth(self): else: raise RuntimeError(f"Unknown output key: {kk}") + @unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") def test_autodiff(self): """Test autodiff.""" if getattr(self, "skip_test_autodiff", False): @@ -801,3 +812,49 @@ def ff_cell(bb): else: # not support virial by far pass + + @unittest.skipIf(TEST_DEVICE == "cpu", "Skip test on CPU.") + def test_device_consistence(self): + """Test forward consistency between devices.""" + test_spin = getattr(self, "test_spin", False) + nf = 1 + natoms = 5 + rng = np.random.default_rng(GLOBAL_SEED) + coord = 4.0 * rng.random([natoms, 3]).reshape([nf, -1]) + atype = np.array([0, 0, 0, 1, 1], dtype=int).reshape([nf, -1]) + spin = 0.5 * rng.random([natoms, 3]).reshape([nf, -1]) + cell = 6.0 * np.eye(3).reshape([nf, 9]) + aparam = None + fparam = None + if self.module.get_dim_aparam() > 0: + aparam = rng.random([nf, natoms, self.module.get_dim_aparam()]) + if self.module.get_dim_fparam() > 0: + fparam = rng.random([nf, self.module.get_dim_fparam()]) + ret = [] + device_module = self.forward_wrapper(self.module) + ref_module = self.forward_wrapper_cpu_ref(deepcopy(self.module)) + + for module in [device_module, ref_module]: + input_dict = { + "coord": coord, + "atype": atype, + "box": cell, + "aparam": aparam, + "fparam": fparam, + } + if test_spin: + input_dict["spin"] = spin + ret.append(module(**input_dict)) + for kk in ret[0]: + subret = [] + for rr in ret: + if rr is not None: + subret.append(rr[kk]) + if len(subret): + for ii, rr in enumerate(subret[1:]): + if subret[0] is None: + assert rr is None + else: + np.testing.assert_allclose( + subret[0], rr, err_msg=f"compare {kk} between 0 and {ii}" + ) diff --git a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py index ceabb8505b..28cce08ef1 100644 --- a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py +++ b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py @@ -48,6 +48,9 @@ from ...dpmodel.model.test_model import ( skip_model_tests, ) +from ...pt.utils.utils import ( + TEST_DEVICE, +) from ..backend import ( DPTestCase, ) @@ -89,6 +92,7 @@ ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestEnergyAtomicModelDP(unittest.TestCase, EnerAtomicModelTest, DPTestCase): @classmethod def setUpClass(cls): @@ -154,6 +158,7 @@ def setUpClass(cls): ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestDosAtomicModelDP(unittest.TestCase, DosAtomicModelTest, DPTestCase): @classmethod def setUpClass(cls): @@ -215,6 +220,7 @@ def setUpClass(cls): ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestDipoleAtomicModelDP(unittest.TestCase, DipoleAtomicModelTest, DPTestCase): @classmethod def setUpClass(cls): @@ -277,6 +283,7 @@ def setUpClass(cls): ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestPolarAtomicModelDP(unittest.TestCase, PolarAtomicModelTest, DPTestCase): @classmethod def setUpClass(cls): @@ -336,6 +343,7 @@ def setUpClass(cls): ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestZBLAtomicModelDP(unittest.TestCase, ZBLAtomicModelTest, DPTestCase): @classmethod def setUpClass(cls): diff --git a/source/tests/universal/dpmodel/backend.py b/source/tests/universal/dpmodel/backend.py index aff009b71b..99170c20e1 100644 --- a/source/tests/universal/dpmodel/backend.py +++ b/source/tests/universal/dpmodel/backend.py @@ -19,6 +19,9 @@ class DPTestCase(BackendTestCase): def forward_wrapper(self, x): return x + def forward_wrapper_cpu_ref(self, x): + return x + @classmethod def convert_to_numpy(cls, xx: np.ndarray) -> np.ndarray: return xx diff --git a/source/tests/universal/dpmodel/descriptor/test_descriptor.py b/source/tests/universal/dpmodel/descriptor/test_descriptor.py index 2e42f070bf..89f57ccf1d 100644 --- a/source/tests/universal/dpmodel/descriptor/test_descriptor.py +++ b/source/tests/universal/dpmodel/descriptor/test_descriptor.py @@ -27,6 +27,9 @@ from ...common.cases.descriptor.descriptor import ( DescriptorTest, ) +from ...pt.utils.utils import ( + TEST_DEVICE, +) from ..backend import ( DPTestCase, ) @@ -413,6 +416,7 @@ def DescriptorParamHybridMixed(ntypes, rcut, rcut_smth, sel, type_map, **kwargs) (DescriptorParamHybridMixed, DescrptHybrid), ) # class_param & class ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestDescriptorDP(unittest.TestCase, DescriptorTest, DPTestCase): def setUp(self): DescriptorTest.setUp(self) diff --git a/source/tests/universal/dpmodel/fitting/test_fitting.py b/source/tests/universal/dpmodel/fitting/test_fitting.py index a4ff01253a..7ee9c835af 100644 --- a/source/tests/universal/dpmodel/fitting/test_fitting.py +++ b/source/tests/universal/dpmodel/fitting/test_fitting.py @@ -21,6 +21,9 @@ from ...common.cases.fitting.fitting import ( FittingTest, ) +from ...pt.utils.utils import ( + TEST_DEVICE, +) from ..backend import ( DPTestCase, ) @@ -193,6 +196,7 @@ def FittingParamPolar( ), # class_param & class (True, False), # mixed_types ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestFittingDP(unittest.TestCase, FittingTest, DPTestCase): def setUp(self): ((FittingParam, Fitting), self.mixed_types) = self.param diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 42eaf876cb..1ff82dc05e 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -27,6 +27,9 @@ EnerModelTest, SpinEnerModelTest, ) +from ...pt.utils.utils import ( + TEST_DEVICE, +) from ..backend import ( DPTestCase, ) @@ -99,6 +102,7 @@ def skip_model_tests(test_obj): ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestEnergyModelDP(unittest.TestCase, EnerModelTest, DPTestCase): @classmethod def setUpClass(cls): @@ -180,6 +184,7 @@ def setUpClass(cls): ), # fitting_class_param & class ), ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestSpinEnergyModelDP(unittest.TestCase, SpinEnerModelTest, DPTestCase): @classmethod def setUpClass(cls): diff --git a/source/tests/universal/dpmodel/utils/test_type_embed.py b/source/tests/universal/dpmodel/utils/test_type_embed.py index 1eec54de9d..eb5190b2c6 100644 --- a/source/tests/universal/dpmodel/utils/test_type_embed.py +++ b/source/tests/universal/dpmodel/utils/test_type_embed.py @@ -8,11 +8,15 @@ from ...common.cases.utils.type_embed import ( TypeEmbdTest, ) +from ...pt.utils.utils import ( + TEST_DEVICE, +) from ..backend import ( DPTestCase, ) +@unittest.skipIf(TEST_DEVICE != "cpu", "Only test on CPU.") class TestTypeEmbd(unittest.TestCase, TypeEmbdTest, DPTestCase): def setUp(self): TypeEmbdTest.setUp(self) diff --git a/source/tests/universal/pt/backend.py b/source/tests/universal/pt/backend.py index 10f5e2e29c..951bf18262 100644 --- a/source/tests/universal/pt/backend.py +++ b/source/tests/universal/pt/backend.py @@ -7,8 +7,12 @@ to_torch_tensor, ) +from ..common.backend import ( + BackendTestCase, +) + -class PTTestCase: +class PTTestCase(BackendTestCase): """Common test case.""" module: "torch.nn.Module" @@ -16,7 +20,8 @@ class PTTestCase: @property def script_module(self): - return torch.jit.script(self.module) + with torch.jit.optimized_execution(False): + return torch.jit.script(self.module) @property def deserialized_module(self): @@ -43,12 +48,24 @@ def convert_to_numpy(cls, xx: torch.Tensor) -> np.ndarray: def convert_from_numpy(cls, xx: np.ndarray) -> torch.Tensor: return to_torch_tensor(xx) - def forward_wrapper(self, module): + def forward_wrapper_cpu_ref(self, module): + module.to("cpu") + return self.forward_wrapper(module, on_cpu=True) + + def forward_wrapper(self, module, on_cpu=False): def create_wrapper_method(method): def wrapper_method(self, *args, **kwargs): # convert to torch tensor args = [to_torch_tensor(arg) for arg in args] kwargs = {k: to_torch_tensor(v) for k, v in kwargs.items()} + if on_cpu: + args = [ + arg.detach().cpu() if arg is not None else None for arg in args + ] + kwargs = { + k: v.detach().cpu() if v is not None else None + for k, v in kwargs.items() + } # forward output = method(*args, **kwargs) # convert to numpy array diff --git a/source/tests/universal/pt/model/test_model.py b/source/tests/universal/pt/model/test_model.py index 1a82c05b1e..7e45b85248 100644 --- a/source/tests/universal/pt/model/test_model.py +++ b/source/tests/universal/pt/model/test_model.py @@ -179,7 +179,8 @@ def setUpClass(cls): ): cls.skip_test_jit = True else: - cls._script_module = torch.jit.script(cls.module) + with torch.jit.optimized_execution(False): + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -275,7 +276,8 @@ def setUpClass(cls): ): cls.skip_test_jit = True else: - cls._script_module = torch.jit.script(cls.module) + with torch.jit.optimized_execution(False): + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -367,7 +369,8 @@ def setUpClass(cls): ): cls.skip_test_jit = True else: - cls._script_module = torch.jit.script(cls.module) + with torch.jit.optimized_execution(False): + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -455,7 +458,8 @@ def setUpClass(cls): ): cls.skip_test_jit = True else: - cls._script_module = torch.jit.script(cls.module) + with torch.jit.optimized_execution(False): + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() @@ -553,7 +557,8 @@ def setUpClass(cls): ): cls.skip_test_jit = True else: - cls._script_module = torch.jit.script(cls.module) + with torch.jit.optimized_execution(False): + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_dim_fparam = ft.get_dim_fparam() @@ -669,7 +674,8 @@ def setUpClass(cls): ): cls.skip_test_jit = True else: - cls._script_module = torch.jit.script(cls.module) + with torch.jit.optimized_execution(False): + cls._script_module = torch.jit.script(cls.module) cls.output_def = cls.module.translated_output_def() cls.expected_has_message_passing = ds.has_message_passing() cls.expected_sel_type = ft.get_sel_type() diff --git a/source/tests/universal/pt/utils/utils.py b/source/tests/universal/pt/utils/utils.py new file mode 100644 index 0000000000..e8cb1efcce --- /dev/null +++ b/source/tests/universal/pt/utils/utils.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import os + +import torch + +# maybe has more elegant way to get DEVICE +if os.environ.get("DEVICE") == "cpu" or torch.cuda.is_available() is False: + TEST_DEVICE = "cpu" +else: + TEST_DEVICE = "cuda" From ba63f7338815a752242c8efb00ff0d42cad3f370 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 27 Jun 2024 00:57:20 +0800 Subject: [PATCH 21/24] fix device --- .../model/atomic_model/linear_atomic_model.py | 7 ++++-- .../model/atomic_model/polar_atomic_model.py | 3 ++- deepmd/pt/model/descriptor/hybrid.py | 6 +++-- deepmd/pt/model/model/spin_model.py | 22 +++++++++---------- deepmd/pt/model/task/polarizability.py | 2 +- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/deepmd/pt/model/atomic_model/linear_atomic_model.py b/deepmd/pt/model/atomic_model/linear_atomic_model.py index ee0be75593..f06a04cd0d 100644 --- a/deepmd/pt/model/atomic_model/linear_atomic_model.py +++ b/deepmd/pt/model/atomic_model/linear_atomic_model.py @@ -224,7 +224,7 @@ def forward_atomic( ener_list = [] for i, model in enumerate(self.models): - type_map_model = self.mapping_list[i] + type_map_model = self.mapping_list[i].to(extended_atype.device) # apply bias to each individual model ener_list.append( model.forward_common_atomic( @@ -239,7 +239,10 @@ def forward_atomic( weights = self._compute_weight(extended_coord, extended_atype, nlists_) fit_ret = { - "energy": torch.sum(torch.stack(ener_list) * torch.stack(weights), dim=0), + "energy": torch.sum( + torch.stack(ener_list) * torch.stack(weights).to(extended_atype.device), + dim=0, + ), } # (nframes, nloc, 1) return fit_ret diff --git a/deepmd/pt/model/atomic_model/polar_atomic_model.py b/deepmd/pt/model/atomic_model/polar_atomic_model.py index 85320210ed..81cf8a23b6 100644 --- a/deepmd/pt/model/atomic_model/polar_atomic_model.py +++ b/deepmd/pt/model/atomic_model/polar_atomic_model.py @@ -49,7 +49,8 @@ def apply_out_stat( # (nframes, nloc, 1) modified_bias = ( - modified_bias.unsqueeze(-1) * self.fitting_net.scale[atype] + modified_bias.unsqueeze(-1) + * (self.fitting_net.scale.to(atype.device))[atype] ) eye = torch.eye(3, dtype=dtype, device=device) diff --git a/deepmd/pt/model/descriptor/hybrid.py b/deepmd/pt/model/descriptor/hybrid.py index 2f5f1bd786..41fb5e68e3 100644 --- a/deepmd/pt/model/descriptor/hybrid.py +++ b/deepmd/pt/model/descriptor/hybrid.py @@ -280,11 +280,13 @@ def forward( for ii, descrpt in enumerate(self.descrpt_list): # cut the nlist to the correct length if self.mixed_types() == descrpt.mixed_types(): - nl = nlist[:, :, self.nlist_cut_idx[ii]] + nl = nlist[:, :, self.nlist_cut_idx[ii].to(atype_ext.device)] else: # mixed_types is True, but descrpt.mixed_types is False assert nl_distinguish_types is not None - nl = nl_distinguish_types[:, :, self.nlist_cut_idx[ii]] + nl = nl_distinguish_types[ + :, :, self.nlist_cut_idx[ii].to(atype_ext.device) + ] odescriptor, gr, g2, h2, sw = descrpt(coord_ext, atype_ext, nl, mapping) out_descriptor.append(odescriptor) if gr is not None: diff --git a/deepmd/pt/model/model/spin_model.py b/deepmd/pt/model/model/spin_model.py index d9517a2feb..72e6797ea8 100644 --- a/deepmd/pt/model/model/spin_model.py +++ b/deepmd/pt/model/model/spin_model.py @@ -53,9 +53,9 @@ def process_spin_input(self, coord, atype, spin): coord = coord.reshape(nframes, nloc, 3) spin = spin.reshape(nframes, nloc, 3) atype_spin = torch.concat([atype, atype + self.ntypes_real], dim=-1) - virtual_coord = coord + spin * self.virtual_scale_mask[atype].reshape( - [nframes, nloc, 1] - ) + virtual_coord = coord + spin * (self.virtual_scale_mask.to(atype.device))[ + atype + ].reshape([nframes, nloc, 1]) coord_spin = torch.concat([coord, virtual_coord], dim=-2) return coord_spin, atype_spin @@ -77,11 +77,9 @@ def process_spin_input_lower( """ nframes, nall = extended_coord.shape[:2] nloc = nlist.shape[1] - virtual_extended_coord = ( - extended_coord - + extended_spin - * self.virtual_scale_mask[extended_atype].reshape([nframes, nall, 1]) - ) + virtual_extended_coord = extended_coord + extended_spin * ( + self.virtual_scale_mask.to(extended_atype.device) + )[extended_atype].reshape([nframes, nall, 1]) virtual_extended_atype = extended_atype + self.ntypes_real extended_coord_updated = self.concat_switch_virtual( extended_coord, virtual_extended_coord, nloc @@ -116,9 +114,9 @@ def process_spin_output( nframes, nloc_double = out_tensor.shape[:2] nloc = nloc_double // 2 if virtual_scale: - virtual_scale_mask = self.virtual_scale_mask + virtual_scale_mask = self.virtual_scale_mask.to(atype.device) else: - virtual_scale_mask = self.spin_mask + virtual_scale_mask = self.spin_mask.to(atype.device) atomic_mask = virtual_scale_mask[atype].reshape([nframes, nloc, 1]) out_real, out_mag = torch.split(out_tensor, [nloc, nloc], dim=1) if add_mag: @@ -144,9 +142,9 @@ def process_spin_output_lower( nframes, nall_double = extended_out_tensor.shape[:2] nall = nall_double // 2 if virtual_scale: - virtual_scale_mask = self.virtual_scale_mask + virtual_scale_mask = self.virtual_scale_mask.to(extended_atype.device) else: - virtual_scale_mask = self.spin_mask + virtual_scale_mask = self.spin_mask.to(extended_atype.device) atomic_mask = virtual_scale_mask[extended_atype].reshape([nframes, nall, 1]) extended_out_real = torch.cat( [ diff --git a/deepmd/pt/model/task/polarizability.py b/deepmd/pt/model/task/polarizability.py index 225299112f..4bf4e3c1c5 100644 --- a/deepmd/pt/model/task/polarizability.py +++ b/deepmd/pt/model/task/polarizability.py @@ -241,7 +241,7 @@ def forward( out = self._forward_common(descriptor, atype, gr, g2, h2, fparam, aparam)[ self.var_name ] - out = out * self.scale[atype] + out = out * (self.scale.to(atype.device))[atype] gr = gr.view(nframes * nloc, -1, 3) # (nframes * nloc, m1, 3) if self.fit_diag: From 860a01cc6bd902268dcfa52dd017622bc3599336 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 27 Jun 2024 01:11:05 +0800 Subject: [PATCH 22/24] Update utils.py --- source/tests/universal/common/cases/model/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index 7b26068659..6d8cfc1553 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -856,5 +856,8 @@ def test_device_consistence(self): assert rr is None else: np.testing.assert_allclose( - subret[0], rr, err_msg=f"compare {kk} between 0 and {ii}" + subret[0], + rr, + err_msg=f"compare {kk} between 0 and {ii}", + atol=1e-10, ) From 0f06f1761d4365e761c76b84c32aca56d6b882db Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Thu, 27 Jun 2024 13:48:57 +0800 Subject: [PATCH 23/24] use CUDA_VISIBLE_DEVICES --- source/tests/universal/common/cases/model/utils.py | 2 +- .../universal/dpmodel/atomc_model/test_atomic_model.py | 6 +++--- .../universal/dpmodel/descriptor/test_descriptor.py | 6 +++--- source/tests/universal/dpmodel/fitting/test_fitting.py | 6 +++--- source/tests/universal/dpmodel/model/test_model.py | 6 +++--- .../tests/universal/dpmodel/utils/test_type_embed.py | 6 +++--- source/tests/universal/pt/utils/utils.py | 10 ---------- source/tests/utils.py | 7 +++++++ 8 files changed, 23 insertions(+), 26 deletions(-) delete mode 100644 source/tests/universal/pt/utils/utils.py create mode 100644 source/tests/utils.py diff --git a/source/tests/universal/common/cases/model/utils.py b/source/tests/universal/common/cases/model/utils.py index 6d8cfc1553..68a5498d32 100644 --- a/source/tests/universal/common/cases/model/utils.py +++ b/source/tests/universal/common/cases/model/utils.py @@ -23,7 +23,7 @@ from .....seed import ( GLOBAL_SEED, ) -from ....pt.utils.utils import ( +from .....utils import ( TEST_DEVICE, ) diff --git a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py index 28cce08ef1..10ff269ef3 100644 --- a/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py +++ b/source/tests/universal/dpmodel/atomc_model/test_atomic_model.py @@ -24,6 +24,9 @@ from ....consistent.common import ( parameterized, ) +from ....utils import ( + TEST_DEVICE, +) from ...common.cases.atomic_model.atomic_model import ( DipoleAtomicModelTest, DosAtomicModelTest, @@ -48,9 +51,6 @@ from ...dpmodel.model.test_model import ( skip_model_tests, ) -from ...pt.utils.utils import ( - TEST_DEVICE, -) from ..backend import ( DPTestCase, ) diff --git a/source/tests/universal/dpmodel/descriptor/test_descriptor.py b/source/tests/universal/dpmodel/descriptor/test_descriptor.py index 89f57ccf1d..691e8312d4 100644 --- a/source/tests/universal/dpmodel/descriptor/test_descriptor.py +++ b/source/tests/universal/dpmodel/descriptor/test_descriptor.py @@ -24,12 +24,12 @@ from ....seed import ( GLOBAL_SEED, ) +from ....utils import ( + TEST_DEVICE, +) from ...common.cases.descriptor.descriptor import ( DescriptorTest, ) -from ...pt.utils.utils import ( - TEST_DEVICE, -) from ..backend import ( DPTestCase, ) diff --git a/source/tests/universal/dpmodel/fitting/test_fitting.py b/source/tests/universal/dpmodel/fitting/test_fitting.py index 7ee9c835af..5bf4e2d45c 100644 --- a/source/tests/universal/dpmodel/fitting/test_fitting.py +++ b/source/tests/universal/dpmodel/fitting/test_fitting.py @@ -18,12 +18,12 @@ from ....seed import ( GLOBAL_SEED, ) +from ....utils import ( + TEST_DEVICE, +) from ...common.cases.fitting.fitting import ( FittingTest, ) -from ...pt.utils.utils import ( - TEST_DEVICE, -) from ..backend import ( DPTestCase, ) diff --git a/source/tests/universal/dpmodel/model/test_model.py b/source/tests/universal/dpmodel/model/test_model.py index 1ff82dc05e..aa735977d5 100644 --- a/source/tests/universal/dpmodel/model/test_model.py +++ b/source/tests/universal/dpmodel/model/test_model.py @@ -23,13 +23,13 @@ from ....consistent.common import ( parameterized, ) +from ....utils import ( + TEST_DEVICE, +) from ...common.cases.model.model import ( EnerModelTest, SpinEnerModelTest, ) -from ...pt.utils.utils import ( - TEST_DEVICE, -) from ..backend import ( DPTestCase, ) diff --git a/source/tests/universal/dpmodel/utils/test_type_embed.py b/source/tests/universal/dpmodel/utils/test_type_embed.py index eb5190b2c6..67faef0a8d 100644 --- a/source/tests/universal/dpmodel/utils/test_type_embed.py +++ b/source/tests/universal/dpmodel/utils/test_type_embed.py @@ -5,12 +5,12 @@ TypeEmbedNet, ) +from ....utils import ( + TEST_DEVICE, +) from ...common.cases.utils.type_embed import ( TypeEmbdTest, ) -from ...pt.utils.utils import ( - TEST_DEVICE, -) from ..backend import ( DPTestCase, ) diff --git a/source/tests/universal/pt/utils/utils.py b/source/tests/universal/pt/utils/utils.py deleted file mode 100644 index e8cb1efcce..0000000000 --- a/source/tests/universal/pt/utils/utils.py +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -import os - -import torch - -# maybe has more elegant way to get DEVICE -if os.environ.get("DEVICE") == "cpu" or torch.cuda.is_available() is False: - TEST_DEVICE = "cpu" -else: - TEST_DEVICE = "cuda" diff --git a/source/tests/utils.py b/source/tests/utils.py new file mode 100644 index 0000000000..694f55186e --- /dev/null +++ b/source/tests/utils.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import os + +if os.environ.get("CUDA_VISIBLE_DEVICES") is None: + TEST_DEVICE = "cpu" +else: + TEST_DEVICE = "cuda" From 383828110e728558eaad3b1616e58cd245670681 Mon Sep 17 00:00:00 2001 From: Duo <50307526+iProzd@users.noreply.github.com> Date: Fri, 28 Jun 2024 01:11:36 +0800 Subject: [PATCH 24/24] Update test_cuda.yml --- .github/workflows/test_cuda.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test_cuda.yml b/.github/workflows/test_cuda.yml index 57ff4d0463..b1634e890f 100644 --- a/.github/workflows/test_cuda.yml +++ b/.github/workflows/test_cuda.yml @@ -60,6 +60,7 @@ jobs: - run: python -m pytest source/tests --durations=0 env: NUM_WORKERS: 0 + CUDA_VISIBLE_DEVICES: 0 - name: Download libtorch run: | wget https://download.pytorch.org/libtorch/cu121/libtorch-cxx11-abi-shared-with-deps-2.2.1%2Bcu121.zip -O libtorch.zip