def test_step_integrator(integrator, stepsize_reported, stepsize_internal): ts = np.arange(interval[0], interval[1], step=stepsize_reported) print(ts) print(ts[1:]) ys = np.zeros(ts.shape[0]) ys[0] = y_true(ts[0]) # known initial value integrator = StepIntegrator(ys[0], f, step="euler", stepsize=stepsize_internal) for i, t in enumerate(ts[1:]): integrator.run_until(t) ts[i + 1] = integrator.t ys[i + 1] = integrator.y assert 85 < ys[-1] < 100 return ts, ys
def set_integrator(self, integrator, use_jac): # Integrator options -------------------------------------------------- # Here we set up the CVODE integrator from Sundials to evolve a # specific micromagnetic equation. The equations are specified in the # sundials_rhs function from any of the micromagnetic drivers in the # micromagnetic folder (LLG, LLG_STT, etc.) if integrator == "sundials" and use_jac: self.integrator = CvodeSolver(self.spin, self.sundials_rhs, self.sundials_jtimes) elif integrator == "sundials_diag": self.integrator = CvodeSolver(self.spin, self.sundials_rhs, linear_solver="diag") elif integrator == "sundials": self.integrator = CvodeSolver(self.spin, self.sundials_rhs) elif integrator == "euler" or integrator == "rk4": self.integrator = StepIntegrator(self.spin, self.step_rhs) elif integrator == "scipy": self.integrator = ScipyIntegrator(self.spin, self.step_rhs) elif integrator == "sundials_openmp" and use_jac: self.integrator = CvodeSolver_OpenMP(self.spin, self.sundials_rhs, self.sundials_jtimes) elif integrator == "sundials_diag_openmp": self.integrator = CvodeSolver_OpenMP(self.spin, self.sundials_rhs, linear_solver="diag") elif integrator == "sundials_openmp": self.integrator = CvodeSolver_OpenMP(self.spin, self.sundials_rhs) elif integrator == "euler_openmp" or integrator == "rk4_openmp": self.integrator = CvodeSolver_OpenMP(self.spin, self.step_rhs, integrator) else: raise NotImplemented("integrator must be sundials, euler or rk4")
def __init__(self, mesh, name='unnamed', integrator='sundials'): """Simulation object. *Arguments* name : the Simulation name (used for writing data files, for examples) """ self.t = 0 self.name = name self.mesh = mesh self.n = mesh.n self.n_nonzero = mesh.n self.unit_length = mesh.unit_length self._alpha = np.zeros(self.n, dtype=np.float) self._Ms = np.zeros(self.n, dtype=np.float) self._Ms_inv = np.zeros(self.n, dtype=np.float) self.spin = np.ones(3 * self.n, dtype=np.float) self.spin_last = np.ones(3 * self.n, dtype=np.float) self._pins = np.zeros(self.n, dtype=np.int32) self.field = np.zeros(3 * self.n, dtype=np.float) self.dm_dt = np.zeros(3 * self.n, dtype=np.float) self._skx_number = np.zeros(self.n, dtype=np.float) self.interactions = [] self.pin_fun = None self.integrator_tolerances_set = False self.step = 0 if integrator == "sundials": self.integrator = SundialsIntegrator(self.spin, self.sundials_rhs) elif integrator == "euler" or integrator == "rk4": self.integrator = StepIntegrator(self.spin, self.step_rhs, integrator) else: raise NotImplemented("integrator must be sundials, euler or rk4") self.saver = DataSaver(self, name + '.txt') self.saver.entities['E_total'] = { 'unit': '<J>', 'get': lambda sim: sim.compute_energy(), 'header': 'E_total'} self.saver.entities['m_error'] = { 'unit': '<>', 'get': lambda sim: sim.compute_spin_error(), 'header': 'm_error'} self.saver.entities['skx_num'] = { 'unit': '<>', 'get': lambda sim: sim.skyrmion_number(), 'header': 'skx_num'} self.saver.entities['rhs_evals'] = { 'unit': '<>', 'get': lambda sim: self.integrator.rhs_evals, 'header': 'rhs_evals'} self.saver.entities['real_time'] = { 'unit': '<s>', 'get': lambda _: time.time(), # seconds since epoch 'header': 'real_time'} self.saver.update_entity_order() # This is for old C files codes using the xperiodic variables self.xperiodic, self.yperiodic, self.zperiodic = mesh.periodicity self.vtk = SaveVTK(self.mesh, name=name) self.set_default_options()
class LLG(object): def __init__(self, mesh, name='unnamed', integrator='sundials'): """Simulation object. *Arguments* name : the Simulation name (used for writing data files, for examples) """ self.t = 0 self.name = name self.mesh = mesh self.n = mesh.n self.n_nonzero = mesh.n self.unit_length = mesh.unit_length self._alpha = np.zeros(self.n, dtype=np.float) self._Ms = np.zeros(self.n, dtype=np.float) self._Ms_inv = np.zeros(self.n, dtype=np.float) self.spin = np.ones(3 * self.n, dtype=np.float) self.spin_last = np.ones(3 * self.n, dtype=np.float) self._pins = np.zeros(self.n, dtype=np.int32) self.field = np.zeros(3 * self.n, dtype=np.float) self.dm_dt = np.zeros(3 * self.n, dtype=np.float) self._skx_number = np.zeros(self.n, dtype=np.float) self.interactions = [] self.pin_fun = None self.integrator_tolerances_set = False self.step = 0 if integrator == "sundials": self.integrator = SundialsIntegrator(self.spin, self.sundials_rhs) elif integrator == "euler" or integrator == "rk4": self.integrator = StepIntegrator(self.spin, self.step_rhs, integrator) else: raise NotImplemented("integrator must be sundials, euler or rk4") self.saver = DataSaver(self, name + '.txt') self.saver.entities['E_total'] = { 'unit': '<J>', 'get': lambda sim: sim.compute_energy(), 'header': 'E_total'} self.saver.entities['m_error'] = { 'unit': '<>', 'get': lambda sim: sim.compute_spin_error(), 'header': 'm_error'} self.saver.entities['skx_num'] = { 'unit': '<>', 'get': lambda sim: sim.skyrmion_number(), 'header': 'skx_num'} self.saver.entities['rhs_evals'] = { 'unit': '<>', 'get': lambda sim: self.integrator.rhs_evals, 'header': 'rhs_evals'} self.saver.entities['real_time'] = { 'unit': '<s>', 'get': lambda _: time.time(), # seconds since epoch 'header': 'real_time'} self.saver.update_entity_order() # This is for old C files codes using the xperiodic variables self.xperiodic, self.yperiodic, self.zperiodic = mesh.periodicity self.vtk = SaveVTK(self.mesh, name=name) self.set_default_options() def set_default_options(self, gamma=2.21e5, Ms=8.0e5, alpha=0.1): self.default_c = 1e11 self._alpha[:] = alpha self._Ms[:] = Ms self.gamma = gamma self.do_procession = True def reset_integrator(self, t=0): self.integrator.reset(self.spin, t) self.t = t # also reinitialise the simulation time and step self.step = 0 def set_tols(self, rtol=1e-8, atol=1e-10, max_ord=None, reset=True): if max_ord is not None: self.integrator.set_tols(rtol=rtol, atol=atol, max_ord=max_ord) else: # not all integrators have max_ord (only VODE does) # and we don't want to encode a default value here either self.integrator.set_tols(rtol=rtol, atol=atol) if reset: self.reset_integrator(self.t) def set_m(self, m0=(1, 0, 0), normalise=True): self.spin[:] = helper.init_vector(m0, self.mesh, normalise) # TODO: carefully checking and requires to call set_mu first self.spin.shape = (-1, 3) for i in range(self.spin.shape[0]): if self._Ms[i] == 0: self.spin[i, :] = 0 self.spin.shape = (-1,) self.integrator.set_initial_value(self.spin, self.t) def get_pins(self): return self._pins def set_pins(self, pin): self._pins[:] = helper.init_scalar(pin, self.mesh) for i in range(len(self._Ms)): if self._Ms[i] == 0.0: self._pins[i] = 1 pins = property(get_pins, set_pins) def get_alpha(self): return self._alpha def set_alpha(self, value): self._alpha[:] = helper.init_scalar(value, self.mesh) alpha = property(get_alpha, set_alpha) def get_Ms(self): return self._Ms def set_Ms(self, value): self._Ms[:] = helper.init_scalar(value, self.mesh) nonzero = 0 for i in range(self.n): if self._Ms[i] > 0.0: self._Ms_inv = 1.0 / self._Ms[i] nonzero += 1 self.n_nonzero = nonzero for i in range(len(self._Ms)): if self._Ms[i] == 0.0: self._pins[i] = 1 self.Ms_const = np.max(self._Ms) Ms = property(get_Ms, set_Ms) def add(self, interaction, save_field=False): interaction.setup(self.mesh, self.spin, Ms=self._Ms) # TODO: FIX for i in self.interactions: if i.name == interaction.name: interaction.name = i.name + '_2' self.interactions.append(interaction) energy_name = 'E_{0}'.format(interaction.name) self.saver.entities[energy_name] = { 'unit': '<J>', 'get': lambda sim: sim.get_interaction(interaction.name).compute_energy(), 'header': energy_name} if save_field: fn = '{0}'.format(interaction.name) self.saver.entities[fn] = { 'unit': '<>', 'get': lambda sim: sim.get_interaction(interaction.name).average_field(), 'header': ('%s_x' % fn, '%s_y' % fn, '%s_z' % fn)} self.saver.update_entity_order() def get_interaction(self, name): for interaction in self.interactions: if interaction.name == name: return interaction else: raise ValueError("Failed to find the interaction with name '{0}', " "available interactions: {1}.".format( name, [x.name for x in self.interactions])) def run_until(self, t): if t <= self.t: if t == self.t and self.t == 0.0: self.compute_effective_field(t) self.saver.save() return self.spin_last[:] = self.spin[:] flag = self.integrator.run_until(t) if flag < 0: raise Exception("Run cython run_until failed!!!") self.spin[:] = self.integrator.y[:] self.t = t self.step += 1 self.compute_effective_field(t) # update fields before saving data self.saver.save() def compute_effective_field(self, t): #self.spin[:] = y[:] self.field[:] = 0 for obj in self.interactions: self.field += obj.compute_field(t) def sundials_rhs(self, t, y, ydot): self.t = t # already synchronized when call this funciton # self.spin[:]=y[:] self.compute_effective_field(t) clib.compute_llg_rhs(ydot, self.spin, self.field, self.alpha, self._pins, self.gamma, self.n, self.do_procession, self.default_c) #ydot[:] = self.dm_dt[:] return 0 def step_rhs(self, t, y): self.t = t self.compute_effective_field(t) clib.compute_llg_rhs(self.dm_dt, self.spin, self.field, self.alpha, self._pins, self.gamma, self.n, self.do_procession, self.default_c) return self.dm_dt def compute_average(self): self.spin.shape = (-1, 3) average = np.sum(self.spin, axis=0) / self.n_nonzero self.spin.shape = (3 * self.n) return average def compute_energy(self): energy = 0 for obj in self.interactions: energy += obj.compute_energy() return energy def skyrmion_number(self): nx = self.mesh.nx ny = self.mesh.ny nz = self.mesh.nz number = clib.compute_skymrion_number( self.spin, self._skx_number, nx, ny, nz, self.mesh.neighbours) return number def spin_at(self, i, j, k): i1 = 3 * self.mesh.index(i, j, k) # print self.spin.shape,nxy,nx,i1,i2,i3 return np.array([self.spin[i1], self.spin[i1 + 1], self.spin[i1 + 2]]) def add_monitor_at(self, i, j, k, name='p'): """ Save site spin with index (i,j,k) to txt file. """ self.saver.entities[name] = { 'unit': '<>', 'get': lambda sim: sim.spin_at(i, j, k), 'header': (name + '_x', name + '_y', name + '_z')} self.saver.update_entity_order() def save_vtk(self): self.vtk.save_vtk(self.spin.reshape(-1, 3), self.Ms, step=self.step) def save_m(self): if not os.path.exists('%s_npys' % self.name): os.makedirs('%s_npys' % self.name) name = '%s_npys/m_%g.npy' % (self.name, self.step) np.save(name, self.spin) def save_skx(self): if not os.path.exists('%s_skx_npys' % self.name): os.makedirs('%s_skx_npys' % self.name) name = '%s_skx_npys/m_%g.npy' % (self.name, self.step) np.save(name, self._skx_number) def stat(self): return self.integrator.stat() def spin_length(self): self.spin.shape = (3, -1) length = np.sqrt(np.sum(self.spin**2, axis=0)) self.spin.shape = (-1,) return length def compute_spin_error(self): length = self.spin_length() - 1.0 length[self._pins > 0] = 0 return np.max(abs(length)) def compute_dmdt(self, dt): m0 = self.spin_last m1 = self.spin dm = (m1 - m0).reshape((3, -1)) max_dm = np.max(np.sqrt(np.sum(dm**2, axis=0))) max_dmdt = max_dm / dt return max_dmdt def relax(self, dt=1e-11, stopping_dmdt=0.01, max_steps=1000, save_m_steps=100, save_vtk_steps=100): ONE_DEGREE_PER_NS = 17453292.52 for i in range(0, max_steps + 1): cvode_dt = self.integrator.get_current_step() increment_dt = dt if cvode_dt > dt: increment_dt = cvode_dt self.run_until(self.t + increment_dt) if save_vtk_steps is not None: if i % save_vtk_steps == 0: self.save_vtk() if save_m_steps is not None: if i % save_m_steps == 0: self.save_m() dmdt = self.compute_dmdt(increment_dt) print 'step=%d, time=%g, max_dmdt=%g ode_step=%g' % (self.step, self.t, dmdt / ONE_DEGREE_PER_NS, cvode_dt) if dmdt < stopping_dmdt * ONE_DEGREE_PER_NS: break if save_m_steps is not None: self.save_m() if save_vtk_steps is not None: self.save_vtk()
class LLG(object): def __init__(self, mesh, name='unnamed', integrator='sundials'): """Simulation object. *Arguments* name : the Simulation name (used for writing data files, for examples) """ self.t = 0 self.name = name self.mesh = mesh self.n = mesh.n self.n_nonzero = mesh.n self.unit_length = mesh.unit_length self._alpha = np.zeros(self.n, dtype=np.float) self._Ms = np.zeros(self.n, dtype=np.float) self._Ms_inv = np.zeros(self.n, dtype=np.float) self.spin = np.ones(3 * self.n, dtype=np.float) self.spin_last = np.ones(3 * self.n, dtype=np.float) self._pins = np.zeros(self.n, dtype=np.int32) self.field = np.zeros(3 * self.n, dtype=np.float) self.dm_dt = np.zeros(3 * self.n, dtype=np.float) self._skx_number = np.zeros(self.n, dtype=np.float) self.interactions = [] self.pin_fun = None self.integrator_tolerances_set = False self.step = 0 if integrator == "sundials": self.integrator = SundialsIntegrator(self.spin, self.sundials_rhs) elif integrator == "euler" or integrator == "rk4": self.integrator = StepIntegrator(self.spin, self.step_rhs, integrator) else: raise NotImplemented("integrator must be sundials, euler or rk4") self.saver = DataSaver(self, name + '.txt') self.saver.entities['E_total'] = { 'unit': '<J>', 'get': lambda sim: sim.compute_energy(), 'header': 'E_total'} self.saver.entities['m_error'] = { 'unit': '<>', 'get': lambda sim: sim.compute_spin_error(), 'header': 'm_error'} self.saver.entities['skx_num'] = { 'unit': '<>', 'get': lambda sim: sim.skyrmion_number(), 'header': 'skx_num'} self.saver.entities['rhs_evals'] = { 'unit': '<>', 'get': lambda sim: self.integrator.rhs_evals, 'header': 'rhs_evals'} self.saver.entities['real_time'] = { 'unit': '<s>', 'get': lambda _: time.time(), # seconds since epoch 'header': 'real_time'} self.saver.update_entity_order() # This is for old C files codes using the xperiodic variables self.xperiodic, self.yperiodic, self.zperiodic = mesh.periodicity self.vtk = SaveVTK(self.mesh, name=name) self.set_default_options() def set_default_options(self, gamma=2.21e5, Ms=8.0e5, alpha=0.1): self.default_c = 1e11 self._alpha[:] = alpha self._Ms[:] = Ms self.gamma = gamma self.do_precession = True def reset_integrator(self, t=0): self.integrator.reset(self.spin, t) self.t = t # also reinitialise the simulation time and step self.step = 0 def set_tols(self, rtol=1e-8, atol=1e-10, max_ord=None, reset=True): if max_ord is not None: self.integrator.set_tols(rtol=rtol, atol=atol, max_ord=max_ord) else: # not all integrators have max_ord (only VODE does) # and we don't want to encode a default value here either self.integrator.set_tols(rtol=rtol, atol=atol) if reset: self.reset_integrator(self.t) def set_m(self, m0=(1, 0, 0), normalise=True): self.spin[:] = helper.init_vector(m0, self.mesh, normalise) # TODO: carefully checking and requires to call set_mu first self.spin.shape = (-1, 3) for i in range(self.spin.shape[0]): if self._Ms[i] == 0: self.spin[i, :] = 0 self.spin.shape = (-1,) self.integrator.set_initial_value(self.spin, self.t) def get_pins(self): return self._pins def set_pins(self, pin): self._pins[:] = helper.init_scalar(pin, self.mesh) for i in range(len(self._Ms)): if self._Ms[i] == 0.0: self._pins[i] = 1 pins = property(get_pins, set_pins) def get_alpha(self): return self._alpha def set_alpha(self, value): self._alpha[:] = helper.init_scalar(value, self.mesh) alpha = property(get_alpha, set_alpha) def get_Ms(self): return self._Ms def set_Ms(self, value): self._Ms[:] = helper.init_scalar(value, self.mesh) nonzero = 0 for i in range(self.n): if self._Ms[i] > 0.0: self._Ms_inv = 1.0 / self._Ms[i] nonzero += 1 self.n_nonzero = nonzero for i in range(len(self._Ms)): if self._Ms[i] == 0.0: self._pins[i] = 1 self.Ms_const = np.max(self._Ms) Ms = property(get_Ms, set_Ms) def add(self, interaction, save_field=False): interaction.setup(self.mesh, self.spin, Ms=self._Ms) # TODO: FIX for i in self.interactions: if i.name == interaction.name: interaction.name = i.name + '_2' self.interactions.append(interaction) energy_name = 'E_{0}'.format(interaction.name) self.saver.entities[energy_name] = { 'unit': '<J>', 'get': lambda sim: sim.get_interaction(interaction.name).compute_energy(), 'header': energy_name} if save_field: fn = '{0}'.format(interaction.name) self.saver.entities[fn] = { 'unit': '<>', 'get': lambda sim: sim.get_interaction(interaction.name).average_field(), 'header': ('%s_x' % fn, '%s_y' % fn, '%s_z' % fn)} self.saver.update_entity_order() def get_interaction(self, name): for interaction in self.interactions: if interaction.name == name: return interaction else: raise ValueError("Failed to find the interaction with name '{0}', " "available interactions: {1}.".format( name, [x.name for x in self.interactions])) def run_until(self, t): if t <= self.t: if t == self.t and self.t == 0.0: self.compute_effective_field(t) self.saver.save() return self.spin_last[:] = self.spin[:] flag = self.integrator.run_until(t) if flag < 0: raise Exception("Run cython run_until failed!!!") self.spin[:] = self.integrator.y[:] self.t = t self.step += 1 self.compute_effective_field(t) # update fields before saving data self.saver.save() def compute_effective_field(self, t): #self.spin[:] = y[:] self.field[:] = 0 for obj in self.interactions: self.field += obj.compute_field(t) def sundials_rhs(self, t, y, ydot): self.t = t # already synchronized when call this funciton # self.spin[:]=y[:] self.compute_effective_field(t) clib.compute_llg_rhs(ydot, self.spin, self.field, self.alpha, self._pins, self.gamma, self.n, self.do_precession, self.default_c) #ydot[:] = self.dm_dt[:] return 0 def step_rhs(self, t, y): self.t = t self.compute_effective_field(t) clib.compute_llg_rhs(self.dm_dt, self.spin, self.field, self.alpha, self._pins, self.gamma, self.n, self.do_precession, self.default_c) return self.dm_dt def compute_average(self): self.spin.shape = (-1, 3) average = np.sum(self.spin, axis=0) / self.n_nonzero self.spin.shape = (3 * self.n) return average def compute_energy(self): energy = 0 for obj in self.interactions: energy += obj.compute_energy() return energy def skyrmion_number(self): nx = self.mesh.nx ny = self.mesh.ny nz = self.mesh.nz number = clib.compute_skymrion_number( self.spin, self._skx_number, nx, ny, nz, self.mesh.neighbours) return number def spin_at(self, i, j, k): i1 = 3 * self.mesh.index(i, j, k) # print self.spin.shape,nxy,nx,i1,i2,i3 return np.array([self.spin[i1], self.spin[i1 + 1], self.spin[i1 + 2]]) def add_monitor_at(self, i, j, k, name='p'): """ Save site spin with index (i,j,k) to txt file. """ self.saver.entities[name] = { 'unit': '<>', 'get': lambda sim: sim.spin_at(i, j, k), 'header': (name + '_x', name + '_y', name + '_z')} self.saver.update_entity_order() def save_vtk(self): self.vtk.save_vtk(self.spin.reshape(-1, 3), self.Ms, step=self.step) def save_m(self): if not os.path.exists('%s_npys' % self.name): os.makedirs('%s_npys' % self.name) name = '%s_npys/m_%g.npy' % (self.name, self.step) np.save(name, self.spin) def save_skx(self): if not os.path.exists('%s_skx_npys' % self.name): os.makedirs('%s_skx_npys' % self.name) name = '%s_skx_npys/m_%g.npy' % (self.name, self.step) np.save(name, self._skx_number) def stat(self): return self.integrator.stat() def spin_length(self): self.spin.shape = (3, -1) length = np.sqrt(np.sum(self.spin**2, axis=0)) self.spin.shape = (-1,) return length def compute_spin_error(self): length = self.spin_length() - 1.0 length[self._pins > 0] = 0 return np.max(abs(length)) def compute_dmdt(self, dt): m0 = self.spin_last m1 = self.spin dm = (m1 - m0).reshape((3, -1)) max_dm = np.max(np.sqrt(np.sum(dm**2, axis=0))) max_dmdt = max_dm / dt return max_dmdt def relax(self, dt=1e-11, stopping_dmdt=0.01, max_steps=1000, save_m_steps=100, save_vtk_steps=100): ONE_DEGREE_PER_NS = 17453292.52 for i in range(0, max_steps + 1): cvode_dt = self.integrator.get_current_step() increment_dt = dt if cvode_dt > dt: increment_dt = cvode_dt self.run_until(self.t + increment_dt) if save_vtk_steps is not None: if i % save_vtk_steps == 0: self.save_vtk() if save_m_steps is not None: if i % save_m_steps == 0: self.save_m() dmdt = self.compute_dmdt(increment_dt) print 'step=%d, time=%g, max_dmdt=%g ode_step=%g' % (self.step, self.t, dmdt / ONE_DEGREE_PER_NS, cvode_dt) if dmdt < stopping_dmdt * ONE_DEGREE_PER_NS: break if save_m_steps is not None: self.save_m() if save_vtk_steps is not None: self.save_vtk()