├── fidimag ├── extensions │ ├── __init__.py │ └── user │ │ └── __init__.py ├── atomistic │ ├── test.txt │ ├── lib │ │ ├── fmmlib │ │ │ ├── utils.hpp │ │ │ ├── utils.cpp │ │ │ ├── tree.hpp │ │ │ ├── fmmlib.pyx │ │ │ └── calculate.hpp │ │ ├── fidimag_random.h │ │ └── sllg.c │ ├── __init__.py │ ├── fmmlib │ │ ├── example.py │ │ ├── utils.cpp │ │ ├── utils.hpp │ │ └── calculate.hpp │ ├── field.py │ ├── materials.py │ ├── exchange_new.py │ ├── energy.py │ ├── demag_full.py │ └── llg.py ├── user │ ├── example │ │ ├── __init__.py │ │ └── example.pyx │ └── README.md ├── common │ ├── __init__.py │ ├── constant.py │ ├── neb_method │ │ ├── nebm_spherical_lib.h │ │ ├── nebm_integrators.h │ │ ├── nebm_geodesic_lib.h │ │ └── nebm_integrators.c │ ├── citation.py │ ├── sim2fdfield.py │ ├── field.py │ ├── helper.py │ ├── save_vtk.py │ ├── vtk.py │ └── dipolar │ │ └── license.txt ├── micro │ ├── __init__.py │ ├── simple_demag.py │ ├── lib │ │ ├── baryakhtar │ │ │ └── baryakhtar_clib.h │ │ └── micro_clib.h │ ├── energy.py │ ├── exchange.py │ ├── relax.py │ └── exchange_rkky.py └── __init__.py ├── bin ├── install-python-packages.sh ├── install-ubuntu-packages.sh ├── install-scikit-odes.sh ├── ubuntu_install_script.sh ├── fix_load_path_mac.py ├── install-fftw.sh └── install-sundials.sh ├── pytest.ini ├── doc ├── images │ ├── nebm.png │ ├── nebm_classes.png │ ├── bobber_toron_vis.png │ └── 2d-lattice-triagonal.pdf ├── user_guide │ ├── ipynb │ │ ├── sanitize_file │ │ └── runtimes.org │ └── index.rst ├── environment.yml ├── _templates │ └── custom-template.html ├── physics_num_methods │ ├── index.rst │ └── monte_carlo.rst ├── index.rst └── todo.org ├── examples ├── micromagnetic │ ├── std4 │ │ └── res.pdf │ ├── skyrmion_stt │ │ ├── m0.npy │ │ └── main.py │ ├── nmag_example_2_box │ │ ├── sim.py │ │ └── plot.py │ ├── pbc_2d │ │ ├── single_cube.py │ │ ├── rod.py │ │ └── main.py │ ├── PRB_88_184422 │ │ ├── oommf │ │ │ └── dmi.mif │ │ └── plot.py │ ├── baryakhtar │ │ └── relax_system.py │ ├── spatial_dmi │ │ └── main.py │ ├── skyrmion │ │ ├── main.py │ │ └── Ku_H │ │ │ └── main.py │ ├── vortex_oommf │ │ ├── relax.mif │ │ └── dyn │ │ │ └── dyn.mif │ ├── std4_oommf │ │ └── stdprob4.mif │ └── single_spin │ │ └── single_spin.py ├── atomistic │ ├── skyrmion │ │ └── skx_rotation │ │ │ ├── m_z_backup.png │ │ │ └── deal_m.py │ ├── dmi │ │ ├── dmi_1d.py │ │ ├── dmi_2d.py │ │ └── interfacial_dmi_dw │ │ │ └── dw.py │ ├── PRL_111_067203 │ │ └── phase_res │ │ │ └── plot.py │ ├── heat │ │ ├── macrospin.py │ │ ├── compute_energy.py │ │ ├── dw-heat.py │ │ └── temperature.py │ ├── dynamic_spectrum │ │ └── plot_results.py │ ├── PRL_108_017601 │ │ ├── figure1.py │ │ └── figure2.py │ ├── dw_demag │ │ └── dw_demag.py │ ├── dw_field │ │ └── dw-field.py │ ├── stt │ │ ├── single_spin_stt.py │ │ └── stt.py │ ├── skyrmion_demag │ │ └── single_ku.py │ ├── demag_field │ │ └── demag_field.py │ └── sw.py ├── neb_micromagnetic │ ├── skyrmion │ │ ├── results │ │ │ └── energy_167.pdf │ │ ├── plot.py │ │ └── relaxation │ │ │ ├── skyrmion_down_relax.py │ │ │ └── skyrmion_relax.py │ └── domain_wall │ │ └── dw.py ├── mc │ └── skx.py ├── eigen │ └── skx.py └── nebm_atomistic │ ├── 1D_spin_chain │ └── relaxation │ │ ├── 1D_spin_chain_fm.py │ │ └── 1D_spin_chain.py │ └── skyrmion_reduced │ └── relax.py ├── tests ├── omfs │ ├── test_dmi_field_oommf.ohf │ ├── test_exch_field_oommf.ohf │ ├── test_with_oommf_spatial_Ms_Demag.ohf │ ├── test_demag_field_oommf_large_Demag.ohf │ ├── test_with_oommf_spatial_Ms_Exchange.ohf │ ├── test_demag_field_oommf_large_Exchange.ohf │ └── dmi-Oxs_TimeDriver-Magnetization-00-0000963.omf ├── mini_test.py ├── __init__.py ├── conftest.py ├── test_citation.py ├── test_imports.py ├── field_test.py ├── vtk_refs │ ├── save_scalar_000000.vtk │ ├── save_vector_000000.vtk │ └── scalar_hexagonal_000000.vtk ├── test_init_scalar.py ├── test_mesh.py ├── test_llg_raises_error.py ├── test_init_vector.py ├── test_atomistic_zeeman.py ├── test_regression_init_scalar.py ├── test_time_zeeman.py ├── test_add_remove_interaction.py ├── test_2dpbc_cube.py ├── test_anis.py ├── test_check_ms_inv_sensible.py ├── test_spatial_exch.py ├── test_stt_slonczewski.py ├── test_demag.py ├── test_monte_carlo.py ├── test_vtk_writing.py ├── test_exch_rkky.py ├── test_dw_dmi.py ├── test_hubert_minimiser.py └── test_micromagnetic_zeeman.py ├── sandbox ├── parallel-cvode │ ├── run_multiple.sh │ ├── test_cvode_serial.py │ ├── test_cvode_parallel.py │ └── test.py ├── relaxation_test │ └── skyrmion.py ├── more-dmi │ ├── dmi-test.py │ ├── isolated_sk_T-Oxs_DMI_T-Field-00-0000000.ohf │ ├── isolated_sk_sim.py │ └── test_dmi.mif └── memory_leak │ └── fidimag_memory_issue_example.py ├── docker ├── minimal-py2 │ ├── Dockerfile.org │ ├── Makefile │ ├── Readme.md │ └── Dockerfile ├── notebook │ ├── Makefile │ ├── Dockerfile │ └── Readme.md ├── minimal-py3 │ ├── Makefile │ ├── Readme.md │ └── Dockerfile └── testing │ └── Dockerfile ├── .readthedocs.yml ├── .travis.yml ├── .gitignore ├── .github └── workflows │ ├── superlinter.yml │ └── build.yml ├── pyproject.toml ├── LICENSE.txt └── Dockerfile /fidimag/extensions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fidimag/extensions/user/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fidimag/atomistic/test.txt: -------------------------------------------------------------------------------- 1 | this is a test file. 2 | -------------------------------------------------------------------------------- /bin/install-python-packages.sh: -------------------------------------------------------------------------------- 1 | pip install --upgrade cython psutil ipywidgets 2 | -------------------------------------------------------------------------------- /fidimag/user/example/__init__.py: -------------------------------------------------------------------------------- 1 | from fidimag.extensions.user.example import * 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | markers = 3 | slow: Mark tests that will take long time to finish 4 | -------------------------------------------------------------------------------- /doc/images/nebm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/doc/images/nebm.png -------------------------------------------------------------------------------- /doc/images/nebm_classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/doc/images/nebm_classes.png -------------------------------------------------------------------------------- /doc/images/bobber_toron_vis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/doc/images/bobber_toron_vis.png -------------------------------------------------------------------------------- /doc/images/2d-lattice-triagonal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/doc/images/2d-lattice-triagonal.pdf -------------------------------------------------------------------------------- /doc/user_guide/ipynb/sanitize_file: -------------------------------------------------------------------------------- 1 | [matplotlib_text_output] 2 | regex: \<(matplotlib|Figure).* 3 | replace: MATPLOTLIB-FIGURE 4 | 5 | -------------------------------------------------------------------------------- /examples/micromagnetic/std4/res.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/examples/micromagnetic/std4/res.pdf -------------------------------------------------------------------------------- /tests/omfs/test_dmi_field_oommf.ohf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/test_dmi_field_oommf.ohf -------------------------------------------------------------------------------- /tests/omfs/test_exch_field_oommf.ohf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/test_exch_field_oommf.ohf -------------------------------------------------------------------------------- /examples/micromagnetic/skyrmion_stt/m0.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/examples/micromagnetic/skyrmion_stt/m0.npy -------------------------------------------------------------------------------- /tests/mini_test.py: -------------------------------------------------------------------------------- 1 | import fidimag as f 2 | 3 | mesh = f.common.CuboidMesh(nx=5, ny=1, nz=1) 4 | sim = f.micro.Sim(mesh) 5 | 6 | sim.set_m([0., 0., 1.]) 7 | -------------------------------------------------------------------------------- /tests/omfs/test_with_oommf_spatial_Ms_Demag.ohf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/test_with_oommf_spatial_Ms_Demag.ohf -------------------------------------------------------------------------------- /tests/omfs/test_demag_field_oommf_large_Demag.ohf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/test_demag_field_oommf_large_Demag.ohf -------------------------------------------------------------------------------- /tests/omfs/test_with_oommf_spatial_Ms_Exchange.ohf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/test_with_oommf_spatial_Ms_Exchange.ohf -------------------------------------------------------------------------------- /tests/omfs/test_demag_field_oommf_large_Exchange.ohf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/test_demag_field_oommf_large_Exchange.ohf -------------------------------------------------------------------------------- /examples/atomistic/skyrmion/skx_rotation/m_z_backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/examples/atomistic/skyrmion/skx_rotation/m_z_backup.png -------------------------------------------------------------------------------- /examples/neb_micromagnetic/skyrmion/results/energy_167.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/examples/neb_micromagnetic/skyrmion/results/energy_167.pdf -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from numpy import allclose 2 | 3 | 4 | def very_close(a, b): 5 | """ close to machine precision """ 6 | return allclose(a, b, rtol=1e-14, atol=1e-14) 7 | -------------------------------------------------------------------------------- /tests/omfs/dmi-Oxs_TimeDriver-Magnetization-00-0000963.omf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computationalmodelling/fidimag/HEAD/tests/omfs/dmi-Oxs_TimeDriver-Magnetization-00-0000963.omf -------------------------------------------------------------------------------- /sandbox/parallel-cvode/run_multiple.sh: -------------------------------------------------------------------------------- 1 | for ((i = 1; i <= 16; i++)); do 2 | export OMP_NUM_THREADS=$i 3 | echo $OMP_NUM_THREADS 4 | python test_cvode_serial.py 5 | python test_cvode_parallel.py 6 | done 7 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/fmmlib/utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FMMLIB_UTILS_HPP 2 | #define FMMLIB_UTILS_HPP 3 | 4 | unsigned int TriangleNumbers(unsigned int n); 5 | 6 | unsigned int Nterms(unsigned int p); 7 | 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | import tempfile 4 | 5 | @pytest.fixture(scope="session", autouse=True) 6 | def config(): 7 | tmpdir = tempfile.mkdtemp(suffix='fidimag-tests') 8 | os.chdir(tmpdir) 9 | -------------------------------------------------------------------------------- /doc/environment.yml: -------------------------------------------------------------------------------- 1 | # name of the conda environment 2 | name: fidimag_docs 3 | 4 | dependencies: 5 | - pandoc 6 | - nbformat 7 | - pip: 8 | - ipython 9 | - nbsphinx 10 | - pydata-sphinx-theme 11 | -------------------------------------------------------------------------------- /examples/neb_micromagnetic/skyrmion/plot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from util.helper import plot_energy_2d, plot_energy_3d 4 | 5 | plot_energy_2d('neb_nanodisk_d50nm_k1e10') 6 | plot_energy_3d('neb_nanodisk_d50nm_k1e10') 7 | -------------------------------------------------------------------------------- /docker/minimal-py2/Dockerfile.org: -------------------------------------------------------------------------------- 1 | * How to use 2 | 3 | ** Linux 4 | 5 | $> sudo docker pull fangohr/fidimag 6 | 7 | $> docker run -ci fangohr/fidimag ipython 8 | 9 | then try 'import fidimag'. 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: "ubuntu-20.04" 5 | tools: 6 | python: "mambaforge-22.9" 7 | 8 | conda: 9 | environment: doc/environment.yml 10 | 11 | sphinx: 12 | # Path to your Sphinx configuration file. 13 | configuration: doc/conf.py 14 | -------------------------------------------------------------------------------- /doc/_templates/custom-template.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /doc/physics_num_methods/index.rst: -------------------------------------------------------------------------------- 1 | =============================== 2 | Magnetism and Numerical Methods 3 | =============================== 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | :caption: Micromagnetics and Discrete Spin Model 8 | 9 | core_eqs 10 | extended_eqs 11 | monte_carlo 12 | nebm 13 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/fmmlib/utils.cpp: -------------------------------------------------------------------------------- 1 | unsigned int TriangleNumbers(unsigned int n) { 2 | return (n * (n + 1)) / 2; 3 | } 4 | 5 | unsigned int Nterms(unsigned int p) { 6 | unsigned int result = 0; 7 | for(unsigned int i = 0; i < p + 2; i++) { 8 | result += TriangleNumbers(i); 9 | } 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /bin/install-ubuntu-packages.sh: -------------------------------------------------------------------------------- 1 | # required to compile fidimag 2 | deps_compilation="python-pip python-numpy python-dev python-scipy cmake liblapack-dev libblas-dev" 3 | 4 | # required for tests and running fidimag 5 | deps_live="python-pytest python-pyvtk ipython python-matplotlib" 6 | 7 | apt-get install $deps_compilation $deps_live 8 | -------------------------------------------------------------------------------- /tests/test_citation.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | 3 | 4 | def test_citation(): 5 | s = fidimag.citation() 6 | assert type(s) == str 7 | assert 'fidimag' in s.lower() 8 | 9 | sb = fidimag.citation(bibtex=True) 10 | assert sb[0] == '@' 11 | assert len(sb.split()) > 1 12 | assert 'fidimag' in sb.lower() 13 | 14 | -------------------------------------------------------------------------------- /fidimag/common/__init__.py: -------------------------------------------------------------------------------- 1 | from .fileio import DataSaver 2 | from .fileio import DataReader 3 | from .batch_task import BatchTasks 4 | from .citation import citation 5 | from .cuboid_mesh import CuboidMesh 6 | #from .neb_cartesian import NEB_Sundials 7 | from .helper import init_scalar, init_vector 8 | from .plot import plot, plot_micro, plot_atom_cub, plot_atom_hex 9 | -------------------------------------------------------------------------------- /tests/test_imports.py: -------------------------------------------------------------------------------- 1 | def test_has_pyvtk_installed(): 2 | # use 'pip install pyvtk' if this fails 3 | import pyvtk 4 | 5 | def test_has_fidimag_installed(): 6 | # fix PYTHONPATH if this fails 7 | import fidimag 8 | 9 | def test_has_pytest_installed(): 10 | # install pytest if this fails (via conda, apt-get, ...) 11 | import pytest 12 | -------------------------------------------------------------------------------- /fidimag/micro/__init__.py: -------------------------------------------------------------------------------- 1 | from .sim import Sim 2 | from .demag import Demag 3 | from .exchange import UniformExchange 4 | from .exchange_rkky import ExchangeRKKY 5 | from .zeeman import Zeeman, TimeZeeman 6 | from .anisotropy import UniaxialAnisotropy, UniaxialAnisotropy4 7 | from .dmi import DMI 8 | from .baryakhtar import LLBar, LLBarFull 9 | from .simple_demag import SimpleDemag 10 | -------------------------------------------------------------------------------- /fidimag/common/constant.py: -------------------------------------------------------------------------------- 1 | from math import pi 2 | 3 | mu_0 = 4 * pi * 1e-7 4 | mu_B = 9.27400949e-24 5 | k_B = 1.3806505e-23 6 | c_e = 1.602176565e-19 7 | eV = 1.602176565e-19 8 | meV = 1.602176565e-22 9 | m_e = 9.10938291e-31 10 | g_e = 2.0023193043737 11 | h_bar = 1.05457172647e-34 12 | h = h_bar * 2. * pi 13 | gamma = g_e * mu_B / h_bar 14 | mu_s_1 = g_e * mu_B * 1.0 # for S=1, 1.856952823077189e-23 15 | h_bar_gamma = h_bar * gamma 16 | -------------------------------------------------------------------------------- /docker/notebook/Makefile: -------------------------------------------------------------------------------- 1 | # to build a new docker image 2 | build: 3 | time docker build -t fidimag/notebook:latest . 4 | 5 | # to run new image 6 | run: build 7 | docker run -v `pwd`:/io -d -p 30008:8888 fidimag/notebook 8 | 9 | # to push the new docker image to dockerhub (need to login first) 10 | push: build 11 | docker push fidimag/notebook:latest 12 | 13 | # to fetch image to local machine 14 | pull: 15 | docker pull fidimag/notebook:latest 16 | -------------------------------------------------------------------------------- /fidimag/common/neb_method/nebm_spherical_lib.h: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #define WIDE_PI 3.1415926535897932384626433832795L 3 | 4 | void normalise_spherical(double *restrict a, int n); 5 | 6 | void normalise_images_spherical_C(double *restrict y, int n_images, 7 | int n_dofs_image); 8 | 9 | double compute_distance_spherical(double *restrict A, double *B, int n, 10 | int *restrict material, int n_dofs_image_material); 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | dist: trusty 4 | group: deprecated-2017Q4 5 | 6 | services: 7 | - docker 8 | 9 | before_install: 10 | - travis_wait 90 docker build -t fidimag -f ./docker/travis/Dockerfile . 11 | - docker run -ti -d --name fidimag fidimag 12 | 13 | jobs: 14 | include: 15 | - stage: Tests 16 | script: make test-docker 17 | - stage: Notebooks 18 | script: make ipynb-docker 19 | 20 | notifications: 21 | email: 22 | on_failure: always 23 | -------------------------------------------------------------------------------- /docker/minimal-py2/Makefile: -------------------------------------------------------------------------------- 1 | # to build a new docker image 2 | build: 3 | time docker build -t fidimag/minimal-py2:latest . 4 | 5 | # to run new image 6 | run: build 7 | docker run -v `pwd`:/io -ti fidimag/minimal-py2 8 | # try 'ipython' and then 'import fidimag' 9 | 10 | # to push the new docker image to dockerhub (need to login first) 11 | push: build 12 | docker push fidimag/minimal-py2:latest 13 | 14 | # to fetch image to local machine 15 | pull: 16 | docker pull fidimag/minimal-py2:latest 17 | -------------------------------------------------------------------------------- /docker/minimal-py3/Makefile: -------------------------------------------------------------------------------- 1 | # to build a new docker image 2 | build: 3 | time docker build -t fidimag/minimal-py3:latest . 4 | 5 | # to run new image 6 | run: build 7 | docker run -v `pwd`:/io -ti fidimag/minimal-py3 8 | # try 'ipython3' and then 'import fidimag' 9 | 10 | # to push the new docker image to dockerhub (need to login first) 11 | push: build 12 | docker push fidimag/minimal-py3:latest 13 | 14 | # to fetch image to local machine 15 | pull: 16 | docker pull fidimag/minimal-py3:latest 17 | -------------------------------------------------------------------------------- /sandbox/relaxation_test/skyrmion.py: -------------------------------------------------------------------------------- 1 | from fidimag.atomistic import Sim 2 | from fidimag.common.cuboid_mesh import CuboidMesh 3 | from fidimag.atomistic import UniformExchange, Zeeman 4 | import fidimag.common.constant as const 5 | 6 | mesh = CuboidMesh(nx=1, ny=1, dx=1, dy=1) 7 | 8 | sim = Sim(mesh, name='relax_sk') 9 | sim.gamma = const.gamma 10 | sim.set_m((1, 0, 0)) 11 | sim.add(Zeeman((0, 0, 25.))) 12 | 13 | sim.run_until(1e-11) 14 | sim.set_tols(rtol=1e-10, atol=1e-12) 15 | sim.run_until(2e-11) 16 | -------------------------------------------------------------------------------- /fidimag/atomistic/__init__.py: -------------------------------------------------------------------------------- 1 | from .sim import Sim 2 | from .exchange import UniformExchange, Exchange 3 | from .anisotropy import Anisotropy, CubicAnisotropy 4 | from .zeeman import Zeeman, TimeZeeman 5 | from .demag import Demag, DemagFMM 6 | from .demag_hexagonal import DemagHexagonal 7 | from .hexagonal_mesh import HexagonalMesh 8 | from .demag_full import DemagFull 9 | from .dmi import DMI 10 | from .monte_carlo import MonteCarlo 11 | import fidimag.common.constant as const 12 | from .materials import UnitMaterial, Nickel 13 | -------------------------------------------------------------------------------- /fidimag/atomistic/fmmlib/example.py: -------------------------------------------------------------------------------- 1 | import fmmgen 2 | 3 | order = 8 4 | source_order = 1 5 | cse = True 6 | atomic = True 7 | precision='double' 8 | fmmgen.generate_code(order, "operators", 9 | precision=precision, 10 | CSE=cse, 11 | cython=False, 12 | harmonic_derivs=True, 13 | potential=False, 14 | field=True, 15 | source_order=source_order, 16 | atomic=atomic) 17 | -------------------------------------------------------------------------------- /fidimag/common/neb_method/nebm_integrators.h: -------------------------------------------------------------------------------- 1 | double step_Verlet_C(double *restrict forces, 2 | double *restrict forces_prev, 3 | double *restrict velocities, 4 | double *restrict velocities_new, 5 | double *restrict y, 6 | double t, 7 | double h, 8 | double mass, 9 | int n_images, 10 | int n_dofs_image, 11 | double (*update_field)(double, double *)); 12 | -------------------------------------------------------------------------------- /tests/field_test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.common.field import scalar_field, vector_field 3 | from fidimag.common import CuboidMesh 4 | from . import very_close 5 | 6 | 7 | def test_initialise_scalar(): 8 | mesh = CuboidMesh(1, 1, 1, 1, 1, 1) 9 | f = scalar_field(mesh, lambda r: r[0] + r[1] + r[2]) 10 | assert very_close(f, np.array((1.5))) 11 | 12 | 13 | def test_initialise_vector(): 14 | mesh = CuboidMesh(1, 1, 1, 1, 1, 1) 15 | v = vector_field(mesh, lambda r: 2 * r) 16 | assert very_close(v, np.array((1, 1, 1))) 17 | -------------------------------------------------------------------------------- /tests/vtk_refs/save_scalar_000000.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 2.0 2 | 3 | ASCII 4 | DATASET RECTILINEAR_GRID 5 | DIMENSIONS 5 4 3 6 | X_COORDINATES 5 double 7 | 0.0 4.0 8.0 12.0 16.0 8 | Y_COORDINATES 4 double 9 | 0.0 3.0 6.0 9.0 10 | Z_COORDINATES 3 double 11 | 0.0 2.0 4.0 12 | CELL_DATA 24 13 | SCALARS s double 1 14 | LOOKUP_TABLE default 15 | 4.5 16 | 8.5 17 | 12.5 18 | 16.5 19 | 7.5 20 | 11.5 21 | 15.5 22 | 19.5 23 | 10.5 24 | 14.5 25 | 18.5 26 | 22.5 27 | 6.5 28 | 10.5 29 | 14.5 30 | 18.5 31 | 9.5 32 | 13.5 33 | 17.5 34 | 21.5 35 | 12.5 36 | 16.5 37 | 20.5 38 | 24.5 -------------------------------------------------------------------------------- /fidimag/user/example/example.pyx: -------------------------------------------------------------------------------- 1 | from libc.math cimport cos, sin 2 | 3 | def fast_sin_init(mesh, double[:] field, *params): 4 | t, axis, Bmax, fc = params 5 | for i in range(mesh.n): 6 | field[3*i+0] = Bmax * axis[0] * sin(fc*t) 7 | field[3*i+1] = Bmax * axis[1] * sin(fc*t) 8 | field[3*i+2] = Bmax * axis[2] * sin(fc*t) 9 | 10 | def TimeZeemanFast_test_time_fun(mesh, double[:] field, *params): 11 | cdef int i 12 | t, frequency = params 13 | for i in range(mesh.n): 14 | field[3*i+0] = 0 15 | field[3*i+1] = 0 16 | field[3*i+2] = 10 * cos(frequency * t) 17 | -------------------------------------------------------------------------------- /fidimag/atomistic/fmmlib/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | size_t TriangleNumbers(size_t n) { 4 | return (n * (n + 1)) / 2; 5 | } 6 | 7 | size_t Nterms(size_t p) { 8 | if (p < 0) { 9 | return 0; 10 | } 11 | size_t result = 0; 12 | for(size_t i = 0; i < p + 2; i++) { 13 | result += TriangleNumbers(i); 14 | } 15 | return result; 16 | } 17 | 18 | size_t Msize(size_t order, size_t source_order) { 19 | if (source_order == 0) { 20 | return Nterms(order); 21 | } 22 | return Nterms(order) - Nterms(source_order-1); 23 | } 24 | 25 | size_t Lsize(size_t order, size_t source_order) { 26 | return Nterms(order - source_order); 27 | } -------------------------------------------------------------------------------- /fidimag/common/neb_method/nebm_geodesic_lib.h: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #define WIDE_PI 3.1415926535897932384626433832795L 3 | 4 | double compute_geodesic_GreatCircle(double *restrict A, double *restrict B, 5 | int n_dofs_image, 6 | int *restrict material, 7 | int n_dofs_image_material); 8 | 9 | double compute_geodesic_Vincenty(double *restrict A, double *restrict B, 10 | int n_dofs_image, 11 | int *restrict material, 12 | int n_dofs_image_material); 13 | -------------------------------------------------------------------------------- /doc/user_guide/index.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | User Guide 3 | ========== 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | :caption: Tutorials 8 | 9 | ipynb/tutorial-docker-container 10 | ipynb/tutorial-basics 11 | ipynb/1d_domain_wall 12 | ipynb/anisotropic-grain-structure 13 | ipynb/current-driven-domain-wall 14 | ipynb/ferromagnetic-resonance-stdprob 15 | ipynb/isolated_skyrmion 16 | ipynb/Simulating an Anisotropic Grain Structure 17 | ipynb/skyrmions-applied-field-gradient 18 | ipynb/spin-polarised-current-driven-skyrmion 19 | ipynb/spin-waves-in-periodic-system 20 | ipynb/standard_problem_4 21 | ipynb/steepest_descent_atomistic 22 | -------------------------------------------------------------------------------- /tests/test_init_scalar.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | from fidimag.common import init_scalar 3 | import numpy as np 4 | import unittest 5 | 6 | def m_init(pos, t): 7 | x, y, z = pos 8 | return np.sin(t) 9 | 10 | def test_init_scalar_function(): 11 | import fidimag 12 | import numpy as np 13 | # Create simulation 14 | nx = ny = nz = 2 15 | mesh = fidimag.common.CuboidMesh(nx=nx, ny=ny, nz=nz, 16 | dx=1, dy=1, dz=1) 17 | 18 | test_vec = np.zeros(nx * ny * nz) 19 | test_vec[:] = init_scalar(m_init, mesh, 0) 20 | assert test_vec[0] == 0.0 21 | test_vec[:] = init_scalar(m_init, mesh, np.pi/2.0) 22 | assert test_vec[0] == 1.0 23 | -------------------------------------------------------------------------------- /sandbox/more-dmi/dmi-test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import fidimag 3 | # PdFe on Ir(111) [PRL, 114(17):1-5, 2015] 4 | Ms = 1.1e6 5 | D = -3.9e-3 6 | 7 | 8 | XL = 15e-9 9 | YL = XL 10 | ZL = XL 11 | 12 | nx = 2 13 | ny = 1 14 | nz = 1 15 | 16 | def set_D(pos): 17 | x, y, z = pos 18 | if x < XL/2: 19 | return 0 20 | else: 21 | return -D 22 | 23 | mesh = fidimag.common.CuboidMesh(nx=nx,ny=ny,nz=nz, dx=XL/nx, dy=YL/ny, dz=ZL/nz) 24 | 25 | sim = fidimag.micro.Sim(mesh) 26 | sim.set_Ms(Ms) 27 | 28 | 29 | sim.add(fidimag.micro.DMI(set_D)) 30 | m0 = np.array([0, 0, 1]) 31 | sim.set_m(m0) 32 | 33 | sim.compute_effective_field(0) 34 | print(sim.driver.field.reshape(-1, 3)) 35 | -------------------------------------------------------------------------------- /fidimag/common/citation.py: -------------------------------------------------------------------------------- 1 | def citation(bibtex=False): 2 | """Return citation string. Use bibtex=True to get 3 | a bibtex-formatted entry. 4 | 5 | Print the return value to see line breaks.""" 6 | 7 | s = """Fidimag - FInite DIfference microMAGnetic simulator. 8 | https://github.com/fangohr/fidimag 9 | (C) University of Southampton, 2012 - 2015""" 10 | 11 | s_bib = """@Misc{Fidimag, 12 | author = {University of Southampton}, 13 | title = {Fidimag - FInite DIfference microMAGnetic simulator}, 14 | year = {2015}, 15 | note = {https://github.com/fangohr/fidimag} 16 | }""" 17 | 18 | if bibtex: 19 | return s_bib 20 | else: 21 | return s 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/vtk_refs/save_vector_000000.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 2.0 2 | 3 | ASCII 4 | DATASET RECTILINEAR_GRID 5 | DIMENSIONS 5 4 3 6 | X_COORDINATES 5 double 7 | 0.0 4.0 8.0 12.0 16.0 8 | Y_COORDINATES 4 double 9 | 0.0 3.0 6.0 9.0 10 | Z_COORDINATES 3 double 11 | 0.0 2.0 4.0 12 | CELL_DATA 24 13 | VECTORS s double 14 | 2.0 1.5 1.0 15 | 6.0 1.5 1.0 16 | 10.0 1.5 1.0 17 | 14.0 1.5 1.0 18 | 2.0 4.5 1.0 19 | 6.0 4.5 1.0 20 | 10.0 4.5 1.0 21 | 14.0 4.5 1.0 22 | 2.0 7.5 1.0 23 | 6.0 7.5 1.0 24 | 10.0 7.5 1.0 25 | 14.0 7.5 1.0 26 | 2.0 1.5 3.0 27 | 6.0 1.5 3.0 28 | 10.0 1.5 3.0 29 | 14.0 1.5 3.0 30 | 2.0 4.5 3.0 31 | 6.0 4.5 3.0 32 | 10.0 4.5 3.0 33 | 14.0 4.5 3.0 34 | 2.0 7.5 3.0 35 | 6.0 7.5 3.0 36 | 10.0 7.5 3.0 37 | 14.0 7.5 3.0 -------------------------------------------------------------------------------- /examples/mc/skx.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.atomistic import MonteCarlo 7 | from fidimag.common import DataReader, CuboidMesh 8 | import fidimag.common.constant as const 9 | 10 | def random_m(pos): 11 | return np.random.random(3) - 0.5 12 | 13 | def run(mesh): 14 | mc = MonteCarlo(mesh, name='test1') 15 | mc.set_m(random_m) 16 | J = 50*const.k_B 17 | mc.set_options(H=[0,0,1.0], J=J, D=0.27*J, T=4.0) 18 | mc.run(steps=int(1e8), save_m_steps=None, save_vtk_steps=50000, save_data_steps=50000) 19 | 20 | if __name__=='__main__': 21 | mesh = CuboidMesh(nx=58, ny=33, nz=1, periodicity = (True, True, False)) 22 | run(mesh) 23 | -------------------------------------------------------------------------------- /fidimag/atomistic/fmmlib/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | size_t TriangleNumbers(size_t n); 6 | size_t Nterms(size_t p); 7 | size_t Msize(size_t order, size_t source_order); 8 | size_t Lsize(size_t order, size_t source_order); 9 | 10 | class Timer { 11 | private: 12 | // Type aliases to make accessing nested type easier 13 | using clock_t = std::chrono::high_resolution_clock; 14 | using second_t = std::chrono::duration>; 15 | std::chrono::time_point t; 16 | 17 | public: 18 | Timer() : t(clock_t::now()) {} 19 | void reset() { t = clock_t::now(); } 20 | double elapsed() const { 21 | return std::chrono::duration_cast(clock_t::now() - t).count(); 22 | } 23 | }; -------------------------------------------------------------------------------- /tests/test_mesh.py: -------------------------------------------------------------------------------- 1 | from fidimag.common import CuboidMesh 2 | import unittest 3 | 4 | def test_mesh1(): 5 | mesh = CuboidMesh(nx=5, ny=3, nz=2, dx=0.23, dy=0.41) 6 | assert len(mesh.coordinates) == 5 * 3 * 2 7 | assert mesh.ny * mesh.nz == 6 8 | assert tuple(mesh.coordinates[mesh.index(0, 0, 0)]) == (0.23 / 2, 0.41 / 2, 0.5) 9 | assert tuple(mesh.coordinates[mesh.index(3, 2, 1)]) == ( 10 | (3 + 0.5) * 0.23, (2 + 0.5) * 0.41, 1 + 0.5) 11 | 12 | 13 | class Mesh_TestCase(unittest.TestCase): 14 | def test_mesh_input_args(self): 15 | self.assertRaises(ValueError, CuboidMesh, 1, 1, 0, 1, 1, 1) 16 | self.assertRaises(ValueError, CuboidMesh, 1, 1, 1, 0, 1, 1) 17 | 18 | if __name__ == '__main__': 19 | test_mesh1() 20 | -------------------------------------------------------------------------------- /tests/test_llg_raises_error.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from fidimag.common import CuboidMesh 3 | from fidimag.micro import Sim 4 | from fidimag.micro import Zeeman 5 | from fidimag.micro import UniaxialAnisotropy 6 | import numpy as np 7 | import unittest 8 | 9 | def run_sim(): 10 | mesh = CuboidMesh() 11 | sim = Sim(mesh, name='spin') 12 | alpha = 0.1 13 | gamma = 2.21e5 14 | sim.alpha = alpha 15 | sim.driver.gamma = gamma 16 | sim.mu_s = 1.0 17 | 18 | sim.set_m((1, 0, 0)) 19 | H0 = 1e5 20 | sim.add(Zeeman((0, 0, H0))) 21 | sim.driver.run_until(1e-10) 22 | sim.driver.run_until(0.5e-10) 23 | 24 | class mytest(unittest.TestCase): 25 | def test_raises_valueerror_time_integration(self): 26 | self.assertRaises(ValueError, run_sim) 27 | -------------------------------------------------------------------------------- /tests/test_init_vector.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | from fidimag.common import init_vector 3 | import numpy as np 4 | import unittest 5 | 6 | def m_init(pos, t): 7 | x, y, z = pos 8 | return (np.sin(t), np.cos(t), 0.0) 9 | 10 | def test_init_vector_function(): 11 | import fidimag 12 | import numpy as np 13 | # Create simulation 14 | nx = ny = nz = 2 15 | mesh = fidimag.common.CuboidMesh(nx=nx, ny=ny, nz=nz, 16 | dx=1, dy=1, dz=1) 17 | 18 | test_vec = np.zeros(3 * nx * ny * nz) 19 | test_vec[:] = init_vector(m_init, mesh, 3, False, 0) 20 | assert test_vec[0] < 1e-15 21 | assert test_vec[1] - 1.0 < 1e-15 22 | test_vec[:] = init_vector(m_init, mesh, 3, False, np.pi/2.0) 23 | assert test_vec[0] - 1.0 < 1e-15 24 | assert test_vec[1] < 1e-15 25 | -------------------------------------------------------------------------------- /tests/test_atomistic_zeeman.py: -------------------------------------------------------------------------------- 1 | from fidimag.atomistic import Zeeman 2 | from fidimag.common import CuboidMesh 3 | from fidimag.atomistic import Sim 4 | import numpy as np 5 | 6 | 7 | def varying_field(pos): 8 | return (1.2 * pos[0], 2.3 * pos[1], 0) 9 | 10 | 11 | def test_zeeman(): 12 | """ 13 | Test the x and y component of the zeeman field 14 | for the 2nd spin 15 | 16 | 6 7 8 9 10 11 17 | 0 1 2 3 4 5 18 | ^ 19 | """ 20 | 21 | mesh = CuboidMesh(nx=5, ny=2, nz=1) 22 | 23 | sim = Sim(mesh) 24 | sim.set_m((1, 0, 0)) 25 | 26 | zeeman = Zeeman(varying_field) 27 | sim.add(zeeman) 28 | 29 | field = zeeman.compute_field() 30 | 31 | assert field[2 * 3] == 1.2 * (2 + 0.5) 32 | assert field[2 * 3 + 1] == 2.3 * 0.5 33 | 34 | 35 | if __name__ == '__main__': 36 | test_zeeman() 37 | -------------------------------------------------------------------------------- /docker/minimal-py2/Readme.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | Run fidimag with Python 2 under Docker. 4 | 5 | ## Using the docker container 6 | 7 | There is a fidimag container available under `fidimag/minimal-py2`. 8 | 9 | To use it, you can try this: 10 | 11 | 1. Install docker 12 | 13 | 2. Pull the container onto your machine using 14 | 15 | docker pull fidimag/minimal-py2 16 | 17 | 3. Start the container using 18 | 19 | docker run -ti fidimag/minimal-py2 20 | 21 | This command should show a bash prompt inside the docker container: 22 | 23 |
24 |     bin:docker fangohr$ docker run -v `pwd`:/io -ti fidimag/minimal-py2
25 |     fidimag@38fdd2a0feb4:/io$
26 |     
27 | 28 | ## Creating the docker container 29 | 30 | The `Makefile` in this directory shows the relevant targets (build, login, push) 31 | to create a new container and push it to the the cloud. 32 | -------------------------------------------------------------------------------- /docker/minimal-py3/Readme.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | Run fidimag with Python 3 under Docker. 4 | 5 | ## Using the docker container 6 | 7 | There is a fidimag container available under `fidimag/minimal-py3`. 8 | 9 | To use it, you can try this: 10 | 11 | 1. Install docker 12 | 13 | 2. Pull the container onto your machine using 14 | 15 | docker pull fidimag/minimal-py3 16 | 17 | 3. Start the container using 18 | 19 | docker run -ti fidimag/minimal-py3 20 | 21 | This command should show a bash prompt inside the docker container: 22 | 23 |
24 |     bin:docker fangohr$ docker run -v `pwd`:/io -ti fidimag/minimal-py3
25 |     fidimag@38fdd2a0feb4:/io$
26 |     
27 | 28 | ## Creating the docker container 29 | 30 | The `Makefile` in this directory shows the relevant targets (build, login, push) 31 | to create a new container and push it to the the cloud. 32 | -------------------------------------------------------------------------------- /fidimag/common/sim2fdfield.py: -------------------------------------------------------------------------------- 1 | import finitedifferencefield 2 | from fidimag.common import CuboidMesh 3 | 4 | def fidimag_to_finitedifferencefield(sim): 5 | """ 6 | fidimag_to_finitedifferencefield(sim) 7 | 8 | This function takes a Fidimag simulation object, and constructs a 9 | Finite Difference Field object which has the magnetisation configuration 10 | from the simulation at the last time step. 11 | """ 12 | cmin = np.array([sim.mesh.x0, sim.mesh.y0, sim.mesh.z0])*sim.mesh.unit_length 13 | cmax = tuple(cmin +np.array([mesh.Lx, mesh.Ly, mesh.Lz])*sim.mesh.unit_length) 14 | cmin = tuple(cmin) 15 | d = tuple(np.array([sim.mesh.dx, sim.mesh.dy, sim.mesh.dz])*sim.mesh.unit_length) 16 | field = finitedifferencefield.Field(cmin, cmax, d) 17 | numpyfield = sim.spin.copy().reshape((mesh.nx, mesh.ny, mesh.nz, 3)) 18 | field.f = numpyfield 19 | return field 20 | 21 | -------------------------------------------------------------------------------- /doc/user_guide/ipynb/runtimes.org: -------------------------------------------------------------------------------- 1 | * <2016-05-01 Sun> 2 | 3 | To see which tests run long: 4 | 5 | cd doc/ipynb && py.test . -v --nbval --duration=10 --sanitize-with sanitize_file 6 | 7 | ========================== slowest 10 test durations =========================== 8 | 17209.34s call doc/ipynb/isolated_skyrmion.ipynb::Cell 13 9 | 4098.12s call doc/ipynb/standard_problem_4.ipynb::Cell 19 10 | 967.73s call doc/ipynb/spin-polarised-current-driven-skyrmion.ipynb::Cell 14 11 | 703.63s call doc/ipynb/standard_problem_4.ipynb::Cell 15 12 | 20.86s call doc/ipynb/tutorial-basics.ipynb::Cell 21 13 | 6.32s call doc/ipynb/spin-waves-in-periodic-system.ipynb::Cell 13 14 | 6.16s call doc/ipynb/isolated_skyrmion.ipynb::Cell 11 15 | 5.76s call doc/ipynb/current-driven-domain-wall.ipynb::Cell 24 16 | 1.95s call doc/ipynb/current-driven-domain-wall.ipynb::Cell 18 17 | 1.67s call doc/ipynb/spin-polarised-current-driven-skyrmion.ipynb::Cell 11 18 | -------------------------------------------------------------------------------- /tests/test_regression_init_scalar.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | def regression_helper_init_scalar(): 5 | import fidimag 6 | import numpy as np 7 | # Create simulation 8 | mesh = fidimag.common.CuboidMesh(nx=10, ny=2, nz=1, 9 | dx=1, dy=1, dz=1) 10 | sim = fidimag.atomistic.Sim(mesh) 11 | # Set the magnetisation and save it to mu_s.npy 12 | sim.mu_s = 3 13 | np.save('mu_s.npy', sim.mu_s) 14 | 15 | # Create another simulation with less elements in the x direction 16 | mesh2 = fidimag.common.CuboidMesh(nx=5, ny=2, nz=1, 17 | dx=1, dy=1, dz=1) 18 | sim2 = fidimag.atomistic.Sim(mesh2) 19 | # Set the magnetisation loading the other simulation file 20 | sim2.mu_s = np.load('mu_s.npy') 21 | 22 | 23 | class regression_test(unittest.TestCase): 24 | 25 | def test_init_scalar(self): 26 | self.assertRaises(ValueError, regression_helper_init_scalar) 27 | -------------------------------------------------------------------------------- /docker/testing/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | # To build this image `docker build -t fidimag .` 4 | # Then you can drop into a live bash shell with `docker run -it fidimag`. 5 | ENTRYPOINT ["/bin/bash"] 6 | SHELL ["/bin/bash", "-c"] 7 | 8 | ARG DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update -y -qq 11 | RUN apt-get install -y -qq build-essential cmake cython3 python3-dev python3-pip \ 12 | liblapack-dev libopenblas-dev \ 13 | wget curl git 14 | 15 | RUN pip3 install --upgrade setuptools 16 | RUN pip3 install numpy matplotlib ipywidgets nbval pyvtk six psutil pytest pytest-cov pluggy scipy -U 17 | 18 | WORKDIR /fidimag 19 | ADD . /fidimag 20 | RUN ./bin/install-sundials.sh 21 | RUN ./bin/install-fftw.sh 22 | RUN make build 23 | 24 | ENV PYTHONPATH=/fidimag \ 25 | LD_LIBRARY_PATH=/fidimag/local/lib LD_RUN_PATH=/fidimag/local/lib \ 26 | OMP_NUM_THREADS=1 MPLBACKEND=Agg QT_API=pyqt 27 | 28 | 29 | RUN make test-docker 30 | RUN make ipynb-docker 31 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. pccp documentation master file, created by 2 | sphinx-quickstart on Tue Aug 27 19:41:06 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Fidimag's documentation! 7 | =================================== 8 | 9 | .. image:: ./images/bobber_toron_vis.png 10 | 11 | Fidimag is a micromagnetic and atomistic simulation package, which can be used 12 | to simulate the magnetisation of nanoscale samples of materials. 13 | 14 | The code for Fidimag is available under an open source license on `GitHub 15 | `_. 16 | 17 | Contents: 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | :caption: Installation Instructions 22 | 23 | install 24 | 25 | .. toctree:: 26 | :caption: User Guide 27 | :maxdepth: 2 28 | 29 | user_guide/index 30 | 31 | .. toctree:: 32 | :maxdepth: 2 33 | :caption: Physics 34 | 35 | physics_num_methods/index 36 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/fidimag_random.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIDIMAG_RANDOM__ 2 | #define __FIDIMAG_RANDOM__ 3 | 4 | 5 | 6 | //#include 7 | 8 | #define WIDE_PI 3.1415926535897932384626433832795L 9 | 10 | //================================================= 11 | //random number, mt19937 12 | typedef struct { 13 | unsigned int MT[624]; 14 | unsigned int matrix[2];// = { 0, 0x9908b0dfU}; 15 | int index_t; 16 | int seed; 17 | 18 | } mt19937_state; 19 | 20 | #define MT19973_RAND_MAX 4294967295u 21 | 22 | mt19937_state *create_mt19937_state(void); 23 | void finalize_mt19937_state(mt19937_state *state); 24 | 25 | void initial_rng_mt19973(mt19937_state *state, int seed); 26 | //inline unsigned int rand_int(mt19937_state *state); 27 | double random_double_half_open(mt19937_state *state); 28 | int rand_int_n(mt19937_state *state, int n); 29 | void gauss_random_vector(mt19937_state *state, double *x, int n); 30 | 31 | void uniform_random_sphere(mt19937_state *state, double *spin, int n); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /fidimag/common/field.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def vector_field(mesh, v): 5 | """ 6 | Returns a np.array with values specified by `v`, where `v` should 7 | be a iterable of length 3, or a function that returns an iterable of 8 | length 3 when getting the coordinates of a cell of `mesh`. 9 | 10 | """ 11 | return field(mesh, v, dim=3) 12 | 13 | 14 | def scalar_field(mesh, s): 15 | """ 16 | Returns a np.array with values specified by `s`, where `s` should be 17 | a scalar, or a function that returns a scalar when getting the coordinates 18 | of a cell of `mesh`. 19 | 20 | """ 21 | return field(mesh, s, dim=1) 22 | 23 | 24 | def field(mesh, val, dim): 25 | values = np.zeros(mesh.vector_shape()) if dim == 3 else np.zeros(mesh.scalar_shape()) 26 | 27 | if hasattr(val, '__call__'): 28 | f = val 29 | else: 30 | f = lambda r: val 31 | 32 | for i, r in enumerate(mesh.coordinates): 33 | values[i] = f(r) 34 | return values 35 | -------------------------------------------------------------------------------- /fidimag/atomistic/field.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def vector_field(mesh, v): 5 | """ 6 | Returns a np.array with values specified by `v`, where `v` should 7 | be a iterable of length 3, or a function that returns an iterable of 8 | length 3 when getting the coordinates of a cell of `mesh`. 9 | 10 | """ 11 | return field(mesh, v, dim=3) 12 | 13 | 14 | def scalar_field(mesh, s): 15 | """ 16 | Returns a np.array with values specified by `s`, where `s` should be 17 | a scalar, or a function that returns a scalar when getting the coordinates 18 | of a cell of `mesh`. 19 | 20 | """ 21 | return field(mesh, s, dim=1) 22 | 23 | 24 | def field(mesh, val, dim): 25 | values = np.zeros(mesh.vector_shape()) if dim == 3 else np.zeros(mesh.scalar_shape()) 26 | 27 | if hasattr(val, '__call__'): 28 | f = val 29 | else: 30 | f = lambda r: val 31 | 32 | for i, r in enumerate(mesh.coordinates): 33 | values[i] = f(r) 34 | return values 35 | -------------------------------------------------------------------------------- /bin/install-scikit-odes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # This script installs the python bindings to SUNDIALS called scikit ODES. 5 | # It requires SUNDIALS 2.6.2 to be installed. 6 | 7 | echo "Installing dependencies." 8 | sudo apt-get install python-dev 9 | sudo pip install scipy numpy cython enum34 10 | 11 | HERE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 12 | FIDIMAG_DIR="$(dirname "$HERE_DIR")" 13 | LIBS_DIR=${FIDIMAG_DIR}/local 14 | 15 | echo "Downloading ODES to "${LIBS_DIR}"." 16 | mkdir -p ${LIBS_DIR} 17 | cd ${LIBS_DIR} 18 | 19 | git clone git://github.com/bmcage/odes.git odes 20 | cd odes 21 | 22 | # Paths to SUNDIALS are hardcoded in odes/scikits/odes/sundials/setup.py. 23 | # The README recommends to edit that file if you want to change the paths... 24 | 25 | sed -i \ 26 | "s|LIB_DIRS_SUNDIALS = \[base_path\,|LIB_DIRS_SUNDIALS = [base_path, '${LIBS_DIR}\/lib',|g" \ 27 | scikits/odes/sundials/setup.py 28 | 29 | python setup.py build 30 | sudo python setup.py install 31 | 32 | cd ${HERE_DIR} 33 | -------------------------------------------------------------------------------- /examples/atomistic/dmi/dmi_1d.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange 3 | from fidimag.common import CuboidMesh 4 | 5 | def init_m(pos): 6 | x, y, z = pos 7 | if x < 50: 8 | return (0, 0, 1) 9 | elif x > 50 - 1: 10 | return (0, 1, -1) 11 | else: 12 | return (0, 1, 0) 13 | 14 | 15 | def relax_system(mesh): 16 | 17 | sim = Sim(mesh, name='relax') 18 | sim.driver.alpha = 0.1 19 | 20 | sim.set_m(init_m) 21 | 22 | J = 1 23 | exch = UniformExchange(J) 24 | sim.add(exch) 25 | 26 | dmi = DMI(0.05 * J) 27 | sim.add(dmi) 28 | 29 | ts = np.linspace(0, 1, 11) 30 | for t in ts: 31 | print t, sim.spin_length() - 1 32 | sim.run_until(t) 33 | 34 | sim.save_vtk() 35 | 36 | return sim.spin 37 | 38 | 39 | if __name__ == '__main__': 40 | 41 | mesh = CuboidMesh(nx=20, ny=1, nz=1, pbc=None) 42 | 43 | m0 = relax_system(mesh) 44 | print 'relax system done' 45 | # spin_wave(mesh,m0) 46 | -------------------------------------------------------------------------------- /docker/notebook/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jupyter/scipy-notebook 2 | # where to install source 3 | USER root 4 | RUN mkdir -p /io 5 | RUN chown $NB_USER /io 6 | RUN apt update && apt install -y cmake 7 | USER $NB_USER 8 | ENV FIDIMAG_DIR /io 9 | WORKDIR /io 10 | RUN git clone https://github.com/rpep/fidimag.git 11 | WORKDIR /io/fidimag 12 | # install third party libraries from source 13 | RUN bash bin/install-fftw.sh 14 | RUN bash bin/install-sundials.sh 15 | 16 | # install pyvtk 17 | RUN pip install pyvtk 18 | # install cython 19 | RUN pip install cython --upgrade 20 | 21 | # compile fidimag 22 | RUN python3 setup.py build_ext --inplace 23 | RUN pip install psutil 24 | ENV PYTHONPATH=$FIDIMAG_DIR 25 | ENV LD_LIBRARY_PATH=$FIDIMAG_DIR/local/lib 26 | WORKDIR $FIDIMAG_DIR/tests 27 | 28 | # https://github.com/conda-forge/matplotlib-feedstock/issues/36 29 | RUN conda install --quiet --yes icu 30 | 31 | # check that tests run okay 32 | RUN conda install --quiet --yes pytest 33 | 34 | # /io will be mounted from the host system 35 | WORKDIR /io 36 | 37 | -------------------------------------------------------------------------------- /examples/micromagnetic/nmag_example_2_box/sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | example 2 in the nmag manual 3 | from http://nmag.soton.ac.uk/nmag/0.2/manual/html/example2/doc.html 4 | 5 | """ 6 | import numpy as np 7 | from fidimag.common import CuboidMesh 8 | from fidimag.micro import Sim, UniformExchange, Demag 9 | 10 | mesh = CuboidMesh(3, 3, 10/3.0, 10, 10, 30, unit_length=1e-9) 11 | 12 | 13 | def run(integrator, jacobian): 14 | name = "sim_" + integrator 15 | if integrator == "sundials": 16 | name += "_J1" if jacobian else "_J0" 17 | sim = Sim(mesh, name, integrator=integrator, driver='llg', use_jac=jacobian) 18 | sim.Ms = 0.86e6 19 | sim.driver.alpha = 0.5 20 | sim.set_m((1, 0, 1)) 21 | sim.add(UniformExchange(A=13e-12)) 22 | sim.add(Demag()) 23 | 24 | ts = np.linspace(0, 3e-10, 61) 25 | for t in ts: 26 | print(f'Running until t = {t}') 27 | sim.driver.run_until(t) 28 | 29 | if __name__ == "__main__": 30 | run("sundials", False) 31 | run("sundials_diag", False) 32 | run("sundials", True) 33 | -------------------------------------------------------------------------------- /examples/atomistic/PRL_111_067203/phase_res/plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | import matplotlib.cm as cm 5 | 6 | import numpy as np 7 | 8 | 9 | def plot_res(Ts, Hs, res): 10 | mesh_x, mesh_y = np.meshgrid(Ts, Hs) 11 | res.shape = (len(Ts), len(Hs)) 12 | 13 | fig = plt.figure(figsize=(6, 4)) 14 | 15 | im = plt.imshow(np.transpose(res), cmap=cm.RdBu, extent=[ 16 | Ts[0], Ts[-1], Hs[0], Hs[-1]], origin='lower', aspect='auto') 17 | plt.colorbar(im) 18 | 19 | plt.text(0.25, 0.4, 'FM') 20 | plt.text(0.05, 0.15, 'SkX') 21 | plt.text(0.1, 0.005, 'HL') 22 | 23 | plt.xlabel(r'$k_B T/J$') 24 | plt.ylabel('H') 25 | plt.title('Skyrmion number') 26 | plt.tight_layout() 27 | 28 | fig.savefig('phase.pdf') 29 | 30 | 31 | if __name__ == '__main__': 32 | # np.random.seed(125) 33 | 34 | Ts = np.linspace(0, 0.5, 11) 35 | Hs = np.linspace(0, 0.5, 11) 36 | 37 | res = np.load('res.npy') 38 | 39 | plot_res(Ts, Hs, res) 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | *.pyc 3 | *.ndt 4 | *.gch 5 | *.swp 6 | *.pdf 7 | *.tmp 8 | *.so 9 | *.o 10 | 11 | local/ 12 | *~ 13 | *.bak 14 | .DS_Store 15 | .pytest_cache/ 16 | # ignore automatically generated cython files 17 | fidimag/atomistic/lib/clib.c 18 | fidimag/common/lib/common_clib.c 19 | fidimag/common/dipolar/dipolar.c 20 | fidimag/common/neb/neb_clib.c 21 | fidimag/common/neb_method/*clib.c 22 | fidimag/common/sundials/cvode.c 23 | fidimag/micro/lib/baryakhtar/baryakhtar_clib.c 24 | fidimag/micro/lib/micro_clib.c 25 | fidimag/user/example/example.c 26 | 27 | # ignore .cache from pytest 28 | .cache 29 | 30 | # ignore simulation data 31 | *_npys 32 | *_vtks 33 | 34 | # ignore output files from NEB method 35 | npys 36 | vtks 37 | 38 | /build/ 39 | /doc/build/ 40 | 41 | 42 | # ignore *.so created by cython 43 | fidimag/extensions/*.so 44 | 45 | # ignore output from coverage 46 | htmlcov 47 | 48 | # ignore junit test output 49 | test-reports 50 | 51 | # ignore notebook checkpoint directory 52 | .ipynb_checkpoints/ 53 | 54 | *.npz 55 | *.npy 56 | fmm.cpp -------------------------------------------------------------------------------- /bin/ubuntu_install_script.sh: -------------------------------------------------------------------------------- 1 | echo "Super user authentication required to add packages (you will be \ 2 | prompted for confirmation)." 3 | sudo bash install-ubuntu-packages.sh 4 | sudo bash install-python-packages.sh 5 | bash install-fftw.sh 6 | bash install-sundials.sh 7 | pushd .. > /dev/null 8 | make 9 | 10 | # Adds fidimag environment variables to profile.d, if they're not already there. 11 | FIDIMAG_PROFILE_PATH=/etc/profile.d/fidimag.sh 12 | if [ ! -e "$FIDIMAG_PROFILE_PATH" ]; then 13 | echo "Warning: Adding Fidimag to path at $FIDIMAG_PROFILE_PATH." 14 | echo "Super user authentication required to add paths." 15 | sudo mkdir --parents "$(dirname $FIDIMAG_PROFILE_PATH)" 16 | sudo bash -c "echo \"export PYTHONPATH=$PWD/:\\\$PYTHONPATH\"\ 17 | > $FIDIMAG_PROFILE_PATH" 18 | sudo bash -c "echo \"export LD_LIBRARY_PATH=$PWD/local/lib:\ 19 | \\\$LD_LIBRARY_PATH\" >> $FIDIMAG_PROFILE_PATH" 20 | sudo chmod 0644 "$FIDIMAG_PROFILE_PATH" 21 | echo "Path written to $FIDIMAG_PROFILE_PATH." 22 | else 23 | echo "Path added previously. Skipping." 24 | fi 25 | -------------------------------------------------------------------------------- /tests/test_time_zeeman.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.common import CuboidMesh 3 | from fidimag.micro import TimeZeeman 4 | 5 | def time_fun(t, frequency): 6 | return 10*np.cos(frequency*t) 7 | 8 | def fixture_setup(nx, ny, nz): 9 | """ 10 | Fixtures for the tests 11 | """ 12 | dx = 10.0/nx 13 | spin = np.zeros(3*nx*ny*nz) 14 | Ms = np.zeros(nx*ny*nz) 15 | Ms_inv = np.zeros(nx*ny*nz) 16 | mesh = CuboidMesh(nx=nx, ny=ny, nz=nz, dx=dx, dy=1, dz=1, unit_length=1e-9) 17 | frequency = 10e9 18 | return mesh, frequency, spin, Ms, Ms_inv 19 | 20 | def test_TimeZeeman(): 21 | mesh, frequency, spin, Ms, Ms_inv = fixture_setup(10, 10, 10) 22 | zee = TimeZeeman(np.array([0.0, 0.0, 1.0]), time_fun, extra_args=[frequency]) 23 | zee.setup(mesh, spin, Ms, Ms_inv) 24 | field1 = zee.compute_field(t=0) 25 | assert field1[0] == 0 26 | assert field1[1] == 0 27 | assert field1[2] == 10 28 | field2 = zee.compute_field(t=1) 29 | assert field2[0] == 0 30 | assert field2[1] == 0 31 | assert field2[2] == 10*np.cos(frequency) 32 | -------------------------------------------------------------------------------- /tests/test_add_remove_interaction.py: -------------------------------------------------------------------------------- 1 | from fidimag.common import CuboidMesh, constant 2 | from fidimag.micro import UniformExchange, Sim, Zeeman 3 | import numpy as np 4 | 5 | def test_add_remove_interaction_simple(): 6 | mesh = CuboidMesh(nx=10, ny=10, nz=10, unit_length=1e-9) 7 | name = 'test_add_remove_intn_simple' 8 | sim = Sim(mesh, name=name) 9 | sim.set_m(lambda pos: (0, 0, 1)) 10 | sim.set_Ms(5.8e5) 11 | exch = UniformExchange(A=1e-11, name='Exchange') 12 | zee = Zeeman((0, 0, 0.05 / constant.mu_0), name='Zeeman') 13 | sim.add(exch) 14 | sim.add(zee) 15 | sim.driver.run_until(1e-9) 16 | sim.remove('Zeeman') 17 | sim.driver.run_until(2e-9) 18 | f = open(name + '.txt') 19 | lines = f.read().split('\n') 20 | headers = lines[0].split() 21 | first_data = lines[2].split() 22 | last_data = lines[2].split() 23 | # Find the position in the data table 24 | position = headers.index('E_Zeeman') 25 | assert np.abs(float(last_data[position])) < 1e-15 26 | 27 | if __name__ == '__main__': 28 | test_add_remove_interaction_simple() -------------------------------------------------------------------------------- /sandbox/memory_leak/fidimag_memory_issue_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | # This script creates multiple fidimag simulation objects and shows how much 4 | # memory (maybe) the simulation objects claim in memory. 5 | 6 | import fidimag 7 | import gc 8 | import resource 9 | import sys 10 | 11 | 12 | def create_simulation(): 13 | return fidimag.micro.Sim(fidimag.micro.CuboidMesh(x0=-200, dx=1, nx=400, 14 | y0=-200, dy=1, ny=400, 15 | unit_length=1e-9, pbc="xy"), 16 | name="resource_test") 17 | 18 | def measure_memory(): 19 | return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss 20 | 21 | 22 | print("Initial memory before simulation creation: {}MB?".format(measure_memory()/1024.**2)) 23 | for zI in range(30): 24 | sim = create_simulation() 25 | gc.collect() 26 | print("Memory after creation of simulation {:02d}: {}MB?"\ 27 | .format(zI + 1, measure_memory()/1024.**2)) 28 | print("\tReference count: {}".format(sys.getrefcount(sim))) 29 | -------------------------------------------------------------------------------- /examples/atomistic/dmi/dmi_2d.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange 3 | from fidimag.common import CuboidMesh 4 | 5 | import time 6 | 7 | 8 | def init_m(pos): 9 | 10 | x, y, z = pos 11 | if x < 50: 12 | return (0, 0, 1) 13 | elif x > 50: 14 | return (0, 0, -1) 15 | else: 16 | return (0, 1, 0) 17 | 18 | 19 | def relax_system(mesh): 20 | 21 | sim = Sim(mesh, name='dmi_2d') 22 | sim.driver.alpha = 0.1 23 | sim.driver.gamma=1.76e11 24 | sim.mu_s = 1e-22 25 | 26 | J = 1e-20 27 | exch = UniformExchange(J) 28 | sim.add(exch) 29 | 30 | dmi = DMI(0.1 * J) 31 | sim.add(dmi) 32 | 33 | sim.set_m(init_m) 34 | 35 | ts = np.linspace(0, 5e-10, 101) 36 | for t in ts: 37 | print(t) 38 | sim.run_until(t) 39 | #sim.save_vtk() 40 | 41 | return sim.spin 42 | 43 | if __name__ == '__main__': 44 | 45 | mesh = CuboidMesh( 46 | nx=1000, ny=1000, nz=1, dx=0.5, dy=0.5, dz=0.5, unit_length=1e-10) 47 | 48 | m0 = relax_system(mesh) 49 | print 'relax system done' 50 | -------------------------------------------------------------------------------- /examples/atomistic/skyrmion/skx_rotation/deal_m.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from moviepy.video.io.bindings import mplfig_to_npimage 4 | from moviepy.editor import VideoClip 5 | import moviepy.editor as mpy 6 | import matplotlib.cm as cm 7 | 8 | duration = 10 9 | 10 | def read_data(i): 11 | m = np.load('dyn_npys/m_%d.npy'%i) 12 | m.shape = (-1,3) 13 | mx = m[:,2] 14 | mx.shape=(140,140) 15 | return mx 16 | 17 | fig_mpl, ax = plt.subplots(1,figsize=(5,5), facecolor='white') 18 | 19 | mx = read_data(0) 20 | myobj = ax.imshow(np.transpose(mx),origin='lower',cmap=cm.rainbow) 21 | ax.set_title('t= 0 ns') 22 | 23 | 24 | # ANIMATE WITH MOVIEPY (UPDATE THE CURVE FOR EACH t). MAKE A GIF. 25 | 26 | def make_frame_mpl(t): 27 | myobj.set_data(read_data(int(t*20))) 28 | ax.set_title('t= %0.2f ns'%(t*40*0.01)) 29 | #fig_mpl.savefig('test.png') 30 | #line.set_ydata() # <= Update the curve 31 | return mplfig_to_npimage(fig_mpl) # RGB image of the figure 32 | 33 | animation = mpy.VideoClip(make_frame_mpl, duration=duration) 34 | animation.write_gif("skx.gif", fps=20) 35 | -------------------------------------------------------------------------------- /.github/workflows/superlinter.yml: -------------------------------------------------------------------------------- 1 | name: Super-Linter 2 | 3 | # Run this workflow every time a new commit pushed to your repository 4 | on: push 5 | 6 | jobs: 7 | # Set the job key. The key is displayed as the job name 8 | # when a job name is not provided 9 | super-lint: 10 | # Name the Job 11 | name: Lint code base 12 | # Set the type of machine to run on 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | ########################## 17 | # Checkout the code base # 18 | ########################## 19 | - name: Checkout Code 20 | uses: actions/checkout@v2 21 | with: 22 | # Full git history is needed to get a proper list of changed files within `super-linter` 23 | fetch-depth: 0 24 | 25 | # Runs the Super-Linter action 26 | - name: Run Super-Linter 27 | uses: github/super-linter@v4 28 | env: 29 | VALIDATE_ALL_CODEBASE: true 30 | DEFAULT_BRANCH: master 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | FILTER_REGEX_EXCLUDE: .*fidimag/atomistic/fmmlib/*.* 33 | FILTER_REGEX_EXCLUDE: .*fidimag/atomistic/lib/fmmlib/*.* 34 | -------------------------------------------------------------------------------- /tests/test_2dpbc_cube.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import numpy as np 3 | from fidimag.micro import Sim 4 | from fidimag.common import CuboidMesh 5 | from fidimag.micro import Demag 6 | 7 | mu0 = 4 * np.pi * 1e-7 8 | 9 | 10 | def test_compute_field(): 11 | """In an infinite film, we expect the demag tensor to be (0, 0, -1), and thus the 12 | magnetisation, if aligned in 0, 0, 1 direction, to create a demag field pointing 13 | with equal strength in the opposite direction. 14 | """ 15 | 16 | mesh = CuboidMesh(nx=1, ny=1, nz=1, dx=2.0, dy=2.0, dz=2.0, 17 | unit_length=1e-9, periodicity=(True, True, False)) 18 | 19 | sim = Sim(mesh, name='relax') 20 | 21 | sim.driver.set_tols(rtol=1e-10, atol=1e-14) 22 | sim.alpha = 0.5 23 | sim.gamma = 2.211e5 24 | sim.Ms = 8.6e5 25 | sim.do_precession = False 26 | 27 | sim.set_m((0, 0, 1)) 28 | 29 | demag = Demag(pbc_2d=True) 30 | sim.add(demag) 31 | field = demag.compute_field() 32 | print((1 + field[2] / 8.6e5)) 33 | assert abs(1 + field[2] / 8.6e5) < 1e-10 34 | 35 | 36 | if __name__ == '__main__': 37 | test_compute_field() 38 | -------------------------------------------------------------------------------- /docker/notebook/Readme.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | First steps towards running fidimag through Docker. 4 | 5 | ## Using the docker container 6 | 7 | There is a fidimag container available under `fangohr/fidimag`. 8 | 9 | To use it, you can try this: 10 | 11 | 1. Install docker 12 | 13 | 2. Pull the container onto your machine using 14 | 15 | docker pull fidimag/notebook 16 | 17 | 3. Start the container using 18 | 19 | docker run -v `pwd`:/io -p 30008:8888 fidimag/notebook 20 | 21 | This will start a notebook server. You can see it in your browser at 22 | http://localhost:30008/ on Linux and Mac (you may 23 | need to change this IP address if your docker VM is at a different address). 24 | 25 | You will need to 26 | To run a shell instead of the notebook server, run: 27 | 28 | docker run -v `pwd`:/io -ti fidimag/notebook bash 29 | 30 | ## Shortcomings 31 | 32 | - need to share directory between host and container (MOUNT or VOLUME) 33 | 34 | 35 | ## Creating the docker container 36 | 37 | The `Makefile` in this directory shows the relevant targets (build, login, push) 38 | to create a new container and push it to the the cloud. 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "fidimag" 3 | dynamic = ["version"] 4 | description = "Atomistic and Finite-DIfference microMAGnetic code, based on Python, Cython and C " 5 | readme = "README.md" 6 | # Not fully supported: 7 | # license-files = ["LICENSE.txt"] 8 | # license = "BSD-2-Clause" 9 | requires-python = ">= 3.10" 10 | dependencies = [ 11 | 'numpy', 12 | 'scipy', 13 | 'cython>=3.0.0', 14 | 'pytest', 15 | 'matplotlib', 16 | 'ipywidgets', 17 | 'pyvtk', 18 | 'ipython', 19 | 'psutil' 20 | ] 21 | authors = [ 22 | { name = "Weiwei Wang" }, 23 | { name = "David Cortes Ortuno" }, 24 | { name = "Ryan Pepper" }, 25 | { name = "Hans Fangohr" }, 26 | { name = "Marc-Antonio Bisotti" }, 27 | { name = "Thomas Kluyver" }, 28 | { name = "Mark Vousden" }, 29 | { name = "Oliver Laslett" }, 30 | { name = "Rebecca Carey" }, 31 | ] 32 | 33 | maintainers = [ 34 | {name = "David Cortes Ortuno", email = "david.cortes.o@gmail.com"}, 35 | {name = "Ryan Pepper"} 36 | ] 37 | 38 | [build-system] 39 | build-backend = "setuptools.build_meta" 40 | requires = [ 41 | "setuptools", 42 | "numpy", 43 | "cython>=3.0.0", 44 | ] 45 | -------------------------------------------------------------------------------- /tests/test_anis.py: -------------------------------------------------------------------------------- 1 | from fidimag.atomistic import Anisotropy, CubicAnisotropy 2 | from fidimag.common import CuboidMesh 3 | from fidimag.atomistic import Sim 4 | import numpy as np 5 | 6 | 7 | def test_anis(): 8 | mesh = CuboidMesh(nx=5, ny=3, nz=2) 9 | spin = np.zeros(90) 10 | anis = Anisotropy(Ku=1, axis=[1, 0, 0]) 11 | mu_s = np.ones(90) 12 | mu_s_inv = np.ones(90) 13 | anis.setup(mesh, spin, mu_s, mu_s_inv) 14 | field = anis.compute_field() 15 | assert len(mesh.coordinates) == 5 * 3 * 2 16 | assert np.max(field) == 0 17 | spin[0] = 99 18 | field = anis.compute_field() 19 | assert field[0] == 2 * 99 20 | 21 | def test_anis_cubic(): 22 | mesh = CuboidMesh(nx=1, ny=1, nz=1) 23 | spin = np.array([0.6,0.8,0]) 24 | anis = CubicAnisotropy(Kc=1.23) 25 | mu_s = np.ones(3) 26 | mu_s_inv = np.ones(3) 27 | anis.setup(mesh, spin, mu_s, mu_s_inv) 28 | field = anis.compute_field() 29 | assert np.max(field-np.array([-1.06272,-2.51904, -0.]))<1e-6 30 | energy = anis.compute_energy() 31 | assert abs(energy-0.663216)<1e-5 32 | 33 | 34 | if __name__ == '__main__': 35 | test_anis() 36 | test_anis_cubic() 37 | -------------------------------------------------------------------------------- /doc/todo.org: -------------------------------------------------------------------------------- 1 | * TODO [0/1] 2 | 1) [ ] Documentation 3 | - [ ] Add docstrings to the Cythonised functions which are exposed to the user; e.g fidimag.micro.sim.Sim 4 | 5 | 2) [1/2] Update dependencies 6 | - [X] FFTW 3.3.3 -> 3.3.4 7 | - [1/1] Sundials -> 8 | - [X] Get it to build 9 | - cmake -DCMAKE_INSTALL_PREFIX=$PWD CC=gcc-5 OPENMP_ENABLE=ON sundials-2.6.2 10 | - make install 11 | - [ ] Get Fidimag to link with it 12 | - Not sure what the problem is here - failed to load library with error: 13 | 14 | fidimag/atomistic/llg.py:5: in 15 | import fidimag.extensions.clib as clib 16 | ImportError: dlopen(/Users/ryan/Git/fidimag/fidimag/extensions/clib.so, 2): 17 | Library not loaded: libsundials_cvodes.2.dylib │ 18 | Referenced from: /Users/ryan/Git/fidimag/fidimag/extensions/clib.so │ 19 | Reason: image not found 20 | 21 | 22 | -------------------------------------------------------------------------------- /fidimag/micro/simple_demag.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .energy import Energy 3 | 4 | 5 | class SimpleDemag(Energy): 6 | """ 7 | Demagnetising field for thin films in the i-direction. 8 | Hj = Hk = 0 and Hi = - Mi. 9 | 10 | """ 11 | def __init__(self, Nx=0, Ny=0.5, Nz=0.5, name='SimpleDemag'): 12 | """ 13 | field_strength is Ms by default 14 | 15 | """ 16 | 17 | self.Nx = Nx 18 | self.Ny = Ny 19 | self.Nz = Nz 20 | self.name = name 21 | 22 | 23 | def compute_field(self, t=0): 24 | self.spin.shape = (3,-1) 25 | self.field.shape = (3,-1) 26 | self.field[0][:] = -self.Nx*self.spin[0][:]*self.Ms[:] 27 | self.field[1][:] = -self.Ny*self.spin[1][:]*self.Ms[:] 28 | self.field[2][:] = -self.Nz*self.spin[2][:]*self.Ms[:] 29 | self.spin.shape = (-1,) 30 | self.field.shape = (-1,) 31 | return self.field 32 | 33 | def compute_energy(self): 34 | 35 | mu_0 = 4*np.pi*1e-7 36 | sf = -0.5 * self.field * self.spin * mu_0 37 | energy = np.sum(sf.reshape(-1, 3), axis=1) * self.Ms 38 | 39 | return energy * self.mesh.cellsize 40 | -------------------------------------------------------------------------------- /examples/micromagnetic/pbc_2d/single_cube.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.micro import Sim 7 | from fidimag.common import CuboidMesh 8 | from fidimag.micro import UniformExchange, Demag, DMI 9 | from fidimag.micro import Zeeman, TimeZeeman 10 | from fidimag.common.fileio import DataReader 11 | 12 | mu0 = 4 * np.pi * 1e-7 13 | 14 | 15 | def compute_field(): 16 | 17 | mesh = CuboidMesh(nx=1, ny=1, nz=1, dx=2.0, dy=2.0, dz=2.0, unit_length=1e-9, periodicity=(True, True, False)) 18 | 19 | sim = Sim(mesh, name='relax') 20 | 21 | sim.driver.set_tols(rtol=1e-10, atol=1e-14) 22 | sim.driver.alpha = 0.5 23 | sim.driver.gamma = 2.211e5 24 | sim.Ms = 8.6e5 25 | sim.do_precession = False 26 | 27 | sim.set_m((0,0,1)) 28 | # sim.set_m(np.load('m0.npy')) 29 | 30 | A = 1.3e-11 31 | exch = UniformExchange(A=A) 32 | sim.add(exch) 33 | 34 | demag = Demag(pbc_2d=True) 35 | sim.add(demag) 36 | field=demag.compute_field() 37 | print(field) 38 | 39 | np.save('m0.npy', sim.spin) 40 | 41 | 42 | if __name__ == '__main__': 43 | 44 | compute_field() 45 | -------------------------------------------------------------------------------- /tests/test_check_ms_inv_sensible.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | import numpy as np 3 | 4 | def setup_fixture_micro(driver='llg'): 5 | mesh = fidimag.common.CuboidMesh(nx=3, ny=3, nz=3, 6 | dx=1, dy=1, dz=1, 7 | unit_length=1e-9) 8 | sim = fidimag.micro.Sim(mesh, driver=driver) 9 | return mesh, sim 10 | 11 | 12 | def setup_fixture_atomistic(driver='llg'): 13 | mesh = fidimag.common.CuboidMesh(nx=3, ny=3, nz=3, 14 | dx=1, dy=1, dz=1, 15 | unit_length=1e-9) 16 | sim = fidimag.atomistic.Sim(mesh, driver=driver) 17 | return mesh, sim 18 | 19 | def set_Ms(pos): 20 | if pos[0] < 2: 21 | return 0 22 | else: 23 | return 5e8 24 | 25 | def test_llg_Ms_inv(): 26 | mesh, sim = setup_fixture_micro() 27 | sim.set_Ms(set_Ms) 28 | assert np.isnan(np.dot(sim._magnetisation_inv, sim._magnetisation_inv)) == False 29 | 30 | def test_llg_atomistic_mu_s_inv(): 31 | mesh, sim = setup_fixture_atomistic() 32 | sim.set_mu_s(set_Ms) 33 | assert np.isnan(np.dot(sim._magnetisation_inv, sim._magnetisation_inv)) == False 34 | -------------------------------------------------------------------------------- /tests/test_spatial_exch.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim 3 | from fidimag.common import CuboidMesh 4 | from fidimag.atomistic import Exchange 5 | 6 | 7 | def init_m(pos): 8 | x, y, z = pos 9 | return (x - 0.5, y - 0.5, z - 0.5) 10 | 11 | 12 | def spatial_J(pos): 13 | x, y, z = pos 14 | if x < 5: 15 | return (-1.0, -1.0, -1.0, -1.0, -1.0, -1.0) 16 | elif x < 6: 17 | return (-1.0, 0.3, -1.0, -1.0, -1.0, -1.0) 18 | elif x > 7: 19 | return (1.0, 1.0, 1.0, 1.0, 1.0, 1.0) 20 | elif x > 6: 21 | return (0.3, 1.0, 1.0, 1.0, 1.0, 1.0) 22 | 23 | 24 | def test_exch_1d_spatial(): 25 | """ 26 | Test the x component of the exchange field 27 | in a 1D mesh, with the spin ordering: 28 | 29 | 0 1 2 3 4 5 30 | 31 | """ 32 | mesh = CuboidMesh(nx=12, ny=1, nz=1) 33 | sim = Sim(mesh) 34 | exch = Exchange(spatial_J) 35 | sim.add(exch) 36 | 37 | sim.set_m(init_m, normalise=False) 38 | 39 | field = exch.compute_field() 40 | 41 | assert exch._J[3, 3] == -1.0 42 | assert exch._J[5, 1] == 0.3 43 | assert exch._J[6, 0] == 0.3 44 | assert exch._J[8, 5] == 1.0 45 | 46 | 47 | if __name__ == '__main__': 48 | test_exch_1d_spatial() 49 | -------------------------------------------------------------------------------- /sandbox/more-dmi/isolated_sk_T-Oxs_DMI_T-Field-00-0000000.ohf: -------------------------------------------------------------------------------- 1 | # OOMMF OVF 2.0 2 | # 3 | # Segment count: 1 4 | # 5 | # Begin: Segment 6 | # Begin: Header 7 | # 8 | # Title: Oxs_DMI_T::Field 9 | # Desc: Oxs vector field output 10 | # Desc: MIF source file: /Users/ryan/git/fidimag/sandbox/more-dmi/test_dmi_multi.mif 11 | # Desc: Iteration: 0, State id: 179 12 | # Desc: Stage: 0, Stage iteration: 0 13 | # Desc: Stage simulation time: -1 s 14 | # Desc: Total simulation time: -2 s 15 | # meshunit: m 16 | # meshtype: rectangular 17 | # xbase: 3.7499999999999997e-09 18 | # ybase: 7.4999999999999993e-09 19 | # zbase: 7.4999999999999993e-09 20 | # xnodes: 2 21 | # ynodes: 1 22 | # znodes: 1 23 | # xstepsize: 7.4999999999999993e-09 24 | # ystepsize: 1.4999999999999999e-08 25 | # zstepsize: 1.4999999999999999e-08 26 | # xmin: 0 27 | # ymin: 0 28 | # zmin: 0 29 | # xmax: 1.4999999999999999e-08 30 | # ymax: 1.4999999999999999e-08 31 | # zmax: 1.4999999999999999e-08 32 | # valuedim: 3 33 | # valuelabels: Field_x Field_y Field_z 34 | # valueunits: A/m A/m A/m 35 | # 36 | # End: Header 37 | # 38 | # Begin: Data Text 39 | -0.00000000000000 -376184.410944480 -0.00000000000000 40 | -0.00000000000000 376184.410944480 -0.00000000000000 41 | # End: Data Text 42 | # End: Segment 43 | -------------------------------------------------------------------------------- /examples/micromagnetic/PRB_88_184422/oommf/dmi.mif: -------------------------------------------------------------------------------- 1 | # MIF 2.1 2 | 3 | Specify Oxs_MultiAtlas:atlas { 4 | atlas { Oxs_BoxAtlas:world { 5 | xrange {0 100e-09} 6 | yrange {0 1e-09} 7 | zrange {0 1e-09} 8 | name world 9 | } } 10 | } 11 | 12 | Specify Oxs_RectangularMesh:mesh [subst { 13 | cellsize {1e-9 1e-09 1e-09} 14 | atlas :atlas 15 | }] 16 | 17 | Specify Oxs_UniformExchange { 18 | A 16e-12 19 | } 20 | 21 | Specify Oxs_DMExchange6Ngbr [subst { 22 | default_D 3.6e-3 23 | atlas :atlas 24 | D { 25 | world world 3.6e-3 26 | } 27 | }] 28 | 29 | Specify Oxs_UniaxialAnisotropy { 30 | axis {0 0 1} 31 | K1 510e3 32 | } 33 | 34 | Specify Oxs_RungeKuttaEvolve:evolve { 35 | alpha 0.5 36 | } 37 | 38 | Specify Oxs_TimeDriver [subst { 39 | basename dmi 40 | evolver :evolve 41 | stage_count 1 42 | stopping_dm_dt 0.01 43 | mesh :mesh 44 | 45 | Ms 8.6e5 46 | 47 | m0 { Oxs_ScriptVectorField { 48 | atlas :atlas 49 | script_args {rawpt} 50 | script init_m0 51 | norm 1 52 | } } 53 | }] 54 | 55 | proc init_m0 { x y z} { 56 | return [list 0 0 1] 57 | } 58 | 59 | Destination archive mmArchive 60 | Schedule DataTable archive Stage 1 61 | Schedule Oxs_TimeDriver::Magnetization archive Stage 1 62 | -------------------------------------------------------------------------------- /tests/test_stt_slonczewski.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import numpy as np 4 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman, Anisotropy 5 | from fidimag.common import CuboidMesh, DataReader 6 | 7 | 8 | def test_dynamic(): 9 | 10 | mesh = CuboidMesh(nx=1, ny=1, nz=1) 11 | 12 | sim = Sim(mesh, name='dyn_spin', driver='llg_stt_cpp') 13 | # sim.set_options(rtol=1e-10,atol=1e-14) 14 | sim.driver.gamma = 1.0 15 | sim.mu_s = 1.0 16 | 17 | sim.set_m((0.8,0,-1)) 18 | 19 | Kx = Anisotropy(Ku=-0.05, axis=(0, 0, 1), name='Kz') 20 | sim.add(Kx) 21 | 22 | sim.p = (0,0,1) 23 | 24 | sim.a_J = 0.0052 25 | sim.alpha = 0.1 26 | 27 | ts = np.linspace(0, 1200, 401) 28 | for t in ts: 29 | sim.driver.run_until(t) 30 | 31 | 32 | mz = sim.spin[2] 33 | alpha, K, u = 0.1, 0.05, 0.0052 34 | print(mz, u/(2*alpha*K)) 35 | 36 | ######################################################### 37 | # The system used in this test can be solved analytically, which gives that mz = u/(2*alpha*K), 38 | # where K represents the easy-plane anisotropy. 39 | ### 40 | assert abs(mz - u/(2*alpha*K))/mz< 5e-4 41 | 42 | 43 | 44 | 45 | if __name__ == '__main__': 46 | 47 | test_dynamic() 48 | -------------------------------------------------------------------------------- /bin/fix_load_path_mac.py: -------------------------------------------------------------------------------- 1 | """ 2 | Creates working dylibs on Mac OS X by adding the full path to referenced libraries. 3 | This fixes ImportErrors that may appear starting with SUNDIALS 2.6. 4 | 5 | """ 6 | import os 7 | import glob 8 | import re 9 | import subprocess 10 | 11 | THIS_FILE = os.path.dirname(os.path.abspath(__file__)) 12 | MODULE_DIR = os.path.abspath(os.path.join(THIS_FILE, os.pardir)) 13 | LIB_DIR = os.path.join(MODULE_DIR, "local", "lib") 14 | 15 | EXTENSION_DIR = os.path.join(MODULE_DIR, "fidimag", "extensions") 16 | 17 | sos = glob.glob(os.path.join(EXTENSION_DIR, "*.so")) 18 | 19 | patten = re.compile(r'libsundials[\w.]+\.dylib') 20 | def extract_library(so_file): 21 | cmd = ('otool', '-L', so_file) 22 | output = subprocess.check_output(cmd) 23 | for line in output.decode().split('\t'): 24 | m = patten.match(line) 25 | print(m, line) 26 | if m: 27 | lib_name = m.group() 28 | full_name = os.path.join(LIB_DIR, lib_name) 29 | print(lib_name, full_name) 30 | cmd = ('install_name_tool', '-change', 31 | lib_name, full_name, so_file 32 | ) 33 | os.system(' '.join(cmd)) 34 | 35 | for so in sos: 36 | extract_library(so) 37 | print("Done for %s!"%so) 38 | -------------------------------------------------------------------------------- /fidimag/micro/lib/baryakhtar/baryakhtar_clib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#include 4 | 5 | #define WIDE_PI 3.1415926535897932384626433832795L 6 | #define MU0 1.25663706143591728850e-6 7 | 8 | inline double cross_x(double a0, double a1, double a2, double b0, double b1, double b2) { return a1*b2 - a2*b1; } 9 | inline double cross_y(double a0, double a1, double a2, double b0, double b1, double b2) { return a2*b0 - a0*b2; } 10 | inline double cross_z(double a0, double a1, double a2, double b0, double b1, double b2) { return a0*b1 - a1*b0; } 11 | 12 | void compute_laplace_m(double *m, double *field, double *Ms, double dx, double dy, double dz, 13 | int nx, int ny, int nz); 14 | 15 | void compute_relaxation_field_c(double *m, double *field, double *Ms, double chi_inv, int n); 16 | 17 | void compute_perp_field_c(double *m, double *field, double *field_p, int n); 18 | 19 | void llg_rhs_baryakhtar(double *dm_dt, double *m, double *h, double *delta_h, 20 | double *alpha, double beta, int *pins, 21 | double gamma, int nxyz, int do_precession); 22 | 23 | 24 | void llg_rhs_baryakhtar_reduced(double *dm_dt, double *m, double *hp, double *delta_hp, 25 | double *alpha, double beta, int *pins, 26 | double gamma, int nxyz, int do_precession, double default_c); 27 | -------------------------------------------------------------------------------- /fidimag/user/README.md: -------------------------------------------------------------------------------- 1 | # User Extensions 2 | 3 | The user extensions directory is here to allow for 4 | the user to be able to straightforwardly run compiled 5 | code within Fidimag for performance reasons. We 6 | consider this an advanced feature and do not recommend 7 | trying this unless you have experience writing and 8 | building C/Cython programs. 9 | 10 | Some of the energy classes perform callbacks to 11 | user-supplied functions. Performance for this 12 | is generally poor, as there is an overhead to 13 | calling Python functions repeatedly. Hence, 14 | we place this folder here to allow you to expose 15 | functions written in Cython/C conveniently. 16 | 17 | An example has been supplied. We suggest copying 18 | the folder and modifying each of the files in 19 | this. Please note that we have automated the 20 | building of the extensions, but you can only 21 | have a single Cython .pyx file per directory, 22 | because a single Cython module is created in 23 | each folder. The module that is created will have 24 | the name of this file. 25 | 26 | You do not explicitly need to write an __init__.py file; 27 | your extension will be importable immediately from 28 | fidimag.extensions.user.$FOLDERNAME 29 | 30 | The __init__.py file lets you do the slightly shorter: 31 | from fidimag.user.$FOLDERNAME import * 32 | 33 | -------------------------------------------------------------------------------- /bin/install-fftw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script installs FFTW locally. It may need to environment 4 | # variables to work, like 'export CC=gcc' in ARCHER. 5 | 6 | FFTW=fftw-3.3.8 7 | 8 | set -e 9 | 10 | # Create target directory if needed. 11 | 12 | 13 | HERE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 14 | FIDIMAG_DIR="$(dirname "$HERE_DIR")" 15 | 16 | if [ -z $LIBS_DIR ]; then LIBS_DIR=${FIDIMAG_DIR}/local; fi 17 | 18 | mkdir -p $LIBS_DIR 19 | cd ${LIBS_DIR} 20 | echo "Installing FFTW to "$LIBS_DIR"." 21 | echo "Using CC="$CC" " 22 | 23 | download_and_install() { 24 | # $1 name of the package 25 | # $2 URL where ${1}.tar.gz can be obtained 26 | # $3 configure options 27 | if [ ! -e ${1}.tar.gz ]; then 28 | echo "Downloading "${1}"." 29 | wget -q ${2}/${1}.tar.gz 30 | fi; 31 | 32 | if [ ! -e ${1} ]; then 33 | tar -xzf ${1}.tar.gz 34 | cd ${1} 35 | echo "Configuring "${1}"." 36 | ./configure --quiet --enable-shared --enable-openmp --prefix=${LIBS_DIR} 37 | echo "Compiling and installing "${1}"." 38 | { 39 | make -j2 40 | make install 41 | } > /dev/null 42 | echo "Done." 43 | cd ${LIBS_DIR} 44 | fi; 45 | } 46 | 47 | download_and_install ${FFTW} http://www.fftw.org 48 | 49 | echo "Installation succesful." 50 | -------------------------------------------------------------------------------- /fidimag/micro/energy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Energy(object): 5 | 6 | """ 7 | An abstract class to implement the basic functions such as setup in micromagnetics. 8 | """ 9 | 10 | def setup(self, mesh, spin, Ms, Ms_inv): 11 | self.mesh = mesh 12 | self.dx = mesh.dx * mesh.unit_length 13 | self.dy = mesh.dy * mesh.unit_length 14 | self.dz = mesh.dz * mesh.unit_length 15 | self.dxyz = self.dx * self.dy * self.dz 16 | self.nx = mesh.nx 17 | self.ny = mesh.ny 18 | self.nz = mesh.nz 19 | self.spin = spin 20 | self.n = mesh.n 21 | 22 | self.field = np.zeros(3 * mesh.n) 23 | self.energy = np.zeros(mesh.n) 24 | self.total_energy = 0 25 | self.Ms = Ms 26 | self.Ms_inv = Ms_inv 27 | 28 | # For old code compatibility 29 | self.xperiodic, self.yperiodic, self.zperiodic = mesh.periodicity 30 | 31 | self.neighbours = mesh.neighbours 32 | 33 | def compute_field(self, t=0): 34 | 35 | return 0 36 | 37 | def compute_energy(self): 38 | 39 | # since we are not always calling this function, so it's okay to call 40 | # compute_field again 41 | self.compute_field() 42 | 43 | self.total_energy = np.sum(self.energy) * self.dxyz 44 | 45 | return self.total_energy 46 | -------------------------------------------------------------------------------- /examples/micromagnetic/baryakhtar/relax_system.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | from fidimag.common import CuboidMesh 7 | from fidimag.micro import Sim 8 | from fidimag.micro import Demag 9 | from fidimag.micro import Zeeman 10 | from fidimag.micro import UniformExchange 11 | 12 | 13 | def relax_system(mesh): 14 | 15 | sim = Sim(mesh, name='relax', driver='llbar_full') 16 | 17 | sim.driver.chi = 1e-3 18 | sim.driver.set_tols(rtol=1e-7, atol=1e-7) 19 | sim.Ms = 8.0e5 20 | sim.driver.alpha = 0.1 21 | sim.beta = 0 22 | sim.driver.gamma = 2.211e5 23 | 24 | sim.set_m((1, 0.25, 0.1)) 25 | # sim.set_m(np.load('m0.npy')) 26 | 27 | A = 1.3e-11 28 | exch = UniformExchange(A=A) 29 | sim.add(exch) 30 | 31 | mT = 795.7747154594767 32 | zeeman = Zeeman([-100 * mT, 4.3 * mT, 0], name='H') 33 | sim.add(zeeman, save_field=True) 34 | 35 | demag = Demag() 36 | sim.add(demag) 37 | 38 | ONE_DEGREE_PER_NS = 17453292.52 39 | 40 | sim.relax(dt=1e-12, stopping_dmdt=0.01, 41 | max_steps=5000, save_m_steps=100, save_vtk_steps=50) 42 | 43 | np.save('m0.npy', sim.spin) 44 | 45 | if __name__ == "__main__": 46 | 47 | mesh = CuboidMesh(nx=20, ny=20, nz=1, dx=2.5, dy=2.5, dz=3, unit_length=1e-9) 48 | relax_system(mesh) 49 | -------------------------------------------------------------------------------- /fidimag/common/helper.py: -------------------------------------------------------------------------------- 1 | from fidimag.extensions.common_clib import normalise 2 | from fidimag.extensions.common_clib import init_scalar 3 | from fidimag.extensions.common_clib import init_vector 4 | from fidimag.extensions.common_clib import init_vector_func_fast 5 | import fidimag.extensions.clib as clib 6 | import numpy as np 7 | 8 | 9 | def extract_data(mesh, npys, pos, comp='x'): 10 | """ 11 | extract data of special positions for given npy data 12 | 13 | npys: 14 | the names of npys 15 | 16 | pos: 17 | something like [(1,0,0),...,(2,3,4)] 18 | """ 19 | ids = [] 20 | for p in pos: 21 | ids.append(mesh.index(p[0], p[1], p[2])) 22 | 23 | ids = np.array(ids) 24 | 25 | if comp == 'x': 26 | cmpi = 0 27 | elif comp == 'y': 28 | cmpi = 1 29 | elif comp == 'z': 30 | cmpi = 2 31 | else: 32 | raise Exception('Seems given component is wrong!!!') 33 | 34 | ids += cmpi * mesh.n 35 | 36 | all_data = [] 37 | 38 | for ny in npys: 39 | 40 | all_data.append(np.load(ny)[ids]) 41 | 42 | return np.array(all_data) 43 | 44 | 45 | def compute_RxRy(mesh, spin, nx_start=0, nx_stop=-1, ny_start=0, ny_stop=-1): 46 | res = clib.compute_RxRy(spin, mesh.nx, mesh.ny, 47 | mesh.nz, nx_start, nx_stop, ny_start, ny_stop) 48 | return res 49 | -------------------------------------------------------------------------------- /fidimag/atomistic/materials.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import numpy as np 3 | 4 | 5 | class UnitMaterial(object): 6 | 7 | def __init__(self): 8 | self.a = 1 9 | self.b = 1 10 | self.c = 1 11 | self.J = 1 12 | self.D = 0.5 13 | self.mu_s = 1 14 | self.gamma = 1 15 | self.alpha = 0.01 16 | self.unit_length = 1 17 | 18 | 19 | class Nickel(object): 20 | 21 | def __init__(self): 22 | self.mu_0 = 4 * np.pi * 1e-7 23 | self.mu_B = 9.27400949e-24 24 | self.k_B = 1.3806505e-23 25 | self.mu_s = 0.617 * self.mu_B 26 | self.S = 1.0 / 2 27 | self.unit_length = 1e-10 28 | # the real length should be a*unit_length 29 | self.a = 3.524 30 | self.b = self.a 31 | self.c = self.a 32 | self.K = 4.8e3 33 | self.D = self.K * self.a**3 34 | self.Tc = 630 35 | self.J = self.k_B * self.Tc / 3.0 36 | self.gamma = 2.210173e5 / self.mu_0 37 | self.Ms = 4.9e5 38 | 39 | self.alpha = 0.5 40 | 41 | if __name__ == '__main__': 42 | ni = Nickel() 43 | print(ni.K) 44 | print('gamma', ni.gamma) 45 | print('mu_s', ni.mu_s) 46 | print('J', ni.J) 47 | print('D', ni.D) 48 | print('D/J:', ni.D / ni.J) 49 | 50 | K = 1e5 * ni.a**3 51 | print(K) 52 | print((ni.J / K)**0.5) 53 | -------------------------------------------------------------------------------- /examples/micromagnetic/pbc_2d/rod.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.micro import Sim 7 | from fidimag.common import CuboidMesh 8 | from fidimag.micro import UniformExchange, Demag, DMI 9 | from fidimag.micro import Zeeman, TimeZeeman 10 | from fidimag.common.fileio import DataReader 11 | 12 | mu0 = 4 * np.pi * 1e-7 13 | 14 | 15 | def relax_system(mesh): 16 | 17 | sim = Sim(mesh, name='relax') 18 | 19 | sim.driver.set_tols(rtol=1e-10, atol=1e-14) 20 | sim.driver.alpha = 0.5 21 | sim.driver.gamma = 2.211e5 22 | sim.Ms = 8.6e5 23 | sim.do_precession = False 24 | 25 | sim.set_m((1,1,1)) 26 | # sim.set_m(np.load('m0.npy')) 27 | 28 | A = 1.3e-11 29 | exch = UniformExchange(A=A) 30 | sim.add(exch) 31 | 32 | dmi = DMI(D=1e-3) 33 | sim.add(dmi) 34 | 35 | zeeman = Zeeman((0, 0, 2e4)) 36 | sim.add(zeeman, save_field=True) 37 | 38 | sim.relax(dt=1e-13, stopping_dmdt=0.01, max_steps=5000, 39 | save_m_steps=None, save_vtk_steps=50) 40 | 41 | np.save('m0.npy', sim.spin) 42 | 43 | 44 | if __name__ == '__main__': 45 | 46 | mesh = CuboidMesh( 47 | nx=2, ny=2, nz=10, dx=1, dy=1, dz=2.0, unit_length=1e-9, periodicity=(True, True, False)) 48 | 49 | relax_system(mesh) 50 | 51 | # apply_field1(mesh) 52 | # deal_plot() 53 | -------------------------------------------------------------------------------- /examples/micromagnetic/PRB_88_184422/plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from micro import Sim 7 | from common import CuboidMesh 8 | from micro import Zeeman 9 | from fidimag.common.fileio import DataReader 10 | 11 | from util.omf import OMF2 12 | 13 | mesh = CuboidMesh(nx=100, dx=1, unit_length=1e-9) 14 | 15 | 16 | def plot_all(): 17 | 18 | font = {'family': 'serif', 19 | 'weight': 'normal', 20 | 'size': 12, 21 | } 22 | 23 | plt.rc('font', **font) 24 | 25 | Ms = 8.6e5 26 | omf = OMF2('oommf/dmi-Oxs_TimeDriver-Magnetization-00-0000963.omf') 27 | mx = omf.get_all_mag(comp='x') / Ms 28 | my = omf.get_all_mag(comp='y') / Ms 29 | mz = omf.get_all_mag(comp='z') / Ms 30 | xs = np.linspace(0.5, 100 - 0.5, 100) 31 | 32 | fig = plt.figure(figsize=(5, 4)) 33 | plt.plot(xs, mx, '--', label='m_x', dashes=(2.0, 2.0)) 34 | plt.plot(xs, my, '--', label='m_y', dashes=(2.0, 2.0)) 35 | plt.plot(xs, mz, '--', label='m_z', dashes=(2.0, 2.0)) 36 | 37 | l1 = plt.legend(bbox_to_anchor=[0.8, 0.8], shadow=True, frameon=True) 38 | # custom_legend(l1) 39 | 40 | plt.xlabel('xs (nm)') 41 | plt.ylabel('m') 42 | plt.title('OOMMF') 43 | plt.tight_layout() 44 | fig.savefig('m_oommf.pdf') 45 | 46 | 47 | if __name__ == '__main__': 48 | 49 | # relax_system() 50 | plot_all() 51 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Weiwei Wang, David Cortes, Marc-Antonio, Hans Fangohr 2 | University of Southampton, 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /examples/atomistic/heat/macrospin.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | from fidimag.atomistic import Anisotropy, Sim, Zeeman 6 | from fidimag.common import CuboidMesh 7 | import numpy as np 8 | 9 | 10 | class Material(): 11 | 12 | def __init__(self): 13 | self.mu_0 = 4 * np.pi * 1e-7 14 | self.mu_s = 1.12e-17 15 | self.K = 3.36e-18 16 | self.unit_length = 1e-10 17 | self.gamma = 2.210173e5 / self.mu_0 18 | 19 | 20 | def single_spin(alpha=0.01): 21 | 22 | mat = Material() 23 | 24 | mesh = CuboidMesh(nx=1, ny=1, nz=1) 25 | 26 | sim = Sim(mesh, driver='sllg') 27 | sim.driver.alpha = alpha 28 | sim.driver.gamma = mat.gamma 29 | sim.mu_s = mat.mu_s 30 | sim.T = 10000 31 | 32 | sim.set_m((1, 1, 1)) 33 | 34 | #sim.add(Zeeman(1,(0, 0, 1))) 35 | 36 | anis = Anisotropy(mat.K, direction=(0, 0, 1)) 37 | sim.add(anis) 38 | 39 | dt = 0.5e-12 40 | ts = np.linspace(0, 1000 * dt, 1001) 41 | 42 | sx = [] 43 | sy = [] 44 | for t in ts: 45 | sim.run_until(t) 46 | sx.append(sim.spin[0]) 47 | sy.append(sim.spin[1]) 48 | print(t) 49 | 50 | plt.plot(sx, sy) 51 | plt.xlabel("$S_x$") 52 | plt.ylabel("$S_y$") 53 | plt.grid() 54 | plt.axis((-0.9, 0.9, -0.9, 0.9)) 55 | plt.axes().set_aspect('equal') 56 | 57 | plt.savefig("macrospin.pdf") 58 | 59 | 60 | if __name__ == '__main__': 61 | single_spin() 62 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/fmmlib/tree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FMMLIB_TREE_HPP 2 | #define FMMLIB_TREE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils.hpp" 9 | 10 | class Particle { 11 | public: 12 | double x, y, z; 13 | double mux, muy, muz; 14 | Particle(double x, double y, double z, double mux, double muy, double muz) : x(x), y(y), z(z), mux(mux), muy(muy), muz(muz) {} 15 | }; 16 | 17 | struct Cell { 18 | public: 19 | unsigned int nleaf; 20 | unsigned int nchild; 21 | unsigned int level; 22 | std::array child; 23 | std::vector Mx; 24 | std::vector My; 25 | std::vector Mz; 26 | std::vector Lx; 27 | std::vector Ly; 28 | std::vector Lz; 29 | std::vector leaf; 30 | double x, y, z, r; 31 | unsigned int parent; 32 | Cell(double x, double y, double z, double r, unsigned int parent, unsigned int order, unsigned int level, unsigned int ncrit); 33 | }; 34 | 35 | void printTreeParticles(std::vector &cells, unsigned int cell, unsigned int depth); 36 | 37 | void add_child(std::vector &cells, int octant, unsigned int p, unsigned int ncrit, unsigned int order); 38 | 39 | 40 | void split_cell(std::vector &cells, std::vector &particles, unsigned int p, unsigned int ncrit, unsigned int order); 41 | 42 | std::vector build_tree(std::vector &particles, Cell &root, unsigned int ncrit, unsigned int order); 43 | 44 | #endif -------------------------------------------------------------------------------- /fidimag/micro/exchange.py: -------------------------------------------------------------------------------- 1 | import fidimag.extensions.micro_clib as micro_clib 2 | from .energy import Energy 3 | #from constant import mu_0 4 | 5 | 6 | class UniformExchange(Energy): 7 | 8 | """ 9 | UniformExchange(A, name='UniformExchange') 10 | 11 | Compute the exchange field in micromagnetics. 12 | 13 | Inputs: 14 | A: float 15 | A is the exchange stiffness constant measured in 16 | Joules / Meter (J / M) 17 | 18 | """ 19 | 20 | def __init__(self, A, name='UniformExchange'): 21 | self.A = A 22 | self.name = name 23 | self.jac = True 24 | 25 | def compute_field(self, t=0, spin=None): 26 | if spin is not None: 27 | m = spin 28 | else: 29 | m = self.spin 30 | 31 | micro_clib.compute_exchange_field_micro(m, 32 | self.field, 33 | self.energy, 34 | self.Ms_inv, 35 | self.A, 36 | self.dx, 37 | self.dy, 38 | self.dz, 39 | self.n, 40 | self.neighbours 41 | ) 42 | 43 | return self.field 44 | -------------------------------------------------------------------------------- /examples/atomistic/dynamic_spectrum/plot_results.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib as mpl 3 | mpl.use("Agg") 4 | 5 | import matplotlib.pyplot as plt 6 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman, TimeZeeman 7 | from fidimag.common import DataReader, BatchTasks, CuboidMesh 8 | 9 | def deal_plot(Hy=0): 10 | 11 | data = DataReader('dyn.txt') 12 | ts = data['time'] 13 | N = len(ts) 14 | #N = 8000 15 | 16 | dt = ts[1] - ts[0] 17 | print('dt=',dt) 18 | 19 | freq = np.fft.fftshift(np.fft.fftfreq(N, dt)) 20 | 21 | H = data['h_z'][0:N] 22 | M = data['m_z'][0:N] 23 | 24 | fH = np.fft.fftshift(np.fft.fft(H)) 25 | fM = np.fft.fftshift(np.fft.fft(M)) 26 | 27 | a = fH.real 28 | b = fH.imag 29 | c = fM.real 30 | d = fM.imag 31 | 32 | rx = (a*c+b*d)/(a*a+b*b) 33 | ix = (b*c-a*d)/(a*a+b*b) 34 | 35 | ind = np.argmax(ix) 36 | print(ind, freq[ind]*2*np.pi) 37 | w_ix = np.array([freq*2*np.pi, ix]) 38 | #np.savetxt('w_ix.txt',np.transpose(w_ix)) 39 | 40 | plt.plot(freq*2*np.pi, ix, '.-') 41 | #plt.legend() 42 | plt.xlim([0, 0.06]) 43 | #plt.ylim([-5, 100]) 44 | plt.xlabel(r'$w$') 45 | plt.ylabel('Susceptibility') 46 | plt.savefig('res.pdf') 47 | 48 | def plot_v(x,y,filename): 49 | fig=plt.figure() 50 | plt.plot(x,y,'^-',markersize=3) 51 | fig.savefig(filename) 52 | 53 | if __name__=='__main__': 54 | 55 | deal_plot() 56 | 57 | -------------------------------------------------------------------------------- /tests/vtk_refs/scalar_hexagonal_000000.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 2.0 2 | 3 | ASCII 4 | DATASET POLYDATA 5 | POINTS 30 double 6 | 2.0 1.7320508075688774 0.0 7 | 1.0 2.3094010767585034 0.0 8 | -2.220446049250313e-16 1.7320508075688774 0.0 9 | 0.0 0.5773502691896257 0.0 10 | 0.9999999999999998 0.0 0.0 11 | 1.9999999999999998 0.5773502691896253 0.0 12 | 4.0 1.7320508075688774 0.0 13 | 3.0 2.3094010767585034 0.0 14 | 3.0 0.0 0.0 15 | 4.0 0.5773502691896253 0.0 16 | 6.0 1.7320508075688774 0.0 17 | 5.0 2.3094010767585034 0.0 18 | 5.0 0.0 0.0 19 | 6.0 0.5773502691896253 0.0 20 | 3.0 3.464101615137755 0.0 21 | 2.0 4.041451884327381 0.0 22 | 0.9999999999999998 3.464101615137755 0.0 23 | 5.0 3.464101615137755 0.0 24 | 4.0 4.041451884327381 0.0 25 | 7.0 3.464101615137755 0.0 26 | 6.0 4.041451884327381 0.0 27 | 7.0 2.309401076758503 0.0 28 | 4.0 5.196152422706632 0.0 29 | 3.0 5.773502691896257 0.0 30 | 1.9999999999999998 5.196152422706632 0.0 31 | 6.0 5.196152422706632 0.0 32 | 5.0 5.773502691896257 0.0 33 | 8.0 5.196152422706632 0.0 34 | 7.0 5.773502691896257 0.0 35 | 8.0 4.04145188432738 0.0 36 | POLYGONS 9 63 37 | 6 0 1 2 3 4 5 38 | 6 6 7 0 5 8 9 39 | 6 10 11 6 9 12 13 40 | 6 14 15 16 1 0 7 41 | 6 17 18 14 7 6 11 42 | 6 19 20 17 11 10 21 43 | 6 22 23 24 15 14 18 44 | 6 25 26 22 18 17 20 45 | 6 27 28 25 20 19 29 46 | CELL_DATA 9 47 | SCALARS s double 1 48 | LOOKUP_TABLE default 49 | 2.1547005383792515 50 | 4.1547005383792515 51 | 6.1547005383792515 52 | 4.886751345948129 53 | 6.886751345948129 54 | 8.886751345948129 55 | 7.618802153517006 56 | 9.618802153517006 57 | 11.618802153517006 -------------------------------------------------------------------------------- /examples/micromagnetic/pbc_2d/main.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.micro import Sim 7 | from fidimag.common import CuboidMesh 8 | from fidimag.micro import UniformExchange, Demag, DMI 9 | from fidimag.micro import Zeeman, TimeZeeman 10 | from fidimag.common.fileio import DataReader 11 | 12 | mu0 = 4 * np.pi * 1e-7 13 | 14 | 15 | def init_m(pos): 16 | 17 | x, y = pos[0] - 500, pos[1] - 500 18 | 19 | if x**2 + y**2 < 50**2: 20 | return (0, 0, -1) 21 | else: 22 | return (0, 0, 1) 23 | 24 | 25 | def relax_system(mesh): 26 | 27 | sim = Sim(mesh, name='relax') 28 | 29 | sim.driver.set_tols(rtol=1e-10, atol=1e-14) 30 | sim.driver.alpha = 0.5 31 | sim.driver.gamma = 2.211e5 32 | sim.Ms = 8.6e5 33 | sim.do_precession = False 34 | 35 | sim.set_m(init_m) 36 | # sim.set_m(np.load('m0.npy')) 37 | 38 | A = 1.3e-11 39 | exch = UniformExchange(A=A) 40 | sim.add(exch) 41 | 42 | dmi = DMI(D=1e-3) 43 | sim.add(dmi) 44 | 45 | zeeman = Zeeman((0, 0, 2e4)) 46 | sim.add(zeeman, save_field=True) 47 | 48 | sim.relax(dt=1e-13, stopping_dmdt=0.01, max_steps=5000, 49 | save_m_steps=None, save_vtk_steps=50) 50 | 51 | np.save('m0.npy', sim.spin) 52 | 53 | 54 | if __name__ == '__main__': 55 | 56 | mesh = CuboidMesh( 57 | nx=1001, ny=1001, nz=1, dx=1, dy=1, dz=2.0, unit_length=1e-9, periodicity=(True, True, False)) 58 | 59 | relax_system(mesh) 60 | 61 | # apply_field1(mesh) 62 | # deal_plot() 63 | -------------------------------------------------------------------------------- /examples/micromagnetic/spatial_dmi/main.py: -------------------------------------------------------------------------------- 1 | import fidimag.micro 2 | import numpy as np 3 | 4 | xMax = 50. # Upper bound of the domain, centred about zero. Domain only varies 5 | # in x. 6 | D = 4e-3 # DMI coefficient, [Jm-2]. 7 | 8 | def m_init(pos): 9 | """Define magnetisation texture corresponding to +Mz at the edges, -Mz at 10 | centre, and rotating through My. Encourages helices that change chirality 11 | at the centre..""" 12 | Mz = abs(pos[0]) * 2. / xMax - 1 13 | My = (1 - Mz ** 2.) ** 0.5 14 | My *= 1 if pos[0] < 0 else -1 # Change direction! Could be the wrong way 15 | # though... 16 | return [0., My, Mz] 17 | 18 | def dmi_variance(pos): 19 | """Define how the DMI is defined on the simulation domain. Is basically: 20 | 21 | ----------|---------- 22 | D -D 23 | 24 | """ 25 | return D if pos[0] < 0 else -D 26 | 27 | # Create a mesh that looks like this: ------------------ 28 | mesh = fidimag.micro.CuboidMesh(nx=100, dx=1, x0=-50, unit_length=1e-9) 29 | sim = fidimag.micro.Sim(mesh) 30 | 31 | # Dynamics parameters. 32 | sim.driver.set_tols(rtol=1e-6, atol=1e-6) 33 | sim.driver.alpha = 0.5 34 | sim.driver.gamma = 2.211e5 35 | sim.Ms = 8.6e5 36 | sim.do_precession = False 37 | 38 | # Set magnetisation and add energies. 39 | sim.set_m(m_init) 40 | sim.add(fidimag.micro.UniformExchange(A=1.3e-11)) 41 | sim.add(fidimag.micro.DMI(D=dmi_variance)) 42 | 43 | # Relax and save. 44 | sim.relax(dt=1e-13, stopping_dmdt=1e-2, save_m_steps=None, save_vtk_steps=50) 45 | np.save('m0.npy', sim.spin) 46 | -------------------------------------------------------------------------------- /examples/micromagnetic/skyrmion/main.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.micro import Sim 7 | from fidimag.common import CuboidMesh 8 | from fidimag.micro import UniformExchange, Demag, DMI 9 | from fidimag.micro import Zeeman, TimeZeeman 10 | from fidimag.common.fileio import DataReader 11 | 12 | mu0 = 4 * np.pi * 1e-7 13 | 14 | 15 | def init_m(pos): 16 | 17 | x, y = pos[0] - 500, pos[1] - 500 18 | 19 | if x**2 + y**2 < 50**2: 20 | return (0, 0, -1) 21 | else: 22 | return (0, 0, 1) 23 | 24 | 25 | def relax_system(mesh): 26 | 27 | sim = Sim(mesh, name='relax') 28 | 29 | sim.driver.set_tols(rtol=1e-10, atol=1e-14) 30 | sim.driver.alpha = 0.5 31 | sim.driver.gamma = 2.211e5 32 | sim.Ms = 8.6e5 33 | sim.do_precession = False 34 | 35 | sim.set_m(init_m) 36 | # sim.set_m(np.load('m0.npy')) 37 | 38 | A = 1.3e-11 39 | exch = UniformExchange(A=A) 40 | sim.add(exch) 41 | 42 | dmi = DMI(D=1e-3) 43 | sim.add(dmi) 44 | 45 | zeeman = Zeeman((0, 0, 2e4)) 46 | sim.add(zeeman, save_field=True) 47 | 48 | sim.relax(dt=1e-13, stopping_dmdt=0.01, max_steps=5000, 49 | save_m_steps=None, save_vtk_steps=50) 50 | 51 | np.save('m0.npy', sim.spin) 52 | 53 | 54 | if __name__ == '__main__': 55 | 56 | mesh = CuboidMesh( 57 | nx=1001, ny=1001, nz=1, dx=1, dy=1, dz=2.0, unit_length=1e-9, periodicity=(True, True, False)) 58 | 59 | relax_system(mesh) 60 | 61 | # apply_field1(mesh) 62 | # deal_plot() 63 | -------------------------------------------------------------------------------- /examples/atomistic/heat/compute_energy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.integrate as integrate 3 | import matplotlib as mpl 4 | mpl.use("Agg") 5 | import matplotlib.pyplot as plt 6 | import fidimag.common.constant as const 7 | """ 8 | compute the figure 2 in the paper at dx.doi.org/10.1063/1.2169472 9 | Note: it seems that the volume given in the paper is not correct, 10 | since v=28e-27 generates the correct figures. 11 | """ 12 | 13 | 14 | def compute_energy(mx): 15 | Ms = 1.42e6 16 | a, b, c = 4, 2, 2 17 | v = 4.0 / 3 * np.pi * a * b * c * 1e-27 18 | 19 | v = 28e-27 20 | 21 | alpha = 0.005 22 | T = 300 23 | nu2 = alpha * 2 * const.k_B * T / (const.mu_0 * Ms**2 * v) 24 | mu = 2 * alpha / nu2 25 | 26 | Dx = 0.0946 27 | Dy = 0.4132 28 | 29 | fun = lambda t: np.exp(-mu / 2.0 * 30 | (Dx * np.cos(t)**2 + Dy * np.sin(t)**2)) * np.sin(t) 31 | res = integrate.quad(fun, 0, np.pi) 32 | Z = res[0] 33 | 34 | print 'mu=', mu, 'Z=', Z 35 | 36 | gl = (Dx * mx**2 + Dy * (1 - mx**2)) / 2.0 37 | 38 | p = 1 / Z * np.exp(-mu * gl) 39 | 40 | return p 41 | 42 | 43 | def plot_energy(name='out.pdf'): 44 | fig = plt.figure() 45 | mxs = np.linspace(-1, 1, 21) 46 | energy = [] 47 | for x in mxs: 48 | en = compute_energy(x) 49 | energy.append(en) 50 | 51 | plt.plot(mxs, energy, '.-') 52 | plt.xlabel('m_x') 53 | plt.ylabel('Energy') 54 | #plt.ylim([0, 2]) 55 | fig.savefig(name) 56 | 57 | 58 | if __name__ == '__main__': 59 | print compute_energy(0) 60 | plot_energy() 61 | -------------------------------------------------------------------------------- /doc/physics_num_methods/monte_carlo.rst: -------------------------------------------------------------------------------- 1 | Monte Carlo Simulation 2 | ======================= 3 | 4 | In the atomistic part of Fidimag, Monte Carlo based on Metropolis algorithm is integrated. 5 | The supported interactions include the exchange interaction, the bulk DMI, the external field and 6 | cubic anisotropy. The total Hamiltonian of the system is therefore given by 7 | 8 | .. math:: 9 | \mathcal{H} = \mathcal{H}_{ex} + \mathcal{H}_{dmi} + \mathcal{H}_{ext} + \mathcal{H}_{c} 10 | 11 | where :math:`\mathcal{H}_{ex}` is the nearest-neighbor exchange interaction, 12 | 13 | .. math:: 14 | \mathcal{H}_{ex} = -J \sum_{}\vec{m}_i \cdot \vec{m}_j 15 | 16 | Note that the summation is taken only once for each pair and :math:`\vec{m}_i` is the unit vector of spin :math:`\vec{S}` at site :math:`i`. 17 | 18 | The Hamiltonian of bulk DMI can be expressed as, 19 | 20 | .. math:: 21 | \mathcal{H}_{dmi}= \sum_{} \vec{D}_{ij}\cdot [\vec{m}_i \times \vec{m}_j] 22 | 23 | where :math:`\vec{D}_{ij} = D \vec{e}_{ij}` with :math:`\vec{e}_{ij}` is the unit vector between :math:`\vec{S}_{i}` and :math:`\vec{S}_{j}`. 24 | 25 | The Hamiltonian of external field is 26 | 27 | .. math:: 28 | \mathcal{H}_{dmi}= - \sum_{i} \mu_s \vec{H}\cdot \vec{m}_i 29 | 30 | where :math:`\mu_s = g \mu_B S`. 31 | 32 | The cubic anisotropy implemented in Fidimag is, 33 | 34 | .. math:: 35 | \mathcal{H}_{c}= - \sum_{i} (K_c/2) (m_{i,x}^4 + m_{i,y}^4 + m_{i,z}^4) 36 | 37 | which is equivalent to the form 38 | 39 | .. math:: 40 | \mathcal{H}_{c}= \sum_{i} K_c (m_{i,x}^2 m_{i,y}^2 + m_{i,y}^2 m_{i,z}^2 + m_{i,z}^2 m_{i,x}^2) 41 | 42 | 43 | -------------------------------------------------------------------------------- /fidimag/common/save_vtk.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from fidimag.common.vtk import VTK 4 | 5 | 6 | class SaveVTK(): 7 | 8 | def __init__(self, mesh, name='unnamed', directory=None): 9 | self.name = name 10 | 11 | if directory is None: 12 | self.directory = '{}_vtks'.format(name) 13 | else: 14 | self.directory = directory 15 | 16 | # Initiate a VTK object 17 | self.VTK = VTK(mesh, 18 | directory=self.directory, 19 | filename=name 20 | ) 21 | 22 | def save_vtk(self, m1, Ms, step=0, vtkname='m'): 23 | self.VTK.reset_data() 24 | # Here we save both Ms and spins as cell data 25 | self.VTK.save_scalar(Ms, name='Ms') 26 | self.VTK.save_vector(m1, name='spins') 27 | 28 | # Now we set the name of the file to start with m_ as default 29 | self.VTK.filename = vtkname 30 | self.VTK.write_file(step=step) 31 | 32 | def save_vtk_scalar(self, scalar_data_array, step=0, vtkname='skx'): 33 | # This saves the skyrmion number or any scalar data 34 | # CHECK: that the array skx_num is being passed with the correct shape 35 | # TODO: put more generic names as default names 36 | self.VTK.save_scalar(scalar_data_array, name='skx_num') 37 | 38 | # These files will be saved starting with: skx_ or other name 39 | # and saved to a different folder instead of {}_vtks 40 | self.VTK.filename = vtkname 41 | self.VTK.directory = self.name + '_' + vtkname 42 | self.VTK.write_file(step=step) 43 | -------------------------------------------------------------------------------- /examples/micromagnetic/nmag_example_2_box/plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | matplotlib.use('Agg') 3 | import matplotlib.pyplot as plt 4 | from fidimag.common.fileio import DataReader 5 | 6 | # labels on plot 7 | mathmode = lambda txt: "$" + txt + "$" 8 | rm = lambda txt: "\mathrm{" + txt + "}" 9 | label = lambda name, mi: mathmode(rm(rm(name) + "\; m_" + rm(mi))) 10 | fidi = mathmode(rm("fidimag")) 11 | m = lambda i: label("fidimag", i) 12 | 13 | for datafile, descr in ( 14 | ("sim_sundials_J0", "w/o Jacobian"), 15 | ("sim_sundials_diag", "Jacobian approx."), 16 | ("sim_sundials_J1", "with Jacobian")): 17 | data = DataReader(datafile + ".txt") 18 | total_wall_time = (data["real_time"][-1] - data["real_time"][0]) / 60.0 19 | 20 | fig, axes = plt.subplots(2, figsize=(10, 8), sharex=True) 21 | 22 | # magnetisation dynamics 23 | axes[0].plot(data["time"] * 1e9, data["m_x"], "bx", label=m("x")) 24 | axes[0].plot(data["time"] * 1e9, data["m_y"], "gx", label=m("y")) 25 | axes[0].plot(data["time"] * 1e9, data["m_z"], "rx", label=m("z")) 26 | axes[0].set_ylim((-0.3, 1.1)) 27 | axes[0].set_ylabel("unit magnetisation (1)") 28 | axes[0].legend() 29 | axes[0].set_title("{}, wall time {:.2} minutes".format(descr, total_wall_time)) 30 | 31 | # number of RHS evaluations 32 | axes[1].plot(data["time"] * 1e9, data["rhs_evals"], label=fidi) 33 | axes[1].legend(loc=0) 34 | axes[1].set_ylabel("# of RHS evaluations") 35 | axes[1].set_xlabel("time (ns)") 36 | axes[1].set_xlim((0, 0.3)) 37 | 38 | fig.tight_layout() 39 | fig.savefig(datafile + ".png") 40 | plt.close(fig) 41 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/fmmlib/fmmlib.pyx: -------------------------------------------------------------------------------- 1 | from libcpp.vector cimport vector 2 | 3 | cdef extern from "tree.hpp": 4 | cdef cppclass Particle: 5 | Particle(double x, double y, double z, double mux, double muy, double muz) 6 | double x, y, z, mux, muy, muz 7 | 8 | cdef cppclass Cell: 9 | Cell(double x, double y, double z, double r, unsigned int parent, unsigned int order, 10 | unsigned int level, unsigned int ncrit) 11 | unsigned int nleaf, nchild, level 12 | double x, y, z, r 13 | unsigned int parent 14 | vector[double] Mx 15 | vector[double] My 16 | vector[double] Mz 17 | vector[double] Lx 18 | vector[double] Ly 19 | vector[double] Lz 20 | vector[int] leaf 21 | 22 | cdef vector[Cell] build_tree(vector[Particle]& particles, 23 | Cell &root, 24 | unsigned int ncrit, 25 | unsigned int order) 26 | 27 | 28 | cdef vector[Particle] sim_to_particles(mesh, mu_s): 29 | """ 30 | Convert the positions of the lattice spins to C++ Particle objects 31 | for the building of the trees. 32 | """ 33 | ids = [] 34 | for k in range(mesh.nz): 35 | for j in range(mesh.ny): 36 | for i in range(mesh.nx): 37 | id = k * mesh.nx * mesh.ny + j * mesh.nx + i 38 | # Check that the spin is not a 'ghost' spin 39 | if mu_s[id] != 0: 40 | ids.append(id) 41 | 42 | 43 | 44 | 45 | 46 | def build_tree(mesh, mus): 47 | pass 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/fmmlib/calculate.hpp: -------------------------------------------------------------------------------- 1 | //############################################ 2 | //# 3 | //# Functions for running the Barnes-Hut 4 | //# method for gravitational source particles. 5 | //# 6 | //# (C) Ryan Pepper, 2018 7 | //# University of Southampton, UK 8 | //# 9 | //# 10 | //########################################### 11 | 12 | #include 13 | #include "expansions.hpp" 14 | #include "tree.hpp" 15 | #include "utils.hpp" 16 | #include 17 | 18 | #ifndef FMMLIB_CALCULATE_HPP 19 | #define FMMLIB_CALCULATE_HPP 20 | 21 | 22 | void evaluate_P2M(std::vector &particles, std::vector &cells, unsigned int cell, unsigned int ncrit, unsigned int exporder); 23 | 24 | void evaluate_M2M(std::vector &particles, std::vector &cells, unsigned int exporder); 25 | 26 | void evaluate_M2P_and_P2P(std::vector &particles, unsigned int p, 27 | unsigned int i, std::vector &cells, std::vector &Bx, 28 | std::vector &By, std::vector &Bz, unsigned int n_crit, 29 | double theta, unsigned int exporder, std::vector> &mempool); 30 | 31 | void evaluate_approx(std::vector &particles, std::vector &cells, std::vector &Bx, 32 | std::vector &By, std::vector &Bz, unsigned int n_crit, double theta, 33 | unsigned int exp_order); 34 | 35 | void evaluate_direct(std::vector &particles, std::vector &Bx, std::vector &By, 36 | std::vector &Bz); 37 | 38 | 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /examples/atomistic/PRL_108_017601/figure1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman 3 | from fidimag.common import CuboidMesh 4 | 5 | def init_m(pos): 6 | x, y, z = pos 7 | 8 | x0, y0, r = 166, 96, 25 9 | 10 | x1 = x % x0 11 | y1 = y % y0 12 | 13 | m1 = (0.05, 0.01, -1) 14 | m2 = (0, 0, 1) 15 | 16 | if (x1 - r)**2 + (y1 - r)**2 < r**2: 17 | return m1 18 | elif (x1 - x0 / 2. - r)**2 + (y1 - y0 / 2. - r)**2 < r**2: 19 | return m1 20 | else: 21 | return m2 22 | 23 | 24 | def random_m(pos): 25 | return np.random.random(3) - 0.5 26 | 27 | 28 | def relax_system(mesh): 29 | 30 | sim = Sim(mesh, name='relax') 31 | # sim.set_options(rtol=1e-10,atol=1e-14) 32 | sim.driver.alpha = 1.0 33 | sim.driver.gamma = 1.0 34 | sim.mu_s = 1.0 35 | 36 | sim.set_m(init_m) 37 | # sim.set_m(random_m) 38 | # sim.set_m(np.load('m_10000.npy')) 39 | 40 | J = 1.0 41 | exch = UniformExchange(J) 42 | sim.add(exch) 43 | 44 | D = 0.09 45 | dmi = DMI(D) 46 | sim.add(dmi) 47 | 48 | zeeman = Zeeman([0, 0, 3.75e-3]) 49 | sim.add(zeeman) 50 | 51 | sim.relax(dt=2.0, stopping_dmdt=1e-6, max_steps=1000, 52 | save_m_steps=100, save_vtk_steps=50) 53 | 54 | np.save('m0.npy', sim.spin) 55 | 56 | 57 | if __name__ == '__main__': 58 | 59 | np.random.seed(11) 60 | 61 | #mesh = CuboidMesh(nx=288,ny=288,nz=1) 62 | mesh = CuboidMesh(nx=166, ny=96 * 2, nz=1, periodicity=(True, True, False)) 63 | 64 | relax_system(mesh) 65 | 66 | print 'relax system done' 67 | # spin_wave(mesh,m0) 68 | -------------------------------------------------------------------------------- /examples/atomistic/dw_demag/dw_demag.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | from fidimag.atomistic import Sim 6 | from fidimag.atomistic import DMI, Demag, UniformExchange 7 | from fidimag.common import CuboidMesh 8 | 9 | 10 | def init_m(pos): 11 | x, y, z = pos 12 | if x < 140 * 0.5: 13 | return (1, 0, 0.1) 14 | elif x > 160 * 0.5: 15 | return (-1, 0, 0.1) 16 | else: 17 | return (0, 1, 0.1) 18 | 19 | 20 | def relax_system(mesh): 21 | 22 | sim = Sim(mesh, name='relax') 23 | sim.mu_s=1e-23 24 | sim.driver.gamma=1.76e11 25 | sim.driver.alpha = 1.0 26 | J = 1e-22 27 | exch = UniformExchange(J) 28 | sim.add(exch) 29 | demag = Demag() 30 | sim.add(demag) 31 | sim.set_m(init_m) 32 | 33 | ts = np.linspace(0, 5e-10, 101) 34 | for t in ts: 35 | sim.driver.run_until(t) 36 | sim.save_vtk() 37 | np.save('m0.npy', sim.spin) 38 | 39 | 40 | def save_plot(): 41 | fig = plt.figure() 42 | data = np.load('m0.npy') 43 | data.shape = (-1, 3) 44 | print(data) 45 | 46 | plt.plot(data[:, 0], '-', label='Sx') 47 | plt.plot(data[:, 1], '-', label='Sy') 48 | plt.plot(data[:, 2], '-', label='Sz') 49 | 50 | plt.ylim([-1.2, 1.2]) 51 | plt.ylabel('S') 52 | plt.xlabel('x/a') 53 | plt.legend(loc=1) 54 | plt.grid() 55 | fig.savefig('mxyz.pdf') 56 | 57 | if __name__ == '__main__': 58 | 59 | mesh = CuboidMesh(nx=300, dx=0.5, dy=1, dz=1, unit_length=1e-9) 60 | 61 | relax_system(mesh) 62 | print('relax system done') 63 | save_plot() 64 | # spin_wave(mesh,m0) 65 | -------------------------------------------------------------------------------- /examples/atomistic/dw_field/dw-field.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pc import * 3 | import time 4 | 5 | 6 | def init_m(pos): 7 | x, y, z = pos 8 | if x < 8: 9 | return (1, 0, 0) 10 | elif x > 12: 11 | return (-1, 0, 0) 12 | else: 13 | return (0, 1, 0) 14 | 15 | 16 | def relax_system(mesh, mat): 17 | sim = Sim(mesh, T=0, mat=mat, name='relax') 18 | sim.c = 2 19 | 20 | exch = UniformExchange(mat.J) 21 | sim.add(exch) 22 | 23 | anis = Anisotropy(mat.D) 24 | sim.add(anis) 25 | 26 | sim.set_m(init_m) 27 | 28 | ts = np.linspace(0, 100, 2001) 29 | sim.save_vtk() 30 | 31 | for t in ts: 32 | sim.run_until(t) 33 | 34 | sim.save_vtk() 35 | 36 | return sim.spin 37 | 38 | 39 | def dw_motion(mesh, m0, mat, H0=1): 40 | sim = Sim(mesh, T=0, mat=mat) 41 | sim.c = 3 42 | 43 | exch = UniformExchange(mat.J) 44 | sim.add(exch) 45 | 46 | anis = Anisotropy(mat.D) 47 | sim.add(anis) 48 | 49 | zeeman = Zeeman(H0, (1, 0, 0)) 50 | sim.add(zeeman) 51 | 52 | sim.set_m(m0) 53 | 54 | ts = np.linspace(0, 200, 2001) 55 | for t in ts: 56 | sim.run_until(t) 57 | sim.save_vtk() 58 | 59 | 60 | if __name__ == '__main__': 61 | 62 | ni = Nickel() 63 | ni.alpha = 0.5 64 | ni.a = 1 65 | ni.b = 1 66 | ni.c = 1 67 | ni.unit_length = 1 68 | ni.mu_s = 1 69 | ni.D = 1 70 | ni.J = 2 71 | ni.gamma = 1 72 | 73 | mesh = CuboidMesh(nx=20, ny=5, nz=2) 74 | mesh.set_material(ni) 75 | 76 | m0 = relax_system(mesh, ni) 77 | print 'relax system done' 78 | ni.alpha = 0.05 79 | dw_motion(mesh, m0, ni) 80 | -------------------------------------------------------------------------------- /fidimag/atomistic/exchange_new.py: -------------------------------------------------------------------------------- 1 | from .field import scalar_field, vector_field 2 | 3 | class Exchange(object): 4 | """ 5 | Uniform exchange interaction. 6 | 7 | """ 8 | def __init__(self, mesh, J, name="exchange"): 9 | self.mesh = mesh 10 | # J is a scalar field, because that's good enough for uniform 11 | # exchange. Could be changed trivially by making J a vector field 12 | # and changing the J = self.J[c_i] line in the compute method. 13 | self.J = scalar_field(mesh, J) 14 | # field and energy are just np.arrays. In principle, they could be 15 | # created in the scope of the compute method, but we want to avoid 16 | # re-creating the objects in memory unnecessarily. 17 | self.field = vector_field(mesh, 0) 18 | self.energy = scalar_field(mesh, 0) 19 | self.in_jacobian = True 20 | 21 | def compute(self, spins): 22 | """ 23 | Compute the exchange field and the exchange energy. 24 | 25 | """ 26 | for c_i in mesh.cells(): 27 | #TODO: cythonise this loop fiercely 28 | # like shown at http://docs.cython.org/src/tutorial/numpy.html 29 | fx = 0 30 | fy = 0 31 | fz = 0 32 | J = self.J[c_i] 33 | for c_j in mesh.neighbours[c_i]: 34 | fx += J * spins[c_j, 0] 35 | fy += J * spins[c_j, 1] 36 | fz += J * spins[c_j, 2] 37 | self.field[c_i] = (fx, fy, fz) 38 | self.energy[c_i] = -0.5 * ( fx * spins[c_i, 0] 39 | + fy * spins[c_i, 1] 40 | + fz * spins[c_i, 2]) 41 | -------------------------------------------------------------------------------- /fidimag/atomistic/energy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | #from constant import mu_0 4 | 5 | 6 | class Energy(object): 7 | 8 | """ 9 | 10 | An abstract class to implement the basic functions such as setup for atomic 11 | dynamics. 12 | 13 | """ 14 | 15 | def setup(self, mesh, spin, mu_s, mu_s_inv): 16 | self.mesh = mesh 17 | self.dx = mesh.dx * mesh.unit_length 18 | self.dy = mesh.dy * mesh.unit_length 19 | self.dz = mesh.dz * mesh.unit_length 20 | self.nx = mesh.nx 21 | self.ny = mesh.ny 22 | self.nz = mesh.nz 23 | self.spin = spin 24 | self.n = mesh.n 25 | self.n_ngbs = mesh.n_ngbs 26 | self.mesh_type = mesh.mesh_type 27 | 28 | self.total_energy = 0 29 | self.mu_s = mu_s 30 | 31 | self.field = np.zeros(3 * self.n, dtype=np.float64) 32 | self.energy = np.zeros(mesh.n, dtype=np.float64) 33 | self.total_energy = 0.0 34 | 35 | self.mu_s_inv = mu_s_inv 36 | 37 | self.xperiodic, self.yperiodic = (mesh.periodicity[0], 38 | mesh.periodicity[1]) 39 | self.neighbours = mesh.neighbours 40 | 41 | try: 42 | self.coordinates = self.mesh.coordinates 43 | except: 44 | self.coordinates = np.array(self.mesh.pos) 45 | 46 | def compute_field(self, t=0): 47 | 48 | return 0 49 | 50 | def compute_energy(self): 51 | 52 | # since we are not always calling this function, so it's okay to call 53 | # compute_field again 54 | self.compute_field() 55 | 56 | self.total_energy = np.sum(self.energy) 57 | 58 | return self.total_energy 59 | -------------------------------------------------------------------------------- /examples/atomistic/stt/single_spin_stt.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman, Anisotropy 3 | from fidimag.common import CuboidMesh, DataReader 4 | import matplotlib.pyplot as plt 5 | 6 | def dynamic(mesh): 7 | 8 | sim = Sim(mesh, name='dyn_spin', driver='slonczewski') 9 | # sim.set_options(rtol=1e-10,atol=1e-14) 10 | sim.driver.gamma = 1.0 11 | sim.mu_s = 1.0 12 | 13 | sim.set_m((0.8,0,-1)) 14 | 15 | Kx = Anisotropy(Ku=-0.05, axis=(0, 0, 1), name='Kz') 16 | sim.add(Kx) 17 | 18 | sim.p = (0,0,1) 19 | 20 | sim.u0 = 0.005 21 | sim.driver.alpha = 0.1 22 | 23 | ts = np.linspace(0, 1200, 401) 24 | for t in ts: 25 | sim.run_until(t) 26 | #sim.save_vtk() 27 | print t 28 | 29 | def plot_all(): 30 | 31 | font = {'family': 'serif', 32 | 'weight': 'normal', 33 | 'size': 12, 34 | } 35 | 36 | plt.rc('font', **font) 37 | 38 | data = DataReader('dyn_spin.txt') 39 | ts = data['time'] 40 | 41 | fig = plt.figure(figsize=(5, 4)) 42 | 43 | mx = data['m_x'] 44 | my = data['m_y'] 45 | mz = data['m_z'] 46 | plt.plot(ts, mx, '-', label='mx', color='b') 47 | plt.plot(ts, my, '-', label='my', color='g') 48 | plt.plot(ts[::6], mz[::6],'.-', label='mz', color='r') 49 | 50 | plt.legend(bbox_to_anchor=[0.8, 0.8], shadow=True, frameon=True) 51 | #plt.xlim([0, 1.01]) 52 | 53 | plt.legend() 54 | 55 | plt.xlabel('Time') 56 | plt.ylabel('m') 57 | plt.tight_layout() 58 | fig.savefig('m_ts.pdf') 59 | 60 | if __name__ == '__main__': 61 | mesh = CuboidMesh(nx=1, ny=1, nz=1) 62 | dynamic(mesh) 63 | plot_all() 64 | -------------------------------------------------------------------------------- /examples/micromagnetic/skyrmion/Ku_H/main.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.micro import Sim 7 | from fidimag.common import CuboidMesh 8 | from fidimag.micro import UniformExchange, Demag, DMI, UniaxialAnisotropy 9 | from fidimag.micro import Zeeman, TimeZeeman 10 | from fidimag.common.fileio import DataReader 11 | 12 | mu0 = 4 * np.pi * 1e-7 13 | 14 | 15 | def init_m(pos): 16 | 17 | x, y = pos[0] - 500, pos[1] - 500 18 | 19 | if x**2 + y**2 < 60**2: 20 | return (0, 0, -1) 21 | else: 22 | return (0, 0, 1) 23 | 24 | 25 | def relax_system(mesh): 26 | 27 | sim = Sim(mesh, name='relax') 28 | 29 | sim.driver.set_tols(rtol=1e-6, atol=1e-6) 30 | sim.driver.alpha = 0.5 31 | sim.driver.gamma = 2.211e5 32 | sim.Ms = 8.6e5 33 | sim.do_precession = False 34 | 35 | sim.set_m(init_m) 36 | # sim.set_m(np.load('m0.npy')) 37 | 38 | A = 1.3e-11 39 | exch = UniformExchange(A=A) 40 | sim.add(exch) 41 | 42 | dmi = DMI(D=1.3e-3) 43 | sim.add(dmi) 44 | 45 | anis = UniaxialAnisotropy(-3.25e4, axis=(0, 0, 1)) 46 | sim.add(anis) 47 | 48 | zeeman = Zeeman((0, 0, 6.014576e4)) 49 | sim.add(zeeman, save_field=True) 50 | 51 | sim.relax(dt=1e-13, stopping_dmdt=1e-2, max_steps=5000, 52 | save_m_steps=None, save_vtk_steps=50) 53 | 54 | np.save('m0.npy', sim.spin) 55 | 56 | 57 | if __name__ == '__main__': 58 | 59 | mesh = CuboidMesh( 60 | nx=501, ny=501, nz=1, dx=2.0, dy=2.0, dz=2.0, unit_length=1e-9, periodicity=(True, True, False)) 61 | 62 | relax_system(mesh) 63 | 64 | # apply_field1(mesh) 65 | # deal_plot() 66 | -------------------------------------------------------------------------------- /sandbox/parallel-cvode/test_cvode_serial.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | import time 3 | d = 100 4 | t = 10 5 | dx = dy = 2.5 6 | 7 | dz = 5 8 | mesh = fidimag.common.CuboidMesh(nx=int(d/dx), ny=int(d/dy), nz=int(t/dz), dx=dx, dy=dy, dz=dz, unit_length=1e-9) 9 | 10 | def Ms_function(Ms): 11 | def wrapped_function(pos): 12 | x, y, z = pos[0], pos[1], pos[2] 13 | 14 | r = ((x-d/2.)**2 + (y-d/2.)**2)**0.5 # distance from the centre 15 | 16 | if r <= d/2: 17 | # Mesh point is inside the disk. 18 | return Ms 19 | else: 20 | # Mesh point is outside the disk. 21 | return 0 22 | return wrapped_function 23 | 24 | def init_m(pos): 25 | x,y,z = pos 26 | x0, y0 = d/2., d/2. 27 | r = ((x-x0)**2 + (y-y0)**2)**0.5 28 | 29 | if r<10: 30 | return (0,0, 1) 31 | elif r<30: 32 | return (0,0, -1) 33 | elif r<60: 34 | return (0, 0, 1) 35 | else: 36 | return (0, 0, -1) 37 | 38 | # FeGe material paremeters. 39 | Ms = 3.84e5 # saturation magnetisation (A/m) 40 | A = 8.78e-12 # exchange energy constant (J/m) 41 | D = 1.58e-3 # Dzyaloshinkii-Moriya energy constant (J/m**2) 42 | alpha = 1 # Gilbert damping 43 | gamma = 2.211e5 # gyromagnetic ration (m/As) 44 | 45 | # Create simulation object. 46 | sim = fidimag.micro.Sim(mesh) 47 | sim.Ms = Ms_function(Ms) 48 | sim.alpha = alpha 49 | sim.driver.gamma = gamma 50 | 51 | # Add energies. 52 | sim.add(fidimag.micro.UniformExchange(A=A)) 53 | sim.add(fidimag.micro.DMI(D=D)) 54 | #sim.add(Demag()) 55 | 56 | # Initialise the system. 57 | sim.set_m(init_m) 58 | a = time.time() 59 | sim.driver.run_until(5e-9) 60 | b = time.time() 61 | print('elpased time: %g'%(b - a)) 62 | -------------------------------------------------------------------------------- /examples/atomistic/heat/dw-heat.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import fidimag 3 | from fidimag.atomistic import * 4 | from fidimag.common import CuboidMesh 5 | import time 6 | 7 | 8 | def init_T(pos): 9 | return 0.001 * pos[0] 10 | 11 | 12 | def init_m(pos): 13 | x, y, z = pos 14 | if x < 300: 15 | return (1, 0, 0) 16 | elif x > 350: 17 | return (-1, 0, 0) 18 | else: 19 | return (0, 1, 0) 20 | 21 | 22 | def relax_system(mesh, mat): 23 | sim = Sim(mesh, name='relax') 24 | sim.set_mu_s(mat.mu_B) 25 | exch = UniformExchange(mat.J) 26 | sim.add(exch) 27 | 28 | anis = Anisotropy(mat.D) 29 | sim.add(anis) 30 | 31 | sim.set_m(init_m) 32 | 33 | ts = np.linspace(0, 5e-10, 21) 34 | sim.save_vtk() 35 | 36 | for t in ts: 37 | sim.driver.run_until(t) 38 | sim.save_vtk() 39 | 40 | return sim.spin 41 | 42 | 43 | def dw_motion(mesh, m0, mat, H0=1): 44 | sim = Sim(mesh, driver='sllg') 45 | sim.driver.set_T(init_T) 46 | 47 | exch = UniformExchange(mat.J) 48 | sim.add(exch) 49 | 50 | anis = Anisotropy(mat.D) 51 | sim.add(anis) 52 | 53 | # zeeman=Zeeman(H0,(1,0,0)) 54 | # sim.add(zeeman) 55 | 56 | sim.set_m(m0) 57 | 58 | ts = np.linspace(0, 5e-10, 1001) 59 | for t in ts: 60 | sim.driver.run_until(t) 61 | print(t) 62 | sim.save_vtk() 63 | 64 | 65 | if __name__ == '__main__': 66 | 67 | ni = Nickel() 68 | ni.J *= 0.05 69 | 70 | dl = dx=ni.a*ni.unit_length 71 | mesh = fidimag.common.CuboidMesh(nx=200, ny=1, nz=1, dx=dl, dy=dl, dz=dl) 72 | 73 | m0 = relax_system(mesh, ni) 74 | print('relax system done') 75 | ni.alpha = 0.05 76 | dw_motion(mesh, m0, ni) 77 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | # Avoid user interaction dialog 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN apt -y update 7 | # Binder fails with Cython from pip -> use apt cython3 8 | RUN apt install -y git python3 python3-pip gcc psutils cmake wget make cython3 9 | RUN apt install -y gfortran libblas-dev liblapack-dev python3-tk sudo fonts-lato 10 | RUN pip3 install pip -U 11 | RUN pip3 install matplotlib pytest scipy psutil pyvtk ipywidgets -U 12 | RUN pip3 install --no-cache-dir notebook 13 | 14 | RUN ln -s /usr/bin/python3 /usr/bin/python 15 | 16 | WORKDIR /usr/local 17 | RUN git clone https://github.com/computationalmodelling/fidimag.git 18 | WORKDIR /usr/local/fidimag 19 | # Work with stable release 20 | RUN git checkout tags/v3.0a2 21 | # Install CVODE and FFTW libraries 22 | WORKDIR /usr/local/fidimag/bin 23 | RUN bash install-fftw.sh 24 | RUN bash install-sundials.sh 25 | 26 | ENV PYTHONPATH="/usr/local/fidimag:$PYTHONPATH" 27 | ENV LD_LIBRARY_PATH="/usr/local/fidimag/local/lib:$LD_LIBRARY_PATH" 28 | 29 | WORKDIR /usr/local/fidimag 30 | RUN python3 setup.py build_ext --inplace 31 | RUN python3 -c "import matplotlib" 32 | # Headless Matplotlib: 33 | ENV MPLBACKEND=Agg 34 | 35 | # Headless Matplotlib: 36 | ENV MPLBACKEND=Agg 37 | 38 | # Set threads for OpenMP: 39 | ENV OMP_NUM_THREADS=2 40 | # WORKDIR /io 41 | 42 | # User to make Binder happy 43 | ENV NB_USER magnetism 44 | ENV NB_UID 1000 45 | ENV HOME /home/${NB_USER} 46 | 47 | RUN adduser --disabled-password \ 48 | --gecos "Default user" \ 49 | --uid ${NB_UID} \ 50 | ${NB_USER} 51 | 52 | # Make sure the contents of our repo are in ${HOME} 53 | COPY . ${HOME} 54 | USER root 55 | RUN chown -R ${NB_UID} ${HOME} 56 | USER ${NB_USER} 57 | 58 | WORKDIR /home/${USER}/magnetism/doc/ipynb 59 | -------------------------------------------------------------------------------- /fidimag/atomistic/lib/sllg.c: -------------------------------------------------------------------------------- 1 | #include "clib.h" 2 | 3 | /* 4 | * n is the spin number 5 | * eta is the random number array 6 | */ 7 | void llg_rhs_dw_c(double *restrict m, double *restrict h, double *restrict dm, double *restrict T, double *restrict alpha, 8 | double *restrict mu_s_inv, int *restrict pins, double *restrict eta, int n, double gamma, double dt) { 9 | 10 | double k_B = 1.3806505e-23; 11 | double Q = 2 * k_B * dt / gamma; 12 | 13 | //#pragma omp parallel for 14 | for (int id = 0; id < n; id++) { 15 | int i = 3*id; 16 | int j = i+1; 17 | int k = j+1; 18 | 19 | if (pins[id]>0){ 20 | dm[i] = 0; 21 | dm[j] = 0; 22 | dm[k] = 0; 23 | continue; 24 | } 25 | 26 | 27 | double coeff = -gamma/ (1.0 + alpha[id] * alpha[id]); 28 | double q = sqrt(Q * alpha[id] * T[id] * mu_s_inv[id]); 29 | 30 | double hi = h[i]*dt + eta[i]*q; 31 | double hj = h[j]*dt + eta[j]*q; 32 | double hk = h[k]*dt + eta[k]*q; 33 | 34 | double mth0 = coeff * (m[j] * hk - m[k] * hj); 35 | double mth1 = coeff * (m[k] * hi - m[i] * hk); 36 | double mth2 = coeff * (m[i] * hj - m[j] * hi); 37 | 38 | dm[i] = mth0 + alpha[id] * (m[j] * mth2 - m[k] * mth1); 39 | dm[j] = mth1 + alpha[id] * (m[k] * mth0 - m[i] * mth2); 40 | dm[k] = mth2 + alpha[id] * (m[i] * mth1 - m[j] * mth0); 41 | 42 | } 43 | } 44 | 45 | void normalise(double *restrict m, int *restrict pins, int n){ 46 | int i, j, k; 47 | double mm; 48 | for (int id = 0; id < n; id++) { 49 | i = 3*id; 50 | j = i + 1; 51 | k = j + 1; 52 | 53 | if (pins[id]>0) continue; 54 | 55 | 56 | mm = 1.0 / sqrt(m[i] * m[i] + m[j] * m[j] + m[k] * m[k]); 57 | m[i] *= mm; 58 | m[j] *= mm; 59 | m[k] *= mm; 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sandbox/parallel-cvode/test_cvode_parallel.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | import time 3 | d = 100 4 | t = 10 5 | dx = dy = 2.5 6 | 7 | dz = 5 8 | mesh = fidimag.common.CuboidMesh(nx=int(d/dx), ny=int(d/dy), nz=int(t/dz), dx=dx, dy=dy, dz=dz, unit_length=1e-9) 9 | 10 | def Ms_function(Ms): 11 | def wrapped_function(pos): 12 | x, y, z = pos[0], pos[1], pos[2] 13 | 14 | r = ((x-d/2.)**2 + (y-d/2.)**2)**0.5 # distance from the centre 15 | 16 | if r <= d/2: 17 | # Mesh point is inside the disk. 18 | return Ms 19 | else: 20 | # Mesh point is outside the disk. 21 | return 0 22 | return wrapped_function 23 | 24 | def init_m(pos): 25 | x,y,z = pos 26 | x0, y0 = d/2., d/2. 27 | r = ((x-x0)**2 + (y-y0)**2)**0.5 28 | 29 | if r<10: 30 | return (0,0, 1) 31 | elif r<30: 32 | return (0,0, -1) 33 | elif r<60: 34 | return (0, 0, 1) 35 | else: 36 | return (0, 0, -1) 37 | 38 | # FeGe material paremeters. 39 | Ms = 3.84e5 # saturation magnetisation (A/m) 40 | A = 8.78e-12 # exchange energy constant (J/m) 41 | D = 1.58e-3 # Dzyaloshinkii-Moriya energy constant (J/m**2) 42 | alpha = 1 # Gilbert damping 43 | gamma = 2.211e5 # gyromagnetic ration (m/As) 44 | 45 | # Create simulation object. 46 | sim = fidimag.micro.Sim(mesh, integrator='sundials_openmp') 47 | sim.Ms = Ms_function(Ms) 48 | sim.alpha = alpha 49 | sim.driver.gamma = gamma 50 | 51 | # Add energies. 52 | sim.add(fidimag.micro.UniformExchange(A=A)) 53 | sim.add(fidimag.micro.DMI(D=D)) 54 | #sim.add(Demag()) 55 | 56 | # Initialise the system. 57 | sim.set_m(init_m) 58 | a = time.time() 59 | sim.driver.run_until(5e-9) 60 | b = time.time() 61 | print('elpased time: %g'%(b - a)) 62 | -------------------------------------------------------------------------------- /examples/atomistic/skyrmion_demag/single_ku.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim 3 | from fidimag.common import CuboidMesh 4 | from fidimag.atomistic import DMI, UniformExchange, Demag, Anisotropy 5 | import fidimag.common.constant as const 6 | 7 | def mu_s(pos): 8 | x, y, z = pos 9 | x0, y0, r = 60 * 0.5, 60 * 0.5, 60.5 * 0.5 10 | 11 | if (x - x0)**2 + (y - y0)**2 <= r**2: 12 | return const.mu_s_1 13 | else: 14 | return 0 15 | 16 | 17 | def init_m(pos): 18 | x, y, z = pos 19 | 20 | x0, y0, r = 60 * 0.5, 60 * 0.5, 25 * 0.5 21 | 22 | m1 = (0.05, 0.01, -1) 23 | m2 = (0, 0, 1) 24 | 25 | if (x - x0)**2 + (y - y0)**2 < r**2: 26 | return m1 27 | else: 28 | return m2 29 | 30 | 31 | def random_m(pos): 32 | return np.random.random(3) - 0.5 33 | 34 | 35 | def relax_system(): 36 | 37 | mesh = CuboidMesh(nx=121, ny=121, dx=0.5, dy=0.5, unit_length=1e-9) 38 | 39 | sim = Sim(mesh, name='relax_skx') 40 | sim.driver.gamma=const.gamma 41 | 42 | sim.driver.alpha = 1.0 43 | 44 | sim.mu_s = mu_s 45 | 46 | sim.set_m(init_m) 47 | 48 | J = 50.0 * const.k_B 49 | exch = UniformExchange(J) 50 | sim.add(exch) 51 | 52 | D = 0.09 * J 53 | dmi = DMI(D) 54 | sim.add(dmi) 55 | 56 | K = 5e-3 * J 57 | anis = Anisotropy(K, axis=(0, 0, 1), name='Ku') 58 | sim.add(anis) 59 | 60 | sim.add(Demag(calc_every=100)) 61 | 62 | ONE_DEGREE_PER_NS = 17453292.52 63 | 64 | sim.relax(dt=1e-12, stopping_dmdt=0.1, 65 | max_steps=5000, save_m_steps=100, save_vtk_steps=100) 66 | 67 | # np.save('m0.npy',sim.spin) 68 | sim.save_vtk() 69 | 70 | if __name__ == '__main__': 71 | 72 | np.random.seed(3) 73 | relax_system() 74 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Fidimag test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | unit-tests: 7 | 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | python-version: ['3.10'] 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: "Checkout" 17 | uses: actions/checkout@v2 18 | 19 | - name: Set up Python ${{ matrix.python-version }} 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | 24 | - name: "Update apt and install cmake" 25 | run: | 26 | sudo apt-get -y update 27 | sudo apt-get install -y cmake 28 | sudo apt-get install -y libatlas-base-dev libatlas3-base 29 | 30 | - name: "Install sundials and fftw" 31 | working-directory: ./bin 32 | run: | 33 | bash install-fftw.sh 34 | bash install-sundials.sh 35 | 36 | - name: "Install pip and packages" 37 | working-directory: ./ 38 | run: | 39 | python3 -m ensurepip 40 | python3 -m pip install --upgrade pip 41 | python3 -m pip install --user scipy numpy pytest matplotlib 42 | python3 -m pip install --user setuptools pyvtk cython psutil 43 | 44 | - name: "Install FIDIMAG" 45 | run: | 46 | python3 setup.py build_ext --inplace 47 | PWD=$(pwd) 48 | export PYTHONPATH=$PWD:$PYTHONPATH 49 | echo "PYTHONPATH=$PYTHONPATH" 50 | echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV 51 | echo "LD_LIBRARY_PATH=$PWD/local/lib" >> $GITHUB_ENV 52 | 53 | - name: "Run test" 54 | working-directory: ./tests 55 | run: | 56 | python3 -m pytest -v 57 | # env: 58 | # PYTHONPATH: $PWD 59 | -------------------------------------------------------------------------------- /examples/atomistic/stt/stt.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman, Anisotropy 3 | from fidimag.common import CuboidMesh 4 | 5 | 6 | def init_m(pos): 7 | x, y, z = pos 8 | if x < 250: 9 | return (1, 0, 0) 10 | elif x > 270: 11 | return (-1, 0, 0) 12 | else: 13 | return (0, 1, 0) 14 | 15 | 16 | def relax_system(mesh): 17 | 18 | sim = Sim(mesh, name='relax') 19 | # sim.set_options(rtol=1e-10,atol=1e-14) 20 | sim.driver.alpha = 1.0 21 | sim.driver.gamma = 1.0 22 | sim.mu_s = 1.0 23 | 24 | sim.set_m(init_m) 25 | # sim.set_m(random_m) 26 | # sim.set_m(np.load('m_10000.npy')) 27 | 28 | J = 1.0 29 | exch = UniformExchange(J) 30 | sim.add(exch) 31 | 32 | Kx = Anisotropy(Ku=0.005, axis=(1, 0, 0), name='Kx') 33 | sim.add(Kx) 34 | 35 | sim.relax(dt=2.0, stopping_dmdt=1e-6, max_steps=1000, 36 | save_m_steps=100, save_vtk_steps=50) 37 | 38 | np.save('m0.npy', sim.spin) 39 | 40 | 41 | def dynamic(mesh): 42 | 43 | sim = Sim(mesh, name='dyn', driver='slonczewski') 44 | # sim.set_options(rtol=1e-10,atol=1e-14) 45 | sim.driver.gamma = 1.0 46 | sim.mu_s = 1.0 47 | 48 | sim.set_m(np.load('m0.npy')) 49 | 50 | J = 1.0 51 | exch = UniformExchange(J) 52 | sim.add(exch) 53 | 54 | Kx = Anisotropy(Ku=0.005, axis=(1, 0, 0), name='Kx') 55 | sim.add(Kx) 56 | 57 | sim.p = (0,0,1) 58 | 59 | sim.u0 = 0.03 60 | sim.driver.alpha = 0.1 61 | 62 | ts = np.linspace(0, 1e3, 101) 63 | for t in ts: 64 | sim.run_until(t) 65 | sim.save_vtk() 66 | print t 67 | 68 | 69 | if __name__ == '__main__': 70 | mesh = CuboidMesh(nx=500, ny=1, nz=1) 71 | relax_system(mesh) 72 | dynamic(mesh) 73 | -------------------------------------------------------------------------------- /tests/test_demag.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from fidimag.common import CuboidMesh 3 | from fidimag.atomistic import Sim 4 | from fidimag.atomistic import Demag 5 | import numpy as np 6 | 7 | 8 | def test_demag_fft_exact(): 9 | mesh = CuboidMesh(nx=5, ny=3, nz=4, unit_length=1e-9) 10 | sim = Sim(mesh) 11 | 12 | demag = Demag() 13 | sim.add(demag) 14 | 15 | def init_m(pos): 16 | x = pos[0] 17 | if x <= 2: 18 | return (1, 0, 0) 19 | elif x >= 4: 20 | return (0, 0, 1) 21 | else: 22 | return (0, 1, 0) 23 | 24 | sim.set_m(init_m) 25 | fft = demag.compute_field() 26 | exact = demag.compute_exact() 27 | 28 | np.testing.assert_allclose(fft, exact, rtol=1e-10) 29 | 30 | 31 | 32 | 33 | def test_demag_fft_exact_oommf(): 34 | mesh = CuboidMesh(nx=5, ny=3, nz=2, unit_length=1e-9) 35 | sim = Sim(mesh) 36 | demag = Demag() 37 | sim.add(demag) 38 | 39 | def init_m(pos): 40 | x = pos[0] 41 | if x <= 2: 42 | return (1, 0, 0) 43 | elif x >= 4: 44 | return (0, 0, 1) 45 | else: 46 | return (0, 1, 0) 47 | sim.set_m(init_m) 48 | fft = demag.compute_field() 49 | exact = demag.compute_exact() 50 | np.testing.assert_allclose(fft, exact, rtol=1e-10) 51 | 52 | 53 | 54 | def test_demag_two_spin_xx(): 55 | mesh = CuboidMesh(nx=2, ny=1, nz=1) 56 | sim = Sim(mesh) 57 | demag = Demag() 58 | sim.add(demag) 59 | sim.set_m((1, 0, 0)) 60 | field = demag.compute_field() 61 | print(field) 62 | assert(field[0] == 2e-7) 63 | assert(field[3] == 2e-7) 64 | 65 | 66 | if __name__ == '__main__': 67 | test_demag_fft_exact() 68 | test_demag_two_spin_xx() 69 | test_demag_fft_exact_oommf() 70 | -------------------------------------------------------------------------------- /sandbox/parallel-cvode/test.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | d = 300 3 | t = 10 4 | dx = dy = 2.5 5 | 6 | dz = 5 7 | mesh = fidimag.common.CuboidMesh(nx=int(d/dx), ny=int(d/dy), nz=int(t/dz), dx=dx, dy=dy, dz=dz, unit_length=1e-9) 8 | 9 | def Ms_function(Ms): 10 | def wrapped_function(pos): 11 | x, y, z = pos[0], pos[1], pos[2] 12 | 13 | r = ((x-d/2.)**2 + (y-d/2.)**2)**0.5 # distance from the centre 14 | 15 | if r <= d/2: 16 | # Mesh point is inside the disk. 17 | return Ms 18 | else: 19 | # Mesh point is outside the disk. 20 | return 0 21 | return wrapped_function 22 | 23 | def init_m(pos): 24 | x,y,z = pos 25 | x0, y0 = d/2., d/2. 26 | r = ((x-x0)**2 + (y-y0)**2)**0.5 27 | 28 | if r<10: 29 | return (0,0, 1) 30 | elif r<30: 31 | return (0,0, -1) 32 | elif r<60: 33 | return (0, 0, 1) 34 | else: 35 | return (0, 0, -1) 36 | 37 | # FeGe material paremeters. 38 | Ms = 3.84e5 # saturation magnetisation (A/m) 39 | A = 8.78e-12 # exchange energy constant (J/m) 40 | D = 1.58e-3 # Dzyaloshinkii-Moriya energy constant (J/m**2) 41 | alpha = 1 # Gilbert damping 42 | gamma = 2.211e5 # gyromagnetic ration (m/As) 43 | 44 | # Create simulation object. 45 | sim = fidimag.micro.Sim(mesh, integrator='sundials') 46 | sim.Ms = Ms_function(Ms) 47 | sim.alpha = alpha 48 | sim.gamma = gamma 49 | 50 | # Add energies. 51 | sim.add(fidimag.micro.UniformExchange(A=A)) 52 | sim.add(fidimag.micro.DMI(D=D)) 53 | #sim.add(Demag()) 54 | 55 | # Since the magnetisation dynamics is not important in this stage, 56 | # the precession term in LLG equation can be set to artificially zero. 57 | sim.do_precession = False 58 | 59 | # Initialise the system. 60 | sim.set_m(init_m) 61 | 62 | sim.run_until(5e-9) 63 | -------------------------------------------------------------------------------- /sandbox/more-dmi/isolated_sk_sim.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import fidimag 3 | from fidimag.micro import Sim 4 | from fidimag.common import CuboidMesh 5 | import fidimag.common.constant as C 6 | 7 | 8 | def init_m(r): 9 | """ 10 | Initial magnetisation profile; a dot to obtain a skyrmion 11 | """ 12 | R_sk = 2 13 | rho = np.sqrt(r[0] ** 2 + r[1] ** 2) 14 | if rho < R_sk: 15 | return (0, 0, -1) 16 | else: 17 | return (0, 0, 1) 18 | 19 | 20 | dx, dy, dz = 0.25, 0.25, 1 21 | Lx, Ly, Lz = 20, 20, 1 22 | mesh = CuboidMesh(nx=int(Lx/dx), ny=int(Ly/dy), nz=int(Lz/dz), 23 | dx=dx, dy=dy, dz=dz, 24 | x0=-Lx/2, y0=-Ly/2, z0=-Lz/2, 25 | unit_length=1e-9) 26 | 27 | sim = Sim(mesh) 28 | 29 | Ms = 1.1e6 30 | A = 2e-12 31 | D = 3.9e-3 32 | Ku = 2.5e6 33 | Bz = 1. 34 | 35 | sim.set_Ms(Ms) 36 | sim.add(fidimag.micro.UniformExchange(A)) 37 | sim.add(fidimag.micro.UniaxialAnisotropy(Ku, axis=(0, 0, 1))) 38 | sim.add(fidimag.micro.Zeeman((0, 0, Bz / C.mu_0))) 39 | 40 | # sim.add(fidimag.micro.DMI(D, dmi_type='interfacial')) 41 | 42 | # For a C_n material, there is a kind of instability when one of the DM 43 | # constants is larger than approx 0.7 times the other DM constant 44 | sim.add(fidimag.micro.DMI([D, 0.6 * D], dmi_type='C_n')) 45 | 46 | sim.set_m(init_m) 47 | 48 | sim.driver.do_precession = False 49 | sim.driver.alpha = 0.9 50 | 51 | sim.relax() 52 | 53 | # ---------------------------------------------------------------------------- 54 | # Plot the 2D system 55 | 56 | import matplotlib.pyplot as plt 57 | 58 | m = sim.spin.reshape(-1, 3) 59 | plt.figure(figsize=(8, 8)) 60 | plt.quiver(mesh.coordinates[:, 0], mesh.coordinates[:, 1], 61 | m[:, 0], m[:, 1], 62 | m[:, 2], cmap='RdYlBu' 63 | ) 64 | plt.show() 65 | -------------------------------------------------------------------------------- /docker/minimal-py2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | # packages we need to run fidimag 4 | RUN apt-get -y update 5 | RUN apt-get -y install python-numpy python-dev python-scipy 6 | RUN apt-get -y install python-pytest python-pyvtk ipython python-matplotlib mayavi2 7 | # standard tools for compilation 8 | RUN apt-get -y install wget make git 9 | 10 | # where to install source 11 | ENV FIDIMAG_HOME /home/fidimag 12 | 13 | RUN mkdir -p $FIDIMAG_HOME 14 | WORKDIR $FIDIMAG_HOME 15 | RUN git clone https://github.com/computationalmodelling/fidimag.git 16 | WORKDIR $FIDIMAG_HOME/fidimag/bin 17 | 18 | # install third party libraries from source 19 | RUN bash install-ubuntu-packages.sh 20 | RUN bash install-fftw.sh 21 | RUN bash install-sundials-2.5.sh 22 | 23 | # for pip 24 | RUN apt-get -y install python-pip 25 | # install cython 26 | RUN pip install cython --upgrade 27 | WORKDIR $FIDIMAG_HOME/fidimag 28 | 29 | # compile fidimag 30 | RUN make 31 | env PYTHONPATH=$FIDIMAG_HOME/fidimag 32 | env LD_LIBRARY_PATH=$FIDIMAG_HOME/fidimag/local/lib 33 | WORKDIR $FIDIMAG_HOME/fidimag/tests 34 | 35 | # check that tests run okay 36 | RUN py.test -v 37 | 38 | 39 | # install Jupyter, port exposing doesn't work yet 40 | #RUN pip install jupyter 41 | 42 | # expose jupyter port - not working yet 43 | #EXPOSE 8888 8888 44 | 45 | 46 | # Set up user so that we do not run as root 47 | RUN useradd -m -s /bin/bash -G sudo fidimag && \ 48 | echo "fidimag:docker" | chpasswd && \ 49 | echo "fidimag ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 50 | RUN chown -R fidimag $FIDIMAG_HOME 51 | 52 | # For bind mounts from host 53 | RUN mkdir /io 54 | RUN chown -R fidimag /io 55 | 56 | USER fidimag 57 | RUN touch $FIDIMAG_HOME/.sudo_as_admin_successful 58 | 59 | # Print something nice on entry. 60 | #COPY WELCOME $FIDIMAG_HOME/WELCOME 61 | 62 | 63 | WORKDIR /io 64 | CMD ["/bin/bash","-i"] 65 | -------------------------------------------------------------------------------- /examples/atomistic/heat/temperature.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pc import * 3 | 4 | import time 5 | 6 | import matplotlib as mpl 7 | mpl.use("Agg") 8 | import matplotlib.pyplot as plt 9 | 10 | 11 | def plot_mxyz(ts, mx, my, mz, me, name): 12 | fig = plt.figure() 13 | plt.plot(ts, mx, '^-', label='mx') 14 | plt.plot(ts, my, '.-', label='my') 15 | plt.plot(ts, mz, 'o-', label='mz') 16 | plt.plot(ts, me, '>-', label='me') 17 | plt.legend() 18 | fig.savefig(name) 19 | 20 | 21 | def temperature_test(T): 22 | ni = Nickel() 23 | ni.alpha = 0.1 24 | ni.D = 1.35e-26 25 | ni.mu_s = 2.16e-23 26 | ni.J = 6.16e-21 27 | 28 | (nx, ny, nz) = (24, 24, 24) 29 | 30 | mesh = CuboidMesh(nx=nx, ny=ny, nz=nz) 31 | 32 | sim = Sim(mesh, T=T, driver='sllg') 33 | sim.set_options(dt=1e-15, gamma=ni.gamma, k_B=ni.k_B) 34 | sim.mu_s = ni.mu_s 35 | 36 | exch = UniformExchange(ni.J) 37 | sim.add(exch) 38 | 39 | anis = Anisotropy(ni.D) 40 | sim.add(anis) 41 | 42 | # zeeman=Zeeman(1e2,(0,0,1)) 43 | # sim.add(zeeman) 44 | 45 | # demag=Demag(mu_s=ni.mu_s) 46 | # sim.add(demag) 47 | 48 | sim.set_m((0, 0.6, 0.99)) 49 | 50 | # vs=VisualSpin(sim) 51 | # vs.init() 52 | 53 | ts = np.linspace(0, 1e-11, 101) 54 | me = [] 55 | mx = [] 56 | my = [] 57 | mz = [] 58 | for t in ts: 59 | sim.run_until(t) 60 | # vs.update() 61 | av = sim.compute_average() 62 | mx.append(av[0]) 63 | my.append(av[1]) 64 | mz.append(av[2]) 65 | me.append(np.sqrt(np.sum(av * av))) 66 | # time.sleep(0.001) 67 | #print av, me[-1] 68 | sim.save_vtk() 69 | name = 'nx%d_ny%d_nz%d_T%g.png' % (nx, ny, nz, T) 70 | plot_mxyz(ts, mx, my, mz, me, name) 71 | 72 | 73 | if __name__ == '__main__': 74 | temperature_test(100) 75 | -------------------------------------------------------------------------------- /sandbox/more-dmi/test_dmi.mif: -------------------------------------------------------------------------------- 1 | # MIF 2.1 --------------------------------------------------------------------- 2 | 3 | # Generate an isolated skyrmion with bulk (T) DMI 4 | # 5 | # Authors: D. Cortes, M. Beg, H.Fangohr (2018) 6 | 7 | set PI [expr {4 * atan(1.)}] 8 | set MU0 [expr {4 * $PI * 1e-7}] 9 | 10 | # ----------------------------------------------------------------------------- 11 | # PdFe on Ir(111) [PRL, 114(17):1-5, 2015] 12 | set Ms [expr {1.1e6}] 13 | set A [expr {2e-12}] 14 | set D [expr {-3.9e-3}] 15 | set KU [expr {2.5e6}] 16 | set BZ [expr {1.0}] 17 | 18 | set XL [expr {15e-9}] 19 | set YL [expr {$XL}] 20 | set ZL [expr {$XL}] 21 | 22 | set xcell [expr {$XL / 2}] 23 | set ycell [expr {$YL / 2}] 24 | set zcell [expr {$XL / 2}] 25 | 26 | # ----------------------------------------------------------------------------- 27 | 28 | # BoxAtlas 29 | Specify Oxs_BoxAtlas:atlas [subst { 30 | xrange {0 $XL} 31 | yrange {0 $YL} 32 | zrange {0 $ZL} 33 | name atlas 34 | }] 35 | 36 | # RectangularMesh 37 | Specify Oxs_RectangularMesh:mesh [subst { 38 | cellsize {$xcell $ycell $zcell} 39 | atlas Oxs_BoxAtlas:atlas 40 | }] 41 | 42 | # T DMI 43 | Specify Oxs_DMI_T [subst { 44 | default_D $D 45 | atlas :atlas 46 | D { 47 | atlas atlas $D 48 | } 49 | }] 50 | 51 | 52 | # CGEvolver 53 | Specify Oxs_CGEvolve {} 54 | 55 | # MinDriver 56 | Specify Oxs_MinDriver [subst { 57 | evolver Oxs_CGEvolve 58 | stopping_mxHxm 0.01 59 | mesh :mesh 60 | Ms $Ms 61 | m0 { 0 0 1 } 62 | basename isolated_sk_T 63 | scalar_field_output_format {text %\#.15g} 64 | vector_field_output_format {text %\#.15g} 65 | }] 66 | 67 | Destination table mmArchive 68 | Destination mags mmArchive 69 | Schedule DataTable table Stage 1 70 | Schedule Oxs_MinDriver::Magnetization mags Stage 1 71 | 72 | 73 | # ============================================================================= 74 | 75 | -------------------------------------------------------------------------------- /examples/eigen/skx.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | 4 | import numpy as np 5 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman, TimeZeeman 6 | from fidimag.common import DataReader, CuboidMesh 7 | 8 | from fidimag.atomistic.eigen import EigenProblem 9 | 10 | import matplotlib.pyplot as plt 11 | 12 | def init_m(pos): 13 | x,y,z = pos 14 | 15 | Rx, Ry, r = 87, 50, 12 16 | 17 | x = x%Rx + 20 18 | y = y%Ry 19 | 20 | m1 = (0.05,0.01,-1) 21 | m2 = (0,0,1) 22 | 23 | if x**2 + y**2 < r**2: 24 | return m1 25 | elif x**2 + (y-Ry)**2 < r**2: 26 | return m1 27 | elif (x-Rx)**2 + y**2 < r**2: 28 | return m1 29 | elif (x-Rx)**2 + (y-Ry)**2 < r**2: 30 | return m1 31 | elif (x-Rx/2.0)**2 + (y-Ry/2.0)**2 < r**2: 32 | return m1 33 | else: 34 | return m2 35 | 36 | 37 | def relax_system(mesh): 38 | 39 | sim=Sim(mesh,name='relax') 40 | sim.set_options(rtol=1e-12,atol=1e-14) 41 | sim.do_precession = False 42 | sim.driver.alpha = 0.5 43 | sim.driver.gamma = 1.0 44 | sim.mu_s = 1.0 45 | 46 | sim.set_m(init_m) 47 | 48 | J = 1.0 49 | exch = UniformExchange(J) 50 | sim.add(exch) 51 | 52 | D = 0.18 53 | dmi = DMI(D) 54 | sim.add(dmi) 55 | 56 | zeeman = Zeeman([0,0e-3,2e-2],name='H') 57 | sim.add(zeeman) 58 | 59 | sim.relax(dt=2.0, stopping_dmdt=1e-8, max_steps=10000, save_m_steps=None, save_vtk_steps=100) 60 | 61 | np.save('m0.npy',sim.spin) 62 | 63 | 64 | def eigen(mesh): 65 | m0 = np.load('m0.npy') 66 | ep = EigenProblem(mesh, m0, H=[0,0,2e-2], J=1.0, D=0.18) 67 | ep.solve_sparse() 68 | 69 | 70 | if __name__=='__main__': 71 | 72 | #mesh = CuboidMesh(nx=174,ny=150, nz=1, pbc='2d') 73 | mesh = CuboidMesh(nx=87,ny=100, nz=1, pbc='2d') 74 | 75 | relax_system(mesh) 76 | 77 | eigen(mesh) 78 | -------------------------------------------------------------------------------- /fidimag/atomistic/demag_full.py: -------------------------------------------------------------------------------- 1 | import fidimag.extensions.clib as clib 2 | import numpy as np 3 | from .energy import Energy 4 | 5 | 6 | class DemagFull(Energy): 7 | """ 8 | Calculation of the demag field using a brute-force approach, 9 | summing the dipolar contributions of the whole system for 10 | every lattice point. 11 | Since we can obtain the field directly, the energy is calculated 12 | in this process, thus we inherit from the Energy class 13 | as in the Exchange field, to calculate the total energy summing up 14 | the energy density. 15 | """ 16 | 17 | def __init__(self, name='DemagFull'): 18 | self.name = name 19 | self.jac = True 20 | 21 | def setup(self, mesh, spin, mu_s, mu_s_inv): 22 | super(DemagFull, self).setup(mesh, spin, mu_s, mu_s_inv) 23 | 24 | unit_length = mesh.unit_length 25 | self.mu_s_scale = np.zeros(mesh.n, dtype=np.float64) 26 | 27 | # note that the 1e-7 comes from \frac{\mu_0}{4\pi} 28 | self.scale = 1e-7 / (unit_length ** 3) 29 | 30 | # could be wrong, needs carefully tests!!! 31 | self.mu_s_scale = self.mu_s * self.scale 32 | 33 | def compute_field(self, t=0, spin=None): 34 | if spin is not None: 35 | m = spin 36 | else: 37 | m = self.spin 38 | 39 | clib.compute_demag_full(m, self.field, 40 | self.energy, 41 | self.mesh.coordinates, 42 | self.mu_s, 43 | self.mu_s_scale, 44 | self.n 45 | ) 46 | 47 | return self.field 48 | 49 | # def compute_energy(self): 50 | # energy = self.demag.compute_energy( 51 | # self.spin, self.mu_s_scale, self.field) 52 | # return energy / self.scale 53 | -------------------------------------------------------------------------------- /examples/atomistic/demag_field/demag_field.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.atomistic import Sim, Demag 7 | from fidimag.common import CuboidMesh 8 | import fidimag.common.constant as const 9 | from fidimag.common.save_vtk import SaveVTK 10 | 11 | 12 | def mu_s(pos): 13 | x, y, z = pos 14 | x0, y0, r = 60 * 0.5, 60 * 0.5, 30 * 0.5 15 | 16 | if (x - x0)**2 + (y - y0)**2 <= r**2: 17 | return const.mu_s_1 18 | else: 19 | return 0 20 | 21 | 22 | def init_m(pos): 23 | x, y, z = pos 24 | 25 | return (0, 0, 1) 26 | 27 | 28 | def random_m(pos): 29 | return np.random.random(3) - 0.5 30 | 31 | 32 | def plot_f(mesh, field, mu_s_inv): 33 | fig = plt.figure(figsize=(6, 4)) 34 | 35 | field.shape = (3, -1) 36 | 37 | xs = range(121) 38 | fz = [] 39 | for i in xs: 40 | j = mesh.index(i, 60, 0) 41 | if mu_s_inv[j] > 0: 42 | fz.append(0) 43 | else: 44 | fz.append(field[2][j]) 45 | 46 | plt.plot(xs, fz) 47 | plt.savefig('f.pdf') 48 | 49 | 50 | def relax_system(): 51 | 52 | mesh = CuboidMesh(nx=121, ny=121, nz=1, dx=0.5, dy=0.5, unit_length=1e-9) 53 | 54 | sim = Sim(mesh, name='relax_skx') 55 | 56 | sim.driver.gamma = const.gamma 57 | #sim.set_default_options(gamma=const.gamma) 58 | 59 | sim.driver.alpha = 1.0 60 | 61 | sim.mu_s = mu_s 62 | 63 | sim.set_m(init_m) 64 | 65 | demag = Demag() 66 | 67 | sim.add(demag) 68 | 69 | field = demag.compute_field() 70 | 71 | print(field) 72 | 73 | #vtk = SaveVTK(mesh, name='demag') 74 | #vtk.save_vtk(field) 75 | 76 | #sim.save_vtk() 77 | 78 | plot_f(mesh, field, sim._mu_s_inv) 79 | 80 | # np.save('m0.npy',sim.spin) 81 | 82 | 83 | if __name__ == '__main__': 84 | 85 | np.random.seed(3) 86 | 87 | relax_system() 88 | -------------------------------------------------------------------------------- /examples/micromagnetic/vortex_oommf/relax.mif: -------------------------------------------------------------------------------- 1 | # MIF 2.1 2 | 3 | set pi [expr 4*atan(1.0)] 4 | set mu0 [expr 4*$pi*1e-7] 5 | 6 | RandomSeed 1 7 | 8 | Parameter cellsize_x 2.5e-9 9 | Parameter cellsize_y 2.5e-9 10 | Parameter cellsize_z 5e-9 11 | 12 | 13 | Specify Oxs_MultiAtlas:atlas { 14 | atlas { Oxs_BoxAtlas:left { 15 | xrange {0 200e-9} 16 | yrange {0 200e-9} 17 | zrange {0 20e-9} 18 | } } 19 | } 20 | 21 | 22 | Specify Oxs_RectangularMesh:mesh [subst { 23 | cellsize {$cellsize_x $cellsize_y $cellsize_z} 24 | atlas :atlas 25 | }] 26 | 27 | 28 | Specify Oxs_UniformExchange { 29 | A 1.3e-11 30 | } 31 | 32 | Specify Oxs_Demag {} 33 | 34 | Specify Oxs_RungeKuttaEvolve:evolve { 35 | alpha 1.0 36 | } 37 | 38 | Specify Oxs_TimeDriver [subst { 39 | basename ./plus 40 | evolver :evolve 41 | stopping_dm_dt 0.05 42 | mesh :mesh 43 | 44 | Ms { Oxs_ScriptScalarField { 45 | atlas :atlas 46 | script_args {rawpt} 47 | script {plus 8.6e5} 48 | } } 49 | 50 | m0 { Oxs_ScriptVectorField { 51 | atlas :atlas 52 | script_args {rawpt} 53 | script init_m0 54 | norm 1 55 | } } 56 | 57 | }] 58 | 59 | 60 | proc plus { Ms x y z } { 61 | 62 | set r 100e-9 63 | 64 | if { ($x-100e-9)*($x-100e-9) + ($y-100e-9)*($y-100e-9) > $r*$r} { 65 | return 0 66 | } 67 | 68 | return $Ms 69 | } 70 | 71 | 72 | proc init_m0 { x y z} { 73 | if { $x < $y } { 74 | if { $x + $y < 200e-9 } { 75 | return "0 -1 0" 76 | } else { 77 | return "-1 0 0" 78 | } 79 | 80 | } else { 81 | if { $x + $y < 200e-9 } { 82 | return "1 0 0" 83 | } else { 84 | return "0 1 0" 85 | } 86 | } 87 | 88 | } 89 | 90 | Destination archive mmArchive 91 | 92 | Schedule DataTable archive Step 20 93 | Schedule DataTable archive Stage 1 94 | Schedule Oxs_TimeDriver::Magnetization archive Stage 1 95 | Schedule Oxs_TimeDriver::Magnetization archive Step 50 96 | -------------------------------------------------------------------------------- /examples/micromagnetic/vortex_oommf/dyn/dyn.mif: -------------------------------------------------------------------------------- 1 | # MIF 2.1 2 | 3 | set pi [expr 4*atan(1.0)] 4 | set mu0 [expr 4*$pi*1e-7] 5 | 6 | RandomSeed 1 7 | 8 | Parameter cellsize_x 2.5e-9 9 | Parameter cellsize_y 2.5e-9 10 | Parameter cellsize_z 5e-9 11 | 12 | 13 | Specify Oxs_MultiAtlas:atlas { 14 | atlas { Oxs_BoxAtlas:left { 15 | xrange {0 200e-9} 16 | yrange {0 200e-9} 17 | zrange {0 20e-9} 18 | } } 19 | } 20 | 21 | 22 | Specify Oxs_RectangularMesh:mesh [subst { 23 | cellsize {$cellsize_x $cellsize_y $cellsize_z} 24 | atlas :atlas 25 | }] 26 | 27 | 28 | Specify Oxs_UniformExchange { 29 | A 1.3e-11 30 | } 31 | 32 | Specify Oxs_Demag {} 33 | 34 | Specify Oxs_RungeKuttaEvolve:evolve { 35 | alpha 0.01 36 | } 37 | 38 | Specify Oxs_TimeDriver [subst { 39 | basename ./dyn 40 | evolver :evolve 41 | stopping_time 2e-12 42 | stage_count 1000 43 | mesh :mesh 44 | 45 | Ms { Oxs_ScriptScalarField { 46 | atlas :atlas 47 | script_args {rawpt} 48 | script {plus 8.6e5} 49 | } } 50 | 51 | m0 { Oxs_FileVectorField { 52 | atlas :atlas 53 | norm 1 54 | file ../plus-Oxs_TimeDriver-Magnetization-00-0001827.omf 55 | } } 56 | 57 | }] 58 | 59 | 60 | proc plus { Ms x y z } { 61 | 62 | set r 100e-9 63 | 64 | if { ($x-100e-9)*($x-100e-9) + ($y-100e-9)*($y-100e-9) > $r*$r} { 65 | return 0 66 | } 67 | 68 | return $Ms 69 | } 70 | 71 | Specify Oxs_ScriptUZeeman { 72 | script_args total_time 73 | script ExpField 74 | } 75 | 76 | proc ExpField { total_time } { 77 | set Hx [expr {79577*exp(-0.5*($total_time/0.1e-9)*($total_time/0.1e-9))}] 78 | set dHx [expr {-$Hx*$total_time/(0.1e-9)/(0.1e-9)}] 79 | return [list $Hx 0 0 $dHx 0 0] 80 | } 81 | 82 | Destination archive mmArchive 83 | 84 | #Schedule DataTable archive Step 20 85 | Schedule DataTable archive Stage 1 86 | #Schedule Oxs_TimeDriver::Magnetization archive Stage 1 87 | #Schedule Oxs_TimeDriver::Magnetization archive Step 50 88 | -------------------------------------------------------------------------------- /examples/atomistic/sw.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pccp.pc import * 3 | import time 4 | 5 | 6 | def init_m(pos): 7 | x, y, z = pos 8 | if x < 10: 9 | return (1, 0, 0) 10 | elif x > 10: 11 | return (-1, 0, 0) 12 | else: 13 | return (0, 1, 0) 14 | 15 | 16 | def pin_fun(t, mesh, spin): 17 | n = mesh.nxyz 18 | h0 = 0.1 19 | omega = 3 20 | 21 | t1 = h0 * np.cos(omega * t) 22 | t2 = h0 * np.sin(omega * t) 23 | t0 = np.sqrt(1 - t1 * t1 - t2 * t2) 24 | 25 | if t >= 1000 and t < 500: 26 | t0 = 1 27 | t1 = 0 28 | t2 = 0 29 | 30 | spin[0] = t0 31 | spin[n] = t1 32 | spin[n + n] = t2 33 | 34 | 35 | def relax_system(mesh): 36 | sim = Sim(mesh, name='relax') 37 | sim.driver.alpha = 0.5 38 | sim.driver.gamma = 5 39 | sim.c = 2 40 | 41 | exch = UniformExchange(1) 42 | sim.add(exch) 43 | 44 | anis = Anisotropy(0.3) 45 | sim.add(anis) 46 | 47 | sim.set_m(init_m) 48 | 49 | ts = np.linspace(0, 50, 101) 50 | for t in ts: 51 | sim.run_until(t) 52 | 53 | # sim.save_vtk() 54 | return sim.spin 55 | 56 | 57 | def spin_wave(mesh, m0, H0=10): 58 | sim = Sim(mesh, name='sw') 59 | sim.driver.alpha = 0.01 60 | sim.driver.gamma = 5 61 | sim.c = 2 62 | sim.pin_fun = pin_fun 63 | 64 | exch = UniformExchange(1) 65 | sim.add(exch) 66 | 67 | anis = Anisotropy(0.3) 68 | sim.add(anis) 69 | 70 | # zeeman=Zeeman(H0,(-1,0,0)) 71 | # sim.add(zeeman) 72 | 73 | sim.set_m(m0) 74 | # vs=VisualSpin(sim) 75 | # vs.init() 76 | 77 | ts = np.linspace(0, 500, 501) 78 | for t in ts: 79 | sim.run_until(t) 80 | sim.save_vtk() 81 | # vs.update() 82 | # time.sleep(0.001) 83 | 84 | 85 | if __name__ == '__main__': 86 | 87 | mesh = CuboidMesh(nx=20) 88 | 89 | m0 = relax_system(mesh) 90 | print 'relax system done' 91 | # spin_wave(mesh,m0) 92 | -------------------------------------------------------------------------------- /fidimag/common/neb_method/nebm_integrators.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "nebm_lib.h" 3 | #include 4 | #include 5 | 6 | double step_Verlet_C(double *restrict forces, 7 | double *restrict forces_prev, 8 | double *restrict velocities, 9 | double *restrict velocities_new, 10 | double *restrict y, 11 | double t, 12 | double h, 13 | double mass, 14 | int n_images, 15 | int n_dofs_image, 16 | double (*update_field)(double, double *) 17 | 18 | ) { 19 | 20 | printf("Hellooooooo\n"); 21 | 22 | update_field(t, y); 23 | 24 | int im_idx; 25 | for (int i = 1; i < n_images - 1; i++) { 26 | 27 | im_idx = n_dofs_image * i; 28 | double *force = &forces[im_idx]; 29 | double *force_prev = &forces_prev[im_idx]; 30 | double *velocity = &velocities[im_idx]; 31 | double *velocity_new = &velocities_new[im_idx]; 32 | 33 | double v_dot_f = 0; 34 | double f_dot_f = 0; 35 | 36 | for (int j = 0; i < n_dofs_image; j++) { 37 | y[im_idx + j] += h * (velocity[j] + (h / (2 * mass)) * force[j]); 38 | 39 | velocity[j] = velocity_new[j] + (h / (2 * mass)) * (force_prev[j] + force[j]); 40 | 41 | v_dot_f += velocity[j] * force[j]; 42 | f_dot_f += force[j] * force[j]; 43 | 44 | force_prev[j] = force[j]; 45 | } 46 | 47 | if (v_dot_f <= 0) { 48 | for (int j = 0; i < n_dofs_image; j++) { 49 | velocity_new[j] = 0.0; 50 | } 51 | } else { 52 | for (int j = 0; i < n_dofs_image; j++) { 53 | velocity_new[j] = v_dot_f * force[j] / f_dot_f; 54 | } 55 | } 56 | } 57 | 58 | normalise_spins_C(y, n_images, n_dofs_image); 59 | 60 | return t + h; 61 | } 62 | -------------------------------------------------------------------------------- /examples/micromagnetic/skyrmion_stt/main.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.micro import Sim 3 | from fidimag.common import CuboidMesh 4 | from fidimag.micro import UniformExchange, DMI, Zeeman 5 | 6 | mu0 = 4 * np.pi * 1e-7 7 | 8 | 9 | def init_m(pos): 10 | 11 | x, y = pos[0] - 100, pos[1] - 100 12 | 13 | if x**2 + y**2 > 20**2: 14 | return (0, 0, 1) 15 | else: 16 | return (0, 0, -1) 17 | 18 | 19 | def relax_system(mesh): 20 | 21 | sim = Sim(mesh, name='relax') 22 | 23 | sim.driver.set_tols(rtol=1e-6, atol=1e-6) 24 | sim.driver.alpha = 0.5 25 | sim.driver.gamma = 2.211e5 26 | sim.Ms = 8.6e5 27 | sim.do_precession = False 28 | 29 | sim.set_m(init_m) 30 | 31 | exch = UniformExchange(A=1.3e-11) 32 | sim.add(exch) 33 | 34 | dmi = DMI(D=-4e-3) 35 | sim.add(dmi) 36 | 37 | zeeman = Zeeman((0, 0, 4e5)) 38 | sim.add(zeeman, save_field=True) 39 | 40 | sim.relax(dt=1e-13, stopping_dmdt=1e-2, 41 | save_m_steps=None, save_vtk_steps=50) 42 | 43 | np.save('m0.npy', sim.spin) 44 | 45 | 46 | def excite_system(mesh): 47 | sim = Sim(mesh, name='dyn', driver='llg_stt') 48 | sim.driver.set_tols(rtol=1e-8, atol=1e-10) 49 | sim.driver.alpha = 0.5 50 | sim.driver.gamma = 2.211e5 51 | sim.Ms = 8.6e5 52 | 53 | sim.set_m(np.load('m0.npy')) 54 | 55 | exch = UniformExchange(A=1.3e-11) 56 | sim.add(exch) 57 | dmi = DMI(D=-4e-3) 58 | sim.add(dmi) 59 | zeeman = Zeeman((0, 0, 4e5)) 60 | sim.add(zeeman, save_field=True) 61 | 62 | sim.jx = -5e12 63 | sim.beta = 0 64 | 65 | ts = np.linspace(0, 0.5e-9, 101) 66 | for t in ts: 67 | print('time', t) 68 | sim.run_until(t) 69 | sim.save_vtk() 70 | #sim.save_m() 71 | 72 | if __name__ == '__main__': 73 | 74 | mesh = CuboidMesh(nx=101, ny=101, nz=1, dx=2.0, dy=2.0, dz=2.0, unit_length=1e-9, periodicity=(True, True, False)) 75 | 76 | relax_system(mesh) 77 | 78 | excite_system(mesh) 79 | -------------------------------------------------------------------------------- /examples/nebm_atomistic/1D_spin_chain/relaxation/1D_spin_chain_fm.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | from fidimag.atomistic import Sim 4 | from fidimag.common import CuboidMesh 5 | from fidimag.atomistic import DMI 6 | from fidimag.atomistic import UniformExchange 7 | from fidimag.atomistic import Zeeman 8 | from fidimag.atomistic import Anisotropy 9 | import fidimag.common.constant as const 10 | 11 | # Number of spins and lattice spacing (see mesh) 12 | nx = 50 13 | dx = 0.27 14 | 15 | sim_name = 'relax_spin_chain_fm' 16 | 17 | 18 | def relax_system(): 19 | 20 | # 1D chain of 50 spins with a lattice constant of 0.27 A 21 | mesh = CuboidMesh(nx=nx, 22 | dx=dx, 23 | unit_length=1e-9, 24 | # pbc='1d' 25 | ) 26 | 27 | # Initiate the simulation. PBCs are specified in the mesh 28 | sim = Sim(mesh, name=sim_name) 29 | sim.driver.gamma = const.gamma 30 | 31 | # magnetisation in units of Bohr's magneton 32 | sim.mu_s = 2. * const.mu_B 33 | 34 | # sim.set_options(gamma=const.gamma, k_B=const.k_B) 35 | 36 | # Initial magnetisation profile 37 | sim.set_m((0, 0, 1)) 38 | 39 | # Exchange constant in Joules: E = Sum J_{ij} S_i S_j 40 | J = 12. * const.meV 41 | exch = UniformExchange(J) 42 | sim.add(exch) 43 | 44 | # DMI constant in Joules: E = Sum D_{ij} S_i x S_j 45 | D = 2. * const.meV 46 | dmi = DMI(D, dmi_type='interfacial') 47 | sim.add(dmi) 48 | 49 | # Anisotropy along +z axis 50 | ku = Anisotropy(Ku=0.5 * const.meV, 51 | axis=[0, 0, 1], 52 | name='ku') 53 | sim.add(ku) 54 | 55 | # Faster convergence 56 | sim.driver.alpha = 0.5 57 | sim.do_precession = False 58 | 59 | sim.relax(dt=1e-13, stopping_dmdt=0.05, 60 | max_steps=700, 61 | save_m_steps=1000, save_vtk_steps=1000) 62 | 63 | # Save the last relaxed state 64 | np.save(sim_name + '.npy', sim.spin) 65 | 66 | 67 | relax_system() 68 | -------------------------------------------------------------------------------- /fidimag/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import platform 4 | 5 | try: 6 | from . import extensions 7 | from . import atomistic 8 | from . import micro 9 | from . import common 10 | citation = common.citation 11 | except ImportError as e: 12 | # cwd = os.getcwd() 13 | FIDIMAG_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 14 | # os.chdir(FIDIMAG_DIR) 15 | message = """ 16 | Could not load the Fidimag extensions. This could be due to a few things: 17 | 1) The extensions are not built. Try running 'make' from the root directory. 18 | 19 | 2) FIDIMAG loads comon libraries dynamically. Currently, FIDIMAG requires 20 | * Sundials 6.6.1 21 | * FFTW 3.3.8 22 | If you are using Linux, you may be able to download these through a 23 | package manager such as apt or yum. However, convenience scripts 24 | are provided in the folder bin to install these locally for Ubuntu. 25 | 26 | 3) If you've run the scripts to install the dynamic libaries, 27 | you may still need to export the LD_LIBRARY_PATH environment 28 | variable. You can do this from the shell with: 29 | export LD_LIBRARY_PATH={}/local/lib:$LD_LIBRARY_PATH 30 | 31 | 4) If after trying *all* of the above, you still can't get Fidimag to install, 32 | please create an issue on the following website: 33 | 34 | https://github.com/computationalmodelling/fidimag/issues 35 | 36 | Copy and paste *all* of the information below which will help 37 | us to diagnose your problem: 38 | 39 | 40 | Exception Error message 41 | ----------------------- 42 | {} 43 | 44 | System Info 45 | ----------------------- 46 | Architecture: {} 47 | Platform: {} 48 | Processor: {} 49 | """ 50 | print(message.format(FIDIMAG_DIR, e, platform.machine(), platform.platform(), platform.processor())) 51 | 52 | 53 | __version__ = '3.0' 54 | -------------------------------------------------------------------------------- /fidimag/micro/lib/micro_clib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #define WIDE_PI 3.1415926535897932384626433832795L 6 | #define MU0 1.25663706143591728850e-6 7 | #define MU0_INV 795774.71545947669074 8 | 9 | inline double cross_x(double a0, double a1, double a2, 10 | double b0, double b1, double b2) { return a1 * b2 - a2 * b1; } 11 | inline double cross_y(double a0, double a1, double a2, 12 | double b0, double b1, double b2) { return a2 * b0 - a0 * b2; } 13 | inline double cross_z(double a0, double a1, double a2, 14 | double b0, double b1, double b2) { return a0 * b1 - a1 * b0; } 15 | 16 | void compute_exch_field_micro(double *restrict m, double *restrict field, double *restrict energy, double *restrict Ms_inv, 17 | double A, double dx, double dy, double dz, int n, int *ngbs); 18 | 19 | void dmi_field(double *restrict m, double *restrict field, 20 | double *restrict energy, double *restrict Ms_inv, 21 | double *restrict D, int n_DMIs, 22 | double *dmi_vector, 23 | double dx, double dy, double dz, int n, int *ngbs); 24 | 25 | void compute_exch_field_rkky_micro(double *m, double *field, double *energy, double *Ms_inv, 26 | double sigma, int nx, double ny, double nz, int z_bottom, int z_top); 27 | 28 | void compute_uniaxial_anis(double *restrict m, double *restrict field, double *restrict energy, double *restrict Ms_inv, 29 | double *restrict Ku, double *restrict axis, int nx, int ny, int nz); 30 | 31 | void compute_uniaxial4_anis(double *restrict m, double *restrict field, double *restrict energy, double *restrict Ms_inv, 32 | double *restrict K1, double *restrict K2, double *restrict axis, int nx, int ny, int nz); 33 | 34 | double skyrmion_number(double *restrict spin, double *restrict charge, 35 | int nx, int ny, int nz, int *restrict ngbs); 36 | -------------------------------------------------------------------------------- /docker/minimal-py3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | # packages we need to run fidimag 4 | RUN apt-get -y update 5 | RUN apt-get -y install python3-numpy python3-dev python3-scipy cmake 6 | RUN apt-get -y install python3-pytest ipython3 python3-matplotlib python3-pip 7 | # standard tools for compilation 8 | RUN apt-get -y install wget make git 9 | 10 | # where to install source 11 | ENV FIDIMAG_HOME /home/fidimag 12 | 13 | RUN mkdir -p $FIDIMAG_HOME 14 | WORKDIR $FIDIMAG_HOME 15 | RUN git clone https://github.com/computationalmodelling/fidimag.git 16 | WORKDIR $FIDIMAG_HOME/fidimag/bin 17 | 18 | # install third party libraries from source 19 | RUN bash install-fftw.sh 20 | RUN bash install-sundials.sh 21 | 22 | # for pip 23 | RUN python3 -m pip install --user --upgrade setuptools pip 24 | # install pyvtk 25 | RUN python3 -m pip install pyvtk 26 | # install cython 27 | RUN python3 -m pip install cython --upgrade 28 | WORKDIR $FIDIMAG_HOME/fidimag 29 | RUN apt-get -y install libatlas-base-dev libatlas3-base libatlas3gf-base 30 | # compile fidimag 31 | RUN python3 setup.py build_ext --inplace 32 | env PYTHONPATH=$FIDIMAG_HOME/fidimag 33 | env LD_LIBRARY_PATH=$FIDIMAG_HOME/fidimag/local/lib 34 | WORKDIR $FIDIMAG_HOME/fidimag/tests 35 | 36 | # check that tests run okay 37 | RUN py.test-3 -v 38 | 39 | 40 | # install Jupyter, port exposing doesn't work yet 41 | #RUN pip install jupyter 42 | 43 | # expose jupyter port - not working yet 44 | #EXPOSE 8888 8888 45 | 46 | 47 | # Set up user so that we do not run as root 48 | RUN useradd -m -s /bin/bash -G sudo fidimag && \ 49 | echo "fidimag:docker" | chpasswd && \ 50 | echo "fidimag ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 51 | RUN chown -R fidimag $FIDIMAG_HOME 52 | 53 | # For bind mounts from host 54 | RUN mkdir /io 55 | RUN chown -R fidimag /io 56 | 57 | USER fidimag 58 | RUN touch $FIDIMAG_HOME/.sudo_as_admin_successful 59 | 60 | RUN cd fidimag 61 | RUN py.test -v 62 | # Print something nice on entry. 63 | #COPY WELCOME $FIDIMAG_HOME/WELCOME 64 | 65 | WORKDIR /io 66 | CMD ["/bin/bash","-i"] 67 | -------------------------------------------------------------------------------- /examples/neb_micromagnetic/domain_wall/dw.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import numpy as np 6 | from fidimag.micro import Sim, UniformExchange, Demag, UniaxialAnisotropy 7 | from fidimag.common import CuboidMesh 8 | from fidimag.common.nebm_cartesian import NEBM_Cartesian 9 | # TODO: FIX the plotting functions 10 | # from fidimag.common.helper import plot_energy_2d, plot_energy_3d 11 | #from finmag.sim.neb import plot_energy_2d, plot_energy_3d 12 | 13 | 14 | def init_dw(pos): 15 | x = pos[0] 16 | 17 | if x < 200: 18 | return (-1, 0, 0) 19 | elif x > 300: 20 | return (1, 0, 0) 21 | else: 22 | return (0, 1, 0) 23 | 24 | 25 | def create_simulation(mesh): 26 | 27 | sim = Sim(mesh) 28 | sim.Ms = 8.6e5 29 | 30 | sim.set_m((1, 0, 0)) 31 | sim.add(UniformExchange(A=1.3e-11)) 32 | # sim.add(Demag()) 33 | #sim.add(UniaxialAnisotropy(Kx, (1, 0, 0), name='Kx')) 34 | anis = UniaxialAnisotropy(1e5, axis=(1, 0, 0)) 35 | sim.add(anis) 36 | 37 | return sim 38 | 39 | 40 | def relax_system(sim): 41 | 42 | # init_images=[np.load('m_init.npy')] 43 | """ 44 | n=20 45 | for i in range(1,n): 46 | theta = i*np.pi/n 47 | mx = -np.cos(theta) 48 | my = np.sin(theta) 49 | init_images.append((mx,my,0)) 50 | """ 51 | 52 | # init_images.append(np.load('m_final.npy')) 53 | 54 | init_images = [(-1, 0, 0), init_dw, (1, 0, 0)] 55 | 56 | neb = NEBM_Cartesian( 57 | sim, init_images, interpolations=[6, 6], name='neb', 58 | spring_constant=1e8) 59 | 60 | # neb.add_noise(0.1) 61 | 62 | neb.relax(dt=1e-8, max_iterations=5000, save_vtks_every=500, 63 | save_npys_every=500, stopping_dYdt=100) 64 | 65 | if __name__ == "__main__": 66 | 67 | mesh = CuboidMesh(nx=160, ny=1, nz=1, dx=4.0, dy=4.0, dz=4.0, unit_length=1e-9) 68 | 69 | sim = create_simulation(mesh) 70 | # relax_two_state(mesh) 71 | relax_system(sim) 72 | # plot_energy_2d('neb') 73 | # plot_energy_3d('neb') 74 | -------------------------------------------------------------------------------- /fidimag/common/vtk.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pyvtk 3 | from fidimag.common import CuboidMesh 4 | from fidimag.atomistic.hexagonal_mesh import HexagonalMesh 5 | import sys 6 | 7 | log = pyvtk.logging.getLogger(pyvtk.__name__) 8 | log.setLevel(pyvtk.logging.ERROR) 9 | 10 | 11 | class VTK(object): 12 | def __init__(self, mesh, header="", directory=".", filename="unnamed"): 13 | self.mesh = mesh 14 | self.directory = directory 15 | self.filename = filename 16 | 17 | if isinstance(mesh, HexagonalMesh): 18 | structure = pyvtk.PolyData(points=mesh.vertices, 19 | polygons=mesh.hexagons) 20 | elif isinstance(mesh, CuboidMesh): 21 | # for keyword argument dimensions: if the mesh is made up of 22 | # nx * ny * nz cells, it has (nx + 1) * (ny + 1) * (nz + 1) 23 | # vertices. 24 | structure = pyvtk.RectilinearGrid(* mesh.grid) 25 | else: 26 | raise NotImplementedError( 27 | "Mesh should be CuboidMesh or HexagonalMesh, is {}.".format( 28 | mesh.__class__.__name__)) 29 | self.structure = structure 30 | self.header = header 31 | 32 | self.init_VtkData(structure, header) 33 | 34 | def init_VtkData(self, structure, header): 35 | self.vtk_data = pyvtk.VtkData(structure, header) 36 | 37 | def reset_data(self): 38 | self.vtk_data = pyvtk.VtkData(self.structure, self.header) 39 | 40 | def save_scalar(self, s, name="my_field", step=0): 41 | self.vtk_data.cell_data.append(pyvtk.Scalars(s, name)) 42 | 43 | def save_vector(self, v, name="my_field", step=0): 44 | self.vtk_data.cell_data.append(pyvtk.Vectors(v, name)) 45 | 46 | def write_file(self, step=0): 47 | if not os.path.isdir(self.directory): 48 | os.makedirs(self.directory) 49 | 50 | filename = "{}_{:06}".format(self.filename, step) + ".vtk" 51 | path = os.path.join(self.directory, filename) 52 | self.vtk_data.tofile(path) 53 | return path 54 | -------------------------------------------------------------------------------- /bin/install-sundials.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # This script installs any SUNDIALS version starting with version 2.6.0 5 | # when SUNDIALS moved to a CMake-based installation. Will install locally. 6 | # It may need environment variables to work, like `export CC=gcc` in ARCHER. 7 | 8 | # Github release from Sundials repository 9 | # https://github.com/LLNL/sundials 10 | SUNDIALS_TAG=v6.6.1 11 | SUNDIALS=sundials-6.6.1 12 | 13 | # Make sure CMake is installed, since SUNDIALS requires it. 14 | type cmake >/dev/null 2>&1 || { printf "CMake required to build SUNDIALS. You can install it by typing: \nsudo apt install cmake\n"; exit 1;} 15 | 16 | 17 | HERE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 18 | FIDIMAG_DIR="$(dirname "$HERE_DIR")" 19 | 20 | if [ -z $LIBS_DIR ]; then LIBS_DIR=${FIDIMAG_DIR}/local; fi 21 | 22 | echo "Will install SUNDIALS to "${LIBS_DIR}" using CC="${CC}"." 23 | mkdir -p ${LIBS_DIR} 24 | cd ${LIBS_DIR} 25 | 26 | download_and_cmake_install() { 27 | # $1 tag of the package 28 | # $2 name of the package 29 | # $3 URL where ${1}.tar.gz can be obtained 30 | # $4 configure options 31 | if [ ! -e ${1}/${2}.tar.gz ]; then 32 | echo "Downloading "${3}/${1}/${2}.tar.gz"." 33 | wget -q -O ${2}.tar.gz ${3}/${1}/${2}.tar.gz 34 | fi; 35 | 36 | if [ ! -e ${2} ]; then 37 | tar -xzf ${2}.tar.gz 38 | 39 | echo "Configuring "${2}"." 40 | mkdir ${2}_build 41 | cd ${2}_build 42 | cmake ${4} ../${2} 43 | 44 | echo "Compiling and installing "${2}"." 45 | { 46 | make -j2 47 | make install 48 | } > /dev/null 49 | 50 | echo "Cleaning up." 51 | cd .. 52 | rm -rf ${2} 53 | rm -rf ${2}_build 54 | 55 | cd ${HERE_DIR} 56 | echo "Done." 57 | fi; 58 | } 59 | 60 | download_and_cmake_install \ 61 | ${SUNDIALS_TAG} \ 62 | ${SUNDIALS} \ 63 | https://github.com/LLNL/sundials/releases/download \ 64 | "-DBUILD_STATIC_LIBS=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="${LIBS_DIR}" -DEXAMPLES_ENABLE=OFF -DENABLE_LAPACK=ON -DENABLE_OPENMP=ON" 65 | -------------------------------------------------------------------------------- /tests/test_monte_carlo.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | 5 | import fidimag.extensions.clib as clib 6 | import numpy as np 7 | from fidimag.atomistic import MonteCarlo, HexagonalMesh 8 | import fidimag.common.constant as const 9 | 10 | def test_random_sphere(do_plot=False): 11 | """ 12 | test whether spins are uniformly distributed on the surface of a sphere. 13 | """ 14 | mt19937 = clib.rng_mt19937() 15 | mt19937.set_seed(123) 16 | spin = np.zeros(3 * 10000, dtype=np.float64) 17 | mt19937.fill_vector_uniform_sphere(spin, 10000) 18 | spin.shape = (-1,3) 19 | n = spin.shape[0] 20 | x = np.average([spin[i,0] for i in range(n) if spin[i,0]>0]) 21 | y = np.average([spin[i,1] for i in range(n) if spin[i,1]>0]) 22 | z = np.average([spin[i,2] for i in range(n) if spin[i,2]>0]) 23 | print(x,y,z) 24 | print(abs(x-y), abs(x-z), abs(y-z)) 25 | assert(abs(x-y)<4e-3) 26 | assert(abs(x-z)<4e-3) 27 | assert(abs(y-z)<4e-3) 28 | 29 | if do_plot: 30 | fig = plt.figure() 31 | ax3D = fig.add_subplot(111, projection='3d') 32 | ax3D.scatter(spin[:1000,0], spin[:1000,1], spin[:1000,2], s=30, marker='.') 33 | plt.savefig('test_random_sphere.png') 34 | 35 | def random_m(pos): 36 | return np.random.random(3) - 0.5 37 | 38 | def test_mc_run(Hz=6.0, T=5.0): 39 | #This fast test just shows whether mc can be run or not. 40 | np.random.seed(100) 41 | #mesh = CuboidMesh(nx=28*2, ny=16*3, nz=1, periodicity = (True, True, False)) 42 | mesh = HexagonalMesh(1, 28, 16*2, periodicity=(True, True)) 43 | mc = MonteCarlo(mesh, name='test_mc') 44 | mc.set_m(random_m) 45 | J = 50*const.k_B 46 | mc.set_options(H=[0,0,Hz], J=J, D=0.5*J, T=T) 47 | mc.run(steps=5000, save_m_steps=None, save_vtk_steps=None, save_data_steps=1000) 48 | skx_number = mc.skyrmion_number() 49 | assert(skx_number<-2.5) 50 | assert(skx_number>-3.5) 51 | #np.save('m.npy', mc.spin) 52 | #plot_m(mesh, 'm.npy', comp='z') 53 | 54 | if __name__ == '__main__': 55 | test_random_sphere(do_plot=True) 56 | test_mc_run() 57 | -------------------------------------------------------------------------------- /examples/micromagnetic/std4_oommf/stdprob4.mif: -------------------------------------------------------------------------------- 1 | # MIF 2.1 2 | # 3 | # muMAG Standard Problem 4. 4 | # 5 | set pi [expr 4*atan(1.0)] 6 | set mu0 [expr 4*$pi*1e-7] 7 | 8 | Parameter solver rkf54 ;# One of rk2, rk2heun, rk4, 9 | ## rkf54, rkf54m, or rkf54s 10 | 11 | Parameter subproblem 1 ;# Should be either 1 or 2 12 | 13 | Parameter initproblem 1 ;# Use 1 to generate initial state, 14 | ## or 0 to run using previously generated state. 15 | 16 | if {1 == $subproblem} { 17 | set basename stdprob4a 18 | set Hx -24.6 ;# Applied field in mT 19 | set Hy 4.3 20 | } elseif {2 == $subproblem} { 21 | set basename stdprob4b 22 | set Hx -35.5 ;# Applied field in mT 23 | set Hy -6.3 24 | } else { 25 | error "Unrecognized subproblem request: $subproblem\ 26 | (should be 1 or 2)" 27 | } 28 | set Hz 0.0 29 | 30 | Specify Oxs_BoxAtlas:atlas { 31 | xrange {0 500e-9} 32 | yrange {0 125e-9} 33 | zrange {0 3e-9} 34 | } 35 | 36 | Specify Oxs_RectangularMesh:mesh { 37 | cellsize {2.5e-9 2.5e-9 3e-9} 38 | atlas Oxs_BoxAtlas:atlas 39 | } 40 | 41 | Specify Oxs_UniformExchange { 42 | A 13E-12 43 | } 44 | 45 | Specify Oxs_Demag {} 46 | 47 | if {$initproblem} { 48 | Specify Oxs_CGEvolve {} 49 | Specify Oxs_MinDriver [subst { 50 | basename stdprob4 51 | evolver Oxs_CGEvolve 52 | mesh :mesh 53 | stopping_mxHxm 1e-6 54 | Ms 8e5 55 | m0 { 1 0.25 0.1 } 56 | }] 57 | } else { 58 | Specify Oxs_FixedZeeman [subst { 59 | multiplier [expr 0.001/$mu0] 60 | field {$Hx $Hy $Hz} 61 | }] 62 | Specify Oxs_RungeKuttaEvolve:evolver [subst { 63 | gamma_G 2.211e5 64 | alpha 0.02 65 | method $solver 66 | }] 67 | Specify Oxs_TimeDriver [subst { 68 | basename $basename 69 | evolver :evolver 70 | mesh :mesh 71 | stopping_time 1e-12 72 | stage_count 3000 73 | Ms 8e5 74 | m0 { Oxs_FileVectorField { 75 | atlas :atlas 76 | norm 1.0 77 | file stdprob4-start.omf 78 | }} 79 | }] 80 | } 81 | 82 | 83 | Destination archive mmArchive Stage 1 84 | Schedule DataTable archive Stage 1 85 | #Schedule Oxs_TimeDriver::Magnetization archive Stage 100 86 | -------------------------------------------------------------------------------- /examples/atomistic/PRL_108_017601/figure2.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange, Zeeman, TimeZeeman 3 | from fidimag.common import CuboidMesh, DataReader 4 | import matplotlib as mpl 5 | mpl.use("Agg") 6 | import matplotlib.pyplot as plt 7 | 8 | 9 | def sinc_fun(t): 10 | 11 | w0 = 0.01 12 | 13 | return np.sinc(w0 * t) 14 | 15 | 16 | def excite_system(mesh): 17 | 18 | sim = Sim(mesh, name='dyn') 19 | 20 | # sim.set_options(rtol=1e-10,atol=1e-14) 21 | sim.driver.alpha = 0.04 22 | sim.driver.gamma = 1.0 23 | sim.mu_s = 1.0 24 | 25 | sim.set_m(np.load('m0.npy')) 26 | 27 | J = 1.0 28 | exch = UniformExchange(J) 29 | sim.add(exch) 30 | 31 | D = 0.09 32 | dmi = DMI(D) 33 | sim.add(dmi) 34 | 35 | zeeman = Zeeman([0, 0, 3.75e-3], name='H') 36 | sim.add(zeeman) 37 | 38 | w0 = 0.02 39 | 40 | def time_fun(t): 41 | return np.exp(-w0 * t) 42 | 43 | hx = TimeZeeman([0, 0, 1e-5], sinc_fun, name='h') 44 | sim.add(hx, save_field=True) 45 | 46 | ts = np.linspace(0, 20000, 5001) 47 | for t in ts: 48 | sim.run_until(t) 49 | print 'sim t=%g' % t 50 | 51 | 52 | def deal_plot(): 53 | data = DataReader('dyn.txt') 54 | ts = data['time'] 55 | N = len(ts) 56 | dt = ts[1] - ts[0] 57 | print 'dt=', dt 58 | 59 | freq = np.fft.fftshift(np.fft.fftfreq(N, dt)) 60 | 61 | H = data['h_z'] 62 | M = data['m_z'] 63 | 64 | fH = np.fft.fftshift(np.fft.fft(H)) 65 | fM = np.fft.fftshift(np.fft.fft(M)) 66 | 67 | a = fH.real 68 | b = fH.imag 69 | c = fM.real 70 | d = fM.imag 71 | 72 | rx = (a * c + b * d) / (a * a + b * b) 73 | ix = (b * c - a * d) / (a * a + b * b) 74 | 75 | plt.plot(freq * 2 * np.pi, ix, '.-') 76 | # plt.legend() 77 | plt.xlim([0, 0.012]) 78 | #plt.ylim([-5, 100]) 79 | plt.xlabel(r'$w$') 80 | plt.ylabel('Susceptibility') 81 | plt.savefig('res.pdf') 82 | 83 | 84 | if __name__ == '__main__': 85 | 86 | #mesh = CuboidMesh(nx=288,ny=288,nz=1) 87 | mesh = CuboidMesh(nx=166, ny=96 * 2, nz=1, periodicity=(True, True, False)) 88 | 89 | excite_system(mesh) 90 | 91 | deal_plot() 92 | -------------------------------------------------------------------------------- /fidimag/micro/relax.py: -------------------------------------------------------------------------------- 1 | import fidimag.extensions.baryakhtar_clib as clib 2 | import numpy as np 3 | 4 | 5 | class Relaxation(object): 6 | 7 | """ 8 | compute the relaxation field related to exchange field. 9 | """ 10 | 11 | def __init__(self, chi, name='relax'): 12 | self.chi = chi 13 | self.name = name 14 | 15 | def setup(self, mesh, m, Ms): 16 | self.mesh = mesh 17 | self.dx = mesh.dx * mesh.unit_length 18 | self.dy = mesh.dy * mesh.unit_length 19 | self.dz = mesh.dz * mesh.unit_length 20 | self.nx = mesh.nx 21 | self.ny = mesh.ny 22 | self.nz = mesh.nz 23 | self.spin = m 24 | self.Ms = Ms 25 | self.field = np.zeros(3 * mesh.n) 26 | 27 | if self.chi == 0.0: 28 | self.chi_inv = 0 29 | else: 30 | self.chi_inv = 1.0 / self.chi 31 | 32 | def compute_field(self, t=0): 33 | 34 | clib.compute_relaxation_field(self.spin, 35 | self.field, 36 | self.Ms, 37 | self.chi_inv, 38 | self.mesh.n) 39 | 40 | return self.field 41 | 42 | def compute_energy(self): 43 | 44 | return 0.0 45 | 46 | 47 | class Laplace(object): 48 | 49 | """ 50 | compute the laplace for given field. 51 | """ 52 | 53 | def __init__(self, mesh): 54 | self.dx = mesh.dx * mesh.unit_length 55 | self.dy = mesh.dy * mesh.unit_length 56 | self.dz = mesh.dz * mesh.unit_length 57 | self.nx = mesh.nx 58 | self.ny = mesh.ny 59 | self.nz = mesh.nz 60 | self.field = np.zeros(3 * mesh.n) 61 | 62 | def compute_laplace_field(self, h, Ms): 63 | 64 | clib.compute_laplace_field(h, self.field, 65 | Ms, 66 | self.dx, 67 | self.dy, 68 | self.dz, 69 | self.nx, 70 | self.ny, 71 | self.nz) 72 | 73 | return self.field 74 | -------------------------------------------------------------------------------- /tests/test_vtk_writing.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | from fidimag.common import CuboidMesh 4 | from fidimag.atomistic.hexagonal_mesh import HexagonalMesh 5 | from fidimag.common.field import scalar_field, vector_field 6 | from fidimag.common.vtk import VTK 7 | import pyvtk 8 | import pytest 9 | 10 | MODULE_DIR = os.path.realpath(os.path.dirname(__file__)) 11 | REF_DIR = os.path.dirname(__file__) + '/vtk_refs/' 12 | 13 | def same_as_ref(filepath, ref_dir): 14 | """ 15 | Looks for file with the same filename as `filepath` in `ref_dir` 16 | and compares the two. 17 | 18 | """ 19 | filename = os.path.basename(filepath) 20 | reference = os.path.join(ref_dir, filename) 21 | ret = subprocess.call(["diff", filepath, reference]) 22 | f = open(filepath, 'r').read() 23 | print('new\n', f) 24 | f = open(reference, 'r').read() 25 | print('ref\n', f) 26 | 27 | return ret == 0 # 0 means files are the same, c.f. man diff exit codes 28 | 29 | @pytest.mark.skip(reason="Need a better way to test; precision means comparing diffs does not work.") 30 | def test_save_scalar_field(tmpdir): 31 | mesh = CuboidMesh(4, 3, 2, 4, 3, 2) 32 | s = scalar_field(mesh, lambda r: r[0] + r[1] + r[2]) 33 | vtk = VTK(mesh, directory=str(tmpdir), filename="save_scalar") 34 | vtk.save_scalar(s, name="s") 35 | assert same_as_ref(vtk.write_file(), REF_DIR) 36 | 37 | @pytest.mark.skip(reason="Need a better way to test; precision means comparing diffs does not work.") 38 | def test_save_vector_field(tmpdir): 39 | mesh = CuboidMesh(4, 3, 2, 4, 3, 2) 40 | s = vector_field(mesh, lambda r: (r[0], r[1], r[2])) 41 | vtk = VTK(mesh, directory=str(tmpdir), filename="save_vector") 42 | vtk.save_vector(s, name="s") 43 | assert same_as_ref(vtk.write_file(), REF_DIR) 44 | 45 | @pytest.mark.skip(reason="Need a better way to test; precision means comparing diffs does not work.") 46 | def test_save_scalar_field_hexagonal_mesh(tmpdir): 47 | mesh = HexagonalMesh(1, 3, 3) 48 | s = scalar_field(mesh, lambda r: r[0] + r[1]) 49 | vtk = VTK(mesh, directory=str(tmpdir), filename="scalar_hexagonal") 50 | vtk.save_scalar(s, name="s") 51 | assert same_as_ref(vtk.write_file(), REF_DIR) 52 | -------------------------------------------------------------------------------- /fidimag/common/dipolar/license.txt: -------------------------------------------------------------------------------- 1 | The files demag_oommf.c and demagcoef.h are from the OOMMF project 2 | (http://math.nist.gov/oommf/) and are distributed under this license: 3 | 4 | -------------- 5 | 6 | OOMMF - Object Oriented MicroMagnetic Framework 7 | 8 | The research software provided in this release (“software”) is provided by 9 | NIST as a public service. You may use, copy and distribute copies of the 10 | software in any medium, provided that you keep intact this entire notice. 11 | You may improve, modify and create derivative works of the software or any 12 | portion of the software, and you may copy and distribute such modifications 13 | or works. Modified works should carry a notice stating that you changed the 14 | software and should note the date and nature of any such change. Please 15 | explicitly acknowledge the National Institute of Standards and Technology 16 | as the source of the software. 17 | 18 | The software is expressly provided “AS IS.” NIST MAKES NO WARRANTY OF ANY 19 | KIND, EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, INCLUDING, 20 | WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. NIST NEITHER 22 | REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE 23 | UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST 24 | DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE 25 | SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE 26 | CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. 27 | 28 | You are solely responsible for determining the appropriateness of using 29 | and distributing the software and you assume all risks associated with 30 | its use, including but not limited to the risks and costs of program 31 | errors, compliance with applicable laws, damage to or loss of data, 32 | programs or equipment, and the unavailability or interruption of operation. 33 | This software is not intended to be used in any situation where a failure 34 | could cause risk of injury or damage to property. The software was 35 | developed by NIST employees. NIST employee contributions are not subject 36 | to copyright protection within the United States. 37 | 38 | -------------------------------------------------------------------------------- /tests/test_exch_rkky.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import matplotlib as mpl 3 | mpl.use("Agg") 4 | import matplotlib.pyplot as plt 5 | 6 | from fidimag.common import CuboidMesh 7 | from fidimag.micro import Sim 8 | from fidimag.micro import Zeeman 9 | from fidimag.micro import UniaxialAnisotropy, ExchangeRKKY 10 | import numpy as np 11 | 12 | 13 | def init_m(pos): 14 | x, y, z = pos 15 | if z<1: 16 | return (0,0.01,-1) 17 | else: 18 | return (0.01, 0, 1) 19 | 20 | 21 | def spatial_Ms(pos): 22 | x, y, z = pos 23 | if z<2 and z>1: 24 | return 0 25 | else: 26 | return 8.6e5 27 | 28 | 29 | def test_excahnge_rkky(do_plot=False): 30 | 31 | mesh = CuboidMesh(nx=1, ny=1, nz=3, dz=1.0, unit_length=1e-9) 32 | 33 | sim = Sim(mesh, name='spin') 34 | sim.driver.alpha = 0.001 35 | sim.driver.gamma = 2.211e5 36 | sim.Ms = spatial_Ms 37 | 38 | sim.set_m(init_m) 39 | 40 | anis = UniaxialAnisotropy(5e4, axis=(0,0,1)) 41 | sim.add(anis) 42 | 43 | exch = ExchangeRKKY(sigma=-1e-4) 44 | sim.add(exch) 45 | 46 | ts = np.linspace(0, 3e-9, 1001) 47 | 48 | mx = [] 49 | 50 | mxt = [] 51 | 52 | real_ts = [] 53 | for t in ts: 54 | sim.driver.run_until(t) 55 | real_ts.append(sim.driver.t) 56 | print(sim.driver.t, abs(sim.spin_length()[0] - 1)) 57 | mx.append(sim.spin[0]) 58 | mxt.append(sim.spin[6]) 59 | 60 | 61 | id = np.argmax(abs(np.fft.fft(mx))) 62 | freqs = np.fft.fftfreq(len(mx), ts[1]-ts[0]) 63 | 64 | mu0 = 4*np.pi*1e-7 65 | Ms = 8.6e5 66 | K = 2*5e4/(mu0*Ms) 67 | sigma = 1e-4/1e-9/(mu0*Ms) 68 | expected = 2.211e5*(K*(K+2*sigma))**0.5/(2*np.pi) 69 | 70 | if do_plot: 71 | ts_ns = np.array(real_ts) * 1e9 72 | plt.plot(ts_ns, mx, label="mx", color='darkslateblue') 73 | plt.plot(ts_ns, mxt, label="mxt", color='m') 74 | 75 | plt.xlabel("time (ns)") 76 | plt.ylabel("m") 77 | plt.legend() 78 | plt.savefig("test_rkky.pdf") 79 | 80 | print((freqs[id]-expected)/expected) 81 | print((freqs[id]-expected)/expected<0.01) 82 | 83 | 84 | 85 | if __name__ == '__main__': 86 | test_excahnge_rkky(do_plot=True) 87 | -------------------------------------------------------------------------------- /examples/nebm_atomistic/skyrmion_reduced/relax.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.atomistic import Sim, DMI, UniformExchange, Anisotropy 3 | from fidimag.common import CuboidMesh 4 | from fidimag.atomistic import NEB_Sundials 5 | 6 | def mu_s(pos): 7 | x,y,z = pos 8 | x0,y0,r = 60,60,60.5 9 | 10 | if (x-x0)**2 + (y-y0)**2 <= r**2: 11 | return 1 12 | else: 13 | return 0 14 | 15 | def init_m(pos): 16 | x,y,z = pos 17 | 18 | x0,y0,r = 60,60,25 19 | 20 | m1 = (0.05,0.01,-1) 21 | m2 = (0,0,1) 22 | 23 | if (x-x0)**2 + (y-y0)**2 < r**2: 24 | return m1 25 | else: 26 | return m2 27 | 28 | def init_m_down(pos): 29 | x,y,z = pos 30 | 31 | x0,y0,r = 60,60,25 32 | 33 | m1 = (0.05,0.01,1) 34 | m2 = (0,0,-1) 35 | 36 | if (x-x0)**2 + (y-y0)**2 < r**2: 37 | return m1 38 | else: 39 | return m2 40 | 41 | def create_sim(): 42 | 43 | mesh = CuboidMesh(nx=121,ny=121,nz=1) 44 | sim=Sim(mesh,name='relax') 45 | 46 | sim.driver.alpha = 1.0 47 | sim.driver.gamma = 0.5 48 | sim.mu_s = mu_s 49 | 50 | sim.set_m(init_m) 51 | 52 | J = 1.0 53 | exch = UniformExchange(J) 54 | sim.add(exch) 55 | 56 | D = 0.08 57 | dmi = DMI(D) 58 | sim.add(dmi) 59 | 60 | K = 4e-3 61 | anis=Anisotropy(K, direction=(0,0,1),name='Ku') 62 | sim.add(anis) 63 | 64 | return sim 65 | 66 | 67 | def relax_system(): 68 | 69 | sim = create_sim() 70 | 71 | sim.do_precession = False 72 | 73 | sim.relax(dt=2.0, stopping_dmdt=1e-6, max_steps=5000, save_m_steps=100, save_vtk_steps=100) 74 | 75 | np.save('m_up.npy',sim.spin) 76 | 77 | sim.set_m(init_m_down) 78 | 79 | sim.relax(dt=2.0, stopping_dmdt=1e-6, max_steps=5000, save_m_steps=100, save_vtk_steps=100) 80 | 81 | np.save('m_down.npy',sim.spin) 82 | 83 | def run_neb(): 84 | 85 | sim = create_sim() 86 | 87 | init_images = [np.load('m_up.npy'), np.load('m_down.npy')] 88 | 89 | neb = NEB_Sundials(sim, init_images, interpolations=[10], name='neb', spring=1.0) 90 | 91 | neb.relax(dt=1, max_steps=5000, save_vtk_steps=500, save_npy_steps=500, stopping_dmdt=1e-5) 92 | 93 | 94 | 95 | if __name__=='__main__': 96 | 97 | #relax_system() 98 | run_neb() 99 | -------------------------------------------------------------------------------- /fidimag/micro/exchange_rkky.py: -------------------------------------------------------------------------------- 1 | import fidimag.extensions.micro_clib as micro_clib 2 | from .energy import Energy 3 | #from constant import mu_0 4 | 5 | 6 | class ExchangeRKKY(Energy): 7 | 8 | """ 9 | RKKYExchange(sigma, Delta, z_bottom=0, z_top = -1, name='RKKYExchange') 10 | 11 | Compute the RKKY-style exchange interaction defined by 12 | 13 | E = sigma/Delta *(1-m_t * m_b) 14 | 15 | where E is the energy density, sigma is the surface exchange coefficient between the two surfaces, 16 | Delata is the space thickness. m_t and m_b are the unit vectors of the top and bottom layers, respectively. 17 | 18 | Inputs: 19 | sigma: float 20 | sigma is the surface exchange stiffness constant. 21 | Delta: float 22 | Delta is the the space thickness in Meter. 23 | z_bottom: int 24 | z_bottom is the index of the bottom layer 25 | z_top: int 26 | z_top is the index of the top layer. 27 | 28 | """ 29 | 30 | def __init__(self, sigma, Delta=1e-9, z_bottom=0, z_top = -1, name='RKKYExchange'): 31 | self.sigma = sigma/Delta 32 | self.name = name 33 | self.z_bottom = z_bottom 34 | self.z_top = z_top 35 | self.jac = True 36 | 37 | def setup(self, mesh, spin, Ms, Ms_inv): 38 | super(ExchangeRKKY, self).setup(mesh, spin, Ms, Ms_inv) 39 | if self.z_top<0: 40 | self.z_top+= self.nz 41 | 42 | 43 | def compute_field(self, t=0, spin=None): 44 | if spin is not None: 45 | m = spin 46 | else: 47 | m = self.spin 48 | 49 | micro_clib.compute_exchange_field_micro_rkky(m, 50 | self.field, 51 | self.energy, 52 | self.Ms_inv, 53 | self.sigma, 54 | self.nx, 55 | self.ny, 56 | self.nz, 57 | self.z_bottom, 58 | self.z_top 59 | ) 60 | 61 | return self.field 62 | -------------------------------------------------------------------------------- /fidimag/atomistic/llg.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from __future__ import print_function 3 | 4 | # Use the common C library for the LLG equation in the atomistic case 5 | import fidimag.extensions.common_clib as clib 6 | 7 | from .atomistic_driver import AtomisticDriver 8 | 9 | 10 | class LLG(AtomisticDriver): 11 | 12 | """ 13 | 14 | This class is the driver to solve the Landau Lifshitz Gilbert equation 15 | which has the form: 16 | 17 | 18 | ds -gamma 19 | ---- = -------- ( s X H_eff + a * s X ( s X H_eff ) ) 20 | dt 2 21 | ( 1 + a ) 22 | 23 | by using the Sundials library with CVODE. 24 | 25 | This class inherits common methods to evolve the system using CVODE, from 26 | the micro_driver.MicroDriver class. Arrays with the system information 27 | are taken as references from the main micromagnetic Simulation class 28 | 29 | """ 30 | 31 | def __init__(self, mesh, spin, mu_s, mu_s_inv, field, pins, 32 | interactions, 33 | name, 34 | data_saver, 35 | use_jac, 36 | integrator='sundials' 37 | ): 38 | 39 | # Inherit from the driver class 40 | super(LLG, self).__init__(mesh, spin, mu_s, mu_s_inv, field, 41 | pins, interactions, name, 42 | data_saver, 43 | use_jac, 44 | integrator=integrator 45 | ) 46 | 47 | def sundials_rhs(self, t, y, ydot): 48 | 49 | self.t = t 50 | 51 | # already synchronized when call this funciton 52 | # self.spin[:]=y[:] 53 | 54 | self.compute_effective_field(t) 55 | 56 | clib.compute_llg_rhs(ydot, 57 | self.spin, 58 | self.field, 59 | self._alpha, 60 | self._pins, 61 | self.gamma, 62 | self.n, 63 | self.do_precession, 64 | self.default_c) 65 | 66 | #ydot[:] = self.dm_dt[:] 67 | 68 | return 0 69 | 70 | if __name__ == '__main__': 71 | pass 72 | -------------------------------------------------------------------------------- /examples/nebm_atomistic/1D_spin_chain/relaxation/1D_spin_chain.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | from fidimag.atomistic import Sim 4 | from fidimag.common import CuboidMesh 5 | from fidimag.atomistic import DMI 6 | from fidimag.atomistic import UniformExchange 7 | from fidimag.atomistic import Zeeman 8 | from fidimag.atomistic import Anisotropy 9 | import fidimag.common.constant as const 10 | 11 | # Number of spins and lattice spacing (see mesh) 12 | nx = 50 13 | dx = 0.27 14 | 15 | 16 | # ^ ^ ^ 17 | # An irregular initial state | | | | | | | | | 18 | # v v v v v v 19 | def init_m(pos): 20 | 21 | chain_third = nx * dx / 3. 22 | 23 | x = pos[0] 24 | 25 | if x < chain_third or x > 2 * chain_third: 26 | return (0, 0, -1) 27 | else: 28 | return (0, 0, 1) 29 | 30 | sim_name = 'relax_spin_chain' 31 | 32 | 33 | def relax_system(): 34 | 35 | # 1D chain of 50 spins with a lattice constant of 0.27 A 36 | mesh = CuboidMesh(nx=nx, 37 | dx=dx, 38 | unit_length=1e-9, 39 | # pbc='1d' 40 | ) 41 | 42 | # Initiate the simulation 43 | sim = Sim(mesh, name=sim_name) 44 | sim.driver.gamma = const.gamma 45 | 46 | # magnetisation in units of Bohr's magneton 47 | sim.mu_s = 2 * const.mu_B 48 | 49 | # sim.set_options(gamma=const.gamma, k_B=const.k_B) 50 | 51 | # Initial magnetisation profile 52 | sim.set_m(init_m) 53 | 54 | # Exchange constant in Joules: E = Sum J_{ij} S_i S_j 55 | J = 12. * const.meV 56 | exch = UniformExchange(J) 57 | sim.add(exch) 58 | 59 | # DMI constant in Joules: E = Sum D_{ij} S_i x S_j 60 | D = 2. * const.meV 61 | dmi = DMI(D, dmi_type='interfacial') 62 | sim.add(dmi) 63 | 64 | # Anisotropy along +z axis 65 | ku = Anisotropy(Ku=0.5 * const.meV, 66 | axis=[0, 0, 1], 67 | name='ku') 68 | sim.add(ku) 69 | 70 | # Faster convergence 71 | sim.driver.alpha = 0.5 72 | sim.do_precession = False 73 | 74 | sim.relax(dt=1e-13, stopping_dmdt=0.05, 75 | max_steps=700, 76 | save_m_steps=1000, save_vtk_steps=1000) 77 | 78 | # Save the last relaxed state 79 | np.save(sim_name + '.npy', sim.spin) 80 | 81 | relax_system() 82 | -------------------------------------------------------------------------------- /examples/neb_micromagnetic/skyrmion/relaxation/skyrmion_down_relax.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Script to generate a skyrmion pointing DOWN in a 50 nm wide 4 | and 5 nm thick FeGe disk 5 | 6 | The skyrmion is stabilised due to the finite system (border 7 | effects) and without Demag, external magnetic fields or 8 | anisotropies 9 | 10 | """ 11 | 12 | # FIDIMAG: 13 | from fidimag.micro import Sim, UniformExchange, Demag, DMI 14 | from fidimag.common import CuboidMesh 15 | import numpy as np 16 | 17 | 18 | # Material Parameters for FeGe 19 | A = 8.78e-12 20 | D = 1.58e-3 21 | Ms = 3.84e5 22 | 23 | # Radius of the nanodisk 24 | radius = 25 25 | 26 | # MESH 27 | # We pass this function to the Ms property 28 | # of the simulation, so spins outside the desired 29 | # radius will have Ms = 0 30 | def cylinder(pos): 31 | 32 | # Relative position 33 | x, y = pos[0] - radius, pos[1] - radius 34 | 35 | if x ** 2 + y ** 2 < radius ** 2: 36 | return Ms 37 | else: 38 | return 0 39 | 40 | # We will generate a 50 nm wide and 5nm thick disk The finite difference 41 | # elements are 2nmx2nm cubes along the disk plane and they have a thickness of 42 | # 1 nm 43 | # Finite differences mesh 44 | mesh = CuboidMesh(nx=25, ny=25, nz=5, 45 | dx=2, dy=2, dz=1, 46 | unit_length=1e-9 47 | ) 48 | 49 | 50 | # Initial magnetisation profile to get the skyrmion 51 | # We create a small core pointing in the -z direction 52 | def init_m(pos): 53 | 54 | x, y = pos[0] - radius, pos[1] - radius 55 | 56 | if x ** 2 + y ** 2 < radius ** 2: 57 | return (0, 0, -1) 58 | else: 59 | return (0, 0, 1) 60 | 61 | # Prepare simulation 62 | # We define the cylinder with the Magnetisation function 63 | sim = Sim(mesh, name='skyrmion_down') 64 | sim.Ms = cylinder 65 | 66 | # To get a faster relaxation, we tune the LLG equation parameters 67 | sim.do_precession = False 68 | sim.driver.alpha = 0.5 69 | 70 | # Initial magnetisation: 71 | sim.set_m(init_m) 72 | 73 | # Energies: 74 | 75 | # Exchange 76 | sim.add(UniformExchange(A=A)) 77 | 78 | # Bulk DMI 79 | sim.add(DMI(D=D)) 80 | 81 | # Relax the system 82 | sim.relax(dt=1e-12, stopping_dmdt=0.0001, max_steps=5000, 83 | save_m_steps=None, 84 | save_vtk_steps=None 85 | ) 86 | 87 | # Save the final state and a vtk file 88 | np.save('sk_down.npy', sim.spin) 89 | sim.save_vtk() 90 | -------------------------------------------------------------------------------- /examples/neb_micromagnetic/skyrmion/relaxation/skyrmion_relax.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Script to generate a skyrmion pointing up in a 50 nm wide 4 | and 5 nm thick FeGe disk 5 | 6 | The skyrmion is stabilised due to the finite system (border 7 | effects) and without Demag, external magnetic fields or 8 | anisotropies 9 | 10 | """ 11 | 12 | # FIDIMAG: 13 | from fidimag.micro import Sim, UniformExchange, Demag, DMI 14 | from fidimag.common import CuboidMesh 15 | import numpy as np 16 | 17 | 18 | # Material Parameters for FeGe 19 | A = 8.78e-12 20 | D = 1.58e-3 21 | Ms = 3.84e5 22 | 23 | # Radius of the nanodisk 24 | radius = 25 25 | 26 | # MESH 27 | # We pass this function to the Ms property 28 | # of the simulation, so spins outside the desired 29 | # radius will have Ms = 0 30 | def cylinder(pos): 31 | 32 | # Relative position 33 | x, y = pos[0] - radius, pos[1] - radius 34 | 35 | if x ** 2 + y ** 2 < radius ** 2: 36 | return Ms 37 | else: 38 | return 0 39 | 40 | # We will generate a 50 nm wide and 5nm thick disk The finite difference 41 | # elements are 2nmx2nm cubes along the disk plane and they have a thickness of 42 | # 1 nm 43 | # Finite differences mesh 44 | mesh = CuboidMesh(nx=25, ny=25, nz=5, 45 | dx=2, dy=2, dz=1, 46 | unit_length=1e-9 47 | ) 48 | 49 | 50 | # Initial magnetisation profile to get the skyrmion 51 | # We create a small core pointing in the +z direction 52 | def init_m(pos): 53 | 54 | x, y = pos[0] - radius, pos[1] - radius 55 | 56 | if x ** 2 + y ** 2 < radius ** 2: 57 | return (0, 0, 1) 58 | else: 59 | return (0, 0, -1) 60 | 61 | # Prepare simulation 62 | 63 | # We define the cylinder with the Magnetisation function 64 | sim = Sim(mesh, name='skyrmion') 65 | sim.Ms = cylinder 66 | 67 | # To get a faster relaxation, we tune the LLG equation parameters 68 | sim.do_precession = False 69 | sim.driver.alpha = 0.5 70 | 71 | # Initial magnetisation: 72 | sim.set_m(init_m) 73 | 74 | # Energies: 75 | 76 | # Exchange 77 | sim.add(UniformExchange(A=A)) 78 | 79 | # Bulk DMI 80 | sim.add(DMI(D=D)) 81 | 82 | # Relax the system 83 | sim.relax(dt=1e-12, stopping_dmdt=0.0001, max_steps=5000, 84 | save_m_steps=None, 85 | save_vtk_steps=None 86 | ) 87 | 88 | # Save the final relaxed state and a vtk file 89 | np.save('sk_up.npy', sim.spin) 90 | sim.save_vtk() 91 | -------------------------------------------------------------------------------- /examples/atomistic/dmi/interfacial_dmi_dw/dw.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.use("Agg") 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | from fidimag.atomistic import Sim, DMI, UniformExchange, Anisotropy 6 | from fidimag.common import constant, CuboidMesh 7 | 8 | 9 | def m_init_dw(pos): 10 | 11 | x = pos[0] 12 | 13 | if x < 140: 14 | return (0, 0, 1) 15 | elif x > 160: 16 | return (0, 0, -1) 17 | else: 18 | return (0, 1, 1) 19 | 20 | 21 | def analytical(xs, A=1.3e-11, D=4e-4, K=8e4): 22 | 23 | delta = np.sqrt(A / (K - D * D / (4 * A))) 24 | 25 | phi = D / (2 * A) * xs 26 | 27 | mx = - np.tanh(xs / delta) 28 | my = 1.0 / np.cosh(xs / delta) * np.cos(phi) 29 | mz = 1.0 / np.cosh(xs / delta) * np.sin(phi) 30 | return mx, my, mz 31 | 32 | 33 | def relax_system(mesh): 34 | 35 | sim = Sim(mesh, name='relax') 36 | sim.driver.gamma = constant.gamma 37 | sim.driver.alpha = 0.5 38 | sim.mu_s = constant.mu_s_1 39 | sim.do_precession = False 40 | 41 | sim.set_m(m_init_dw) 42 | 43 | J = 50.0 * constant.k_B 44 | exch = UniformExchange(J) 45 | sim.add(exch) 46 | 47 | D = 0.1 * J 48 | dmi = DMI(D, dmi_type='interfacial') 49 | sim.add(dmi) 50 | 51 | K = 0.02 * J 52 | anis = Anisotropy(K, axis=[0, 0, 1]) 53 | sim.add(anis) 54 | 55 | ONE_DEGREE_PER_NS = 17453292.52 56 | 57 | sim.relax(dt=1e-13, stopping_dmdt=0.01 * ONE_DEGREE_PER_NS, 58 | max_steps=1000, save_m_steps=100, save_vtk_steps=50) 59 | 60 | np.save('m0.npy', sim.spin) 61 | 62 | xs = np.array([p[0] for p in mesh.coordinates]) - 150 63 | 64 | mx, my, mz = analytical(xs, A=J/2.0, D=-D, K=K) 65 | mxyz = sim.spin.copy() 66 | mxyz.shape = (3, -1) 67 | 68 | save_plot(xs, mxyz, mx, my, mz) 69 | 70 | 71 | def save_plot(xs, mxyz, mx, my, mz): 72 | fig = plt.figure() 73 | mxyz.shape = (3, -1) 74 | plt.plot(xs, mxyz[0], '.', label='mx') 75 | plt.plot(xs, mxyz[1], '.', label='my') 76 | plt.plot(xs, mxyz[2], '.', label='mz') 77 | 78 | plt.plot(xs, mx, '-') 79 | plt.plot(xs, my, '-') 80 | plt.plot(xs, mz, '-') 81 | 82 | plt.ylabel('mxyz') 83 | plt.xlabel('x/a') 84 | plt.legend(loc=1) 85 | plt.grid() 86 | #plt.xlim([-150, 150]) 87 | plt.ylim([-1.2, 1.2]) 88 | fig.savefig('dw_dmi.pdf') 89 | 90 | 91 | if __name__ == '__main__': 92 | mesh = CuboidMesh(nx=300, ny=40, nz=1) 93 | relax_system(mesh) 94 | #excite_system(mesh) 95 | -------------------------------------------------------------------------------- /examples/micromagnetic/single_spin/single_spin.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fidimag.micro import Sim, Zeeman 3 | from fidimag.common import CuboidMesh 4 | from fidimag.common.fileio import DataReader 5 | import matplotlib.pyplot as plt 6 | 7 | 8 | def single_spin(alpha, gamma, H0, ts): 9 | """ 10 | compute single spin under the external field H 11 | """ 12 | 13 | precession = gamma / (1 + alpha**2) 14 | beta = precession * H0 * ts 15 | 16 | mx = np.cos(beta) / np.cosh(alpha * beta) 17 | my = np.sin(beta) / np.cosh(alpha * beta) 18 | mz = np.tanh(alpha * beta) 19 | 20 | return mx, my, mz 21 | 22 | 23 | def relax_system(): 24 | mesh = CuboidMesh(nx=1, ny=1, nz=1) 25 | sim = Sim(mesh, name='relax') 26 | sim.driver.set_tols(rtol=1e-10, atol=1e-10) 27 | sim.driver.alpha = 0.5 28 | 29 | sim.set_m((1.0, 0, 0)) 30 | 31 | sim.add(Zeeman((0, 0, 1e5))) 32 | 33 | ts = np.linspace(0, 1e-9, 1001) 34 | 35 | for t in ts: 36 | sim.run_until(t) 37 | 38 | 39 | def custom_legend(legend): 40 | frame = legend.get_frame() 41 | frame.set_facecolor('0.90') 42 | 43 | # Set the fontsize 44 | for label in legend.get_texts(): 45 | label.set_fontsize(11) 46 | 47 | for label in legend.get_lines(): 48 | label.set_linewidth(1.5) # the legend line width 49 | 50 | 51 | def plot_all(): 52 | 53 | font = {'family': 'serif', 54 | 'weight': 'normal', 55 | 'size': 12, 56 | } 57 | 58 | plt.rc('font', **font) 59 | 60 | data = DataReader('relax.txt') 61 | ts = data['time'] 62 | 63 | mx, my, mz = single_spin(0.5, 2.21e5, 1e5, ts) 64 | 65 | ts = ts * 1e9 66 | fig = plt.figure(figsize=(5, 4)) 67 | plt.plot(ts, mx, '--', label='m_x', dashes=(2.0, 2.0)) 68 | plt.plot(ts, my, '--', label='m_y', dashes=(2.0, 2.0)) 69 | plt.plot(ts, mz, '--', label='m_z', dashes=(2.0, 2.0)) 70 | 71 | ts = ts[::10] 72 | mx = data['m_x'][::10] 73 | my = data['m_y'][::10] 74 | mz = data['m_z'][::10] 75 | plt.plot(ts, mx, '.', color='b') 76 | plt.plot(ts, my, '.', color='g') 77 | plt.plot(ts[::2], mz[::2], '.', color='r') 78 | plt.xlim([0, 1.01]) 79 | 80 | l1 = plt.legend(bbox_to_anchor=[0.8, 0.8], shadow=True, frameon=True) 81 | custom_legend(l1) 82 | 83 | plt.xlabel('Time (ns)') 84 | plt.ylabel('m') 85 | plt.tight_layout() 86 | fig.savefig('m_ts.pdf') 87 | 88 | 89 | if __name__ == '__main__': 90 | 91 | relax_system() 92 | plot_all() 93 | -------------------------------------------------------------------------------- /tests/test_dw_dmi.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from fidimag.common import CuboidMesh 4 | from fidimag.micro import Sim 5 | from fidimag.micro import UniformExchange 6 | from fidimag.micro import UniaxialAnisotropy 7 | from fidimag.micro import DMI 8 | 9 | import matplotlib.pyplot as plt 10 | 11 | mesh = CuboidMesh(dx=2, nx=150, x0=-150, unit_length=1e-9) 12 | 13 | 14 | def m_init_dw(pos): 15 | 16 | x = pos[0] 17 | 18 | if x < -10: 19 | return (1, 0, 0) 20 | elif x > 10: 21 | return (-1, 0, 0) 22 | else: 23 | return (0, 1, 0) 24 | 25 | 26 | def analytical(xs, A=1.3e-11, D=4e-4, K=8e4): 27 | 28 | delta = np.sqrt(A / (K - D * D / (4 * A))) * 1e9 29 | 30 | phi = D / (2 * A) * xs * 1e-9 31 | 32 | mx = - np.tanh(xs / delta) 33 | my = 1.0 / np.cosh(xs / delta) * np.cos(phi) 34 | mz = 1.0 / np.cosh(xs / delta) * np.sin(phi) 35 | return mx, my, mz 36 | 37 | 38 | def save_plot(mxyz, mx, my, mz): 39 | fig = plt.figure() 40 | mxyz.shape = (-1, 3) 41 | xs = np.array([p[0] for p in mesh.pos]) 42 | plt.plot(xs, mxyz[:, 0], '.', label='mx') 43 | plt.plot(xs, mxyz[:, 1], '.', label='my') 44 | plt.plot(xs, mxyz[:, 2], '.', label='mz') 45 | 46 | plt.plot(xs, mx, '-') 47 | plt.plot(xs, my, '-') 48 | plt.plot(xs, mz, '-') 49 | 50 | plt.ylabel('mxyz') 51 | plt.xlabel('x (nm)') 52 | plt.legend(loc=1) 53 | plt.grid() 54 | plt.xlim([-150, 150]) 55 | plt.ylim([-1.2, 1.2]) 56 | fig.savefig('dw_dmi.pdf') 57 | 58 | 59 | def test_dw_dmi(mesh=mesh, do_plot=False): 60 | 61 | Ms = 8.0e5 62 | sim = Sim(mesh, name='relax') 63 | 64 | sim.set_m(m_init_dw) 65 | 66 | sim.driver.set_tols(rtol=1e-8, atol=1e-12) 67 | sim.Ms = Ms 68 | sim.alpha = 0.5 69 | sim.do_precession = False 70 | 71 | A = 1.3e-11 72 | D = 4e-4 73 | Kx = 8e4 74 | Kp = -6e5 75 | 76 | sim.add(UniformExchange(A)) 77 | sim.add(DMI(D)) 78 | sim.add(UniaxialAnisotropy(Kx, axis=[1, 0, 0], name='Kx')) 79 | 80 | sim.driver.relax(stopping_dmdt=0.01) 81 | 82 | xs = np.array([p[0] for p in mesh.coordinates]) 83 | mx, my, mz = analytical(xs, A=A, D=D, K=Kx) 84 | mxyz = sim.spin.copy() 85 | mxyz = mxyz.reshape(-1, 3) 86 | 87 | assert max(abs(mxyz[:, 0] - mx)) < 0.002 88 | assert max(abs(mxyz[:, 1] - my)) < 0.002 89 | assert max(abs(mxyz[:, 2] - mz)) < 0.0006 90 | 91 | if do_plot: 92 | 93 | save_plot(mxyz, mx, my, mz) 94 | 95 | if __name__ == '__main__': 96 | 97 | test_dw_dmi(do_plot=True) 98 | -------------------------------------------------------------------------------- /fidimag/atomistic/fmmlib/calculate.hpp: -------------------------------------------------------------------------------- 1 | //############################################ 2 | //# 3 | //# Functions for running the Barnes-Hut 4 | //# method for gravitational source particles. 5 | //# 6 | //# (C) Ryan Pepper, 2018 7 | //# University of Southampton, UK 8 | //# 9 | //# 10 | //########################################### 11 | #pragma once 12 | #include "tree.hpp" 13 | #include "utils.hpp" 14 | #include 15 | #include 16 | 17 | void M_sanity_check(const std::vector &cells); 18 | 19 | void evaluate_P2M(std::vector &particles, std::vector &cells, 20 | size_t cell, size_t ncrit, size_t exporder); 21 | 22 | void evaluate_M2M(std::vector &particles, std::vector &cells, 23 | size_t exporder); 24 | 25 | 26 | void evaluate_L2L(std::vector &cells, size_t exporder); 27 | 28 | void evaluate_L2P(std::vector &particles, std::vector &cells, 29 | double *F, size_t ncrit, size_t exporder); 30 | 31 | void evaluate_direct(std::vector &particles, double *F, size_t Nparticles); 32 | 33 | void interact_dehnen(size_t A, size_t B, std::vector &cells, std::vector &particles, double theta, size_t order, size_t ncrit, double *F); 34 | 35 | void interact_dehnen_lazy(const size_t A, const size_t B, const std::vector &cells, const std::vector &particles, 36 | const double theta, const size_t order, const size_t ncrit, 37 | std::vector> &M2L_list, 38 | std::vector> &P2P_list); 39 | 40 | void P2P_Cells(size_t A, size_t B, std::vector &cells, 41 | std::vector &particles, double *F); 42 | 43 | void evaluate_P2P_lazy(std::vector &cells, 44 | std::vector> &P2P_list); 45 | 46 | void evaluate_M2L_lazy(std::vector &cells, 47 | std::vector> &M2L_list, 48 | std::vector &M2L_locks); 49 | 50 | void evaluate_M2L_lazy(std::vector &cells, 51 | std::vector> &M2L_list, size_t order); 52 | 53 | void evaluate_P2P_lazy(std::vector &cells, std::vector &particles, 54 | std::vector> &P2P_list, double *F); 55 | 56 | void evaluate_M2P_and_P2P(std::vector &particles, unsigned int p, unsigned int i, 57 | std::vector &cells, double *F, unsigned int n_crit, double theta, 58 | unsigned int exporder); 59 | -------------------------------------------------------------------------------- /tests/test_hubert_minimiser.py: -------------------------------------------------------------------------------- 1 | import fidimag 2 | import fidimag.common.constant as C 3 | import numpy as np 4 | 5 | 6 | def test_hubert_minimiser_1D_DW(): 7 | 8 | nx, ny, nz = 100, 1, 1 9 | dx, dy, dz = 1, 1, 1 10 | 11 | mesh = fidimag.common.CuboidMesh(nx=nx, ny=ny, nz=nz, dx=dx, dy=dy, dz=dz, 12 | periodicity=(False, False, False), 13 | unit_length=1e-9) 14 | 15 | sim = fidimag.micro.Sim(mesh, name='1Dmicro', driver='hubert_minimiser') 16 | 17 | Ms = 0.86e6 18 | A = 13e-12 19 | Ku = 0.4e6 20 | 21 | # Define the magnetisation 22 | sim.set_Ms(Ms) 23 | 24 | # Add the magnetic interactions 25 | sim.add(fidimag.micro.UniformExchange(A)) 26 | sim.add(fidimag.micro.UniaxialAnisotropy(Ku, axis=(0, 0, 1))) 27 | # sim.add(fidimag.atomistic.DMI(D, dmi_type='interfacial')) 28 | # sim.add(fidimag.micro.Zeeman((0, 0, B))) 29 | 30 | xs = mesh.coordinates[:, 0] 31 | centre_x = (xs.max() + xs.min()) * 0.5 + xs.min() 32 | 33 | def m_initial(r): 34 | x, y, z = r[0], r[1], r[2] 35 | if x < centre_x: 36 | return (0, 0.1, -.9) 37 | else: 38 | return (0, 0.1, .9) 39 | sim.set_m(m_initial) 40 | 41 | mesh_vol = mesh.n * mesh.dx * mesh.dy * mesh.dz * 1e-27 42 | Kd = C.mu_0 * (Ms ** 2) * 0.5 * mesh_vol 43 | # Scale the energy for the minimiser 44 | sim.driver.energyScale = Kd 45 | 46 | sim.driver.minimise(stopping_dE=1e-6, maxCreep=6, 47 | eta_scale=1e-6, log_steps=10) 48 | mz = sim.spin.reshape(-1, 3)[:, 2] 49 | 50 | # ANALYSIS 51 | 52 | def mz_dw_analyt(x, xc): 53 | """Analytical DW function using DW width param""" 54 | # DW width from theory 55 | deltaB = np.sqrt(A / Ku) 56 | return np.tanh((x - xc) / deltaB) 57 | 58 | # Analytical model in nm units 59 | x = sim.mesh.coordinates[:, 0] 60 | y = mz_dw_analyt(x * 1e-9, 50 * 1e-9) 61 | 62 | # Mean absolute error at points within the DW width: 63 | # The maximum "deviation" a spin might have from the curve is 2, since 64 | # the spin-z is in the [-1, 1] range 65 | deltaB = np.sqrt(A / Ku) * 1e9 66 | xc = 50 # sample centre 67 | ftr = np.logical_and(x <= xc + deltaB, x >= xc - deltaB) 68 | 69 | MAE_dw = np.mean(np.abs(y[ftr] - mz[ftr])) 70 | print('Domain wall MAE', MAE_dw) 71 | # This is at least 1% the max deviation 72 | assert MAE_dw < 0.02 73 | 74 | 75 | if __name__ == "__main__": 76 | test_hubert_minimiser_1D_DW() 77 | -------------------------------------------------------------------------------- /tests/test_micromagnetic_zeeman.py: -------------------------------------------------------------------------------- 1 | from fidimag.micro import Zeeman 2 | from fidimag.common import CuboidMesh 3 | from fidimag.micro import Sim 4 | import numpy as np 5 | 6 | 7 | def varying_field(pos): 8 | return (1.2 * pos[0], 2.3 * pos[1], 0) 9 | 10 | 11 | def test_H0_is_indexable_or_callable(): 12 | """ 13 | Test that an exception is raised if H0 is not indexable, and that an 14 | exception is not raised if H0 is indexable. 15 | """ 16 | # Test for some different accepted types. 17 | inputSuccess = ([0., 0., 1.], 18 | np.array([0., 0., 1.]), 19 | lambda x: x + 0.1) 20 | for zS in inputSuccess: 21 | Zeeman(zS) 22 | 23 | # Test for different failing types. Should perhaps use a unittest.TestCase 24 | # for testing to make this more elegant, but there's probably a reason why 25 | # it's not used elsewhere. 26 | inputFailures = [5., -7] 27 | for zS in inputFailures: 28 | try: 29 | Zeeman(zS) 30 | except ValueError: 31 | pass 32 | else: 33 | raise Exception("Zeeman argument \"{}\" was expected to raise an " 34 | "exception, but did not!." 35 | .format(zS)) 36 | 37 | def test_zeeman(): 38 | 39 | mesh = CuboidMesh(nx=5, ny=2, nz=1) 40 | 41 | sim = Sim(mesh) 42 | sim.set_m((1, 0, 0)) 43 | 44 | zeeman = Zeeman(varying_field) 45 | sim.add(zeeman) 46 | 47 | field = zeeman.compute_field() 48 | 49 | assert field[6] == 1.2 * (2 + 0.5) 50 | assert field[7] == 2.3 * 0.5 51 | 52 | 53 | def test_zeeman_energy(): 54 | 55 | mu0 = 4 * np.pi * 1e-7 56 | # A system of 8 cells ( not using nm units) 57 | mesh = CuboidMesh(dx=2, dy=2, dz=2, 58 | nx=2, ny=2, nz=2 59 | ) 60 | 61 | sim = Sim(mesh) 62 | Ms = 1e5 63 | sim.set_Ms(Ms) 64 | 65 | sim.set_m((0, 0, 1)) 66 | 67 | H = 0.1 / mu0 68 | zeeman = Zeeman((0, 0, H)) 69 | sim.add(zeeman) 70 | 71 | field = zeeman.compute_field() 72 | zf = sim.get_interaction('Zeeman') 73 | 74 | # -> -> 75 | # Expected energy: Int ( -mu0 M * H ) dV 76 | # Since we have 8 cells with the same M, we just sum their contrib 77 | exp_energy = 8 * (-mu0 * H * Ms * mesh.dx * mesh.dy * mesh.dz) 78 | 79 | assert np.abs(zf.compute_energy() - exp_energy) < 1e-10 80 | 81 | 82 | if __name__ == "__main__": 83 | test_zeeman() 84 | test_H0_is_indexable_or_callable() 85 | test_zeeman_energy() 86 | --------------------------------------------------------------------------------