Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3a7cde4
Implement window shift
lamoreel May 7, 2025
a2fb820
Merge branch 'dev' into moving-window
lamoreel May 7, 2025
09ef235
Let user insert values at boundaries
lamoreel May 7, 2025
4f8a5f8
Add proper window shift
lamoreel May 13, 2025
75687ae
Improve shift calculation
lamoreel May 14, 2025
1fc19f9
Merge branch 'dev' into moving-window
lamoreel Jun 4, 2026
c86696e
Minor clean-up after a year's worth of dust
lamoreel Jun 5, 2026
382bf67
Fix DW position determination
lamoreel Jun 5, 2026
1f85324
Generalize horizontal shift
lamoreel Jun 5, 2026
52ad56a
Use checkout@v6 to avoid Node.js 20 deprecation
JonathanMaes Jun 8, 2026
d15698f
Avoid upcoming change to MSVC 2026 in windows-latest runner
JonathanMaes Jun 8, 2026
411c5ed
Use download-artifact@v7 to avoid Node.js 20 deprecation
JonathanMaes Jun 8, 2026
b243fd6
Fix unexpected input warning
JonathanMaes Jun 8, 2026
217e048
Re-center website navbar icon links
JonathanMaes Jun 8, 2026
e0597f4
Generalize to all domain magnetization directions
lamoreel Jun 8, 2026
e6f5eb3
Support shift in all orthogonal directions
lamoreel Jun 9, 2026
93df4ae
Add support for multi-sublattice systems
lamoreel Jun 9, 2026
0a6aafb
Add test
lamoreel Jun 12, 2026
9ce0303
Add Python documentation and checks
lamoreel Jun 15, 2026
1b93dd6
Slightly improve documentation
lamoreel Jun 15, 2026
4b811ed
Add chiral ME coupling constant to field and force
ilateur Jun 15, 2026
f6111ae
Reduce compatibility to uniform magnets
lamoreel Jun 17, 2026
e342b02
Account for non-zero origin
lamoreel Jun 17, 2026
3e53820
Postpone geometry/regions setting
lamoreel Jun 18, 2026
6d02cca
Add suggested changes to src/
lamoreel Jun 23, 2026
74236d3
Merge branch 'master' into dev
ilateur Jun 24, 2026
10868e0
Add test for the chiral magnetoelastic field
ilateur Jun 25, 2026
0dcbf90
Add test for the chiral magnetoelastic force
ilateur Jun 25, 2026
cafe40c
Add test for the (chiral) magnetoelastic field with rigid strain
ilateur Jun 25, 2026
25cfac4
Add suggested changes in Python wrapper
lamoreel Jul 6, 2026
e4efb67
Add function to disable window motion
lamoreel Jul 6, 2026
064d923
Add example
lamoreel Jul 6, 2026
aa53f37
Merge branch 'master' into dev
ilateur Jul 13, 2026
6044631
Change docstring of B_chiral
ilateur Jul 13, 2026
b4e62bc
Tweak example
lamoreel Jul 14, 2026
4e507ae
Add requested changes
lamoreel Jul 15, 2026
4c64a0d
Update tick positions instead of labels
lamoreel Jul 15, 2026
f82397d
Don't fix typo with typo
lamoreel Jul 15, 2026
7d2ed40
Clarify B_chiral docstring citation
ilateur Jul 15, 2026
c957a6a
Clarify even harder
ilateur Jul 16, 2026
fee7e8b
Merge pull request #164 from mumax/feature/chiral-ME
ilateur Jul 16, 2026
a98da4a
Merge pull request #161 from mumax/moving-window-uniform
lamoreel Jul 27, 2026
3b4ecbb
Add #include <array> to window.hpp
DiegoDeGusem Jul 28, 2026
3cdab9e
Remove unused argument
ilateur Jul 29, 2026
5e4ccdb
Remove unused width and Ny from multilayer example
ilateur Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
matrix:
os:
- {name: "ubuntu", version: "22.04"}
- {name: "windows", version: "latest"}
- {name: "windows", version: "2022"}
cuda: ["12.4.1"]
python: ["3.11", "3.12", "3.13", "3.14"]

Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:

steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7
with:
path: artifacts

Expand Down Expand Up @@ -158,6 +158,6 @@ jobs:
with:
tag_name: ${{ github.event.release.tag_name || github.event.inputs.tag }}
files: dist-gh-release/*
overwrite: true
overwrite_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Deploy docs/_build/html to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
Expand Down
4 changes: 4 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ html[data-theme="dark"] .navbar-brand img {
display: block;
width: 100%;
}

.bd-sidebar-primary .navbar-icon-links {
justify-content: space-evenly !important;
}
1 change: 1 addition & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ API
PoissonSystem
DmiTensor
BoundaryTraction
Window

.. toctree::
:maxdepth: 1
Expand Down
1 change: 1 addition & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Here we show some example Python scripts to run mumax⁺ simulations.
examples/DW_SAW
examples/voronoi
examples/Bloch_wall_altermagnet
examples/moving_window
22 changes: 22 additions & 0 deletions docs/examples/moving_window.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
:nosearch:

Moving simulation window
========================

In this example we move a domain wall in a ferromagnet using a Zhang-Li STT. We let the simulation
window move together with the wall, keeping the domain wall centered in the simulation space.
Using this, we can virtually simulate an infinitely long magnetic nanowire using a limited number
of simulation cells.

Note:
The moving window functionality only works properly if
- The magnet parameters are uniform
- The magnet has no geometry
- The magnet has no regions

.. literalinclude:: ../../examples/moving_window.py
:language: python
:lines: 13-

.. video:: ../images/moving_window.mp4
:align: center
Binary file added docs/images/moving_window.mp4
Binary file not shown.
3 changes: 0 additions & 3 deletions examples/Bloch_wall_altermagnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@
A12 = A0/2

length = 256e-9
width = 64e-9

# ----------- Create altermagnet -----------

Nx = int(length / cs)
Ny = int(width / cs)

world = World((cs, cs, cs))
grid = Grid((Nx, 1, 1))
magnet = Altermagnet(world, grid)
Expand Down
146 changes: 146 additions & 0 deletions examples/moving_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
"""
In this example we move a domain wall in a ferromagnet using a Zhang-Li STT. We let the simulation
window move together with the wall, keeping the domain wall centered in the simulation space.
Using this, we can virtually simulate an infinitely long magnetic nanowire using a limited number
of simulation cells.

Note:
The moving window functionality only works properly if
- The magnet parameters are uniform
- The magnet has no geometry
- The magnet has no regions
"""
from mumaxplus import World, Grid, Ferromagnet
from mumaxplus.util import twodomain, plot_field

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, FFMpegWriter
import numpy as np

# ----------- Material and simulation parameters -----------
cs = 1e-9
length = 256e-9
width = 64e-9
thickness = 1e-9

Ms = 600e3
aex = 10e-12
alpha = 0.02
ku = 6e5
anisU = (1, 0, 0)

# ----------- Create magnet -----------
world = World((cs, cs, cs))
grid = Grid((int(length / cs), int(width / cs), int(thickness / cs)))

magnet = Ferromagnet(world, grid)

magnet.msat = Ms
magnet.aex = aex
magnet.alpha = alpha
magnet.ku1 = ku
magnet.anisU = anisU

magnet.enable_demag = False
magnet.enable_openbc = True


# ----------- Create two domain state -----------
magnet.magnetization = twodomain((1, 0, 0), (0, 1, 0), (-1, 0, 0), magnet.center[0], 5e-9)
magnet.minimize()

# ----------- Add current and simulate -----------
magnet.jcur = (-1e12, 0, 0)
magnet.xi = 0.2
magnet.pol = 1

# Center the simulation window, keeping component 0 (x) close to zero.
# We expect motion along the x axis.
world.center_domain_wall(comp=0, axis=0)

tmax = 0.5e-9
timepoints = np.linspace(0, tmax, 100)

def DW_pos(field):
mx = field[0, 0, int(width / cs/2), :]
sign = np.sign(mx)
# find cell where magnetization component crosses zero
i = np.where(np.diff(sign) != 0)[0][0]
# linearly interpolate
m1, m2 = mx[i], mx[i + 1]
return (i - m1 / (m2 - m1)) * cs

outputquantities = {"mag": magnet.magnetization,
"window position": lambda: world.window.position[0],
"wall position": lambda: world.window.position[0] + DW_pos(magnet.magnetization())}

output = world.timesolver.solve(timepoints, outputquantities, tqdm=True)

p0 = output["wall position"][0]

# ----------- Create movie -----------
print("Creating animation...")
fig, axes = plt.subplots(2, 1, figsize=(10, 7))

# Time trace subplot
ax_trace = axes[0]
lines = {}
keys = ["window position", "wall position"]
for key in keys:
lines[key], = ax_trace.plot([], [], '-', label=key)

ax_trace.set_xlim(0, tmax * 1e9)
ax_trace.set_ylim(min(0, min(output["window position"]) * 1e9),
max(0, max(output["wall position"] - p0) * 1e9))
ax_trace.set_xlabel("Time $t$ (ns)")
ax_trace.set_ylabel("position (nm)")
ax_trace.legend()
ax_trace.grid()

# Magnetization image subplot
ax_image = axes[1]
plot_field(output["mag"][0], ax=ax_image, arrow_size=8)

ax_image.set_xlim(0, int(length/cs))
ticks = ax_image.get_xticks()

ax_image.set_title("$t$ = 0.000 ns")
ax_image.set_xlabel("$x$ (nm)")
ax_image.set_ylabel("$y$ (nm)")

fig.tight_layout()

# --- Animation Function ---
def update(frame):
# Update image
ax_image.clear()
plot_field(output["mag"][frame], ax=ax_image, arrow_size=8)
ax_image.set_xlabel("$x$ (nm)")
ax_image.set_ylabel("$y$ (nm)")

# update x-ticks
shift = output["window position"][frame] * 1e9
tick_positions = (ticks - shift)
mask = (0 <= tick_positions) & (tick_positions <= int(length/cs))

ax_image.set_xticks(tick_positions[mask])
ax_image.set_xticklabels([f"{t:.0f}" for t in ticks[mask]])
ax_image.set_title(f"$t$ = {output['time'][frame] * 1e9:.3f} ns")

# Update time trace
lines["window position"].set_data(np.array(output["time"][:frame+1]) * 1e9,
np.array(output["window position"][:frame+1]) * 1e9)
lines["wall position"].set_data(np.array(output["time"][:frame+1]) * 1e9,
np.array(output["wall position"][:frame+1] - p0) * 1e9)

return [ax_image] + list(lines.values())

# Animation parameters
fps = 15
anim = FuncAnimation(fig, update, frames=len(output["time"]),
interval=1000 / fps, repeat_delay=5000 / fps)

# --- Save the animation ---
save_filename = "moving_window.mp4"
writer = FFMpegWriter(fps=fps)
anim.save(save_filename, writer=writer)
4 changes: 2 additions & 2 deletions examples/standardproblem2.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def get_next_power_of_2(x):
y *= 2
return y

def get_gridsize(L, d, t, l_ex=l_ex):
def get_gridsize(L, d, t):
"""Cell length should at least be < l_ex/2. The number of cells is best
a power of 2 for FFT. This results in cell sizes between 0.25*l_ex and
0.5*l_ex."""
Expand All @@ -42,7 +42,7 @@ def get_gridsize(L, d, t, l_ex=l_ex):
L = L_p_d * d # dimensionless length L = length/l_ex
t = t_p_d * d # dimensionless thickness t = thickness/l_ex

nx, ny, nz = get_gridsize(L, d, t, l_ex=l_ex)
nx, ny, nz = get_gridsize(L, d, t)
world = World(cellsize=(L*l_ex/nx, d*l_ex/ny, t*l_ex/nz))
magnet = Ferromagnet(world, Grid((nx, ny, nz)))
magnet.msat = msat
Expand Down
2 changes: 2 additions & 0 deletions mumaxplus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from .traction import BoundaryTraction
from .variable import Variable
from .world import World
from .window import Window
from . import util

FP_PRECISION = {1: "SINGLE", 2: "DOUBLE"}.get(_cpp.FP_PRECISION, "UNKNOWN") # Use _cpp value, as that is certainly the correct one
Expand All @@ -77,6 +78,7 @@
"TimeSolver",
"Variable",
"World",
"Window",
"PoissonSystem",
"util",
"FP_PRECISION"
Expand Down
38 changes: 34 additions & 4 deletions mumaxplus/ferromagnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ def B1(self) -> Parameter:

See Also
--------
B2
B2, B_chiral
"""
return Parameter(self._impl.B1)

Expand All @@ -678,7 +678,7 @@ def B2(self) -> Parameter:

See Also
--------
B1
B1, B_chiral
"""
return Parameter(self._impl.B2)

Expand All @@ -697,6 +697,36 @@ def B2(self, value):
+ " is set to a positive value, instead of negative (or zero)."
+ " Make sure this is intentional!", UserWarning)

@property
def B_chiral(self) -> Parameter:
r"""Chiral magnetoelastic coupling constant (J/m³).

Notes
-----
Materials of the cubic point group 23 (or B20 compounds) can have a
chiral magnetoelastic coupling, with the following energy density.

.. math:: \mathcal{E} = B_\text{chiral} \sum_{i, j, k} \epsilon_{ijk} \varepsilon_{ii} m_j^2

Here :math:`\epsilon_{ijk}` is the Levi-Civita symbol and
:math:`\varepsilon_{ii}` denotes the normal strain components.
This energy density comes from equations (8.12) and (8.16) in Ref. [1], where
B_chiral corresponds to :math:`\lambda_{12}`. Magnetoelastic coupling constants
B1 and B2 correspond to :math:`\lambda_{11}` and :math:`2 \lambda_{44}` respectively.
These lambdas are not the usual magnetostrictive coefficients.

.. [1] L\ . Franke, “Elastic Coupling at Quantum Phase Transitions and in Chiral Magnets,” Das Karlsruher Institut für Technologie, Karlsruhe, 2025. doi: 10.5445/IR/1000184834.

See Also
--------
B1, B2
"""
return Parameter(self._impl.B_chiral)

@B_chiral.setter
def B_chiral(self, value):
self.B_chiral.set(value)

# ----- POISSON SYSTEM ----------------------

@property
Expand Down Expand Up @@ -1128,7 +1158,7 @@ def magnetoelastic_field(self) -> FieldQuantity:

See Also
--------
B1, B2
B1, B2, B_chiral
Magnet.strain_tensor, Magnet.rigid_norm_strain, Magnet.rigid_shear_strain
magnetoelastic_force
"""
Expand Down Expand Up @@ -1160,7 +1190,7 @@ def magnetoelastic_force(self) -> FieldQuantity:

See Also
--------
B1, B2
B1, B2, B_chiral
Magnet.effective_body_force, magnetoelastic_field
"""
return FieldQuantity(_cpp.magnetoelastic_force(self._impl))
2 changes: 1 addition & 1 deletion mumaxplus/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"show_magnet_geometry",
"show_field_3D",
"show_regions",
# voronoi
# misc
"VoronoiTessellator",
"MFM"
]
1 change: 1 addition & 0 deletions mumaxplus/util/voronoi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .. import _cpp
from mumaxplus.world import World
from mumaxplus.grid import Grid

class VoronoiTessellator:


Expand Down
Loading