def field(self, state, x=None, lump=True): cache = self._assemble_cache if cache.requires_update(state): u = TrialFunction(state.FunctionSpace()) w = TestFunction(state.VectorFunctionSpace()) cache.A = assemble(-state.material.ms * inner(grad(u), w) * state.dx("magnetic")) with Timer("Demag Field"): return super(DemagField, self).field( state, x, lump, lambda state: cache.A * self.u(state).vector())
def field(self, state, x=None, lump=True): cache = self._assemble_cache if cache.requires_update(state): m = TrialFunction(state.VectorFunctionSpace()) w = TestFunction(state.VectorFunctionSpace()) cache.A = assemble( self._f(state) * Dx(m[i], j) * Dx(w[i], j) / Constants.gamma * state.dx("magnetic")) with Timer("Exchange Field"): return super(ExchangeField, self).field(state, x, lump, lambda state: cache.A * state.m.vector())
def u(self, state): """ Calculate the demagnetization-field potential u for a given simulation state *Arguments* state (:class:`State`) The simulation state """ cache = self._result_cache if cache.requires_update(state): with Timer("Demag Potential"): cache.u = self.solver.calculate(state, state.m) return cache.u
def step(self, state, dt): """ Calculate :math:`\\vec{s}(t+\Delta t)` for a given timestep. *Arguments* state (:class:`State`) The simulation state. dt (:class:`float`) The time-step size. """ with Timer("Spin-Diffusion Step"): # regions Omega = 'conducting' omega = 'magnetic' # Functions Spaces ... VV = state.VectorFunctionSpace() s = TrialFunction(VV) # s_i+1 zeta = TestFunction(VV) # zeta D0x2 = state.material.D0 * Constant(2.0) beta = state.material.beta beta_prime = state.material.beta_prime lambda_sf = state.material.lambda_sf lambda_j = state.material.lambda_j grad = lambda x: transpose(nabla_grad(x)) n = FacetNormal(state.mesh) # Forms a = inner(s, zeta) / Constant(dt) * state.dx(Omega) \ + D0x2 / Constant(state.scale**2) * inner(grad(s), grad(zeta)) * state.dx(Omega) \ - D0x2 / Constant(state.scale**2) * beta * beta_prime * inner(outer(state.m, transpose(grad(s)) * state.m), grad(zeta)) * state.dx(omega) \ + D0x2 / lambda_sf**2 * inner(s, zeta) * state.dx(Omega) \ + D0x2 / lambda_j**2 * inner(cross(s, state.m), zeta) * state.dx(omega) L = inner(state.s, zeta) / Constant(dt) * state.dx(Omega) \ + beta * Constant(Constants.mu_b / Constants.e / state.scale) * inner(outer(state.m, state.j), grad(zeta)) * state.dx(omega) \ - beta * Constant(Constants.mu_b / Constants.e / state.scale) * inner(state.m, zeta) * inner(state.j, n) * state.ds('outermagnet') # Solve system A, b = assemble_system(a, L) s = Function(state.VectorFunctionSpace()) solver = KrylovSolver(A, "gmres", "ilu") solver.solve(s.vector(), b) state.s = s
def step(self, state, dt): """ Calculate :math:`\\vec{m}(t+\Delta t)` for a given timestep. *Arguments* state (:class:`State`) The magnetization configuration. dt (:class:`float`) The time-step size. """ with Timer("LLG Step"): v = self.calculate_v(state, dt) state.m.vector().axpy(dt, v.vector()) # NOTE state.update_uuid() is not called, because normlize does the job state.m.normalize()
def field(self, state, x = None, lump = True): with Timer("Spin Torque"): return super(SpinTorque, self).field(state, x, lump)
def field(self, state, x = None, lump = True): with Timer("Uniaxial Anisotropy Field"): return super(UniaxialAnisotropyField, self).field(state, x, lump)
def field(self, state, x = None, lump = False): with Timer("Spin Torque Zhang&Li"): return super(SpinTorqueZhangLi, self).field(state, x, lump)
def calculate_v(self, state, dt): """ Calculate :math:`\\vec{v}` according to the algorithm introduced above. *Arguments* state (:class:`State`) The simulation state containing the magnetization configuration. dt (:class:`float`) The time-step size. """ with Timer("Calculate v"): # Initialize mesh and function spaces VV = state.VectorFunctionSpace() VS = state.FunctionSpace() v = TrialFunction(VV) w = TestFunction(VV) ####################################################### # Forms ####################################################### f_ex = Constant(-2.0 / state.scale**2 * Constants.gamma / Constants.mu0) \ * state.material.Aex / state.material.ms # Bilinear form for LLG a = state.material.alpha * dot(v, w) * state.dx('magnetic') a += dot(cross(state.m, v), w) * state.dx('magnetic') L = zero() # Effective field contributions for term in self.terms: L += term.form_rhs(state, w) * state.dx('magnetic') a += term.form_lhs( state, w, Constant(0.5 * dt) * v) * state.dx('magnetic') ####################################################### # Assembly ####################################################### # System to solve: # (1 - B^t B) A x = (1 - B^t B) b class ProjectionOperator(LinearOperator): def __init__(self, A, BTB, u): LinearOperator.__init__(self, u.vector(), u.vector()) self._A = A self._BTB = BTB def size(self): return self._A.size(0) def mult(self, x, y): self._BTB.transpmult(-self._A * x, y) y.axpy(1.0, self._A * x) A = assemble(a, keep_diagonal=True) A.ident_zeros() v = TestFunction(state.VectorFunctionSpace()) u = TrialFunction(state.VectorFunctionSpace()) BTB = assemble(inner(state.m, v) * inner(state.m, u) * dP) b = assemble(L) b.axpy(-1.0, BTB * b) v = Function(VV) Op = ProjectionOperator(A, BTB, v) with Timer("Solve"): solve(Op, v.vector(), b, "gmres") return v
def calculate_v(self, state, dt): """ Calculate :math:`\\vec{v}` according to the algorithm introduced above. *Arguments* state (:class:`State`) The simulation state containing the magnetization configuration. dt (:class:`float`) The time-step size. """ with Timer("Calculate v"): # Initialize mesh and function spaces VV = state.VectorFunctionSpace() VS = state.FunctionSpace() v = TrialFunction(VV) w = TestFunction(VV) ####################################################### # Forms ####################################################### f_ex = Constant(-2.0 / state.scale**2 * Constants.gamma / Constants.mu0) \ * state.material.Aex / state.material.ms # Bilinear form for LLG a = state.material.alpha * dot(v, w) * state.dx('magnetic') a += dot(cross(state.m, v), w) * state.dx('magnetic') L = zero() # Effective field contributions for term in self.terms: L += term.form_rhs(state, w) * state.dx('magnetic') a += term.form_lhs( state, w, Constant(0.5 * dt) * v) * state.dx('magnetic') ####################################################### # Assembly ####################################################### # assemble llg A = assemble(a, keep_diagonal=True) A.ident_zeros() b = assemble(L) # assemble constraint #B = DofAssembler.assemble(ScalarProductMatrix(VS, VV, state.m)) #BT = DofAssembler.assemble(TransScalarProductMatrix(VS, VV, state.m)) v = TestFunction(state.FunctionSpace()) u = TrialFunction(state.VectorFunctionSpace()) B = assemble(v * dot(state.m, u) * dP) v = TestFunction(state.VectorFunctionSpace()) u = TrialFunction(state.FunctionSpace()) BT = assemble(u * dot(state.m, v) * dP) # assemble block matrix AA = block_mat([[A, BT], [B, 0]]) bb = block_vec([b, BT.create_vec()]) Ap = ILU(A) Bp = InvDiag(collapse(B * LumpedInvDiag(A) * BT)) AAp = block_mat([[Ap, BT], [0, -Bp]]).scheme('sgs') ####################################################### # Solve the system ####################################################### AAinv = BiCGStab(AA, precond=AAp, tolerance=1e-8 / dt) u, foo = AAinv * bb v = Function(VV) v.vector()[:] = u return v
def calculate_v(self, state, dt): """ Calculate :math:`\\vec{v}` according to the algorithm introduced above. *Arguments* state (:class:`State`) The simulation state containing the magnetization configuration. dt (:class:`float`) The time-step size. """ with Timer("Calculate v"): cache = self._assemble_cache if cache.requires_update(state): if isinstance(state.mesh, WrappedMesh): raise Exception("Use simple mesh with shell instead of WrappedMesh.") # setup function spaces cache.VV = VectorFunctionSpace(state.mesh, "CG", 1) cache.VD = FunctionSpace(state.mesh, "CG", self.demag_order) cache.VL = FunctionSpace(state.mesh, "CG", 1) # setup some stuff for the demag field transformation_order = 2 if (self.demag_order == 1) else 2 shell_width = state.mesh.coordinates().max(axis=0).min() / 2.0 sample_size = state.mesh.coordinates().max(axis=0) - shell_width cache.gx = MetricMatrix.create_for_cube(sample_size, 0, transformation_order) cache.gy = MetricMatrix.create_for_cube(sample_size, 1, transformation_order) cache.gz = MetricMatrix.create_for_cube(sample_size, 2, transformation_order) # Test and Trial Functions u = TrialFunction(cache.VD) v = TrialFunction(cache.VV) sigma = TrialFunction(cache.VL) w1 = TestFunction(cache.VD) w2 = TestFunction(cache.VV) w3 = TestFunction(cache.VL) ####################################################### # Define weak forms ####################################################### f_ex = (- 2.0 * state.material.Aex * Constants.gamma) / \ (Constants.mu0 * state.material.ms * state.scale**2) # Bilinear form a12 = - 0.5 * Constant(dt) * inner(v, grad(w1)) * state.dx('magnetic') # Demag Field, Implicit RHS a11 = inner(grad(w1), grad(u)) * state.dx('all') \ + inner(grad(w1), grad(u)) * state.dx(1000) \ + inner(grad(w1), cache.gx * grad(u)) * state.dx(1001) \ + inner(grad(w1), cache.gy * grad(u)) * state.dx(1002) \ + inner(grad(w1), cache.gz * grad(u)) * state.dx(1003) a21 = - Constant(state.material.ms * Constants.gamma) * inner(grad(u), w2) * state.dx('magnetic') # Demag a22 = Constant(state.material.alpha) * dot(v, w2) * state.dx('magnetic') # LLG a22 += dot(cross(state.m, v), w2) * state.dx('magnetic') a22 += - 0.5 * Constant(dt * f_ex) * Dx(v[i],j) * Dx(w2[i],j) * state.dx('magnetic') # Exchange # Linear form L1 = inner(state.m, grad(w1)) * state.dx('magnetic') # Demag Field L2 = Constant(f_ex) * Dx(state.m[i],j) * Dx(w2[i],j) * state.dx('magnetic') # Exchange for term in self.terms: # Additional Terms L2 += term.form_rhs(state, w2) * state.dx('magnetic') #a22 += term.form_lhs(state, w2, Constant(0.5 * dt) * v) * state.dx('magnetic') ####################################################### # Define boundary conditions ####################################################### bc1 = DirichletBC(cache.VD, Constant(0.0), DomainBoundary()) ####################################################### # Assemble the system ####################################################### A11, b1 = assemble_system(a11, L1, bc1) A12 = assemble(a12) A21 = assemble(a21) A22 = assemble(a22, keep_diagonal=True); A22.ident_zeros() v23 = TestFunction(state.VectorFunctionSpace()) u23 = TrialFunction(state.FunctionSpace()) A23 = assemble(u23 * dot(state.m, v23) * dP) v32 = TestFunction(state.FunctionSpace()) u32 = TrialFunction(state.VectorFunctionSpace()) A32 = assemble(v32 * dot(state.m, u32) * dP) #A23 = DofAssembler.assemble(TransScalarProductMatrix(cache.VL, cache.VV, state.m)) #A32 = DofAssembler.assemble(ScalarProductMatrix(cache.VL, cache.VV, state.m)) b2 = assemble(L2) ####################################################### # Schur Ansatz ####################################################### A11p = ILU(A11) A11inv = ConjGrad(A11, precond=A11p) z1 = A11inv * b1 S11 = A22 - A21 * A11inv * A12 S = block_mat([[S11, A23], [A32, 0]]) Sp11 = ILU(A22) Sp22 = InvDiag(collapse(A32 * LumpedInvDiag(A22) * A23)) Sp = block_mat([[Sp11, A23], [0, -Sp22]]).scheme('sgs') Sinv = BiCGStab(S, precond=Sp, tolerance=1e-8/dt) b = block_vec([b2 - A21*z1, 0]) v, _ = Sinv * b return Function(cache.VV, v)