def use_zhangli(self, J_profile=(1e10, 0, 0), P=0.5, beta=0.01, using_u0=False, with_time_update=None): """ if using_u0 = True, the factor of 1/(1+beta^2) will be dropped. With with_time_update should be a function like: def f(t): return (0, 0, J*g(t)) We do not use a position dependent function for performance reasons. """ self.do_zhangli = True self.fun_zhangli_time_update = with_time_update self._J = helpers.vector_valued_function(J_profile, self.S3) self.J = self._J.vector().array() self.compute_gradient_matrix() self.H_gradm = df.PETScVector() const_e = 1.602176565e-19 # elementary charge in As mu_B = 9.27400968e-24 # Bohr magneton self.P = P self.beta = beta u0 = P * mu_B / const_e # P g mu_B/(2 e Ms) and g=2 for electrons if using_u0: self.u0 = u0 else: self.u0 = u0 / (1 + beta ** 2)
def test_dmi_pbc2d_1D(plot=False): def m_init_fun(p): if p[0] < 10: return [0.5, 0, 1] else: return [-0.5, 0, -1] mesh = df.RectangleMesh(df.Point(0, 0), df.Point(20, 2), 10, 1) m_init = vector_valued_function(m_init_fun, mesh) Ms = 8.6e5 sim = Simulation(mesh, Ms, pbc='2d', unit_length=1e-9) sim.set_m(m_init_fun) A = 1.3e-11 D = 5e-3 sim.add(Exchange(A)) sim.add(DMI(D)) sim.relax(stopping_dmdt=0.0001) if plot: sim.m_field.plot_with_dolfin() mx = [sim.m_field.probe([x + 0.5, 1])[0] for x in range(20)] assert np.max(np.abs(mx)) < 1e-6
def use_zhangli(self, J_profile=(1e10, 0, 0), P=0.5, beta=0.01, using_u0=False, with_time_update=None): self.zhangli_stt = True self.fun_zhangli_time_update = with_time_update self.P = P self.beta = beta self._J = helpers.vector_valued_function(J_profile, self.S3) self.J = self._J.vector().array() self.compute_gradient_matrix() self.H_gradm = df.PETScVector() self.integrator = native_llb.StochasticLLGIntegratorSTT( self.m, self.m_pred, self._Ms, self._T, self.real_volumes, self._alpha, self.P, self.beta, self.stochastic_update_field, self.method) # seems that in the presence of current, the time step have to very # small self.dt = 1e-14
def set_parameters(self, J_profile=(1e10, 0, 0), P=0.5, D=2.5e-4, lambda_sf=5e-9, lambda_J=1e-9, speedup=1): self._J = helpers.vector_valued_function(J_profile, self.S3) self.J = self._J.vector().array() self.compute_gradient_matrix() self.H_gradm = df.PETScVector() self.P = P self.D = D / speedup self.lambda_sf = lambda_sf self.lambda_J = lambda_J self.tau_sf = lambda_sf**2 / D * speedup self.tau_sd = lambda_J**2 / D * speedup self.compute_laplace_matrix() self.H_laplace = df.PETScVector() self.nodal_volume_S3 = nodal_volume(self.S3)
def run_measurements(m, mesh, unit_length, tol, repetitions=10, H_expected=None, name="", skip=[]): S3 = df.VectorFunctionSpace(mesh, "CG", 1) m = vector_valued_function(m, S3) Ms = 1 bem, boundary_to_global = compute_bem_fk(df.BoundaryMesh(mesh, 'exterior', False)) if H_expected is not None: H = vector_valued_function(H_expected, S3) H_expected = H.vector().array() else: # use default/default as reference then. demag = fk.FKDemag() demag.precomputed_bem(bem, boundary_to_global) demag.setup(S3, m, Ms, unit_length) H_expected = demag.compute_field() del(demag) if name == "": pass else: name = name + "_" runner = create_measurement_runner(S3, m, Ms, unit_length, H_expected, tol, repetitions, bem, boundary_to_global) solvers = [s[0] for s in df.krylov_solver_methods()] preconditioners = [p[0] for p in df.krylov_solver_preconditioners()] results_1, failed_1 = runner("first linear solve", "phi_1_solver", solvers, "phi_1_preconditioner", preconditioners, skip, "{}timings_log_1.txt".format(name), "{}results_1.pickled".format(name)) results_2, failed_2 = runner("second linear solve", "phi_2_solver", solvers, "phi_2_preconditioner", preconditioners, skip, "{}timings_log_2.txt".format(name), "{}results_2.pickled".format(name)) return solvers, preconditioners, results_1, failed_1, results_2, failed_2
def run_demag_benchmark(m, mesh, unit_length, tol, repetitions=10, name="bench", H_expected=None): S3 = df.VectorFunctionSpace(mesh, "CG", 1) m = vector_valued_function(m, S3) Ms = 1 # pre-compute BEM to save time bem, boundary_to_global = compute_bem_fk( df.BoundaryMesh(mesh, 'exterior', False)) if H_expected is not None: H = vector_valued_function(H_expected, S3) H_expected = H.vector().array() else: # if no H_expected was passed, use default/default as reference demag = fk.FKDemag() demag.precomputed_bem(bem, boundary_to_global) demag.setup(S3, m, Ms, unit_length) H_expected = demag.compute_field() del (demag) # gather all solvers and preconditioners solvers = [s[0] for s in df.krylov_solver_methods()] preconditioners = [p[0] for p in df.krylov_solver_preconditioners()] benchmark = prepare_benchmark(S3, m, Ms, unit_length, H_expected, tol, repetitions, bem, boundary_to_global) results_1 = benchmark("first linear solve", "phi_1_solver", solvers, "phi_1_preconditioner", preconditioners, name=name + "_1") results_2 = benchmark("second linear solve", "phi_2_solver", solvers, "phi_2_preconditioner", preconditioners, name=name + "_2") return solvers, preconditioners, results_1, results_2
def solve(self, t): # we don't use self.effective_field.compute(t) for performance reasons self.effective_field.update(t) H_eff = self.effective_field.H_eff[self.v2d_xxx] # alias (for readability) H_eff.shape = (3, -1) timer.start("solve", self.__class__.__name__) # Use the same characteristic time as defined by c char_time = 0.1 / self.c # Prepare the arrays in the correct shape m = self._m_field.get_ordered_numpy_array_xxx() m.shape = (3, -1) dmdt = np.zeros(m.shape) alpha__ = self.alpha.vector().array()[self.v2d_scale] # Calculate dm/dt if self.do_slonczewski: if self.fun_slonczewski_time_update != None: J_new = self.fun_slonczewski_time_update(t) self.J[:] = J_new native_llg.calc_llg_slonczewski_dmdt( m, H_eff, t, dmdt, self.pins, self.gamma, alpha__, char_time, self.Lambda, self.epsilonprime, self.J, self.P, self.d, self._Ms, self.p) elif self.do_zhangli: if self.fun_zhangli_time_update != None: J_profile = self.fun_zhangli_time_update(t) self._J = helpers.vector_valued_function(J_profile, self.S3) self.J = self._J.vector().array() self.compute_gradient_matrix() H_gradm = self.compute_gradient_field() H_gradm.shape = (3, -1) native_llg.calc_llg_zhang_li_dmdt( m, H_eff, H_gradm, t, dmdt, self.pins, self.gamma, alpha__, char_time, self.u0, self.beta, self._Ms) H_gradm.shape = (-1,) else: native_llg.calc_llg_dmdt(m, H_eff, t, dmdt, self.pins, self.gamma, alpha__, char_time, self.do_precession) dmdt.shape = (-1,) H_eff.shape = (-1,) timer.stop("solve", self.__class__.__name__) self._dmdt.vector().set_local(dmdt[self.d2v_xxx]) return dmdt
def three_dimensional_problem(): x_max = 10e-9 y_max = 1e-9 z_max = 1e-9 mesh = df.BoxMesh(df.Point(0, 0, 0), df.Point(x_max, y_max, z_max), 40, 2, 2) V = df.VectorFunctionSpace(mesh, 'Lagrange', 1) Ms = 8.6e5 m0_x = "pow(sin(0.2*x[0]*1e9), 2)" m0_y = "0" m0_z = "pow(cos(0.2*x[0]*1e9), 2)" m = Field(V, value=vector_valued_function((m0_x, m0_y, m0_z), V, normalise=True)) C = 1.3e-11 u_exch = Exchange(C) u_exch.setup(m, Field(df.FunctionSpace(mesh, 'DG', 0), Ms)) finmag_exch = u_exch.compute_field() magpar_result = os.path.join(MODULE_DIR, 'magpar_result', 'test_exch') nodes, magpar_exch = magpar.get_field(magpar_result, 'exch') ## Uncomment the line below to invoke magpar to compute the results, ## rather than using our previously saved results. # nodes, magpar_exch = magpar.compute_exch_magpar(m, A=C, Ms=Ms) print magpar_exch # Because magpar have changed the order of the nodes!!! tmp = df.Function(V) tmp_c = mesh.coordinates() mesh.coordinates()[:] = tmp_c * 1e9 finmag_exch, magpar_exch, \ diff, rel_diff = magpar.compare_field( mesh.coordinates(), finmag_exch, nodes, magpar_exch) return dict(m0=m.get_numpy_array_debug(), mesh=mesh, exch=finmag_exch, magpar_exch=magpar_exch, diff=diff, rel_diff=rel_diff)
def set_m(self, value, normalise=True, **kwargs): """ Set the magnetisation (if `normalise` is True, it is automatically normalised to unit length). `value` can have any of the forms accepted by the function 'finmag.util.helpers.vector_valued_function' (see its docstring for details). You can call this method anytime during the simulation. However, when providing a numpy array during time integration, the use of the attribute m instead of this method is advised for performance reasons and because the attribute m doesn't normalise the vector. """ self.m = helpers.vector_valued_function(value, self.S3, normalise=normalise, **kwargs).vector().array()
def setup(self, m, Ms, unit_length=1): self.m = m self.Ms = Ms self.unit_length = unit_length if self.scalar_df_expression: dofmap = m.functionspace.dofmap() self.S1 = df.FunctionSpace( m.mesh(), "Lagrange", 1, constrained_domain=dofmap.constrained_domain) self.h0 = helpers.scalar_valued_function(self.df_expression, self.S1).vector().array() self.H0 = df.Function(m.functionspace) else: self.H0 = helpers.vector_valued_function(self.df_expression, self.m.functionspace) self.E = -mu0 * self.Ms.f * df.dot(self.m.f, self.H0) self.H_init = self.H0.vector().array() self.H = self.H_init.copy()
def set_m(self, value, normalise=True, **kwargs): """ Set the magnetisation (if `normalise` is True, it is automatically normalised to unit length). `value` can have any of the forms accepted by the function 'finmag.util.helpers.vector_valued_function' (see its docstring for details). You can call this method anytime during the simulation. However, when providing a numpy array during time integration, the use of the attribute m instead of this method is advised for performance reasons and because the attribute m doesn't normalise the vector. """ m0 = helpers.vector_valued_function(value, self.S3, normalise=False, **kwargs).vector().array()[self.v2d_xxx] if np.any(np.isnan(m0)): raise ValueError("Attempting to initialise m with NaN(s)") if normalise: m0 = helpers.fnormalise(m0) self._m_field.set_with_ordered_numpy_array_xxx(m0)
def set_m(self, value, normalise=True): m_tmp = helpers.vector_valued_function( value, self.S3, normalise=normalise).vector().array() self._m_field.set_with_numpy_array_debug(m_tmp) self.m[:] = self._m_field.get_numpy_array_debug()
def set_M(self, value, **kwargs): self._M = helpers.vector_valued_function(value, self.S3, normalise=False) self.M[:]=self._M.vector().array()[:]
def get_dolfin_function(self, interaction_name, region=None): interaction = self.get(interaction_name) return vector_valued_function(interaction.compute_field(), self.m_field.functionspace)