From 7c2c39e95b1705f8e4ded76303b7a92bdfec304d Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Sat, 23 Mar 2024 11:57:59 +0100 Subject: [PATCH 1/6] Test for vector-valued ZhangLi u --- micromagnetictests/calculatortests/zhangli.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/micromagnetictests/calculatortests/zhangli.py b/micromagnetictests/calculatortests/zhangli.py index 407dbb3..326ed13 100644 --- a/micromagnetictests/calculatortests/zhangli.py +++ b/micromagnetictests/calculatortests/zhangli.py @@ -256,3 +256,68 @@ def time_dep(t): assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 self.calculator.delete(system) + + def test_field_vector(self): + """ + Domain wall in a strip oriented in x (y) direction. Current is applied in x (y) + direction. The average mz component before and after moving the domain walls + are compared. There is no check for mx and my because we do not ensure same + chirality of the domain walls. + """ + md = self.calculator.MinDriver() + td = self.calculator.TimeDriver() + + pa = 200e-9 + pb = 20e-9 + Ms = 5.8e5 + + def init_m(direction): + def _inner(p): + if p[direction] < 70e-9: + return (0.1, 0.1, -1) + return (0.1, 0.1, 1) + + return _inner + + A = 15e-12 + K = 0.5e6 + u = (0, 0, 1) + + system_x = mm.System(name="strip_x") + system_x.energy = mm.Exchange(A=A) + mm.UniaxialAnisotropy(K=K, u=u) + mesh = df.Mesh(p1=(0, 0, 0), p2=(pa, pb, 5e-9), cell=(5e-9, 5e-9, 5e-9)) + system_x.m = df.Field(mesh, nvdim=3, value=init_m(0), norm=Ms) + md.drive(system_x) + + system_y = mm.System(name="strip_y") + system_y.energy = mm.Exchange(A=A) + mm.UniaxialAnisotropy(K=K, u=u) + mesh = df.Mesh(p1=(0, 0, 0), p2=(pb, pa, 5e-9), cell=(5e-9, 5e-9, 5e-9)) + system_y.m = df.Field(mesh, nvdim=3, value=init_m(1), norm=Ms) + md.drive(system_y) + + assert system_x.m.orientation.z.mean() > 0.25 + assert np.isclose( + system_x.m.orientation.z.mean(), system_y.m.orientation.z.mean() + ).all() + + system_x.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=(200, 0, 0), beta=0.5) + ) + td.drive(system_x, t=0.4e-9, n=1) + + system_y.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=(0, 200, 0), beta=0.5) + ) + td.drive(system_y, t=0.4e-9, n=1) + + assert system_x.m.orientation.z.mean() < -0.25 + assert np.isclose( + system_x.m.orientation.z.mean(), system_y.m.orientation.z.mean() + ).all() + + self.calculator.delete(system_x) + self.calculator.delete(system_y) From 72b892d92f50dc4bd803437dafb26afb34893909 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Sun, 9 Jun 2024 16:32:59 +0200 Subject: [PATCH 2/6] Extend test for ZhangLi with vector-valued u --- micromagnetictests/calculatortests/zhangli.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/micromagnetictests/calculatortests/zhangli.py b/micromagnetictests/calculatortests/zhangli.py index 737f556..706c3c7 100644 --- a/micromagnetictests/calculatortests/zhangli.py +++ b/micromagnetictests/calculatortests/zhangli.py @@ -140,6 +140,9 @@ def test_dict_scalar(self): def time_dep(t): return np.sin(t * 1e10) + # - default value set to 0 + # - vector-valued dictionary elements + u = {"r2": (1, 0, 0)} system.dynamics = mm.ZhangLi(u=u, beta=beta, func=time_dep, dt=1e-13) system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) @@ -162,6 +165,7 @@ def time_dep(t): tcl_strings["script_args"] = "total_time" tcl_strings["script_name"] = "TimeFunction" + u = {"r1": 0, "r2": 1} system.dynamics = mm.ZhangLi(u=u, beta=beta, tcl_strings=tcl_strings) system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) @@ -236,6 +240,14 @@ def time_dep(t): tcl_strings["script_args"] = "total_time" tcl_strings["script_name"] = "TimeFunction" + def u_fun(pos): + x, y, z = pos + if y <= 0: + return (0, 0, 0) + else: + return (1, 0, 0) + + u = df.Field(mesh, nvdim=3, value=u_fun) system.dynamics = mm.ZhangLi(u=u, beta=beta, tcl_strings=tcl_strings) system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) @@ -251,7 +263,7 @@ def time_dep(t): self.calculator.delete(system) - def test_field_vector(self): + def test_vector_scalar(self): """ Domain wall in a strip oriented in x (y) direction. Current is applied in x (y) direction. The average mz component before and after moving the domain walls @@ -290,9 +302,9 @@ def _inner(p): md.drive(system_y) assert system_x.m.orientation.z.mean() > 0.25 - assert np.isclose( + assert np.allclose( system_x.m.orientation.z.mean(), system_y.m.orientation.z.mean() - ).all() + ) system_x.dynamics = ( mm.Precession(gamma0=mm.consts.gamma0) @@ -309,9 +321,9 @@ def _inner(p): td.drive(system_y, t=0.4e-9, n=1) assert system_x.m.orientation.z.mean() < -0.25 - assert np.isclose( + assert np.allclose( system_x.m.orientation.z.mean(), system_y.m.orientation.z.mean() - ).all() + ) self.calculator.delete(system_x) self.calculator.delete(system_y) From b90ecb8a1ab2200d0603746c9abd4afab8dc4124 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Sun, 14 Jul 2024 14:15:17 +0200 Subject: [PATCH 3/6] Re-write ZhangLi tests (now based on DW motion in a nanostrip) --- micromagnetictests/calculatortests/zhangli.py | 449 +++++++++--------- 1 file changed, 213 insertions(+), 236 deletions(-) diff --git a/micromagnetictests/calculatortests/zhangli.py b/micromagnetictests/calculatortests/zhangli.py index 706c3c7..8d1fdc1 100644 --- a/micromagnetictests/calculatortests/zhangli.py +++ b/micromagnetictests/calculatortests/zhangli.py @@ -1,329 +1,306 @@ +import math + import discretisedfield as df +import micromagneticdata as mdata import micromagneticmodel as mm -import numpy as np import pytest class TestZhangLi: + """ + Each test defines a nanostrip with a domain wall in the left half. Current is + applied to move the DW to the other side of the strip. Details of the current + (direction, time dependence) are varied in the different tests. + """ + @pytest.fixture(autouse=True) def _setup_calculator(self, calculator): self.calculator = calculator - def setup_method(self): - p1 = (-5e-9, -5e-9, -3e-9) - p2 = (5e-9, 5e-9, 3e-9) - self.region = df.Region(p1=p1, p2=p2) - self.cell = (1e-9, 1e-9, 3e-9) - self.subregions = { - "r1": df.Region(p1=(-5e-9, -5e-9, -3e-9), p2=(5e-9, 0, 3e-9)), - "r2": df.Region(p1=(-5e-9, 0, -3e-9), p2=(5e-9, 5e-9, 3e-9)), + # inside setup_method it is not possible to use a fixture + @pytest.fixture(autouse=True) + def setup_method_as_fixture(self): + """Prepare nano strip (l_x=200nm) with DW at x≈70nm.""" + p1 = (0, 0, 0) + p2 = (200e-9, 20e-9, 5e-9) + cell = (5e-9, 5e-9, 5e-9) + subregions = { + "r1": df.Region(p1=(0, 0, 0), p2=(100e-9, 20e-9, 5e-9)), + "r2": df.Region(p1=(100e-9, 0, 0), p2=(200e-9, 20e-9, 5e-9)), } - def test_scalar_scalar(self): - name = "zhangli_scalar_scalar" - - u = 0 - beta = 0.5 - H = (0, 0, 1e5) - Ms = 1e6 + Ms = 5.8e5 + A = 15e-12 + K = 0.5e6 + anisotropy_axis = (0, 0, 1) - mesh = df.Mesh(region=self.region, cell=self.cell) + def init_m(p): + if p[0] < 70e-9: + return (0.1, 0.1, -1) + return (0.1, 0.1, 1) - system = mm.System(name=name) - system.energy = mm.Zeeman(H=H) - system.dynamics = mm.ZhangLi(u=u, beta=beta) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + system = mm.System(name="strip_x") + system.energy = mm.Exchange(A=A) + mm.UniaxialAnisotropy(K=K, u=anisotropy_axis) + mesh = df.Mesh(p1=p1, p2=p2, cell=cell, subregions=subregions) + system.m = df.Field(mesh, nvdim=3, value=init_m, norm=Ms) - td = self.calculator.TimeDriver() - td.drive(system, t=0.2e-9, n=50) + md = self.calculator.MinDriver() + md.drive(system) - # u is zero, nothing should change. - value = system.m(mesh.region.center) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + # ensure that the initial state is as expected, + # a domain wall at x≈70 nm + assert 0.2 < system.m.orientation.z.mean() < 0.4 + assert system.m.orientation.z.sel(x=(0, 60e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(x=(80e-9, 200e-9)).mean() > 0.95 - system.dynamics -= mm.ZhangLi(u=u, beta=beta) - # empty dynamics is not allowed - system.dynamics += mm.Damping(alpha=1) + self.u = 200 + self.beta = 0.5 + self.system = system - td.drive(system, t=0.2e-9, n=50) + def test_scalar_scalar(self): + """ + Uniform current in x direction. + """ + td = self.calculator.TimeDriver() - def test_time_scalar_scalar(self): - name = "zhangli_scalar_scalar" + system = self.system - u = 0 - beta = 0.5 - H = (0, 0, 1e5) - Ms = 1e6 + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=self.u, beta=self.beta) + ) + td.drive(system, t=0.35e-9, n=1) - mesh = df.Mesh(region=self.region, cell=self.cell) + # check that the domain wall moved to the right side of the strip to x≈130nm + assert -0.4 < system.m.orientation.z.mean() < -0.2 + assert system.m.orientation.z.sel(x=(0, 120e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(x=(140e-9, 200e-9)).mean() > 0.95 - system = mm.System(name=name) - system.energy = mm.Zeeman(H=H) - system.dynamics = mm.ZhangLi(u=u, beta=beta) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + self.calculator.delete(system) + def test_time_func_scalar_scalar(self): + """ + Uniform current in x direction with sin time dependence. + """ td = self.calculator.TimeDriver() - td.drive(system, t=0.2e-9, n=50) - # u is zero, nothing should change. - value = system.m(mesh.region.center) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + system = self.system - system.dynamics -= mm.ZhangLi(u=u, beta=beta) - # empty dynamics is not allowed - system.dynamics += mm.Damping(alpha=1) + f = 2 * math.pi / 0.6e-9 - td.drive(system, t=0.2e-9, n=50) + def time_dep(t): + return math.sin(f * t) - # Check if it runs. + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=self.u, beta=self.beta, func=time_dep, dt=1e-13) + ) - # time-dependence - function - def time_dep(t): - return np.sin(t * 1e10) + # drive for one period and save two steps + td.drive(system, t=0.6e-9, n=2) - system.dynamics = mm.ZhangLi(u=u, beta=beta, func=time_dep, dt=1e-13) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + # use micromagneticdata to read the two saved steps + drive = mdata.Data(name=system.name)[-1] - td.drive(system, t=0.2e-9, n=50) + # check that the domain wall moved to the right + # during the first half wave + assert -0.1 < drive[0].orientation.z.mean() < 0.1 + assert drive[0].orientation.z.sel(x=(0, 90e-9)).mean() < -0.95 + assert drive[0].orientation.z.sel(x=(110e-9, 200e-9)).mean() > 0.95 - # u is zero, nothing should change. - value = system.m(mesh.region.center) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + # check that the domain wall moved back to its initial position at x≈70nm + # during the second half wave + assert 0.2 < drive[1].orientation.z.mean() < 0.4 + assert drive[1].orientation.z.sel(x=(0, 60e-9)).mean() < -0.95 + assert drive[1].orientation.z.sel(x=(80e-9, 200e-9)).mean() > 0.95 + + # self.calculator.delete(system) + + def test_time_tcl_scalar_scalar(self): + """ + Uniform current in x direction with sin time dependence. + """ + td = self.calculator.TimeDriver() + system = self.system # time-dependence - tcl strings tcl_strings = {} + # pre-compute frequency (pi not directly available) + # f = 2 * pi / 0.6e-9 = 10471975511.965977 tcl_strings["script"] = """proc TimeFunction { total_time } { - return $total_time + return [expr sin(10471975511.965977 * $total_time)] } """ tcl_strings["script_args"] = "total_time" tcl_strings["script_name"] = "TimeFunction" - system.dynamics = mm.ZhangLi(u=u, beta=beta, tcl_strings=tcl_strings) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) - - td.drive(system, t=0.2e-9, n=50) - - # u is zero, nothing should change. - value = system.m(mesh.region.center) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=self.u, beta=self.beta, tcl_strings=tcl_strings) + ) - self.calculator.delete(system) + # drive for one period and save two steps + td.drive(system, t=0.6e-9, n=2) - def test_dict_scalar(self): - name = "zhangli_dict_scalar" + # use micromagneticdata to read the two saved steps + drive = mdata.Data(name=system.name)[-1] - H = (0, 0, 1e6) - u = {"r1": 0, "r2": 1} - beta = 0.5 - Ms = 1e6 + # check that the domain wall moved to the right + # during the first half wave + assert -0.1 < drive[0].orientation.z.mean() < 0.1 + assert drive[0].orientation.z.sel(x=(0, 90e-9)).mean() < -0.95 + assert drive[0].orientation.z.sel(x=(110e-9, 200e-9)).mean() > 0.95 - mesh = df.Mesh(region=self.region, cell=self.cell, subregions=self.subregions) + # check that the domain wall moved back to its initial position at x≈70nm + # during the second half wave + assert 0.2 < drive[1].orientation.z.mean() < 0.4 + assert drive[1].orientation.z.sel(x=(0, 60e-9)).mean() < -0.95 + assert drive[1].orientation.z.sel(x=(80e-9, 200e-9)).mean() > 0.95 - system = mm.System(name=name) - system.energy = mm.Zeeman(H=H) - system.dynamics = mm.ZhangLi(u=u, beta=beta) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + self.calculator.delete(system) + def test_dict_scalar(self): + """ + Current only in left half of the strip, defined with a dict. + """ td = self.calculator.TimeDriver() - td.drive(system, t=0.2e-9, n=50) - - # u=0 region - value = system.m((1e-9, -4e-9, 3e-9)) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 - - # u!=0 region - value = system.m((1e-9, 4e-9, 3e-9)) - assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 - - # time-dependence - function - def time_dep(t): - return np.sin(t * 1e10) - # - default value set to 0 - # - vector-valued dictionary elements - u = {"r2": (1, 0, 0)} - system.dynamics = mm.ZhangLi(u=u, beta=beta, func=time_dep, dt=1e-13) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + system = self.system - td.drive(system, t=0.2e-9, n=50) + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u={"r1": self.u, "r2": 0}, beta=self.beta) + ) + td.drive(system, t=0.35e-9, n=1) - # u=0 region - value = system.m((1e-9, -4e-9, 3e-9)) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + # check that the domain wall stops moving when the current stops at x≈100nm + assert -0.1 < system.m.orientation.z.mean() < 0.1 + assert system.m.orientation.z.sel(x=(0, 90e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(x=(110e-9, 200e-9)).mean() > 0.95 - # u!=0 region - value = system.m((1e-9, 4e-9, 3e-9)) - assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 + self.calculator.delete(system) - # time-dependence - tcl strings - tcl_strings = {} - tcl_strings["script"] = """proc TimeFunction { total_time } { - return $total_time - } + def test_dict_vector(self): """ - tcl_strings["script_args"] = "total_time" - tcl_strings["script_name"] = "TimeFunction" - - u = {"r1": 0, "r2": 1} - system.dynamics = mm.ZhangLi(u=u, beta=beta, tcl_strings=tcl_strings) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + Current only in left half of the strip, defined with a dict. + """ + td = self.calculator.TimeDriver() - td.drive(system, t=0.2e-9, n=50) + system = self.system - # u=0 region - value = system.m((1e-9, -4e-9, 3e-9)) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u={"r1": (self.u, 0, 0), "r2": (0, 0, 0)}, beta=self.beta) + ) + td.drive(system, t=0.35e-9, n=1) - # u!=0 region - value = system.m((1e-9, 4e-9, 3e-9)) - assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 + # check that the domain wall stops moving when the current stops at x≈100nm + assert -0.1 < system.m.orientation.z.mean() < 0.1 + assert system.m.orientation.z.sel(x=(0, 90e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(x=(110e-9, 200e-9)).mean() > 0.95 self.calculator.delete(system) def test_field_scalar(self): - name = "zhangli_field_scalar" - - mesh = df.Mesh(region=self.region, cell=self.cell) - - def u_fun(pos): - x, y, z = pos - if y <= 0: - return 0 - else: - return 1 - - H = (0, 0, 1e6) - u = df.Field(mesh, nvdim=1, value=u_fun) - beta = 0.5 - Ms = 1e6 - - system = mm.System(name=name) - system.energy = mm.Zeeman(H=H) - system.dynamics = mm.ZhangLi(u=u, beta=beta) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) - + """ + Current only in left half of the strip, defined with a Field. + """ td = self.calculator.TimeDriver() - td.drive(system, t=0.2e-9, n=50) - - # u=0 region - value = system.m((1e-9, -4e-9, 3e-9)) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 - # u!=0 region - value = system.m((1e-9, 4e-9, 3e-9)) - assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 + system = self.system - # time-dependence - function - def time_dep(t): - return np.sin(t * 1e10) - - system.dynamics = mm.ZhangLi(u=u, beta=beta, func=time_dep, dt=1e-13) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + u_field = df.Field( + mesh=system.m.mesh, nvdim=1, value=lambda p: self.u if p[0] < 100e-9 else 0 + ) - td.drive(system, t=0.2e-9, n=50) + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=u_field, beta=self.beta) + ) + td.drive(system, t=0.35e-9, n=1) - # u=0 region - value = system.m((1e-9, -4e-9, 3e-9)) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + # check that the domain wall stops moving when the current stops at x≈100nm + assert -0.1 < system.m.orientation.z.mean() < 0.1 + assert system.m.orientation.z.sel(x=(0, 90e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(x=(110e-9, 200e-9)).mean() > 0.95 - # u!=0 region - value = system.m((1e-9, 4e-9, 3e-9)) - assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 + self.calculator.delete(system) - # time-dependence - tcl strings - tcl_strings = {} - tcl_strings["script"] = """proc TimeFunction { total_time } { - return $total_time - } + def test_field_vector(self): """ - tcl_strings["script_args"] = "total_time" - tcl_strings["script_name"] = "TimeFunction" - - def u_fun(pos): - x, y, z = pos - if y <= 0: - return (0, 0, 0) - else: - return (1, 0, 0) + Current only in left half of the strip, defined with a Field. + """ + td = self.calculator.TimeDriver() - u = df.Field(mesh, nvdim=3, value=u_fun) - system.dynamics = mm.ZhangLi(u=u, beta=beta, tcl_strings=tcl_strings) - system.m = df.Field(mesh, nvdim=3, value=(0, 0.1, 1), norm=Ms) + system = self.system - td.drive(system, t=0.2e-9, n=50) + u_field = df.Field( + mesh=system.m.mesh, + nvdim=3, + value=lambda p: (self.u, 0, 0) if p[0] < 100e-9 else (0, 0, 0), + ) - # u=0 region - value = system.m((1e-9, -4e-9, 3e-9)) - assert np.linalg.norm(np.cross(value, (0, 0.1 * Ms, Ms))) < 1e-3 + system.dynamics = ( + mm.Precession(gamma0=mm.consts.gamma0) + + mm.Damping(alpha=0.3) + + mm.ZhangLi(u=u_field, beta=self.beta) + ) + td.drive(system, t=0.35e-9, n=1) - # u!=0 region - value = system.m((1e-9, 4e-9, 3e-9)) - assert np.linalg.norm(np.subtract(value, (0, 0, Ms))) > 1 + # check that the domain wall stops moving when the current stops at x≈100nm + assert -0.1 < system.m.orientation.z.mean() < 0.1 + assert system.m.orientation.z.sel(x=(0, 90e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(x=(110e-9, 200e-9)).mean() > 0.95 self.calculator.delete(system) def test_vector_scalar(self): """ - Domain wall in a strip oriented in x (y) direction. Current is applied in x (y) - direction. The average mz component before and after moving the domain walls - are compared. There is no check for mx and my because we do not ensure same - chirality of the domain walls. + Strip oriented along y with uniform current applied in y direction. """ md = self.calculator.MinDriver() td = self.calculator.TimeDriver() - pa = 200e-9 - pb = 20e-9 - Ms = 5.8e5 + system = self.system - def init_m(direction): - def _inner(p): - if p[direction] < 70e-9: - return (0.1, 0.1, -1) - return (0.1, 0.1, 1) + # replace system m with strip along y + p1 = (0, 0, 0) + p2 = (20e-9, 200e-9, 5e-9) + cell = (5e-9, 5e-9, 5e-9) - return _inner + def init_m(p): + if p[1] < 70e-9: + return (0.1, 0.1, -1) + return (0.1, 0.1, 1) - A = 15e-12 - K = 0.5e6 - u = (0, 0, 1) - - system_x = mm.System(name="strip_x") - system_x.energy = mm.Exchange(A=A) + mm.UniaxialAnisotropy(K=K, u=u) - mesh = df.Mesh(p1=(0, 0, 0), p2=(pa, pb, 5e-9), cell=(5e-9, 5e-9, 5e-9)) - system_x.m = df.Field(mesh, nvdim=3, value=init_m(0), norm=Ms) - md.drive(system_x) - - system_y = mm.System(name="strip_y") - system_y.energy = mm.Exchange(A=A) + mm.UniaxialAnisotropy(K=K, u=u) - mesh = df.Mesh(p1=(0, 0, 0), p2=(pb, pa, 5e-9), cell=(5e-9, 5e-9, 5e-9)) - system_y.m = df.Field(mesh, nvdim=3, value=init_m(1), norm=Ms) - md.drive(system_y) - - assert system_x.m.orientation.z.mean() > 0.25 - assert np.allclose( - system_x.m.orientation.z.mean(), system_y.m.orientation.z.mean() - ) + mesh = df.Mesh(p1=p1, p2=p2, cell=cell) + Ms = 5.8e5 + system.m = df.Field(mesh, nvdim=3, value=init_m, norm=Ms) - system_x.dynamics = ( - mm.Precession(gamma0=mm.consts.gamma0) - + mm.Damping(alpha=0.3) - + mm.ZhangLi(u=(200, 0, 0), beta=0.5) - ) - td.drive(system_x, t=0.4e-9, n=1) + md.drive(system) - system_y.dynamics = ( + # ensure that the initial state is as expected, + # a domain wall at y≈70 nm + assert 0.2 < system.m.orientation.z.mean() < 0.4 + assert system.m.orientation.z.sel(y=(0, 60e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(y=(80e-9, 200e-9)).mean() > 0.95 + + system.dynamics = ( mm.Precession(gamma0=mm.consts.gamma0) + mm.Damping(alpha=0.3) + mm.ZhangLi(u=(0, 200, 0), beta=0.5) ) - td.drive(system_y, t=0.4e-9, n=1) + td.drive(system, t=0.35e-9, n=1) - assert system_x.m.orientation.z.mean() < -0.25 - assert np.allclose( - system_x.m.orientation.z.mean(), system_y.m.orientation.z.mean() - ) + # check that the domain wall moved to the right side of the strip to y≈130nm + assert -0.4 < system.m.orientation.z.mean() < -0.2 + assert system.m.orientation.z.sel(y=(0, 120e-9)).mean() < -0.95 + assert system.m.orientation.z.sel(y=(140e-9, 200e-9)).mean() > 0.95 - self.calculator.delete(system_x) - self.calculator.delete(system_y) + self.calculator.delete(system) From 0b9f91cb29a0494d4e3749f4cc31607210740cec Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Sun, 14 Jul 2024 14:21:21 +0200 Subject: [PATCH 4/6] Add micromagneticdata as dependency --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index ea390ad..e3bccb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ classifiers = [ dependencies = [ "micromagneticmodel>=0.63.2", + "micromagneticdata>=0.65.2", "scipy>=1.5" ] From 8ba12fad00b36ca911723f06c3678e636bf7218d Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Sun, 14 Jul 2024 14:38:01 +0200 Subject: [PATCH 5/6] Rename all ZhangLi tests to hopefully more meaningful names --- micromagnetictests/calculatortests/zhangli.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/micromagnetictests/calculatortests/zhangli.py b/micromagnetictests/calculatortests/zhangli.py index 8d1fdc1..43f1bda 100644 --- a/micromagnetictests/calculatortests/zhangli.py +++ b/micromagnetictests/calculatortests/zhangli.py @@ -57,7 +57,7 @@ def init_m(p): self.beta = 0.5 self.system = system - def test_scalar_scalar(self): + def test_scalar_u(self): """ Uniform current in x direction. """ @@ -79,7 +79,7 @@ def test_scalar_scalar(self): self.calculator.delete(system) - def test_time_func_scalar_scalar(self): + def test_time_func_scalar_u(self): """ Uniform current in x direction with sin time dependence. """ @@ -118,7 +118,7 @@ def time_dep(t): # self.calculator.delete(system) - def test_time_tcl_scalar_scalar(self): + def test_time_tcl_scalar_u(self): """ Uniform current in x direction with sin time dependence. """ @@ -162,7 +162,7 @@ def test_time_tcl_scalar_scalar(self): self.calculator.delete(system) - def test_dict_scalar(self): + def test_dict_scalar_u(self): """ Current only in left half of the strip, defined with a dict. """ @@ -184,7 +184,7 @@ def test_dict_scalar(self): self.calculator.delete(system) - def test_dict_vector(self): + def test_dict_vector_u(self): """ Current only in left half of the strip, defined with a dict. """ @@ -206,7 +206,7 @@ def test_dict_vector(self): self.calculator.delete(system) - def test_field_scalar(self): + def test_field_scalar_u(self): """ Current only in left half of the strip, defined with a Field. """ @@ -232,7 +232,7 @@ def test_field_scalar(self): self.calculator.delete(system) - def test_field_vector(self): + def test_field_vector_u(self): """ Current only in left half of the strip, defined with a Field. """ @@ -260,7 +260,7 @@ def test_field_vector(self): self.calculator.delete(system) - def test_vector_scalar(self): + def test_vector_u(self): """ Strip oriented along y with uniform current applied in y direction. """ From 7ba4b05749548ffe4eb8a8d5af81d3b7f419097a Mon Sep 17 00:00:00 2001 From: Martin Lang <67915889+lang-m@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:54:06 +0200 Subject: [PATCH 6/6] Update micromagnetictests/calculatortests/zhangli.py Co-authored-by: Sam Holt <48217392+samjrholt@users.noreply.github.com> --- micromagnetictests/calculatortests/zhangli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micromagnetictests/calculatortests/zhangli.py b/micromagnetictests/calculatortests/zhangli.py index 43f1bda..8ebbd3e 100644 --- a/micromagnetictests/calculatortests/zhangli.py +++ b/micromagnetictests/calculatortests/zhangli.py @@ -294,7 +294,7 @@ def init_m(p): system.dynamics = ( mm.Precession(gamma0=mm.consts.gamma0) + mm.Damping(alpha=0.3) - + mm.ZhangLi(u=(0, 200, 0), beta=0.5) + + mm.ZhangLi(u=(0, self.u, 0), beta=self.beta) ) td.drive(system, t=0.35e-9, n=1)