From 520bb6f25fe09be8cbe0f6aa9281f757a8ad2916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=BChle=2C=20Laura=20Christine=20=28lakue103=29?= <laura.kuehle@uni-duesseldorf.de> Date: Fri, 10 Mar 2023 15:43:36 +0100 Subject: [PATCH] Added 'update_right_hand_side()' for Burgers class. --- Snakefile | 6 +- scripts/tcd/Equation.py | 138 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/Snakefile b/Snakefile index b415bad..03a1175 100644 --- a/Snakefile +++ b/Snakefile @@ -32,9 +32,11 @@ TODO: Add 'update_time_step()' to Burgers -> Done TODO: Add derivative basis to Basis class -> Done TODO: Fix wrong type for number of quadrature nodes -> Done TODO: Add 'solve_exactly()' to Burgers -TODO: Add 'update_right_hand_side()' to Burgers -TODO: Add initialization to Burgers +TODO: Add 'update_right_hand_side()' to Burgers -> Done TODO: Add Dirichlet boundary +TODO: Test Burgers +TODO: Rework Burgers for speed-up and better structure +TODO: Add initialization to Burgers TODO: Use cfl_number for updating, not just time (equation-related?) Critical, but not urgent: diff --git a/scripts/tcd/Equation.py b/scripts/tcd/Equation.py index d0bd5ce..5298b04 100644 --- a/scripts/tcd/Equation.py +++ b/scripts/tcd/Equation.py @@ -7,6 +7,7 @@ from typing import Tuple from abc import ABC, abstractmethod import numpy as np from numpy import ndarray +from sympy import Symbol from .Basis_Function import Basis from .Boundary_Condition import enforce_boundary @@ -16,6 +17,9 @@ from .projection_utils import do_initial_projection from .Quadrature import Quadrature +x = Symbol('x') + + class Equation(ABC): """Abstract class for equation. @@ -496,6 +500,23 @@ class Burgers(Equation): """ pass + volume_integral_matrix = self._burgers_volume_integral(projection) + boundary_matrix = self._burgers_boundary_matrix(projection) + + # Initialize vector and set first entry to accommodate for ghost cell + right_hand_side = [0] + + for j in range(self._mesh.num_cells): + right_hand_side.append(2*(volume_integral_matrix[:, j + 1] + + boundary_matrix[:, j + 1])) + + # Set ghost cells to respective value + # (Periodic, Updated to Dirichlet in enforce_boundary_condition + # for DiscontinuousConstant problem) + # right_hand_side[0] = right_hand_side[self._mesh.num_cells] + # right_hand_side.append(right_hand_side[1]) + + return np.transpose(right_hand_side) # right_hand_side = np.zeros_like(projection) # if self._wave_speed > 0: # right_hand_side[:, self._mesh.num_ghost_cells: @@ -516,3 +537,120 @@ class Burgers(Equation): # -self._mesh.num_ghost_cells]) # # return right_hand_side + + def _burgers_volume_integral(self, projection): + basis_vector = self._basis.basis + derivative_basis_vector = self._basis.derivative + + # Initialize matrix and set first entry to accommodate for ghost cell + volume_integral_matrix = [0] + + for cell in range(self._mesh.num_cells): + new_row = [] + # Approximation u at Gauss-Legendre points + approx_eval = [sum(projection[degree][cell + 1] + * basis_vector[degree].subs( + x, self._quadrature.nodes[point]) + for degree in range( + self._basis.polynomial_degree + 1)) + for point in range(self._quadrature.nodes)] + approx_eval = np.array(approx_eval) + + # print("u", approx_eval) + # Quadrature Evaluation + for degree in range(self._basis.polynomial_degree + 1): + weighted_derivatives = [ + derivative_basis_vector[degree].subs( + x, self._quadrature.nodes[point]) + * self._quadrature.weights[point] + for point in range(self._quadrature.num_nodes)] + new_entry = sum(list(approx_eval**2 * weighted_derivatives)) / 2 + + new_row.append(np.float64(new_entry)) + + new_row = np.array(new_row).T + volume_integral_matrix.append(new_row) + + # Set ghost cells to respective value + # (Periodic, Updated to Dirichlet in enforce_boundary_condition + # for DiscontinuousConstant problem) + # volume_integral_matrix[0] = volume_integral_matrix[ + # self._mesh.num_cells] + # volume_integral_matrix.append(volume_integral_matrix[1]) + + return np.transpose(np.array(volume_integral_matrix)) + + def _burgers_local_Lax_Friedrichs(self, projection): + # Calculating the left and right boundaries for each cell, + # u_{j-1/2}^+, u_{j+1/2}^- + boundary_left, boundary_right = self._calculate_boundary_points( + projection, self._basis.polynomial_degree + 1) + # print("shape BL", boundary_left.shape) + + # Initializing Burgers local Lax-Friedrichs flux matrix + burgers_flux = [0] + for j in range(self._mesh.num_cells): + # approximations j+1/2^-, j+1/2^+ for interior cells + # and max velocity + approx_minus = boundary_right[:, j+1] + approx_plus = boundary_left[:, j + 2] + max_velocity = max(abs(approx_minus), abs(approx_plus)) + + # respective fluxes + flux_minus = approx_minus**2 / 2 + flux_plus = approx_plus**2 / 2 + + # local Lax-Friedrichs flux + numerical_flux = 0.5 * (flux_minus + flux_plus - max_velocity * + (approx_plus - approx_minus)) + + burgers_flux.append(numerical_flux) + + # Set Ghost cells to respective value + # (Periodic, Updated to Dirichlet in enforce_boundary_condition + # for DiscontinuousConstant problem) + # burgers_flux[0] = burgers_flux[self._mesh.num_cells] + # burgers_flux.append(burgers_flux[1]) + + return np.array(burgers_flux) + + def _burgers_boundary_matrix(self, projection): + burgers_LF_flux = self._burgers_local_Lax_Friedrichs(projection) + + # Initializing boundary matrix + boundary_matrix = [0] + + for j in range(self._mesh.num_cells): + new_row = [] + for degree in range(self._basis.polynomial_degree + 1): + new_row.append(np.sqrt(degree + 0.5) * + (-burgers_LF_flux[j + 1] + (-1)**degree * + burgers_LF_flux[j])) + + boundary_matrix.append(new_row) + + # Set Ghost cells to respective value + # (Periodic, Updated to Dirichlet in enforce_boundary_condition + # for DiscontinuousConstant problem) + # boundary_matrix[0] = boundary_matrix[self._mesh.num_cells] + # boundary_matrix.append(boundary_matrix[1]) + + boundary_matrix = np.transpose(np.array(boundary_matrix)) + + return boundary_matrix[0] + + @staticmethod + def _calculate_boundary_points(projection, max_degree): + # Approximation at j-1/2 ^+ + boundary_left = [sum(projection[degree][cell] * (-1) ** degree * + np.sqrt(degree + 0.5) + for degree in range(max_degree)) + for cell in range(len(projection[0]))] + + # Approximation at j+1/2 ^- + boundary_right = [sum(projection[degree][cell]* np.sqrt(degree + 0.5) + for degree in range(max_degree)) + for cell in range(len(projection[0]))] + + return np.reshape(np.array(boundary_left), (1, len(boundary_left))), \ + np.reshape(np.array(boundary_right), (1, len(boundary_right))) -- GitLab