Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: support exclude atypes in atomic model #3357

Merged
merged 12 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions deepmd/dpmodel/atomic_model/make_base_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@
def get_type_map(self) -> Optional[List[str]]:
"""Get the type map."""

def get_ntypes(self) -> int:
"""Get the number of atom types."""
tmap = self.get_type_map()
if tmap is not None:
return len(tmap)

Check warning on line 55 in deepmd/dpmodel/atomic_model/make_base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/atomic_model/make_base_atomic_model.py#L53-L55

Added lines #L53 - L55 were not covered by tests
else:
raise ValueError(

Check warning on line 57 in deepmd/dpmodel/atomic_model/make_base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/atomic_model/make_base_atomic_model.py#L57

Added line #L57 was not covered by tests
"cannot infer the number of types from a None type map"
)

@abstractmethod
def get_sel(self) -> List[int]:
"""Returns the number of selected atoms for each type."""
Expand Down
79 changes: 79 additions & 0 deletions deepmd/pt/model/atomic_model/base_atomic_model.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,99 @@
# SPDX-License-Identifier: LGPL-3.0-or-later


from typing import (

Check warning on line 4 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L4

Added line #L4 was not covered by tests
Dict,
List,
Optional,
Tuple,
)

import torch

from deepmd.dpmodel.atomic_model import (
make_base_atomic_model,
)
from deepmd.pt.utils import (

Check warning on line 16 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L16

Added line #L16 was not covered by tests
AtomExcludeMask,
PairExcludeMask,
)

BaseAtomicModel_ = make_base_atomic_model(torch.Tensor)


class BaseAtomicModel(BaseAtomicModel_):
def __init__(

Check warning on line 25 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L25

Added line #L25 was not covered by tests
self,
atom_exclude_types: List[int] = [],
pair_exclude_types: List[Tuple[int, int]] = [],
):
super().__init__()
self.reinit_atom_exclude(atom_exclude_types)
self.reinit_pair_exclude(pair_exclude_types)

Check warning on line 32 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L30-L32

Added lines #L30 - L32 were not covered by tests

def reinit_atom_exclude(

Check warning on line 34 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L34

Added line #L34 was not covered by tests
self,
exclude_types: List[int] = [],
):
self.atom_exclude_types = exclude_types
if exclude_types == []:
self.atom_excl = None

Check warning on line 40 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L38-L40

Added lines #L38 - L40 were not covered by tests
else:
self.atom_excl = AtomExcludeMask(self.get_ntypes(), self.atom_exclude_types)

Check warning on line 42 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L42

Added line #L42 was not covered by tests

def reinit_pair_exclude(

Check warning on line 44 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L44

Added line #L44 was not covered by tests
self,
exclude_types: List[Tuple[int, int]] = [],
):
self.pair_exclude_types = exclude_types
if exclude_types == []:
self.pair_excl = None

Check warning on line 50 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L48-L50

Added lines #L48 - L50 were not covered by tests
else:
self.pair_excl = PairExcludeMask(self.get_ntypes(), self.pair_exclude_types)

Check warning on line 52 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L52

Added line #L52 was not covered by tests

# export public methods that are not abstract
get_nsel = torch.jit.export(BaseAtomicModel_.get_nsel)
get_nnei = torch.jit.export(BaseAtomicModel_.get_nnei)

@torch.jit.export
def get_model_def_script(self) -> str:
return self.model_def_script

def forward_common_atomic(

Check warning on line 62 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L62

Added line #L62 was not covered by tests
self,
extended_coord: torch.Tensor,
extended_atype: torch.Tensor,
nlist: torch.Tensor,
mapping: Optional[torch.Tensor] = None,
fparam: Optional[torch.Tensor] = None,
aparam: Optional[torch.Tensor] = None,
) -> Dict[str, torch.Tensor]:
nf, nloc, nnei = nlist.shape
nf, nall = extended_atype.shape
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
atype = extended_atype[:, :nloc]
if self.pair_excl is not None:
pair_mask = self.pair_excl(nlist, extended_atype)

Check warning on line 75 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L71-L75

Added lines #L71 - L75 were not covered by tests
# exclude neighbors in the nlist
nlist = torch.where(pair_mask == 1, nlist, -1)

Check warning on line 77 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L77

Added line #L77 was not covered by tests

ret_dict = self.forward_atomic(

Check warning on line 79 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L79

Added line #L79 was not covered by tests
extended_coord,
extended_atype,
nlist,
mapping=mapping,
fparam=fparam,
aparam=aparam,
)

