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,180 @@
|
|
|
1
|
+
"""Schedule parsing and counter arithmetic for hysteresis runs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import Any, cast
|
|
8
|
+
|
|
9
|
+
from when import When
|
|
10
|
+
|
|
11
|
+
from .clock import SimulationClock
|
|
12
|
+
|
|
13
|
+
Action = Callable[[Any], Any]
|
|
14
|
+
ScheduleInput = list[tuple[object, ...]]
|
|
15
|
+
ScheduledAction = tuple[Action, When]
|
|
16
|
+
CounterTriple = tuple[Any | None, Any | None, Any | None]
|
|
17
|
+
|
|
18
|
+
_subsequent_spaces = re.compile(r"[ \t_]+")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _string_normalise(s: str, lower: bool = True, spaces: str | None = "_") -> str:
|
|
22
|
+
"""
|
|
23
|
+
Used by `_append_x_list` to obtain a standard string format.
|
|
24
|
+
Examples:
|
|
25
|
+
'save fields' --> 'save_fields'
|
|
26
|
+
'Save_Fields' --> 'save_fields'
|
|
27
|
+
"""
|
|
28
|
+
ns = s
|
|
29
|
+
if lower:
|
|
30
|
+
ns = s.lower()
|
|
31
|
+
if spaces is not None:
|
|
32
|
+
ns = re.sub(_subsequent_spaces, spaces, ns)
|
|
33
|
+
return ns
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _append_x_list(
|
|
37
|
+
target_list: list[ScheduledAction],
|
|
38
|
+
input_list: ScheduleInput,
|
|
39
|
+
prefix: str = "",
|
|
40
|
+
predefined_actions: dict[str, Action] | None = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Internally used by `_join_save_and_do_lists` to parse the
|
|
44
|
+
multi-argument 'save' and 'do' tuples.
|
|
45
|
+
"""
|
|
46
|
+
if predefined_actions is None:
|
|
47
|
+
predefined_actions = {}
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
for tuple_item in input_list:
|
|
51
|
+
list_item = list(tuple_item)
|
|
52
|
+
if not list_item:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
things = list_item[0:-1]
|
|
56
|
+
when = list_item[-1]
|
|
57
|
+
|
|
58
|
+
for thing in things:
|
|
59
|
+
if callable(thing):
|
|
60
|
+
target_list.append((cast(Action, thing), cast(When, when)))
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
if isinstance(thing, str):
|
|
64
|
+
normalised_thing = _string_normalise(f"{prefix} {thing}")
|
|
65
|
+
if normalised_thing in predefined_actions:
|
|
66
|
+
action = predefined_actions[normalised_thing]
|
|
67
|
+
target_list.append((action, cast(When, when)))
|
|
68
|
+
continue
|
|
69
|
+
else:
|
|
70
|
+
# Try without prefix
|
|
71
|
+
normalised_thing = _string_normalise(thing)
|
|
72
|
+
if normalised_thing in predefined_actions:
|
|
73
|
+
action = predefined_actions[normalised_thing]
|
|
74
|
+
target_list.append((action, cast(When, when)))
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
# If we are here, the 'thing' is not a callable and not
|
|
78
|
+
# a recognized string.
|
|
79
|
+
msg = (
|
|
80
|
+
f"Error in optional argument '{prefix}' of method "
|
|
81
|
+
f"'hysteresis': you want to {prefix} '{thing}' "
|
|
82
|
+
f"but I don't know how to do it. Hint: when specifying "
|
|
83
|
+
f"what to {prefix} you can use a string or a function. "
|
|
84
|
+
f"Available strings are: {', '.join(predefined_actions.keys())}."
|
|
85
|
+
)
|
|
86
|
+
raise ValueError(msg)
|
|
87
|
+
|
|
88
|
+
except TypeError as e:
|
|
89
|
+
msg = (
|
|
90
|
+
f"Bad syntax for argument '{prefix}' of the method 'hysteresis': "
|
|
91
|
+
f"remember that you should provide a list of tuples "
|
|
92
|
+
f"(things_to_{prefix}, when). You can also provide tuples "
|
|
93
|
+
f"with many things to save, such as (thing1, thing2, "
|
|
94
|
+
f"..., when)."
|
|
95
|
+
)
|
|
96
|
+
raise ValueError(msg) from e
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _join_save_and_do_lists(
|
|
100
|
+
save_list: ScheduleInput,
|
|
101
|
+
do_list: ScheduleInput,
|
|
102
|
+
predefined_actions: dict[str, Action] | None = None,
|
|
103
|
+
) -> list[ScheduledAction]:
|
|
104
|
+
"""
|
|
105
|
+
Takes 'save' and 'do' parameters from the 'hysteresis' method
|
|
106
|
+
and joins them into a unique list.
|
|
107
|
+
Tags (e.g., "save averages") are replaced with the appropriate functions.
|
|
108
|
+
Also checks that the provided tags actually exist.
|
|
109
|
+
"""
|
|
110
|
+
if predefined_actions is None:
|
|
111
|
+
predefined_actions = {}
|
|
112
|
+
|
|
113
|
+
joint_list: list[ScheduledAction] = []
|
|
114
|
+
|
|
115
|
+
# Note: It is important to process 'do' before 'save'.
|
|
116
|
+
# A 'do' command might be 'next_stage', and 'save' commands
|
|
117
|
+
# need to know if this is the last step of the stage.
|
|
118
|
+
_append_x_list(joint_list, do_list, prefix="do", predefined_actions=predefined_actions)
|
|
119
|
+
_append_x_list(joint_list, save_list, prefix="save", predefined_actions=predefined_actions)
|
|
120
|
+
|
|
121
|
+
# XXX Matteo, can we at this point order the save_ entries such that
|
|
122
|
+
# the save_restart is the last? See my explanation in ticket:169.
|
|
123
|
+
# Hans, 11/ll/2008
|
|
124
|
+
|
|
125
|
+
return joint_list
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _next_deltas(
|
|
129
|
+
event: When,
|
|
130
|
+
clock: SimulationClock,
|
|
131
|
+
suggest: CounterTriple | None = None,
|
|
132
|
+
tols: dict[str, Any] | None = None,
|
|
133
|
+
) -> CounterTriple:
|
|
134
|
+
"""
|
|
135
|
+
Return the next occurrence of the given event as a triple of deltas:
|
|
136
|
+
- (delta_step, delta_time, delta_real_time)
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def delta(name: str) -> Any | None:
|
|
140
|
+
n = event.next_time(name, clock, tols=tols)
|
|
141
|
+
return n - clock[name] if not isinstance(n, bool) else None
|
|
142
|
+
|
|
143
|
+
def minimum(ls: list[Any | None]) -> Any | None:
|
|
144
|
+
return min((item for item in ls if item is not None), default=None)
|
|
145
|
+
|
|
146
|
+
delta_step, delta_time, delta_real_time = suggest or (None, None, None)
|
|
147
|
+
|
|
148
|
+
delta_step = minimum([delta("step"), delta("stage_step"), delta_step])
|
|
149
|
+
delta_time = minimum([delta("time"), delta("stage_time"), delta_time])
|
|
150
|
+
delta_real_time = minimum([delta("real_time"), delta_real_time])
|
|
151
|
+
|
|
152
|
+
return (delta_step, delta_time, delta_real_time)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _next_time(
|
|
156
|
+
event: When,
|
|
157
|
+
clock: SimulationClock,
|
|
158
|
+
tols: dict[str, Any] | None = None,
|
|
159
|
+
) -> CounterTriple:
|
|
160
|
+
"""
|
|
161
|
+
Returns a triple of absolute counter values for the next event:
|
|
162
|
+
- (next_step, next_time, next_real_time)
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
def delta(name: str, starting_time: str | None = None) -> Any | None:
|
|
166
|
+
n = event.next_time(name, clock, tols=tols)
|
|
167
|
+
if isinstance(n, bool):
|
|
168
|
+
return None
|
|
169
|
+
return n - clock[starting_time] if starting_time else n
|
|
170
|
+
|
|
171
|
+
def minimum(ls: list[Any | None]) -> Any | None:
|
|
172
|
+
return min((item for item in ls if item is not None), default=None)
|
|
173
|
+
|
|
174
|
+
next_time = minimum([delta("time", "zero_stage_time"), delta("stage_time")])
|
|
175
|
+
|
|
176
|
+
next_step = minimum([delta("step", "zero_stage_step"), delta("stage_step")])
|
|
177
|
+
|
|
178
|
+
next_real_time = delta("real_time")
|
|
179
|
+
|
|
180
|
+
return (next_step, next_time, next_real_time)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger("nmagmake")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class InferenceEntity:
|
|
13
|
+
name: str
|
|
14
|
+
depends_on: list[str] = field(default_factory=lambda: [])
|
|
15
|
+
how_to_make: list[Callable[..., Any]] = field(default_factory=lambda: [])
|
|
16
|
+
also_updates: list[str] = field(default_factory=lambda: [])
|
|
17
|
+
_is_prerequisite: list[str] = field(default_factory=lambda: [], init=False)
|
|
18
|
+
_is_uptodate: bool = field(default=False, init=False)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InferenceEngine:
|
|
22
|
+
def __init__(self, entities: list[dict[str, Any]] | None = None) -> None:
|
|
23
|
+
self.entities: dict[str, InferenceEntity] = {}
|
|
24
|
+
if entities:
|
|
25
|
+
for e_desc in entities:
|
|
26
|
+
ie = InferenceEntity(**e_desc)
|
|
27
|
+
self.entities[ie.name] = ie
|
|
28
|
+
|
|
29
|
+
self._build_backlinks()
|
|
30
|
+
self._check_for_cycles()
|
|
31
|
+
|
|
32
|
+
def _build_backlinks(self) -> None:
|
|
33
|
+
"""Connects dependencies to their dependents and validates existence."""
|
|
34
|
+
for name, ie in self.entities.items():
|
|
35
|
+
for dep in ie.depends_on:
|
|
36
|
+
if (ie_dep := self.entities.get(dep)) is None:
|
|
37
|
+
raise KeyError(f"Dependency '{dep}' required by '{name}' not found.")
|
|
38
|
+
ie_dep._is_prerequisite.append(name)
|
|
39
|
+
|
|
40
|
+
def _check_for_cycles(self) -> None:
|
|
41
|
+
"""Detects circular dependencies using DFS to prevent infinite recursion."""
|
|
42
|
+
visited: set[str] = set()
|
|
43
|
+
rec_stack: set[str] = set()
|
|
44
|
+
|
|
45
|
+
def has_cycle(name: str) -> bool:
|
|
46
|
+
visited.add(name)
|
|
47
|
+
rec_stack.add(name)
|
|
48
|
+
|
|
49
|
+
for neighbor in self.entities[name].depends_on:
|
|
50
|
+
if neighbor not in visited:
|
|
51
|
+
if has_cycle(neighbor):
|
|
52
|
+
return True
|
|
53
|
+
elif neighbor in rec_stack:
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
rec_stack.remove(name)
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
for node in self.entities:
|
|
60
|
+
if node not in visited:
|
|
61
|
+
if has_cycle(node):
|
|
62
|
+
raise ValueError(f"Circular dependency detected involving '{node}'")
|
|
63
|
+
|
|
64
|
+
def invalidate(self, name: str) -> None:
|
|
65
|
+
"""Recursively marks an entity and its dependents as dirty."""
|
|
66
|
+
if (ie := self.entities.get(name)) is None:
|
|
67
|
+
raise KeyError(f"Entity '{name}' is unknown.")
|
|
68
|
+
|
|
69
|
+
if ie._is_uptodate:
|
|
70
|
+
ie._is_uptodate = False
|
|
71
|
+
log.debug(f"Invalidated: {name}")
|
|
72
|
+
for dependent_name in ie._is_prerequisite:
|
|
73
|
+
self.invalidate(dependent_name)
|
|
74
|
+
|
|
75
|
+
def make(self, name: str, **make_args: Any) -> None:
|
|
76
|
+
"""Builds target and dependencies recursively."""
|
|
77
|
+
if (ie := self.entities.get(name)) is None:
|
|
78
|
+
raise KeyError(f"Cannot build unknown entity '{name}'.")
|
|
79
|
+
|
|
80
|
+
if ie._is_uptodate:
|
|
81
|
+
log.debug(f"'{name}' is up-to-date.")
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
for dep_name in ie.depends_on:
|
|
85
|
+
self.make(dep_name, **make_args)
|
|
86
|
+
|
|
87
|
+
log.info(f"Building: {name}")
|
|
88
|
+
for step in ie.how_to_make:
|
|
89
|
+
step(**make_args)
|
|
90
|
+
|
|
91
|
+
for also_name in ie.also_updates:
|
|
92
|
+
if other := self.entities.get(also_name):
|
|
93
|
+
other._is_uptodate = True
|
|
94
|
+
|
|
95
|
+
ie._is_uptodate = True
|
simulation/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker for PEP 561 inline type information.
|
simulation/quantity.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from si.physical import SI
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class Quantity:
|
|
9
|
+
"""A dataclass describing a physical quantity for data saving.
|
|
10
|
+
|
|
11
|
+
A quantity is a description of any thing that may be saved inside
|
|
12
|
+
a ndt file. It may just represent an integer-floating point number
|
|
13
|
+
or a vector field. The Quantity class is a descriptor for such a thing.
|
|
14
|
+
It contains details about the corresponding type, SI unit, the id name,
|
|
15
|
+
the signature (indices and per-material).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
name: str
|
|
19
|
+
type: str # 'int', 'float', 'field', 'pfield', 'date'
|
|
20
|
+
units: SI | None
|
|
21
|
+
signature: str | None = None
|
|
22
|
+
context: str | None = None
|
|
23
|
+
parent: Optional["Quantity"] = None
|
|
24
|
+
|
|
25
|
+
def __post_init__(self) -> None:
|
|
26
|
+
if self.signature is None:
|
|
27
|
+
object.__setattr__(self, "signature", self.name)
|
|
28
|
+
|
|
29
|
+
def sub_quantity(self, name: str) -> "Quantity":
|
|
30
|
+
"""Creates a new Quantity representing a sub-component."""
|
|
31
|
+
return self.__class__(
|
|
32
|
+
name=name,
|
|
33
|
+
type=self.type,
|
|
34
|
+
units=self.units,
|
|
35
|
+
signature=self.signature,
|
|
36
|
+
context=self.context,
|
|
37
|
+
parent=self,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
UNIT_DIMENSIONLESS = SI(1)
|
|
42
|
+
UNIT_SECONDS = SI("s")
|
|
43
|
+
UNIT_A_PER_M = SI("A/m")
|
|
44
|
+
UNIT_A_PER_M2 = SI("A/m^2")
|
|
45
|
+
UNIT_A_PER_M_PER_S = SI("A/m/s")
|
|
46
|
+
UNIT_INVERSE_SECONDS = SI("1/s")
|
|
47
|
+
UNIT_J_PER_M3 = SI("J/m^3")
|
|
48
|
+
UNIT_AMPERE = SI("A")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
known_quantities: list[Quantity] = [
|
|
52
|
+
# name type unit signature context
|
|
53
|
+
Quantity("id", "int", UNIT_DIMENSIONLESS, None),
|
|
54
|
+
Quantity("step", "int", UNIT_DIMENSIONLESS, None),
|
|
55
|
+
Quantity("stage_step", "int", UNIT_DIMENSIONLESS, None),
|
|
56
|
+
Quantity("stage", "int", UNIT_DIMENSIONLESS, None),
|
|
57
|
+
Quantity("last_step_dt", "float", UNIT_SECONDS, None),
|
|
58
|
+
Quantity("time", "float", UNIT_SECONDS, None),
|
|
59
|
+
Quantity("stage_time", "float", UNIT_SECONDS, None),
|
|
60
|
+
Quantity("real_time", "float", UNIT_SECONDS, None),
|
|
61
|
+
Quantity("unixtime", "float", UNIT_SECONDS, None),
|
|
62
|
+
Quantity("maxangle", "float", UNIT_DIMENSIONLESS, None),
|
|
63
|
+
Quantity("localtime", "date", None, None),
|
|
64
|
+
Quantity("H_total", "field", UNIT_A_PER_M, "_?_*"),
|
|
65
|
+
Quantity("M", "field", UNIT_A_PER_M, "_?_*"),
|
|
66
|
+
Quantity("m", "pfield", UNIT_DIMENSIONLESS, "_?_*"),
|
|
67
|
+
Quantity("pin", "pfield", UNIT_DIMENSIONLESS, None),
|
|
68
|
+
Quantity("current_density", "pfield", UNIT_A_PER_M2, "_*", "stt"),
|
|
69
|
+
Quantity("dmdt", "field", UNIT_A_PER_M_PER_S, "_?_*"),
|
|
70
|
+
Quantity("dm_dcurrent", "field", UNIT_INVERSE_SECONDS, "_?_*", "stt"),
|
|
71
|
+
Quantity("H_ext", "field", UNIT_A_PER_M, "_*"),
|
|
72
|
+
Quantity("H_anis", "field", UNIT_A_PER_M, "_?_*", "anis"),
|
|
73
|
+
Quantity("H_exch", "field", UNIT_A_PER_M, "_?_*", "exch"),
|
|
74
|
+
Quantity("H_demag", "field", UNIT_A_PER_M, "_*", "demag"),
|
|
75
|
+
Quantity("E_total", "field", UNIT_J_PER_M3, "_?"),
|
|
76
|
+
Quantity("E_ext", "field", UNIT_J_PER_M3, "_?"),
|
|
77
|
+
Quantity("E_anis", "field", UNIT_J_PER_M3, "_?", "anis"),
|
|
78
|
+
Quantity("E_exch", "field", UNIT_J_PER_M3, "_?", "exch"),
|
|
79
|
+
Quantity("E_demag", "field", UNIT_J_PER_M3, "_?", "demag"),
|
|
80
|
+
Quantity("phi", "field", UNIT_AMPERE, None, "demag"),
|
|
81
|
+
Quantity("rho", "field", UNIT_A_PER_M2, None, "demag"),
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
known_quantities_by_name: dict[str, Quantity] = {q.name: q for q in known_quantities}
|
|
85
|
+
|
|
86
|
+
known_field_quantities: list[Quantity] = [
|
|
87
|
+
q for q in known_quantities if q.type in ("field", "pfield")
|
|
88
|
+
]
|