Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
gpu_pitch_angle_diffusion.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2025 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
24// This is the GPU version of cpu_pitch_angle_diffusion
25
26#include "../parameters.h"
27#include "../object_wrapper.h"
28#include <math.h>
29//#include <cmath> // NaN Inf checks
30#include <iostream>
31#include <fstream>
32#include <iomanip>
33#include <iterator>
34#include <Eigen/Geometry>
36#include "../arch/gpu_base.hpp"
38
39#define GPUCELLMUSPACE(var,cellIdx,v_ind,mu_ind) var[(cellIdx)*nbins_v*nbins_mu+(mu_ind)*nbins_v + (v_ind)]
40
41__global__ void __launch_bounds__(WID3) build2dArrayOfFvmu_kernel(
42 size_t *dev_cellIdxArray,
55 ){
56
57 int totalBlockIndex = blockIdx.x; // Corresponds to index spatial and velocity blocks
58
59 const int i = threadIdx.x;
60 const int j = threadIdx.y;
61 const int k = threadIdx.z;
62 size_t cellIdx = dev_cellIdxArray[totalBlockIndex];
63 size_t velocityIdx = dev_velocityIdxArray[totalBlockIndex];
64
65 const Real* __restrict__ blockParameters = dev_velocityBlockContainer[cellIdx]->getParameters(velocityIdx);
66
67 //Get velocity space coordinates
71
75
78 const Real mu = Vpara/(normV+std::numeric_limits<Real>::min()); // + min value to avoid division by 0.
79
80 const int Vindex = static_cast<int>(std::nearbyint(floor((normV) / dVbins)));
81 const Real Vmu = dVbins * (Vindex+0.5); // Take value at the center of the mu cell
82 int muindex = static_cast<int>(std::nearbyint(floor((mu+1.0) / dmubins)));
83
85 const Real increment = 2.0 * M_PI * Vmu*Vmu * cellValue;
86 // Safety check to handle edge case where mu = exactly 1.0
87 const int mui = std::max(0,std::min(muindex,nbins_mu-1));
88 const int vi = std::max(0,std::min(Vindex,nbins_v-1));
89
90 // TODO: can this be done without atomicAdd while avoiding race conditions?
93}
94
95__global__ void __launch_bounds__(WID3) computeNewCellValues_kernel(
96 size_t *dev_cellIdxArray,
106 Real dVbins,
107 const Real dmubins,
108 int nbins_v,
109 int nbins_mu
110 ){
111
112 int totalBlockIndex = blockIdx.x; // Corresponds to index spatial and velocity blocks
113
114 const int i = threadIdx.x;
115 const int j = threadIdx.y;
116 const int k = threadIdx.z;
117 size_t cellIdx = dev_cellIdxArray[totalBlockIndex];
118 size_t velocityIdx = dev_velocityIdxArray[totalBlockIndex];
119
120 const Real* __restrict__ blockParameters = dev_velocityBlockContainer[cellIdx]->getParameters(velocityIdx);
121
122 //Get velocity space coordinates
126
127 const Real VplasmaX = VX - dev_bulkVX[cellIdx];
128 const Real VplasmaY = VY - dev_bulkVY[cellIdx];
129 const Real VplasmaZ = VZ - dev_bulkVZ[cellIdx];
130
133 const Real mu = Vpara/(normV+std::numeric_limits<Real>::min()); // + min value to avoid division by 0.
134
135 const int Vindex = static_cast<int>(std::nearbyint(floor((normV) / dVbins)));
136 int muindex = static_cast<int>(std::nearbyint(floor((mu+1.0) / dmubins)));
137
138 Realf dfdt = 0.0;
139 // Safety check to handle edge case where mu = exactly 1.0
140 const int mui = std::max(0,std::min(muindex,nbins_mu-1));
141 const int vi = std::max(0,std::min(Vindex,nbins_v-1));
142 dfdt = GPUCELLMUSPACE(dev_dfdt_mu,cellIdx,vi,mui); // dfdt_mu was scaled back down by 2pi*v^2 on creation
143
144 // Update cell value, ensuring result is non-negative
146 const bool lessZero = (NewCellValue < 0.0);
149}
150
152 size_t *dev_smallCellIdxArray,
153 int *dev_fcount,
154 Realf *dev_fmu,
155 Real *dev_nu0Values,
157 int *dev_cellIdxKeys,
158 Real *dev_potentialDdtValues,
159 Realf *dev_sparsity,
160 Real dVbins,
161 const Real dmubins,
162 const Real epsilon,
163 Realf PADCFL,
164 int nbins_v,
165 int nbins_mu,
166 int blocksPerSpatialCell,
167 int lastBlockSize
168 ){
169
170 int spatialBlockIndex = blockIdx.x/blocksPerSpatialCell; // Corresponds to index spatial and velocity blocks
171 int indexInsideBlock = blockIdx.x%blocksPerSpatialCell;
172 int nextIndexInsideBlock = (blockIdx.x+1)%blocksPerSpatialCell;
173 int idx = indexInsideBlock*blockDim.x+threadIdx.x;
174 int threadIndex = threadIdx.x;
175 int indv = idx%nbins_v;
176 int indmu = (idx/nbins_v)%nbins_mu;
177 size_t cellIdx = dev_smallCellIdxArray[spatialBlockIndex];
178
179 // Initiate shared memory values
180 extern __shared__ Real localDdtValues[];
181 localDdtValues[threadIndex] = std::numeric_limits<Real>::max();
182
184
185 if(nextIndexInsideBlock != 0 || threadIndex < lastBlockSize){
186
187 // Search limits for how many cells in mu-direction should be max evaluated when searching for a near neighbour?
188 // Assuming some oversampling; changing these values may result in method breaking at very small plasma frame velocities.
189 const int rlimit = nbins_mu-1;
190 const int llimit = 0;
191
192 int cLeft = 0;
193 int cRight = 0;
194
195 // !!! DANGER, WARP DIVERGENCE AHEAD !!!
196 // TODO: Can this be avoided?
197
198 if (indmu != nbins_mu-1) {
199 for(cRight = 1; indmu + cRight < rlimit; cRight++){
200 if(GPUCELLMUSPACE(dev_fcount,cellIdx,indv,indmu + cRight) != 0){
201 break;
202 }
203 }
204 if( (GPUCELLMUSPACE(dev_fcount,cellIdx,indv,indmu + cRight) == 0) && (indmu + cRight == rlimit) ) {
205 cRight = 0;
206 }
207 }
208 if (indmu != 0) {
209 for(cLeft = 1; indmu - cLeft > llimit; cLeft++){
210 if(GPUCELLMUSPACE(dev_fcount,cellIdx,indv,indmu - cLeft) != 0){
211 break;
212 }
213 }
214 if( (GPUCELLMUSPACE(dev_fcount,cellIdx,indv,indmu - cLeft) == 0) && (indmu - cLeft == llimit) ) {
215 cLeft = 0;
216 }
217 }
218
220
221 const Real Vmu = dVbins * (float(indv)+0.5);
222 Realf dfdmu = 0.0;
223 Realf dfdmu2 = 0.0;
224 // Compute spatial derivatives
225 if( (cRight != 0) || (cLeft != 0)) {
227 /((cRight + cLeft)*dmubins) ;
228 }
229 if( (cRight != 0) && (cLeft != 0)) {
232 /(cLeft*dmubins) ) / (0.5 * dmubins * (cRight + cLeft));
233 }
234
235 // Compute time derivative
236 const Realf mu = (indmu+0.5)*dmubins - 1.0;
237 const Realf Dmumu = dev_nu0Values[cellIdx]/2.0 * ( abs(mu)/(1.0 + abs(mu)) + epsilon ) * (1.0 - mu*mu);
238 const Realf dDmu = dev_nu0Values[cellIdx]/2.0 * ( (mu/abs(mu)) * ((1.0 - mu*mu)/((1.0 + abs(mu))*(1.0 + abs(mu)))) - 2.0*mu*( abs(mu)/(1.0 + abs(mu)) + epsilon));
239 // We divide dfdt_mu by the normalization factor 2pi*v^2 already here.
240 const Realf dfdt_mu_val = ( dDmu * dfdmu + Dmumu * dfdmu2 ) / (2.0 * M_PI * Vmu*Vmu);
242
243 // Only consider CFL for non-negative phase-space cells above the sparsity threshold
244 const Realf CellValue = GPUCELLMUSPACE(dev_fmu,cellIdx,indv,indmu) / (2.0 * M_PI * Vmu*Vmu);
245 const Realf absdfdt = abs(dfdt_mu_val); // Already scaled
246
247 // Save calculated Ddt value
248 if (absdfdt > 0.0 && CellValue > dev_sparsity[cellIdx]) {
249 localDdtValues[threadIndex] = CellValue * PADCFL * (1.0/absdfdt);
250 }
251
252 // Reduction in shared memory
254 for (int s = blockDim.x / 2; s > GPUTHREADS/2; s >>= 1) {
255 if (threadIndex < s) {
256 localDdtValues[threadIndex] = min(localDdtValues[threadIndex], localDdtValues[threadIndex + s]);
257 }
259 }
260 }
261
262 // Warp reduction
263 if (threadIndex < GPUTHREADS) {
264 gpuWarpSync();
265
266 Real val = localDdtValues[threadIndex];
267 for (int offset = GPUTHREADS/2; offset > 0; offset /= 2) {
268 val = min(val, gpuKernelShflDown(val, offset));
269 }
270
271 // Write the result from the first thread of each block
272 if (threadIndex == 0) {
273 dev_potentialDdtValues[blockIdx.x] = val;
274 dev_cellIdxKeys[blockIdx.x] = cellIdx;
275 }
276 }
277}
278
280 int *dev_cellIdxKeys,
281 Real *dev_potentialDdtValues,
282 Real *dev_Ddt,
283 int blocksPerSpatialCell
284 ){
285
286 int startIdx = blockIdx.x*blocksPerSpatialCell;
287 int threadIndex = threadIdx.x;
288 size_t cellIdx = dev_cellIdxKeys[startIdx];
289
290 // Initiate shared memory values
291 extern __shared__ Real localDdtValues[];
292 localDdtValues[threadIndex] = std::numeric_limits<Real>::max();
293
294 for(int i = threadIndex; i < blocksPerSpatialCell; i+=blockDim.x){
295 localDdtValues[threadIndex] = min(localDdtValues[threadIndex], dev_potentialDdtValues[startIdx+i]);
296 }
297
298 // Reduction in shared memory
300 for (int s = blockDim.x / 2; s > GPUTHREADS/2; s >>= 1) {
301 if (threadIndex < s) {
302 localDdtValues[threadIndex] = min(localDdtValues[threadIndex], localDdtValues[threadIndex + s]);
303 }
305 }
306 // Warp reduction
307 if (threadIndex < GPUTHREADS) {
308 gpuWarpSync();
309
310 Real val = localDdtValues[threadIndex];
311 for (int offset = GPUTHREADS/2; offset > 0; offset /= 2) {
312 val = min(val, gpuKernelShflDown(val, offset));
313 }
314
315 // Write the result from the first thread of each block
316 if (threadIndex == 0) {
317 dev_Ddt[cellIdx] = val;
318 }
319 }
320}
321
322__global__ void __launch_bounds__(Hashinator::defaults::MAX_BLOCKSIZE/2) dividefByCount_kernel(
323 size_t *dev_smallCellIdxArray,
324 Realf *dev_fmu,
325 int *dev_fcount,
326 int nbins_v,
327 int nbins_mu,
329 ){
330
331 int idx = blockIdx.x*blockDim.x + threadIdx.x;
332
333 if(idx >= maxThreadIndex){return;}
334
335 int indv = idx%nbins_v;
336 int indmu = (idx/nbins_v)%nbins_mu;
337 int spatialBlockIndex = idx/(nbins_v*nbins_mu); // Corresponds to index spatial and velocity blocks
338 size_t cellIdx = dev_smallCellIdxArray[spatialBlockIndex];
339
344 }
345}
346
347__global__ void __launch_bounds__(Hashinator::defaults::MAX_BLOCKSIZE/2) getCellIndexArray_kernel(
348 size_t *dev_cellIdxArray,
349 size_t *dev_velocityIdxArray,
353 ){
354
355 size_t totalBlockIndex = blockIdx.x*blockDim.x + threadIdx.x;
356
357 if(totalBlockIndex >= (size_t)numberOfComputedVelocityBlocks){return;}
358
359 // Binary search
360 int left = 0;
362 int cellIndex = 0;
363
364#ifdef DEBUG_SOLVERS
365 assert(right>=left);
366#endif
367
368 while (left <= right) {
369 int mid = (left + right) >> 1;
370 if (dev_cellIdxStartCutoff[mid] <= (size_t)totalBlockIndex) {
371 cellIndex = mid;
372 left = mid + 1;
373 } else {
374 right = mid - 1;
375 }
376 }
377
378 dev_cellIdxArray[totalBlockIndex] = cellIndex;
379 dev_velocityIdxArray[totalBlockIndex] = totalBlockIndex - dev_cellIdxStartCutoff[cellIndex];
380}
381
382__global__ void __launch_bounds__(WID3) calculateDensity_kernel(
383 Realf *dev_density,
385 ){
386
387 const int i = threadIdx.x;
388 const int j = threadIdx.y;
389 const int k = threadIdx.z;
390 const int threadIndex = k*WID2+j*WID+i;
391 const int cellIdx = blockIdx.x;
392 const int blockSize = blockDim.x*blockDim.y*blockDim.z;
393
396
398
402
403 // Reduction in shared memory
405 for (int s = blockSize / 2; s > 0; s >>= 1) {
406 if (threadIndex < s) {
408 }
410 }
411
412 // Write the result from the first thread of each block
413 if (threadIndex == 0) {
414 dev_density[cellIdx] = localDensity[threadIndex];
415 }
416}
417
418__global__ void __launch_bounds__(WID3) conserveMass_kernel(
419 Realf *dev_densityPreAdjust,
422 ){
423
424 const int i = threadIdx.x;
425 const int j = threadIdx.y;
426 const int k = threadIdx.z;
427 const int cellIdx = blockIdx.x;
428
429 if (dev_densityPostAdjust[cellIdx] == 0.0 || dev_densityPreAdjust[cellIdx] == dev_densityPostAdjust[cellIdx]){ return; }
430
432
434
437 }
438}
439
440void pitchAngleDiffusion(dccrg::Dccrg<spatial_cell::SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid, const uint popID){
441
442 // Ensure nu0 dat file is read, if requested
443 if (P::PADcoefficient < 0) {
445 }
446
449 const Real dmubins = 2.0/nbins_mu;
450
451 // resonance gap filling coefficient, not needed assuming even number of bins in mu-space
452 const Real epsilon = 0.0;
453
454 phiprof::Timer diffusionTimer {"pitch-angle-diffusion"};
455
456 const std::vector<CellID>& LocalCells=getLocalCells();
457
458 size_t numberOfLocalCells = LocalCells.size();
459
460 std::vector<Real> dtTotalDiff(numberOfLocalCells, 0.0); // Diffusion time elapsed for each spatial cells
461
462 int maxThreadsPerBlock = Hashinator::defaults::MAX_BLOCKSIZE;
463 int blocksPerSpatialCell = (nbins_v*nbins_mu+maxThreadsPerBlock-1)/maxThreadsPerBlock;
464
465 // Compute total number of velocity blocks
466 int totalNumberOfVelocityBlocks = 0;
467 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
468
469 const auto CellID = LocalCells[CellIdx];
470 spatial_cell::SpatialCell& cell = *mpiGrid[CellID];
471
472 vmesh::LocalID numberOfVelocityBlocks = cell.get_number_of_velocity_blocks(popID);
473
474 totalNumberOfVelocityBlocks += numberOfVelocityBlocks;
475 } // End spatial cell loop
476
477 // Start session
478 gpuMemoryManager.startSession(0,0);
479
480 // Allocate host memory and get pointers
481 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_bValues, 3*numberOfLocalCells*sizeof(Real));
482 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_nu0Values, numberOfLocalCells*sizeof(Real));
483 SESSION_HOST_ALLOCATE(gpuMemoryManager, Realf, host_sparsity, numberOfLocalCells*sizeof(Realf));
484 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_bulkVX, 3*numberOfLocalCells*sizeof(Real));
485 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_bulkVY, numberOfLocalCells*sizeof(Real));
486 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_bulkVZ, numberOfLocalCells*sizeof(Real));
487 SESSION_HOST_ALLOCATE(gpuMemoryManager, size_t, host_cellIdxStartCutoff, numberOfLocalCells*sizeof(size_t));
488 SESSION_HOST_ALLOCATE(gpuMemoryManager, size_t, host_smallCellIdxArray, numberOfLocalCells*sizeof(size_t));
489 SESSION_HOST_ALLOCATE(gpuMemoryManager, size_t, host_remappedCellIdxArray, numberOfLocalCells*sizeof(size_t)); // remappedCellIdxArray tells the position of the cell index in the sequence instead of the actual index
490 SESSION_HOST_ALLOCATE(gpuMemoryManager, Real, host_Ddt, numberOfLocalCells*sizeof(Real));
491
492 Real *host_bValues = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_bValues);
493 Real *host_nu0Values = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_nu0Values);
494 Realf *host_sparsity = GET_SESSION_HOST_POINTER(gpuMemoryManager, Realf, host_sparsity);
495 Real *host_bulkVX = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_bulkVX);
496 Real *host_bulkVY = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_bulkVY);
497 Real *host_bulkVZ = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_bulkVZ);
498 size_t*host_cellIdxStartCutoff = GET_SESSION_HOST_POINTER(gpuMemoryManager, size_t, host_cellIdxStartCutoff);
499 size_t *host_smallCellIdxArray = GET_SESSION_HOST_POINTER(gpuMemoryManager, size_t, host_smallCellIdxArray);
500 size_t *host_remappedCellIdxArray = GET_SESSION_HOST_POINTER(gpuMemoryManager, size_t, host_remappedCellIdxArray);
501 Real *host_Ddt = GET_SESSION_HOST_POINTER(gpuMemoryManager, Real, host_Ddt);
502
503 // Allocate device memory and get pointers
504 SESSION_ALLOCATE(gpuMemoryManager, size_t, dev_cellIdxArray, totalNumberOfVelocityBlocks*sizeof(size_t));
505 SESSION_ALLOCATE(gpuMemoryManager, size_t, dev_velocityIdxArray, totalNumberOfVelocityBlocks*sizeof(size_t));
506 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_bValues, 3*numberOfLocalCells*sizeof(Real));
507 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_nu0Values, numberOfLocalCells*sizeof(Real));
508 SESSION_ALLOCATE(gpuMemoryManager, Realf, dev_sparsity, numberOfLocalCells*sizeof(Realf));
510 SESSION_ALLOCATE(gpuMemoryManager, int, dev_fcount, numberOfLocalCells*nbins_v*nbins_mu*sizeof(int));
511 SESSION_ALLOCATE(gpuMemoryManager, Realf, dev_fmu, numberOfLocalCells*nbins_v*nbins_mu*sizeof(Realf));
512 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_bulkVX, numberOfLocalCells*sizeof(Real));
513 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_bulkVY, numberOfLocalCells*sizeof(Real));
514 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_bulkVZ, numberOfLocalCells*sizeof(Real));
515 SESSION_ALLOCATE(gpuMemoryManager, Realf, dev_densityPreAdjust, numberOfLocalCells*sizeof(Realf));
517 SESSION_ALLOCATE(gpuMemoryManager, size_t, dev_cellIdxStartCutoff, numberOfLocalCells*sizeof(size_t));
518 SESSION_ALLOCATE(gpuMemoryManager, size_t, dev_smallCellIdxArray, numberOfLocalCells*sizeof(size_t));
519 SESSION_ALLOCATE(gpuMemoryManager, size_t, dev_remappedCellIdxArray, numberOfLocalCells*sizeof(size_t));
520 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_Ddt, numberOfLocalCells*sizeof(Real));
521 SESSION_ALLOCATE(gpuMemoryManager, Real, dev_potentialDdtValues, numberOfLocalCells*blocksPerSpatialCell*sizeof(Real));
522 SESSION_ALLOCATE(gpuMemoryManager, int, dev_cellIdxKeys, numberOfLocalCells*blocksPerSpatialCell*sizeof(int));
523
527 Real *dev_nu0Values = GET_SESSION_POINTER(gpuMemoryManager, Real, dev_nu0Values);
528 Realf *dev_sparsity = GET_SESSION_POINTER(gpuMemoryManager, Realf, dev_sparsity);
535 Realf *dev_densityPreAdjust = GET_SESSION_POINTER(gpuMemoryManager, Realf, dev_densityPreAdjust);
538 size_t *dev_smallCellIdxArray = GET_SESSION_POINTER(gpuMemoryManager, size_t, dev_smallCellIdxArray);
541 Real *dev_potentialDdtValues = GET_SESSION_POINTER(gpuMemoryManager, Real, dev_potentialDdtValues);
542 int *dev_cellIdxKeys = GET_SESSION_POINTER(gpuMemoryManager, int, dev_cellIdxKeys);
543
544 gpu_batch_allocate(numberOfLocalCells, 0);
545
546 std::vector<bool> spatialLoopComplete(numberOfLocalCells, false);
547
548 // Compute parameters
549 #pragma omp parallel for
550 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
551 bool currentSpatialLoopComplete;
552 Realf sparsity;
553 std::array<Real,3> b;
554 Real nu0;
555
556 const auto CellID = LocalCells[CellIdx];
557 SpatialCell& cell = *mpiGrid[CellID];
558
560 cell,
561 popID, CellIdx, currentSpatialLoopComplete,
562 sparsity, b, nu0
563 );
564
565 // Save computed values to host
566 spatialLoopComplete[CellIdx] = currentSpatialLoopComplete;
567 host_sparsity[CellIdx] = sparsity;
568 host_bValues[3*CellIdx] = b[0];
569 host_bValues[3*CellIdx+1] = b[1];
570 host_bValues[3*CellIdx+2] = b[2];
571 host_nu0Values[CellIdx] = nu0;
572 } // End spatial cell loop
573
574 bool allSpatialCellTimeLoopsComplete = true;
575 // Check if at least one cell needs to be calculated
576 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
577 if(!spatialLoopComplete[CellIdx]){
578 allSpatialCellTimeLoopsComplete = false;
579 break;
580 }
581 }
582
583 if(allSpatialCellTimeLoopsComplete){
584 // No need for any calculations
585 return;
586 }
587
588 // Load CPU data
589 const size_t meshID = getObjectWrapper().particleSpecies[popID].velocityMesh;
590 const vmesh::MeshParameters& vMeshParams = vmesh::getMeshWrapper()->velocityMeshes->at(meshID);
591
592 const Real Vmax = 2*sqrt(3)*vMeshParams.meshLimits[1];
593 Real dVbins = Vmax/nbins_v;
594
595 #pragma omp parallel for
596 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
597 const auto CellID = LocalCells[CellIdx];
598 spatial_cell::SpatialCell *cell = mpiGrid[CellID];
599
600 host_bulkVX[CellIdx] = cell->parameters[CellParams::VX];
601 host_bulkVY[CellIdx] = cell->parameters[CellParams::VY];
602 host_bulkVZ[CellIdx] = cell->parameters[CellParams::VZ];
603
605 } // End spatial cell loop
606
607 // Copy data to device
608 CHK_ERR( gpuMemcpy(dev_bValues, host_bValues, 3*numberOfLocalCells*sizeof(Real), gpuMemcpyHostToDevice) );
609 CHK_ERR( gpuMemcpy(dev_nu0Values, host_nu0Values, numberOfLocalCells*sizeof(Real), gpuMemcpyHostToDevice) );
610 CHK_ERR( gpuMemcpy(dev_sparsity, host_sparsity, numberOfLocalCells*sizeof(Realf), gpuMemcpyHostToDevice) );
611 CHK_ERR( gpuMemcpy(dev_bulkVX, host_bulkVX, numberOfLocalCells*sizeof(Real), gpuMemcpyHostToDevice) );
612 CHK_ERR( gpuMemcpy(dev_bulkVY, host_bulkVY, numberOfLocalCells*sizeof(Real), gpuMemcpyHostToDevice) );
613 CHK_ERR( gpuMemcpy(dev_bulkVZ, host_bulkVZ, numberOfLocalCells*sizeof(Real), gpuMemcpyHostToDevice) );
615
616 if (getObjectWrapper().particleSpecies[popID].sparse_conserve_mass) {
617 dim3 threadsPerBlock_massConservation(WID, WID, WID);
618 int blocksPerGrid_massConservation = numberOfLocalCells;
619
620 // Ensure mass conservation
621 calculateDensity_kernel<<<blocksPerGrid_massConservation, threadsPerBlock_massConservation>>>(
622 dev_densityPreAdjust,
624 );
625
627 }
628
629 while (!allSpatialCellTimeLoopsComplete) { // Substep loop
630
631 // Compute maximum indices and construct cellIdx arrays
632 int remappedCellIdx = 0;
634 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
635 // Add elements to remapped cellIdx array
636 host_remappedCellIdxArray[CellIdx] = remappedCellIdx;
637
638 if(spatialLoopComplete[CellIdx]){
639 continue;
640 }
641
642 const auto CellID = LocalCells[CellIdx];
643 spatial_cell::SpatialCell& cell = *mpiGrid[CellID];
644
645 vmesh::LocalID numberOfVelocityBlocks = cell.get_number_of_velocity_blocks(popID);
646
647 // Add elements to cellIdx arrays
648 host_cellIdxStartCutoff[remappedCellIdx] = numberOfComputedVelocityBlocks;
649 host_smallCellIdxArray[remappedCellIdx] = CellIdx;
650
651 numberOfComputedVelocityBlocks += numberOfVelocityBlocks;
652 remappedCellIdx++;
653 } // End spatial cell loop
654
655 int maxCellIndex = remappedCellIdx;
656 int maxBlockIndex = numberOfComputedVelocityBlocks;
657
658 // Copy data to device
659 CHK_ERR( gpuMemcpy(dev_cellIdxStartCutoff, host_cellIdxStartCutoff, maxCellIndex*sizeof(size_t), gpuMemcpyHostToDevice) );
660 CHK_ERR( gpuMemcpy(dev_smallCellIdxArray, host_smallCellIdxArray, maxCellIndex*sizeof(size_t), gpuMemcpyHostToDevice) );
661 CHK_ERR( gpuMemcpy(dev_remappedCellIdxArray, host_remappedCellIdxArray, numberOfLocalCells*sizeof(size_t), gpuMemcpyHostToDevice) );
662
663 // Initialize with zero values
664 CHK_ERR( gpuMemset(dev_fmu, 0.0, numberOfLocalCells*nbins_v*nbins_mu*sizeof(Realf)) );
665 CHK_ERR( gpuMemset(dev_fcount, 0, numberOfLocalCells*nbins_v*nbins_mu*sizeof(int)) );
666
667 int totalThreadsPerBlock_getCellIndexArray = Hashinator::defaults::MAX_BLOCKSIZE/2; //Using Hashinator::defaults::MAX_BLOCKSIZE/2 = 512 blocks can lead to better streaming multiprocessor occupancy
668 int maxThreadIndex_getCellIndexArray = numberOfComputedVelocityBlocks;
669 int blocksPerGrid_getCellIndexArray = (maxThreadIndex_getCellIndexArray+totalThreadsPerBlock_getCellIndexArray-1)/totalThreadsPerBlock_getCellIndexArray;
670
671 // Find spatial and velocity cell indices corresponding to each GPU block based on cutoffs,
672 // so that each block will know the correct indeces in later kernels
673 phiprof::Timer cellIdxArrayTimer {"getCellIndexArray_kernel"};
674 getCellIndexArray_kernel<<<blocksPerGrid_getCellIndexArray, totalThreadsPerBlock_getCellIndexArray>>>(
680 );
681
683 cellIdxArrayTimer.stop();
684
685 dim3 threadsPerBlock_build2dArrayOfFvmu(WID, WID, WID);
686 int blocksPerGrid_build2dArrayOfFvmu = maxBlockIndex;
687
688 // Build Fvmu array by dividing data to bins
689 phiprof::Timer builFvmuTimer {"build2dArrayOfFvmu_kernel"};
690 build2dArrayOfFvmu_kernel<<<blocksPerGrid_build2dArrayOfFvmu, threadsPerBlock_build2dArrayOfFvmu>>>(
698 dev_fmu,
700 dVbins,
701 dmubins,
702 nbins_v,
704 );
705
707 builFvmuTimer.stop();
708
709 int totalThreadsPerBlock_dividefByCount = Hashinator::defaults::MAX_BLOCKSIZE/2; //Using Hashinator::defaults::MAX_BLOCKSIZE/2 = 512 blocks can lead to better streaming multiprocessor occupancy
710 int maxThreadIndex_dividefByCount = numberOfLocalCells*nbins_v*nbins_mu;
711 int blocksPerGrid_dividefByCount = (maxThreadIndex_dividefByCount+totalThreadsPerBlock_dividefByCount-1)/totalThreadsPerBlock_dividefByCount;
712
713 // Divide by count
714 phiprof::Timer divideFByCountTimer {"dividefByCount_kernel"};
715 dividefByCount_kernel<<<blocksPerGrid_dividefByCount, totalThreadsPerBlock_dividefByCount>>>(
716 dev_smallCellIdxArray,
717 dev_fmu,
719 nbins_v,
720 nbins_mu,
721 maxThreadIndex_dividefByCount
722 );
723
725 divideFByCountTimer.stop();
726
727 int lastBlockSize = nbins_v*nbins_mu-(blocksPerSpatialCell-1)*maxThreadsPerBlock;
728 int totalThreadsPerBlock_computeDerivativesCFLDdt;
729 if(blocksPerSpatialCell == 1){
730 totalThreadsPerBlock_computeDerivativesCFLDdt = nextPowerOfTwo(nbins_v*nbins_mu);
731 }else{
732 totalThreadsPerBlock_computeDerivativesCFLDdt = maxThreadsPerBlock;
733 }
734 int blocksPerGrid_computeDerivativesCFLDdt = numberOfLocalCells*blocksPerSpatialCell;
735 int sharedMemorySize = totalThreadsPerBlock_computeDerivativesCFLDdt * sizeof(Real);
736
737 // Compute derivatives and Ddt
738 phiprof::Timer computeDerivativesTimer {"computeDerivativesCFLDdt_kernel"};
740 dev_smallCellIdxArray,
742 dev_fmu,
743 dev_nu0Values,
745 dev_cellIdxKeys,
746 dev_potentialDdtValues,
747 dev_sparsity,
748 dVbins,
749 dmubins,
750 epsilon,
752 nbins_v,
753 nbins_mu,
754 blocksPerSpatialCell,
755 lastBlockSize
756 );
757
759 computeDerivativesTimer.stop();
760
761 int totalThreadsPerBlock_reduceDdtValues;
762 if(blocksPerSpatialCell < maxThreadsPerBlock){
763 totalThreadsPerBlock_reduceDdtValues = max(nextPowerOfTwo(blocksPerSpatialCell), GPUTHREADS);
764 }else{
765 totalThreadsPerBlock_reduceDdtValues = maxThreadsPerBlock;
766 }
767 int blocksPerGrid_reduceDdtValues = numberOfLocalCells;
768 int sharedMemorySize_reduceDdtValues = totalThreadsPerBlock_reduceDdtValues * sizeof(Real);
769
770 // Find minimum values of the calculated potential ddt values for each spatial cell
771 phiprof::Timer reduceDdtValuesTimer {"reduceDdtValues_kernel"};
773 dev_cellIdxKeys,
774 dev_potentialDdtValues,
775 dev_Ddt,
776 blocksPerSpatialCell
777 );
778
780 reduceDdtValuesTimer.stop();
782
783 CHK_ERR( gpuMemcpy(host_Ddt, dev_Ddt, numberOfLocalCells * sizeof(Real), gpuMemcpyDeviceToHost) );
784
785 // Compute Ddt
786 remappedCellIdx = 0;
787 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
788 if(spatialLoopComplete[CellIdx]){
789 continue;
790 }
791 const Real RemainT = Parameters::dt - dtTotalDiff[CellIdx]; //Remaining time before reaching simulation time step
792 if (host_Ddt[CellIdx] > RemainT) {
793 host_Ddt[CellIdx] = RemainT;
794 }
795 dtTotalDiff[CellIdx] += host_Ddt[CellIdx];
796 remappedCellIdx++;
797 } // End spatial cell loop
798
799 CHK_ERR( gpuMemcpy(dev_Ddt, host_Ddt, numberOfLocalCells*sizeof(Real), gpuMemcpyHostToDevice) );
800
801 dim3 threadsPerBlock_computeNewCellValues(WID, WID, WID);
802 int blocksPerGrid_computeNewCellValues = maxBlockIndex;
803
804 // Get new cell values
805 phiprof::Timer newCellValuesTimer {"computeNewCellValues_kernel"};
806 computeNewCellValues_kernel<<<blocksPerGrid_computeNewCellValues, threadsPerBlock_computeNewCellValues>>>(
816 dev_Ddt,
817 dVbins,
818 dmubins,
819 nbins_v,
821 );
822
824 newCellValuesTimer.stop();
826
827 // Check if all cells are done
828 for (size_t CellIdx = 0; CellIdx < numberOfLocalCells; CellIdx++) { // Iterate over all spatial cells
829 allSpatialCellTimeLoopsComplete = true;
830 if(dtTotalDiff[CellIdx] < Parameters::dt){
831 allSpatialCellTimeLoopsComplete = false;
832 }else{
833 spatialLoopComplete[CellIdx] = true;
834 }
835 }
836
837 } // End Time loop
838
839 if (getObjectWrapper().particleSpecies[popID].sparse_conserve_mass) {
840 dim3 threadsPerBlock_massConservation(WID, WID, WID);
841 int blocksPerGrid_massConservation = numberOfLocalCells;
842
843 // Ensure mass conservation
844 calculateDensity_kernel<<<blocksPerGrid_massConservation, threadsPerBlock_massConservation>>>(
847 );
848
850
851 conserveMass_kernel<<<blocksPerGrid_massConservation, threadsPerBlock_massConservation>>>(
852 dev_densityPreAdjust,
855 );
856
859 }
860
861 gpuMemoryManager.endSession();
862 diffusionTimer.stop();
863} // End function
for i
Definition Dispersion.m:24
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
#define gpuPeekAtLastError
#define gpuWarpSync()
#define gpuMemcpyHostToDevice
#define CHK_ERR(err)
#define gpuMemcpy
#define gpuMemcpyDeviceToHost
#define gpuKernelShflDown(val, offset)
#define gpuMemset
#define gpuDeviceSynchronize
#define GPUTHREADS
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > parameters
vmesh::VelocityBlockContainer * dev_get_velocity_blocks(const size_t &popID)
const std::vector< CellID > & getLocalCells()
Definition main.cpp:39
#define WID
Definition common.h:514
const int WID3
Definition common.h:517
const int WID2
Definition common.h:516
void readNuArrayFromFile()
void computePitchAngleDiffusionParameters(SpatialCell &cell, const uint popID, const size_t CellIdx, bool &currentSpatialLoopComplete, Realf &sparsity, std::array< Real, 3 > &b, Real &nu0)
float Real
Definition definitions.h:41
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
unsigned int nextPowerOfTwo(unsigned int n)
Definition gpu_base.cpp:92
GPUMemoryManager gpuMemoryManager
Definition gpu_base.cpp:64
__host__ void gpu_batch_allocate(uint nCells, uint maxNeighbours)
Definition gpu_base.cpp:462
#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
__global__ void Realf int int int int maxThreadIndex
const Real VY
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf int Real const Real int int nbins_mu
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real * dev_bulkVZ
#define GPUCELLMUSPACE(var, cellIdx, v_ind, mu_ind)
const Real increment
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf * dev_fmu
__global__ void size_t size_t * dev_cellIdxStartCutoff
const int Vindex
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf int Real dVbins
const Realf cellValue
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf int * dev_fcount
const Real VplasmaZ
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real * dev_bulkVY
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const * dev_velocityBlockContainer
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real * dev_bValues
__global__ void Realf * dev_densityPostAdjust
const Real mu
const int vi
__global__ void size_t size_t vmesh::VelocityBlockContainer *__restrict__ Real Real Real Real Realf Real * dev_Ddt
__global__ void size_t * dev_velocityIdxArray
const Real VplasmaY
const int threadIndex
__global__ void size_t size_t int int maxCellIndex
void pitchAngleDiffusion(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint popID)
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf int Real const Real int nbins_v
__shared__ Realf localDensity[WID3]
__global__ void reduceDdtValues_kernel(int *dev_cellIdxKeys, Real *dev_potentialDdtValues, Real *dev_Ddt, int blocksPerSpatialCell)
__global__ void size_t size_t vmesh::VelocityBlockContainer *__restrict__ Real Real Real Real Realf * dev_dfdt_mu
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf int Real const Real dmubins
const int mui
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real * dev_bulkVX
size_t velocityIdx
const Real VplasmaX
const int blockSize
__global__ void computeDerivativesCFLDdt_kernel(size_t *dev_smallCellIdxArray, int *dev_fcount, Realf *dev_fmu, Real *dev_nu0Values, Realf *dev_dfdt_mu, int *dev_cellIdxKeys, Real *dev_potentialDdtValues, Realf *dev_sparsity, Real dVbins, const Real dmubins, const Real epsilon, Realf PADCFL, int nbins_v, int nbins_mu, int blocksPerSpatialCell, int lastBlockSize)
const Real VZ
const int j
const bool lessZero
const uint numberOfVelocityCells
__global__ void size_t size_t int numberOfComputedVelocityBlocks
const Real *__restrict__ blockParameters
__syncthreads()
const Real Vmu
const Real Vpara
const Real VX
const int k
const Real normV
dev_cellIdxArray[totalBlockIndex]
__global__ void size_t * dev_remappedCellIdxArray
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
static __global__ void __launch_bounds__(WID3, 4) population_scale_kernel(vmesh
uint32_t LocalID
Definition definitions.h:60
ARCH_HOSTDEV MeshWrapper * getMeshWrapper()
std::vector< species::Species > particleSpecies
static int PADvbins
Definition parameters.h:240
static Realf PADcoefficient
Definition parameters.h:238
static Realf PADCFL
Definition parameters.h:239
static int PADmubins
Definition parameters.h:241
static Real dt
Definition parameters.h:55
std::array< vmesh::MeshParameters, MAX_VMESH_PARAMETERS_COUNT > * velocityMeshes
static ARCH_HOSTDEV VecSimple< T > min(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV VecSimple< T > max(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV VecSimple< T > abs(const VecSimple< T > &l)
static ARCH_HOSTDEV VecSimple< T > floor(VecSimple< T > const &a)