├── LICENSE ├── README.md ├── hyper1D ├── LICENSE ├── PDE1D_Octave │ ├── README.txt │ ├── compute_fluxes_HLL.m │ ├── main.m │ ├── octave-workspace │ └── phys_const.m ├── README ├── src_hyper1D │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── pde.f03 │ ├── tools.f03 │ └── tools │ │ └── octaPLOTSOL_Euler.m └── src_hyper1D_simple │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── pde.f03 │ ├── tools.f03 │ └── tools │ └── octaPLOTSOL_Euler.m ├── hyper2D_CUDA ├── LICENSE ├── README ├── src_hyper2D_CUDA │ ├── Makefile │ ├── PDEs_various │ │ ├── pde_Euler.cuf │ │ ├── pde_Euler_AXI.cuf │ │ ├── pde_Euler_relativistic_AXI.cuf │ │ └── pde_shallow_water.cuf │ ├── global_module.cuf │ ├── hyper2D.cuf │ ├── integration.cuf │ ├── pde.cuf │ └── tools.cuf └── src_hyper2D_CUDA_simplest │ ├── Makefile │ ├── global_module.cuf │ ├── hyper2D.cuf │ ├── integration.cuf │ ├── pde.cuf │ └── tools.cuf └── hyper2D_single_core ├── hyper2D_basic ├── AXISYMMETRIC │ ├── LICENSE │ ├── README │ └── src │ │ ├── Makefile │ │ ├── global_module.f03 │ │ ├── hyper2D.f03 │ │ ├── integration.f03 │ │ ├── pde.f03 │ │ ├── tools.f03 │ │ └── various_PDEs │ │ ├── pde_Euler.f03 │ │ ├── pde_shallow_water.f03 │ │ └── pde_vibration.f03 ├── LICENSE ├── README ├── src_basic │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── pde.f03 │ ├── tools.f03 │ └── various_PDEs │ │ ├── pde_Euler.f03 │ │ ├── pde_shallow_water.f03 │ │ └── pde_vibration.f03 └── src_higher_order │ ├── LICENSE │ ├── README │ └── src │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── pde.f03 │ └── tools.f03 ├── hyper2D_flatplate ├── LICENSE ├── README └── src │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── pde.f03 │ └── tools.f03 ├── hyper2D_hypersonic ├── LICENSE ├── README └── src │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── other_files │ ├── integration_explicit.f03 │ ├── integration_point_implicit.f03 │ ├── pde_TTv.f03 │ ├── pde_monatomic.f03 │ └── pde_vibration.f03 │ ├── pde.f03 │ └── tools.f03 ├── hyper2D_kinetic ├── LICENSE ├── README ├── relativistic │ ├── LICENSE │ ├── README │ └── src │ │ ├── Makefile │ │ ├── global_module.f03 │ │ ├── hyper2D.f03 │ │ ├── integration.f03 │ │ ├── nohup.out │ │ ├── pde.f03 │ │ └── tools.f03 └── src │ ├── Makefile │ ├── global_module.f03 │ ├── hyper2D.f03 │ ├── integration.f03 │ ├── pde.f03 │ └── tools.f03 └── hyper2D_unstructured ├── LICENSE ├── README └── src ├── Makefile ├── global_module.f03 ├── grid.f03 ├── hyper2D.f03 ├── integration.f03 ├── mesh.hyp ├── mesh_preprocessing ├── cyl_mesh_finer.su2 └── process_su2_quad_grid.m ├── nodes.hyp ├── pde.f03 └── tools.f03 /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper1D/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper1D/PDE1D_Octave/README.txt: -------------------------------------------------------------------------------- 1 | This folder contains the Octave/MATLAB solver "PDE1D", that 2 | demonstrates the finite volume method in 1-dimension for the 3 | Euler equations. 4 | 5 | The solution is initialized as a Riemann problem, showing 6 | two initially uniform states separated by a discontinuity 7 | (Sod shock tube problem). 8 | 9 | Open Octave/MATLAB and run the main.m script. 10 | -------------------------------------------------------------------------------- /hyper1D/PDE1D_Octave/compute_fluxes_HLL.m: -------------------------------------------------------------------------------- 1 | function F_int = compute_fluxes_HLL(U) 2 | 3 | % This function computes all interface numerical fluxes, using 4 | % the HLL scheme. 5 | 6 | phys_const; % Load physical constants 7 | 8 | N_int = size(U,2)-1; % aka N_int = N_cells - 1 9 | 10 | % Loop on interfaces 11 | for ii = 1:N_int 12 | 13 | % ID CELLS 14 | ID_C_L = ii; 15 | ID_C_R = ii+1; 16 | 17 | % Solution at the Left and Right of the interface 18 | UL = U(:, ID_C_L); 19 | UR = U(:, ID_C_R); 20 | 21 | % Reconstruct solution (aka primitive variables) 22 | rhoL = UL(1); 23 | uL = UL(2)/rhoL; 24 | PL = (gam-1)*(UL(3) - rhoL*uL*uL/2); 25 | 26 | rhoR = UR(1); 27 | uR = UR(2)/rhoR; 28 | PR = (gam-1)*(UR(3) - rhoR*uR*uR/2); 29 | 30 | % Build flux function (from the Euler equations) 31 | FL = [0;0;0]; 32 | FL(1) = rhoL*uL; 33 | FL(2) = rhoL*uL*uL + PL; 34 | FL(3) = rhoL*uL^3/2 + PL/(gam-1)*uL + PL*uL; 35 | 36 | FR = [0;0;0]; 37 | FR(1) = rhoR*uR; 38 | FR(2) = rhoR*uR*uR + PR; 39 | FR(3) = rhoR*uR^3/2 + PR/(gam-1)*uR + PR*uR; 40 | 41 | % Compute wave speeds 42 | aL = sqrt(gam*PL/rhoL); % Speed of sound in the left cell 43 | aR = sqrt(gam*PR/rhoR); % Speed of sound in the right cell 44 | 45 | sMinL = uL - aL; % Minimum wave speed (Euler's eq eigenvalues) 46 | sMaxR = uR + aR; % Maximum wave speed (Euler's eq eigenvalues) 47 | 48 | % HLL fluxes 49 | if (sMinL >= 0) 50 | F_int(:,ii) = FL; 51 | elseif (sMaxR <= 0) 52 | F_int(:,ii) = FR; 53 | else 54 | F_int(:,ii) = (sMinL*sMaxR*(UR - UL) + sMaxR*FL - sMinL*FR)/(sMaxR - sMinL); 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /hyper1D/PDE1D_Octave/main.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear 3 | clc 4 | 5 | % For Octave 6 | try 7 | page_screen_output(0); 8 | end 9 | 10 | % Load phys stuff 11 | phys_const; 12 | 13 | % =============== Time discretization ==================== 14 | dt = 2e-6; % [s] time step 15 | N_time = 200; % Number of time steps 16 | t_vect = [0:dt:dt*N_time]; % Array of times 17 | 18 | % =============== Create mesh ==================== 19 | x_min = 0.0; % [m] Domain size 20 | x_max = 1.0; % [m] Domain size 21 | N_cells = 500; % Number of cells, including ghost cells 22 | N_int = N_cells - 1; % Number of interfaces 23 | 24 | Lcell = (x_max - x_min)/(N_cells-2); % [m] size of a single cell 25 | x_cc = linspace(x_min - Lcell/2, x_max + Lcell/2, N_cells); 26 | x_int = (x_cc(2:end) + x_cc(1:end-1))/2; 27 | 28 | % ============== Solution vector ================== 29 | 30 | % The solution vector U contains 3 rows (one for the density, one for the momentum 31 | % and one for the energy) and one column for each grid cell 32 | 33 | U = zeros(3, N_cells); 34 | 35 | % +++++ Initial condition - initialize as the Sod shocktube problem 36 | 37 | % Left state 38 | rhoL = 4.0; % [kg/m3] density 39 | uL = 0.0; % [m/s] velocity 40 | PL = 400000; % [Pa] pressure 41 | 42 | U(1,1:floor(N_cells/2)) = rhoL; 43 | U(2,1:floor(N_cells/2)) = rhoL*uL; 44 | U(3,1:floor(N_cells/2)) = rhoL*uL^2/2 + PL/(gam-1); 45 | 46 | % Right state 47 | rhoR = 1.0; % [kg/m3] density 48 | uR = 0.0; % [m/s] velocity 49 | PR = 100000; % [Pa] pressure 50 | 51 | U(1,floor(N_cells/2):end) = rhoR; 52 | U(2,floor(N_cells/2):end) = rhoR*uR; 53 | U(3,floor(N_cells/2):end) = rhoR*uR^2/2 + PR/(gam-1); 54 | 55 | % =============== SOLVE IN TIME =============== 56 | SolFig = figure(); 57 | 58 | for tID = 1:N_time 59 | 60 | fprintf('Solving timestep %d of %d\n', tID, N_time); 61 | 62 | % Compute interface numerical fluxes from solution 63 | F_int = compute_fluxes_HLL(U); % This is a matrix, with N_int columns 64 | 65 | % Update solution (Forward Euler) 66 | % The solution in a cell is the solution itself PLUS the flux from the left interface 67 | % MINUS the flux from the right interface 68 | U(:,2:end-1) = U(:, 2:end-1) + dt/Lcell*(F_int(:, 1:end-1) - F_int(:, 2:end)); 69 | 70 | % Plot the solution every Nplot steps 71 | Nplot = 10; 72 | if (mod(tID,Nplot)==0) 73 | subplot(3,1,1) 74 | plot(x_cc, U(1,:),'b','linewidth',2); 75 | xlabel('Position [m]') 76 | ylabel('Density [kg/m3]') 77 | title(['Time: ', num2str(t_vect(tID)), ' s']); 78 | 79 | subplot(3,1,2) 80 | plot(x_cc, U(2,:),'b','linewidth',2); 81 | xlabel('Position [m]') 82 | ylabel('Momentum [kg/m3*m/s]') 83 | 84 | subplot(3,1,3) 85 | plot(x_cc, U(3,:),'b','linewidth',2); 86 | xlabel('Position [m]') 87 | ylabel('Energy [J/m3]') 88 | pause(0.001) 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /hyper1D/PDE1D_Octave/octave-workspace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbocce/hyper2D/a3610536a53684d197c04834e640012575f98bdf/hyper1D/PDE1D_Octave/octave-workspace -------------------------------------------------------------------------------- /hyper1D/PDE1D_Octave/phys_const.m: -------------------------------------------------------------------------------- 1 | % Contains some physical constants. 2 | 3 | gam = 5/3; % Adiabatic constant of the gas. 4 | % Monatomic gas: 5/3. Diatomic gas with rotation: 7/5. Monatomic gas with 1 only component of molecular velocity: 3 5 | 6 | % ------------ 7 | 8 | kB = 1.38e-23; % [J/K] Boltzmann constant 9 | -------------------------------------------------------------------------------- /hyper1D/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper1D folder contains the simplest 1D implementation of the Hyper2D finite volume solver, 6 | for the Euler equations of gas dynamics, on a uniform grid. 7 | 8 | In the simplest implementation, we use a forward Euler time integrator, with fixed time step. 9 | The solution simply evolves from the initial state and according to the BCs. 10 | All input data is specified inside the global_module.f03 file. You can modify it there, then 11 | compile and run the code. 12 | You should ensure that the time step is small enough as to respect the CFL condition, or 13 | the solution will diverge. 14 | 15 | The "higher_order" directory shows how to implement van Leer's MUSCL approach with TVD limiter, 16 | and 3rd order WENO schemes with third-order TVD Runge-Kutta time integrators. 17 | Also, in this directory, we employ a CFL-limited time marching: the time step is 18 | adapted to ensure that the maximum Courant number throughout the domain is 19 | smaller than a threshold. 20 | Various parameters are available in the global_module.f03 file, and allow to set the CFL, 21 | the space and time order etc. 22 | 23 | ================================== 24 | = COMPILING AND RUNNING THE CODE = 25 | ================================== 26 | 27 | For compiling the code, go into the src directory and type "make". 28 | This will create the 'hyper2d.exe' executable file. 29 | Copy it to the desired location and run it with: 30 | 31 | $ ./hyper2d.exe 32 | 33 | ***** 34 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 35 | ***** DIRECTORY. YOU NEED TO CREATE IT! 36 | ***** 37 | 38 | ========================= 39 | = STRUCTURE OF THE CODE = 40 | ========================= 41 | 42 | The hyper2d.f03 contains the main program. 43 | The global settings are implemented in the global_module.f03 file. 44 | The PDEs are implemented in the pde.f03 file. 45 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 46 | The routine for exporting to dat file is in tools.f03. 47 | 48 | The program goes like this: 49 | 1) The solution is initialized (calling pde.f03) 50 | 2) Boundary conditions are applied (calling pde.f03) 51 | 3) Time integration starts (calling integration.f03) 52 | 3.1) Numerical fluxes are computed 53 | 3.2) The solution is updated in time 54 | 4) The solution is exported (calling tools.f03) 55 | 56 | 57 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 -llapack 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | implicit none 4 | 5 | ! Time integration 6 | 7 | real(kind=8), parameter :: t_end = 0.2d0 ! [s] total simulated time (from 0 to t_end) 8 | real(kind=8), parameter :: CFL_target = 0.2d0 9 | 10 | real(kind=8), parameter :: x_min = -0.5d0 ! [m] 11 | real(kind=8), parameter :: x_max = 0.5d0 ! [m] 12 | 13 | ! Total number of cells (including 4 ghost cells for each side) 14 | ! (using 4 ghost cells makes it easy to reach higher order accuracy) 15 | 16 | integer, parameter :: Nx = 200 17 | 18 | logical, parameter :: bool_PERIODIC = .false. 19 | 20 | ! Note: we use 4 ghost cells per side. This allows to reach up to 5th order 21 | ! (with the WENO method) 22 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-8) 23 | 24 | ! Order in space 25 | ! 1: uniform sol in cell, first order in space 26 | ! 2: MUSCL with TVD slope limiter, second order in space 27 | ! 3: WENO 3rd order 28 | ! 5: WENO 5th order 29 | integer, parameter :: space_order = 3 30 | 31 | ! Order in time 32 | ! 1: forward Euler, first order in time 33 | ! 2: midpoint Euler, second order in time 34 | ! 3: explicit TVD Runge-Kutta, third order in time 35 | integer, parameter :: time_order = 3 36 | 37 | ! Space fluxes: choose ONLY one 38 | logical, parameter :: flux_type_Rusanov = .false. 39 | logical, parameter :: flux_type_HLL = .true. 40 | 41 | ! Utilities 42 | real(kind=8) :: ws_maxabs ! Global variable, maximum wave speed 43 | 44 | end module 45 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### 1D version ########## 10 | ! ########### ########## 11 | ! ###################################################################### 12 | ! ###################################################################### 13 | 14 | program hyper2D 15 | 16 | use global_module ! Simulation parameters: domain size, number of cells etc 17 | use pde ! Definition of the system of equations 18 | use integration ! Functions for integrating in time and numerical fluxes 19 | use tools ! Output subroutines etc etc 20 | 21 | implicit none 22 | 23 | ! The solution is a 2D matrix. 24 | ! The first index "eqID" represents the equation 25 | ! (for Euler 1: density, 2: x-momentum, 3: total energy) 26 | ! the second index "i" represents the x-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | real(kind=8) :: dt, t_now, CFL_now 34 | 35 | write(*,*) "Initializing solution..." 36 | call initialize_solution(U) ! See the pde.f03 module 37 | 38 | write(*,*) "Assigning BCs..." 39 | call assign_BCs(U) ! See the pde.f03 module 40 | 41 | write(*,*) "Writing solution at time step", 0, "..." 42 | call export_sol(0, 0.0d0, U) 43 | 44 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 45 | 46 | ! Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 47 | ! do t_ID = 1, Nt 48 | 49 | t_now = 0.0d0 ! Init 50 | dt = 1.0d-10 ! Very first time step 51 | t_ID = 0.0 ! Init 52 | 53 | do while( t_now .le. t_end) 54 | 55 | ! ------ Prepare variables ------ 56 | t_ID = t_ID + 1 57 | t_now = t_now + dt 58 | ws_maxabs = 0.0 ! Global variable, init to zero 59 | 60 | ! ------ Integrate by dt ------ 61 | if (time_order .eq. 1) then 62 | call forward_Euler_step(U, dt) 63 | else if (time_order .eq. 2) then 64 | call midpoint_Euler_step(U, dt) 65 | else if (time_order .eq. 3) then 66 | call RK3_step(U, dt) 67 | else 68 | write(*,*) "Attention! Order of the time marching scheme unknown! Check global_module file!" 69 | write(*,*) "Aborting!" 70 | stop 71 | end if 72 | 73 | ! ----- Write solution to VTK, every ... time steps ----- 74 | if ( mod(t_ID, 100) .EQ. 0 ) then 75 | write(*,*) "Writing solution at time step", t_ID, "..." 76 | call export_sol(t_ID, t_now, U) 77 | end if 78 | 79 | ! ------ Estimate current Courant number and update time step ----- 80 | CFL_now = ws_maxabs*dt/dx 81 | write(*,'(A,EN15.5,A,F10.5,A,ES14.7,A)') 'Time', t_now, ' [s]. Current CFL: ', CFL_now, '. dt = ', dt, '[s]' 82 | dt = dt*CFL_target/CFL_now 83 | 84 | end do 85 | 86 | ! Export very last timestep 87 | call export_sol(t_ID, t_now, U) 88 | 89 | end program 90 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D/pde.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | use global_module 4 | 5 | implicit none 6 | 7 | integer, parameter :: Neq = 3 ! Number of equations 8 | 9 | real(kind=8), parameter :: gam = 1.6667 ! adiabatic constant 10 | 11 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 12 | ! NOTE: To initialize it here, all entries need to have the same length!!! 13 | ! I'm using three letters for simplicity. 14 | character(len=20), dimension(Neq) :: prim_names = (/'rho','UUx','PPP'/) 15 | 16 | contains 17 | 18 | ! ============================================================ 19 | 20 | subroutine initialize_solution(U) 21 | 22 | implicit none 23 | 24 | real(kind=8), dimension(:,:), intent(inout) :: U 25 | 26 | integer :: i 27 | 28 | real(kind=8) :: rhoL, uxL, PL 29 | real(kind=8) :: rhoR, uxR, PR 30 | 31 | ! Left state 32 | rhoL = 2.0 33 | uxL = 0.0 34 | PL = 2.0 35 | 36 | ! Right state 37 | rhoR = 1.0 38 | uxR = 0.0 39 | PR = 1.0 40 | 41 | ! Initialize solution (all cells, also internal ones) 42 | U(1,1:floor(Nx/2.0)) = rhoL ! Density 43 | U(2,1:floor(Nx/2.0)) = rhoL*uxL ! Momentum 44 | U(3,1:floor(Nx/2.0)) = rhoL*uxL*uxL/2.0 + PL/(gam-1.0) ! Energy 45 | 46 | U(1,floor(Nx/2.0):Nx) = rhoR 47 | U(2,floor(Nx/2.0):Nx) = rhoR*uxR 48 | U(3,floor(Nx/2.0):Nx) = rhoR*uxR*uxR/2.0 + PR/(gam-1.0) 49 | 50 | end subroutine 51 | 52 | ! ============================================================ 53 | 54 | subroutine assign_BCs(U) 55 | 56 | implicit none 57 | 58 | real(kind=8), dimension(:,:), intent(inout) :: U 59 | 60 | integer :: i 61 | 62 | ! ----- LEFT BC -------- 63 | 64 | ! Do nothing! 65 | 66 | ! U(1, 1:2) = ... 67 | ! U(2, 1:2) = ... 68 | ! U(3, 1:2) = ... 69 | 70 | ! ----- RIGHT BC -------- 71 | 72 | ! Do nothing! 73 | 74 | ! U(1, Nx-1:Nx) = ... 75 | ! U(2, Nx-1:Nx) = ... 76 | ! U(3, Nx-1:Nx) = ... 77 | 78 | end subroutine 79 | 80 | ! ============================================================ 81 | 82 | subroutine compute_conserved_from_primitive(prim, U) 83 | 84 | ! Computes vector of conserved variables "U" from the primitive variables "prim" 85 | 86 | implicit none 87 | 88 | real(kind=8), dimension(Neq), intent(in) :: prim 89 | real(kind=8), dimension(Neq), intent(out) :: U 90 | 91 | ! Working variables 92 | real(kind=8) :: rho, ux, P 93 | 94 | ! Extract primitive variables 95 | rho = prim(1) 96 | ux = prim(2) 97 | P = prim(3) 98 | 99 | ! Compose array of primitive variables 100 | U(1) = rho 101 | U(2) = rho*ux 102 | U(3) = rho*ux*ux/2.0d0 + P/(gam - 1.0d0) 103 | 104 | end subroutine 105 | 106 | ! ============================================================ 107 | 108 | subroutine compute_primitive_from_conserved(U, prim) 109 | 110 | ! Computes vector of primitive variables "prim" from the conserved variables "U" 111 | 112 | implicit none 113 | 114 | real(kind=8), dimension(Neq), intent(in) :: U 115 | real(kind=8), dimension(Neq), intent(out) :: prim 116 | 117 | ! Working variables 118 | real(kind=8) :: rho, ux, P 119 | 120 | ! Extract primitive variables 121 | rho = U(1) 122 | ux = U(2)/(rho + 1.0d-25) ! Use a small tolerance, since rho may be zero 123 | P = (gam-1.0)*(U(3) - rho*ux*ux/2.0) 124 | 125 | ! Compose array of primitive variables 126 | prim(1) = rho 127 | prim(2) = ux 128 | prim(3) = P 129 | 130 | end subroutine 131 | 132 | ! ============================================================ 133 | 134 | subroutine compute_flux_ws_x(U, Fx, ws_max, ws_min) 135 | 136 | ! Computes the convective flux along x, 137 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 138 | 139 | implicit none 140 | 141 | real(kind=8), dimension(Neq), intent(in) :: U 142 | real(kind=8), dimension(Neq), intent(out) :: Fx 143 | real(kind=8), intent(out) :: ws_max, ws_min 144 | 145 | real(kind=8), dimension(Neq) :: prim 146 | real(kind=8) :: rho, ux, P 147 | 148 | ! Compute primitive variables 149 | call compute_primitive_from_conserved(U, prim) 150 | rho = prim(1) 151 | ux = prim(2) 152 | P = prim(3) 153 | 154 | ! Assemble fluxes Fx 155 | Fx(1) = rho*ux 156 | Fx(2) = rho*ux*ux + P 157 | Fx(3) = U(3)*ux + P*ux ! note: U(3) = rho*E 158 | 159 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 160 | ws_max = ux + sqrt(gam*P/rho) 161 | ws_min = ux - sqrt(gam*P/rho) 162 | 163 | end subroutine 164 | 165 | end module 166 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol(t_ID, t_now, U) 13 | 14 | ! This subroutine writes the solution on a dat file. 15 | ! Only internal cells (no ghost cells), are written 16 | 17 | integer, intent(in) :: t_ID 18 | real(kind=8), intent(in) :: t_now 19 | real(kind=8), dimension(:,:), intent(in) :: U 20 | 21 | real(kind=8), dimension(Neq,Nx) :: prim ! Primitive variables 22 | 23 | integer :: eqID, i 24 | 25 | character(len=512) :: file_name ! Name of the output file 26 | 27 | ! ====== Open file for writing 28 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.dat' 29 | open(11189, file=file_name, status="replace", form="formatted") 30 | 31 | ! ====== Write header 32 | write(11189,'(A)',advance="no") '# t x ' 33 | 34 | do eqID = 1, Neq 35 | write(11189, '(A)', advance="no") prim_names(eqID) 36 | end do 37 | 38 | write(11189, '(A)') " " 39 | 40 | ! ====== Write the solution 41 | prim = 0.0 ! Init 42 | 43 | do i = 3, Nx-2 ! Only internal cells 44 | call compute_primitive_from_conserved(U(:,i), prim(:,i)) 45 | 46 | write(11189, '(EN17.5E3,A,EN17.5E3,A)', advance="no") t_now, " ", x_min + dx/2.0 + dx*(i-3.0), " " ! Time and position 47 | 48 | write(11189, *) prim(:,i), " " ! Solution in primitive variables 49 | 50 | end do 51 | 52 | close(11189) 53 | 54 | end subroutine 55 | 56 | end module 57 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D/tools/octaPLOTSOL_Euler.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear 3 | clc 4 | 5 | page_screen_output(0); 6 | 7 | % Plots solution in time 8 | 9 | files_list = dir('../dumps/sol_*'); 10 | 11 | figure 12 | for ii = 1:1:numel(files_list) 13 | 14 | % Load file 15 | dd = load(['../dumps/',files_list(ii).name]); 16 | fprintf('Data from: %s\n', files_list(ii).name); 17 | 18 | % Extract data 19 | t_now = dd(1,1); % first column is time 20 | xx = dd(:,2); % position is in the second column 21 | UU = dd(:,3:end); % solution (primitive variables) is written in all other columns 22 | 23 | % Print stuff 24 | subplot(3,1,1) 25 | plot(xx, UU(:,1), 'linewidth', 2); 26 | hold off 27 | grid on 28 | title(['Time: ', num2str(t_now), ' s']) 29 | xlabel('Position [m]') 30 | ylabel('prim(1)') 31 | 32 | subplot(3,1,2) 33 | plot(xx, UU(:,2), 'linewidth', 2); 34 | hold off 35 | grid on 36 | xlabel('Position [m]') 37 | ylabel('prim(2)') 38 | 39 | subplot(3,1,3) 40 | plot(xx, UU(:,3), 'linewidth', 2); 41 | hold off 42 | grid on 43 | xlabel('Position [m]') 44 | ylabel('prim(3)') 45 | 46 | pause(0.002) 47 | 48 | end 49 | 50 | 51 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 -llapack 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | implicit none 4 | 5 | ! Time integration 6 | 7 | real(kind=8), parameter :: dt = 0.0005d0 ! [s] time step 8 | integer, parameter :: Nt = 500 ! Number of time steps to be performed 9 | 10 | real(kind=8), parameter :: x_min = -0.5d0 ! [m] beginning of computational domain 11 | real(kind=8), parameter :: x_max = 0.5d0 ! [m] end of computational domain 12 | 13 | ! Total number of cells (including 4 ghost cells for each side) 14 | ! (using 4 ghost cells makes it easy to reach higher order accuracy) 15 | 16 | integer, parameter :: Nx = 200 17 | 18 | logical, parameter :: bool_PERIODIC = .false. ! Boundary conditions 19 | 20 | ! Note: we use here 4 ghost cells per side. This allows for a good generalization 21 | ! for higher order cases. 22 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-8) 23 | 24 | end module 25 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### 1D version ########## 10 | ! ########### ########## 11 | ! ###################################################################### 12 | ! ###################################################################### 13 | 14 | program hyper2D 15 | 16 | use global_module ! Simulation parameters: domain size, number of cells etc 17 | use pde ! Definition of the system of equations 18 | use integration ! Functions for integrating in time and numerical fluxes 19 | use tools ! Output subroutines etc etc 20 | 21 | implicit none 22 | 23 | ! The solution is a 2D matrix. 24 | ! The first index "eqID" represents the equation 25 | ! (for Euler 1: density, 2: x-momentum, 3: total energy) 26 | ! the second index "i" represents the x-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx) :: U, P 31 | 32 | integer :: t_ID 33 | real(kind=8) :: t_now 34 | 35 | write(*,*) "Initializing solution..." 36 | call initialize_solution(U) ! See the pde.f03 module 37 | 38 | write(*,*) "Assigning BCs..." 39 | call assign_BCs(U) ! See the pde.f03 module 40 | 41 | write(*,*) "Writing solution at time step", 0, "..." 42 | call export_sol(0, 0.0d0, U) 43 | 44 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 45 | 46 | t_now = 0.0d0 ! Init 47 | 48 | do t_ID = 1, Nt 49 | 50 | t_now = t_now + dt 51 | 52 | ! ------ Integrate by dt ------ 53 | call forward_Euler_step(U, dt) 54 | 55 | ! ----- Write solution to VTK, every ... time steps ----- 56 | if ( mod(t_ID, 100) .EQ. 0 ) then 57 | write(*,*) "Writing solution at time step", t_ID, "..." 58 | call export_sol(t_ID, t_now, U) 59 | end if 60 | 61 | end do 62 | 63 | ! Export very last timestep 64 | call export_sol(t_ID, t_now, U) 65 | 66 | end program 67 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/integration.f03: -------------------------------------------------------------------------------- 1 | module integration 2 | 3 | use pde 4 | use global_module 5 | 6 | implicit none 7 | 8 | real(kind=8), dimension(Neq,Nx) :: U_new ! Working variable 9 | 10 | contains 11 | 12 | ! ======================================================================== 13 | 14 | subroutine forward_Euler_step(U, dt) 15 | 16 | ! This function performs one step of the Forward Euler explicit time integrator 17 | 18 | implicit none 19 | 20 | real(kind=8), dimension(Neq,Nx), intent(inout) :: U 21 | 22 | real(kind=8), intent(in) :: dt 23 | integer :: i, j, eqID 24 | 25 | real(kind=8), dimension(Neq) :: F_W, F_E 26 | 27 | ! First, assign BCs. Wall BCs need to be updated in time, taking the value 28 | ! from neighboring cells. 29 | call assign_BCs(U) ! See the pde.f03 module 30 | 31 | ! Update solution using the forward Euler integrator - INTERNAL CELLS only 32 | ! (I am using 4 ghost cells per side. This is useful for further generalizations 33 | ! to higher order methods) 34 | do i = 5, Nx-4 35 | 36 | ! Choose one of these fluxes 37 | call compute_fluxes_HLL(U, i, F_W, F_E) 38 | ! call compute_fluxes_Rusanov(U, i, F_W, F_E) 39 | 40 | ! Advect remaining stuff 41 | U_new(:,i) = U(:,i) - dt/dx*(F_E - F_W) ! No source term 42 | 43 | ! Check that the solution did not diverge 44 | do eqID = 1, Neq 45 | if (isnan(U_new(eqID,i))) then 46 | print*, 'Solution diverged, try with a smaller time step! Aborting.' 47 | print*, 'Solution that diverged: ', U_new(:,i) 48 | print*, 'in cell i = ', i 49 | stop 50 | end if 51 | end do 52 | 53 | end do 54 | 55 | ! Save solution (internal cells ONLY! Do not overwrite ghost cells!) 56 | U(:,5:Nx-4) = U_new(:,5:Nx-4) 57 | 58 | end subroutine 59 | 60 | ! ======================================================================== 61 | 62 | subroutine compute_fluxes_HLL(U, i, F_W, F_E) 63 | 64 | ! Computes HLL numerical fluxes for the cell "i" 65 | ! 'F_W' and 'F_E' are the complete fluxes at the cell interfaces, to be then 66 | ! added in the time-discretized PDE. 67 | ! The variables 'F_L' and 'F_R' are temporary variables used for the 68 | ! fluxes at the left and right of an interface. 69 | 70 | implicit none 71 | 72 | real(kind=8), dimension(Neq,Nx), intent(in) :: U 73 | real(kind=8), dimension(Neq), intent(out) :: F_W, F_E 74 | integer, intent(in) :: i 75 | 76 | integer :: eqID 77 | real(kind=8), dimension(Neq) :: U_im3, U_im2, U_im1, U_i, U_ip1, U_ip2, U_ip3 78 | real(kind=8), dimension(Neq) :: U_L, U_R, F_L, F_R 79 | 80 | real(kind=8) :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_min, ws_max ! wave speeds 81 | 82 | ! ---- West interface ----- 83 | 84 | U_L = U(:,i-1) 85 | U_R = U(:,i) 86 | 87 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 88 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 89 | 90 | ws_min = MIN(ws_min_L, ws_min_R) 91 | ws_max = MAX(ws_max_L, ws_max_R) 92 | 93 | ! HLL fluxes 94 | if (ws_min .ge. 0.0) then 95 | F_W = F_L 96 | else if (ws_max .lt. 0.0) then 97 | F_W = F_R 98 | else 99 | F_W = (ws_min*ws_max*(U_R - U_L) + ws_max*F_L - ws_min*F_R)/(ws_max - ws_min); 100 | end if 101 | 102 | ! ---- East interface ----- 103 | 104 | U_L = U(:,i) 105 | U_R = U(:,i+1) 106 | 107 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 108 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 109 | 110 | ws_min = MIN(ws_min_L, ws_min_R) 111 | ws_max = MAX(ws_max_L, ws_max_R) 112 | 113 | ! HLL fluxes 114 | if (ws_min .ge. 0.0) then 115 | F_E = F_L 116 | else if (ws_max .lt. 0.0) then 117 | F_E = F_R 118 | else 119 | F_E = (ws_min*ws_max*(U_R - U_L) + ws_max*F_L - ws_min*F_R)/(ws_max - ws_min); 120 | end if 121 | 122 | end subroutine 123 | 124 | ! ======================================================================== 125 | 126 | subroutine compute_fluxes_Rusanov(U, i, F_W, F_E) 127 | 128 | ! Computes HLL numerical fluxes for the cell "i" 129 | ! 'F_W' and 'F_E' are the complete fluxes at the cell interfaces, to be then 130 | ! added in the time-discretized PDE. 131 | ! The variables 'F_L' and 'F_R' are temporary variables used for the 132 | ! fluxes at the left and right of an interface. 133 | 134 | implicit none 135 | 136 | real(kind=8), dimension(Neq,Nx), intent(in) :: U 137 | real(kind=8), dimension(Neq), intent(out) :: F_W, F_E 138 | integer, intent(in) :: i 139 | 140 | integer :: eqID 141 | real(kind=8), dimension(Neq) :: U_L, U_R, F_L, F_R 142 | real(kind=8) :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_min, ws_max ! wave speeds 143 | 144 | ! ---- West interface ----- 145 | 146 | U_L = U(:,i-1) 147 | U_R = U(:,i) 148 | 149 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 150 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 151 | 152 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 153 | 154 | ! West interface 155 | F_W = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 156 | 157 | ! ---- East interface ----- 158 | 159 | U_L = U(:,i) 160 | U_R = U(:,i+1) 161 | 162 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 163 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 164 | 165 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 166 | 167 | ! West interface 168 | F_E = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 169 | 170 | end subroutine 171 | 172 | end module 173 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/pde.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | use global_module 4 | 5 | implicit none 6 | 7 | integer, parameter :: Neq = 3 ! Number of equations 8 | 9 | real(kind=8), parameter :: gam = 1.6667 ! adiabatic constant 10 | 11 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 12 | ! NOTE: To initialize it here, all entries need to have the same length!!! 13 | ! I'm using three letters for simplicity. 14 | character(len=20), dimension(Neq) :: prim_names = (/'rho','UUx','PPP'/) 15 | 16 | contains 17 | 18 | ! ============================================================ 19 | 20 | subroutine initialize_solution(U) 21 | 22 | implicit none 23 | 24 | real(kind=8), dimension(:,:), intent(inout) :: U 25 | 26 | integer :: i 27 | 28 | real(kind=8) :: rhoL, uxL, PL 29 | real(kind=8) :: rhoR, uxR, PR 30 | 31 | ! Left state 32 | rhoL = 2.0 33 | uxL = 0.0 34 | PL = 2.0 35 | 36 | ! Right state 37 | rhoR = 1.0 38 | uxR = 0.0 39 | PR = 1.0 40 | 41 | ! Initialize solution (all cells, also internal ones) 42 | U(1,1:floor(Nx/2.0)) = rhoL ! Density 43 | U(2,1:floor(Nx/2.0)) = rhoL*uxL ! Momentum 44 | U(3,1:floor(Nx/2.0)) = rhoL*uxL*uxL/2.0 + PL/(gam-1.0) ! Energy 45 | 46 | U(1,floor(Nx/2.0):Nx) = rhoR 47 | U(2,floor(Nx/2.0):Nx) = rhoR*uxR 48 | U(3,floor(Nx/2.0):Nx) = rhoR*uxR*uxR/2.0 + PR/(gam-1.0) 49 | 50 | end subroutine 51 | 52 | ! ============================================================ 53 | 54 | subroutine assign_BCs(U) 55 | 56 | implicit none 57 | 58 | real(kind=8), dimension(:,:), intent(inout) :: U 59 | 60 | integer :: i 61 | 62 | ! ----- LEFT BC -------- 63 | 64 | ! Do nothing! 65 | 66 | ! U(1, 1:2) = ... 67 | ! U(2, 1:2) = ... 68 | ! U(3, 1:2) = ... 69 | 70 | ! ----- RIGHT BC -------- 71 | 72 | ! Do nothing! 73 | 74 | ! U(1, Nx-1:Nx) = ... 75 | ! U(2, Nx-1:Nx) = ... 76 | ! U(3, Nx-1:Nx) = ... 77 | 78 | end subroutine 79 | 80 | ! ============================================================ 81 | 82 | subroutine compute_conserved_from_primitive(prim, U) 83 | 84 | ! Computes vector of conserved variables "U" from the primitive variables "prim" 85 | 86 | implicit none 87 | 88 | real(kind=8), dimension(Neq), intent(in) :: prim 89 | real(kind=8), dimension(Neq), intent(out) :: U 90 | 91 | ! Working variables 92 | real(kind=8) :: rho, ux, P 93 | 94 | ! Extract primitive variables 95 | rho = prim(1) 96 | ux = prim(2) 97 | P = prim(3) 98 | 99 | ! Compose array of primitive variables 100 | U(1) = rho 101 | U(2) = rho*ux 102 | U(3) = rho*ux*ux/2.0d0 + P/(gam - 1.0d0) 103 | 104 | end subroutine 105 | 106 | ! ============================================================ 107 | 108 | subroutine compute_primitive_from_conserved(U, prim) 109 | 110 | ! Computes vector of primitive variables "prim" from the conserved variables "U" 111 | 112 | implicit none 113 | 114 | real(kind=8), dimension(Neq), intent(in) :: U 115 | real(kind=8), dimension(Neq), intent(out) :: prim 116 | 117 | ! Working variables 118 | real(kind=8) :: rho, ux, P 119 | 120 | ! Extract primitive variables 121 | rho = U(1) 122 | ux = U(2)/(rho + 1.0d-25) ! Use a small tolerance, since rho may be zero 123 | P = (gam-1.0)*(U(3) - rho*ux*ux/2.0) 124 | 125 | ! Compose array of primitive variables 126 | prim(1) = rho 127 | prim(2) = ux 128 | prim(3) = P 129 | 130 | end subroutine 131 | 132 | ! ============================================================ 133 | 134 | subroutine compute_flux_ws_x(U, Fx, ws_max, ws_min) 135 | 136 | ! Computes the convective flux along x, 137 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 138 | 139 | implicit none 140 | 141 | real(kind=8), dimension(Neq), intent(in) :: U 142 | real(kind=8), dimension(Neq), intent(out) :: Fx 143 | real(kind=8), intent(out) :: ws_max, ws_min 144 | 145 | real(kind=8), dimension(Neq) :: prim 146 | real(kind=8) :: rho, ux, P 147 | 148 | ! Compute primitive variables 149 | call compute_primitive_from_conserved(U, prim) 150 | rho = prim(1) 151 | ux = prim(2) 152 | P = prim(3) 153 | 154 | ! Assemble fluxes Fx 155 | Fx(1) = rho*ux 156 | Fx(2) = rho*ux*ux + P 157 | Fx(3) = U(3)*ux + P*ux ! note: U(3) = rho*E 158 | 159 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 160 | ws_max = ux + sqrt(gam*P/rho) 161 | ws_min = ux - sqrt(gam*P/rho) 162 | 163 | end subroutine 164 | 165 | end module 166 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol(t_ID, t_now, U) 13 | 14 | ! This subroutine writes the solution on a dat file. 15 | ! Only internal cells (no ghost cells), are written 16 | 17 | integer, intent(in) :: t_ID 18 | real(kind=8), intent(in) :: t_now 19 | real(kind=8), dimension(:,:), intent(in) :: U 20 | 21 | real(kind=8), dimension(Neq,Nx) :: prim ! Primitive variables 22 | 23 | integer :: eqID, i 24 | 25 | character(len=512) :: file_name ! Name of the output file 26 | 27 | ! ====== Open file for writing 28 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.dat' 29 | open(11189, file=file_name, status="replace", form="formatted") 30 | 31 | ! ====== Write header 32 | write(11189,'(A)',advance="no") '# t x ' 33 | 34 | do eqID = 1, Neq 35 | write(11189, '(A)', advance="no") prim_names(eqID) 36 | end do 37 | 38 | write(11189, '(A)') " " 39 | 40 | ! ====== Write the solution 41 | prim = 0.0 ! Init 42 | 43 | do i = 3, Nx-2 ! Only internal cells 44 | call compute_primitive_from_conserved(U(:,i), prim(:,i)) 45 | 46 | write(11189, '(EN17.5E3,A,EN17.5E3,A)', advance="no") t_now, " ", x_min + dx/2.0 + dx*(i-3.0), " " ! Time and position 47 | 48 | write(11189, *) prim(:,i), " " ! Solution in primitive variables 49 | 50 | end do 51 | 52 | close(11189) 53 | 54 | end subroutine 55 | 56 | end module 57 | -------------------------------------------------------------------------------- /hyper1D/src_hyper1D_simple/tools/octaPLOTSOL_Euler.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear 3 | clc 4 | 5 | page_screen_output(0); 6 | 7 | % Plots solution in time 8 | 9 | files_list = dir('../dumps/sol_*'); 10 | 11 | figure 12 | for ii = 1:1:numel(files_list) 13 | 14 | % Load file 15 | dd = load(['../dumps/',files_list(ii).name]); 16 | fprintf('Data from: %s\n', files_list(ii).name); 17 | 18 | % Extract data 19 | t_now = dd(1,1); % first column is time 20 | xx = dd(:,2); % position is in the second column 21 | UU = dd(:,3:end); % solution (primitive variables) is written in all other columns 22 | 23 | % Print stuff 24 | subplot(3,1,1) 25 | plot(xx, UU(:,1), 'linewidth', 2); 26 | hold off 27 | grid on 28 | title(['Time: ', num2str(t_now), ' s']) 29 | xlabel('Position [m]') 30 | ylabel('prim(1)') 31 | 32 | subplot(3,1,2) 33 | plot(xx, UU(:,2), 'linewidth', 2); 34 | hold off 35 | grid on 36 | xlabel('Position [m]') 37 | ylabel('prim(2)') 38 | 39 | subplot(3,1,3) 40 | plot(xx, UU(:,3), 'linewidth', 2); 41 | hold off 42 | grid on 43 | xlabel('Position [m]') 44 | ylabel('prim(3)') 45 | 46 | pause(0.002) 47 | 48 | end 49 | 50 | 51 | -------------------------------------------------------------------------------- /hyper2D_CUDA/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_CUDA/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | This directory cointains a CUDA Fortran implementation of Hyper2D. 6 | 7 | The "src_simplest" directory contains the most basic implementation: 8 | fixed time step, first order in time and space. Only the Euler equations 9 | are shown. 10 | 11 | The "src" directory contains the actual implementation: the time step 12 | is chosen based on the Courant number, higher order in space and time 13 | is implemented, and there are some different PDEs implemented, including axisymmetric 14 | formulations. 15 | 16 | ================================== 17 | = COMPILING AND RUNNING THE CODE = 18 | ================================== 19 | 20 | For compiling the code, go into the src directory and type "make". 21 | This will create the 'hyper2d.exe' executable file. 22 | Copy it to the desired location and run it with: 23 | 24 | $ ./hyper2d.exe 25 | 26 | ***** 27 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 28 | ***** DIRECTORY. YOU NEED TO CREATE IT! 29 | ***** 30 | 31 | ========================================== 32 | = Computational grid, threads and blocks = 33 | ========================================== 34 | 35 | Notice that 4 layers of ghost cells are employed for each boundary. 36 | 37 | Every thread is associated to a finite volume cell of the computational domain. 38 | Threads in the GPU are executed in blocks, for a maximum of 256 threads per block (but 39 | depending on the GPU). We define the variables BLOCK_X_threads and BLOCK_Y_threads, and 40 | we have that N_threads_per_block = BLOCK_X_threads*BLOCK_Y_threads. 41 | These quantities are defined in the "global_module.cuf" file. 42 | 43 | The total grid will be composed by BLOCK_X_threadx*N_BLOCKS_X elements along x and 44 | analogously along y. 45 | 46 | **** Choosing the number of threads per block **** 47 | 48 | Choose BLOCK_X_threads and BLOCK_Y_threads to be somewhere around 8-16. 49 | If your PDE is very complex (for example, many equations) and require to define 50 | a lot of working variables, the GPU registers could get filled. If this happens, select less 51 | threads per block. With the Euler equation, I had success using 16x16 on a Tesla K20X, while 52 | for a system of 14 equations with complicated constitutive relations, I had success using 8. 53 | 54 | 55 | The integration time loop is divided into kernels. Each kernel does a different task and 56 | before moving to the next kernel, the GPU must have done this into each block. 57 | Therefore, dividing the program into kernel enforces that the integration steps are executed 58 | completely and in the correct order. 59 | For instance: you first have to update the BCs, and only after this is done, start computing 60 | the fluxes. 61 | 62 | **** Choosing the number of blocks **** 63 | 64 | Once you have chosen the number of threads per block (that is limited, see above), you just 65 | pick the number of blocks as to have the required total number of cells in the domain. 66 | As simple as that. 67 | 68 | **** Wave speeds for the CFL condition **** 69 | 70 | Explicit time steps require to respect the CFL condition, that is the maximum Courant number 71 | must be below a threshold (below 1). 72 | The Courant number is computed from the wave speeds (eigenvalues of the flux Jacobian). 73 | Now, these wave speeds depend on the position inside the domain. Therefore, during the 74 | computation, we must keep track of the absolute maximum wave speeds. For a serial CPU solver 75 | this is a simple task. For a GPU solver, it's a bit more of an issue, because you need 76 | to do a "reduce" operation and compare the value in different cells avoiding racing 77 | conditions. 78 | Creating a matrix of wave speeds, one per each cell, and then downloading it on the CPU 79 | and computing with the CPU the maximum valie requires 1) a lot of additional memory and 80 | 2) a lot of CPU computations. 81 | Instead, we decided to work at a block-level: we define a matrix of wave speeds with 82 | N_BLOCKS_X*N_BLOCKS_Y elements. Inside every block, we do an atomic operation and check 83 | the maximum wave speed. Then, we download this matrix to the CPU, and do a CPU comparison 84 | of these numbers to find the maximum one. 85 | 86 | 87 | NOTES: single or double precision is set at make time through a command! All real variables 88 | are just declared as "real", and a compile flag choses double over single precision. 89 | 90 | 91 | The hyper2D_basic folder contains a basic implementation of the Hyper2D finite volume solver. 92 | This version uses a time-explicit forward Euler time integrator, with fixed time step, and 93 | a Cartesian grid. No objects are introduced in the domain. The solution simply evolves 94 | from the initial state and according to the BCs. 95 | All input data is specified inside the global_module.f03 file. You can modify it there, then 96 | compile and run the code. 97 | 98 | Some different PDE systems are available in the "src/various_PDEs" directory. 99 | 100 | ========================= 101 | = STRUCTURE OF THE CODE = 102 | ========================= 103 | 104 | The hyper2d.f03 contains the main program. 105 | The global settings are implemented in the global_module.f03 file. 106 | The PDEs are implemented in the pde.f03 file. 107 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 108 | The routine for exporting to VTK is in tools.f03. 109 | 110 | The program goes like this: 111 | 1) The solution is initialized (calling pde.f03) 112 | 2) Boundary conditions are applied (calling pde.f03) 113 | 3) Time integration starts (calling integration.f03) 114 | 3.1) Numerical fluxes are computed 115 | 3.2) The solution is updated in time 116 | 4) The solution is exported (calling tools.f03) 117 | 118 | 119 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = nvfortran -c 6 | LNK = nvfortran 7 | 8 | # ---- Compile options. cc35 stands for "compute capability 3.5" 9 | # OPTS = -O3 -cuda -gpu=cc35 -r4 # float 10 | OPTS = -O3 -cuda -gpu=cc35 -r8 # double precision 11 | # OPTS = -cuda -gpu=cc35,debug -r4 -g # For debugging, use these options 12 | 13 | OBJS = global_module.o tools.o pde.o integration.o 14 | 15 | ######### Executable generation by the linker 16 | 17 | hyper2D.exe: hyper2D.o $(OBJS) 18 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 19 | 20 | ######### Objects generation 21 | 22 | hyper2D.o: hyper2D.cuf $(OBJS) 23 | $(CMPF) $(OPTS) hyper2D.cuf 24 | 25 | integration.o: integration.cuf global_module.o pde.o 26 | $(CMPF) $(OPTS) integration.cuf 27 | 28 | pde.o: pde.cuf global_module.o 29 | $(CMPF) $(OPTS) pde.cuf 30 | 31 | tools.o: tools.cuf pde.o global_module.o 32 | $(CMPF) $(OPTS) tools.cuf 33 | 34 | global_module.o: global_module.cuf 35 | $(CMPF) $(OPTS) global_module.cuf 36 | 37 | ########## Cleaning commands 38 | 39 | # Use "clean" to remove the objects and exectutable files 40 | clean: 41 | @echo cleaning objects, modules and executables 42 | rm -f *.o *.mod *.exe *~ 43 | 44 | # Use "cleanoutput" to remove the output files, located in the dumps directory 45 | cleanoutput: 46 | @echo cleaning output and dump files 47 | rm -f dumps/* 48 | 49 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA/global_module.cuf: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | ! This module contains data needed throughout the program. 4 | ! Most data is specified as a parameter, as to make the execution faster. 5 | ! This module is loaded by most other modules. 6 | 7 | implicit none 8 | 9 | ! Time integration 10 | 11 | real, parameter :: CFL_target = 0.1 ! Target CFL for the simulation 12 | real, parameter :: t_end = 80.0d0 ! [s] total simulated time (from 0 to t_end) 13 | real, parameter :: dt_max = 0.01 ! [s] maximum admissible time step (useful if you have sources) 14 | 15 | integer, parameter :: WRITE_VTK_EACH = 200 ! Write a VTK file each this many time steps 16 | 17 | ! Specify domain and discretization 18 | 19 | real, parameter :: x_min = 0.0 ! [m] 20 | real, parameter :: x_max = 1.0 ! [m] 21 | real, parameter :: y_min = 0.0 ! [m] 22 | real, parameter :: y_max = 1.0 ! [m] 23 | 24 | ! Boundary conditions 25 | logical, parameter :: bool_AXI = .False. ! Axi-symmetric simulation? Modifies 1) update and 2) BCs 26 | 27 | logical, parameter :: X_PERIODIC = .False. 28 | logical, parameter :: Y_PERIODIC = .False. 29 | 30 | logical, parameter :: X_low_ZEROGRAD = .False. 31 | logical, parameter :: X_high_ZEROGRAD = .True. 32 | logical, parameter :: Y_low_ZEROGRAD = .False. 33 | logical, parameter :: Y_high_ZEROGRAD = .True. 34 | 35 | ! Spacial accuracy (order) 36 | ! 1: uniform sol in cell, first order in space 37 | ! 2: MUSCL with TVD slope limiter, second order in space 38 | ! 3: WENO 3rd order 39 | ! 5: WENO 5th order 40 | integer, parameter :: space_order = 2 41 | 42 | ! Time accuracy (order) 43 | ! 1: forward Euler, first order in time 44 | ! 3: explicit TVD Runge-Kutta, third order in time 45 | integer, parameter :: time_order = 1 46 | 47 | ! ======== CUDA launch configuration and GRID ========== 48 | ! Threads per block along x and y 49 | 50 | integer, parameter :: BLOCK_X_threads = 8 51 | integer, parameter :: BLOCK_Y_threads = 8 52 | 53 | integer, parameter :: N_BLOCKS_X = 50 54 | integer, parameter :: N_BLOCKS_Y = 50 55 | 56 | ! Total number of cells (including 2 ghost cells for each side) 57 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 58 | ! Note: use a multiple of the number of threads per block 59 | 60 | integer, parameter :: Nx = N_BLOCKS_X*BLOCK_X_threads 61 | integer, parameter :: Ny = N_BLOCKS_Y*BLOCK_Y_threads 62 | 63 | real, parameter :: dx = (x_max-x_min)/real(Nx-8) 64 | real, parameter :: dy = (y_max-y_min)/real(Ny-8) 65 | 66 | end module 67 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA/tools.cuf: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real, dimension(:,:,:), intent(in) :: U 32 | 33 | real, dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 8 42 | Ny_int = Ny - 8 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call CPU_compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 5, Ny-4 81 | do i = 5, Nx-4 82 | write(11189, '(E20.7E6,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA_simplest/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = nvfortran -c 6 | LNK = nvfortran 7 | 8 | # ---- Compile options. cc35 stands for "compute capability 3.5" 9 | # OPTS = -O3 -cuda -gpu=cc35 -r4 # float 10 | OPTS = -O3 -cuda -gpu=cc35 -r8 # double precision 11 | # OPTS = -cuda -gpu=cc35,debug -r4 -g # For debugging, use these options 12 | 13 | OBJS = global_module.o tools.o pde.o integration.o 14 | 15 | ######### Executable generation by the linker 16 | 17 | hyper2D.exe: hyper2D.o $(OBJS) 18 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 19 | 20 | ######### Objects generation 21 | 22 | hyper2D.o: hyper2D.cuf $(OBJS) 23 | $(CMPF) $(OPTS) hyper2D.cuf 24 | 25 | integration.o: integration.cuf global_module.o pde.o 26 | $(CMPF) $(OPTS) integration.cuf 27 | 28 | pde.o: pde.cuf global_module.o 29 | $(CMPF) $(OPTS) pde.cuf 30 | 31 | tools.o: tools.cuf pde.o global_module.o 32 | $(CMPF) $(OPTS) tools.cuf 33 | 34 | global_module.o: global_module.cuf 35 | $(CMPF) $(OPTS) global_module.cuf 36 | 37 | ########## Cleaning commands 38 | 39 | # Use "clean" to remove the objects and exectutable files 40 | clean: 41 | @echo cleaning objects, modules and executables 42 | rm -f *.o *.mod *.exe *~ 43 | 44 | # Use "cleanoutput" to remove the output files, located in the dumps directory 45 | cleanoutput: 46 | @echo cleaning output and dump files 47 | rm -f dumps/* 48 | 49 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA_simplest/global_module.cuf: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | ! This module contains data needed throughout the program. 4 | ! Most data is specified as a parameter, as to make the execution faster. 5 | ! This module is loaded by most other modules. 6 | 7 | implicit none 8 | 9 | ! Time integration 10 | 11 | real, parameter :: dt = 0.000001 ! [s] time step 12 | integer, parameter :: Nt = 10000 ! Total number of time steps 13 | 14 | integer, parameter :: WRITE_VTK_EACH = 200 ! Write a VTK file each this many time steps 15 | 16 | ! Specify domain and discretization 17 | 18 | real, parameter :: x_min = -1.0 ! [m] 19 | real, parameter :: x_max = 1.0 ! [m] 20 | real, parameter :: y_min = -1.0 ! [m] 21 | real, parameter :: y_max = 1.0 ! [m] 22 | 23 | ! Boundary conditions 24 | logical, parameter :: X_PERIODIC = .False. 25 | logical, parameter :: Y_PERIODIC = .False. 26 | 27 | logical, parameter :: X_low_ZEROGRAD = .False. 28 | logical, parameter :: X_high_ZEROGRAD = .False. 29 | logical, parameter :: Y_low_ZEROGRAD = .False. 30 | logical, parameter :: Y_high_ZEROGRAD = .False. 31 | 32 | ! ======== CUDA launch configuration and GRID ========== 33 | ! Threads per block along x and y 34 | 35 | integer, parameter :: BLOCK_X_threads = 8 36 | integer, parameter :: BLOCK_Y_threads = 8 37 | 38 | integer, parameter :: N_BLOCKS_X = 100 39 | integer, parameter :: N_BLOCKS_Y = 100 40 | 41 | ! Total number of cells (including 4 ghost cells for each side) 42 | ! (using 4 ghost cells makes it easy to reach high order accuracy) 43 | ! Note: use a multiple of the number of threads per block 44 | 45 | integer, parameter :: Nx = N_BLOCKS_X*BLOCK_X_threads 46 | integer, parameter :: Ny = N_BLOCKS_Y*BLOCK_Y_threads 47 | 48 | real, parameter :: dx = (x_max-x_min)/real(Nx-8) 49 | real, parameter :: dy = (y_max-y_min)/real(Ny-8) 50 | 51 | end module 52 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA_simplest/hyper2D.cuf: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use cudafor 16 | 17 | use global_module ! Simulation parameters: domain size, number of cells etc 18 | use pde ! Definition of the system of equations 19 | use integration ! Functions for integrating in time and numerical fluxes 20 | use tools ! Output subroutines etc etc 21 | 22 | implicit none 23 | 24 | ! The solution is a 3D matrix. 25 | ! The first index "eqID" represents the equation 26 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 27 | ! the second index "i" represents the x-position 28 | ! the third index "j" represents the y-position. 29 | ! This might be counter-intuitive, but recall that Fortran represents data 30 | ! in column-major order. 31 | 32 | real, dimension(Neq,Nx,Ny) :: U, P ! Solution on the CPU 33 | real, dimension(Neq,Nx,Ny), device :: d_U, d_U_new ! Solution on the GPU 34 | 35 | ! Maximum wave speed (for each block) 36 | real, dimension(N_BLOCKS_X,N_BLOCKS_Y) :: ws_max_blocks 37 | real, dimension(N_BLOCKS_X,N_BLOCKS_Y), device :: d_ws_max_blocks 38 | 39 | ! Time integration variable 40 | integer :: t_ID 41 | integer :: err 42 | real :: t_now 43 | 44 | type(dim3) :: grid, tBlock ! GPU Launch configuration 45 | 46 | write(*,*) "Initializing solution..." 47 | call initialize_solution(U) ! See the pde.f03 module 48 | 49 | write(*,*) "Writing solution at time step", 0, "..." 50 | call export_sol_vtk(0, U) 51 | 52 | write(*,*) "Copying initial solution to the GPU..." 53 | d_U = U 54 | 55 | ! ------- Prepare launch configuration ---------- 56 | tBlock = dim3(BLOCK_X_threads, BLOCK_Y_threads, 1) 57 | grid = dim3(N_BLOCKS_X, N_BLOCKS_Y, 1) 58 | 59 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 60 | 61 | t_now = 0.0 62 | t_ID = 0 63 | 64 | do t_ID = 1, Nt 65 | 66 | write(*,'(A10,I10,A4,I10)') 'Timestep: ', t_ID, ' of ', Nt 67 | 68 | t_now = t_now + dt ! Update simulation time 69 | 70 | ! ------ Integrate one step in time ----- 71 | 72 | call assign_BCs<<>>(d_U) ! Update BCs in real time in case periodicity is needed 73 | err = cudaDeviceSynchronize() 74 | 75 | d_U_new = d_U ! Init 76 | call forward_Euler_step<<>>(d_U, d_U_new, dt, t_now) ! Updates d_U_new 77 | d_U = d_U_new ! Now U is updated 78 | 79 | ! ------- Write to VTK every ... timesteps 80 | if ( mod(t_ID, WRITE_VTK_EACH) .EQ. 0 ) then 81 | 82 | write(*,*) "Writing solution at time step", t_ID, "..." 83 | U = d_U ! Download solution from the GPU 84 | call export_sol_vtk(t_ID, U) 85 | 86 | end if 87 | 88 | end do 89 | 90 | err = cudaDeviceReset() 91 | 92 | end program 93 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA_simplest/integration.cuf: -------------------------------------------------------------------------------- 1 | module integration 2 | 3 | ! This module contains the routines for the time integration and the computation 4 | ! of numerical fluxes (Rusanov in this example). 5 | 6 | use ieee_arithmetic 7 | use pde 8 | use global_module 9 | 10 | implicit none 11 | 12 | real, dimension(Neq,Nx,Ny) :: U_new ! Working variable 13 | 14 | contains 15 | 16 | ! ======================================================================== 17 | 18 | attributes(global) subroutine forward_Euler_step(U, U_new, dt, t_now) 19 | 20 | ! This kernel performs one step of the Forward Euler explicit time integrator 21 | 22 | implicit none 23 | 24 | real, dimension(Neq,Nx,Ny) :: U, U_new ! Device variable in global memory 25 | real, value :: dt, t_now ! Value that we pass from host space to the kernel 26 | 27 | integer :: i, j, eqID 28 | 29 | real, dimension(Neq) :: F_N, F_S, F_W, F_E 30 | 31 | ! Find coordinates of the present thread (aka cell i and j) 32 | i = (blockIdx%x - 1)*blockDim%x + threadIDx%x 33 | j = (blockIdx%y - 1)*blockDim%y + threadIDx%y 34 | 35 | ! Update solution using the forward Euler integrator - INTERNAL CELLS only, 36 | ! do not overwrite ghost cells 37 | if ( (i .ge. 5) .and. (i .le. Nx-4) .and. (j .ge. 5) .and. (j .le. Ny-4) ) then 38 | 39 | call compute_fluxes_Rusanov(U, i, j, F_N, F_S, F_W, F_E) 40 | 41 | U_new(:,i,j) = U(:,i,j) - dt/dx*(F_E - F_W) - dt/dy*(F_N - F_S) 42 | 43 | ! Check that the solution did not diverge 44 | do eqID = 1, Neq 45 | if (ieee_is_nan(U_new(eqID,i,j))) then 46 | print*, 'Solution diverged, try with a smaller time step! Aborting.' 47 | stop 48 | end if 49 | end do 50 | 51 | end if 52 | 53 | end subroutine 54 | 55 | ! ======================================================================== 56 | 57 | attributes(device) subroutine compute_fluxes_Rusanov(U, i, j, F_N, F_S, F_W, F_E) 58 | 59 | ! Computes Rusanov numerical fluxes for the cell (i,j) 60 | 61 | implicit none 62 | 63 | real, dimension(Neq,Nx,Ny), intent(in) :: U 64 | real, dimension(Neq), intent(out) :: F_N, F_S, F_W, F_E 65 | integer, intent(in) :: i, j 66 | 67 | integer :: eqID 68 | real, dimension(Neq) :: U_L, U_R, F_L, F_R 69 | 70 | real :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_max ! wave speeds 71 | 72 | ! ------ North interface 73 | 74 | ! Reconstruct the solution, passing the four cells that neighbor the interface 75 | U_L = U(:,i,j) 76 | U_R = U(:,i,j+1) 77 | 78 | call compute_flux_ws_y(U_L, F_L, ws_max_L, ws_min_L) 79 | call compute_flux_ws_y(U_R, F_R, ws_max_R, ws_min_R) 80 | 81 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 82 | 83 | F_N = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 84 | 85 | ! ------ South interface 86 | 87 | ! Reconstruct the solution, passing the four cells that neighbor the interface 88 | U_L = U(:,i,j-1) 89 | U_R = U(:,i,j) 90 | 91 | call compute_flux_ws_y(U_L, F_L, ws_max_L, ws_min_L) 92 | call compute_flux_ws_y(U_R, F_R, ws_max_R, ws_min_R) 93 | 94 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 95 | 96 | F_S = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 97 | 98 | ! ------ East interface 99 | 100 | ! Reconstruct the solution, passing the four cells that neighbor the interface 101 | U_L = U(:,i,j) 102 | U_R = U(:,i+1,j) 103 | 104 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 105 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 106 | 107 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 108 | 109 | F_E = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 110 | 111 | ! ------ West interface 112 | 113 | ! Reconstruct the solution, passing the four cells that neighbor the interface 114 | U_L = U(:,i-1,j) 115 | U_R = U(:,i,j) 116 | 117 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 118 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 119 | 120 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 121 | 122 | F_W = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 123 | 124 | end subroutine 125 | 126 | end module 127 | -------------------------------------------------------------------------------- /hyper2D_CUDA/src_hyper2D_CUDA_simplest/tools.cuf: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real, dimension(:,:,:), intent(in) :: U 32 | 33 | real, dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 8 42 | Ny_int = Ny - 8 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call CPU_compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 5, Ny-4 81 | do i = 5, Nx-4 82 | write(11189, '(E20.7E6,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_basic folder contains a basic implementation of the Hyper2D finite volume solver. 6 | This version uses a time-explicit forward Euler time integrator, with fixed time step, and 7 | a Cartesian grid. No objects are introduced in the domain. The solution simply evolves 8 | from the initial state and according to the BCs. 9 | All input data is specified inside the global_module.f03 file. You can modify it there, then 10 | compile and run the code. 11 | 12 | Some different PDE systems are available in the "src/various_PDEs" directory. 13 | 14 | ================================== 15 | = COMPILING AND RUNNING THE CODE = 16 | ================================== 17 | 18 | For compiling the code, go into the src directory and type "make". 19 | This will create the 'hyper2d.exe' executable file. 20 | Copy it to the desired location and run it with: 21 | 22 | $ ./hyper2d.exe 23 | 24 | ***** 25 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 26 | ***** DIRECTORY. YOU NEED TO CREATE IT! 27 | ***** 28 | 29 | ========================= 30 | = STRUCTURE OF THE CODE = 31 | ========================= 32 | 33 | The hyper2d.f03 contains the main program. 34 | The global settings are implemented in the global_module.f03 file. 35 | The PDEs are implemented in the pde.f03 file. 36 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 37 | The routine for exporting to VTK is in tools.f03. 38 | 39 | The program goes like this: 40 | 1) The solution is initialized (calling pde.f03) 41 | 2) Boundary conditions are applied (calling pde.f03) 42 | 3) Time integration starts (calling integration.f03) 43 | 3.1) Numerical fluxes are computed 44 | 3.2) The solution is updated in time 45 | 4) The solution is exported (calling tools.f03) 46 | 47 | 48 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | ! This module contains data needed throughout the program. 4 | ! Most data is specified as a parameter, as to make the execution faster. 5 | ! This module is loaded by most other modules. 6 | 7 | implicit none 8 | 9 | ! Time integration 10 | 11 | real(kind=8), parameter :: dt = 1.0d-3 ! [s] time step for the simulation 12 | real(kind=8), parameter :: t_end = 500.0d0 ! [s] total simulated time (from 0 to t_end) 13 | 14 | ! Specify domain and discretization 15 | 16 | real(kind=8), parameter :: x_min = 0.0d0 ! [m] 17 | real(kind=8), parameter :: x_max = 3.0d0 ! [m] 18 | real(kind=8), parameter :: y_min = 0.0d0 ! [m] MUST BE POSITIVE FOR AXISYMMETRIC SIMULATION 19 | real(kind=8), parameter :: y_max = 1.0d0 ! [m] 20 | 21 | ! Total number of cells (including 2 ghost cells for each side) 22 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 23 | 24 | integer, parameter :: Nx = 300 25 | integer, parameter :: Ny = 150 26 | 27 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) 28 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) 29 | 30 | ! Spatial accuracy 31 | logical, parameter :: bool_MUSCL = .TRUE. 32 | 33 | end module 34 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | 34 | write(*,*) "Initializing solution..." 35 | call initialize_solution(U) ! See the pde.f03 module 36 | 37 | write(*,*) "Assigning BCs..." 38 | call assign_BCs(U) ! See the pde.f03 module 39 | 40 | write(*,*) "Writing solution at time step", 0, "..." 41 | call export_sol_vtk(0, U) 42 | 43 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 44 | 45 | Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 46 | 47 | do t_ID = 1, Nt 48 | 49 | write(*,*) 'Timestep', t_ID, 'of', Nt 50 | 51 | call forward_Euler_step(U, dt) 52 | 53 | if ( mod(t_ID, 25) .EQ. 0 ) then ! Write to VTK every ... timesteps 54 | 55 | write(*,*) "Writing solution at time step", t_ID, "..." 56 | call export_sol_vtk(t_ID, U) 57 | 58 | end if 59 | 60 | end do 61 | 62 | end program 63 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real(kind=8), dimension(:,:,:), intent(in) :: U 32 | 33 | real(kind=8), dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 4 42 | Ny_int = Ny - 4 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 3, Ny-2 81 | do i = 3, Nx-2 82 | write(11189, '(EN17.5E3,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/AXISYMMETRIC/src/various_PDEs/pde_shallow_water.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | ! This module contains all information that appears inside the PDEs. 4 | ! It specifies how many equations shall be solved, the numerical data, 5 | ! the routines to compute the fluxes from the solution, routines for 6 | ! computing primitive variables from the conserved solution U, etc. 7 | ! 8 | ! ---------- SHALLOW WATER EQUATIONS ---------- 9 | 10 | use global_module 11 | 12 | implicit none 13 | 14 | integer, parameter :: Neq = 3 ! Number of equations 15 | real(kind=8), parameter :: g = 9.81 ! [N/kg] Earth's gravity 16 | 17 | ! Initial conditions 18 | real(kind=8), parameter :: h0 = 1.0 ! [m] 19 | real(kind=8), parameter :: ux0 = 0.0 ! [m/s] 20 | real(kind=8), parameter :: uy0 = 0.0 ! [m/s] 21 | 22 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 23 | ! NOTE: To initialize it here, all entries need to have the same length!!! 24 | ! I'm using two letters for simplicity. 25 | character(len=20), dimension(Neq) :: prim_names = (/'hh','Ux','Uy'/) 26 | 27 | contains 28 | 29 | ! ============================================================ 30 | 31 | subroutine initialize_solution(U) 32 | 33 | implicit none 34 | 35 | real(kind=8), dimension(:,:,:), intent(inout) :: U 36 | 37 | ! Initialize internal cells (i = "1,2" and "Nx-1, Nx" are ghost cells. Same thing for j) 38 | U(1, 3:Nx-2, 3:Ny-2) = h0 ! Density 39 | U(2, 3:Nx-2, 3:Ny-2) = h0*ux0 ! Momentum along x 40 | U(3, 3:Nx-2, 3:Ny-2) = h0*uy0 ! Momentum along y 41 | 42 | 43 | U(1, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0 44 | U(2, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0*ux0 45 | U(3, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0*uy0 46 | 47 | end subroutine 48 | 49 | ! ============================================================ 50 | 51 | subroutine assign_BCs(U) 52 | 53 | ! This subroutine assigns boundary values to the ghost cells. 54 | ! In this form, we impose periodic BCs, by copying into the ghost cells the values inside the 55 | ! domain cells at the other side of the domain. 56 | 57 | implicit none 58 | 59 | real(kind=8), dimension(:,:,:), intent(inout) :: U 60 | 61 | integer :: i, j 62 | 63 | ! Periodic BCs 64 | U(:, 1:2, :) = U(:, Nx-3:Nx-2, :) ! Left BC 65 | U(:, Nx-1:Nx, :) = U(:, 3:4, :) ! Right BC 66 | U(:, :, 1:2) = U(:, :, Ny-3:Ny-2) ! Bottom BC 67 | U(:, :, Ny-1:Ny) = U(:, :, 3:4) ! Top BC 68 | 69 | end subroutine 70 | 71 | ! ============================================================ 72 | 73 | subroutine compute_primitive_from_conserved(U, prim) 74 | 75 | ! Computes vector of primitive variables "prim" from the conserved variables "U" 76 | 77 | implicit none 78 | 79 | real(kind=8), dimension(Neq), intent(in) :: U 80 | real(kind=8), dimension(Neq), intent(out) :: prim 81 | 82 | ! Working variables 83 | real(kind=8) :: h, ux, uy 84 | 85 | ! Extract primitive variables 86 | h = U(1) 87 | ux = U(2)/(h + 1.0d-25) ! Use a small tolerance, since h may be zero 88 | uy = U(3)/(h + 1.0d-25) ! Use a small tolerance, since h may be zero 89 | 90 | ! Compose array of primitive variables 91 | prim(1) = h 92 | prim(2) = ux 93 | prim(3) = uy 94 | 95 | end subroutine 96 | 97 | ! ============================================================ 98 | 99 | subroutine compute_flux_ws_x(U, Fx, ws_max, ws_min) 100 | 101 | ! Computes the convective flux along x, 102 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 103 | 104 | implicit none 105 | 106 | real(kind=8), dimension(Neq), intent(in) :: U 107 | real(kind=8), dimension(Neq), intent(out) :: Fx 108 | real(kind=8), intent(out) :: ws_max, ws_min 109 | 110 | real(kind=8), dimension(Neq) :: prim 111 | real(kind=8) :: h, ux, uy 112 | 113 | ! Compute primitive variables 114 | call compute_primitive_from_conserved(U, prim) 115 | h = prim(1) 116 | ux = prim(2) 117 | uy = prim(3) 118 | 119 | ! Assemble fluxes Fx 120 | Fx(1) = h*ux 121 | Fx(2) = h*ux*ux + 0.5*g*h**2 122 | Fx(3) = h*ux*uy 123 | 124 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 125 | ws_max = ux + sqrt(g*h) 126 | ws_min = ux - sqrt(g*h) 127 | 128 | end subroutine 129 | 130 | ! ============================================================ 131 | 132 | subroutine compute_flux_ws_y(U, Fy, ws_max, ws_min) 133 | 134 | ! Computes the convective flux along y, 135 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 136 | 137 | implicit none 138 | 139 | real(kind=8), dimension(Neq), intent(in) :: U 140 | real(kind=8), dimension(Neq), intent(out) :: Fy 141 | real(kind=8), intent(out) :: ws_max, ws_min 142 | 143 | real(kind=8), dimension(Neq) :: prim 144 | real(kind=8) :: h, ux, uy 145 | 146 | ! Compute primitive variables 147 | call compute_primitive_from_conserved(U, prim) 148 | h = prim(1) 149 | ux = prim(2) 150 | uy = prim(3) 151 | 152 | ! Assemble fluxes Fx 153 | Fy(1) = h*uy 154 | Fy(2) = h*ux*uy 155 | Fy(3) = h*uy*uy + 0.5*g*h*h 156 | 157 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 158 | ws_max = uy + sqrt(g*h) 159 | ws_min = uy - sqrt(g*h) 160 | 161 | end subroutine 162 | 163 | end module 164 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_basic folder contains a basic implementation of the Hyper2D finite volume solver. 6 | This version uses a time-explicit forward Euler time integrator, with fixed time step, and 7 | a Cartesian grid. No objects are introduced in the domain. The solution simply evolves 8 | from the initial state and according to the BCs. 9 | All input data is specified inside the global_module.f03 file. You can modify it there, then 10 | compile and run the code. 11 | 12 | Some different PDE systems are available in the "src/various_PDEs" directory. 13 | 14 | ================================== 15 | = COMPILING AND RUNNING THE CODE = 16 | ================================== 17 | 18 | For compiling the code, go into the src directory and type "make". 19 | This will create the 'hyper2d.exe' executable file. 20 | Copy it to the desired location and run it with: 21 | 22 | $ ./hyper2d.exe 23 | 24 | ***** 25 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 26 | ***** DIRECTORY. YOU NEED TO CREATE IT! 27 | ***** 28 | 29 | ========================= 30 | = STRUCTURE OF THE CODE = 31 | ========================= 32 | 33 | The hyper2d.f03 contains the main program. 34 | The global settings are implemented in the global_module.f03 file. 35 | The PDEs are implemented in the pde.f03 file. 36 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 37 | The routine for exporting to VTK is in tools.f03. 38 | 39 | The program goes like this: 40 | 1) The solution is initialized (calling pde.f03) 41 | 2) Boundary conditions are applied (calling pde.f03) 42 | 3) Time integration starts (calling integration.f03) 43 | 3.1) Numerical fluxes are computed 44 | 3.2) The solution is updated in time 45 | 4) The solution is exported (calling tools.f03) 46 | 47 | 48 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | ! This module contains data needed throughout the program. 4 | ! Most data is specified as a parameter, as to make the execution faster. 5 | ! This module is loaded by most other modules. 6 | 7 | implicit none 8 | 9 | ! Time integration 10 | 11 | !!! For Euler !!! real(kind=8), parameter :: dt = 1.0d-7 ! [s] time step for the simulation 12 | !!! For Euler !!! real(kind=8), parameter :: t_end = 1.0d-2 ! [s] total simulated time (from 0 to t_end) 13 | 14 | real(kind=8), parameter :: dt = 1.0d-4 ! [s] time step for the simulation 15 | real(kind=8), parameter :: t_end = 10.0d0 ! [s] total simulated time (from 0 to t_end) 16 | 17 | ! Specify domain and discretization 18 | 19 | real(kind=8), parameter :: x_min = -1.0 ! [m] 20 | real(kind=8), parameter :: x_max = 2.0 ! [m] 21 | real(kind=8), parameter :: y_min = -1.0 ! [m] 22 | real(kind=8), parameter :: y_max = 1.0 ! [m] 23 | 24 | ! Total number of cells (including 2 ghost cells for each side) 25 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 26 | 27 | integer, parameter :: Nx = 500 28 | integer, parameter :: Ny = 500 29 | 30 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) 31 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) 32 | 33 | end module 34 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | 34 | write(*,*) "Initializing solution..." 35 | call initialize_solution(U) ! See the pde.f03 module 36 | 37 | write(*,*) "Assigning BCs..." 38 | call assign_BCs(U) ! See the pde.f03 module 39 | 40 | write(*,*) "Writing solution at time step", 0, "..." 41 | call export_sol_vtk(0, U) 42 | 43 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 44 | 45 | Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 46 | 47 | do t_ID = 1, Nt 48 | 49 | write(*,*) 'Timestep', t_ID, 'of', Nt 50 | 51 | call forward_Euler_step(U, dt) 52 | 53 | if ( mod(t_ID, 25) .EQ. 0 ) then ! Write to VTK every ... timesteps 54 | 55 | write(*,*) "Writing solution at time step", t_ID, "..." 56 | call export_sol_vtk(t_ID, U) 57 | 58 | end if 59 | 60 | end do 61 | 62 | end program 63 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/integration.f03: -------------------------------------------------------------------------------- 1 | module integration 2 | 3 | ! This module contains the routines for the time integration and the computation 4 | ! of numerical fluxes (Rusanov in this example). 5 | 6 | use pde 7 | use global_module 8 | 9 | implicit none 10 | 11 | real(kind=8), dimension(Neq,Nx,Ny) :: U_new ! Working variable 12 | 13 | contains 14 | 15 | ! ======================================================================== 16 | 17 | subroutine forward_Euler_step(U, dt) 18 | 19 | ! This function performs one step of the Forward Euler explicit time integrator 20 | 21 | implicit none 22 | 23 | real(kind=8), dimension(Neq,Nx,Ny), intent(inout) :: U 24 | 25 | real(kind=8), intent(in) :: dt 26 | integer :: i, j, eqID 27 | 28 | real(kind=8), dimension(Neq) :: F_N, F_S, F_W, F_E 29 | 30 | ! First, assign BCs. Wall BCs need to be updated in time, taking the value 31 | ! from neighboring cells. 32 | call assign_BCs(U) ! See the pde.f03 module 33 | 34 | ! Update solution using the forward Euler integrator - INTERNAL CELLS only 35 | do j = 3, Ny-2 36 | do i = 3, Nx-2 37 | 38 | call compute_fluxes_Rusanov(U, i, j, F_N, F_S, F_W, F_E) 39 | 40 | U_new(:,i,j) = U(:,i,j) - dt/dx*(F_E - F_W) - dt/dy*(F_N - F_S) 41 | 42 | ! Check that the solution did not diverge 43 | do eqID = 1, Neq 44 | if (isnan(U_new(eqID,i,j))) then 45 | print*, 'Solution diverged, try with a smaller time step! Aborting.' 46 | stop 47 | end if 48 | end do 49 | 50 | end do 51 | end do 52 | 53 | ! Save solution (internal cells ONLY! Do not overwrite ghost cells!) 54 | U(:,3:Nx-2,3:Ny-2) = U_new(:,3:Nx-2,3:Ny-2) 55 | 56 | end subroutine 57 | 58 | ! ======================================================================== 59 | 60 | subroutine compute_fluxes_Rusanov(U, i, j, F_N, F_S, F_W, F_E) 61 | 62 | ! Computes Rusanov numerical fluxes for the cell (i,j) 63 | 64 | implicit none 65 | 66 | real(kind=8), dimension(Neq,Nx,Ny), intent(in) :: U 67 | real(kind=8), dimension(Neq), intent(out) :: F_N, F_S, F_W, F_E 68 | integer, intent(in) :: i, j 69 | 70 | integer :: eqID 71 | real(kind=8), dimension(Neq) :: U_L, U_R, F_L, F_R 72 | 73 | real(kind=8) :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_max ! wave speeds 74 | 75 | ! ------ North interface 76 | U_L = U(:,i,j) 77 | U_R = U(:,i,j+1) 78 | 79 | call compute_flux_ws_y(U_L, F_L, ws_max_L, ws_min_L) 80 | call compute_flux_ws_y(U_R, F_R, ws_max_R, ws_min_R) 81 | 82 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 83 | 84 | F_N = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 85 | 86 | ! ------ South interface 87 | U_L = U(:,i,j-1) 88 | U_R = U(:,i,j) 89 | 90 | call compute_flux_ws_y(U_L, F_L, ws_max_L, ws_min_L) 91 | call compute_flux_ws_y(U_R, F_R, ws_max_R, ws_min_R) 92 | 93 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 94 | 95 | F_S = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 96 | 97 | ! ------ East interface 98 | U_L = U(:,i,j) 99 | U_R = U(:,i+1,j) 100 | 101 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 102 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 103 | 104 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 105 | 106 | F_E = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 107 | 108 | ! ------ West interface 109 | U_L = U(:,i-1,j) 110 | U_R = U(:,i,j) 111 | 112 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 113 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 114 | 115 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 116 | 117 | F_W = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 118 | 119 | end subroutine 120 | 121 | end module 122 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/pde.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | ! This module contains all information that appears inside the PDEs. 4 | ! It specifies how many equations shall be solved, the numerical data, 5 | ! the routines to compute the fluxes from the solution, routines for 6 | ! computing primitive variables from the conserved solution U, etc. 7 | ! 8 | ! ---------- SHALLOW WATER EQUATIONS ---------- 9 | 10 | use global_module 11 | 12 | implicit none 13 | 14 | integer, parameter :: Neq = 3 ! Number of equations 15 | real(kind=8), parameter :: g = 9.81 ! [N/kg] Earth's gravity 16 | 17 | ! Initial conditions 18 | real(kind=8), parameter :: h0 = 1.0 ! [m] 19 | real(kind=8), parameter :: ux0 = 0.0 ! [m/s] 20 | real(kind=8), parameter :: uy0 = 0.0 ! [m/s] 21 | 22 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 23 | ! NOTE: To initialize it here, all entries need to have the same length!!! 24 | ! I'm using two letters for simplicity. 25 | character(len=20), dimension(Neq) :: prim_names = (/'hh','Ux','Uy'/) 26 | 27 | contains 28 | 29 | ! ============================================================ 30 | 31 | subroutine initialize_solution(U) 32 | 33 | implicit none 34 | 35 | real(kind=8), dimension(:,:,:), intent(inout) :: U 36 | 37 | ! Initialize internal cells (i = "1,2" and "Nx-1, Nx" are ghost cells. Same thing for j) 38 | U(1, 3:Nx-2, 3:Ny-2) = h0 ! Density 39 | U(2, 3:Nx-2, 3:Ny-2) = h0*ux0 ! Momentum along x 40 | U(3, 3:Nx-2, 3:Ny-2) = h0*uy0 ! Momentum along y 41 | 42 | 43 | U(1, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0 44 | U(2, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0*ux0 45 | U(3, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0*uy0 46 | 47 | end subroutine 48 | 49 | ! ============================================================ 50 | 51 | subroutine assign_BCs(U) 52 | 53 | ! This subroutine assigns boundary values to the ghost cells. 54 | ! In this form, we impose periodic BCs, by copying into the ghost cells the values inside the 55 | ! domain cells at the other side of the domain. 56 | 57 | implicit none 58 | 59 | real(kind=8), dimension(:,:,:), intent(inout) :: U 60 | 61 | integer :: i, j 62 | 63 | ! Periodic BCs 64 | U(:, 1:2, :) = U(:, Nx-3:Nx-2, :) ! Left BC 65 | U(:, Nx-1:Nx, :) = U(:, 3:4, :) ! Right BC 66 | U(:, :, 1:2) = U(:, :, Ny-3:Ny-2) ! Bottom BC 67 | U(:, :, Ny-1:Ny) = U(:, :, 3:4) ! Top BC 68 | 69 | end subroutine 70 | 71 | ! ============================================================ 72 | 73 | subroutine compute_primitive_from_conserved(U, prim) 74 | 75 | ! Computes vector of primitive variables "prim" from the conserved variables "U" 76 | 77 | implicit none 78 | 79 | real(kind=8), dimension(Neq), intent(in) :: U 80 | real(kind=8), dimension(Neq), intent(out) :: prim 81 | 82 | ! Working variables 83 | real(kind=8) :: h, ux, uy 84 | 85 | ! Extract primitive variables 86 | h = U(1) 87 | ux = U(2)/(h + 1.0d-25) ! Use a small tolerance, since h may be zero 88 | uy = U(3)/(h + 1.0d-25) ! Use a small tolerance, since h may be zero 89 | 90 | ! Compose array of primitive variables 91 | prim(1) = h 92 | prim(2) = ux 93 | prim(3) = uy 94 | 95 | end subroutine 96 | 97 | ! ============================================================ 98 | 99 | subroutine compute_flux_ws_x(U, Fx, ws_max, ws_min) 100 | 101 | ! Computes the convective flux along x, 102 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 103 | 104 | implicit none 105 | 106 | real(kind=8), dimension(Neq), intent(in) :: U 107 | real(kind=8), dimension(Neq), intent(out) :: Fx 108 | real(kind=8), intent(out) :: ws_max, ws_min 109 | 110 | real(kind=8), dimension(Neq) :: prim 111 | real(kind=8) :: h, ux, uy 112 | 113 | ! Compute primitive variables 114 | call compute_primitive_from_conserved(U, prim) 115 | h = prim(1) 116 | ux = prim(2) 117 | uy = prim(3) 118 | 119 | ! Assemble fluxes Fx 120 | Fx(1) = h*ux 121 | Fx(2) = h*ux*ux + 0.5*g*h**2 122 | Fx(3) = h*ux*uy 123 | 124 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 125 | ws_max = ux + sqrt(g*h) 126 | ws_min = ux - sqrt(g*h) 127 | 128 | end subroutine 129 | 130 | ! ============================================================ 131 | 132 | subroutine compute_flux_ws_y(U, Fy, ws_max, ws_min) 133 | 134 | ! Computes the convective flux along y, 135 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 136 | 137 | implicit none 138 | 139 | real(kind=8), dimension(Neq), intent(in) :: U 140 | real(kind=8), dimension(Neq), intent(out) :: Fy 141 | real(kind=8), intent(out) :: ws_max, ws_min 142 | 143 | real(kind=8), dimension(Neq) :: prim 144 | real(kind=8) :: h, ux, uy 145 | 146 | ! Compute primitive variables 147 | call compute_primitive_from_conserved(U, prim) 148 | h = prim(1) 149 | ux = prim(2) 150 | uy = prim(3) 151 | 152 | ! Assemble fluxes Fx 153 | Fy(1) = h*uy 154 | Fy(2) = h*ux*uy 155 | Fy(3) = h*uy*uy + 0.5*g*h*h 156 | 157 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 158 | ws_max = uy + sqrt(g*h) 159 | ws_min = uy - sqrt(g*h) 160 | 161 | end subroutine 162 | 163 | end module 164 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real(kind=8), dimension(:,:,:), intent(in) :: U 32 | 33 | real(kind=8), dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 4 42 | Ny_int = Ny - 4 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 3, Ny-2 81 | do i = 3, Nx-2 82 | write(11189, '(EN17.5E3,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_basic/various_PDEs/pde_shallow_water.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | ! This module contains all information that appears inside the PDEs. 4 | ! It specifies how many equations shall be solved, the numerical data, 5 | ! the routines to compute the fluxes from the solution, routines for 6 | ! computing primitive variables from the conserved solution U, etc. 7 | ! 8 | ! ---------- SHALLOW WATER EQUATIONS ---------- 9 | 10 | use global_module 11 | 12 | implicit none 13 | 14 | integer, parameter :: Neq = 3 ! Number of equations 15 | real(kind=8), parameter :: g = 9.81 ! [N/kg] Earth's gravity 16 | 17 | ! Initial conditions 18 | real(kind=8), parameter :: h0 = 1.0 ! [m] 19 | real(kind=8), parameter :: ux0 = 0.0 ! [m/s] 20 | real(kind=8), parameter :: uy0 = 0.0 ! [m/s] 21 | 22 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 23 | ! NOTE: To initialize it here, all entries need to have the same length!!! 24 | ! I'm using two letters for simplicity. 25 | character(len=20), dimension(Neq) :: prim_names = (/'hh','Ux','Uy'/) 26 | 27 | contains 28 | 29 | ! ============================================================ 30 | 31 | subroutine initialize_solution(U) 32 | 33 | implicit none 34 | 35 | real(kind=8), dimension(:,:,:), intent(inout) :: U 36 | 37 | ! Initialize internal cells (i = "1,2" and "Nx-1, Nx" are ghost cells. Same thing for j) 38 | U(1, 3:Nx-2, 3:Ny-2) = h0 ! Density 39 | U(2, 3:Nx-2, 3:Ny-2) = h0*ux0 ! Momentum along x 40 | U(3, 3:Nx-2, 3:Ny-2) = h0*uy0 ! Momentum along y 41 | 42 | 43 | U(1, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0 44 | U(2, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0*ux0 45 | U(3, floor((Nx)/3.0):floor(real(Nx)/2.0), floor((Ny)/3.0):floor(real(Ny)/2.0)) = 2.0*h0*uy0 46 | 47 | end subroutine 48 | 49 | ! ============================================================ 50 | 51 | subroutine assign_BCs(U) 52 | 53 | ! This subroutine assigns boundary values to the ghost cells. 54 | ! In this form, we impose periodic BCs, by copying into the ghost cells the values inside the 55 | ! domain cells at the other side of the domain. 56 | 57 | implicit none 58 | 59 | real(kind=8), dimension(:,:,:), intent(inout) :: U 60 | 61 | integer :: i, j 62 | 63 | ! Periodic BCs 64 | U(:, 1:2, :) = U(:, Nx-3:Nx-2, :) ! Left BC 65 | U(:, Nx-1:Nx, :) = U(:, 3:4, :) ! Right BC 66 | U(:, :, 1:2) = U(:, :, Ny-3:Ny-2) ! Bottom BC 67 | U(:, :, Ny-1:Ny) = U(:, :, 3:4) ! Top BC 68 | 69 | end subroutine 70 | 71 | ! ============================================================ 72 | 73 | subroutine compute_primitive_from_conserved(U, prim) 74 | 75 | ! Computes vector of primitive variables "prim" from the conserved variables "U" 76 | 77 | implicit none 78 | 79 | real(kind=8), dimension(Neq), intent(in) :: U 80 | real(kind=8), dimension(Neq), intent(out) :: prim 81 | 82 | ! Working variables 83 | real(kind=8) :: h, ux, uy 84 | 85 | ! Extract primitive variables 86 | h = U(1) 87 | ux = U(2)/(h + 1.0d-25) ! Use a small tolerance, since h may be zero 88 | uy = U(3)/(h + 1.0d-25) ! Use a small tolerance, since h may be zero 89 | 90 | ! Compose array of primitive variables 91 | prim(1) = h 92 | prim(2) = ux 93 | prim(3) = uy 94 | 95 | end subroutine 96 | 97 | ! ============================================================ 98 | 99 | subroutine compute_flux_ws_x(U, Fx, ws_max, ws_min) 100 | 101 | ! Computes the convective flux along x, 102 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 103 | 104 | implicit none 105 | 106 | real(kind=8), dimension(Neq), intent(in) :: U 107 | real(kind=8), dimension(Neq), intent(out) :: Fx 108 | real(kind=8), intent(out) :: ws_max, ws_min 109 | 110 | real(kind=8), dimension(Neq) :: prim 111 | real(kind=8) :: h, ux, uy 112 | 113 | ! Compute primitive variables 114 | call compute_primitive_from_conserved(U, prim) 115 | h = prim(1) 116 | ux = prim(2) 117 | uy = prim(3) 118 | 119 | ! Assemble fluxes Fx 120 | Fx(1) = h*ux 121 | Fx(2) = h*ux*ux + 0.5*g*h**2 122 | Fx(3) = h*ux*uy 123 | 124 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 125 | ws_max = ux + sqrt(g*h) 126 | ws_min = ux - sqrt(g*h) 127 | 128 | end subroutine 129 | 130 | ! ============================================================ 131 | 132 | subroutine compute_flux_ws_y(U, Fy, ws_max, ws_min) 133 | 134 | ! Computes the convective flux along y, 135 | ! and also the maximum and minimum wave speeds (required by some numerical flux schemes) 136 | 137 | implicit none 138 | 139 | real(kind=8), dimension(Neq), intent(in) :: U 140 | real(kind=8), dimension(Neq), intent(out) :: Fy 141 | real(kind=8), intent(out) :: ws_max, ws_min 142 | 143 | real(kind=8), dimension(Neq) :: prim 144 | real(kind=8) :: h, ux, uy 145 | 146 | ! Compute primitive variables 147 | call compute_primitive_from_conserved(U, prim) 148 | h = prim(1) 149 | ux = prim(2) 150 | uy = prim(3) 151 | 152 | ! Assemble fluxes Fx 153 | Fy(1) = h*uy 154 | Fy(2) = h*ux*uy 155 | Fy(3) = h*uy*uy + 0.5*g*h*h 156 | 157 | ! Maximum and minimum wave speeds (eigenvalues of the Euler system) 158 | ws_max = uy + sqrt(g*h) 159 | ws_min = uy - sqrt(g*h) 160 | 161 | end subroutine 162 | 163 | end module 164 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_higher_order/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_higher_order/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | This directory contains a higher order implementation of the basic hyper2D solver. 6 | Please refer to the previous directories for a full description. 7 | 8 | A Cartesian grid is employed, and no objects are introduced into the domain. 9 | Notice that four ghost cells are employed for each side of the domain. 10 | This allows to reach up to 5th accuracy at the boundaries (with WENO). 11 | We provide the following possibilities: 12 | 13 | SPACE INTEGRATION 14 | 15 | - Second order in space, using van Leer's MUSCL linear reconstruction with TVD slope limiter. 16 | 17 | - Third order in space, with WENO method 18 | 19 | - Fifth order in space, with WENO method 20 | 21 | TIME INTEGRATION (explicit steppers) 22 | 23 | - First order, forward Euler 24 | 25 | - Second order, midpoint Euler 26 | 27 | - Third order, TVD Runge-Kutta 28 | 29 | These options are chosen via parameters in the global_module file. 30 | 31 | ================================== 32 | = COMPILING AND RUNNING THE CODE = 33 | ================================== 34 | 35 | For compiling the code, go into the src directory and type "make". 36 | This will create the 'hyper2d.exe' executable file. 37 | Copy it to the desired location and run it with: 38 | 39 | $ ./hyper2d.exe 40 | 41 | ***** 42 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 43 | ***** DIRECTORY. YOU NEED TO CREATE IT! 44 | ***** 45 | 46 | 47 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_higher_order/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_higher_order/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | ! This module contains data needed throughout the program. 4 | ! Most data is specified as a parameter, as to make the execution faster. 5 | ! This module is loaded by most other modules. 6 | 7 | implicit none 8 | 9 | ! Time integration 10 | 11 | ! For Euler ! real(kind=8), parameter :: dt = 1.0d-6 ! [s] time step for the simulation 12 | ! For Euler ! real(kind=8), parameter :: t_end = 1.0d-2 ! [s] total simulated time (from 0 to t_end) 13 | 14 | real(kind=8), parameter :: dt = 1.0d-4 ! [s] time step for the simulation 15 | real(kind=8), parameter :: t_end = 10.0d0 ! [s] total simulated time (from 0 to t_end) 16 | 17 | ! Specify domain and discretization 18 | 19 | real(kind=8), parameter :: x_min = -1.0 ! [m] 20 | real(kind=8), parameter :: x_max = 2.0 ! [m] 21 | real(kind=8), parameter :: y_min = -1.0 ! [m] 22 | real(kind=8), parameter :: y_max = 1.0 ! [m] 23 | 24 | ! Total number of cells (including 2 ghost cells for each side) 25 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 26 | 27 | integer, parameter :: Nx = 500 28 | integer, parameter :: Ny = 500 29 | 30 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) 31 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) 32 | 33 | ! Spacial accuracy (order) 34 | ! 1: uniform sol in cell, first order in space 35 | ! 2: MUSCL with TVD slope limiter, second order in space 36 | ! 3: WENO 3rd order 37 | ! 5: WENO 5th order 38 | integer, parameter :: space_order = 5 39 | 40 | ! Time accuracy (order) 41 | ! 1: forward Euler, first order in time 42 | ! 2: midpoint Euler, second order in time 43 | ! 3: explicit TVD Runge-Kutta, third order in time 44 | integer, parameter :: time_order = 3 45 | 46 | ! Space fluxes: choose ONLY one 47 | logical, parameter :: flux_type_Rusanov = .true. 48 | 49 | end module 50 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_higher_order/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | 34 | write(*,*) "Initializing solution..." 35 | call initialize_solution(U) ! See the pde.f03 module 36 | 37 | write(*,*) "Assigning BCs..." 38 | call assign_BCs(U) ! See the pde.f03 module 39 | 40 | write(*,*) "Writing solution at time step", 0, "..." 41 | call export_sol_vtk(0, U) 42 | 43 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 44 | 45 | Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 46 | 47 | do t_ID = 1, Nt 48 | 49 | write(*,*) 'Timestep', t_ID, 'of', Nt 50 | 51 | ! Integrate by one timestep 52 | 53 | if (time_order .eq. 1) then 54 | 55 | call forward_Euler_step(U, dt) 56 | 57 | else if (time_order .eq. 2) then 58 | 59 | call midpoint_Euler_step(U, dt) 60 | 61 | else if (time_order .eq. 3) then 62 | 63 | call RK3_step(U, dt) 64 | 65 | end if 66 | 67 | ! Export solution 68 | 69 | if ( mod(t_ID, 25) .EQ. 0 ) then ! Write to VTK every ... timesteps 70 | 71 | write(*,*) "Writing solution at time step", t_ID, "..." 72 | call export_sol_vtk(t_ID, U) 73 | 74 | end if 75 | 76 | end do 77 | 78 | end program 79 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_basic/src_higher_order/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real(kind=8), dimension(:,:,:), intent(in) :: U 32 | 33 | real(kind=8), dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 4 42 | Ny_int = Ny - 4 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 3, Ny-2 81 | do i = 3, Nx-2 82 | write(11189, '(EN17.5E3,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_basic folder contains a basic implementation of the Hyper2D finite volume solver. 6 | This version uses a time-explicit forward Euler time integrator, with fixed time step, and 7 | a Cartesian grid. A flat plate is introduced inside the domain. 8 | All input data is specified inside the global_module.f03 file. You can modify it there, then 9 | compile and run the code. 10 | 11 | ================================== 12 | = COMPILING AND RUNNING THE CODE = 13 | ================================== 14 | 15 | For compiling the code, go into the src directory and type "make". 16 | This will create the 'hyper2d.exe' executable file. 17 | Copy it to the desired location and run it with: 18 | 19 | $ ./hyper2d.exe 20 | 21 | ***** 22 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 23 | ***** DIRECTORY. YOU NEED TO CREATE IT! 24 | ***** 25 | 26 | ========================= 27 | = STRUCTURE OF THE CODE = 28 | ========================= 29 | 30 | The hyper2d.f03 contains the main program. 31 | The global settings are implemented in the global_module.f03 file. 32 | The PDEs are implemented in the pde.f03 file. 33 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 34 | The routine for exporting to VTK is in tools.f03. 35 | 36 | The program goes like this: 37 | 1) The solution is initialized (calling pde.f03) 38 | 2) Boundary conditions are applied (calling pde.f03) 39 | 3) Time integration starts (calling integration.f03) 40 | 3.1) Numerical fluxes are computed 41 | 3.2) The solution is updated in time 42 | 4) The solution is exported (calling tools.f03) 43 | 44 | 45 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | ! This module contains data needed throughout the program. 4 | ! Most data is specified as a parameter, as to make the execution faster. 5 | ! This module is loaded by most other modules. 6 | 7 | implicit none 8 | 9 | ! Time integration 10 | 11 | real(kind=8), parameter :: dt = 1.0d-7 ! [s] time step for the simulation 12 | real(kind=8), parameter :: t_end = 1.0d-2 ! [s] total simulated time (from 0 to t_end) 13 | 14 | ! Specify domain and discretization 15 | 16 | real(kind=8), parameter :: x_min = -1.0 ! [m] needs to be NEGATIVE 17 | real(kind=8), parameter :: x_max = 2.0 ! [m] needs to be LARGER THAN PLATE LENGTH L_plate 18 | real(kind=8), parameter :: y_min = -1.0 ! [m] needs to be NEGATIVE 19 | real(kind=8), parameter :: y_max = 1.0 ! [m] needs to be POSITIVE 20 | 21 | ! Total number of cells (including 2 ghost cells for each side) 22 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 23 | 24 | integer, parameter :: Nx = 100 25 | integer, parameter :: Ny = 100 26 | 27 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) 28 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) 29 | 30 | ! Flat plate inside the domain. 31 | ! The plate is placed with the leading edge at (x,y) = (0,0). 32 | ! Make sure the domain is chosen correspondingly. 33 | 34 | real(kind=8), parameter :: L_plate = 1 ! [m] length of the flat plate 35 | 36 | integer, parameter :: j_plate = floor(Ny/(y_max - y_min)*(0 - y_min)) ! find j-index of plate 37 | integer, parameter :: i_1_plate = floor(Nx/(x_max - x_min)*(0 - x_min)) ! starting coordinate of plate 38 | integer, parameter :: i_2_plate = floor(Nx/(x_max - x_min)*(L_plate - x_min)) ! starting coordinate of plate 39 | 40 | ! Free stream conditions for initializing the solution 41 | real(kind=8) :: rho0 = 1.225 ! [kg/m3] 42 | real(kind=8) :: ux0 = 0.0 ! [m/s] 43 | real(kind=8) :: uy0 = 10000.0 ! [m/s] 44 | real(kind=8) :: T0 = 300.0 ! [K] 45 | 46 | end module 47 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | 34 | write(*,*) "Initializing solution..." 35 | call initialize_solution(U) ! See the pde.f03 module 36 | 37 | write(*,*) "Assigning BCs..." 38 | call assign_BCs(U) ! See the pde.f03 module 39 | 40 | write(*,*) "Writing solution at time step", 0, "..." 41 | call export_sol_vtk(0, U) 42 | 43 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 44 | 45 | Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 46 | 47 | do t_ID = 1, Nt 48 | 49 | write(*,*) 'Timestep', t_ID, 'of', Nt 50 | 51 | call forward_Euler_step(U, dt) 52 | 53 | if ( mod(t_ID, 50) .EQ. 0 ) then ! Write to VTK every ... timesteps 54 | 55 | write(*,*) "Writing solution at time step", t_ID, "..." 56 | call export_sol_vtk(t_ID, U) 57 | 58 | end if 59 | 60 | end do 61 | 62 | end program 63 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/src/integration.f03: -------------------------------------------------------------------------------- 1 | module integration 2 | 3 | ! This module contains the routines for the time integration and the computation 4 | ! of numerical fluxes (Rusanov in this example). 5 | 6 | use pde 7 | use global_module 8 | 9 | implicit none 10 | 11 | real(kind=8), dimension(Neq,Nx,Ny) :: U_new ! Working variable 12 | 13 | contains 14 | 15 | ! ======================================================================== 16 | 17 | subroutine forward_Euler_step(U, dt) 18 | 19 | ! This function performs one step of the Forward Euler explicit time integrator 20 | 21 | implicit none 22 | 23 | real(kind=8), dimension(Neq,Nx,Ny), intent(inout) :: U 24 | 25 | real(kind=8), intent(in) :: dt 26 | integer :: i, j, eqID 27 | 28 | real(kind=8), dimension(Neq) :: F_N, F_S, F_W, F_E 29 | 30 | ! First, assign BCs. Wall BCs need to be updated in time, taking the value 31 | ! from neighboring cells. 32 | call assign_BCs(U) ! See the pde.f03 module 33 | 34 | ! Update solution using the forward Euler integrator - INTERNAL CELLS only 35 | do j = 3, Ny-2 36 | do i = 3, Nx-2 37 | 38 | call compute_fluxes_Rusanov(U, i, j, F_N, F_S, F_W, F_E) 39 | 40 | call introduce_flat_plate(U, i, j, F_N, F_S, F_W, F_E) 41 | 42 | U_new(:,i,j) = U(:,i,j) - dt/dx*(F_E - F_W) - dt/dy*(F_N - F_S) 43 | 44 | ! Check that the solution did not diverge 45 | do eqID = 1, Neq 46 | if (isnan(U_new(eqID,i,j))) then 47 | print*, 'Solution diverged, try with a smaller time step! Aborting.' 48 | stop 49 | end if 50 | end do 51 | 52 | end do 53 | end do 54 | 55 | ! Save solution (internal cells ONLY! Do not overwrite ghost cells!) 56 | U(:,3:Nx-2,3:Ny-2) = U_new(:,3:Nx-2,3:Ny-2) 57 | 58 | end subroutine 59 | 60 | ! ======================================================================== 61 | 62 | subroutine compute_fluxes_Rusanov(U, i, j, F_N, F_S, F_W, F_E) 63 | 64 | ! Computes Rusanov numerical fluxes for the cell (i,j) 65 | 66 | implicit none 67 | 68 | real(kind=8), dimension(Neq,Nx,Ny), intent(in) :: U 69 | real(kind=8), dimension(Neq), intent(out) :: F_N, F_S, F_W, F_E 70 | integer, intent(in) :: i, j 71 | 72 | integer :: eqID 73 | real(kind=8), dimension(Neq) :: U_L, U_R, F_L, F_R 74 | 75 | real(kind=8) :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_max ! wave speeds 76 | 77 | ! ------ North interface 78 | U_L = U(:,i,j) 79 | U_R = U(:,i,j+1) 80 | 81 | call compute_flux_ws_y(U_L, F_L, ws_max_L, ws_min_L) 82 | call compute_flux_ws_y(U_R, F_R, ws_max_R, ws_min_R) 83 | 84 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 85 | 86 | F_N = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 87 | 88 | ! ------ South interface 89 | U_L = U(:,i,j-1) 90 | U_R = U(:,i,j) 91 | 92 | call compute_flux_ws_y(U_L, F_L, ws_max_L, ws_min_L) 93 | call compute_flux_ws_y(U_R, F_R, ws_max_R, ws_min_R) 94 | 95 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 96 | 97 | F_S = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 98 | 99 | ! ------ East interface 100 | U_L = U(:,i,j) 101 | U_R = U(:,i+1,j) 102 | 103 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 104 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 105 | 106 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 107 | 108 | F_E = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 109 | 110 | ! ------ West interface 111 | U_L = U(:,i-1,j) 112 | U_R = U(:,i,j) 113 | 114 | call compute_flux_ws_x(U_L, F_L, ws_max_L, ws_min_L) 115 | call compute_flux_ws_x(U_R, F_R, ws_max_R, ws_min_R) 116 | 117 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 118 | 119 | F_W = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 120 | 121 | end subroutine 122 | 123 | ! ============================================== 124 | 125 | subroutine introduce_flat_plate(U, i, j, F_N, F_S, F_W, F_E) 126 | 127 | ! This function introduces a flat plate, by modifying the fluxes, only for the cells 128 | ! that are in contact with the plate. 129 | 130 | implicit none 131 | 132 | integer, intent(in) :: i, j 133 | real(kind=8), dimension(Neq), intent(inout) :: F_N, F_S, F_W, F_E 134 | real(kind=8), dimension(Neq,Nx,Ny), intent(in) :: U 135 | 136 | real(kind=8), dimension(Neq) :: prim ! Primitive variables 137 | real(kind=8) :: P 138 | 139 | ! The indices j_plate, i_1_plate, i_2_plate identify the plate position. 140 | ! They are defined in global_module.f03 141 | 142 | if (j .EQ. j_plate) then ! Cells below the plate 143 | 144 | if ( (i .GE. i_1_plate) .AND. (i .LE. i_2_plate) ) then ! Cells in contact with the plate 145 | 146 | ! These cells are BELOW the plate. Change F_N 147 | call compute_primitive_from_conserved(U(:,i,j), prim) 148 | 149 | P = prim(1)/M*kB*prim(4) ! P = n*kB*T = rho/M*kB*T 150 | 151 | ! Only pressure normal to the wall remains 152 | F_N(1) = 0.0 153 | F_N(2) = 0.0 154 | F_N(3) = P 155 | F_N(4) = 0.0 156 | 157 | end if 158 | 159 | else if (j .EQ. j_plate + 1) then 160 | 161 | if ( (i .GE. i_1_plate) .AND. (i .LE. i_2_plate) ) then ! Cells in contact with the plate 162 | 163 | ! These cells are ABOVE the plate. Change F_S 164 | call compute_primitive_from_conserved(U(:,i,j), prim) 165 | 166 | P = prim(1)/M*kB*prim(4) ! P = n*kB*T = rho/M*kB*T 167 | 168 | ! Only pressure normal to the wall remains 169 | F_S(1) = 0.0 170 | F_S(2) = 0.0 171 | F_S(3) = P 172 | F_S(4) = 0.0 173 | 174 | end if 175 | 176 | end if 177 | 178 | end subroutine 179 | 180 | end module 181 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_flatplate/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real(kind=8), dimension(:,:,:), intent(in) :: U 32 | 33 | real(kind=8), dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 4 42 | Ny_int = Ny - 4 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 3, Ny-2 81 | do i = 3, Nx-2 82 | write(11189, '(EN17.5E3,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_hypersonic/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_hypersonic/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_hypersonic folder contains a non-equilibrium two-temperatures solver for the 6 | Euler equations. Two temperatures are considered: a roto-translational temperature T and 7 | a vibrational temperature Tv. These temperatures relax following the Landau-Teller model. 8 | 9 | The time scales for vibrational relaxation can be very fast. Therefore, implicit time 10 | integration could be preferred in some conditions. The directory "other_files" contains 11 | both an explicit and a point-implicit integration scheme. The point-implicit scheme 12 | is only done on the vibrational energy equation, since the source term for the other 13 | equations is zero. 14 | 15 | A Cartesian grid is used, and a flat plate is introduced inside the domain. 16 | All input data is specified inside the global_module.f03 file. You can modify it there, then 17 | compile and run the code. 18 | 19 | ================================== 20 | = COMPILING AND RUNNING THE CODE = 21 | ================================== 22 | 23 | For compiling the code, go into the src directory and type "make". 24 | This will create the 'hyper2d.exe' executable file. 25 | Copy it to the desired location and run it with: 26 | 27 | $ ./hyper2d.exe 28 | 29 | ***** 30 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 31 | ***** DIRECTORY. YOU NEED TO CREATE IT! 32 | ***** 33 | 34 | ========================= 35 | = STRUCTURE OF THE CODE = 36 | ========================= 37 | 38 | The hyper2d.f03 contains the main program. 39 | The global settings are implemented in the global_module.f03 file. 40 | The PDEs are implemented in the pde.f03 file. 41 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 42 | The routine for exporting to VTK is in tools.f03. 43 | 44 | The program goes like this: 45 | 1) The solution is initialized (calling pde.f03) 46 | 2) Boundary conditions are applied (calling pde.f03) 47 | 3) Time integration starts (calling integration.f03) 48 | 3.1) Numerical fluxes are computed 49 | 3.2) The solution is updated in time 50 | 4) The solution is exported (calling tools.f03) 51 | 52 | 53 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_hypersonic/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_hypersonic/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | implicit none 4 | 5 | ! Time integration 6 | 7 | real(kind=8), parameter :: t_end = 1.0d-1 ! [s] total simulated time (from 0 to t_end) 8 | real(kind=8), parameter :: CFL_target = 0.25 9 | 10 | ! Specify domain and discretization. This version includes a flat plate in the domain, 11 | ! therefore the domain must contain it. 12 | 13 | real(kind=8), parameter :: x_min = -1.75 ! [m] needs to be NEGATIVE 14 | real(kind=8), parameter :: x_max = 2.75 ! [m] needs to be LARGER THAN PLATE LENGTH L_plate 15 | real(kind=8), parameter :: y_min = -0.7 ! [m] needs to be NEGATIVE 16 | real(kind=8), parameter :: y_max = 2.1 ! [m] needs to be POSITIVE 17 | 18 | ! Total number of cells (including 2 ghost cells for each side) 19 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 20 | 21 | integer, parameter :: Nx = 100 22 | integer, parameter :: Ny = 100 23 | 24 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) 25 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) 26 | 27 | ! Flat plate inside the domain. 28 | ! The plate is placed with the leading edge at (x,y) = (0,0). 29 | ! Make sure the domain is chosen correspondingly. 30 | 31 | real(kind=8), parameter :: L_plate = 1 ! [m] length of the flat plate 32 | 33 | integer, parameter :: j_plate = floor(Ny/(y_max - y_min)*(0 - y_min)) ! find j-index of plate 34 | integer, parameter :: i_1_plate = floor(Nx/(x_max - x_min)*(0 - x_min)) ! starting coordinate of plate 35 | integer, parameter :: i_2_plate = floor(Nx/(x_max - x_min)*(L_plate - x_min)) ! starting coordinate of plate 36 | 37 | ! Free stream 38 | 39 | real(kind=8), parameter :: rho0 = 1.225d0 ! [kg/m3] 40 | real(kind=8), parameter :: ux0 = 0.0 ! [m/s] 41 | real(kind=8), parameter :: uy0 = 2867.2 ! [m/s] 42 | real(kind=8), parameter :: T0 = 300.0 ! [K] 43 | 44 | ! Utilities 45 | real(kind=8) :: ws_maxabs 46 | 47 | end module 48 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_hypersonic/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | real(kind=8) :: dt, t_now, CFL_now 34 | 35 | write(*,*) "Initializing solution..." 36 | call initialize_solution(U) ! See the pde.f03 module 37 | 38 | write(*,*) "Assigning BCs..." 39 | call assign_BCs(U) ! See the pde.f03 module 40 | 41 | write(*,*) "Writing solution at time step", 0, "..." 42 | call export_sol_vtk(0, U) 43 | 44 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 45 | 46 | ! Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 47 | ! do t_ID = 1, Nt 48 | 49 | t_now = 0.0d0 ! Init 50 | dt = 1.0d-10 ! Very first time step 51 | t_ID = 0.0 ! Init 52 | 53 | do while( t_now .le. t_end) 54 | 55 | ! ------ Prepare variables ------ 56 | t_ID = t_ID + 1 57 | t_now = t_now + dt 58 | ws_maxabs = 0.0 ! Global variable, init to zero 59 | 60 | ! ------ Integrate by dt ------ 61 | call forward_Euler_step(U, dt) 62 | 63 | ! ----- Write solution to VTK, every ... time steps ----- 64 | if ( mod(t_ID, 100) .EQ. 0 ) then 65 | write(*,*) "Writing solution at time step", t_ID, "..." 66 | call export_sol_vtk(t_ID, U) 67 | end if 68 | 69 | ! ------ Estimate current Courant number and update time step ----- 70 | CFL_now = ws_maxabs*dt/MIN(dx,dy) 71 | write(*,'(A,EN15.5,A,F10.5,A,ES14.7,A)') 'Time', t_now, ' [s]. Current CFL: ', CFL_now, '. dt = ', dt, '[s]' 72 | dt = dt*CFL_target/CFL_now 73 | 74 | end do 75 | 76 | end program 77 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_hypersonic/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! --------------------------------------------------------------------------------------- 29 | 30 | integer, intent(in) :: t_ID 31 | real(kind=8), dimension(:,:,:), intent(in) :: U 32 | 33 | real(kind=8), dimension(Neq,Nx,Ny) :: prim ! Primitive variables 34 | 35 | integer :: Nx_int, Ny_int 36 | integer :: ID_EQ, i, j 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! Number of internal cells 41 | Nx_int = Nx - 4 42 | Ny_int = Ny - 4 43 | 44 | ! ----- Compute primitive variables on the grid ------ 45 | 46 | prim = 0.0 ! Init 47 | do i = 1, Nx 48 | do j = 1, Ny 49 | call compute_primitive_from_conserved(U(:,i,j), prim(:,i,j)) 50 | end do 51 | end do 52 | 53 | ! ------- Write VTK file ------- 54 | 55 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 56 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 57 | open(11189, file=file_name, status="replace", form="formatted") 58 | 59 | ! The VTK file starts with this header 60 | write(11189, '(A)') "# vtk DataFile Version 2.0" 61 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 62 | write(11189, '(A)') "ASCII" 63 | 64 | ! Write the information about the grid: number of points etc etc 65 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 66 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 67 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx, dy, 0.0 68 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", x_min+dx/2.0, y_min+dy/2.0, 0.0 69 | 70 | ! Now write the fields as "point data", each point is a cell center. 71 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 72 | 73 | do ID_EQ = 1, Neq ! Loop over the equations 74 | 75 | ! The array "prim_names" is defined in the "pde" module 76 | write(11189, '(A,A,A)') "SCALARS ", prim_names(ID_EQ), " float 1" 77 | write(11189, '(A)') "LOOKUP_TABLE default" 78 | 79 | ! Print value (only internal cells, not ghost cells) 80 | do j = 3, Ny-2 81 | do i = 3, Nx-2 82 | write(11189, '(EN17.5E3,A)', advance="no") prim(ID_EQ,i,j), " " ! WRITE SOL HERE 83 | end do 84 | end do 85 | 86 | write(11189,*) " " 87 | 88 | end do 89 | 90 | write(11189,*) " " 91 | 92 | ! write(11189,'(A)') "METADATA" 93 | ! write(11189,'(A)') "INFORMATION 0" 94 | 95 | close(11189) 96 | 97 | end subroutine 98 | 99 | end module 100 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_kinetic folder contains a simple implementation of the Hyper2D finite volume solver 6 | for the Boltzmann/Vlasov equation in the 1D1V phase space (one-dimensional in physical space and 7 | one-dimensional in the velocity as well). 8 | Label "x" denotes the space axis, while the label "y" is used in this version to denote the 9 | velocity axis, to keep the notation consistent with the other versions of hyper2D. 10 | 11 | All input data is specified inside the global_module.f03 file. You can modify it there, then 12 | compile and run the code. 13 | 14 | Notice that the VTK output of the solution is nondimensionalized. That is, variables x and y 15 | in the VTK file are divided by the interval length that you specify in the global_module.f03 16 | file. This is because the velocity and physical space axes are very different in dimension, 17 | and plotting them in VTK requires some scaling. You just need to re-multiply the x and y 18 | axes by the physical domain length and velocity if you want dimensional axes. 19 | 20 | ================================== 21 | = COMPILING AND RUNNING THE CODE = 22 | ================================== 23 | 24 | For compiling the code, go into the src directory and type "make". 25 | This will create the 'hyper2d.exe' executable file. 26 | Copy it to the desired location and run it with: 27 | 28 | $ ./hyper2d.exe 29 | 30 | ***** 31 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 32 | ***** DIRECTORY. YOU NEED TO CREATE IT! 33 | ***** 34 | 35 | ========================= 36 | = STRUCTURE OF THE CODE = 37 | ========================= 38 | 39 | The hyper2d.f03 contains the main program. 40 | The global settings are implemented in the global_module.f03 file. 41 | The PDEs are implemented in the pde.f03 file. 42 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 43 | The routine for exporting to VTK is in tools.f03. 44 | 45 | The program goes like this: 46 | 1) The solution is initialized (calling pde.f03) 47 | 2) Boundary conditions are applied (calling pde.f03) 48 | 3) Time integration starts (calling integration.f03) 49 | 3.1) Numerical fluxes are computed 50 | 3.2) The solution is updated in time 51 | 4) The solution is exported (calling tools.f03) 52 | 53 | 54 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_kinetic folder contains a simple implementation of the Hyper2D finite volume solver 6 | for the Boltzmann/Vlasov equation in the 1D1V phase space (one-dimensional in physical space and 7 | one-dimensional in the velocity as well). 8 | Label "x" denotes the space axis, while the label "y" is used in this version to denote the 9 | velocity axis, to keep the notation consistent with the other versions of hyper2D. 10 | 11 | All input data is specified inside the global_module.f03 file. You can modify it there, then 12 | compile and run the code. 13 | 14 | Notice that the VTK output of the solution is nondimensionalized. That is, variables x and y 15 | in the VTK file are divided by the interval length that you specify in the global_module.f03 16 | file. This is because the velocity and physical space axes are very different in dimension, 17 | and plotting them in VTK requires some scaling. You just need to re-multiply the x and y 18 | axes by the physical domain length and velocity if you want dimensional axes. 19 | 20 | ================================== 21 | = COMPILING AND RUNNING THE CODE = 22 | ================================== 23 | 24 | For compiling the code, go into the src directory and type "make". 25 | This will create the 'hyper2d.exe' executable file. 26 | Copy it to the desired location and run it with: 27 | 28 | $ ./hyper2d.exe 29 | 30 | ***** 31 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 32 | ***** DIRECTORY. YOU NEED TO CREATE IT! 33 | ***** 34 | 35 | ========================= 36 | = STRUCTURE OF THE CODE = 37 | ========================= 38 | 39 | The hyper2d.f03 contains the main program. 40 | The global settings are implemented in the global_module.f03 file. 41 | The PDEs are implemented in the pde.f03 file. 42 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 43 | The routine for exporting to VTK is in tools.f03. 44 | 45 | The program goes like this: 46 | 1) The solution is initialized (calling pde.f03) 47 | 2) Boundary conditions are applied (calling pde.f03) 48 | 3) Time integration starts (calling integration.f03) 49 | 3.1) Numerical fluxes are computed 50 | 3.2) The solution is updated in time 51 | 4) The solution is exported (calling tools.f03) 52 | 53 | 54 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | implicit none 4 | 5 | ! Time integration 6 | 7 | real(kind=8), parameter :: dt = 1.0d-4 ! [s] time step for the simulation 8 | real(kind=8), parameter :: t_end = 0.5d-0 ! [s] total simulated time (from 0 to t_end) 9 | 10 | real(kind=8), parameter :: c = 299792458.0 ! [m/s] speed of light in vacuum 11 | 12 | ! Specify domain and discretization 13 | 14 | real(kind=8), parameter :: x_min = -c/10.0 ! [m] 15 | real(kind=8), parameter :: x_max = c ! [m] 16 | real(kind=8), parameter :: y_min = -0.5*9.109d-31*c ! [kg*m/s] THIS IS A MOMENTUM 17 | real(kind=8), parameter :: y_max = 4.0*9.109d-31*c ! [kg*m/s] THIS IS A MOMENTUM 18 | 19 | ! Total number of cells (including 2 ghost cells for each side) 20 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 21 | 22 | integer, parameter :: Nx = 256 ! Physical space 23 | integer, parameter :: Ny = 256*4 ! Momentum space 24 | 25 | ! Periodicity and second order 26 | logical, parameter :: x_periodic_bool = .False. 27 | logical, parameter :: second_order_bool = .True. 28 | 29 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) ! discretization in physical space 30 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) ! discretization in velocity space 31 | 32 | ! ! Initial 1D1V maxwellian 33 | ! real(kind=8), parameter :: n0 = 1.0d16 ! [1/m3] number density 34 | ! real(kind=8), parameter :: u0 = 0.0d0 ! [m/s] average velocity 35 | ! real(kind=8), parameter :: T0 = 116045.0d0 ! [K] temperature 36 | 37 | end module 38 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | real(kind=8) :: t_now 34 | 35 | real(kind=8) :: dummy1, dummy2, dummy3 36 | 37 | write(*,*) "Initializing solution..." 38 | call initialize_solution(U) ! See the pde.f03 module 39 | 40 | write(*,*) "Assigning BCs..." 41 | call assign_BCs(U) ! See the pde.f03 module 42 | 43 | write(*,*) "Writing solution at time step", 0, "..." 44 | call export_sol_vtk(0, U) 45 | 46 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 47 | 48 | Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 49 | 50 | do t_ID = 1, Nt 51 | 52 | t_now = t_ID*dt 53 | write(*,*) 'Timestep', t_ID, 'of', Nt, ' - Current time:', t_now, '[s]' 54 | 55 | call forward_Euler_step(U, dt) 56 | ! call midpoint_Euler_step(U, dt) 57 | 58 | if ( mod(t_ID, 25) .EQ. 0 ) then ! Write to VTK every ... timesteps 59 | 60 | write(*,*) "Writing solution at time step", t_ID, "..." 61 | call export_sol_vtk(t_ID, U) 62 | 63 | end if 64 | 65 | end do 66 | 67 | end program 68 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/src/nohup.out: -------------------------------------------------------------------------------- 1 | Generic Warning: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 1436 2 | Error reading ascii data. Possible mismatch of datasize with declaration. 3 | 4 | ERROR: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 939 5 | vtkStructuredPointsReader (0x56452f132fa0): Unsupported point attribute type: 11.35139e+045 for file: /mydir/PhD/software/hyper2D/GITHUB_VERSION/hyper2D_kinetic/relativistic/src/dumps/sol_00000100.vtk 6 | 7 | Generic Warning: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 1436 8 | Error reading ascii data. Possible mismatch of datasize with declaration. 9 | 10 | ERROR: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 939 11 | vtkStructuredPointsReader (0x56452f132fa0): Unsupported point attribute type: 70.16348e+045 for file: /mydir/PhD/software/hyper2D/GITHUB_VERSION/hyper2D_kinetic/relativistic/src/dumps/sol_00000150.vtk 12 | 13 | Generic Warning: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 1436 14 | Error reading ascii data. Possible mismatch of datasize with declaration. 15 | 16 | ERROR: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 939 17 | vtkStructuredPointsReader (0x5608b606c6a0): Unsupported point attribute type: 364.20545e+036 for file: /mydir/PhD/software/hyper2D/GITHUB_VERSION/hyper2D_kinetic/relativistic/src/dumps/sol_00000050.vtk 18 | 19 | Generic Warning: In /build/paraview-OJ3Fdc/paraview-5.4.1+dfsg4/VTK/IO/Legacy/vtkDataReader.cxx, line 1436 20 | Error reading ascii data. Possible mismatch of datasize with declaration. 21 | 22 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/src/pde.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | ! This module contains the kinetic equation PDE, aka the Boltzmann equation, 4 | ! or whatever other equation (Vlasov / BGK / ...) according to the collision 5 | ! operator that we employ. 6 | ! Hyper2D is still two-dimensional, meaning that the kinetic equation will 7 | ! be 1D1V: 1D in space and 1V in the velocity. 8 | ! Dimension "x" refers to the space coordinate, while dimension "y" is a 9 | ! velocity "v". 10 | 11 | use global_module 12 | 13 | implicit none 14 | 15 | real(kind=8), parameter :: M = 9.109d-31 ! [kg] particle mass 16 | real(kind=8), parameter :: q = -1.602176d-19 ! [C] particle charge 17 | 18 | real(kind=8), parameter :: kB = 1.3806503d-23 ! [J/K] Boltzmann constant 19 | real(kind=8), parameter :: PI = 3.1415926535 20 | 21 | integer, parameter :: Neq = 1 ! Number of equations: (x, v, f) 22 | 23 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 24 | ! NOTE: To initialize it here, all entries need to have the same length!!! 25 | ! I'm using three letters for simplicity. 26 | character(len=20), dimension(Neq) :: prim_names = (/'f'/) 27 | 28 | contains 29 | 30 | ! ============================================================ 31 | 32 | subroutine initialize_solution(U) 33 | 34 | implicit none 35 | 36 | real(kind=8), dimension(:,:,:), intent(inout) :: U 37 | 38 | integer :: i, j 39 | real(kind=8) :: x, p, gam, v 40 | 41 | ! Initialize all cells with a single-velocity (1V) Maxwellian VDF 42 | ! do j = 1, Ny 43 | ! v = compute_v_from_j(j) 44 | ! do i = 1, Nx 45 | ! ! x = x_min + dx/2.0 + real(i-1)*dx 46 | ! U(1,i,j) = n0*sqrt(M/(2.0*PI*kB*T0))*exp(-M/(2.0*kB*T0)*(v - u0)*(v - u0)) 47 | ! end do 48 | ! end do 49 | 50 | ! Init with a box 51 | U(1,:,:) = 1.0d-10 52 | do j = 1, Ny ! floor(Ny/2.0 - Ny/20.0), floor(Ny/2.0 + Ny/20.0) 53 | 54 | p = compute_p_from_j(j) 55 | gam = sqrt(1 + p*p/M/c) 56 | v = p/gam/M 57 | 58 | do i = 1, Nx ! floor(Nx/2.0 - Nx/20.0), floor(Nx/2.0 + Nx/20.0) 59 | 60 | x = compute_x_from_i(i) 61 | 62 | if ((x .ge. 0.0) .and. (x.lt.c/10.0) .and. (v .ge. 0.0) .and. (v .le. c/2.5) ) then 63 | U(1,i,j) = 1.0 64 | end if 65 | end do 66 | end do 67 | 68 | end subroutine 69 | 70 | ! ============================================================ 71 | 72 | function compute_x_from_i(i) 73 | 74 | implicit none 75 | 76 | integer, intent(in) :: i 77 | real(kind=8) :: compute_x_from_i 78 | 79 | compute_x_from_i = x_min + dx/2.0 + real(i-1)*dx 80 | 81 | end function 82 | 83 | ! ============================================================ 84 | 85 | function compute_p_from_j(j) 86 | 87 | implicit none 88 | 89 | integer, intent(in) :: j 90 | real(kind=8) :: compute_p_from_j 91 | 92 | compute_p_from_j = y_min + dy/2.0 + real(j-1)*dy 93 | 94 | end function 95 | 96 | ! ============================================================ 97 | 98 | subroutine assign_BCs(U) 99 | 100 | implicit none 101 | 102 | real(kind=8), dimension(:,:,:), intent(inout) :: U 103 | 104 | integer :: i, j 105 | 106 | ! Periodic BCs 107 | if (X_PERIODIC_BOOL) then 108 | U(:,1,:) = U(:,Nx-3,:) 109 | U(:,2,:) = U(:,Nx-2,:) 110 | U(:,Nx-1,:) = U(:,3,:) 111 | U(:,Nx,:) = U(:,4,:) 112 | end if 113 | 114 | end subroutine 115 | 116 | ! ========================================================================= 117 | 118 | function F_field(x) 119 | 120 | implicit none 121 | 122 | real(kind=8), intent(in) :: x 123 | real(kind=8) :: F_field 124 | 125 | real(kind=8) :: k 126 | 127 | ! Cosinusoidal electric field profile 128 | F_field = 2.0d-21 ! [N] 129 | 130 | end function 131 | 132 | end module 133 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/relativistic/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! - The domain is scaled with the simulated domain size. The x and y axes will span 29 | ! the domain (-0.5, 0.5). This is because the physical space and velocity are usually 30 | ! very different, and we need scaling for the representation. 31 | ! --------------------------------------------------------------------------------------- 32 | 33 | integer, intent(in) :: t_ID 34 | real(kind=8), dimension(Neq,Nx,Ny), intent(in) :: U 35 | 36 | integer :: Nx_int, Ny_int 37 | integer :: i, j 38 | 39 | character(len=512) :: file_name ! Name of the output file 40 | 41 | real(kind=8) :: x_scale, y_scale ! for scaling the axes 42 | 43 | x_scale = 1.0/c 44 | y_scale = 1.0/(M*c) 45 | 46 | ! Number of internal cells 47 | Nx_int = Nx - 4 48 | Ny_int = Ny - 4 49 | 50 | ! ------- Write VTK file ------- 51 | 52 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 53 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 54 | open(11189, file=file_name, status="replace", form="formatted") 55 | 56 | ! The VTK file starts with this header 57 | write(11189, '(A)') "# vtk DataFile Version 2.0" 58 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 59 | write(11189, '(A)') "ASCII" 60 | 61 | ! Write the information about the grid: number of points etc etc 62 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 63 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 64 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx*x_scale, dy*y_scale, 0.0 65 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", (x_min+dx/2.0)*x_scale, (y_min+dy/2.0)*y_scale, 0.0 66 | 67 | ! Now write the fields as "point data", each point is a cell center. 68 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 69 | 70 | ! The array "prim_names" is defined in the "pde" module 71 | write(11189, '(A,A,A)') "SCALARS ", prim_names(1), " float 1" 72 | write(11189, '(A)') "LOOKUP_TABLE default" 73 | 74 | ! Print value (only internal cells, not ghost cells) 75 | do j = 3, Ny-2 76 | do i = 3, Nx-2 77 | write(11189, '(EN17.5E3,A)', advance="no") U(1,i,j), " " ! WRITE SOL HERE 78 | end do 79 | end do 80 | 81 | write(11189,*) " " 82 | write(11189,*) " " 83 | 84 | ! write(11189,'(A)') "METADATA" 85 | ! write(11189,'(A)') "INFORMATION 0" 86 | 87 | close(11189) 88 | 89 | end subroutine 90 | 91 | end module 92 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | tools.o: tools.f03 pde.o global_module.o 29 | $(CMPF) $(OPTS) tools.f03 30 | 31 | global_module.o: global_module.f03 32 | $(CMPF) $(OPTS) global_module.f03 33 | 34 | ########## Cleaning commands 35 | 36 | # Use "clean" to remove the objects and exectutable files 37 | clean: 38 | @echo cleaning objects, modules and executables 39 | rm -f *.o *.mod *.exe *~ 40 | 41 | # Use "cleanoutput" to remove the output files, located in the dumps directory 42 | cleanoutput: 43 | @echo cleaning output and dump files 44 | rm -f dumps/* 45 | 46 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | implicit none 4 | 5 | ! Time integration 6 | 7 | real(kind=8), parameter :: dt = 5.0d-10 ! [s] time step for the simulation 8 | real(kind=8), parameter :: t_end = 5.0d-6 ! [s] total simulated time (from 0 to t_end) 9 | 10 | ! Specify domain and discretization 11 | 12 | real(kind=8), parameter :: x_min = -0.0 ! [m] 13 | real(kind=8), parameter :: x_max = 0.01 ! [m] 14 | real(kind=8), parameter :: y_min = -25000.0 ! [m/s] THIS IS A VELOCITY IN THE KINETIC EQ! 15 | real(kind=8), parameter :: y_max = 25000.0 ! [m/s] THIS IS A VELOCITY IN THE KINETIC EQ! 16 | 17 | ! Total number of cells (including 2 ghost cells for each side) 18 | ! (using 2 ghost cells makes it easy to reach second order accuracy) 19 | 20 | integer, parameter :: Nx = 2*256 ! Physical space 21 | integer, parameter :: Ny = 2*256 ! Velocity space 22 | 23 | ! Periodicity and second order 24 | logical, parameter :: x_periodic_bool = .True. 25 | logical, parameter :: second_order_bool = .True. 26 | 27 | real(kind=8), parameter :: dx = (x_max-x_min)/(Nx-4) ! discretization in physical space 28 | real(kind=8), parameter :: dy = (y_max-y_min)/(Ny-4) ! discretization in velocity space 29 | 30 | ! Initial 1D1V maxwellian 31 | real(kind=8), parameter :: n0 = 1.0d16 ! [1/m3] number density 32 | real(kind=8), parameter :: u0 = 0.0d0 ! [m/s] average velocity 33 | real(kind=8), parameter :: T0 = 116045.0d0 ! [K] temperature 34 | 35 | end module 36 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use pde ! Definition of the system of equations 17 | use integration ! Functions for integrating in time and numerical fluxes 18 | use tools ! Output subroutines etc etc 19 | 20 | implicit none 21 | 22 | ! The solution is a 3D matrix. 23 | ! The first index "eqID" represents the equation 24 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 25 | ! the second index "i" represents the x-position 26 | ! the third index "j" represents the y-position. 27 | ! This might be counter-intuitive, but recall that Fortran represents data 28 | ! in column-major order. 29 | 30 | real(kind=8), dimension(Neq,Nx,Ny) :: U, P 31 | 32 | integer :: Nt, t_ID ! Variables for time integration 33 | real(kind=8) :: t_now 34 | 35 | real(kind=8) :: dummy1, dummy2, dummy3 36 | 37 | write(*,*) "Initializing solution..." 38 | call initialize_solution(U) ! See the pde.f03 module 39 | 40 | write(*,*) "Assigning BCs..." 41 | call assign_BCs(U) ! See the pde.f03 module 42 | 43 | write(*,*) "Writing solution at time step", 0, "..." 44 | call export_sol_vtk(0, U) 45 | 46 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 47 | 48 | Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 49 | 50 | do t_ID = 1, Nt 51 | 52 | t_now = t_ID*dt 53 | write(*,*) 'Timestep', t_ID, 'of', Nt, ' - Current time:', t_now, '[s]' 54 | 55 | ! call forward_Euler_step(U, dt) 56 | call midpoint_Euler_step(U, dt) 57 | 58 | if ( mod(t_ID, 50) .EQ. 0 ) then ! Write to VTK every ... timesteps 59 | 60 | write(*,*) "Writing solution at time step", t_ID, "..." 61 | call export_sol_vtk(t_ID, U) 62 | 63 | end if 64 | 65 | end do 66 | 67 | end program 68 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/src/pde.f03: -------------------------------------------------------------------------------- 1 | module pde 2 | 3 | ! This module contains the kinetic equation PDE, aka the Boltzmann equation, 4 | ! or whatever other equation (Vlasov / BGK / ...) according to the collision 5 | ! operator that we employ. 6 | ! Hyper2D is still two-dimensional, meaning that the kinetic equation will 7 | ! be 1D1V: 1D in space and 1V in the velocity. 8 | ! Dimension "x" refers to the space coordinate, while dimension "y" is a 9 | ! velocity "v". 10 | 11 | use global_module 12 | 13 | implicit none 14 | 15 | real(kind=8), parameter :: M = 6.6337d-26 ! [kg] particle mass 16 | real(kind=8), parameter :: q = 1.602176d-19 ! [C] particle charge 17 | 18 | real(kind=8), parameter :: kB = 1.3806503d-23 ! [J/K] Boltzmann constant 19 | real(kind=8), parameter :: PI = 3.1415926535 20 | 21 | integer, parameter :: Neq = 1 ! Number of equations: (x, v, f) 22 | 23 | ! Name of primitive variables, used ONLY for exporting the solution to VTK file 24 | ! NOTE: To initialize it here, all entries need to have the same length!!! 25 | ! I'm using three letters for simplicity. 26 | character(len=20), dimension(Neq) :: prim_names = (/'f'/) 27 | 28 | contains 29 | 30 | ! ============================================================ 31 | 32 | subroutine initialize_solution(U) 33 | 34 | implicit none 35 | 36 | real(kind=8), dimension(:,:,:), intent(inout) :: U 37 | 38 | integer :: i, j 39 | real(kind=8) :: x, v 40 | 41 | ! Initialize all cells with a single-velocity (1V) Maxwellian VDF 42 | do j = 1, Ny 43 | 44 | v = compute_v_from_j(j) 45 | 46 | do i = 1, Nx 47 | 48 | ! x = x_min + dx/2.0 + real(i-1)*dx 49 | 50 | U(1,i,j) = n0*sqrt(M/(2.0*PI*kB*T0))*exp(-M/(2.0*kB*T0)*(v - u0)*(v - u0)) 51 | 52 | end do 53 | 54 | end do 55 | 56 | end subroutine 57 | 58 | ! ============================================================ 59 | 60 | function compute_x_from_i(i) 61 | 62 | implicit none 63 | 64 | integer, intent(in) :: i 65 | real(kind=8) :: compute_x_from_i 66 | 67 | compute_x_from_i = x_min + dx/2.0 + real(i-1)*dx 68 | 69 | end function 70 | 71 | ! ============================================================ 72 | 73 | function compute_v_from_j(j) 74 | 75 | implicit none 76 | 77 | integer, intent(in) :: j 78 | real(kind=8) :: compute_v_from_j 79 | 80 | compute_v_from_j = y_min + dy/2.0 + real(j-1)*dy 81 | 82 | end function 83 | 84 | ! ============================================================ 85 | 86 | subroutine assign_BCs(U) 87 | 88 | implicit none 89 | 90 | real(kind=8), dimension(:,:,:), intent(inout) :: U 91 | 92 | integer :: i, j 93 | 94 | ! Periodic BCs 95 | if (X_PERIODIC_BOOL) then 96 | U(:,1,:) = U(:,Nx-3,:) 97 | U(:,2,:) = U(:,Nx-2,:) 98 | U(:,Nx-1,:) = U(:,3,:) 99 | U(:,Nx,:) = U(:,4,:) 100 | end if 101 | 102 | end subroutine 103 | 104 | ! ========================================================================= 105 | 106 | function E_field(x) 107 | 108 | implicit none 109 | 110 | real(kind=8), intent(in) :: x 111 | real(kind=8) :: E_field 112 | 113 | real(kind=8) :: k 114 | 115 | ! Cosinusoidal electric field profile 116 | k = 2.0*PI*4.0/(x_max-x_min) 117 | E_field = 10.0*k*cos(k*x) 118 | 119 | end function 120 | 121 | !! ! ========================================================================== 122 | !! 123 | !! subroutine compute_moments(U, i, n, u_ave, T) 124 | !! 125 | !! implicit none 126 | !! 127 | !! real(kind=8), dimension(Neq,Nx,Ny), intent(in) :: U 128 | !! integer, intent(in) :: i 129 | !! real(kind=8), intent(out) :: n, u_ave, T 130 | !! 131 | !! integer :: j 132 | !! 133 | !! real(kind=8) :: n_u, rhoE, v 134 | !! 135 | !! ! For every position along x, integrate in velocity 136 | !! n = 0.0 137 | !! n_u = 0.0 138 | !! u_ave = 0.0 139 | !! T = 0.0 140 | !! rhoE = 0.0 141 | !! 142 | !! do j = 1, Ny 143 | !! 144 | !! v = compute_v_from_j(j) 145 | !! 146 | !! n = n + U(1,i,j)*dy 147 | !! n_u = n_u + v*U(1,i,j)*dy 148 | !! rhoE = rhoE + M*v*v/2.0*U(1,i,j)*dy 149 | !! 150 | !! end do 151 | !! 152 | !! u_ave = n_u/n ! Average velocity 153 | !! T = (rhoE - n*M*u_ave*u_ave/2.0)*2.0/(n*kB) 154 | !! 155 | !! end subroutine 156 | 157 | end module 158 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_kinetic/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use pde 5 | 6 | implicit none 7 | 8 | contains 9 | 10 | ! #################################################################### 11 | 12 | subroutine export_sol_vtk(t_ID, U) 13 | 14 | ! --------------------------------------------------------------------------------------- 15 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 16 | ! ParaView. 17 | ! This helps for checking that all is good. 18 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 19 | ! time ID "t_ID" given as an input to the subroutine. 20 | ! U: conserved variables 21 | ! 22 | ! Notes: 23 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 24 | ! This helps for debugging. 25 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 26 | ! using the option "Surface with Edges": this is misleading, and these edges do not 27 | ! represent the cells boundaries. Instead, each point is a cell center. 28 | ! - The domain is scaled with the simulated domain size. The x and y axes will span 29 | ! the domain (-0.5, 0.5). This is because the physical space and velocity are usually 30 | ! very different, and we need scaling for the representation. 31 | ! --------------------------------------------------------------------------------------- 32 | 33 | integer, intent(in) :: t_ID 34 | real(kind=8), dimension(Neq,Nx,Ny), intent(in) :: U 35 | 36 | integer :: Nx_int, Ny_int 37 | integer :: i, j 38 | 39 | character(len=512) :: file_name ! Name of the output file 40 | 41 | real(kind=8) :: x_scale, y_scale ! for scaling the axes 42 | 43 | x_scale = 1.0/(x_max - x_min) 44 | y_scale = 1.0/(y_max - y_min) 45 | 46 | ! Number of internal cells 47 | Nx_int = Nx - 4 48 | Ny_int = Ny - 4 49 | 50 | ! ------- Write VTK file ------- 51 | 52 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 53 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 54 | open(11189, file=file_name, status="replace", form="formatted") 55 | 56 | ! The VTK file starts with this header 57 | write(11189, '(A)') "# vtk DataFile Version 2.0" 58 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 59 | write(11189, '(A)') "ASCII" 60 | 61 | ! Write the information about the grid: number of points etc etc 62 | write(11189, '(A)') "DATASET STRUCTURED_POINTS" 63 | write(11189, '(A,I8,I8,I8)') "DIMENSIONS ", Nx_int, Ny_int, 1 ! Write only internal cells 64 | write(11189, '(A,F14.7,F14.7,F14.7)') "SPACING ", dx*x_scale, dy*y_scale, 0.0 65 | write(11189, '(A,F14.7,F14.7,F14.7)') "ORIGIN ", (x_min+dx/2.0)*x_scale, (y_min+dy/2.0)*y_scale, 0.0 66 | 67 | ! Now write the fields as "point data", each point is a cell center. 68 | write(11189, '(A,I10)') "POINT_DATA ", Nx_int*Ny_int 69 | 70 | ! The array "prim_names" is defined in the "pde" module 71 | write(11189, '(A,A,A)') "SCALARS ", prim_names(1), " float 1" 72 | write(11189, '(A)') "LOOKUP_TABLE default" 73 | 74 | ! Print value (only internal cells, not ghost cells) 75 | do j = 3, Ny-2 76 | do i = 3, Nx-2 77 | write(11189, '(EN17.5E3,A)', advance="no") U(1,i,j), " " ! WRITE SOL HERE 78 | end do 79 | end do 80 | 81 | write(11189,*) " " 82 | write(11189,*) " " 83 | 84 | ! write(11189,'(A)') "METADATA" 85 | ! write(11189,'(A)') "INFORMATION 0" 86 | 87 | close(11189) 88 | 89 | end subroutine 90 | 91 | end module 92 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Stefano Boccelli 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/README: -------------------------------------------------------------------------------- 1 | ========== 2 | = README = 3 | ========== 4 | 5 | The hyper2D_unstructured directory contains a Hyper2D implementation that supports 6 | unstructured quad grids. 7 | 8 | ================================== 9 | = COMPILING AND RUNNING THE CODE = 10 | ================================== 11 | 12 | For compiling the code, go into the src directory and type "make". 13 | This will create the 'hyper2d.exe' executable file. 14 | Copy it to the desired location and run it with: 15 | 16 | $ ./hyper2d.exe 17 | 18 | ***** 19 | ***** NOTE THAT hyper2d WILL ATTEMPT TO WRITE THE OUTPUT INSIDE A LOCAL "dumps" 20 | ***** DIRECTORY. YOU NEED TO CREATE IT! 21 | ***** 22 | 23 | ======== 24 | = GRID = 25 | ======== 26 | 27 | The grid can be created for instance with GMSH and needs to be exported in SU2 format. 28 | Such exported grid then needs to be processed before being digestible by hyper2D. This 29 | can be done with the Octave/MATLAB script "process_su2_quad_grid.m" 30 | 31 | When the grid is created, you need to assign a numeric value to the boundary interfaces. 32 | These need to be: 33 | 34 | BC_inlet_ID = -1; 35 | BC_outlet_ID = -2; 36 | BC_wall_ID = -3; 37 | BC_sym_ID = -4; 38 | 39 | These values are set in the "process_su2_quad_grid.m" script. You can modify the values 40 | directly inside the script. NOTICE THAT THESE VALUES ARE NEGATIVE! This is so that 41 | Hyper2D can immediately recognize a boundary ID from an element ID, while running. 42 | The grid filename is also specified in the "process_su2_quad_grid.m" script. 43 | The script will create two files that are digestible by Hyper2D: a nodes.hyp and a mesh.hyp 44 | files. 45 | 46 | The nodes.hyp file contains the number of nodes on the first line, and then 47 | the (x,y) position of each node. 48 | 49 | The mesh.hyp file contains on the first non-commented line the total number of elements, and 50 | the other lines contain, for each element, the remaining info that is needed for doing the computations. 51 | This info is: 52 | # ele_ID, A, xC, yC, L12, n12(1), n12(2), neigh_12, L23, n23(1), n23(2), neigh_23, L34, n34(1), n34(2), neigh_34, L41, n41(1), n41(2), neigh_41) 53 | 54 | ele_ID: ID of the quad element (progressively increasing from 1 to Nele). Numbering starts from 1, in Fortran-style. 55 | A: Area of the element; 56 | xC, yC: Position of the element centroid; 57 | 58 | Interfaces are labeled as "12", "23", "34", "41" (meaning <> etc etc). 59 | L12: Length of the interface "12" 60 | n12(1): x-component of the normal vector for the interface "12" 61 | n12(2): y-component of the normal vector for the interface "12" 62 | neigh_12: ID of the quad element that neighbors the interface "12" (if the interface is a boundary 63 | interface, then this will be a negative value, among "BC_inlet_ID", "BC_outlet_ID" etc etc) 64 | 65 | L23: .... 66 | n23(1): ... 67 | etc etc with the other interfaces. 68 | 69 | TODO: THE OCTAVE SCRIPT TAKES A WHILE TO RUN! MAKE IT MORE EFFICIENT OR REPLACE IT WITH A FORTRAN CODE 70 | 71 | Note that you need to copy these files in the same directory as the executable. 72 | 73 | ========================== 74 | = Specifying BCs and ICs = 75 | ========================== 76 | 77 | As for the simpler versions of Hyper2D, the BCs are specified into the pde.f03 file, in the 78 | "initialize_solution()" subroutine. 79 | The Initial Conditions (ICs) are specified in the global_module.f03 file. 80 | 81 | Some different PDE systems are available in the "src/various_PDEs" directory. 82 | 83 | ========================= 84 | = STRUCTURE OF THE CODE = 85 | ========================= 86 | 87 | The hyper2d.f03 contains the main program. 88 | The global settings are implemented in the global_module.f03 file. 89 | The PDEs are implemented in the pde.f03 file. 90 | The time integrator and the computation of numerical fluxes are inside integrator.f03. 91 | The routine for exporting to VTK is in tools.f03. 92 | 93 | The program goes like this: 94 | 1) The solution is initialized (calling pde.f03) 95 | 2) Boundary conditions are applied (calling pde.f03) 96 | 3) Time integration starts (calling integration.f03) 97 | 3.1) Numerical fluxes are computed 98 | 3.2) The solution is updated in time 99 | 4) The solution is exported (calling tools.f03) 100 | 101 | 102 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # MAKEFILE # 3 | ############################################################ 4 | 5 | CMPF = gfortran -c 6 | LNK = gfortran 7 | 8 | OPTS = -O3 9 | 10 | OBJS = global_module.o tools.o grid.o pde.o integration.o 11 | 12 | ######### Executable generation by the linker 13 | 14 | hyper2D.exe: hyper2D.o $(OBJS) 15 | $(LNK) $(OPTS) hyper2D.o $(OBJS) -o hyper2D.exe 16 | 17 | ######### Objects generation 18 | 19 | hyper2D.o: hyper2D.f03 $(OBJS) 20 | $(CMPF) $(OPTS) hyper2D.f03 21 | 22 | integration.o: integration.f03 grid.o global_module.o pde.o 23 | $(CMPF) $(OPTS) integration.f03 24 | 25 | pde.o: pde.f03 grid.o global_module.o 26 | $(CMPF) $(OPTS) pde.f03 27 | 28 | grid.o: grid.f03 29 | $(CMPF) $(OPTS) grid.f03 30 | 31 | tools.o: tools.f03 grid.o pde.o global_module.o 32 | $(CMPF) $(OPTS) tools.f03 33 | 34 | global_module.o: global_module.f03 35 | $(CMPF) $(OPTS) global_module.f03 36 | 37 | ########## Cleaning commands 38 | 39 | # Use "clean" to remove the objects and exectutable files 40 | clean: 41 | @echo cleaning objects, modules and executables 42 | rm -f *.o *.mod *.exe *~ 43 | 44 | # Use "cleanoutput" to remove the output files, located in the dumps directory 45 | cleanoutput: 46 | @echo cleaning output and dump files 47 | rm -f dumps/* 48 | 49 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/src/global_module.f03: -------------------------------------------------------------------------------- 1 | module global_module 2 | 3 | implicit none 4 | 5 | ! Time integration 6 | 7 | real(kind=8), parameter :: t_end = 1.0d-0 ! [s] total simulated time (from 0 to t_end) 8 | real(kind=8), parameter :: CFL_target = 0.25 9 | 10 | !!!! TEST TEST TEST !!! ! Reconstruction order 11 | !!!! TEST TEST TEST !!! ! integer, parameter :: reconstr_order = 0 ! 0: no reconstruction -> first order in space 12 | !!!! TEST TEST TEST !!! integer, parameter :: reconstr_order = 1 ! 1: linear reconstruction -> second order in space 13 | 14 | ! Free stream 15 | 16 | real(kind=8), parameter :: rho0 = 1.225 ! [kg/m3] 17 | real(kind=8), parameter :: ux0 = 2000.0 ! [m/s] 18 | real(kind=8), parameter :: uy0 = 0.0 ! [m/s] 19 | real(kind=8), parameter :: T0 = 300.0 ! [K] 20 | 21 | ! Utilities 22 | real(kind=8) :: ws_over_sqrtA_maxabs 23 | 24 | end module 25 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/src/hyper2D.f03: -------------------------------------------------------------------------------- 1 | ! ###################################################################### 2 | ! ###################################################################### 3 | ! ########### _ ____ ____ ########## 4 | ! ########### | |__ _ _ _ __ ___ _ __(___ \| _ \ ########## 5 | ! ########### | '_ \| | | | '_ \ / _ \ '__| __) | | | | ########## 6 | ! ########### | | | | |_| | |_) | __/ | / __/| |_| | ########## 7 | ! ########### |_| |_|\__, | .__/ \___|_| /_____|____/ ########## 8 | ! ########### |___/|_| ########## 9 | ! ########### ########## 10 | ! ###################################################################### 11 | ! ###################################################################### 12 | 13 | program hyper2D 14 | 15 | use global_module ! Simulation parameters: domain size, number of cells etc 16 | use grid ! Loads and stores the grid 17 | use pde ! Definition of the system of equations 18 | use integration ! Functions for integrating in time and numerical fluxes 19 | use tools ! Output subroutines etc etc 20 | 21 | implicit none 22 | 23 | ! The solution is a 3D matrix. 24 | ! The first index "eqID" represents the equation 25 | ! (for Euler 1: density, 2: x-momentum, 3: y-momentum, 4: total energy) 26 | ! the second index "i" represents the x-position 27 | ! the third index "j" represents the y-position. 28 | ! This might be counter-intuitive, but recall that Fortran represents data 29 | ! in column-major order. 30 | 31 | real(kind=8), dimension(:,:), allocatable :: U, U_new 32 | 33 | integer :: Nt, t_ID ! Variables for time integration 34 | real(kind=8) :: dt, t_now, CFL_now 35 | 36 | write(*,*) "Reading grid file..." 37 | call load_grid_from_file 38 | 39 | write(*,*) "Initializing solution..." 40 | allocate(U(Neq,Nele), U_new(Neq,Nele)) 41 | call initialize_solution(U) ! See the pde.f03 module 42 | 43 | write(*,*) "Writing solution at time step", 0, "..." 44 | call export_sol_vtk(0, U) 45 | 46 | ! $$$$$$$$$$$ Integrate in time $$$$$$$$$$$$$ 47 | 48 | ! Nt = ceiling(t_end/dt) ! t_end and dt are defined in global_module.f90 49 | ! do t_ID = 1, Nt 50 | 51 | t_now = 0.0d0 ! Init 52 | dt = 1.0d-10 ! Very first time step 53 | t_ID = 0.0 ! Init 54 | 55 | do while( t_now .le. t_end) 56 | 57 | ! ------ Prepare variables ------ 58 | t_ID = t_ID + 1 59 | t_now = t_now + dt 60 | 61 | ws_over_sqrtA_maxabs = 0.0 ! Global variable, init to zero 62 | 63 | ! ------ Integrate by dt ------ 64 | call forward_Euler_step(U, U_new, dt) 65 | 66 | ! ----- Write solution to VTK, every ... time steps ----- 67 | if ( mod(t_ID, 100) .EQ. 0 ) then 68 | write(*,*) "Writing solution at time step", t_ID, "..." 69 | call export_sol_vtk(t_ID, U) 70 | end if 71 | 72 | ! ------ Estimate current Courant number and update time step ----- 73 | CFL_now = ws_over_sqrtA_maxabs*dt 74 | write(*,'(A,EN15.5,A,F10.5,A,ES14.7,A)') 'Time', t_now, ' [s]. Current CFL: ', CFL_now, '. dt = ', dt, '[s]' 75 | dt = dt*CFL_target/CFL_now 76 | 77 | end do 78 | 79 | end program 80 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/src/integration.f03: -------------------------------------------------------------------------------- 1 | module integration 2 | 3 | use pde 4 | use grid 5 | use global_module 6 | 7 | implicit none 8 | 9 | contains 10 | 11 | ! ======================================================================== 12 | 13 | subroutine forward_Euler_step(U, U_new, dt) 14 | 15 | ! This function performs one step of the Forward Euler explicit time integrator 16 | 17 | implicit none 18 | 19 | real(kind=8), dimension(:,:), intent(inout) :: U, U_new 20 | 21 | real(kind=8), intent(in) :: dt 22 | integer :: eleID, eqID, intID 23 | 24 | real(kind=8), dimension(Neq) :: F_dot_n, U_sym 25 | real(kind=8) :: nx, ny, Lint, Aele 26 | integer :: neigh 27 | 28 | do eleID = 1, Nele 29 | 30 | Aele = ele_geom(eleID, 1) 31 | U_new(:,eleID) = U(:,eleID) ! Init 32 | 33 | do intID = 1, 4 ! Only quad element supported 34 | 35 | F_dot_n = 0.0 ! Init 36 | 37 | ! Extract data 38 | Lint = ele_int_len(eleID,intID) 39 | nx = ele_int_nx(eleID,intID) 40 | ny = ele_int_ny(eleID,intID) 41 | 42 | neigh = ele_neigh(eleID,intID) 43 | 44 | ! Check what neighbor is it 45 | if (neigh .gt. 0) then ! +++++++++ INTERNAL CELL 46 | 47 | call compute_fluxes_HLL(U(:,eleID), U(:,neigh), nx, ny, F_dot_n, Aele) 48 | 49 | else if (neigh .eq. -1) then ! ++++++++ INLET BOUNDARY +++++++++++++++++++ 50 | 51 | call compute_fluxes_HLL(U(:,eleID), U_inlet, nx, ny, F_dot_n, Aele) 52 | 53 | else if (neigh .eq. -2) then ! ++++++++ OUTLET BOUNDARY +++++++++++++++++++ 54 | 55 | call compute_fluxes_HLL(U(:,eleID), U_outlet, nx, ny, F_dot_n, Aele) 56 | 57 | else if (neigh .eq. -3) then ! ++++++++ WALL BOUNDARY ++++++++++++++++++++ 58 | 59 | call compute_wall_flux(U(:,eleID), nx, ny, F_dot_n, Aele) 60 | 61 | else if (neigh .eq. -4) then ! ++++++++ SYM BOUNDARY ++++++++++++++++++++ 62 | 63 | call compute_sym_state(U(:,eleID), nx, ny, U_sym) 64 | call compute_fluxes_HLL(U(:,eleID), U_sym, nx, ny, F_dot_n, Aele) 65 | 66 | else 67 | print*, "ERROR! UNKNOWN BOUNDARY TYPE ", neigh, " for element ", eleID, " Check the mesh or the pre-processing." 68 | print*, "ABORTING!" 69 | STOP 70 | end if 71 | 72 | ! Update solution 73 | U_new(:,eleID) = U_new(:,eleID) - dt*F_dot_n*Lint/Aele 74 | 75 | ! Check that the solution did not diverge 76 | do eqID = 1, Neq 77 | if (isnan(U_new(eqID,eleID))) then 78 | print*, 'Solution diverged, try with a smaller time step! Aborting.' 79 | print*, 'Solution that diverged: ', U_new(:,eleID) 80 | print*, 'in cell ID = ', eleID 81 | stop 82 | end if 83 | end do 84 | 85 | end do ! End loop on interfaces 86 | 87 | end do ! End loop on elements 88 | 89 | U = U_new ! Save results 90 | 91 | end subroutine 92 | 93 | ! ======================================================================== 94 | 95 | subroutine compute_fluxes_HLL(U_L, U_R, nx, ny, F_dot_n, A_ele) 96 | 97 | ! Computes HLL numerical fluxes among the cell eleID and the neighbor cell neigh 98 | ! The element area Aele is also passed, for the sake of computing the CFL number. 99 | 100 | implicit none 101 | 102 | real(kind=8), dimension(:), intent(in) :: U_L, U_R 103 | real(kind=8), intent(in) :: nx, ny, A_ele 104 | real(kind=8), dimension(Neq), intent(out) :: F_dot_n 105 | 106 | real(kind=8), dimension(Neq) :: F_L, F_R 107 | 108 | ! Wave speeds 109 | real(kind=8) :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_max, ws_min 110 | 111 | call compute_flux_ws(U_L, F_L, nx, ny, ws_max_L, ws_min_L) 112 | call compute_flux_ws(U_R, F_R, nx, ny, ws_max_R, ws_min_R) 113 | 114 | ws_min = MIN(ws_min_L, ws_min_R) 115 | ws_max = MAX(ws_max_L, ws_max_R) 116 | 117 | ! HLL fluxes 118 | if (ws_min .ge. 0.0) then 119 | F_dot_n = F_L 120 | else if (ws_max .lt. 0.0) then 121 | F_dot_n = F_R 122 | else 123 | F_dot_n = (ws_min*ws_max*(U_R - U_L) + ws_max*F_L - ws_min*F_R)/(ws_max - ws_min); 124 | end if 125 | 126 | ! Update global maximum wave speed (used for setting the time step) 127 | ws_max = abs(ws_max) 128 | ws_over_sqrtA_maxabs = MAX(ws_over_sqrtA_maxabs, ws_max/sqrt(A_ele)) 129 | 130 | end subroutine 131 | 132 | 133 | ! ======================================================================== 134 | 135 | subroutine compute_fluxes_Rusanov(U_L, U_R, nx, ny, F_dot_n, A_ele) 136 | 137 | ! Computes Rusanov numerical fluxes among the cell eleID and the neighbor cell neigh 138 | ! The element area A_ele is also passed, for the sake of computing the Courant number 139 | 140 | implicit none 141 | 142 | real(kind=8), dimension(:), intent(in) :: U_L, U_R 143 | real(kind=8), intent(in) :: nx, ny, A_ele 144 | real(kind=8), dimension(Neq), intent(out) :: F_dot_n 145 | 146 | real(kind=8), dimension(Neq) :: F_L, F_R 147 | 148 | ! Wave speeds 149 | real(kind=8) :: ws_min_L, ws_max_L, ws_min_R, ws_max_R, ws_max 150 | 151 | call compute_flux_ws(U_L, F_L, nx, ny, ws_max_L, ws_min_L) 152 | call compute_flux_ws(U_R, F_R, nx, ny, ws_max_R, ws_min_R) 153 | 154 | ws_max = MAX(ABS(ws_max_L), ABS(ws_min_L), ABS(ws_max_R), ABS(ws_min_R)) 155 | 156 | F_dot_n = 0.5*(F_R + F_L) - ws_max/2.0*(U_R-U_L) ! Rusanov flux 157 | 158 | ! Update global maximum wave speed (used for setting the time step) 159 | ws_over_sqrtA_maxabs = MAX(ws_over_sqrtA_maxabs, ws_max/sqrt(A_ele)) 160 | 161 | end subroutine 162 | 163 | end module 164 | -------------------------------------------------------------------------------- /hyper2D_single_core/hyper2D_unstructured/src/tools.f03: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | use global_module 4 | use grid 5 | use pde 6 | 7 | implicit none 8 | 9 | contains 10 | 11 | ! #################################################################### 12 | 13 | subroutine export_sol_vtk(t_ID, U) 14 | 15 | ! --------------------------------------------------------------------------------------- 16 | ! This subroutine exports data in the legacy VTK format, that can be visualized using 17 | ! ParaView. 18 | ! This helps for checking that all is good. 19 | ! The output file is put in the "dumps" directory and is named "sol_..." where ... is the 20 | ! time ID "t_ID" given as an input to the subroutine. 21 | ! U: conserved variables 22 | ! 23 | ! Notes: 24 | ! - All cells are printed, including the two layers of ghost cells for each boundary. 25 | ! This helps for debugging. 26 | ! - The data is exported for each cell center. In ParaView, you may visualize the data 27 | ! using the option "Surface with Edges": this is misleading, and these edges do not 28 | ! represent the cells boundaries. Instead, each point is a cell center. 29 | ! --------------------------------------------------------------------------------------- 30 | 31 | integer, intent(in) :: t_ID 32 | real(kind=8), dimension(:,:), intent(in) :: U 33 | 34 | real(kind=8), dimension(:,:), allocatable :: prim ! Primitive variables 35 | 36 | integer :: eqID, i 37 | 38 | character(len=512) :: file_name ! Name of the output file 39 | 40 | ! ----- Compute primitive variables on the grid ------ 41 | 42 | allocate(prim(Neq,Nele)) 43 | 44 | prim = 0.0 ! Init 45 | do i = 1, Nele 46 | call compute_primitive_from_conserved(U(:,i), prim(:,i)) 47 | end do 48 | 49 | ! ------- Write VTK file ------- 50 | 51 | ! Open file, and replace if existing. 11189 is just an arbitrary ID. 52 | write(file_name,'(A, I8.8, A)') './dumps/sol_', t_ID, '.vtk' 53 | open(11189, file=file_name, status="replace", form="formatted") 54 | 55 | ! The VTK file starts with this header 56 | write(11189, '(A)') "# vtk DataFile Version 2.0" 57 | write(11189, '(A30,I8)') "hyper2D solution at timestep ", t_ID 58 | write(11189, '(A)') "ASCII" 59 | 60 | ! Write the information about the grid: number of points etc etc 61 | write(11189, '(A)') "DATASET UNSTRUCTURED_GRID" 62 | write(11189, '(A)') " " 63 | write(11189, '(A,I8,A)') "POINTS ", Nnodes, " float" 64 | 65 | do i = 1,Nnodes 66 | write(11189, '(EN17.5E3,EN17.5E3,EN17.5E3)') nodes_xy(i,1), nodes_xy(i,2), 0.0 ! WRITE SOL HERE 67 | end do 68 | 69 | write(11189, '(A)') " " 70 | write(11189, '(A,I8,I8)') "CELLS ", Nele, Nele*5 ! For triangles, use Nele*4 71 | do i = 1,Nele 72 | ! Note: VTK is written in C++ and uses indices starting from zero 73 | write(11189, '(I8, I8, I8, I8, I8)') 4, ele_nodes(i,1)-1, ele_nodes(i,2)-1, & 74 | ele_nodes(i,3)-1, ele_nodes(i,4)-1 75 | end do 76 | 77 | write(11189, '(A)') " " 78 | write(11189, '(A,I8)') "CELL_TYPES ", Nele 79 | do i = 1,Nele 80 | write(11189, '(I8)') 9 81 | end do 82 | 83 | write(11189, '(A)') " " 84 | write(11189, '(A,I8)') "CELL_DATA ", Nele 85 | 86 | do eqID = 1, Neq 87 | write(11189, '(A,A,A)') "SCALARS ", prim_names(eqID), "float 1" 88 | write(11189, '(A)') "LOOKUP_TABLE default" 89 | 90 | do i = 1,Nele 91 | write(11189, '(EN17.5E3,A)', advance="no") prim(eqID,i), " " ! WRITE SOL HERE 92 | end do 93 | 94 | write(11189,*) " " 95 | 96 | end do 97 | 98 | ! ! write(11189,'(A)') "METADATA" 99 | ! ! write(11189,'(A)') "INFORMATION 0" 100 | 101 | close(11189) 102 | 103 | end subroutine 104 | 105 | end module 106 | --------------------------------------------------------------------------------