def adjust_stepsize(self, state, h, order, y, y_err, dydt): # [y] = A/m. # [dydt] = A/m (deriviative of y). # [y_err] = A/m (estimated error dydt). # - One RK step: y = y_prev + (h*dydt +- y_err) max_y_err = magneto.scaled_abs_max( y_err, state.Ms ) # max_y_err = max_i(|y_err[i]| / Ms[i]), [max_y_err] = rad max_dydt = magneto.scaled_abs_max( dydt, state.Ms ) # max_dydt = max_i(|dydt[i]| / Ms[i]), [max_dydt] = rad/s # Calculate estimated absolute and relative error. try: e_abs = max_y_err # [e_abs] = rad e_rel = e_abs / (h * max_dydt) # [e_rel] = 1 except ZeroDivisionError: print("ZeroDivisionError!") return True, 5e-14 # Accept the step only with tolerable errors. accept = (e_abs <= self.allowed_absolute_error) and ( e_rel <= self.allowed_relative_error) # Determine step size scaling factor for allowed absolute and relative errors. h_scale_abs = self.STEP_HEADROOM * pow( self.allowed_absolute_error / e_abs, 1.0 / (order + 1.0)) h_scale_rel = self.STEP_HEADROOM * pow( self.allowed_relative_error / e_rel, 1.0 / order) def clamp(x, min_x, max_x): if x < min_x: x = min_x if x > max_x: x = max_x return x # Take the most pessimistic (= smallest) scaling factor and clamp by [max_step_decrease, max_step_increase] h_scale = clamp(min([h_scale_abs, h_scale_rel]), self.MIN_TIMESTEP_SCALE, self.MAX_TIMESTEP_SCALE) # Determine next step size and clamp by [min_h, max_h] h_next = clamp(h * h_scale, self.MIN_TIMESTEP, self.MAX_TIMESTEP) # Accept step anyway if time step can not go any smaller. if h_next == self.MIN_TIMESTEP: accept = True return accept, h_next
def test_1(self): mesh = RectangularMesh((10,10,10), (1e-9,1e-9,1e-9)) M = VectorField(mesh); M.fill((-8e5,0,0)) Ms = Field(mesh); Ms.fill(8e5) sam = magneto.scaled_abs_max(M, Ms) self.assertEqual(1.0, sam)
def test_2(self): mesh = RectangularMesh((10, 10, 10), (1e-9, 1e-9, 1e-9)) M = VectorField(mesh) M.fill((-8e5, 0, 0)) Ms = Field(mesh) Ms.fill(8e5) Ms.set(0, 0) Ms.set(0, 8e5) self.assertFalse(Ms.isUniform()) sam = magneto.scaled_abs_max(M, Ms) self.assertEqual(1.0, sam)
def adjust_stepsize(self, state, h, order, y, y_err, dydt): # [y] = A/m. # [dydt] = A/m (deriviative of y). # [y_err] = A/m (estimated error dydt). # - One RK step: y = y_prev + (h*dydt +- y_err) max_y_err = magneto.scaled_abs_max(y_err, state.Ms) # max_y_err = max_i(|y_err[i]| / Ms[i]), [max_y_err] = rad max_dydt = magneto.scaled_abs_max(dydt, state.Ms) # max_dydt = max_i(|dydt[i]| / Ms[i]), [max_dydt] = rad/s # Calculate estimated absolute and relative error. try: e_abs = max_y_err # [e_abs] = rad e_rel = e_abs / (h*max_dydt) # [e_rel] = 1 except ZeroDivisionError: print("ZeroDivisionError!") return True, 5e-14 # Accept the step only with tolerable errors. accept = (e_abs <= self.allowed_absolute_error) and (e_rel <= self.allowed_relative_error) # Determine step size scaling factor for allowed absolute and relative errors. h_scale_abs = self.STEP_HEADROOM * pow(self.allowed_absolute_error / e_abs, 1.0/(order+1.0)) h_scale_rel = self.STEP_HEADROOM * pow(self.allowed_relative_error / e_rel, 1.0/order) def clamp(x, min_x, max_x): if x < min_x: x = min_x if x > max_x: x = max_x return x # Take the most pessimistic (= smallest) scaling factor and clamp by [max_step_decrease, max_step_increase] h_scale = clamp(min([h_scale_abs, h_scale_rel]), self.MIN_TIMESTEP_SCALE, self.MAX_TIMESTEP_SCALE) # Determine next step size and clamp by [min_h, max_h] h_next = clamp(h * h_scale, self.MIN_TIMESTEP, self.MAX_TIMESTEP) # Accept step anyway if time step can not go any smaller. if h_next == self.MIN_TIMESTEP: accept = True return accept, h_next