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
Exemple #5
0
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
    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
Exemple #8
0
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))
Exemple #10
0
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
Exemple #12
0
 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 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)
Exemple #14
0
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