#!/usr/bin/env python # coding: utf-8 # # Deriving a dynamics term # # 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: # In[1]: import micromagneticmodel as mm class SpecialDynamics(mm.DynamicsTerm): pass # Now, we can try to instantiate it # In[2]: try: sd = SpecialDynamics(xi=0.1, v=(0, 0, 1)) except TypeError: print("Exception raised.") # An exception was raised because `_reprlatex` and `_allowed_attributes` properties must be implemented. Therefore, an extended implementation of the class is: # In[3]: class SpecialDynamics(mm.DynamicsTerm): _reprlatex = r"$\xi\mathbf{m}\times\mathbf{v}$" _allowed_attributes = ["xi", "v"] def dmdt(self, m): raise NotImplementedError # We can try to instantiate the class again: # In[4]: 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](https://ubermagutil.readthedocs.io/en/latest/). # In[5]: import discretisedfield as df import ubermagutil.typesystem as ts @ts.typesystem( xi=ts.Parameter(descriptor=ts.Scalar(unsigned=True), otherwise=df.Field), v=ts.Parameter(descriptor=ts.Vector(size=3), otherwise=df.Field), ) class SpecialDynamics(mm.DynamicsTerm): _reprlatex = r"$\xi\mathbf{m}\times\mathbf{v}$" _allowed_attributes = ["xi", "v"] def dmdt(self, m): raise NotImplementedError # If we now attempt to pass invalid input arguments, exceptions are raised. # In[6]: try: sd = SpecialDynamics(xi=-0.1, v=(0, 0, 1)) # negative xi except ValueError: print("Exception raised.") # In[7]: try: sd = SpecialDynamics(xi=0.1, v=(0, 1)) # 2D v except ValueError: print("Exception raised.") # Some of the properties and methods of the implemented energy term are: # In[8]: sd = SpecialDynamics(xi=0.1, v=(0, 1, 1)) # In[9]: sd.xi # In[10]: sd.v # In[11]: sd.name # In[12]: sd # In[13]: repr(sd)