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"): # 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)