class ExchangeField(module.Module): def __init__(self): super(ExchangeField, self).__init__() def calculates(self): return ["H_exch", "E_exch"] def params(self): return ["A"] def properties(self): return {'EFFECTIVE_FIELD_TERM': "H_exch", 'EFFECTIVE_FIELD_ENERGY': "E_exch"} def initialize(self, system): self.system = system self.A = Field(self.system.mesh); self.A.fill(0.0) def calculate(self, state, id): cache = state.cache if id == "H_exch": if hasattr(cache, "H_exch"): return cache.H_exch H_exch = cache.H_exch = VectorField(self.system.mesh) magneto.exchange(state.Ms, state.A, state.M, H_exch) return H_exch elif id == "E_exch": return -MU0 / 2.0 * self.system.mesh.cell_volume * state.M.dotSum(state.H_exch) else: raise KeyError("ExchangeField.calculate: Can't calculate %s", id)
def __update_field(self, state): # Get value of homogeneous field if hasattr(state, self.__value_id): value = getattr(state, self.__value_id) else: if not self.__default_value: raise ValueError("HomogeneousField: Can't initialize field '%s' because no initial value is given!" % self.__var_id) value = self.__default_value # Create field (Field or VectorField) from value try: if isinstance(value, numbers.Number): value = float(value) field = Field(self.__mesh) field.fill(value) elif hasattr(value, "__iter__") and len(value) == 3: value = tuple(map(float, value)) field = VectorField(self.__mesh) field.fill(value) else: raise ValueError except ValueError: raise ValueError("HomogeneousField: Expected scalar value or 3-tuple of scalar values for the 'value' (second) parameter") # Store value and field in state setattr(state, self.__value_id, value) setattr(state, self.__field_id, field) return field
class AnisotropyField(module.Module): def __init__(self): super(AnisotropyField, self).__init__() def calculates(self): return ["H_aniso", "E_aniso"] def params(self): return ["k_uniaxial", "k_cubic", "axis1", "axis2"] def properties(self): return {'EFFECTIVE_FIELD_TERM': "H_aniso", 'EFFECTIVE_FIELD_ENERGY': "E_aniso"} def initialize(self, system): self.system = system self.k_uniaxial = Field(self.system.mesh); self.k_uniaxial.fill(0.0) self.k_cubic = Field(self.system.mesh); self.k_cubic.fill(0.0) self.axis1 = VectorField(self.system.mesh); self.axis1.fill((0.0, 0.0, 0.0)) self.axis2 = VectorField(self.system.mesh); self.axis2.fill((0.0, 0.0, 0.0)) def calculate(self, state, id): if id == "H_aniso": if hasattr(state.cache, "H_aniso"): return state.cache.H_aniso H_aniso = state.cache.H_aniso = VectorField(self.system.mesh) axis1 = self.axis1 axis2 = self.axis2 k_uni = self.k_uniaxial k_cub = self.k_cubic skip_uni = k_uni.isUniform() and k_uni.uniform_value == 0.0 have_uni = not skip_uni skip_cub = k_cub.isUniform() and k_cub.uniform_value == 0.0 have_cub = not skip_cub Ms = self.system.Ms if not have_uni and not have_cub: H_aniso.fill((0.0, 0.0, 0.0)) state.cache.E_aniso_sum = 0.0 elif not have_uni and have_cub: state.cache.E_aniso_sum = magneto.cubic_anisotropy(axis1, axis2, k_cub, Ms, state.M, H_aniso) elif have_uni and not have_cub: state.cache.E_aniso_sum = magneto.uniaxial_anisotropy(axis1, k_uni, Ms, state.M, H_aniso) elif have_uni and have_cub: tmp = VectorField(self.system.mesh) E0 = magneto.uniaxial_anisotropy(axis1, k_uni, Ms, state.M, tmp) E1 = magneto.cubic_anisotropy(axis1, axis2, k_cub, Ms, state.M, H_aniso) state.cache.E_aniso_sum = E0 + E1 H_aniso.add(tmp) return H_aniso elif id == "E_aniso": if not hasattr(state.cache, "E_aniso"): foo = state.H_aniso return state.cache.E_aniso_sum * self.system.mesh.cell_volume else: raise KeyError("AnisotropyField.calculate: Can't calculate %s", id)
def __update_field(self, state): # Get value of homogeneous field if hasattr(state, self.__value_id): value = getattr(state, self.__value_id) else: if not self.__default_value: raise ValueError( "HomogeneousField: Can't initialize field '%s' because no initial value is given!" % self.__var_id) value = self.__default_value # Create field (Field or VectorField) from value try: if isinstance(value, numbers.Number): value = float(value) field = Field(self.__mesh) field.fill(value) elif hasattr(value, "__iter__") and len(value) == 3: value = tuple(map(float, value)) field = VectorField(self.__mesh) field.fill(value) else: raise ValueError except ValueError: raise ValueError( "HomogeneousField: Expected scalar value or 3-tuple of scalar values for the 'value' (second) parameter" ) # Store value and field in state setattr(state, self.__value_id, value) setattr(state, self.__field_id, field) return field
class SpinTorque(module.Module): def __init__(self, do_precess=True): super(SpinTorque, self).__init__() self.__do_precess = do_precess def calculates(self): return ["dMdt_ST"] def params(self): return ["xi", "P"] def properties(self): return {"LLGE_TERM": "dMdt_ST"} def initialize(self, system): self.system = system self.P = Field(self.system.mesh) self.P.fill(0.0) self.xi = Field(self.system.mesh) self.xi.fill(0.0) def calculate(self, state, id): cache = state.cache if id == "dMdt_ST": if hasattr(cache, "dMdt_ST"): return cache.dMdt_ST dMdt_ST = cache.dMdt_ST = VectorField(self.system.mesh) # Calculate spin torque term due to Zhang & Li nx, ny, nz = self.system.mesh.num_nodes dx, dy, dz = self.system.mesh.delta magneto.fdm_zhangli( nx, ny, nz, dx, dy, dz, self.__do_precess, self.P, self.xi, self.system.Ms, self.system.alpha, state.j, state.M, dMdt_ST, ) return dMdt_ST else: raise KeyError("SpinTorque.calculate: Can't calculate %s", id)
def calculate_minimizer_dM(self, state): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "minimizer_dM"): return state.cache.minimizer_dM result = state.cache.minimizer_dM = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # TODO do this in every step? zero = Field(self.system.mesh) zero.fill(0.0) magneto.llge(zero, self.__f2, state.M, H_tot, result) return result
class ExchangeField(module.Module): def __init__(self): super(ExchangeField, self).__init__() def calculates(self): return ["H_exch", "E_exch"] def params(self): return ["A"] def properties(self): return { 'EFFECTIVE_FIELD_TERM': "H_exch", 'EFFECTIVE_FIELD_ENERGY': "E_exch" } def initialize(self, system): self.system = system self.A = Field(self.system.mesh) self.A.fill(0.0) self.__peri_x = system.mesh.periodic_bc[0].find("x") != -1 self.__peri_y = system.mesh.periodic_bc[0].find("y") != -1 self.__peri_z = system.mesh.periodic_bc[0].find("z") != -1 def calculate(self, state, id): cache = state.cache if id == "H_exch": if hasattr(cache, "H_exch"): return cache.H_exch H_exch = cache.H_exch = VectorField(self.system.mesh) #nx, ny, nz = self.system.mesh.num_nodes #dx, dy, dz = self.system.mesh.delta #bcx, bcy, bcz = self.__peri_x, self.__peri_y, self.__peri_z magneto.exchange(self.system.Ms, self.system.A, state.M, H_exch) return H_exch elif id == "E_exch": return -MU0 / 2.0 * self.system.mesh.cell_volume * state.M.dotSum( state.H_exch) else: raise KeyError("ExchangeField.calculate: Can't calculate %s", id)
def set_param(self, id, val): if id == self.__var_id: if isinstance(val, numbers.Number): fld = Field(self.system.mesh) fld.fill(val) elif hasattr(val, "__iter__") and len(val) == 3: val = tuple(map(float, val)) field = VectorField(self.system.mesh) field.fill(val) elif isinstance(val, Field): fld = Field(self.system.mesh) fld.assign(val) elif isinstance(val, VectorField): fld = VectorField(self.system.mesh) fld.assign(val) else: raise ValueError self.__field = fld else: raise ValueError("%s: Don't know how to update %s." % (self.name(), id))
class ExchangeField(module.Module): def __init__(self): super(ExchangeField, self).__init__() def calculates(self): return ["H_exch", "E_exch"] def params(self): return ["A"] def properties(self): return {"EFFECTIVE_FIELD_TERM": "H_exch", "EFFECTIVE_FIELD_ENERGY": "E_exch"} def initialize(self, system): self.system = system self.A = Field(self.system.mesh) self.A.fill(0.0) self.__peri_x = system.mesh.periodic_bc[0].find("x") != -1 self.__peri_y = system.mesh.periodic_bc[0].find("y") != -1 self.__peri_z = system.mesh.periodic_bc[0].find("z") != -1 def calculate(self, state, id): cache = state.cache if id == "H_exch": if hasattr(cache, "H_exch"): return cache.H_exch H_exch = cache.H_exch = VectorField(self.system.mesh) nx, ny, nz = self.system.mesh.num_nodes dx, dy, dz = self.system.mesh.delta bcx, bcy, bcz = self.__peri_x, self.__peri_y, self.__peri_z magneto.fdm_exchange(nx, ny, nz, dx, dy, dz, bcx, bcy, bcz, self.system.Ms, self.system.A, state.M, H_exch) return H_exch elif id == "E_exch": return -MU0 / 2.0 * self.system.mesh.cell_volume * state.M.dotSum(state.H_exch) else: raise KeyError("ExchangeField.calculate: Can't calculate %s", id)
def calculate_minimizer_dM_minimize_BB(self, state): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "minimizer_dM_minimize_BB"): return state.cache.minimizer_dM_minimize_BB result = state.cache.minimizer_dM_minimize_BB = VectorField( self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # TODO do this in every step? zero = Field(self.system.mesh) zero.fill(0.0) # changed; set llge coefficient to 1.0 for minimization factor = Field(self.system.mesh) factor.fill(1.) magneto.llge(zero, factor, state.M, H_tot, result) return result
class MacroSpinTorque(module.Module): def __init__(self, do_precess = True): super(SpinTorque, self).__init__() self.__do_precess = do_precess raise NotImplementedError("The MacroSpinTorque module does not work yet.") def calculates(self): return ["dMdt_ST"] def params(self): return ["a_j", "p"] def properties(self): return {'LLGE_TERM': "dMdt_ST"} def initialize(self, system): self.system = system self.a_j = Field(self.system.mesh); self.a_j.fill(0.0) self.p = Field(self.system.mesh); self.p.fill(0.0) def calculate(self, state, id): cache = state.cache if id == "dMdt_ST": if hasattr(cache, "dMdt_ST"): return cache.dMdt_ST dMdt_ST = cache.dMdt_ST = VectorField(self.system.mesh) # Calculate macro spin torque term due to Slonchewski nx, ny, nz = self.system.mesh.num_nodes dx, dy, dz = self.system.mesh.delta magneto.fdm_slonchewski( nx, ny, nz, dx, dy, dz, #self.__do_precess, a_j, p, state.Ms, state.alpha, state.M, dMdt_ST ) return dMdt_ST else: raise KeyError("MacroSpinTorque.calculate: Can't calculate %s", id)
class SpinTorque(module.Module): def __init__(self, do_precess=True): super(SpinTorque, self).__init__() self.__do_precess = do_precess def calculates(self): return ["dMdt_ST"] def params(self): return ["xi", "P"] def properties(self): return {'LLGE_TERM': "dMdt_ST"} def initialize(self, system): self.system = system self.P = Field(self.system.mesh) self.P.fill(0.0) self.xi = Field(self.system.mesh) self.xi.fill(0.0) def calculate(self, state, id): cache = state.cache if id == "dMdt_ST": if hasattr(cache, "dMdt_ST"): return cache.dMdt_ST dMdt_ST = cache.dMdt_ST = VectorField(self.system.mesh) # Calculate spin torque term due to Zhang & Li nx, ny, nz = self.system.mesh.num_nodes dx, dy, dz = self.system.mesh.delta magneto.fdm_zhangli(nx, ny, nz, dx, dy, dz, self.__do_precess, self.P, self.xi, self.system.Ms, self.system.alpha, state.j, state.M, dMdt_ST) return dMdt_ST else: raise KeyError("SpinTorque.calculate: Can't calculate %s", id)
class ExchangeField(module.Module): def __init__(self): super(ExchangeField, self).__init__() def calculates(self): return ["H_exch", "E_exch"] def params(self): return ["A"] def properties(self): return { 'EFFECTIVE_FIELD_TERM': "H_exch", 'EFFECTIVE_FIELD_ENERGY': "E_exch" } def initialize(self, system): self.system = system self.A = Field(self.system.mesh) self.A.fill(0.0) def calculate(self, state, id): cache = state.cache if id == "H_exch": if hasattr(cache, "H_exch"): return cache.H_exch H_exch = cache.H_exch = VectorField(self.system.mesh) magneto.exchange(state.Ms, state.A, state.M, H_exch) return H_exch elif id == "E_exch": return -MU0 / 2.0 * self.system.mesh.cell_volume * state.M.dotSum( state.H_exch) else: raise KeyError("ExchangeField.calculate: Can't calculate %s", id)
class LandauLifshitzGilbert(module.Module): def __init__(self, do_precess=True): super(LandauLifshitzGilbert, self).__init__() self.__do_precess = do_precess def calculates(self): # deprecated names for H_tot and E_tot: return ["dMdt", "M", "H_tot", "E_tot", "deg_per_ns"] + ["H_eff", "E_eff"] def updates(self): return ["M"] def params(self): return ["Ms", "alpha"] def on_param_update(self, id): if id in ["Ms", "alpha"]: self.__valid_factors = False def initialize(self, system): self.system = system self.Ms = Field(system.mesh); self.Ms.fill(0.0) self.alpha = Field(system.mesh); self.alpha.fill(0.0) self.__valid_factors = False # Find other active modules self.field_terms = [] self.field_energies = [] self.llge_terms = [] for mod in system.modules: prop = mod.properties() if 'EFFECTIVE_FIELD_TERM' in prop.keys(): self.field_terms.append(prop['EFFECTIVE_FIELD_TERM']) if 'EFFECTIVE_FIELD_ENERGY' in prop.keys(): self.field_energies.append(prop['EFFECTIVE_FIELD_ENERGY']) if 'LLGE_TERM' in prop.keys(): self.llge_terms.append(prop['LLGE_TERM']) logger.info("LandauLifshitzGilbert module configuration:") logger.info(" - H_tot = %s", " + ".join(self.field_terms) or "0") logger.info(" - E_tot = %s", " + ".join(self.field_energies) or "0") logger.info(" - dM/dt = %s", " + ".join(["LLGE(M, H_tot)"] + self.llge_terms) or "0") if not self.__do_precess: logger.info(" - Precession term is disabled") def calculate(self, state, id): if id == "M": return state.y if id == "H_tot" or id == "H_eff": return self.calculate_H_tot(state) if id == "E_tot" or id == "E_eff": return self.calculate_E_tot(state) if id == "dMdt": return self.calculate_dMdt(state) if id == "deg_per_ns": deg_per_timestep = (180.0 / math.pi) * math.atan2(state.dMdt.absMax() * state.h, state.M.absMax()) # we assume a<b at atan(a/b). deg_per_ns = 1e-9 * deg_per_timestep / state.h return deg_per_ns else: raise KeyError(id) def update(self, state, id, value): if id == "M": logger.info("Assigning new magnetic state M") module.assign(state.y, value) state.y.normalize(self.system.Ms) # XXX: Is this a good idea? (Solution: Use unit magnetization everywhere.) state.flush_cache() else: raise KeyError(id) def calculate_H_tot(self, state): if hasattr(state.cache, "H_tot"): return state.cache.H_tot H_tot = state.cache.H_tot = VectorField(self.system.mesh) if len(self.field_terms) == 0: H_tot.fill((0.0, 0.0, 0.0)) else: for i, H_str in enumerate(self.field_terms): H_i = getattr(state, H_str) if i == 0: H_tot.assign(H_i) else: H_tot.add(H_i) return H_tot def calculate_E_tot(self, state): if hasattr(state.cache, "E_tot"): return state.cache.E_tot state.cache.E_tot = sum(getattr(state, E_str) for E_str in self.field_energies) # calculate sum of all registered energy terms return state.cache.E_tot def calculate_dMdt(self, state): if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "dMdt"): return state.cache.dMdt dMdt = state.cache.dMdt = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # Basic term magneto.llge(self.__f1, self.__f2, state.M, H_tot, dMdt) # Optional other terms for dMdt_str in self.llge_terms: dMdt_i = getattr(state, dMdt_str) dMdt.add(dMdt_i) return dMdt def __initFactors(self): self.__f1 = f1 = Field(self.system.mesh) # precession factors self.__f2 = f2 = Field(self.system.mesh) # damping factors # Prepare factors nx, ny, nz = self.system.mesh.num_nodes for z in range(nz): for y in range(ny): for x in range(nx): alpha, Ms = self.alpha.get(x,y,z), self.Ms.get(x,y,z) if Ms != 0.0: gamma_prime = GYROMAGNETIC_RATIO / (1.0 + alpha**2) f1_i = -gamma_prime f2_i = -alpha * gamma_prime / Ms else: f1_i, f2_i = 0.0, 0.0 f1.set(x,y,z, f1_i) f2.set(x,y,z, f2_i) # If precession is disabled, blank f1. if not self.__do_precess: f1.fill(0.0) # Done. self.__valid_factors = True
class AnisotropyField(module.Module): def __init__(self): super(AnisotropyField, self).__init__() def calculates(self): return ["H_aniso", "E_aniso"] def params(self): return ["k_uniaxial", "k_cubic", "axis1", "axis2"] def properties(self): return {'EFFECTIVE_FIELD_TERM': "H_aniso", 'EFFECTIVE_FIELD_ENERGY': "E_aniso"} def initialize(self, system): self.system = system self.k_uniaxial = Field(self.system.mesh); self.k_uniaxial.fill(0.0) self.k_cubic = Field(self.system.mesh); self.k_cubic.fill(0.0) self.axis1 = VectorField(self.system.mesh); self.axis1.fill((0.0, 0.0, 0.0)) self.axis2 = VectorField(self.system.mesh); self.axis2.fill((0.0, 0.0, 0.0)) def on_param_update(self, id): if id in self.params() + ["Ms"]: axis1, axi2 = self.axis1, self.axis2 k_uni, k_cub = self.k_uniaxial, self.k_cubic Ms = self.system.Ms def compute_none(state, H_aniso): H_aniso.fill((0.0, 0.0, 0.0)) return 0.0 def compute_uniaxial(state, H_aniso): return magneto.uniaxial_anisotropy(axis1, k_uni, Ms, state.M, H_aniso) def compute_cubic(state, H_aniso): return magneto.cubic_anisotropy(axis1, axis2, k_cub, Ms, state.M, H_aniso) def compute_uniaxial_and_cubic(state, H_aniso): tmp = VectorField(self.system.mesh) E0 = magneto.uniaxial_anisotropy(axis1, k_uni, Ms, state.M, tmp) E1 = magneto.cubic_anisotropy(axis1, axis2, k_cub, Ms, state.M, H_aniso) state.cache.E_aniso_sum = E0 + E1 H_aniso.add(tmp) fns = {(False, False): compute_none, ( True, False): compute_uniaxial, (False, True): compute_cubic, ( True, True): compute_uniaxial_and_cubic} have_uni = not (k_uni.isUniform() and k_uni.uniform_value == 0.0) have_cub = not (k_cub.isUniform() and k_cub.uniform_value == 0.0) self.__compute_fn = fns[have_uni, have_cub] def calculate(self, state, id): if id == "H_aniso": if hasattr(state.cache, "H_aniso"): return state.cache.H_aniso H_aniso = state.cache.H_aniso = VectorField(self.system.mesh) state.cache.E_aniso_sum = self.__compute_fn(state, H_aniso) return H_aniso elif id == "E_aniso": if not hasattr(state.cache, "E_aniso_sum"): self.calculate(state, "H_aniso") return state.cache.E_aniso_sum * self.system.mesh.cell_volume else: raise KeyError("AnisotropyField.calculate: Can't calculate %s", id)
class AnisotropyField(module.Module): def __init__(self): super(AnisotropyField, self).__init__() def calculates(self): return ["H_aniso", "E_aniso"] def params(self): return ["k_uniaxial", "k_cubic", "axis1", "axis2"] def properties(self): return { 'EFFECTIVE_FIELD_TERM': "H_aniso", 'EFFECTIVE_FIELD_ENERGY': "E_aniso" } def initialize(self, system): self.system = system self.k_uniaxial = Field(self.system.mesh) self.k_uniaxial.fill(0.0) self.k_cubic = Field(self.system.mesh) self.k_cubic.fill(0.0) self.axis1 = VectorField(self.system.mesh) self.axis1.fill((0.0, 0.0, 0.0)) self.axis2 = VectorField(self.system.mesh) self.axis2.fill((0.0, 0.0, 0.0)) def on_param_update(self, id): if id in self.params() + ["Ms"]: axis1, axis2 = self.axis1, self.axis2 k_uni, k_cub = self.k_uniaxial, self.k_cubic Ms = self.system.get_param("Ms") def compute_none(state, H_aniso): H_aniso.fill((0.0, 0.0, 0.0)) return 0.0 def compute_uniaxial(state, H_aniso): return magneto.uniaxial_anisotropy(axis1, k_uni, Ms, state.M, H_aniso) def compute_cubic(state, H_aniso): return magneto.cubic_anisotropy(axis1, axis2, k_cub, Ms, state.M, H_aniso) def compute_uniaxial_and_cubic(state, H_aniso): tmp = VectorField(self.system.mesh) E0 = magneto.uniaxial_anisotropy(axis1, k_uni, Ms, state.M, tmp) E1 = magneto.cubic_anisotropy(axis1, axis2, k_cub, Ms, state.M, H_aniso) state.cache.E_aniso_sum = E0 + E1 H_aniso.add(tmp) fns = { (False, False): compute_none, (True, False): compute_uniaxial, (False, True): compute_cubic, (True, True): compute_uniaxial_and_cubic } have_uni = not (k_uni.isUniform() and k_uni.uniform_value == 0.0) have_cub = not (k_cub.isUniform() and k_cub.uniform_value == 0.0) self.__compute_fn = fns[have_uni, have_cub] def calculate(self, state, id): cache = state.cache if id == "H_aniso": if hasattr(cache, "H_aniso"): return cache.H_aniso H_aniso = cache.H_aniso = VectorField(self.system.mesh) cache.E_aniso_sum = self.__compute_fn(state, H_aniso) return H_aniso elif id == "E_aniso": if not hasattr(cache, "E_aniso_sum"): self.calculate(state, "H_aniso") return cache.E_aniso_sum * self.system.mesh.cell_volume else: raise KeyError("AnisotropyField.calculate: Can't calculate %s", id)
class LandauLifshitzGilbert(module.Module): def __init__(self, do_precess=True): super(LandauLifshitzGilbert, self).__init__() self.__do_precess = do_precess self.__valid_factors = False def calculates(self): return ["dMdt", "M", "H_tot", "E_tot", "deg_per_ns", "minimizer_M", "minimizer_dM"] def updates(self): return ["M"] def params(self): return ["Ms", "alpha"] def on_param_update(self, id): if id in self.params(): self.__valid_factors = False def initialize(self, system): self.system = system self.Ms = Field(system.mesh); self.Ms.fill(0.0) self.alpha = Field(system.mesh); self.alpha.fill(0.0) self.__valid_factors = False # Find other active modules self.field_terms = [] self.field_energies = [] self.llge_terms = [] for mod in system.modules: prop = mod.properties() if 'EFFECTIVE_FIELD_TERM' in prop.keys(): self.field_terms.append(prop['EFFECTIVE_FIELD_TERM']) if 'EFFECTIVE_FIELD_ENERGY' in prop.keys(): self.field_energies.append(prop['EFFECTIVE_FIELD_ENERGY']) if 'LLGE_TERM' in prop.keys(): self.llge_terms.append(prop['LLGE_TERM']) logger.info("LandauLifshitzGilbert module configuration:") logger.info(" - H_tot = %s", " + ".join(self.field_terms) or "0") logger.info(" - E_tot = %s", " + ".join(self.field_energies) or "0") logger.info(" - dM/dt = %s", " + ".join(["LLGE(M, H_tot)"] + self.llge_terms) or "0") if not self.__do_precess: logger.info(" - Precession term is disabled") def calculate(self, state, id): if id == "M": return state.y elif id == "H_tot": return self.calculate_H_tot(state) elif id == "E_tot": return self.calculate_E_tot(state) elif id == "dMdt": return self.calculate_dMdt(state) elif id == "deg_per_ns": return self.calculate_deg_per_ns(state) elif id == "minimizer_M": return lambda h: self.calculate_minimizer_M(state, h) elif id == "minimizer_dM": return self.calculate_minimizer_dM(state) else: raise KeyError(id) def update(self, state, id, value): if id == "M": logger.info("Assigning new magnetic state M") module.assign(state.y, value) state.y.normalize(state.Ms) # XXX: Is this a good idea? (Solution: Use unit magnetization everywhere.) state.flush_cache() else: raise KeyError(id) def calculate_H_tot(self, state): if hasattr(state.cache, "H_tot"): return state.cache.H_tot H_tot = state.cache.H_tot = VectorField(self.system.mesh) H_tot.fill((0.0, 0.0, 0.0)) for H_id in self.field_terms: H_i = getattr(state, H_id) H_tot.add(H_i) return H_tot def calculate_E_tot(self, state): if hasattr(state.cache, "E_tot"): return state.cache.E_tot state.cache.E_tot = sum(getattr(state, E_id) for E_id in self.field_energies) # calculate sum of all registered energy terms return state.cache.E_tot def calculate_dMdt(self, state): if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "dMdt"): return state.cache.dMdt dMdt = state.cache.dMdt = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # Basic term magneto.llge(self.__f1, self.__f2, state.M, H_tot, dMdt) # Optional other terms for dMdt_id in self.llge_terms: dMdt_i = getattr(state, dMdt_id) dMdt.add(dMdt_i) return dMdt def calculate_minimizer_dM(self, state): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "minimizer_dM"): return state.cache.minimizer_dM result = state.cache.minimizer_dM = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # TODO do this in every step? zero = Field(self.system.mesh) zero.fill(0.0) magneto.llge(zero, self.__f2, state.M, H_tot, result) return result def calculate_minimizer_M(self, state, h): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() result = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) magneto.minimize(self.__f2, h, state.M, H_tot, result) return result def calculate_deg_per_ns(self, state): if hasattr(state.cache, "deg_per_ns"): return state.cache.deg_per_ns deg_per_timestep = (180.0 / math.pi) * math.atan2(state.dMdt.absMax() * state.h, state.M.absMax()) # we assume a<b at atan(a/b). deg_per_ns = state.cache.deg_per_ns = 1e-9 * deg_per_timestep / state.h return deg_per_ns def __initFactors(self): self.__f1 = f1 = Field(self.system.mesh) # precession factors of llge self.__f2 = f2 = Field(self.system.mesh) # damping factors of llge alpha, Ms = self.alpha, self.Ms # Prepare factors for x, y, z in self.system.mesh.iterateCellIndices(): alpha_i, Ms_i = alpha.get(x, y, z), Ms.get(x, y, z) if Ms_i != 0.0: gamma_prime = GYROMAGNETIC_RATIO / (1.0 + alpha_i ** 2) f1_i = -gamma_prime f2_i = -alpha_i * gamma_prime / Ms_i else: f1_i, f2_i = 0.0, 0.0 f1.set(x, y, z, f1_i) f2.set(x, y, z, f2_i) # If precession is disabled, blank f1. if not self.__do_precess: f1.fill(0.0) # Done. self.__valid_factors = True
class LandauLifshitzGilbert(module.Module): def __init__(self, do_precess=True): super(LandauLifshitzGilbert, self).__init__() self.__do_precess = do_precess self.__valid_factors = False def calculates(self): return [ "dMdt", "M", "H_tot", "E_tot", "E_minimize_BB", "deg_per_ns", "minimizer_M", "minimizer_dM", "minimizer_dM_minimize_BB" ] def updates(self): return ["M"] def params(self): return ["Ms", "alpha"] def on_param_update(self, id): if id in self.params(): self.__valid_factors = False def initialize(self, system): self.system = system self.Ms = Field(system.mesh) self.Ms.fill(0.0) self.alpha = Field(system.mesh) self.alpha.fill(0.0) self.__valid_factors = False # Find other active modules self.field_terms = [] self.field_energies = [] self.llge_terms = [] for mod in system.modules: prop = mod.properties() if 'EFFECTIVE_FIELD_TERM' in prop.keys(): self.field_terms.append(prop['EFFECTIVE_FIELD_TERM']) if 'EFFECTIVE_FIELD_ENERGY' in prop.keys(): self.field_energies.append(prop['EFFECTIVE_FIELD_ENERGY']) if 'LLGE_TERM' in prop.keys(): self.llge_terms.append(prop['LLGE_TERM']) logger.info("LandauLifshitzGilbert module configuration:") logger.info(" - H_tot = %s", " + ".join(self.field_terms) or "0") logger.info(" - E_tot = %s", " + ".join(self.field_energies) or "0") logger.info(" - dM/dt = %s", " + ".join(["LLGE(M, H_tot)"] + self.llge_terms) or "0") if not self.__do_precess: logger.info(" - Precession term is disabled") def calculate(self, state, id): if id == "M": return state.y elif id == "H_tot": return self.calculate_H_tot(state) elif id == "E_tot": return self.calculate_E_tot(state) elif id == "E_minimize_BB": #eingefuegt return self.calculate_E_minimize_BB(state) elif id == "dMdt": return self.calculate_dMdt(state) elif id == "deg_per_ns": return self.calculate_deg_per_ns(state) elif id == "minimizer_M": return lambda h: self.calculate_minimizer_M(state, h) elif id == "minimizer_dM": return self.calculate_minimizer_dM(state) elif id == "minimizer_dM_minimize_BB": return self.calculate_minimizer_dM_minimize_BB(state) else: raise KeyError(id) def update(self, state, id, value): if id == "M": logger.info("Assigning new magnetic state M") module.assign(state.y, value) state.y.normalize( state.Ms ) # XXX: Is this a good idea? (Solution: Use unit magnetization everywhere.) state.flush_cache() else: raise KeyError(id) def calculate_H_tot(self, state): if hasattr(state.cache, "H_tot"): return state.cache.H_tot H_tot = state.cache.H_tot = VectorField(self.system.mesh) H_tot.fill((0.0, 0.0, 0.0)) for H_id in self.field_terms: H_i = getattr(state, H_id) H_tot.add(H_i) return H_tot def calculate_E_tot(self, state): if hasattr(state.cache, "E_tot"): return state.cache.E_tot state.cache.E_tot = sum( getattr(state, E_id) for E_id in self.field_energies ) # calculate sum of all registered energy terms return state.cache.E_tot def calculate_E_minimize_BB(self, state): if hasattr(state.cache, "E_tot"): return state.cache.E_tot state.cache.E_tot = sum( getattr(state, E_id) for E_id in self.field_energies ) * 1.e28 #calculate sum of all registered energy terms return state.cache.E_tot def calculate_dMdt(self, state): if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "dMdt"): return state.cache.dMdt dMdt = state.cache.dMdt = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # Basic term magneto.llge(self.__f1, self.__f2, state.M, H_tot, dMdt) # Optional other terms for dMdt_id in self.llge_terms: dMdt_i = getattr(state, dMdt_id) dMdt.add(dMdt_i) return dMdt def calculate_minimizer_dM(self, state): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "minimizer_dM"): return state.cache.minimizer_dM result = state.cache.minimizer_dM = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # TODO do this in every step? zero = Field(self.system.mesh) zero.fill(0.0) magneto.llge(zero, self.__f2, state.M, H_tot, result) return result def calculate_minimizer_dM_minimize_BB(self, state): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() if hasattr(state.cache, "minimizer_dM_minimize_BB"): return state.cache.minimizer_dM_minimize_BB result = state.cache.minimizer_dM_minimize_BB = VectorField( self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) # TODO do this in every step? zero = Field(self.system.mesh) zero.fill(0.0) # changed; set llge coefficient to 1.0 for minimization factor = Field(self.system.mesh) factor.fill(1.) magneto.llge(zero, factor, state.M, H_tot, result) return result def calculate_minimizer_M(self, state, h): # TODO other LLG terms? if not self.__valid_factors: self.__initFactors() result = VectorField(self.system.mesh) # Get effective field H_tot = self.calculate_H_tot(state) magneto.minimize(self.__f2, h, state.M, H_tot, result) return result def calculate_deg_per_ns(self, state): if hasattr(state.cache, "deg_per_ns"): return state.cache.deg_per_ns deg_per_timestep = (180.0 / math.pi) * math.atan2( state.dMdt.absMax() * state.h, state.M.absMax()) # we assume a<b at atan(a/b). deg_per_ns = state.cache.deg_per_ns = 1e-9 * deg_per_timestep / state.h return deg_per_ns def __initFactors(self): self.__f1 = f1 = Field(self.system.mesh) # precession factors of llge self.__f2 = f2 = Field(self.system.mesh) # damping factors of llge alpha, Ms = self.alpha, self.Ms # Prepare factors for x, y, z in self.system.mesh.iterateCellIndices(): alpha_i, Ms_i = alpha.get(x, y, z), Ms.get(x, y, z) if Ms_i != 0.0: gamma_prime = GYROMAGNETIC_RATIO / (1.0 + alpha_i**2) f1_i = -gamma_prime f2_i = -alpha_i * gamma_prime / Ms_i else: f1_i, f2_i = 0.0, 0.0 f1.set(x, y, z, f1_i) f2.set(x, y, z, f2_i) # If precession is disabled, blank f1. if not self.__do_precess: f1.fill(0.0) # Done. self.__valid_factors = True