def step(self, u_start: VectorHeat1D2Pts, t_start: float, t_stop: float) -> VectorHeat1D2Pts: """ Time integration routine for 1D heat equation example problem: Backward Euler (BDF1) One-step method u_i = (I + dt*L)^{-1} * (u_{i-1} + dt*b_i), where L = self.space_disc is the spatial discretization operator Note: step takes two BDF1 steps * one step from (t_start + dtau) to t_stop * one step from t_stop to (t_stop + dtau) :param u_start: approximate solution for the input time t_start :param t_start: time associated with the input approximate solution u_start :param t_stop: time to evolve the input approximate solution to :return: approximate solution at input time t_stop """ first, second, dtau = u_start.get_values() tmp1 = spsolve( (t_stop - t_start - dtau) * self.space_disc + self.identity, second + self.rhs(self.x, t_stop) * (t_stop - t_start - dtau)) tmp2 = spsolve(dtau * self.space_disc + self.identity, tmp1 + self.rhs(self.x, t_stop + dtau) * dtau) ret = VectorHeat1D2Pts(u_start.size, u_start.dtau) ret.set_values(first_time_point=tmp1, second_time_point=tmp2, dtau=dtau) return ret
def __init__(self, x_start: float, x_end: float, nx: int, dtau: float, a: float, init_cond: Callable = lambda x: x * 0, rhs: Callable = lambda x, t: x * 0, *args, **kwargs): """ Constructor. :param x_start: left interval bound of spatial domain :param x_end: right interval bound of spatial domain :param nx: number of spatial degrees of freedom :param dtau: time-step size within pair :param a: thermal conductivity :param init_cond: initial condition :param rhs: right-hand side """ super().__init__(*args, **kwargs) # Spatial domain with homogeneous Dirichlet boundary conditions self.x_start = x_start self.x_end = x_end self.x = np.linspace(self.x_start, self.x_end, nx) self.x = self.x[1:-1] self.nx = nx - 2 self.dx = self.x[1] - self.x[0] # Thermal conductivity self.a = a # (Spatial) identity matrix and spatial discretization matrix self.identity = identity(self.nx, dtype='float', format='csr') self.space_disc = self.compute_matrix() # Set right-hand side routine self.rhs = rhs # Set the data structure for any user-defined time-point pairs self.vector_template = VectorHeat1D2Pts(self.nx, dtau) # Set initial condition self.init_cond = init_cond self.vector_t_start = VectorHeat1D2Pts(self.nx, dtau) tmp1 = self.init_cond(self.x) # Use trapezoidal rule to get value at time dtau tmp2 = spsolve( (dtau / 2) * self.space_disc + self.identity, (self.identity - (dtau / 2) * self.space_disc) * tmp1 + (dtau / 2) * (self.rhs(self.x, self.t[0]) + self.rhs(self.x, self.t[0] + dtau))) self.vector_t_start.set_values(first_time_point=tmp1, second_time_point=tmp2, dtau=dtau)
def step(self, u_start: VectorHeat1D2Pts, t_start: float, t_stop: float) -> VectorHeat1D2Pts: """ Time integration routine for 1D heat equation: BDF2 Two-step method on variably spaced grid with spacing tau_i = t_i - t_{i-1}. In time-based stencil notation, we have at time point t_i [r_i^2/(tau_i*(1+r_i))*I, -((1+r_i)/tau_i)*I, (1+2r_i)/(tau_i*(1+r_i))*I + L, 0, 0], where L = self.space_disc is the spatial discretization operator and r_i = tau_i/tau_{i-1} Note: For the pair associated with input time t_stop * update at t_stop involves values at t_start and (t_start + dtau) * update at t_stop + dtau involves values at (t_start + dtau) and t_stop :param u_start: approximate solution for the input time t_start :param t_start: time associated with the input approximate solution u_start :param t_stop: time to evolve the input approximate solution to :return: approximate solution for the input time t_stop """ first, second, dtau = u_start.get_values() # Update value at t_i = t_stop tau_i = t_stop - t_start - dtau tau_im1 = dtau r_i = tau_i / tau_im1 coeffm2 = (r_i**2) / (tau_i * (1 + r_i)) coeffm1 = (1 + r_i) / tau_i coeff = (1 + 2 * r_i) / (tau_i * (1 + r_i)) rhs = self.rhs(self.x, t_stop) - coeffm2 * first + coeffm1 * second tmp1 = spsolve(self.space_disc + coeff * self.identity, rhs) # Update value at t_i = t_stop + dtau tau_im1 = tau_i tau_i = dtau r_i = tau_i / tau_im1 coeffm2 = (r_i**2) / (tau_i * (1 + r_i)) coeffm1 = (1 + r_i) / tau_i coeff = (1 + 2 * r_i) / (tau_i * (1 + r_i)) rhs = self.rhs(self.x, t_stop + dtau) - coeffm2 * second + coeffm1 * tmp1 tmp2 = spsolve(self.space_disc + coeff * self.identity, rhs) ret = VectorHeat1D2Pts(u_start.size, u_start.dtau) ret.set_values(first_time_point=tmp1, second_time_point=tmp2, dtau=dtau) return ret
def test_vector_heat_1d_2pts_sub(): """ Test __sub__ """ vector_heat_1d_2pts_1 = VectorHeat1D2Pts(size=3, dtau=0.1) vector_heat_1d_2pts_1.values_first_time_point = np.ones(3) vector_heat_1d_2pts_1.values_second_time_point = np.ones(3) vector_heat_1d_2pts_2 = VectorHeat1D2Pts(size=3, dtau=0.1) vector_heat_1d_2pts_2.values_first_time_point = 2 * np.ones(3) vector_heat_1d_2pts_2.values_second_time_point = 2 * np.ones(3) vector_heat_1d_2pts_res = vector_heat_1d_2pts_2 - vector_heat_1d_2pts_1 np.testing.assert_equal(vector_heat_1d_2pts_res.values_first_time_point, np.ones(3)) np.testing.assert_equal(vector_heat_1d_2pts_res.values_second_time_point, np.ones(3))
def test_vector_heat_1d_2pts_get_values(): """ Test get_values() """ vector_heat_1d_2pts = VectorHeat1D2Pts(size=5, dtau=0.1) np.testing.assert_equal(vector_heat_1d_2pts.get_values()[0], np.zeros(5)) np.testing.assert_equal(vector_heat_1d_2pts.get_values()[1], np.zeros(5)) np.testing.assert_equal(vector_heat_1d_2pts.get_values()[2], 0.1)
def test_vector_heat_1d_2pts_norm(): """ Test norm() """ vector_heat_1d_2pts = VectorHeat1D2Pts(size=5, dtau=0.1) vector_heat_1d_2pts.values_first_time_point = np.array([1, 2, 3, 4, 5]) vector_heat_1d_2pts.values_second_time_point = np.array([1, 2, 3, 4, 5]) np.testing.assert_equal(np.linalg.norm(np.append(np.array([1, 2, 3, 4, 5]), np.array([1, 2, 3, 4, 5]))), vector_heat_1d_2pts.norm())
def test_vector_heat_1d_2pts_set_values(): """ Test the set_values() """ vector_heat_1d_2pts = VectorHeat1D2Pts(size=2, dtau=0.1) vector_heat_1d_2pts.set_values(first_time_point=np.array([1, 2]), second_time_point=np.array([2, 3]), dtau=0.1) np.testing.assert_equal(vector_heat_1d_2pts.values_first_time_point, np.array([1, 2])) np.testing.assert_equal(vector_heat_1d_2pts.values_second_time_point, np.array([2, 3])) np.testing.assert_equal(vector_heat_1d_2pts.dtau, 0.1)
def test_vector_heat_1d_2pts_clone_rand(): """ Test clone_rand() """ vector_heat_1d_2pts = VectorHeat1D2Pts(size=2, dtau=0.1) vector_heat_1d_2pts_clone = vector_heat_1d_2pts.clone_rand() np.testing.assert_equal(True, isinstance(vector_heat_1d_2pts_clone, VectorHeat1D2Pts)) np.testing.assert_equal(vector_heat_1d_2pts_clone.size, 2) np.testing.assert_equal(vector_heat_1d_2pts_clone.dtau, 0.1) np.testing.assert_equal(len(vector_heat_1d_2pts_clone.values_first_time_point), 2) np.testing.assert_equal(len(vector_heat_1d_2pts_clone.values_second_time_point), 2)
def test_vector_heat_1d_2pts_constructor(): """ Test constructor """ vector_heat_1d_2pts = VectorHeat1D2Pts(size=3, dtau=0.1) np.testing.assert_equal(vector_heat_1d_2pts.size, 3) np.testing.assert_equal(vector_heat_1d_2pts.dtau, 0.1) np.testing.assert_equal(vector_heat_1d_2pts.values_first_time_point[0], 0) np.testing.assert_equal(vector_heat_1d_2pts.values_first_time_point[1], 0) np.testing.assert_equal(vector_heat_1d_2pts.values_first_time_point[2], 0) np.testing.assert_equal(vector_heat_1d_2pts.values_second_time_point[0], 0) np.testing.assert_equal(vector_heat_1d_2pts.values_second_time_point[1], 0) np.testing.assert_equal(vector_heat_1d_2pts.values_second_time_point[2], 0)
def test_vector_heat_1d_2pts_mul(): """ Test __mul__ """ vector_heat_1d_2pts_1 = VectorHeat1D2Pts(size=3, dtau=0.1) vector_heat_1d_2pts_1.values_first_time_point = np.ones(3) vector_heat_1d_2pts_1.values_second_time_point = np.ones(3) vector_heat_1d_2pts_res = vector_heat_1d_2pts_1 * 3 np.testing.assert_equal(vector_heat_1d_2pts_res.values_first_time_point, np.ones(3)*3) np.testing.assert_equal(vector_heat_1d_2pts_res.values_second_time_point, np.ones(3)*3) vector_heat_1d_2pts_res = 5 * vector_heat_1d_2pts_1 np.testing.assert_equal(vector_heat_1d_2pts_res.values_first_time_point, np.ones(3)*5) np.testing.assert_equal(vector_heat_1d_2pts_res.values_second_time_point, np.ones(3)*5) vector_heat_1d_2pts_res *= 4 np.testing.assert_equal(vector_heat_1d_2pts_res.values_first_time_point, np.ones(3)*20) np.testing.assert_equal(vector_heat_1d_2pts_res.values_second_time_point, np.ones(3)*20)