if self.atom_excl is not None:
atom_mask = self.atom_excl(atype)
for kk in ret_dict.keys():
ret_dict[kk] = ret_dict[kk] * atom_mask[:, :, None]

Check warning on line 91 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L88-L91

Added lines #L88 - L91 were not covered by tests

return ret_dict

Check warning on line 93 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L93

Added line #L93 was not covered by tests

def serialize(self) -> dict:
return {

Check warning on line 96 in deepmd/pt/model/atomic_model/base_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/base_atomic_model.py#L95-L96

Added lines #L95 - L96 were not covered by tests
"atom_exclude_types": self.atom_exclude_types,
"pair_exclude_types": self.pair_exclude_types,
}
41 changes: 28 additions & 13 deletions deepmd/pt/model/atomic_model/dp_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@
For example `type_map[1]` gives the name of the type 1.
"""

def __init__(self, descriptor, fitting, type_map: Optional[List[str]]):
super().__init__()
def __init__(

Check warning on line 52 in deepmd/pt/model/atomic_model/dp_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/dp_atomic_model.py#L52

Added line #L52 was not covered by tests
self,
descriptor,
fitting,
type_map: Optional[List[str]],
**kwargs,
):
torch.nn.Module.__init__(self)

Check warning on line 59 in deepmd/pt/model/atomic_model/dp_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/dp_atomic_model.py#L59

Added line #L59 was not covered by tests
self.model_def_script = ""
ntypes = len(type_map)
self.type_map = type_map
Expand All @@ -59,6 +65,8 @@
self.rcut = self.descriptor.get_rcut()
self.sel = self.descriptor.get_sel()
self.fitting_net = fitting
# order matters ntypes and type_map should be initialized first.
BaseAtomicModel.__init__(self, **kwargs)

Check warning on line 69 in deepmd/pt/model/atomic_model/dp_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/dp_atomic_model.py#L69

Added line #L69 was not covered by tests

def fitting_output_def(self) -> FittingOutputDef:
"""Get the output def of the fitting net."""
Expand Down Expand Up @@ -95,22 +103,29 @@
return self.descriptor.mixed_types()

def serialize(self) -> dict:
return {
"@class": "Model",
"type": "standard",
"@version": 1,
"type_map": self.type_map,
"descriptor": self.descriptor.serialize(),
"fitting": self.fitting_net.serialize(),
}
dd = BaseAtomicModel.serialize(self)
dd.update(

Check warning on line 107 in deepmd/pt/model/atomic_model/dp_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/dp_atomic_model.py#L106-L107

Added lines #L106 - L107 were not covered by tests
{
"@class": "Model",
"@version": 1,
"type": "standard",
"type_map": self.type_map,
"descriptor": self.descriptor.serialize(),
"fitting": self.fitting_net.serialize(),
}
)
return dd

Check warning on line 117 in deepmd/pt/model/atomic_model/dp_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/dp_atomic_model.py#L117

Added line #L117 was not covered by tests

@classmethod
def deserialize(cls, data) -> "DPAtomicModel":
data = copy.deepcopy(data)
check_version_compatibility(data.pop("@version", 1), 1, 1)
descriptor_obj = BaseDescriptor.deserialize(data["descriptor"])
fitting_obj = BaseFitting.deserialize(data["fitting"])
obj = cls(descriptor_obj, fitting_obj, type_map=data["type_map"])
data.pop("@class", None)
data.pop("type", None)
descriptor_obj = BaseDescriptor.deserialize(data.pop("descriptor"))
fitting_obj = BaseFitting.deserialize(data.pop("fitting"))
type_map = data.pop("type_map", None)
obj = cls(descriptor_obj, fitting_obj, type_map=type_map, **data)

Check warning on line 128 in deepmd/pt/model/atomic_model/dp_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/dp_atomic_model.py#L123-L128

Added lines #L123 - L128 were not covered by tests
return obj

def forward_atomic(
Expand Down
36 changes: 22 additions & 14 deletions deepmd/pt/model/atomic_model/linear_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@
models: List[BaseAtomicModel],
**kwargs,
):
super().__init__()
torch.nn.Module.__init__(self)

Check warning on line 57 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L57

Added line #L57 was not covered by tests
self.models = torch.nn.ModuleList(models)
self.atomic_bias = None
self.mixed_types_list = [model.mixed_types() for model in self.models]
BaseAtomicModel.__init__(self, **kwargs)

Check warning on line 61 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L61

Added line #L61 was not covered by tests

def mixed_types(self) -> bool:
"""If true, the model
Expand Down Expand Up @@ -307,32 +308,39 @@
self.zbl_weight = torch.empty(0, dtype=torch.float64, device=env.DEVICE)

