Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
gpu_dt.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2024 Finnish Meteorological Institute and University of Helsinki
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include <vector>
24#include "../definitions.h"
26#include "../object_wrapper.h"
27#include "../arch/gpu_base.hpp"
29//#include <stdint.h>
30#include <dccrg.hpp>
31#include <dccrg_cartesian_geometry.hpp>
32
33//using namespace std;
34using namespace spatial_cell;
35
36// Using a single kernel launch to reduce the allowed timestep for all cells instead of utilizing
37// ARCH-looping provides an order of 10x-40x performance improvement.
38
39/* Kernel for evalutaing all blocks in all velocity meshes
40 * finding the low and high corner velocities
41 * comparing with the spatial cell size
42 * and storing the largest allowed spatial dt for each cell
43 *
44 * @param dev_vmeshes buffer of pointers to velocitymeshes, used for gathering active blocks
45 * @param dev_max_dt Buffer to store max allowed dt into (siz of nAllCells)
46 * @param dev_dxdydz Buffer of cell spatial extents (size of 3*nAllCells)
47 * @param nAllCells count of cells to process
48 */
49__global__ void __launch_bounds__(GPUTHREADS*WARPSPERBLOCK) reduce_v_dt_kernel(
50 const vmesh::VelocityMesh* __restrict__ const *dev_vmeshes,
51 Real* dev_max_dt,
52 const Real* dev_dxdydz,
53 const uint nAllCells)
54{
55 const uint ti = threadIdx.x; // [0,GPUTHREADS*WARPSPERBLOCK)
56 const uint blockSize = blockDim.x;
57 const uint cellIndex = blockIdx.x; // userd for pointer to cell (or population)
58
59 __shared__ Real smallest[GPUTHREADS*WARPSPERBLOCK]; //==blockSize
60 smallest[ti] = numeric_limits<Real>::max();
61
62 const vmesh::VelocityMesh* __restrict__ thisVmesh = dev_vmeshes[cellIndex];
63 const uint thisVmeshSize = thisVmesh->size();
64 Real blockInfo[6];
65 const Real dx = dev_dxdydz[3*cellIndex + 0];
66 const Real dy = dev_dxdydz[3*cellIndex + 1];
67 const Real dz = dev_dxdydz[3*cellIndex + 2];
68 const Real EPS = numeric_limits<Real>::min() * 1000;
69 const Real HALF = 0.5;
70
71 for (uint blockIndex = ti/2; blockIndex < thisVmeshSize; blockIndex += blockSize/2) {
72 if (blockIndex < thisVmeshSize) {
73 const vmesh::GlobalID GID = thisVmesh->getGlobalID(blockIndex);
74 thisVmesh->getBlockInfo(GID,blockInfo); //This now calculates instead of reading from stored arrays
75 // Indices 0-2 contain coordinates of the lower left corner.
76 // Indices 3-5 contain the cell size.
77 const int i = (ti % 2) * (WID-1);
78 // low and high corners, i.e., i == 0, i == WID - 1
79 const Real Vx = blockInfo[0] + (i + HALF) * blockInfo[3] + EPS;
80 const Real Vy = blockInfo[1] + (i + HALF) * blockInfo[4] + EPS;
81 const Real Vz = blockInfo[2] + (i + HALF) * blockInfo[5] + EPS;
82 smallest[ti] = min({dx / fabs(Vx), dy / fabs(Vy), dz / fabs(Vz), smallest[ti]});
83 }
84 }
86 // Now reduce for cell
87 for (unsigned int s=blockSize/2; s>0; s>>=1) {
88 if (ti < s) {
89 smallest[ti] = min(smallest[ti],smallest[ti + s]);
90 }
92 }
93 // Kostis' suggestion: use two-stage warp votes to reduce
94 // for (int offset = GPUTHREADS/2; offset > 0; offset >>=1){
95 // val = min(val,__shfl_down_sync(FULL_MASK, val, offset));
96 // }
97 // __syncthreads();
98 if (ti==0) {
99 dev_max_dt[cellIndex] = smallest[0];
100 }
101}
102
103
104void reduce_vlasov_dt(dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
105 const vector<CellID>& cells,
106 Real (&dtMaxLocal)[3]) {
107
108 phiprof::Timer computeGpuTimestepTimer {"compute-vlasov-gpu-timestep"};
109 // Does not use streams
110 const uint nAllCells = cells.size();
111 const uint nPOP = getObjectWrapper().particleSpecies.size();
112
113 // Resize dev_vmeshes, one for each cell and each pop
114 gpu_trans_allocate(nAllCells*nPOP,0,0);
115
116 gpuMemoryManager.startSession(0,0);
117
118 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_max_dt, nAllCells*nPOP*sizeof(Real));
119 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_dxdydz, nAllCells*nPOP*3*sizeof(Real));
120 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_max_dt, nAllCells*nPOP*sizeof(Real));
121 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_dxdydz, nAllCells*nPOP*3*sizeof(Real));
122
123 Real* host_max_dt = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_max_dt);
124 Real* host_dxdydz = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_dxdydz);
125 Real* dev_max_dt = GET_SESSION_POINTER(gpuMemoryManager, Real, dev_max_dt);
126 Real* dev_dxdydz = GET_SESSION_POINTER(gpuMemoryManager, Real, dev_dxdydz);
127
128 // Gather vmeshes
129 #pragma omp parallel for schedule(static)
130 for(uint celli = 0; celli < nAllCells; celli++){
131 SpatialCell* cell = mpiGrid[cells[celli]];
132 cell->parameters[CellParams::MAXRDT] = numeric_limits<Real>::max();
133 //cell->parameters[CellParams::MAXRDT] = numeric_limits<Real>::max();
134 for (uint popID = 0; popID < nPOP; ++popID) {
135 host_dxdydz[3*celli*nPOP + 3*popID + 0] = cell->parameters[CellParams::DX];
136 host_dxdydz[3*celli*nPOP + 3*popID + 1] = cell->parameters[CellParams::DY];
137 host_dxdydz[3*celli*nPOP + 3*popID + 2] = cell->parameters[CellParams::DZ];
138 (GET_POINTER(gpuMemoryManager, vmesh::VelocityMesh*, host_vmeshes))[celli*nPOP + popID] = cell->dev_get_velocity_mesh(popID); // GPU-side vmesh
139 }
140 }
141 CHK_ERR( gpuMemcpy(dev_dxdydz, host_dxdydz, nAllCells*nPOP*3*sizeof(Real), gpuMemcpyHostToDevice) );
143
144 // Launch kernel gathering largest allowed dt for velocity
145 reduce_v_dt_kernel<<<nAllCells, GPUTHREADS*WARPSPERBLOCK, 0, 0>>> (
147 dev_max_dt,
148 dev_dxdydz,
149 nAllCells*nPOP
150 );
152 CHK_ERR( gpuMemcpy(host_max_dt, dev_max_dt, nAllCells*nPOP*sizeof(Real), gpuMemcpyDeviceToHost) );
153 // CHK_ERR( gpuStreamSynchronize(bgStream) );
154
155 #pragma omp parallel for schedule(static)
156 for(uint celli = 0; celli < nAllCells; celli++){
157 SpatialCell* cell = mpiGrid[cells[celli]];
158 for (uint popID = 0; popID < nPOP; ++popID) {
159 cell->set_max_r_dt(popID, host_max_dt[celli*nPOP + popID]);
161 }
162 }
163 computeGpuTimestepTimer.stop();
164
165 gpuMemoryManager.endSession();
166
167 // GPUTODO thread this?
168 phiprof::Timer computeRestTimestepTimer {"compute-vlasov-rest-timestep"};
169 for (vector<CellID>::const_iterator cell_id = cells.begin(); cell_id != cells.end(); ++cell_id) {
170 SpatialCell* cell = mpiGrid[*cell_id];
171
174 // spatial fluxes computed also for L1 boundary cells
175 dtMaxLocal[0] = min(dtMaxLocal[0], cell->parameters[CellParams::MAXRDT]);
176 }
177
178 if (cell->parameters[CellParams::MAXVDT] != 0 &&
181 // acceleration only done on non-boundary cells
182 dtMaxLocal[1] = min(dtMaxLocal[1], cell->parameters[CellParams::MAXVDT]);
183 }
184 }
185 computeRestTimestepTimer.stop();
186}
for i
Definition Dispersion.m:24
dx
Definition Dispersion.m:38
#define gpuPeekAtLastError
#define WARPSPERBLOCK
#define gpuMemcpyHostToDevice
#define CHK_ERR(err)
#define gpuMemcpy
#define gpuMemcpyDeviceToHost
#define GPUTHREADS
void set_max_r_dt(const uint popID, const Real &value)
const Real & get_max_r_dt(const uint popID) const
std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > parameters
vmesh::VelocityMesh * dev_get_velocity_mesh(const size_t &popID)
#define WID
Definition common.h:514
float Real
Definition definitions.h:41
static creal EPS
Definition fs_common.h:61
const Real HALF
Definition fs_common.h:49
const uint ti
GPUMemoryManager gpuMemoryManager
Definition gpu_base.cpp:64
__host__ void gpu_trans_allocate(cuint nAllCells, cuint largestVmesh, cuint unionSetSize)
Definition gpu_base.cpp:607
#define SESSION_HOST_ALLOCATE(object, type, member, bytes)
Definition gpu_base.hpp:600
#define SESSION_ALLOCATE(object, type, member, bytes)
Definition gpu_base.hpp:557
#define GET_SESSION_POINTER(object, type, member)
Definition gpu_base.hpp:833
#define GET_SESSION_HOST_POINTER(object, type, member)
Definition gpu_base.hpp:853
#define GET_POINTER(object, type, member)
Definition gpu_base.hpp:809
void reduce_vlasov_dt(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &cells, Real(&dtMaxLocal)[3])
Definition gpu_dt.cpp:104
const int blockSize
__syncthreads()
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
static __global__ void __launch_bounds__(WID3, 4) population_scale_kernel(vmesh
uint32_t GlobalID
Definition definitions.h:59
std::vector< species::Species > particleSpecies
static bool vlasovAccelerateMaxwellianBoundaries
Definition parameters.h:158
static ARCH_HOSTDEV VecSimple< T > min(VecSimple< T > const &l, VecSimple< T > const &r)