Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
spatial_cell_gpu.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 <unordered_set>
24
26#include "../arch/gpu_base.hpp"
27#include "../object_wrapper.h"
29
31
32// INIT_VMESH_SIZE and INIT_MAP_SIZE defined in arch/gpu_base.hpp
33
34using namespace std;
35
36// Certain addition lists are used in acceleration, and can require a larger allocation
37// in case very many blocks are added at once.
38const static uint acc_reserve_multiplier = 3;
39
40namespace spatial_cell {
44
46 // Block list and cache always have room for all blocks
47 this->sysBoundaryLayer=0; // Default value, layer not yet initialized
48 for (unsigned int i=0; i<WID3; ++i) {
49 null_block_data[i] = 0.0;
50 }
51
52 // reset spatial cell parameters
53 for (unsigned int i = 0; i < CellParams::N_SPATIAL_CELL_PARAMS; i++) {
54 this->parameters[i]=0.0;
55 }
56
57 // reset BVOL derivatives
58 for (unsigned int i = 0; i < bvolderivatives::N_BVOL_DERIVATIVES; i++) {
59 this->derivativesBVOL[i]=0;
60 }
61
62 for (unsigned int i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
64 this->neighbor_block_data[i] = NULL;
65 }
66
67 //is transferred by default
68 this->mpiTransferEnabled=true;
69
70 // Set correct number of populations
71 populations.resize(getObjectWrapper().particleSpecies.size());
72
73 // Set velocity meshes
74 for (uint popID=0; popID<populations.size(); ++popID) {
76 populations[popID].vmesh->initialize(spec.velocityMesh);
77 populations[popID].vmesh->gpu_prefetchDevice();
78 populations[popID].blockContainer->gpu_prefetchDevice();
79 populations[popID].Upload();
80 populations[popID].velocityBlockMinValue = spec.sparseMinValue;
81 populations[popID].N_blocks = 0;
82 }
83
84 // SplitVectors and hashmaps via pointers for unified memory
85
86 // create in host instead of unified memory, upload device copy
87 void *buf0 = malloc(sizeof(split::SplitVector<vmesh::GlobalID>));
88 velocity_block_with_content_list = ::new (buf0) split::SplitVector<vmesh::GlobalID>(INIT_VMESH_SIZE);
89 //velocity_block_with_content_list = new split::SplitVector<vmesh::GlobalID>(INIT_VMESH_SIZE);
94
95 // create in host instead of unified memory, upload device copy
96 // velocity_block_with_content_map = new Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(7);
97 // velocity_block_with_no_content_map = new Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(7);
98 void *buf1 = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
99 void *buf2 = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
100 velocity_block_with_content_map = ::new (buf1) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(INIT_MAP_SIZE);
101 velocity_block_with_no_content_map = ::new (buf2) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(INIT_MAP_SIZE);
106
107 // Lists used in block adjustment
108 void *buf11 = malloc(sizeof(split::SplitVector<vmesh::GlobalID>));
109 void *buf12 = malloc(sizeof(split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>));
110 void *buf13 = malloc(sizeof(split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>));
111 void *buf14 = malloc(sizeof(split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>));
112 list_with_replace_new = ::new (buf11) split::SplitVector<vmesh::GlobalID>(INIT_VMESH_SIZE*acc_reserve_multiplier);
113 list_delete = ::new (buf12) split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(INIT_VMESH_SIZE);
114 list_to_replace = ::new (buf13) split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(INIT_VMESH_SIZE);
115 list_with_replace_old = ::new (buf14) split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(INIT_VMESH_SIZE);
116 // list_with_replace_new = new split::SplitVector<vmesh::GlobalID>(INIT_VMESH_SIZE*acc_reserve_multiplier);
117 // list_delete = new split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(INIT_VMESH_SIZE);
118 // list_to_replace = new split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(INIT_VMESH_SIZE);
119 // list_with_replace_old = new split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(INIT_VMESH_SIZE);
121 dev_list_delete = list_delete->upload<true>();
122 dev_list_to_replace = list_to_replace->upload<true>();
128 }
129
134 }
138 }
142 }
145 vbwcl_sizePower = 0;
147
149 ::delete list_with_replace_new;
151 }
152 if (list_delete) {
153 ::delete list_delete;
154 list_delete = 0;
155 }
156 if (list_to_replace) {
157 ::delete list_to_replace;
158 list_to_replace = 0;
159 }
161 ::delete list_with_replace_old;
163 }
168 }
169
171 std::cerr<<"Warning! Spatial Cell GPU copy constructor called. Performance may degrade."<<std::endl;
172 // Note: DCCRG should not call this method ever, as far as we know. Thus untested.
173 const uint reserveSize = other.velocity_block_with_content_list_capacity;
174
175 // create in host instead of unified memory, upload device copy
176 void *buf0 = malloc(sizeof(split::SplitVector<vmesh::GlobalID>));
177 velocity_block_with_content_list = ::new (buf0) split::SplitVector<vmesh::GlobalID>(reserveSize);
178 //velocity_block_with_content_list = new split::SplitVector<vmesh::GlobalID>(reserveSize);
183
184 // create in host instead of unified memory, upload device copy
185 void *buf1 = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
186 void *buf2 = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
187 velocity_block_with_content_map = ::new (buf1) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(other.vbwcl_sizePower);
188 velocity_block_with_no_content_map = ::new (buf2) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(other.vbwncl_sizePower);
193
194 // Lists used in block adjustment
195 void *buf11 = malloc(sizeof(split::SplitVector<vmesh::GlobalID>));
196 void *buf12 = malloc(sizeof(split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>));
197 void *buf13 = malloc(sizeof(split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>));
198 void *buf14 = malloc(sizeof(split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>));
199 list_with_replace_new = ::new (buf11) split::SplitVector<vmesh::GlobalID>(other.list_with_replace_new_capacity);
200 list_delete = ::new (buf12) split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(other.list_delete_capacity);
201 list_to_replace = ::new (buf13) split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(other.list_to_replace_capacity);
202 list_with_replace_old = ::new (buf14) split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(other.list_with_replace_old_capacity);
203 // list_with_replace_new = new split::SplitVector<vmesh::GlobalID>(other.list_with_replace_new_capacity);
204 // list_delete = new split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(other.list_delete_capacity);
205 // list_to_replace = new split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(other.list_to_replace_capacity);
206 // list_with_replace_old = new split::SplitVector<Hashinator::hash_pair<vmesh::GlobalID,vmesh::LocalID>>(other.list_with_replace_old_capacity);
208 dev_list_delete = list_delete->upload<true>();
209 dev_list_to_replace = list_to_replace->upload<true>();
215
216 // Member variables
221 initialized = other.initialized;
223 for (unsigned int i=0; i<bvolderivatives::N_BVOL_DERIVATIVES; ++i) {
225 }
226 for (unsigned int i=0; i<CellParams::N_SPATIAL_CELL_PARAMS; ++i) {
227 parameters[i] = other.parameters[i];
228 }
229 for (unsigned int i=0; i<WID3; ++i) {
230 null_block_data[i] = 0.0;
231 }
232 for (unsigned int i=0; i<MAX_NEIGHBORS_PER_DIM; ++i) {
235 }
236 face_neighbor_ranks.clear();
237 // for (unsigned int i=0; i<MAX_NEIGHBORS_PER_DIM; ++i) {
238 // neighbor_block_data[i] = other.neighbor_block_data[i];
239 // neighbor_number_of_blocks[i] = other.neighbor_number_of_blocks[i];
240 // }
241 // if (other.face_neighbor_ranks.size()>0) {
242 // face_neighbor_ranks = std::map<int,std::set<int>>(other.face_neighbor_ranks);
243 // }
244 if (other.populations.size()>0) {
245 populations = std::vector<spatial_cell::Population>(other.populations);
246 }
247 }
248
249 const SpatialCell& SpatialCell::operator=(const SpatialCell& other) {
250 // Used for refining spatial cells
256
257 gpuStream_t stream = gpu_getStream();
258
259 if (vbwcl_sizePower < other.vbwcl_sizePower) {
262 void *buf1 = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
263 velocity_block_with_content_map = ::new (buf1)Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(vbwcl_sizePower);
265 } else {
266 velocity_block_with_content_map->clear<false>(Hashinator::targets::device,stream,std::pow(2,vbwcl_sizePower));
267 }
271 void *buf2 = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
272 velocity_block_with_no_content_map = ::new (buf2) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(vbwncl_sizePower);
274 } else {
275 velocity_block_with_no_content_map->clear<false>(Hashinator::targets::device,stream,std::pow(2,vbwncl_sizePower));
276 }
277
282 list_with_replace_new->clear();
283 list_delete->clear();
284 list_to_replace->clear();
285 list_with_replace_old->clear();
286
292 dev_list_delete = list_delete->upload<false>();
293 dev_list_to_replace = list_to_replace->upload<false>();
295
296 // Member variables
297 //ioLocalCellId = other.ioLocalCellId;
301 initialized = other.initialized;
303 for (unsigned int i=0; i<bvolderivatives::N_BVOL_DERIVATIVES; ++i) {
304 derivativesBVOL[i] = other.derivativesBVOL[i]; // Will be re-calculated
305 }
306 for (unsigned int i=0; i<CellParams::N_SPATIAL_CELL_PARAMS; ++i) {
307 parameters[i] = other.parameters[i]; // Need to be re-defined
308 }
309 for (unsigned int i=0; i<WID3; ++i) {
310 null_block_data[i] = 0.0;
311 }
312 for (unsigned int i=0; i<MAX_NEIGHBORS_PER_DIM; ++i) {
315 }
316 face_neighbor_ranks.clear(); // Needs re-building after refinement
317 populations = std::vector<spatial_cell::Population>(other.populations);
318
319 return *this;
320 }
321
324 void SpatialCell::setReservation(const uint popID, const vmesh::LocalID reservationsize, bool force) {
325 if (force || (reservationsize > populations[popID].reservation)) {
326 populations[popID].reservation = reservationsize;
327 }
328 }
330 return populations[popID].reservation;
331 }
332
334 void SpatialCell::applyReservation(const uint popID) {
335 const size_t reserveSize = populations[popID].reservation;
336 size_t newReserve = populations[popID].reservation * BLOCK_ALLOCATION_PADDING;
337 const vmesh::LocalID HashmapReqSize = ceil(log2(reserveSize))+1;
338 gpuStream_t stream = gpu_getStream();
339 // Now uses host-cached values
340 // upload() calls include an optimizeGPU() already.
341
343 velocity_block_with_content_list->reserve(newReserve,true);
346 }
347 // This one is also used in acceleration for adding new blocks to the mesh, so should have more room.
348 if (vbwcl_sizePower < HashmapReqSize+1) {
349 vbwcl_sizePower = HashmapReqSize+1;
350 velocity_block_with_content_map->resize(vbwcl_sizePower, Hashinator::targets::device, stream);
351 // ::delete velocity_block_with_content_map;
352 // void *buf = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
353 // velocity_block_with_content_map = ::new (buf) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(vbwcl_sizePower);
354 // dev_velocity_block_with_content_map = velocity_block_with_content_map->upload<true>(stream);
355 }
356 // Here the regular size estimate should be enough.
357 if (vbwncl_sizePower < HashmapReqSize) {
358 vbwncl_sizePower = HashmapReqSize;
359 velocity_block_with_no_content_map->resize(vbwncl_sizePower, Hashinator::targets::device, stream);
360 // ::delete velocity_block_with_no_content_map;
361 // void *buf = malloc(sizeof(Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>));
362 // velocity_block_with_no_content_map = ::new (buf) Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID>(vbwncl_sizePower);
363 // dev_velocity_block_with_no_content_map = velocity_block_with_no_content_map->upload<true>(stream);
364 }
365 // These lists are also used in acceleration, where sometimes, very many blocks may be added.
366 // (Maximum possible is all existing blocks moved to a new location + 2 per column)
367 // Thus, this one list needs to have larger capacity than the others..
369 list_with_replace_new->reserve(newReserve * acc_reserve_multiplier,true);
371 dev_list_with_replace_new = list_with_replace_new->upload<true>(stream);
372 }
373 if (list_delete_capacity < reserveSize) {
374 list_delete->reserve(newReserve,true);
375 list_delete_capacity = newReserve;
376 dev_list_delete = list_delete->upload<true>(stream);
377 }
378 if (list_to_replace_capacity < reserveSize) {
379 list_to_replace->reserve(newReserve,true);
380 list_to_replace_capacity = newReserve;
381 dev_list_to_replace = list_to_replace->upload<true>(stream);
382 }
383 if (list_with_replace_old_capacity < reserveSize) {
384 list_with_replace_old->reserve(newReserve,true);
386 dev_list_with_replace_old = list_with_replace_old->upload<true>(stream);
387 }
388 }
389
396 bool SpatialCell::add_velocity_block(const vmesh::GlobalID& block,const uint popID) {
398 // Block insert will fail, if the block already exists, or if
399 // there are too many blocks in the spatial cell
400 bool success = true;
401 if (populations[popID].vmesh->push_back(block) == false) {
402 return false;
403 }
404
405 const vmesh::LocalID VBC_LID = populations[popID].blockContainer->push_back_and_zero();
406
407 // Set block parameters:
408 Real* parameters = get_block_parameters(VBC_LID,popID);
409 populations[popID].vmesh->getBlockInfo(block, parameters);
410
411 // The following call 'should' be the fastest, but is actually
412 // much slower that the parameter setting above
413 //vmesh::VelocityMesh::getBlockInfo(block,get_block_parameters( blockContainer->push_back() ));
414 return success;
415 }
416
436
437 void SpatialCell::adjust_velocity_blocks(const uint popID, bool doDeleteEmptyBlocks) {
439
440 const uint cpuThreadID = gpu_getThread();
441 const gpuStream_t stream = gpu_getStream();
442
443 vmesh::VelocityMesh* host_vmesh = populations[popID].vmesh;
444 vmesh::VelocityMesh* dev_vmesh = gpuMemoryManager.getPointer<vmesh::VelocityMesh>(populations[popID].dev_vmesh);
445 vmesh::GlobalID* _withContentData = velocity_block_with_content_list->data();
446
447 // Evaluate velocity halo for local content blocks
449 const int addWidthV = getObjectWrapper().particleSpecies[popID].sparseBlockAddWidthV;
450 if (addWidthV!=1) {
451 std::cerr<<"Warning! "<<__FILE__<<":"<<__LINE__<<" Halo extent is not 1, unsupported size."<<std::endl;
452 }
453 // Halo of 1 in each direction adds up to 26 velocity neighbours.
454 // For NVIDIA/CUDA, we dan do 26 neighbours and 32 threads per warp in a single block.
455 // For AMD/HIP, we dan do 13 neighbours and 64 threads per warp in a single block, meaning two loops per cell.
456 // In either case, we launch blocks equal to velocity_block_with_content_list_size
458 dev_vmesh,
460 _withContentData,
463 );
465 //CHK_ERR( gpuStreamSynchronize(stream) );
466 }
467
472
473 /****
474 // Gather pointers and counts from neighbours
475 uint neighbours_count = neighbor_ptrs.size();
476 uint neighbours_blocks_count = 0;
477 std::vector<vmesh::GlobalID*> neigh_vbwcls;
478 std::vector<vmesh::LocalID> neigh_Nvbwcls;
479
480 if (neighbours_count > 0) {
481 for (std::vector<SpatialCell*>::const_iterator neighbor=neighbor_ptrs.begin();
482 neighbor != neighbor_ptrs.end(); ++neighbor) {
483 if ((*neighbor)->velocity_block_with_content_list_size > 0) {
484 neigh_Nvbwcls.push_back((*neighbor)->velocity_block_with_content_list_size);
485 neigh_vbwcls.push_back((*neighbor)->velocity_block_with_content_list->data());
486 neighbours_blocks_count += (*neighbor)->velocity_block_with_content_list_size;
487 }
488 }
489 neighbours_count = neigh_Nvbwcls.size(); // Only include neighbours with content.
490 }
491
492 if (neighbours_count > 0) {
493 // Upload pointers and counters for neighbours
494 vmesh::GlobalID** dev_neigh_vbwcls;
495 vmesh::GlobalID* dev_neigh_Nvbwcls;
496 CHK_ERR( gpuMallocAsync((void**)&dev_neigh_vbwcls, neighbours_count*sizeof(vmesh::GlobalID*), stream) ); // where would these be cleared?
497 CHK_ERR( gpuMallocAsync((void**)&dev_neigh_Nvbwcls, neighbours_count*sizeof(vmesh::LocalID), stream) );
498 CHK_ERR( gpuMemcpyAsync(dev_neigh_vbwcls, neigh_vbwcls.data(), neighbours_count*sizeof(vmesh::GlobalID*), gpuMemcpyHostToDevice, stream) );
499 CHK_ERR( gpuMemcpyAsync(dev_neigh_Nvbwcls, neigh_Nvbwcls.data(), neighbours_count*sizeof(vmesh::LocalID), gpuMemcpyHostToDevice, stream) );
500 // For NVIDIA/CUDA, we dan do 32 neighbour GIDs and 32 threads per warp in a single block.
501 // For AMD/HIP, we dan do 16 neighbour GIDs and 64 threads per warp in a single block
502 // This is handled in-kernel.
503 // ceil int division
504 uint launchBlocks = 1 + ((neighbours_blocks_count - 1) / WARPSPERBLOCK);
505 if (launchBlocks < std::pow(2,31)) {
506 update_neighbour_halo_kernel<<<launchBlocks, WARPSPERBLOCK*GPUTHREADS, 0, stream>>> (
507 dev_vmesh,
508 neighbours_count,
509 dev_neigh_vbwcls,
510 dev_neigh_Nvbwcls,
511 dev_velocity_block_with_content_map,
512 dev_velocity_block_with_no_content_map
513 );
514 CHK_ERR( gpuPeekAtLastError() );
515 } else {
516 // Too many launch blocks, call one by one (unlikely)
517 for (uint neigh_i = 0; neigh_i < neighbours_count; neigh_i++) {
518 uint launchBlocks = 1 + ((neigh_Nvbwcls[neigh_i] - 1) / WARPSPERBLOCK);
519 update_neighbour_halo_kernel<<<launchBlocks, WARPSPERBLOCK*GPUTHREADS, 0, stream>>> (
520 dev_vmesh,
521 1,
522 dev_neigh_vbwcls+neigh_i,
523 dev_neigh_Nvbwcls+neigh_i,
524 dev_velocity_block_with_content_map,
525 dev_velocity_block_with_no_content_map
526 );
527 CHK_ERR( gpuPeekAtLastError() );
528 }
529 }
530 //CHK_ERR( gpuStreamSynchronize(stream) );
531 }
532 *****/
533
544 const vmesh::GlobalID emptybucket = velocity_block_with_content_map->get_emptybucket();
545 const vmesh::GlobalID tombstone = velocity_block_with_content_map->get_tombstone();
546 const vmesh::GlobalID invalidGID = host_vmesh->invalidGlobalID();
547 const vmesh::LocalID invalidLID = host_vmesh->invalidLocalID();
548
549 auto rule_add = [emptybucket, tombstone, invalidGID, invalidLID]
550 __device__(const Hashinator::hash_pair<vmesh::GlobalID, vmesh::LocalID>& kval) -> bool {
551 return kval.first != emptybucket &&
552 kval.first != tombstone &&
553 kval.first != invalidGID &&
554 // Required GIDs which do not yet exist in vmesh were stored in
555 // velocity_block_with_content_map with kval.second==invalidLID
556 kval.second == invalidLID; };
557 velocity_block_with_content_map->extractKeysByPatternLoop(*dev_list_with_replace_new, rule_add, stream);
558
559 if (doDeleteEmptyBlocks) {
560 Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID> *vbwncm = dev_velocity_block_with_no_content_map;
561 split::SplitVector<vmesh::GlobalID> *d_list_add = dev_list_with_replace_new;
562
563 auto rule_delete_move = [emptybucket, tombstone, vbwncm, d_list_add, dev_vmesh, invalidGID, invalidLID]
564 __device__(const Hashinator::hash_pair<vmesh::GlobalID, vmesh::LocalID>& kval) -> bool {
565 const vmesh::LocalID nBlocksAfterAdjust1 = dev_vmesh->size()
566 + d_list_add->size() - vbwncm->size();
567 return kval.first != emptybucket &&
568 kval.first != tombstone &&
569 kval.first != invalidGID &&
570 kval.second >= nBlocksAfterAdjust1 &&
571 kval.second != invalidLID; };
572 auto rule_to_replace = [emptybucket, tombstone, vbwncm, d_list_add, dev_vmesh, invalidGID, invalidLID]
573 __device__(const Hashinator::hash_pair<vmesh::GlobalID, vmesh::LocalID>& kval) -> bool {
574 const vmesh::LocalID nBlocksAfterAdjust2 = dev_vmesh->size()
575 + d_list_add->size() - vbwncm->size();
576 return kval.first != emptybucket &&
577 kval.first != tombstone &&
578 kval.first != invalidGID &&
579 kval.second < nBlocksAfterAdjust2 &&
580 kval.second != invalidGID; };
581
582 velocity_block_with_content_map->extractPatternLoop(*dev_list_with_replace_old, rule_delete_move, stream);
583 velocity_block_with_no_content_map->extractPatternLoop(*dev_list_delete, rule_delete_move, stream);
584 velocity_block_with_no_content_map->extractPatternLoop(*dev_list_to_replace, rule_to_replace, stream);
585 } else {
586 list_with_replace_old->clear();
587 list_delete->clear();
588 list_to_replace->clear();
589 }
590 // Note:list_with_replace_new contains both new GIDs to use for replacements and new GIDs to place at end of vmesh
591
592 // Actual adjustment calling happens in separate function as it is also called from within acceleration
593 vmesh::LocalID nBlocksAfterAdjust = adjust_velocity_blocks_caller(popID);
594
595 // Perform hashmap cleanup here (instead of at acceleration mid-steps)
596 populations[popID].vmesh->gpu_cleanHashMap(stream);
597 populations[popID].Upload();
598
599 #ifdef DEBUG_SPATIAL_CELL
600 const size_t vmeshSize = (populations[popID].vmesh)->size();
601 const size_t vbcSize = (populations[popID].blockContainer)->size();
602 if (vmeshSize != vbcSize) {
603 printf("ERROR: population vmesh %zu and blockcontainer %zu sizes do not match!\n",vmeshSize,vbcSize);
604 }
605 #endif
606 #ifdef DEBUG_VLASIATOR
607 // This is a bit extreme
608 if (!populations[popID].vmesh->check()) {
609 printf("ERROR in vmesh check: %s at %d\n",__FILE__,__LINE__);
610 }
611 #endif
612 }
613
618 const uint cpuThreadID = gpu_getThread();
619 const gpuStream_t stream = gpu_getStream();
620 (GET_SUBPOINTER(gpuMemoryManager, Realf, host_returnRealf, cpuThreadID))[0] = 0; // host_rhoLossAdjust
621 // populations[popID].vmesh->print();
622 // Grow the vmesh and block container, if necessary. Try performing this on-device, if possible.
624 gpuMemoryManager.getPointer<vmesh::VelocityMesh>(populations[popID].dev_vmesh),
625 gpuMemoryManager.getPointer<vmesh::VelocityBlockContainer>(populations[popID].dev_blockContainer),
630 GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, returnLID, cpuThreadID), // return values: nbefore, nafter, nblockstochange, resize success
631 GET_SUBPOINTER(gpuMemoryManager, Realf, returnRealf, cpuThreadID) // mass loss, set to zero
632 );
634 CHK_ERR( gpuMemcpyAsync(GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, host_returnLID, cpuThreadID), GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, returnLID, cpuThreadID), 4*sizeof(vmesh::LocalID), gpuMemcpyDeviceToHost, stream) );
635 CHK_ERR( gpuStreamSynchronize(stream) );
636 // Grow mesh if necessary and on-device resize did not work??
637 const vmesh::LocalID nBlocksBeforeAdjust = (GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, host_returnLID, cpuThreadID))[0];
638 const vmesh::LocalID nBlocksAfterAdjust = (GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, host_returnLID, cpuThreadID))[1];
639 const vmesh::LocalID nBlocksToChange = (GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, host_returnLID, cpuThreadID))[2];
640 const vmesh::LocalID resizeDevSuccess = (GET_SUBPOINTER(gpuMemoryManager, vmesh::LocalID, host_returnLID, cpuThreadID))[3];
641 if ( (nBlocksAfterAdjust > nBlocksBeforeAdjust) && (resizeDevSuccess == 0)) {
642 //GPUTODO is _FACTOR enough instead of _PADDING?
643 populations[popID].vmesh->setNewCapacity(nBlocksAfterAdjust*BLOCK_ALLOCATION_PADDING);
644 populations[popID].vmesh->setNewSize(nBlocksAfterAdjust);
645 populations[popID].blockContainer->setNewCapacity(nBlocksAfterAdjust*BLOCK_ALLOCATION_PADDING);
646 populations[popID].blockContainer->setNewSize(nBlocksAfterAdjust);
647 populations[popID].Upload();
648 }
649
650 if (nBlocksToChange==0) {
651 return nBlocksAfterAdjust;
652 }
653
654 // Each GPU block / workunit could handle several Vlasiator velocity blocks at once.
655 // However, thread syncs inside the kernel prevent this.
656 // const uint vlasiBlocksPerWorkUnit = WARPSPERBLOCK * GPUTHREADS / WID3;
657 const uint vlasiBlocksPerWorkUnit = 1;
658 // ceil int division
659 const uint launchBlocks = 1 + ((nBlocksToChange - 1) / vlasiBlocksPerWorkUnit);
660
661 // Third argument specifies the number of bytes in *shared memory* that is
662 // dynamically allocated per block for this call in addition to the statically allocated memory.
663 //CHK_ERR( gpuStreamSynchronize(stream) );
664 update_velocity_blocks_kernel<<<launchBlocks, vlasiBlocksPerWorkUnit * WID3, 0, stream>>> (
665 gpuMemoryManager.getPointer<vmesh::VelocityMesh>(populations[popID].dev_vmesh),
666 gpuMemoryManager.getPointer<vmesh::VelocityBlockContainer>(populations[popID].dev_blockContainer),
671 nBlocksBeforeAdjust,
672 nBlocksToChange,
673 nBlocksAfterAdjust,
674 GET_SUBPOINTER(gpuMemoryManager, Realf, returnRealf, cpuThreadID) // mass loss
675 );
677 CHK_ERR( gpuMemcpyAsync(GET_SUBPOINTER(gpuMemoryManager, Realf, host_returnRealf, cpuThreadID), GET_SUBPOINTER(gpuMemoryManager, Realf, returnRealf, cpuThreadID), sizeof(Realf), gpuMemcpyDeviceToHost, stream) );
678
679 // Shrink the vmesh and block container, if necessary
680 if (nBlocksAfterAdjust < nBlocksBeforeAdjust) {
681 // Should not re-allocate on shrinking, so do on-device
683 gpuMemoryManager.getPointer<vmesh::VelocityMesh>(populations[popID].dev_vmesh),
684 gpuMemoryManager.getPointer<vmesh::VelocityBlockContainer>(populations[popID].dev_blockContainer),
685 nBlocksAfterAdjust
686 );
688 }
689 // Update vmesh cached size
690 populations[popID].vmesh->setNewCachedSize(nBlocksAfterAdjust);
691 populations[popID].blockContainer->setNewCachedSize(nBlocksAfterAdjust);
692
693 CHK_ERR( gpuStreamSynchronize(stream) );
694 this->populations[popID].RHOLOSSADJUST += (GET_SUBPOINTER(gpuMemoryManager, Realf, host_returnRealf, cpuThreadID))[0];
695
696 // DEBUG output after kernel
697 #ifdef DEBUG_SPATIAL_CELL
698 const vmesh::LocalID nAll = populations[popID].vmesh->size();
699 if (nAll!=nBlocksAfterAdjust) {
700 populations[popID].vmesh->gpu_prefetchHost();
701 CHK_ERR( gpuStreamSynchronize(stream) );
702 printf("after kernel, size is %d should be %d\n",nAll,nBlocksAfterAdjust);
703 for (vmesh::LocalID m=0; m<nAll; ++m) {
704 const vmesh::GlobalID GIDs = populations[popID].vmesh->getGlobalID(m);
705 const vmesh::LocalID LIDs = populations[popID].vmesh->getLocalID(GIDs);
706 printf("LID %d GID-solved %d LID-solved %d\n",m,GIDs,LIDs);
707 }
708 populations[popID].vmesh->gpu_prefetchDevice();
709 }
710 #endif
711 return nBlocksAfterAdjust;
712 }
713
714 void SpatialCell::adjustSingleCellVelocityBlocks(const uint popID, bool doDeleteEmpty) {
717 adjust_velocity_blocks(popID,doDeleteEmpty);
718 }
719
725 const gpuStream_t stream = gpu_getStream();
726
727 applyReservation(popID);
728
730 velocity_block_with_content_map->clear<false>(Hashinator::targets::device,stream,std::pow(2,vbwcl_sizePower));
731 velocity_block_with_no_content_map->clear<false>(Hashinator::targets::device,stream,std::pow(2,vbwncl_sizePower));
732 CHK_ERR( gpuStreamSynchronize(stream) );
733
734 const uint nBlocks = populations[popID].vmesh->size();
735 if (nBlocks==0) {
736 return;
737 }
738 CHK_ERR( gpuStreamSynchronize(stream) );
739
740 const Real velocity_block_min_value = getVelocityBlockMinValue(popID);
741 // Each GPU block / workunit can handle several Vlasiator velocity blocks at once. (TODO FIX)
742 //const uint vlasiBlocksPerWorkUnit = WARPSPERBLOCK * GPUTHREADS / WID3;
743 const uint vlasiBlocksPerWorkUnit = 1;
744 // ceil int division
745 const uint launchBlocks = 1 + ((nBlocks - 1) / vlasiBlocksPerWorkUnit);
746
747 // Third argument specifies the number of bytes in *shared memory* that is
748 // dynamically allocated per block for this call in addition to the statically allocated memory.
749 //update_velocity_block_content_lists_kernel<<<launchBlocks, WID3, WID3*sizeof(int), stream>>> (
750 update_velocity_block_content_lists_kernel<<<launchBlocks, (vlasiBlocksPerWorkUnit * WID3), 0, stream>>> (
751 gpuMemoryManager.getPointer<vmesh::VelocityMesh>(populations[popID].dev_vmesh),
752 gpuMemoryManager.getPointer<vmesh::VelocityBlockContainer>(populations[popID].dev_blockContainer),
755 velocity_block_min_value
756 );
758
759 // Now extract values from the map
761 split::SplitInfo info;
762 velocity_block_with_content_list->copyMetadata(&info, stream);
763 CHK_ERR( gpuStreamSynchronize(stream) );
765 }
766
768 for (size_t p=0; p<populations.size(); ++p) {
769 populations[p].vmesh->gpu_prefetchDevice();
770 populations[p].blockContainer->gpu_prefetchDevice();
771 }
772 }
774 for (size_t p=0; p<populations.size(); ++p) {
775 populations[p].vmesh->gpu_prefetchHost();
776 populations[p].blockContainer->gpu_prefetchHost();
777 }
778 }
779
783 const Real& SpatialCell::get_max_r_dt(const uint popID) const {
785 return populations[popID].max_dt[species::MAXRDT];
786 }
787
791 const Real& SpatialCell::get_max_v_dt(const uint popID) const {
793 return populations[popID].max_dt[species::MAXVDT];
794 }
795
803 std::tuple<void*, int, MPI_Datatype> SpatialCell::get_mpi_datatype(
804 const CellID cellID,
805 const int sender_rank,
806 const int receiver_rank,
807 const bool receiving,
808 const int neighborhood
809 ) {
810
811 std::vector<MPI_Aint> displacements;
812 std::vector<int> block_lengths;
813
814 // create datatype for actual data if we are in the first two
815 // layers around a boundary, or if we send for the whole system
817 this->sysBoundaryLayer ==1 || this->sysBoundaryLayer ==2 )) {
818
819 //add data to send/recv to displacement and block length lists
821 // first copy values in case this is the send operation
822 populations[activePopID].N_blocks = populations[activePopID].vmesh->size();
823
824 // send velocity block list size
825 displacements.push_back((uint8_t*) &(populations[activePopID].N_blocks) - (uint8_t*) this);
826 block_lengths.push_back(sizeof(vmesh::LocalID));
827 }
828
830 // STAGE1 should have been done, otherwise we have problems...
831 if (receiving) {
832 // Set population size based on mpi_number_of_blocks transferred earlier.
833 // Does not need to be cleared. Vmesh map and VBC will be prepared in prepare_to_receive_blocks.
835 } else {
836 // Ensure N_blocks is still correct
837 populations[activePopID].N_blocks = populations[activePopID].vmesh->size();
838 }
839
840 // send velocity block list
841 if (populations[activePopID].N_blocks > 0) {
842 displacements.push_back((uint8_t*) populations[activePopID].vmesh->getGrid()->data() - (uint8_t*) this);
843 block_lengths.push_back(sizeof(vmesh::GlobalID) * populations[activePopID].N_blocks);
844 } else {
845 displacements.push_back(0);
846 block_lengths.push_back(0);
847 }
848 }
849
851 //Communicate size of list so that buffers can be allocated on receiving side
852 // if (!receiving) { // Already done during block evaluation
853 // this->velocity_block_with_content_list_size = velocity_block_with_content_list->size();
854 // }
855 displacements.push_back((uint8_t*) &(this->velocity_block_with_content_list_size) - (uint8_t*) this);
856 block_lengths.push_back(sizeof(vmesh::LocalID));
857 }
859 const gpuStream_t stream = gpu_getStream();
860 if (receiving) {
866 //this->velocity_block_with_content_list->optimizeGPU(stream); // included in upload<true>()
867 } else {
870 }
871 }
872 //velocity_block_with_content_list_size should first be updated, before this can be done (STAGE1)
873 displacements.push_back((uint8_t*) this->velocity_block_with_content_list->data() - (uint8_t*) this);
874 block_lengths.push_back(sizeof(vmesh::GlobalID)*this->velocity_block_with_content_list_size);
875 }
876
878 displacements.push_back((uint8_t*) get_data(activePopID) - (uint8_t*) this);
879 block_lengths.push_back(sizeof(Realf) * WID3 * populations[activePopID].blockContainer->size());
880 }
881
883 /*We are actually transferring the data of a
884 * neighbor. The values of neighbor_block_data
885 * and neighbor_number_of_blocks should be set in
886 * solver.*/
887
888 // Send this data only to ranks that contain face neighbors
889 // this->neighbor_number_of_blocks has been initialized to 0, on other ranks it can stay that way.
890 const set<int>& ranks = this->face_neighbor_ranks[neighborhood];
891 if ( P::amrMaxSpatialRefLevel == 0 || receiving || ranks.find(receiver_rank) != ranks.end()) {
892
893 for ( int i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
894 displacements.push_back((uint8_t*) this->neighbor_block_data[i] - (uint8_t*) this);
895 block_lengths.push_back(sizeof(Realf) * WID3 * this->neighbor_number_of_blocks[i]);
896 }
897
898 }
899 }
900
901 // send spatial cell parameters
903 displacements.push_back((uint8_t*) &(this->parameters[0]) - (uint8_t*) this);
904 block_lengths.push_back(sizeof(Real) * CellParams::N_SPATIAL_CELL_PARAMS);
905 }
906
907 // send spatial cell dimensions and coordinates
909 displacements.push_back((uint8_t*) &(this->parameters[CellParams::XCRD]) - (uint8_t*) this);
910 block_lengths.push_back(sizeof(Real) * 6);
911 }
912
913 // send BGBXVOL BGBYVOL BGBZVOL PERBXVOL PERBYVOL PERBZVOL
915 displacements.push_back((uint8_t*) &(this->parameters[CellParams::BGBXVOL]) - (uint8_t*) this);
916 block_lengths.push_back(sizeof(Real) * 6);
917 }
918
919 // send RHOM, VX, VY, VZ
921 displacements.push_back((uint8_t*) &(this->parameters[CellParams::RHOM]) - (uint8_t*) this);
922 block_lengths.push_back(sizeof(Real) * 4);
923 }
924
925 // send RHOM_DT2, VX_DT2, VY_DT2, VZ_DT2
927 displacements.push_back((uint8_t*) &(this->parameters[CellParams::RHOM_DT2]) - (uint8_t*) this);
928 block_lengths.push_back(sizeof(Real) * 4);
929 }
930
931 // send RHOQ
933 displacements.push_back((uint8_t*) &(this->parameters[CellParams::RHOQ]) - (uint8_t*) this);
934 block_lengths.push_back(sizeof(Real));
935 }
936
937 // send RHOQ_DT2
939 displacements.push_back((uint8_t*) &(this->parameters[CellParams::RHOQ_DT2]) - (uint8_t*) this);
940 block_lengths.push_back(sizeof(Real));
941 }
942
943 // send spatial cell BVOL derivatives
945 displacements.push_back((uint8_t*) &(this->derivativesBVOL[0]) - (uint8_t*) this);
946 block_lengths.push_back(sizeof(Real) * bvolderivatives::N_BVOL_DERIVATIVES);
947 }
948
950 displacements.push_back((uint8_t*) &(this->ioLocalCellId) - (uint8_t*) this);
951 block_lengths.push_back(sizeof(uint64_t));
952 }
953
954 // send electron pressure gradient term components
956 displacements.push_back((uint8_t*) &(this->parameters[CellParams::EXGRADPE]) - (uint8_t*) this);
957 block_lengths.push_back(sizeof(Real) * 3);
958 }
959
960
961 // send P tensor diagonal components
963 displacements.push_back((uint8_t*) &(this->parameters[CellParams::P_11]) - (uint8_t*) this);
964 block_lengths.push_back(sizeof(Real) * 3);
965 }
966
968 displacements.push_back((uint8_t*) &(this->parameters[CellParams::P_11_DT2]) - (uint8_t*) this);
969 block_lengths.push_back(sizeof(Real) * 3);
970 }
971
972 // send sysBoundaryFlag
974 displacements.push_back((uint8_t*) &(this->sysBoundaryFlag) - (uint8_t*) this);
975 block_lengths.push_back(sizeof(uint));
976 displacements.push_back((uint8_t*) &(this->sysBoundaryLayer) - (uint8_t*) this);
977 block_lengths.push_back(sizeof(uint));
978 }
979
981 displacements.push_back((uint8_t*) get_block_parameters(activePopID) - (uint8_t*) this);
982 block_lengths.push_back(sizeof(Real) * size(activePopID) * BlockParams::N_VELOCITY_BLOCK_PARAMS);
983 }
984 // Copy particle species metadata
986 for (uint popID=0; popID<populations.size(); ++popID) {
987 displacements.push_back((uint8_t*) &(populations[popID].RHO) - (uint8_t*)this);
988 block_lengths.push_back(offsetof(spatial_cell::Population, N_blocks));
989 }
990 }
991
992 // Refinement parameters
994 displacements.push_back(reinterpret_cast<uint8_t*>(this->parameters.data() + CellParams::AMR_ALPHA1) - reinterpret_cast<uint8_t*>(this));
995 block_lengths.push_back(sizeof(Real) * (CellParams::AMR_ALPHA2 - CellParams::AMR_ALPHA1 + 1)); // This is just 2, but let's be explicit
996 }
997
998 }
999
1000 void* address = this;
1001 int count;
1002 MPI_Datatype datatype;
1003
1004 if (displacements.size() > 0) {
1005 count = 1;
1006 MPI_Type_create_hindexed(
1007 displacements.size(),
1008 &block_lengths[0],
1009 &displacements[0],
1010 MPI_BYTE,
1011 &datatype
1012 );
1013 } else {
1014 count = 0;
1015 datatype = MPI_BYTE;
1016 }
1017
1018 const bool printMpiDatatype = false;
1019 if(printMpiDatatype) {
1020 int mpiSize;
1021 int myRank;
1022 MPI_Type_size(datatype,&mpiSize);
1023 MPI_Comm_rank(MPI_COMM_WORLD,&myRank);
1024 cout << myRank << " get_mpi_datatype: " << cellID << " " << sender_rank << " " << receiver_rank << " " << mpiSize << ", Nblocks = " << populations[activePopID].N_blocks << ", nbr Nblocks =";
1025 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
1026 const set<int>& ranks = this->face_neighbor_ranks[neighborhood];
1027 if ( receiving || ranks.find(receiver_rank) != ranks.end()) {
1028 cout << " " << this->neighbor_number_of_blocks[i];
1029 } else {
1030 cout << " " << 0;
1031 }
1032 }
1033 cout << " face_neighbor_ranks =";
1034 for (const auto& rank : this->face_neighbor_ranks[neighborhood]) {
1035 cout << " " << rank;
1036 }
1037 cout << endl;
1038 }
1039
1040 return std::make_tuple(address,count,datatype);
1041 }
1042
1047 Real SpatialCell::getVelocityBlockMinValue(const uint popID) const {
1048 return populations[popID].velocityBlockMinValue;
1049 }
1050
1056 void SpatialCell::prepare_to_receive_blocks(const uint popID) {
1057 setNewSizeClear(popID);
1058 // As the globalToLocalMap is empty, instead of calling
1059 // vmesh->setGrid() we can update both that and the block
1060 // parameters with a single kernel launch.
1061
1062 //populations[popID].vmesh->setGrid(); // Based on localToGlobalMap
1063 const gpuStream_t stream = gpu_getStream();
1064 const uint newSize = populations[popID].N_blocks;
1065 // Set velocity block parameters:
1066 if (newSize>0) {
1067 // ceil int division
1068 #ifdef USE_WARPACCESSORS
1069 const uint launchBlocks = 1 + ((newSize - 1) / (WARPSPERBLOCK));
1070 #else
1071 const uint launchBlocks = 1 + ((newSize - 1) / (WARPSPERBLOCK*GPUTHREADS));
1072 #endif
1073 update_vmesh_and_blockparameters_kernel<<<launchBlocks, (WARPSPERBLOCK*GPUTHREADS), 0, stream>>> (
1074 gpuMemoryManager.getPointer<vmesh::VelocityMesh>(populations[popID].dev_vmesh),
1075 gpuMemoryManager.getPointer<vmesh::VelocityBlockContainer>(populations[popID].dev_blockContainer),
1076 newSize
1077 );
1079 CHK_ERR( gpuStreamSynchronize(stream) );
1080 }
1081 }
1082
1087 bool SpatialCell::setCommunicatedSpecies(const uint popID) {
1088 #ifdef DEBUG_SPATIAL_CELL
1089 if (popID >= getObjectWrapper().particleSpecies.size()) {
1090 std::cerr << "ERROR, popID " << popID << " exceeds species.size() " << getObjectWrapper().particleSpecies.size() << " in ";
1091 std::cerr << __FILE__ << ":" << __LINE__ << std::endl;
1092 exit(1);
1093 }
1094 #endif
1095
1096 activePopID = popID;
1097 return true;
1098 }
1099
1104 void SpatialCell::set_max_r_dt(const uint popID,const Real& value) {
1106 populations[popID].max_dt[species::MAXRDT] = value;
1107 }
1108
1113 void SpatialCell::set_max_v_dt(const uint popID,const Real& value) {
1115 populations[popID].max_dt[species::MAXVDT] = value;
1116 }
1117
1123 bool success = true;
1124 return true; // on AMD, shrink_to_fit appears broken.
1125 size_t largestAmount = 0;
1126 for (size_t popID=0; popID<populations.size(); ++popID) {
1127 const vmesh::LocalID amount
1128 = 2 + populations[popID].blockContainer->size()
1129 * populations[popID].blockContainer->getBlockAllocationFactor();
1130 largestAmount = std::max(largestAmount,(size_t)populations[popID].blockContainer->size());
1131 // Allow capacity to be a bit larger than needed by number of blocks, shrink otherwise
1132 if (populations[popID].blockContainer->capacity() > amount ) {
1133 if (populations[popID].blockContainer->setNewCapacityShrink(amount) == false) {
1134 success = false;
1135 }
1136 populations[popID].Upload();
1137 }
1138 }
1139 largestvmesh = largestAmount;
1140 return success;
1141 }
1143 cerr << "SC::printMeshSizes:" << endl;
1144 for (size_t p=0; p<populations.size(); ++p) {
1145 cerr << "\t pop " << p << " " << populations[p].vmesh->size() << ' ' << populations[p].blockContainer->size() << endl;
1146 }
1147 }
1148
1151 void SpatialCell::updateSparseMinValue(const uint popID) {
1152
1153 species::Species& population = getObjectWrapper().particleSpecies[popID];
1154
1155 if ( population.sparseDynamicAlgorithm == 1 || population.sparseDynamicAlgorithm == 2 ) {
1156 // Linear algorithm for the minValue: y=kx+b
1157 const Real k = (population.sparseDynamicMinValue2 - population.sparseDynamicMinValue1) / (population.sparseDynamicBulkValue2 - population.sparseDynamicBulkValue1);
1158 const Real b = population.sparseDynamicMinValue1 - k * population.sparseDynamicBulkValue1;
1159 Real x;
1160 if ( population.sparseDynamicAlgorithm == 1 ) {
1161 x = this->populations[popID].RHO;
1162 } else {
1163 x = this->get_number_of_velocity_blocks(popID);
1164 }
1165 const Real newMinValue = k*x+b;
1166 if( newMinValue < population.sparseDynamicMinValue1 ) { // Compare against the min minValue
1167 populations[popID].velocityBlockMinValue = population.sparseDynamicMinValue1;
1168 } else if( newMinValue > population.sparseDynamicMinValue2 ) { // Compare against the max minValue
1169 populations[popID].velocityBlockMinValue = population.sparseDynamicMinValue2;
1170 } else {
1171 populations[popID].velocityBlockMinValue = newMinValue;
1172 }
1173 return;
1174 } else {
1175 populations[popID].velocityBlockMinValue = getObjectWrapper().particleSpecies[popID].sparseMinValue;
1176 return;
1177 }
1178 }
1179
1180} // namespace spatial_cell
for i
Definition Dispersion.m:24
set(gca, 'YDir', 'normal')
#define gpuPeekAtLastError
#define WARPSPERBLOCK
#define gpuStream_t
#define gpuStreamSynchronize
#define CHK_ERR(err)
#define gpuMemcpyDeviceToHost
#define gpuMemcpyAsync
#define GPUTHREADS
split::SplitVector< vmesh::GlobalID > * dev_velocity_block_with_content_list
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
void debug_population_check(const uint popID) const
void updateSparseMinValue(const uint popID)
Real * get_block_parameters(const uint popID)
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * dev_velocity_block_with_no_content_map
vmesh::LocalID adjust_velocity_blocks_caller(const uint popID)
size_t count(const vmesh::GlobalID &block, const uint popID) const
std::tuple< void *, int, MPI_Datatype > get_mpi_datatype(const CellID cellID, const int sender_rank, const int receiver_rank, const bool receiving, const int neighborhood)
size_t size(const uint popID) const
std::array< Realf *, MAX_NEIGHBORS_PER_DIM > neighbor_block_data
split::SplitVector< vmesh::GlobalID > * list_with_replace_new
void set_max_r_dt(const uint popID, const Real &value)
void adjustSingleCellVelocityBlocks(const uint popID, bool doDeleteEmpty=false)
vmesh::LocalID getReservation(const uint popID) const
static bool setCommunicatedSpecies(const uint popID)
Real getVelocityBlockMinValue(const uint popID) const
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * dev_velocity_block_with_content_map
split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > * list_with_replace_old
void prepare_to_receive_blocks(const uint popID)
std::vector< vmesh::GlobalID > * velocity_block_with_content_list
split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > * dev_list_to_replace
split::SplitVector< vmesh::GlobalID > * dev_list_with_replace_new
vmesh::LocalID velocity_block_with_content_list_capacity
void dev_resize_vmesh(const uint popID, const uint nBlocks)
std::array< Realf, WID3 > null_block_data
vmesh::LocalID list_to_replace_capacity
void set_max_v_dt(const uint popID, const Real &value)
void setNewSizeClear(const uint popID, const vmesh::LocalID &newSize)
const Real & get_max_r_dt(const uint popID) const
split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > * list_delete
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * velocity_block_with_no_content_map
vmesh::LocalID list_with_replace_new_capacity
std::array< vmesh::LocalID, MAX_NEIGHBORS_PER_DIM > neighbor_number_of_blocks
void applyReservation(const uint popID)
std::array< Real, bvolderivatives::N_BVOL_DERIVATIVES > derivativesBVOL
void adjust_velocity_blocks(const std::vector< SpatialCell * > &spatial_neighbors, const uint popID, bool doDeleteEmptyBlocks=true)
split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > * dev_list_delete
split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > * dev_list_with_replace_old
Realf * get_data(const uint popID)
const Real & get_max_v_dt(const uint popID) const
vmesh::LocalID list_with_replace_old_capacity
vmesh::LocalID velocity_block_with_content_list_size
void update_velocity_block_content_lists(const uint popID)
std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > parameters
const SpatialCell & operator=(const SpatialCell &other)
split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > * list_to_replace
void setReservation(const uint popID, const vmesh::LocalID reservationsize, bool force=false)
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * velocity_block_with_content_map
std::vector< spatial_cell::Population > populations
std::map< int, std::set< int > > face_neighbor_ranks
bool add_velocity_block(const vmesh::GlobalID &block, const uint popID)
std::vector< vmesh::GlobalID > * getGrid()
static vmesh::LocalID invalidLocalID()
static vmesh::GlobalID invalidGlobalID()
const int WID3
Definition common.h:517
float Real
Definition definitions.h:41
#define MAX_NEIGHBORS_PER_DIM
Definition definitions.h:93
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
const vmesh::VelocityMesh *__restrict__ vmesh
split::SplitVector< vmesh::GlobalID > * list_with_replace_new
GPUMemoryManager gpuMemoryManager
Definition gpu_base.cpp:64
int myRank
Definition gpu_base.cpp:48
__host__ gpuStream_t gpu_getStream()
Definition gpu_base.cpp:244
uint gpu_largest_columnCount
Definition gpu_base.cpp:75
__host__ uint gpu_getThread()
Definition gpu_base.cpp:77
#define GET_SUBPOINTER(object, type, member, index)
Definition gpu_base.hpp:819
static const uint INIT_MAP_SIZE(16 - WID)
static const double BLOCK_ALLOCATION_PADDING
Definition gpu_base.hpp:60
static const uint INIT_VMESH_SIZE(32768/WID3)
const int k
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
@ N_VELOCITY_BLOCK_PARAMS
Definition common.h:115
@ N_SPATIAL_CELL_PARAMS
Definition common.h:229
@ AMR_ALPHA2
Definition common.h:221
@ AMR_ALPHA1
Definition common.h:220
uint32_t uint
static const uint64_t CELL_GRADPE_TERM
static const uint64_t VEL_BLOCK_PARAMETERS
static const uint64_t CELL_P
static const uint64_t REFINEMENT_PARAMETERS
static const uint64_t CELL_SYSBOUNDARYFLAG
static const uint64_t CELL_BVOL
static const uint64_t CELL_RHOM_V
static const uint64_t CELL_RHOMDT2_VDT2
static const uint64_t POP_METADATA
static const uint64_t VEL_BLOCK_LIST_STAGE2
static const uint64_t CELL_BVOL_DERIVATIVES
static const uint64_t VEL_BLOCK_LIST_STAGE1
static const uint64_t CELL_PDT2
static const uint64_t CELL_IOLOCALCELLID
static const uint64_t VEL_BLOCK_WITH_CONTENT_STAGE1
static const uint64_t VEL_BLOCK_DATA
static const uint64_t CELL_RHOQ
static const uint64_t NEIGHBOR_VEL_BLOCK_DATA
static const uint64_t VEL_BLOCK_WITH_CONTENT_STAGE2
static const uint64_t CELL_PARAMETERS
static const uint64_t CELL_RHOQDT2
static const uint64_t CELL_DIMENSIONS
uint32_t LocalID
Definition definitions.h:60
uint32_t GlobalID
Definition definitions.h:59
static const uint acc_reserve_multiplier
__global__ void resize_vbc_kernel_pre(vmesh::VelocityMesh *vmesh, vmesh::VelocityBlockContainer *blockContainer, const split::SplitVector< vmesh::GlobalID > *__restrict__ list_with_replace_new, const split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > *__restrict__ list_delete, const split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > *__restrict__ list_to_replace, const split::SplitVector< Hashinator::hash_pair< vmesh::GlobalID, vmesh::LocalID > > *__restrict__ list_with_replace_old, vmesh::LocalID *returnLID, Realf *gpu_rhoLossAdjust)
__global__ void update_velocity_halo_kernel(const vmesh::VelocityMesh *__restrict__ vmesh, const vmesh::LocalID velocity_block_with_content_list_size, const vmesh::GlobalID *__restrict__ velocity_block_with_content_list_data, Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > *dev_velocity_block_with_content_map, Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > *dev_velocity_block_with_no_content_map)
__global__ void resize_vbc_kernel_post(vmesh::VelocityMesh *vmesh, vmesh::VelocityBlockContainer *blockContainer, const vmesh::LocalID nBlocksAfterAdjust)
__global__ void update_vmesh_and_blockparameters_kernel(vmesh::VelocityMesh *dev_vmesh, vmesh::VelocityBlockContainer *dev_blockContainer, const vmesh::LocalID nLIDs)
T * getPointer(const size_t &pointerIndex) const
Definition gpu_base.hpp:812
std::vector< species::Species > particleSpecies
static int amrMaxSpatialRefLevel
Definition parameters.h:190