def serialize(self) -> dict:
return {
"@class": "Model",
"type": "zbl",
"@version": 1,
"models": LinearAtomicModel.serialize([self.dp_model, self.zbl_model]),
"sw_rmin": self.sw_rmin,
"sw_rmax": self.sw_rmax,
"smin_alpha": self.smin_alpha,
}
dd = BaseAtomicModel.serialize(self)
dd.update(

Check warning on line 312 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L311-L312

Added lines #L311 - L312 were not covered by tests
{
"@class": "Model",
"@version": 1,
"type": "zbl",
"models": LinearAtomicModel.serialize([self.dp_model, self.zbl_model]),
"sw_rmin": self.sw_rmin,
"sw_rmax": self.sw_rmax,
"smin_alpha": self.smin_alpha,
}
)
return dd

Check warning on line 323 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L323

Added line #L323 was not covered by tests

@classmethod
def deserialize(cls, data) -> "DPZBLLinearAtomicModel":
data = copy.deepcopy(data)
check_version_compatibility(data.pop("@version", 1), 1, 1)
sw_rmin = data["sw_rmin"]
sw_rmax = data["sw_rmax"]
smin_alpha = data["smin_alpha"]
sw_rmin = data.pop("sw_rmin")
sw_rmax = data.pop("sw_rmax")
smin_alpha = data.pop("smin_alpha")

Check warning on line 331 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L329-L331

Added lines #L329 - L331 were not covered by tests

dp_model, zbl_model = LinearAtomicModel.deserialize(data["models"])
dp_model, zbl_model = LinearAtomicModel.deserialize(data.pop("models"))

Check warning on line 333 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L333

Added line #L333 was not covered by tests

data.pop("@class", None)
data.pop("type", None)

Check warning on line 336 in deepmd/pt/model/atomic_model/linear_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/linear_atomic_model.py#L335-L336

Added lines #L335 - L336 were not covered by tests
return cls(
dp_model=dp_model,
zbl_model=zbl_model,
sw_rmin=sw_rmin,
sw_rmax=sw_rmax,
smin_alpha=smin_alpha,
**data,
)

