|
| 1 | +import numpy as np |
| 2 | +from test_domain_wall_cobalt import setup_domain_wall_cobalt |
| 3 | + |
| 4 | + |
| 5 | +def norm(a): |
| 6 | + return np.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]) |
| 7 | + |
| 8 | + |
| 9 | +def setup_llg_params_near_one(node_count=5, A=3.6 * 4e-7 * np.pi, Ms=6.7e5, K1=4.3, do_precession=True): |
| 10 | + sim = setup_domain_wall_cobalt( |
| 11 | + node_count=node_count, A=A, Ms=Ms, K1=K1, length=1.3, do_precession=do_precession, unit_length=1) |
| 12 | + sim.default_c = 1.23 |
| 13 | + sim.gamma = 1.56 |
| 14 | + sim.alpha = 2.35 |
| 15 | + sim.pins = lambda r: 0 |
| 16 | + sim.set_m((0, 0, 1)) |
| 17 | + return sim, sim.spin |
| 18 | + |
| 19 | + |
| 20 | +def compute_jacobean_fd(sim, m, eps=1): |
| 21 | + # use 4th order FD scheme which should produce an exact result without demag |
| 22 | + # hence set eps to 1 |
| 23 | + n = sim.mesh.n |
| 24 | + print sim.mesh.coordinates |
| 25 | + # compute the jacobean using the finite difference approximation |
| 26 | + jac = np.zeros((3 * n, 3 * n)) |
| 27 | + w = np.array([1. / 12., -2. / 3., 2. / 3., -1. / 12.]) / eps |
| 28 | + once = False |
| 29 | + for j, v in enumerate(np.eye(3 * n)): |
| 30 | + sim.spin[:] = m - 2 * eps * v |
| 31 | + f0 = np.zeros(3 * n) |
| 32 | + sim.sundials_rhs(0, 0, f0) |
| 33 | + sim.spin[:] = m - eps * v |
| 34 | + f1 = np.zeros(3 * n) |
| 35 | + sim.sundials_rhs(0, 0, f1) |
| 36 | + sim.spin[:] = m + eps * v |
| 37 | + f2 = np.zeros(3 * n) |
| 38 | + sim.sundials_rhs(0, 0, f2) |
| 39 | + sim.spin[:] = m + 2 * eps * v |
| 40 | + f3 = np.zeros(3 * n) |
| 41 | + sim.sundials_rhs(0, 0, f3) |
| 42 | + if not once: |
| 43 | + print "m", m |
| 44 | + print "m - 2 * eps * v", m - 2 * eps * v |
| 45 | + print "f0", f0 |
| 46 | + print "f1", f1 |
| 47 | + print "f2", f2 |
| 48 | + print "f3", f3 |
| 49 | + once = True |
| 50 | + jac[:, j] = w[0] * f0 + w[1] * f1 + w[2] * f2 + w[3] * f3 |
| 51 | + return jac |
| 52 | + |
| 53 | + |
| 54 | +def compute_jacobean_jtimes(sim, m): |
| 55 | + # use the jtimes function to compute the jacobean |
| 56 | + n = sim.mesh.n |
| 57 | + jac = np.zeros((3 * n, 3 * n)) |
| 58 | + tmp = np.zeros(m.shape) |
| 59 | + fy = np.zeros(m.shape) |
| 60 | + jtimes = np.zeros(m.shape) |
| 61 | + for j, v in enumerate(np.eye(3 * n)): |
| 62 | + # use fy=None since it's not used for the computation |
| 63 | + sim.sundials_jtimes(v, jtimes, 0., m, fy) |
| 64 | + jac[:, j] = jtimes |
| 65 | + return jac |
| 66 | + |
| 67 | + |
| 68 | +def test_compute_fd(): |
| 69 | + sim, m = setup_llg_params_near_one() |
| 70 | + # Jacobian computation should be exact with eps=1 or eps=2 |
| 71 | + assert np.max(np.abs(compute_jacobean_fd(sim, m, eps=1) - compute_jacobean_fd(sim, m, eps=2))) < 1e-13 |
| 72 | + |
| 73 | + |
| 74 | +def test_compute_jtimes(): |
| 75 | + sim, m = setup_llg_params_near_one(node_count=2) |
| 76 | + fd = compute_jacobean_fd(sim, m) |
| 77 | + jtimes = compute_jacobean_jtimes(sim, m) |
| 78 | + print "m" |
| 79 | + print m |
| 80 | + print "FD" |
| 81 | + print fd |
| 82 | + print "JTIMES" |
| 83 | + print jtimes |
| 84 | + assert np.max(np.abs(fd - jtimes)) < 1e-13 |
0 commit comments