def test_hysteresis(tmpdir): os.chdir(str(tmpdir)) sim = barmini() mesh = df.BoxMesh(df.Point(0, 0, 0), df.Point(1, 1, 1), 1, 1, 1) H_ext_list = [(1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0)] N = len(H_ext_list) # Run a relaxation and save a vtk snapshot at the end of each stage; # this should result in three .vtu files (one for each stage). sim1 = sim_with(mesh, Ms=1e6, m_init=(0.8, 0.2, 0), alpha=1.0, unit_length=1e-9, A=None, demag_solver=None) sim1.schedule('save_vtk', at_end=True, filename='barmini_hysteresis.pvd') res1 = sim1.hysteresis(H_ext_list=H_ext_list) assert (len(glob('barmini_hysteresis*.vtu')) == N) assert (res1 == None) # Run a relaxation with a non-trivial `fun` argument and check # that we get a list of return values. sim2 = sim_with(mesh, Ms=1e6, m_init=(0.8, 0.2, 0), alpha=1.0, unit_length=1e-9, A=None, demag_solver=None) res2 = sim2.hysteresis(H_ext_list=H_ext_list, fun=lambda sim: sim.m_average[0]) assert (len(res2) == N)
def demo1(): # create example simulation import finmag import dolfin as df xmin, ymin, zmin = 0, 0, 0 # one corner of cuboid xmax, ymax, zmax = 6, 6, 11 # other corner of cuboid nx, ny, nz = 3, 3, 6 # number of subdivisions (use ~2nm edgelength) mesh = df.BoxMesh(df.Point(xmin, ymin, zmin), df.Point(xmax, ymax, zmax), nx, ny, nz) # standard Py parameters sim = finmag.sim_with(mesh, Ms=0.86e6, alpha=0.5, unit_length=1e-9, A=13e-12, m_init=(1, 0, 1)) filename = 'data.txt' ndt = Tablewriter(filename, sim, override=True) times = np.linspace(0, 3.0e-11, 6 + 1) for i, time in enumerate(times): print("In iteration {}, computing up to time {}".format(i, time)) sim.run_until(time) ndt.save() # now open file for reading f = Tablereader(filename) print f.timesteps() print f['m_x']
def bar(name='bar', demag_solver_type=None): """Py bar with dimensions 30x30x100nm, initial field pointing in (1,0,1) direction. Same as example 2 in Nmag manual. This function returns a simulation object that is 'ready to go'. Useful commands to run this for a minute:: times = numpy.linspace(0, 3.0e-11, 6 + 1) for t in times: # Integrate sim.run_until(t) """ xmin, ymin, zmin = 0, 0, 0 # one corner of cuboid xmax, ymax, zmax = 30, 30, 100 # other corner of cuboid # number of subdivisions (use ~2nm edgelength) nx, ny, nz = 15, 15, 50 mesh = df.BoxMesh(df.Point(xmin, ymin, zmin), df.Point(xmax, ymax, zmax), nx, ny, nz) sim = finmag.sim_with(mesh, Ms=0.86e6, alpha=0.5, unit_length=1e-9, A=13e-12, m_init=(1, 0, 1), name=name, demag_solver_type=demag_solver_type) return sim
def macrospin_box(Ms=0.86e6, m_init=(1, 0, 0), H_ext=(0, 0, 1e6), alpha=0.1, name='macrospin'): """ Cubic mesh of length 1 nm along each edge, with eight vertices located in the corners of the cube. No anisotropy, exchange coupling or demag is present so that magnetic moments at the vertices behave identical under the influence of the external field. Default values for the arguments: Ms = 0.86e6 (saturation magnetisation in A/m) m_init = (1, 0, 0) (initial magnetisation pointing along the x-axis) H_ext = (0, 0, 1e6) (external field in A/m) alpha = 0.1 (Gilbert damping coefficient) """ mesh = df.BoxMesh(df.Point(0, 0, 0), df.Point(1, 1, 1), 1, 1, 1) sim = sim_with(mesh, Ms=0.86e6, alpha=alpha, unit_length=1e-9, A=None, H_ext=H_ext, m_init=(1, 0, 0), name=name) return sim
def test_Table_writer_and_reader(tmpdir): os.chdir(str(tmpdir)) import finmag import dolfin as df xmin, ymin, zmin = 0, 0, 0 # one corner of cuboid xmax, ymax, zmax = 6, 6, 11 # other corner of cuboid nx, ny, nz = 3, 3, 6 # number of subdivisions (use ~2nm edgelength) mesh = df.BoxMesh(df.Point(xmin, ymin, zmin), df.Point(xmax, ymax, zmax), nx, ny, nz) # standard Py parameters sim = finmag.sim_with(mesh, Ms=0.86e6, alpha=0.5, unit_length=1e-9, A=13e-12, m_init=(1, 0, 1)) filename = 'test-save_averages-data.ndt' ndt = Tablewriter(filename, sim) times = np.linspace(0, 3.0e-11, 6 + 1) for i, time in enumerate(times): print("In iteration {}, computing up to time {}".format(i, time)) sim.run_until(time) ndt.save() # now open file for reading data = Tablereader(filename) print data.timesteps() - times print("III") assert np.all(np.abs(data.timesteps() - times)) < 1e-25 mx, my, mz = sim.m_average assert abs(data['m_x'][-1] - mx) < 1e-11 assert abs(data['m_y'][-1] - my) < 1e-11 assert abs(data['m_z'][-1] - mz) < 1e-11 # Try reading multiple columns at once by indexing 'data' # with multiple indices (in the assert statement). dmx = data['m_x'] dmy = data['m_y'] dmz = data['m_z'] dm = np.vstack([dmx, dmy, dmz]).T # stack the arrays together assert np.allclose(dm, np.array(data['m_x', 'm_y', 'm_z']).T) # Reading an incomplete dataset should raise a runtime error with pytest.raises(RuntimeError): Tablereader(os.path.join(MODULE_DIR, 'test-incomplete-data.ndt'))
def test_get_interaction_list(): # has bar mini example Demag and Exchange? s = finmag.example.barmini() lst = s.get_interaction_list() assert 'Exchange' in lst assert 'Demag' in lst assert len(lst) == 2 # Let's remove one and ceck again s.remove_interaction('Exchange') assert s.get_interaction_list() == ['Demag'] # test simulation with no interaction s2 = finmag.sim_with(mesh=dolfin.IntervalMesh(10, 0, 1), m_init=(1, 0, 0), Ms=1, demag_solver=None, unit_length=1e-8) assert s2.get_interaction_list() == []
def barmini(name='barmini', mark_regions=False, demag_solver_type=None): """Py bar with dimensions 3x3x10nm, initial field pointing in (1,0,1) direction. Same as example 2 in Nmag manual, but much smaller (and faster). This function returns a simulation object that is 'ready to go'. If `mark_regions` is True, the mesh will be subdivided vertically into two regions which are markes as 'top' and 'bottom'. Useful commands to run this for a couple of seconds: times = numpy.linspace(0, 3.0e-11, 6 + 1) for t in times: # Integrate sim.run_until(t) """ xmin, ymin, zmin = 0, 0, 0 # one corner of cuboid xmax, ymax, zmax = 3, 3, 10 # other corner of cuboid # number of subdivisions (use ~2nm edgelength) nx, ny, nz = 2, 2, 4 mesh = df.BoxMesh(df.Point(xmin, ymin, zmin), df.Point(xmax, ymax, zmax), nx, ny, nz) sim = finmag.sim_with(mesh, Ms=0.86e6, alpha=0.5, unit_length=1e-9, A=13e-12, m_init=(1, 0, 1), name=name, demag_solver_type=demag_solver_type) if mark_regions: def fun_regions(pt): return 'bottom' if (pt[2] <= 5.0) else 'top' sim.mark_regions(fun_regions) return sim
def setup_class(cls): """ Create a box mesh and a simulation object on this mesh which will be used to compute Zeeman energies in the individual tests. """ # The mesh and simulation are only created once for the entire # test class and are re-used in each test method for efficiency. cls.Lx, cls.Ly, cls.Lz = 100, 30, 10 nx, ny, nz = 30, 10, 5 mesh = df.BoxMesh(0, 0, 0, cls.Lx, cls.Ly, cls.Lz, nx, ny, nz) unit_length = 1e-9 cls.mesh_vol = cls.Lx * cls.Ly * cls.Lz * unit_length**3 cls.S3 = df.VectorFunctionSpace(mesh, 'CG', 1, dim=3) # The values for Ms and m_init are arbitrary as they will be # ovewritten in the tests. cls.sim = sim_with(mesh, Ms=1, m_init=(1, 0, 0), demag_solver=None, unit_length=unit_length)
def test_hysteresis_loop_and_plotting(tmpdir): """ Call the hysteresis loop with various combinations for saving snapshots and check that the correct number of vtk files have been produced. Also check that calling the plotting function works (although the output image isn't verified). """ os.chdir(str(tmpdir)) mesh = df.BoxMesh(df.Point(0, 0, 0), df.Point(1, 1, 1), 1, 1, 1) sim = sim_with(mesh, Ms=1e6, m_init=(0.8, 0.2, 0), alpha=1.0, unit_length=1e-9, A=None, demag_solver=None) H_vals, m_vals = \ sim.hysteresis_loop(H, initial_direction, N, stopping_dmdt=10) # Check that the magnetisation values are as trivial as we expect # them to be ;-) assert (np.allclose(m_vals, [1.0 for _ in xrange(2 * N)], atol=1e-4)) # This only tests whether the plotting function works without # errors. It currently does *not* check that it produces # meaningful results (and the plot is quite boring for the system # above anyway). plot_hysteresis_loop(H_vals, m_vals, infobox=["param_A = 23", ("param_B", 42)], title="Hysteresis plot test", xlabel="H_ext", ylabel="m_avg", figsize=(5, 4), infobox_loc="bottom left", filename='test_plot.pdf') # Test multiple filenames, too plot_hysteresis_loop(H_vals, m_vals, filename=['test_plot.pdf', 'test_plot.png'])
def nanowire(lx=100, ly=10, lz=3, nx=30, ny=3, nz=1, name='nanowire'): """ Permalloy nanowire with head-to-head domain wall. The nanowire has dimensions lx, ly, lz and discretization nx, ny, nz along the three coordinate axes. """ A = 13e-12 Ms = 8e5 mesh = df.BoxMesh(df.Point(0, 0, 0), df.Point(lx, ly, lz), nx, ny, nz) S1 = df.FunctionSpace(mesh, 'CG', 1) S3 = df.VectorFunctionSpace(mesh, 'CG', 1, dim=3) def m_init_fun(pt): x, y, z = pt return [cos(x*pi/lx), sin(x*pi/lx), 0] sim = finmag.sim_with(mesh, Ms=Ms, m_init=m_init_fun, unit_length=1e-9, A=A) return sim
def test_airbox_method(): """ Define a mesh with two regions (Permalloy and 'air'), where the Permalloy region is e.g. a sphere of radius 1.0 and the 'air' region is a cube with sides of length 10. Next set Ms in both regions, where Ms in the 'air' region is either zero or has a very low value. Then run the simulation and and check that the value of the external field in the 'air' region coincides with the field of a dipole. """ mesh = from_geofile("mesh.geo") mesh_region = df.MeshFunction("uint", mesh, "mesh_mat.xml") # Visualise mesh regions to check they look right (this will be # removed in the final test). #plot_mesh_regions(mesh_region, regions=[1, 2], colors=["green", "red"], # alphas=[1.0, 0.25]) #plt.show() # Define different values for Ms on each subdomain Ms_vals = (8.6e5, 0) Ms = piecewise_on_subdomains(mesh, mesh_region, Ms_vals) sim = sim_with(mesh, Ms=Ms, m_init=(1.0, 0.0, 0), alpha=1.0, unit_length=1e-9, A=13.0e-12, demag_solver='FK') print "Computing effective field..." H_eff = sim.effective_field() print "Computed field: {}".format(H_eff) sim.relax(save_snapshots=True, save_every=1e-11, filename="snapshots/snapshot.pvd")
def macrospin_interval(Ms=0.86e6, m_init=(1, 0, 0), H_ext=(0, 0, 1e6), alpha=0.1, name='macrospin'): """ 1d mesh (= interval) with two vertices which are 1 nm apart. No anisotropy, exchange coupling or demag is present so that magnetic moments at the vertices behave identical under the influence of the external field. The damping constant has the value alpha=0.1. Default values for the arguments: Ms = 0.86e6 (saturation magnetisation in A/m) m_init = (1, 0, 0) (initial magnetisation pointing along the x-axis) H_ext = (0, 0, 1e6) (external field in A/m) alpha = 0.1 (Gilbert damping coefficient) """ mesh = df.UnitIntervalMesh() sim = sim_with(mesh, Ms=1e6, m_init=(1, 0, 0), alpha=alpha, unit_length=1e-9, H_ext=H_ext, A=None, demag_solver=None, name=name) return sim
def test_check_Kittel_mode_for_single_sphere(tmpdir, debug=False): """ Compute the eigenmodes of a perfect sphere and check that the frequency of the base mode equals the analytical value from the Kittel equation (see Charles Kittel, "Introduction to solid state physics", 7th edition, Ch. 16, p.505): omega_0 = gamma * B_0 Here omega_0 is the angular frequency, so the actual frequency is equal to omega_0 / (2*pi). """ os.chdir(str(tmpdir)) sphere = Sphere(r=11) mesh = sphere.create_mesh(maxh=2.0) print "[DDD] mesh: {}".format(mesh) print mesh_info(mesh) if debug: plot_mesh_with_paraview(mesh, outfile='mesh_sphere.png') H_z = 4.42e5 # slightly odd value to make the test a bit more reliable frequency_unit = 1e9 sim = sim_with(mesh, Ms=1e6, m_init=[ 0, 0, 1], A=13e-12, H_ext=[0, 0, H_z], unit_length=1e-9, demag_solver='FK') sim.relax() A, M, _, _ = compute_generalised_eigenproblem_matrices( sim, alpha=0.0, frequency_unit=1e9) RTOL = 1e-3 n_values = 2 n_values_export = 0 omega, w = compute_normal_modes_generalised( A, M, n_values=n_values, discard_negative_frequencies=False) assert(len(omega) == n_values) # Check that the frequency of the base mode equals the analytical value from the Kittel equation # (see Charles Kittel, "Introduction to solid state physics", 7th edition, Ch. 16, p.505): # # omega_0 = gamma * B_0 # # The frequency is equal to omega_0 / (2*pi). # freq_expected = sim.gamma * H_z / (2 * pi * frequency_unit) assert(np.allclose(omega[0], +freq_expected, atol=0, rtol=RTOL)) assert(np.allclose(omega[1], -freq_expected, atol=0, rtol=RTOL)) logger.debug("Computed eigenfrequencies: {}".format(omega)) logger.debug( "Expected frequency of the Kittel mode: {}".format(freq_expected)) # Perform the same test when negative frequencies are discarded omega_positive, _ = compute_normal_modes_generalised( A, M, n_values=n_values, discard_negative_frequencies=True) logger.debug("[DDD] omega_positive: {}".format(omega_positive)) assert(len(omega_positive) == n_values) assert(np.allclose(omega_positive[0], freq_expected, atol=0, rtol=RTOL)) # Ensure that the frequencies are all positive and sorted by absolute value assert((np.array(omega_positive) > 0).all()) assert(np.allclose(omega_positive, sorted(omega_positive, key=abs))) omega_positive_first_half = omega_positive[:(n_values // 2)] assert(np.allclose(sorted(np.concatenate([omega_positive_first_half, -omega_positive_first_half])), sorted(omega))) # Export normal mode animations for debugging for i in xrange(n_values_export): freq = omega_positive[i] export_normal_mode_animation( sim, freq, w[i], filename='normal_mode_{:02d}__{:.3f}_GHz.pvd'.format(i, freq)) ## # Perform the same test as above but without demag, wich should improve the accuracy. ## sim = sim_with(mesh, Ms=1e6, m_init=[ 0, 0, 1], A=13e-12, H_ext=[0, 0, H_z], unit_length=1e-9, demag_solver=None) sim.relax() A, M, _, _ = compute_generalised_eigenproblem_matrices( sim, alpha=0.0, frequency_unit=1e9) RTOL = 1e-9 omega, _ = compute_normal_modes_generalised( A, M, n_values=1, discard_negative_frequencies=True) logger.debug("Computed eigenfrequencies (without demag): {}".format(omega)) logger.debug( "Expected frequency of the Kittel mode: {}".format(freq_expected)) assert(np.allclose(omega[0], freq_expected, atol=0, rtol=RTOL))
import dolfin as df from numpy import linspace from math import cos, sin, pi from finmag import sim_with from finmag.util.meshes import ellipsoid r1 = 30.0 r2 = 10.0 r3 = 10.0 maxh = 3.0 Ms = 1e6 # A/m A = 13.0e-12 # J/m alpha = 1.0 # large damping for quick convergence H = 1e6 # external field strength in A/m m_init = (1, 0, 0) # Create a few external field values (at 45 degree angles # to each other, sweeping a half-circle). H_ext_list = [(cos(t)*H, sin(t)*H, 0.01*H) for t in linspace(0, pi, 5)] mesh = ellipsoid(r1, r2, r3, maxh) sim = sim_with(mesh, Ms, m_init, alpha=alpha, unit_length=1e-9, A=A, demag_solver='FK') sim.hysteresis(H_ext_list[1:3], filename="snapshots/hysteresis_example/hysteresis_ellipsoid.pvd", save_snapshots=True, save_every=10e-12, force_overwrite=True)