def _compute_weight(
Expand Down
33 changes: 20 additions & 13 deletions deepmd/pt/model/atomic_model/pairtab_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@
def __init__(
self, tab_file: str, rcut: float, sel: Union[int, List[int]], **kwargs
):
super().__init__()
torch.nn.Module.__init__(self)

Check warning on line 55 in deepmd/pt/model/atomic_model/pairtab_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/pairtab_atomic_model.py#L55

Added line #L55 was not covered by tests
self.model_def_script = ""
self.tab_file = tab_file
self.rcut = rcut
self.tab = self._set_pairtab(tab_file, rcut)
BaseAtomicModel.__init__(self, **kwargs)

Check warning on line 60 in deepmd/pt/model/atomic_model/pairtab_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/pairtab_atomic_model.py#L60

Added line #L60 was not covered by tests

# handle deserialization with no input file
if self.tab_file is not None:
Expand Down Expand Up @@ -125,23 +126,29 @@
return True

def serialize(self) -> dict:
return {
"@class": "Model",
"type": "pairtab",
"@version": 1,
"tab": self.tab.serialize(),
"rcut": self.rcut,
"sel": self.sel,
}
dd = BaseAtomicModel.serialize(self)
dd.update(

Check warning on line 130 in deepmd/pt/model/atomic_model/pairtab_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/pairtab_atomic_model.py#L129-L130

Added lines #L129 - L130 were not covered by tests
{
"@class": "Model",
"@version": 1,
"type": "pairtab",
"tab": self.tab.serialize(),
"rcut": self.rcut,
"sel": self.sel,
}
)
return dd

Check warning on line 140 in deepmd/pt/model/atomic_model/pairtab_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/pairtab_atomic_model.py#L140

Added line #L140 was not covered by tests

@classmethod
def deserialize(cls, data) -> "PairTabAtomicModel":
data = copy.deepcopy(data)
check_version_compatibility(data.pop("@version", 1), 1, 1)
rcut = data["rcut"]
sel = data["sel"]
tab = PairTab.deserialize(data["tab"])
tab_model = cls(None, rcut, sel)
rcut = data.pop("rcut")
sel = data.pop("sel")
tab = PairTab.deserialize(data.pop("tab"))
data.pop("@class", None)
data.pop("type", None)
tab_model = cls(None, rcut, sel, **data)

Check warning on line 151 in deepmd/pt/model/atomic_model/pairtab_atomic_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/atomic_model/pairtab_atomic_model.py#L146-L151

Added lines #L146 - L151 were not covered by tests
tab_model.tab = tab
tab_model.register_buffer("tab_info", torch.from_numpy(tab_model.tab.tab_info))
tab_model.register_buffer("tab_data", torch.from_numpy(tab_model.tab.tab_data))
Expand Down
18 changes: 16 additions & 2 deletions deepmd/pt/model/descriptor/se_a.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@
"""Update mean and stddev for descriptor elements."""
return self.sea.compute_input_stats(merged, path)

def reinit_exclude(

Check warning on line 136 in deepmd/pt/model/descriptor/se_a.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/descriptor/se_a.py#L136

Added line #L136 was not covered by tests
self,
exclude_types: List[Tuple[int, int]] = [],
):
"""Update the type exclusions."""
self.sea.reinit_exclude(exclude_types)

Check warning on line 141 in deepmd/pt/model/descriptor/se_a.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/descriptor/se_a.py#L141

Added line #L141 was not covered by tests

def forward(
self,
coord_ext: torch.Tensor,
Expand Down Expand Up @@ -271,10 +278,10 @@
self.prec = PRECISION_DICT[self.precision]
self.resnet_dt = resnet_dt
self.old_impl = old_impl
self.exclude_types = exclude_types
self.ntypes = len(sel)
self.emask = PairExcludeMask(len(sel), exclude_types=exclude_types)
self.type_one_side = type_one_side
# order matters, placed after the assignment of self.ntypes
self.reinit_exclude(exclude_types)

Check warning on line 284 in deepmd/pt/model/descriptor/se_a.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/descriptor/se_a.py#L284

Added line #L284 was not covered by tests

self.sel = sel
self.sec = torch.tensor(
Expand Down Expand Up @@ -407,6 +414,13 @@
)
return self.stats

def reinit_exclude(

Check warning on line 417 in deepmd/pt/model/descriptor/se_a.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/descriptor/se_a.py#L417

Added line #L417 was not covered by tests
self,
exclude_types: List[Tuple[int, int]] = [],
):
self.exclude_types = exclude_types
self.emask = PairExcludeMask(self.ntypes, exclude_types=exclude_types)

Check warning on line 422 in deepmd/pt/model/descriptor/se_a.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/descriptor/se_a.py#L421-L422

Added lines #L421 - L422 were not covered by tests

def forward(
self,
nlist: torch.Tensor,
Expand Down
2 changes: 1 addition & 1 deletion deepmd/pt/model/model/make_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
nframes, nall = extended_atype.shape[:2]
extended_coord = extended_coord.view(nframes, -1, 3)
nlist = self.format_nlist(extended_coord, extended_atype, nlist)
atomic_ret = self.forward_atomic(
atomic_ret = self.forward_common_atomic(

Check warning on line 196 in deepmd/pt/model/model/make_model.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/model/make_model.py#L196

Added line #L196 was not covered by tests
extended_coord,
extended_atype,
nlist,
Expand Down
12 changes: 9 additions & 3 deletions deepmd/pt/model/task/fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,8 @@
self.precision = precision
self.prec = PRECISION_DICT[self.precision]
self.rcond = rcond
self.exclude_types = exclude_types

self.emask = AtomExcludeMask(self.ntypes, self.exclude_types)
# order matters, should be place after the assignment of ntypes
self.reinit_exclude(exclude_types)

Check warning on line 292 in deepmd/pt/model/task/fitting.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/task/fitting.py#L292

Added line #L292 was not covered by tests

net_dim_out = self._net_out_dim()
# init constants
Expand Down Expand Up @@ -366,6 +365,13 @@
log.info("Set seed to %d in fitting net.", seed)
torch.manual_seed(seed)

def reinit_exclude(

Check warning on line 368 in deepmd/pt/model/task/fitting.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/task/fitting.py#L368

Added line #L368 was not covered by tests
self,
exclude_types: List[int] = [],
):
self.exclude_types = exclude_types
self.emask = AtomExcludeMask(self.ntypes, self.exclude_types)

Check warning on line 373 in deepmd/pt/model/task/fitting.py

View check run for this annotation

Codecov / codecov/patch

deepmd/pt/model/task/fitting.py#L372-L373

Added lines #L372 - L373 were not covered by tests

def serialize(self) -> dict:
"""Serialize the fitting to dict."""
return {
Expand Down
Loading
Loading