def _setup(self, doing=None): assert not self.initialised, \ "FDSimulation._setup has already been called" if self.fd_mesh == None: if doing != None: doing = " " + doing raise NmagUserError("You should define a mesh before%s!" % doing) if len(self.materials) < 1: raise NmagUserError("You should specify at least one material!") elif len(self.materials) > 1: self._fd_na("multi-material") mat = self.materials[0] Ms = self.units.of(mat.Ms, compatible_with=SI('A/m')) A = self.units.of(mat.exchange_coupling, compatible_with=SI('J/m')) gamma = self.units.of(mat.llg_gamma_G, compatible_with=SI('m/s A')) alpha = self.units.of(mat.llg_damping, compatible_with=SI(1)) Hext = array([0.0, 0.0, 0.0]) Hext = Hext/MU_ZERO self.zeeman = Zeemanfield(self.fd_mesh, Hext) timer1.start('exchange init') exchange = Exchangefield(self.fd_mesh, Ms, A) timer1.stop('exchange init') field_dict = {'H_ext':self.zeeman, 'H_exch':exchange} timer1.start('demag init') if self.do_demag: demag = Demagfield(self.fd_mesh, init_random=False, expansion="opt") field_dict['H_demag'] = demag self.field_array = FieldArray(field_dict) timer1.stop('demag init') self.fd_model = \ self.model_cls(self.fd_mesh, self.field_array, Ms, gamma, alpha, precession_enabled=mat.do_precession) self.integrator = Integrator(self.fd_model, self.ts_rel_tol, self.ts_abs_tol, self.ts_tstep0, method="rk", order=2) self.initialised = True
class FDSimulation(SimulationCore): def __init__(self, name=None, do_demag=True,model="basic"): SimulationCore.__init__(self, name=name, do_demag=do_demag, id="FD Simulation class") self.initialised = False self.field_array = None if self._restarting: raise NotImplementedError('Restarting capabilities are not ' 'implemented by the FD code, yet!') # These are our default simulation units. self.units = nsim.su_units.SimulationUnits({'A': 1.0, 'kg': 1.0, 'm': 1.0, 's': 1.0, 'cd': 1.0, 'K': 1.0, 'mol': 1.0}) # The FD mesh self.fd_mesh = None self.zeeman = None self.ts_rel_tol = 1e-0 self.ts_abs_tol = 1e-0 self.ts_tstep0 = 1e-15 self.integrator = None if model == "basic": self.model_cls = BasicMicromagneticModel else: raise RuntimeError("unknown finite difference model type '%s'" % model) self.stopping_dm_dt = self.units.of(1.0*degrees_per_ns) def _fd_na(self, reason): """Called internally to raise error messages which are raised frequently""" msgs = { "multi-material": "The finite difference version of Nmag does " "support multiple materials, yet. You should " "define and use just one MagMaterial!" } try: msg = msgs[reason] except: msg = "Unknown error!" raise NotImplementedError(msg) def _setup(self, doing=None): assert not self.initialised, \ "FDSimulation._setup has already been called" if self.fd_mesh == None: if doing != None: doing = " " + doing raise NmagUserError("You should define a mesh before%s!" % doing) if len(self.materials) < 1: raise NmagUserError("You should specify at least one material!") elif len(self.materials) > 1: self._fd_na("multi-material") mat = self.materials[0] Ms = self.units.of(mat.Ms, compatible_with=SI('A/m')) A = self.units.of(mat.exchange_coupling, compatible_with=SI('J/m')) gamma = self.units.of(mat.llg_gamma_G, compatible_with=SI('m/s A')) alpha = self.units.of(mat.llg_damping, compatible_with=SI(1)) Hext = array([0.0, 0.0, 0.0]) Hext = Hext/MU_ZERO self.zeeman = Zeemanfield(self.fd_mesh, Hext) timer1.start('exchange init') exchange = Exchangefield(self.fd_mesh, Ms, A) timer1.stop('exchange init') field_dict = {'H_ext':self.zeeman, 'H_exch':exchange} timer1.start('demag init') if self.do_demag: demag = Demagfield(self.fd_mesh, init_random=False, expansion="opt") field_dict['H_demag'] = demag self.field_array = FieldArray(field_dict) timer1.stop('demag init') self.fd_model = \ self.model_cls(self.fd_mesh, self.field_array, Ms, gamma, alpha, precession_enabled=mat.do_precession) self.integrator = Integrator(self.fd_model, self.ts_rel_tol, self.ts_abs_tol, self.ts_tstep0, method="rk", order=2) self.initialised = True def _setup_if_needed(self, doing=None): if self.initialised: return self._setup(doing=doing) def set_params(self, stopping_dm_dt=None, ts_rel_tol=None, ts_abs_tol=None): if stopping_dm_dt != None: self.stopping_dm_dt = self.units.of(stopping_dm_dt, compatible_with=SI('1/s')) reset_tols = False if ts_rel_tol != None: self.ts_rel_tol = ts_rel_tol reset_tols = True if ts_abs_tol != None: self.ts_abs_tol = ts_abs_tol reset_tols = True if reset_tols and self.integrator != None: raise NotImplementedError("Tolerances cannot be set after the " "integrator has been created. Try to " "call set_params before create_mesh.") def reinitialise(self, initial_time=None): pass def set_m(self, values, subfieldname=None): print "FIXME: set_m, set_H_ext etc are not fully implemented, yet!" if subfieldname != None: self._fd_na("multi-material") self._setup_if_needed("setting the magnetisation") factor = self.fd_model.Ms if not type(values) is FunctionType: try: values, u = nsim.map_terminals.SI_vector(values) factor *= self.units.of(u, compatible_with=SI(1)) except: pass M0 = self.fd_mesh.create_vectorfield(values,'magnetic') M0.shape = self.fd_mesh.get_vectorfield_flat_shape() norm_to(self.fd_mesh, M0, factor) M0 = M0.reshape(-1) self.integrator.set_initial_values(self.fd_model.create_dof_field_M0(M0), 0.0) def set_H_ext(self, values, unit=None): v, u = nsim.map_terminals.SI_vector(values) factor = self.units.of(u, compatible_with=SI('A/m')) v_su = [vi*factor for vi in v] self._setup_if_needed('setting the external field') self.zeeman.set_field(v_su) def set_pinning(self, values): print "set_pinning not fully implemented, yet!" def create_mesh(self, cell_nums, cell_sizes, materials, regions=None, origin=(0, 0, 0)): print "FIXME: create_mesh: boundary not included and not conforming " \ "to the interface specification: see SimulationCore class!" cell_nums_su = [int(self.units.of(ni, compatible_with=SI(1))) for ni in cell_nums] cell_sizes_su = [self.units.of(si, compatible_with=SI('m')) for si in cell_sizes] origin_su = [self.units.of(si, compatible_with=SI('m')) for si in origin] self.fd_mesh = Mesh(cells=cell_nums_su, cell_sizes=cell_sizes_su,regions=regions,origin=origin_su) if type(materials) == list: self.materials = materials else: self.materials = [materials] self._setup_if_needed() create_mesh.__doc__ = SimulationCore.create_mesh.__doc__ def is_integration_converged(self): return self.fd_model.get_max_dmdt() < self.stopping_dm_dt def advance_time(self, target_time, max_it=-1): if not self.initialised: self._setup(doing="calling advance_time") time_su = self.units.of(target_time, compatible_with=SI('s')) num_steps_0 = self.integrator.used_steps time_0 = self.integrator.t self.integrator.integrate(time_su, max_it, stop_test=self.is_integration_converged) delta_steps = self.integrator.used_steps - num_steps_0 delta_time = self.integrator.t - time_0 time_su2si = self.units.conversion_factor_of(SI("s")) delta_time_si = time_su2si*delta_time self.clock['time'] += delta_time_si self.clock['stage_time'] += delta_time_si self.clock['step'] += delta_steps self.clock['stage_step'] += delta_steps self.clock['convergence'] = self.integrator.converged return self.clock['time'] def get_subfield_average(self, field_name, subfield_name=None): material = self.materials[0] if subfield_name != None and subfield_name != material.name: self._fd_na("multi-material") if field_name == 'm': Ms = self.units.of(material.Ms) return list(average(self.get_M_field_flat())/Ms) elif field_name == 'M': return list(average((self.get_M_field_flat()))*SI('A/m')) elif field_name in ['H_ext', 'H_exch', 'H_demag']: try: H, E, H_avg = \ self.field_array.calculate_field(self.get_M_field_flat(), 0.0, field_name, True, True) return list(H_avg*SI('A/m')) except: return None else: return None def load_m_from_file(self, filename, format=None): print "FIXME: debug load_m_from_file" if format == None: extension = filename.split(os.extsep)[-1].lower() format = extension if not format in ['omf', 'ovf']: # report a warning, not an error: we do not want the user to find # that the simulation stopped just because the format was not the # right one (remember one may save at the end of the simulation) print ("FIXME: MAKE ME A LOG: WARNING: format not supported. " "Using OMF format to save the field.") data, X = omf.load_omf(filename) self.set_m(data) def save_m_to_file(self, filename, format=None): # print "FIXME: save_m_to_file: Add a LOG!!!" if format == None: extension = filename.split(os.extsep)[-1].lower() format = extension if not format in ['omf', 'ovf']: # report a warning, not an error: we do not want the user to find # that the simulation stopped just because the format was not the # right one (remember one may save at the end of the simulation) print ("FIXME: MAKE ME A LOG: WARNING: format not supported. " "Using OMF format to save the field.") header_dict = omf.new_header() nx, ny, nz = self.fd_mesh.cells sx, sy, sz = self.fd_mesh.cellsizes ox, oy, oz = self.fd_mesh.origin data_to_set = \ [('xnodes', nx), ('ynodes', ny), ('znodes', nz), ('xmin', ox), ('ymin', oy), ('zmin', oz), ('xmax', ox+nx*sx), ('ymax', oy+ny*sy), ('zmax', oz+nz*sz), ('xstepsize', sx), ('ystepsize', sy), ('zstepsize', sz), ('xbase', 0.5*sx), ('ybase', 0.5*sy), ('zbase', 0.5*sz)] omf.add_header_data(header_dict, [('Segment', 0), ('Header', 0)], data_to_set) omf.write_omf(filename, self.get_M_field_flat(), header_dict=header_dict) save_m_to_file.__doc__ = SimulationCore.save_m_to_file.__doc__ def save_data(self, fields=None, avoid_same_step=False): SimulationCore.save_data(self, fields, avoid_same_step) if fields != None: if 'm' in fields or 'all' in fields: self.clock['id'] += 1 filename = 'm-%012d.omf' % self.id self.save_m_to_file(filename) save_data.__doc__ = SimulationCore.save_data.__doc__ def get_M_field_flat(self): return self.integrator.dof.M_field_flat