All dynamics terms in micromagneticmodel
are in micromagneticmodel/dynamics
directory. They are all derived from micromagneticmodel.dynamics.DynamicsTerm
base class.
For instance, let us say we want to implement a dynamics term with following specifications:
property | value |
---|---|
name | SpecialDynamics |
expression | $\xi\mathbf{m}\times\mathbf{v}$ |
parameters | $\xi$, $\mathbf{v}$ |
parameter properties | $\xi \ge 0$, can be spatially varying |
$\mathbf{v}$ is three-dimensional, can be spatially varying |
The dynamics term class would be:
import micromagneticmodel as mm
class SpecialDynamics(mm.DynamicsTerm):
def __init__(self, xi, v, name='specialdynamics'):
self.xi = xi
self.v = v
self.name = name
Now, we can try to instantiate it
try:
sd = SpecialDynamics(xi=0.1, v=(0, 0, 1))
except TypeError:
print('Exception raised.')
Exception raised.
An exception was raised because _repr
and _latex
properties must be implemented. Therefore, an extended implementation of the class is:
class SpecialDynamics(mm.DynamicsTerm):
_latex = r'$\xi\mathbf{m}\times\mathbf{v}$'
def __init__(self, xi, v, name='specialdynamics'):
self.xi = xi
self.v = v
self.name = name
@property
def _repr(self):
return f'SpecialDynamics(xi={self.xi}, v={self.v}, name=\'{self.name}\')'
We can try to instantiate the class again:
sd = SpecialDynamics(xi=0.1, v=(0, 0, 1))
sd
The dynamics object is created. The last thing we have to impose on the energy class is the typesystem. More precisely, we have to make sure no negative $\xi$ values are allowed, $\mathbf{v}$ is three-dimensional and that name
attribute accepts only valid Python variable names. This is done by using ubermagutil
. Full documentation can be found here.
import ubermagutil.typesystem as ts
import discretisedfield as df
@ts.typesystem(xi=ts.Parameter(descriptor=ts.Scalar(unsigned=True), otherwise=df.Field),
v=ts.Parameter(descriptor=ts.Vector(size=3), otherwise=df.Field),
name=ts.Name())
class SpecialDynamics(mm.DynamicsTerm):
_latex = r'$\xi\mathbf{m}\times\mathbf{v}$'
def __init__(self, xi, v, name='specialdynamics'):
self.xi = xi
self.v = v
self.name = name
@property
def _repr(self):
return f'SpecialDynamics(xi={self.xi}, v={self.v}, name=\'{self.name}\')'
If we now attempt to pass invalid input arguments, exceptions are raised.
try:
sd = SpecialDynamics(xi=-0.1, v=(0, 0, 1)) # negative xi
except ValueError:
print('Exception raised.')
Exception raised.
try:
sd = SpecialDynamics(xi=0.1, v=(0, 1)) # 2D v
except ValueError:
print('Exception raised.')
Exception raised.
Some of the properties and methods of the implemented energy term are:
sd = SpecialDynamics(xi=0.1, v=(0, 1, 1), name='specialdynamics')
sd.xi
0.1
sd.v
(0, 1, 1)
sd.name
'specialdynamics'
sd
repr(sd)
"SpecialDynamics(xi=0.1, v=(0, 1, 1), name='specialdynamics')"
Finally, the class we have just implemented is going to be inherited by a specific micromagnetic calculator, where _script
method is going to be implemented.
try:
sd._script
except NotImplementedError:
print('Exception raised.')
Exception raised.
Full description of all existing descriptors can be found in the API Reference.