TetraX.2: Cleaner, more convenient and reliable#
We’re thrilled to introduce TetraX.2, a leap forward for our micromagnetic modeling package! This major update brings several improvements, from a complete architectural overhaul of samples to enhanced tools for running experiments and analyzing results. With a focus on simplicity, flexibility, and performance, TetraX.2 represents a significant step forward in enabling researchers to model and study spin waves in numerical micromagnetism with ease.
Among many structural changes, we have worked hard on a revamped material handling, better organization of numerical experiments, modularized magnetic interactions to ensure smoother, more efficient workflows. In addition, we implement a great deal of new features, such as integrated plotting of numerical results, a more reliable relaxation method using torque minimization, and a completely new geometry type to model axially-symmetric waveguides!
Read on to discover the big and small changes that come with TetraX.2!
Sample, mesh and material#
The architecture around samples has been completely redesigned to be safer and
simpler. In TetraX versions 1.x, the AbstractSample sample object had too
many responsibilities which are now subdivided into class components such as
handling the mesh and the material separately. Different traits such as the
type of geometry (waveguide, layer, etc.) or the magnetic order (FM, AFM) were
configured through multiple-inheritance and created by the create_sample()
factory. This is much simpler now.
A simpler Sample class#
In version 2, there is a single Sample
class whose properties are configured through composition. Responsbilites such as mananging the geometry or the material of the sample
have been outsourced to the new SampleMesh and SampleMaterial
which are accessible as the mesh and material attributes of a sample. Instead of calling the old create_sample() function, now
simply create a sample in the following way.
from tetrax import Sample, geometries
sample = Sample(geometries.waveguide.tube(20, 30, 2))
# is the same as
sample = Sample(geometries.waveguide.tube(inner_radius=20, outer_radius=30, cell_size=2),
geometry_type="waveguide",
magnetic_order="FM"
)
sample.show() # works just like before
Note that, it is not possible anymore to create a Sample without specifying
a mesh (which are now organized more neatly in the tetrax.geometries module).
Previously, the unnecessary possibility to have a sample without mesh always lead to problems.
Similarly, by default, the magnetization is always set to the \(z\) direction.
Note
When choosing a geometry from our template library, the GeometryType
is automatically inferred from the mesh and does not need to be supplied
explicitely. Moreover, the MagneticOrder always defaults to ferromagnetic.
New SampleMesh class#
As before, upon creation of a sample, all necessary matrices and quantities assosiated with the geometry of the mesh are precalculated. These
are now managed by the new SampleMesh which is accesible as the mesh attribute of the respective
sample. For example, the number of nodes in a sample is now accessed with
sample.mesh.nx
# returns the number of nodes in the mesh of the sample
New SampleMaterial and MaterialParameter classes#
Material properties of samples are now not accesible anymore directly as sample attributes, but instead managed by the
SampleMaterial that is accessed through the material attribute of a sample. This unloads
responsibility from the Sample class and removes the possibility to set non-existent material parameters.
In versions 1.x, material parameters could be set as
sample.Msat = 1e3 # DEPRECATED!
sample.Ms = 1e3 # did not raise an error
which is now done via
sample.material["Msat"] = 1e3
sample.material["Ms"] = = 1e3 # raises an error
Other than that, material paramaters can be set as before.
Each parameter like "Msat" is stored as a MaterialParameter object that provides
metadata and some convencience methods. For example
sample.material["Msat"]
# will print a html summary of the material parameter,
# including unit, current value, average, etc.
sample.material["Msat"].value
# will return the current value of the parameter
sample.material["Msat"].average
# will return the sample average of the parameter
For more details, see SampleMaterial
and MaterialParameter within the API reference.
ExperimentSetup and results#
We were not happy with the way that numerical experiments were organized. Somehow, the necessity to create
an ExperimentalSetup to manage numerical experiments felt off and was also not very useful when wanting to organize several experiments
on the same sample. This is now completely overhauled for more modularity and automatic documentation.
First of all, we get rid of the experimental setup and
included its attributes (microwave antenna and external field) into the properties of the sample.
Furthermore, most experiments are now implemented directly as top-level functions that take a particular
sample as a parameter and generate a Result as an output. For example the
eigenmodes() experiment acts as
eigen_result = tx.experiments.eigenmodes(sample)
and returns an EigenResult.
Depending on the particular experiment, each Result provides methods to plot the
calculated data and perform post-processing on it. For example, the
EigenResult allows calculating the power absorption of the a
spin-wave spectrum with respect to a specified microwave antenna using the
EigenResult.absorption() method (which returns an
AbsorptionResult).
By default, each Result is automatically saved to the disk. This includes the
calculated data itself, as well as some metadata and the parameters used to perform the calculations. For example,
running the eigenmodes() experiment as written above produces the following output on the disk.
my_sample/
eigen/
external_field.vtk
eigenvalue_dataframe.csv
mode_profiles/
...
equilibrium.vtk
report.json
with a report.json file that contains material parameters, experiment configuration, metadata (such as the version of
TetraX that has been used) and can be used, for example, for data archiving. By default, running the same experiment
twice will overwrite the old results.
In order to circumvent this, results can be equipped with a label when running the
experiment. For example,
eigen_result_A = tx.experiments.eigenmodes(sample, label="A", **some_settings)
...
eigen_result_B = tx.experiments.eigenmodes(sample, label="B", **different_settings)
produces
my_sample/
eigen_A/
...
eigen_B/
...
For more information on how to run experiments, see the User Guide.
Interactions#
While different magnetic interactions have been more or less fixed throughout previous version of TetraX, they are now modularized as
Interaction s in the tetrax.interactions module. The different interactions of a sample are
now listed in its interactions attritube. Each interaction has an
InteractionName that allows to address it. For example
sample.interactions
# returns a list of the different interactions in the sample,
sample.get_interaction("exchange")
# returns reference to the ExchangeInteration object of the sample,
sample.get_field("dipole")
# returns the current dipolar get_field and
sample.get_energy("cubic_anisotropy")
# returns the current cubic-anisotropy energy.
In this way, the different interactions that participate in a particular numerical experiment can now be chosen freely. For example
zeeman = sample.get_interaction("zeeman")
exchange = sample.get_interaction("exchange")
relax(sample, interactions=[zeeman, exchange])
eigen_result = eigenmodes(sample, interactions=[zeeman, exchange])
minimizes the energy of the sample and calculates its eigenmodes only considering Zeeman and exchange interaction. This allows, for example, to subsequently perturb an eigenspectrum using additional interactions.
dipole = sample.get_interaction("dipole")
dmi_bulk = sample.get_interaction("dmi_bulk")
eigen_result.perturb_with([dipole, dmi_bulk])
which calculates the zeroth-order perturbation of an eigenspectrum with respect to dipolar and bulk Dzyaloshinskii-Moriya interaction. More details are found in the User Guide or in the example Thin film dispersion exact vs perturbation (Kalinikos & Slavin).
Torque minimization with the new relax_dynamic() experiment#
In need of a more reliable equilibration method than energy minization using the relax() experiment,
we now additionally implemented relaxation based on the overdamped Landau-Lifhsitz-Gilbert equation in the new
relax_dynamic() experiment. This is generally slower than energy minization but
gets the job done in almost all cases where energy minimization fails. This can be come especially important when Dzyaloshinskii-Moriya
interactions are included, as seen in the newly added example Channeling mixed Néel-Bloch domain walls with iDMI.
New geometry type: Axially-symmetric waveguide#
Thus far, through the WAVEGUIDE and LAYER
geometr types, we have
provided the oppurtunity to exploit translational symmetries in magnetic samples and directly calculate the spin-wave spectrum as a function
of the wave number \(k\) along the translation axis. We are curretly working hard to expand this notion to magnetic systems with
cylindrical/axial symmetries. For this, we are introducing the first of two new geometry types, namely
WAVEGUIDE_AXIAL. This geometry type combines axial with translational symmetries and allow to efficiently model
round wires, tubes, or multitubes by only modeling the magnetic system within a one-dimensional mesh along the radial direction. The
spin-wave modes are directly calculated as function of wave vector \(k\) and azimuthal mode index \(m\) in the angular direction.
A demonstration is found in the updated Dispersion of a nanotube in vortex state example or in the newly added
Dispersion of a solid wire in axial magnetization state example. We hope you are having fun with this new geometry type. Meanwhile, we are working on
finalizing the CONFINED_AXIAL geometry type, allowing to model confined samples with axial symmetry
(such as ring, disks, or toroids).
Other new features and changes#
A couple of template materials have been added, which are available in the new
tetrax.materialsmodule. They can be listed by accessingtetrax.materials.available.Similarly, the library of template geometries
tetrax.geometrieshas been restructured and subdivided into more meaningful submodules such astetrax.geometries.waveguideortetrax.geometries.layer. All template geometries have been cleaned up (e.g. keywords have more meaningful names) and can be listed usingtetrax.geometries.available.All template vectorfields have been cleaned up and can be accessed with
tetrax.vectorfields.available.Both vectorfields and geometries can now be read from a file using
tetrax.geometries.from_file()ortetrax.vectorfields.from_file().A new microwave antenna (
MultiStriplineAntenna) has been added, which allows to model an arbitrary series of stripline antennae (e.g. to model a meandering antenna).All examples have been revised to comply with version 2. Furthermore, new examples have been added.
The number of CPU cores
num_cpuswhen calculating an eigen spectrum is now-1by default (all cores are used).Frequencies are now stored in Hz, wave vectors in rad/m.
The symmetry breaking direction
material["e_d"]of theInterfacialDMIcan now be chosen freely.Both
InterfacialDMIandBulkDMInow satisfy proper boundary conditions at the sample boundary. Open boundary conditions can be recovered by setting theopen_boundaryattribute of the respective interaction to True, which requires to call theupdate_matrices()function of the interaction. Setting open boundary conditions should be done with care (that’s why this feature is kind of hidden).The
plotmethod of the sample has been removed and its functionality absorbed into theshowmethod.