nmag-python-3 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anisotropy/__init__.py +28 -0
- anisotropy/anisotropy.py +13 -0
- anisotropy/evaluation.py +70 -0
- anisotropy/model.py +200 -0
- anisotropy/predefined.py +202 -0
- anisotropy/py.typed +1 -0
- anisotropy/values.py +84 -0
- mag_material/__init__.py +3 -0
- mag_material/mag_material.py +231 -0
- mag_material/parameters.py +150 -0
- mag_material/py.typed +1 -0
- nmag/__init__.py +36 -0
- nmag/backends.py +493 -0
- nmag/checkpoint.py +327 -0
- nmag/config.py +174 -0
- nmag/demag/__init__.py +39 -0
- nmag/demag/bem_operator.py +149 -0
- nmag/demag/geometry.py +134 -0
- nmag/demag/lindholm.py +133 -0
- nmag/demag/lindholm_fast.py +463 -0
- nmag/demag/linear.py +489 -0
- nmag/dynamics/__init__.py +255 -0
- nmag/output.py +27 -0
- nmag/parallel.py +45 -0
- nmag/py.typed +1 -0
- nmag/resources.py +38 -0
- nmag/simulation/__init__.py +519 -0
- nmag/simulation/anisotropy/__init__.py +5 -0
- nmag/simulation/anisotropy/fields.py +56 -0
- nmag/simulation/anisotropy/materials.py +138 -0
- nmag/simulation/demag/__init__.py +1 -0
- nmag/simulation/demag/bem/__init__.py +11 -0
- nmag/simulation/demag/bem/diagnostics.py +73 -0
- nmag/simulation/demag/bem/dirichlet.py +85 -0
- nmag/simulation/demag/bem/hierarchical.py +74 -0
- nmag/simulation/demag/bem/operator.py +292 -0
- nmag/simulation/demag/fem/__init__.py +11 -0
- nmag/simulation/demag/fem/assembly.py +114 -0
- nmag/simulation/demag/fem/charges.py +38 -0
- nmag/simulation/demag/fem/geometry.py +261 -0
- nmag/simulation/demag/fields/__init__.py +11 -0
- nmag/simulation/demag/fields/auxiliary.py +186 -0
- nmag/simulation/demag/fields/probe.py +77 -0
- nmag/simulation/demag/fields/recovery.py +207 -0
- nmag/simulation/demag/solver.py +17 -0
- nmag/simulation/dynamics/__init__.py +92 -0
- nmag/simulation/dynamics/advance.py +199 -0
- nmag/simulation/dynamics/integrator.py +263 -0
- nmag/simulation/exchange/__init__.py +13 -0
- nmag/simulation/exchange/coefficients.py +185 -0
- nmag/simulation/exchange/fields.py +106 -0
- nmag/simulation/exchange/llg_rhs.py +218 -0
- nmag/simulation/fields/__init__.py +19 -0
- nmag/simulation/fields/arrays.py +111 -0
- nmag/simulation/fields/availability.py +188 -0
- nmag/simulation/fields/averages.py +293 -0
- nmag/simulation/fields/derived.py +164 -0
- nmag/simulation/fields/maxangle.py +163 -0
- nmag/simulation/fields/probes.py +106 -0
- nmag/simulation/implicit_dynamics.py +221 -0
- nmag/simulation/mesh/__init__.py +13 -0
- nmag/simulation/mesh/geometry.py +153 -0
- nmag/simulation/mesh/materials.py +299 -0
- nmag/simulation/mesh/probe.py +234 -0
- nmag/simulation/restart.py +103 -0
- nmag/simulation/support.py +224 -0
- nmag_python_3-0.0.2.dist-info/METADATA +157 -0
- nmag_python_3-0.0.2.dist-info/RECORD +147 -0
- nmag_python_3-0.0.2.dist-info/WHEEL +5 -0
- nmag_python_3-0.0.2.dist-info/licenses/LICENSE +339 -0
- nmag_python_3-0.0.2.dist-info/top_level.txt +8 -0
- nmesh/__init__.py +130 -0
- nmesh/backend.py +286 -0
- nmesh/geometry/__init__.py +52 -0
- nmesh/geometry/boolean_operations.py +157 -0
- nmesh/geometry/primitives.py +453 -0
- nmesh/geometry/transform.py +126 -0
- nmesh/io/__init__.py +50 -0
- nmesh/io/ascii.py +132 -0
- nmesh/io/legacy_nmesh_hdf5.py +318 -0
- nmesh/io/meshio_support.py +170 -0
- nmesh/mesh_generation.py +182 -0
- nmesh/mesh_io.py +227 -0
- nmesh/mesh_model.py +147 -0
- nmesh/mesh_utilities.py +79 -0
- nmesh/mesher/__init__.py +21 -0
- nmesh/mesher/driver.py +146 -0
- nmesh/mesher/meshing_defaults.py +252 -0
- nmesh/mesher/meshing_parameters.py +185 -0
- nmesh/mesher/parity.py +21 -0
- nmesh/mesher/parity_canonical.py +142 -0
- nmesh/mesher/parity_comparison.py +191 -0
- nmesh/mesher/parity_metrics.py +114 -0
- nmesh/mesher/periodic.py +97 -0
- nmesh/mesher/relaxation/__init__.py +14 -0
- nmesh/mesher/relaxation/_constants.py +20 -0
- nmesh/mesher/relaxation/_types.py +15 -0
- nmesh/mesher/relaxation/density.py +170 -0
- nmesh/mesher/relaxation/engine/__init__.py +18 -0
- nmesh/mesher/relaxation/engine/state.py +155 -0
- nmesh/mesher/relaxation/engine/steps.py +248 -0
- nmesh/mesher/relaxation/engine/topology.py +230 -0
- nmesh/mesher/relaxation/forces/__init__.py +96 -0
- nmesh/mesher/relaxation/forces/jit.py +102 -0
- nmesh/mesher/relaxation/forces/neighbors.py +186 -0
- nmesh/mesher/relaxation/forces/simplex.py +302 -0
- nmesh/mesher/relaxation/forces/summary.py +207 -0
- nmesh/mesher/relaxation/forces/types.py +92 -0
- nmesh/mesher/relaxation/geometry/__init__.py +6 -0
- nmesh/mesher/relaxation/geometry/builder.py +154 -0
- nmesh/mesher/relaxation/geometry/model.py +194 -0
- nmesh/mesher/relaxation/seeding/__init__.py +74 -0
- nmesh/mesher/relaxation/seeding/periodic.py +88 -0
- nmesh/mesher/relaxation/seeding/points.py +88 -0
- nmesh/mesher/relaxation/seeding/sampling.py +142 -0
- nmesh/mesher/relaxation/topology/__init__.py +297 -0
- nmesh/mesher/relaxation/topology/finalize.py +78 -0
- nmesh/mesher/relaxation/topology/recovery.py +310 -0
- nmesh/mesher/sectioned_config.py +70 -0
- nmesh/nmesh.py +99 -0
- nmesh/py.typed +1 -0
- nmesh/utils/__init__.py +33 -0
- nmesh/utils/array_list_utils.py +128 -0
- nmesh/utils/constants.py +22 -0
- nmesh/utils/timing_memory_utils.py +51 -0
- nmesh/utils/types.py +13 -0
- si/constants.py +49 -0
- si/physical.py +722 -0
- si/py.typed +1 -0
- simulation/__init__.py +1 -0
- simulation/clock.py +237 -0
- simulation/data_writer.py +273 -0
- simulation/data_writer_collection.py +267 -0
- simulation/hysteresis.py +74 -0
- simulation/hysteresis_runner.py +286 -0
- simulation/hysteresis_schedule.py +180 -0
- simulation/inference/__init__.py +3 -0
- simulation/inference/inference.py +95 -0
- simulation/py.typed +1 -0
- simulation/quantity.py +88 -0
- simulation/simulation_core.py +458 -0
- throttler/__init__.py +3 -0
- throttler/py.typed +1 -0
- throttler/throttler.py +55 -0
- when/__init__.py +3 -0
- when/py.typed +1 -0
- when/when.py +416 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Definition of the MagMaterial class, which allows to define a magnetic
|
|
3
|
+
material and all its parameters (saturation magnetisation, exchange coupling,
|
|
4
|
+
etc.)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any, Protocol, cast
|
|
9
|
+
|
|
10
|
+
from anisotropy import PredefinedAnisotropy
|
|
11
|
+
from si.physical import SI
|
|
12
|
+
|
|
13
|
+
from .parameters import (
|
|
14
|
+
AnisotropyFunction,
|
|
15
|
+
MaterialScalar,
|
|
16
|
+
resolve_material_parameters,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
log = logging.getLogger("nmag")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _SIConstants(Protocol):
|
|
23
|
+
boltzmann_constant: SI
|
|
24
|
+
gamma0: SI
|
|
25
|
+
mu0: SI
|
|
26
|
+
bohr_magneton: SI
|
|
27
|
+
positron_charge: SI
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
_constants_cache: _SIConstants | None = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _si_constants() -> _SIConstants:
|
|
34
|
+
global _constants_cache
|
|
35
|
+
if _constants_cache is None:
|
|
36
|
+
from si import constants
|
|
37
|
+
|
|
38
|
+
_constants_cache = cast(_SIConstants, constants)
|
|
39
|
+
return _constants_cache
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MagMaterial:
|
|
43
|
+
"""Define the physical parameters assigned to a magnetic mesh region.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
name: Unique material name used in field and output labels.
|
|
47
|
+
Ms: Saturation magnetization, compatible with A/m.
|
|
48
|
+
llg_damping: Dimensionless Gilbert damping coefficient.
|
|
49
|
+
llg_gamma_G: Gyromagnetic ratio used by the LLG equation.
|
|
50
|
+
llg_normalisationfactor: Coefficient for numerical norm correction.
|
|
51
|
+
llg_xi: Dimensionless nonadiabatic Zhang-Li coefficient.
|
|
52
|
+
llg_polarisation: Dimensionless spin-current polarization.
|
|
53
|
+
do_precession: Include the precessional LLG term when true.
|
|
54
|
+
exchange_coupling: Exchange constant, compatible with J/m.
|
|
55
|
+
anisotropy: Predefined anisotropy or custom energy callable.
|
|
56
|
+
anisotropy_order: Polynomial order required for a custom callable.
|
|
57
|
+
properties: Compatibility property labels. Most users should omit this.
|
|
58
|
+
scale_volume_charges: Multiplier for interior demagnetization volume
|
|
59
|
+
charge. Boundary surface charges remain physical and unscaled.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
TypeError: If a parameter has an unsupported type or dimensions.
|
|
63
|
+
ValueError: If a value is non-finite, physically invalid, or a custom
|
|
64
|
+
anisotropy omits its order.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
name: str,
|
|
70
|
+
Ms: SI | None = None,
|
|
71
|
+
llg_damping: MaterialScalar = 0.5,
|
|
72
|
+
llg_gamma_G: SI | None = None,
|
|
73
|
+
llg_normalisationfactor: SI | None = None,
|
|
74
|
+
llg_xi: MaterialScalar = 0.0,
|
|
75
|
+
llg_polarisation: MaterialScalar = 0.0,
|
|
76
|
+
do_precession: bool = True,
|
|
77
|
+
exchange_coupling: SI | None = None,
|
|
78
|
+
anisotropy: PredefinedAnisotropy | AnisotropyFunction | None = None,
|
|
79
|
+
anisotropy_order: int | None = None,
|
|
80
|
+
properties: list[str] | None = None,
|
|
81
|
+
scale_volume_charges: float = 1.0,
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Initialize a material after validating units and physical values."""
|
|
84
|
+
parameters = resolve_material_parameters(
|
|
85
|
+
name,
|
|
86
|
+
ms=Ms,
|
|
87
|
+
damping=llg_damping,
|
|
88
|
+
gamma=llg_gamma_G,
|
|
89
|
+
normalisation=llg_normalisationfactor,
|
|
90
|
+
xi=llg_xi,
|
|
91
|
+
polarisation=llg_polarisation,
|
|
92
|
+
do_precession=do_precession,
|
|
93
|
+
exchange=exchange_coupling,
|
|
94
|
+
anisotropy=anisotropy,
|
|
95
|
+
anisotropy_order=anisotropy_order,
|
|
96
|
+
properties=properties,
|
|
97
|
+
scale_volume_charges=scale_volume_charges,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self.name = name
|
|
101
|
+
self.Ms = parameters.ms
|
|
102
|
+
self.llg_gamma_G = parameters.gamma
|
|
103
|
+
self.llg_damping = parameters.damping
|
|
104
|
+
self.llg_normalisationfactor = parameters.normalisation
|
|
105
|
+
self.llg_xi = parameters.xi
|
|
106
|
+
self.llg_polarisation = parameters.polarisation
|
|
107
|
+
self.do_precession = parameters.do_precession
|
|
108
|
+
self.properties = parameters.properties
|
|
109
|
+
self.exchange_coupling = parameters.exchange
|
|
110
|
+
self.scale_volume_charges = parameters.scale_volume_charges
|
|
111
|
+
self.anisotropy = parameters.anisotropy
|
|
112
|
+
self.anisotropy_order = parameters.anisotropy_order
|
|
113
|
+
|
|
114
|
+
# SU units units for backwards compatibility, they used to be stripped
|
|
115
|
+
# of units, but now we can do calculations with the units attached
|
|
116
|
+
self.su_Ms = self.Ms
|
|
117
|
+
self.su_llg_gamma_G = self.llg_gamma_G
|
|
118
|
+
self.su_llg_damping = self.llg_damping
|
|
119
|
+
self.su_llg_normalisationfactor = self.llg_normalisationfactor
|
|
120
|
+
self.su_exchange_coupling = self.exchange_coupling
|
|
121
|
+
|
|
122
|
+
gilbert_to_ll = 1.0 / (1.0 + self.su_llg_damping**2)
|
|
123
|
+
self.su_llg_coeff1 = -self.su_llg_gamma_G * gilbert_to_ll
|
|
124
|
+
self.su_llg_coeff2 = self.su_llg_coeff1 * self.su_llg_damping
|
|
125
|
+
|
|
126
|
+
if not self.do_precession:
|
|
127
|
+
log.info(
|
|
128
|
+
"Setting su_llg_coeff1 to zero; thus no precession for material '%s'", self.name
|
|
129
|
+
)
|
|
130
|
+
self.su_llg_coeff1 = 0.0
|
|
131
|
+
|
|
132
|
+
self.su_anisotropy = self.anisotropy
|
|
133
|
+
self._derived_su_constants: dict[str, MaterialScalar] | None = None
|
|
134
|
+
|
|
135
|
+
self.extended_print = False
|
|
136
|
+
if log.isEnabledFor(logging.INFO):
|
|
137
|
+
log.info("Created new Material:\n %s", self)
|
|
138
|
+
|
|
139
|
+
def _derived_su_values(self) -> dict[str, MaterialScalar]:
|
|
140
|
+
if self._derived_su_constants is None:
|
|
141
|
+
constants = _si_constants()
|
|
142
|
+
thermal_factor = (2.0 * constants.boltzmann_constant * self.llg_damping) / (
|
|
143
|
+
-constants.gamma0 * constants.mu0 * self.Ms
|
|
144
|
+
)
|
|
145
|
+
gilbert_to_ll = 1.0 / (1.0 + self.su_llg_damping**2)
|
|
146
|
+
polarisation = (
|
|
147
|
+
self.llg_polarisation.in_units_of(SI(1))
|
|
148
|
+
if isinstance(self.llg_polarisation, SI)
|
|
149
|
+
else float(self.llg_polarisation)
|
|
150
|
+
)
|
|
151
|
+
xi = self.llg_xi.in_units_of(SI(1)) if isinstance(self.llg_xi, SI) else float(self.llg_xi)
|
|
152
|
+
bohr_magneton = float(
|
|
153
|
+
cast(Any, 1.0 * constants.bohr_magneton).to("J/T").magnitude
|
|
154
|
+
)
|
|
155
|
+
charge = float(cast(Any, 1.0 * constants.positron_charge).to("C").magnitude)
|
|
156
|
+
ms = self.Ms.in_units_of(SI("A/m"))
|
|
157
|
+
su_f = (
|
|
158
|
+
SI(0.0, "m^3/A/s")
|
|
159
|
+
if ms == 0.0
|
|
160
|
+
else SI(
|
|
161
|
+
-gilbert_to_ll
|
|
162
|
+
* polarisation
|
|
163
|
+
* bohr_magneton
|
|
164
|
+
/ (charge * ms * (1.0 + xi * xi)),
|
|
165
|
+
"m^3/A/s",
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
self._derived_su_constants = {
|
|
169
|
+
"thermal_factor": thermal_factor,
|
|
170
|
+
"su_thermal_factor": thermal_factor,
|
|
171
|
+
"su_llg_stt_prefactor": 0.0 if su_f == 0.0 else 1.0,
|
|
172
|
+
"su_llg_stt_nadiab": su_f * (xi - self.su_llg_damping),
|
|
173
|
+
"su_llg_stt_adiab": su_f * (1.0 + self.su_llg_damping * xi),
|
|
174
|
+
"su_exch_prefactor": (
|
|
175
|
+
2.0 * self.su_exchange_coupling / (constants.mu0 * self.su_Ms)
|
|
176
|
+
),
|
|
177
|
+
}
|
|
178
|
+
return self._derived_su_constants
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def thermal_factor(self) -> MaterialScalar:
|
|
182
|
+
return self._derived_su_values()["thermal_factor"]
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def su_thermal_factor(self) -> MaterialScalar:
|
|
186
|
+
return self._derived_su_values()["su_thermal_factor"]
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def su_llg_stt_prefactor(self) -> MaterialScalar:
|
|
190
|
+
return self._derived_su_values()["su_llg_stt_prefactor"]
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def su_llg_stt_nadiab(self) -> MaterialScalar:
|
|
194
|
+
return self._derived_su_values()["su_llg_stt_nadiab"]
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def su_llg_stt_adiab(self) -> MaterialScalar:
|
|
198
|
+
return self._derived_su_values()["su_llg_stt_adiab"]
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def su_exch_prefactor(self) -> MaterialScalar:
|
|
202
|
+
return self._derived_su_values()["su_exch_prefactor"]
|
|
203
|
+
|
|
204
|
+
def __str__(self) -> str:
|
|
205
|
+
repr_str = f"Material '{self.name}'\n"
|
|
206
|
+
|
|
207
|
+
attrs = list(filter(lambda a: a[0] != "_", dir(self)))
|
|
208
|
+
|
|
209
|
+
if not self.extended_print:
|
|
210
|
+
attrs = [
|
|
211
|
+
"name",
|
|
212
|
+
"Ms",
|
|
213
|
+
"exchange_coupling",
|
|
214
|
+
"anisotropy",
|
|
215
|
+
"anisotropy_order",
|
|
216
|
+
"llg_gamma_G",
|
|
217
|
+
"llg_damping",
|
|
218
|
+
"llg_normalisationfactor",
|
|
219
|
+
"do_precession",
|
|
220
|
+
"llg_polarisation",
|
|
221
|
+
"llg_xi",
|
|
222
|
+
"thermal_factor",
|
|
223
|
+
"extended_print",
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
for attr in attrs:
|
|
227
|
+
if hasattr(self, attr):
|
|
228
|
+
value_str = str(getattr(self, attr))
|
|
229
|
+
repr_str += f" {attr:>25} = {value_str}\n"
|
|
230
|
+
|
|
231
|
+
return repr_str
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Normalization and validation for :class:`mag_material.MagMaterial` inputs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from functools import lru_cache
|
|
8
|
+
from typing import cast
|
|
9
|
+
|
|
10
|
+
from anisotropy import EnergyFunction, PredefinedAnisotropy
|
|
11
|
+
from si.physical import SI
|
|
12
|
+
|
|
13
|
+
MaterialScalar = SI | float
|
|
14
|
+
AnisotropyFunction = EnergyFunction
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(slots=True)
|
|
18
|
+
class MaterialParameters:
|
|
19
|
+
"""Fully resolved constructor values for a magnetic material."""
|
|
20
|
+
|
|
21
|
+
ms: SI
|
|
22
|
+
damping: MaterialScalar
|
|
23
|
+
gamma: SI
|
|
24
|
+
normalisation: SI
|
|
25
|
+
xi: MaterialScalar
|
|
26
|
+
polarisation: MaterialScalar
|
|
27
|
+
do_precession: bool
|
|
28
|
+
exchange: SI
|
|
29
|
+
anisotropy: PredefinedAnisotropy | AnisotropyFunction | None
|
|
30
|
+
anisotropy_order: int | None
|
|
31
|
+
properties: list[str]
|
|
32
|
+
scale_volume_charges: float
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@lru_cache(maxsize=1)
|
|
36
|
+
def _expected_parameter_units() -> tuple[tuple[str, SI], ...]:
|
|
37
|
+
one = SI(1)
|
|
38
|
+
return (
|
|
39
|
+
("Ms", SI(1, "A/m")),
|
|
40
|
+
("llg_gamma_G", SI(1, "m/A/s")),
|
|
41
|
+
("llg_damping", one),
|
|
42
|
+
("llg_normalisationfactor", SI(1, "1/s")),
|
|
43
|
+
("llg_xi", one),
|
|
44
|
+
("llg_polarisation", one),
|
|
45
|
+
("exchange_coupling", SI(1, "J/m")),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _value_by_public_name(parameters: MaterialParameters, name: str) -> MaterialScalar:
|
|
50
|
+
values: dict[str, MaterialScalar] = {
|
|
51
|
+
"Ms": parameters.ms,
|
|
52
|
+
"llg_gamma_G": parameters.gamma,
|
|
53
|
+
"llg_damping": parameters.damping,
|
|
54
|
+
"llg_normalisationfactor": parameters.normalisation,
|
|
55
|
+
"llg_xi": parameters.xi,
|
|
56
|
+
"llg_polarisation": parameters.polarisation,
|
|
57
|
+
"exchange_coupling": parameters.exchange,
|
|
58
|
+
}
|
|
59
|
+
return values[name]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _validate_units(name: str, parameters: MaterialParameters) -> None:
|
|
63
|
+
for attribute, expected_unit in _expected_parameter_units():
|
|
64
|
+
value = _value_by_public_name(parameters, attribute)
|
|
65
|
+
value_to_check = value._quantity if isinstance(value, SI) else value
|
|
66
|
+
if not expected_unit._quantity.is_compatible_with(value_to_check):
|
|
67
|
+
raise TypeError(
|
|
68
|
+
f"The argument '{attribute}' for material '{name}' requires units compatible "
|
|
69
|
+
f"with {expected_unit.dens_str()}, but received a value of '{value}'."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _resolve_anisotropy(
|
|
74
|
+
anisotropy: PredefinedAnisotropy | AnisotropyFunction | None,
|
|
75
|
+
anisotropy_order: int | None,
|
|
76
|
+
) -> tuple[PredefinedAnisotropy | AnisotropyFunction | None, int | None]:
|
|
77
|
+
if isinstance(anisotropy, PredefinedAnisotropy):
|
|
78
|
+
if anisotropy_order is not None:
|
|
79
|
+
raise ValueError(
|
|
80
|
+
"Cannot specify custom 'anisotropy_order' when using a predefined anisotropy."
|
|
81
|
+
)
|
|
82
|
+
if not anisotropy.has_function() or anisotropy.order is None:
|
|
83
|
+
raise ValueError("A material anisotropy must provide an energy function and order.")
|
|
84
|
+
return anisotropy, anisotropy.order
|
|
85
|
+
if anisotropy is None:
|
|
86
|
+
if anisotropy_order is not None:
|
|
87
|
+
raise ValueError("anisotropy_order requires an anisotropy energy function.")
|
|
88
|
+
return None, None
|
|
89
|
+
if not callable(anisotropy):
|
|
90
|
+
raise TypeError("anisotropy must be a PredefinedAnisotropy, callable, or None.")
|
|
91
|
+
custom_order = cast(object, anisotropy_order)
|
|
92
|
+
if (
|
|
93
|
+
custom_order is None
|
|
94
|
+
or type(custom_order) is bool
|
|
95
|
+
or not isinstance(custom_order, int)
|
|
96
|
+
or custom_order <= 0
|
|
97
|
+
):
|
|
98
|
+
raise ValueError(
|
|
99
|
+
"You must specify 'anisotropy_order' as a positive integer when using a custom "
|
|
100
|
+
"anisotropy function."
|
|
101
|
+
)
|
|
102
|
+
return anisotropy, anisotropy_order
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def resolve_material_parameters(
|
|
106
|
+
name: str,
|
|
107
|
+
*,
|
|
108
|
+
ms: SI | None,
|
|
109
|
+
damping: MaterialScalar,
|
|
110
|
+
gamma: SI | None,
|
|
111
|
+
normalisation: SI | None,
|
|
112
|
+
xi: MaterialScalar,
|
|
113
|
+
polarisation: MaterialScalar,
|
|
114
|
+
do_precession: bool,
|
|
115
|
+
exchange: SI | None,
|
|
116
|
+
anisotropy: PredefinedAnisotropy | AnisotropyFunction | None,
|
|
117
|
+
anisotropy_order: int | None,
|
|
118
|
+
properties: list[str] | None,
|
|
119
|
+
scale_volume_charges: float,
|
|
120
|
+
) -> MaterialParameters:
|
|
121
|
+
"""Apply legacy defaults and reject invalid material constructor values."""
|
|
122
|
+
try:
|
|
123
|
+
resolved_volume_charge_scale = float(scale_volume_charges)
|
|
124
|
+
except (TypeError, ValueError) as error:
|
|
125
|
+
raise TypeError("scale_volume_charges must be a finite real number.") from error
|
|
126
|
+
if not math.isfinite(resolved_volume_charge_scale):
|
|
127
|
+
raise ValueError("scale_volume_charges must be finite.")
|
|
128
|
+
|
|
129
|
+
resolved_anisotropy, resolved_order = _resolve_anisotropy(anisotropy, anisotropy_order)
|
|
130
|
+
parameters = MaterialParameters(
|
|
131
|
+
ms=SI(0.86e6, "A/m") if ms is None else ms,
|
|
132
|
+
damping=damping,
|
|
133
|
+
gamma=SI(2.210173e5, "m/A/s") if gamma is None else gamma,
|
|
134
|
+
normalisation=SI(0.1e12, "1/s") if normalisation is None else normalisation,
|
|
135
|
+
xi=xi,
|
|
136
|
+
polarisation=polarisation,
|
|
137
|
+
do_precession=do_precession,
|
|
138
|
+
exchange=SI(1.3e-11, "J/m") if exchange is None else exchange,
|
|
139
|
+
anisotropy=resolved_anisotropy,
|
|
140
|
+
anisotropy_order=resolved_order,
|
|
141
|
+
properties=["magnetic", "material"] if properties is None else properties,
|
|
142
|
+
scale_volume_charges=resolved_volume_charge_scale,
|
|
143
|
+
)
|
|
144
|
+
_validate_units(name, parameters)
|
|
145
|
+
if parameters.exchange < 0.0:
|
|
146
|
+
raise ValueError(
|
|
147
|
+
"The exchange coupling constant must be positive. For "
|
|
148
|
+
f"material '{name}', you specified: {parameters.exchange}."
|
|
149
|
+
)
|
|
150
|
+
return parameters
|
mag_material/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker for PEP 561 inline type information.
|
nmag/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Public Python 3 entrypoint for the nmag rewrite."""
|
|
2
|
+
|
|
3
|
+
from anisotropy import (
|
|
4
|
+
PredefinedAnisotropy,
|
|
5
|
+
cubic_anisotropy,
|
|
6
|
+
uniaxial_anisotropy,
|
|
7
|
+
want_anisotropy,
|
|
8
|
+
)
|
|
9
|
+
from mag_material import MagMaterial
|
|
10
|
+
from si.physical import SI, Physical
|
|
11
|
+
|
|
12
|
+
from .config import ACCELERATOR_ENV, HierarchicalBemConfig, NmagConfig, RustKernel
|
|
13
|
+
from .demag.bem_operator import BemOperatorStats
|
|
14
|
+
from .dynamics import IntegratorConfig, IntegratorStats
|
|
15
|
+
from .parallel import ParallelRuntimeInfo, parallel_runtime_info
|
|
16
|
+
from .simulation import Simulation
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"MagMaterial",
|
|
20
|
+
"NmagConfig",
|
|
21
|
+
"HierarchicalBemConfig",
|
|
22
|
+
"BemOperatorStats",
|
|
23
|
+
"IntegratorConfig",
|
|
24
|
+
"IntegratorStats",
|
|
25
|
+
"ParallelRuntimeInfo",
|
|
26
|
+
"Physical",
|
|
27
|
+
"PredefinedAnisotropy",
|
|
28
|
+
"SI",
|
|
29
|
+
"Simulation",
|
|
30
|
+
"RustKernel",
|
|
31
|
+
"ACCELERATOR_ENV",
|
|
32
|
+
"cubic_anisotropy",
|
|
33
|
+
"parallel_runtime_info",
|
|
34
|
+
"uniaxial_anisotropy",
|
|
35
|
+
"want_anisotropy",
|
|
36
|
+
]
|