Skip to content

Commit

Permalink
Add functionality for finding and reading data
Browse files Browse the repository at this point in the history
moved from micromagneticdata and ubermagtable, respectively
  • Loading branch information
lang-m committed Nov 29, 2023
1 parent 1eeb7c0 commit c1cebd1
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 0 deletions.
1 change: 1 addition & 0 deletions mumax3c/_output_collecting_util/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .mumax3drive import Mumax3Drive as Drive
129 changes: 129 additions & 0 deletions mumax3c/_output_collecting_util/mumax3drive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import pathlib

import micromagneticdata as md
import ubermagutil as uu

from .abstract_drive import AbstractDrive


@uu.inherit_docs
class Mumax3Drive(md.Drive):
"""Drive class for Mumax3Drives (created automatically).
This class provides utility for the analysis of individual mumax3 drives. It should
not be created explicitly. Instead, use ``micromagneticdata.Drive`` which
automatically creates a ``drive`` object of the correct sub-type.
Parameters
----------
name : str
System's name.
number : int
Drive number.
dirname : str, optional
Directory in which system's data is saved. Defults to ``'./'``.
x : str, optional
Independent variable column name. Defaults to ``None`` and depending on
the driver used, one is found automatically.
use_cache : bool, optional
If ``True`` the Drive object will read tabular data and the names and number of
magnetisation files only once. Note: this prevents Drive to detect new data when
looking at the output of a running simulation. If set to ``False`` the data is
read every time the user accesses it. Defaults to ``False``.
Raises
------
IOError
If the drive directory cannot be found.
Examples
--------
1. Getting drive object.
>>> import os
>>> import micromagneticdata as md
...
>>> dirname = dirname=os.path.join(os.path.dirname(__file__),
... 'tests', 'test_sample')
>>> drive = md.Drive(name='system_name', number=1, dirname=dirname)
>>> drive
Mumax3Drive(...)
"""

def __init__(self, name, number, dirname="./", x=None, use_cache=False, **kwargs):
self._mumax_output_path = pathlib.Path(
f"{dirname}/{name}/drive-{number}/{name}.out"
) # required to initialise self.x in super
if not self._mumax_output_path.exists():
raise IOError(
f"Output directory {self._mumax_output_path!r} does not exist."
)

super().__init__(name, number, dirname, x, use_cache, **kwargs)

@AbstractDrive.x.setter
def x(self, value):
if value is None:
# self.info["driver"] in ["TimeDriver", "RelaxDriver", "MinDriver"]:
self._x = "t"
else:
# self.table reads self.x so self._x has to be defined first
if hasattr(self, "_x"):
# store old value to reset in case value is invalid
_x = self._x
self._x = value
if value not in self.table.data.columns:
self._x = _x
raise ValueError(f"Column {value=} does not exist in data.")

@property
def _table_path(self):
return self._mumax_output_path / "table.txt"

@property
def _step_file_glob(self):
return self._mumax_output_path.glob("*.ovf")

@property
def calculator_script(self):
with (self.drive_path / f"{self.name}.mx3").open() as f:
return f.read()

def __repr__(self):
"""Representation string.
Returns
-------
str
Representation string.
Examples
--------
1. Representation string.
>>> import os
>>> import micromagneticdata as md
...
>>> dirname = dirname=os.path.join(os.path.dirname(__file__),
... 'tests', 'test_sample')
>>> drive = md.Drive(name='system_name', number=1, dirname=dirname)
>>> drive
Mumax3Drive(name='system_name', number=1, dirname='...test_sample', x='t')
"""
return (
f"Mumax3Drive(name='{self.name}', number={self.number}, "
f"dirname='{self.dirname}', x='{self.x}')"
)
122 changes: 122 additions & 0 deletions mumax3c/_output_collecting_util/read_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import re

import pandas as pd
import ubermagtable


def table_from_file(filename, /, x=None, rename=True):
"""Convert a mumax3 ``.txt`` scalar data file into a ``ubermagtable.Table``.
Parameters
----------
filename : str
mumax3 ``.txt`` file.
x : str, optional
Independent variable name. Defaults to ``None``.
rename : bool, optional
If ``rename=True``, the column names are renamed with their shorter
versions. Defaults to ``True``.
Returns
-------
ubermagtable.Table
Table object.
TODO: update example
Examples
--------
1. Defining ``ubermagtable.Table`` by reading an OOMMF ``.odt`` file.
>>> import os
>>> import ubermagtable as ut
...
>>> odtfile = os.path.join(os.path.dirname(__file__),
... 'tests', 'test_sample',
... 'oommf-hysteresis1.odt')
>>> table = ut.Table.fromfile(odtfile, x='B_hysteresis')
2. Defining ``ubermagtable.Table`` by reading a mumax3 ``.txt`` file.
>>> odtfile = os.path.join(os.path.dirname(__file__),
... 'tests', 'test_sample', 'mumax3-file1.txt')
>>> table = ut.Table.fromfile(odtfile, x='t')
"""
quantities = _read_header(filename, rename=rename)
data = pd.read_csv(
filename,
sep=r"\s+",
comment="#",
header=None,
names=list(quantities.keys()),
)
return ubermagtable.Table(data=data, units=quantities, x=x)


def _read_header(filename, rename=True):
"""Extract quantities for individual columns from a table file.
This method extracts both column names and units and returns a dictionary,
where keys are column names and values are the units.
Parameters
----------
filename : str
OOMMF ``.odt`` or mumax3 ``.txt`` file.
rename : bool
If ``rename=True``, the column names are renamed with their shorter
versions. Defaults to ``True``.
Returns
-------
dict
Dictionary of column names and units.
"""

with open(filename) as f:
header_line_1 = f.readline()

header_line_1 = header_line_1[len("# ") :].rstrip().split("\t")
# COLUMN NAMES
cols = [elem.split()[0] for elem in header_line_1]
# UNITS
units = [re.sub(r"[()]", "", elem.split()[1]) for elem in header_line_1]

if rename:
cols = [_rename_column(col, _MUMAX3_DICT) for col in cols]

return dict(zip(cols, units))


def _rename_column(name, cols_dict):
"""Rename columns to get shorter names without spaces.
Renaming is based on _MUMAX3_DICT.
"""
return cols_dict.get(name, name)


# The mumax3 columns are renamed according to this dictionary.
_MUMAX3_DICT = {
"t": "t",
"mx": "mx",
"my": "my",
"mz": "mz",
"E_total": "E",
"E_exch": "E_totalexchange",
"E_demag": "E_demag",
"E_Zeeman": "E_zeeman",
"E_anis": "E_totalanisotropy",
"dt": "dt",
"maxTorque": "maxtorque",
}

0 comments on commit c1cebd1

Please sign in to comment.