OpenLB 1.7
Loading...
Searching...
No Matches
blockLattice.hh
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2006-2008 Jonas Latt
4 * 2008-2021 Mathias Krause
5 * 2022 Adrian Kummerlaender
6 * E-mail contact: info@openlb.net
7 * The most recent release of OpenLB can be downloaded at
8 * <http://www.openlb.net/>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public
21 * License along with this program; if not, write to the Free
22 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24*/
25
26#ifndef BLOCK_LATTICE_HH
27#define BLOCK_LATTICE_HH
28
29#include "blockLattice.h"
30
31namespace olb {
32
33
34template<typename T, typename DESCRIPTOR>
36 : BlockStructure<DESCRIPTOR>(size, padding),
37 _platform(platform),
38 _statisticsEnabled{true},
39 _statistics{nullptr}
40{ }
41
42template<typename T, typename DESCRIPTOR>
44{
45 if (_statistics) {
46 delete _statistics;
47 }
48}
49
50template<typename T, typename DESCRIPTOR>
52{
53 addPostProcessor(typeid(stage::PostStream), meta::id<StatisticsPostProcessor>());
54
55 // Todo: Move to StatisticsPostProcessor::setup
56 _statistics = new LatticeStatistics<T>;
57 _statistics->initialize();
58
59 setProcessingContext(ProcessingContext::Simulation);
60 postProcess();
61}
62
63template<typename T, typename DESCRIPTOR>
66{
67 if (!indicator.isEmpty()) {
68 T physR[DESCRIPTOR::d] = { };
69 T rhoTmp = T();
70 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
71 if (indicator(loc)) {
72 indicator.getBlockGeometry().getPhysR(physR, loc);
73 rho(&rhoTmp,physR);
74 get(loc).defineRho(rhoTmp);
75 }
76 });
77 }
78}
79
80template<typename T, typename DESCRIPTOR>
83{
84 if (!indicator.isEmpty()) {
85 T physR[DESCRIPTOR::d] = { };
86 T uTmp[DESCRIPTOR::d] = { };
87 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
88 if (indicator(loc)) {
89 indicator.getBlockGeometry().getPhysR(physR, loc);
90 u(uTmp,physR);
91 get(loc).defineU(uTmp);
92 }
93 });
94 }
97template<typename T, typename DESCRIPTOR>
101{
102 if (!indicator.isEmpty()) {
103 T physR[DESCRIPTOR::d] = { };
104 T uTmp[DESCRIPTOR::d] = { };
105 T rhoTmp = T();
106 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
107 if (indicator(loc)) {
108 indicator.getBlockGeometry().getPhysR(physR, loc);
109 rho(&rhoTmp,physR);
110 u(uTmp,physR);
111 get(loc).defineRhoU(rhoTmp,uTmp);
112 }
113 });
114 }
115}
116
117template<typename T, typename DESCRIPTOR>
120{
121 if (!indicator.isEmpty()) {
122 T physR[DESCRIPTOR::d] = { };
123 T pop[DESCRIPTOR::q];
124 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
125 if (indicator(loc)) {
126 indicator.getBlockGeometry().getPhysR(physR, loc);
127 popF(pop,physR);
128 get(loc).definePopulations(pop);
129 }
130 });
131 }
132}
133
134template<typename T, typename DESCRIPTOR>
137{
138 if (!indicator.isEmpty()) {
139 T pop[DESCRIPTOR::q];
140 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
141 if (indicator(loc)) {
142 popF(pop, loc);
143 get(loc).definePopulations(pop);
144 }
145 });
146 }
147}
148
149template<typename T, typename DESCRIPTOR>
150template<typename FIELD>
153{
154 if (!indicator.isEmpty()) {
155 // Don't use FieldD here as long as AnalyticalF is fixed to T
156 std::array<T,DESCRIPTOR::template size<FIELD>()> fieldTmp;
157 T physR[DESCRIPTOR::d] = { };
158 this->forSpatialLocationsParallel([&](LatticeR<DESCRIPTOR::d> loc) {
159 if (indicator(loc)) {
160 indicator.getBlockGeometry().getPhysR(physR, loc);
161 field(fieldTmp.data(), physR);
162 get(loc).template setField<FIELD>(fieldTmp.data());
163 }
164 });
165 }
166}
167
168template<typename T, typename DESCRIPTOR>
169template<typename FIELD>
172{
173 if (!indicator.isEmpty()) {
175 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
176 if (indicator(loc)) {
177 field(fieldTmp.data(), loc.data());
178 get(loc).template setField<FIELD>(fieldTmp);
179 }
180 });
181 }
182}
183
184template<typename T, typename DESCRIPTOR>
185template<typename FIELD>
187 IndicatorF<T,DESCRIPTOR::d>& indicatorF,
189{
190 BlockIndicatorFfromIndicatorF<T,DESCRIPTOR::d> indicator(indicatorF, blockGeometry);
191 defineField<FIELD>(indicator, field);
192}
193
194template<typename T, typename DESCRIPTOR>
198{
199 if (!indicator.isEmpty()) {
200 T physR[DESCRIPTOR::d] = { };
201 T uTmp[DESCRIPTOR::d] = { };
202 T rhoTmp = T();
203 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
204 if (indicator(loc)) {
205 indicator.getBlockGeometry().getPhysR(physR, loc);
206 u(uTmp, physR);
207 rho(&rhoTmp, physR);
208 get(loc).iniEquilibrium(rhoTmp, uTmp);
209 }
210 });
211 }
212}
213
214template<typename T, typename DESCRIPTOR>
218{
219 if (!indicator.isEmpty()) {
220 T physR[DESCRIPTOR::d] = { };
221 T uTmp[DESCRIPTOR::d] = { };
222 T rhoTmp = T();
223 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
224 if (indicator(loc)) {
225 indicator.getBlockGeometry().getPhysR(physR, loc);
226 u(uTmp, loc.data());
227 rho(&rhoTmp, physR);
228 get(loc).iniEquilibrium(rhoTmp, uTmp);
229 }
230 });
231 }
232}
233
234template<typename T, typename DESCRIPTOR>
239{
240 if (!indicator.isEmpty()) {
241 T physR[DESCRIPTOR::d] = { };
242 T uTmp[DESCRIPTOR::d] = { };
243 T rhoTmp = T();
244 T piTmp[util::TensorVal<DESCRIPTOR>::n] = { };
245 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
246 if (indicator(loc)) {
247 indicator.getBlockGeometry().getPhysR(physR, loc);
248 u(uTmp, physR);
249 rho(&rhoTmp, physR);
250 pi(piTmp, physR);
251 get(loc).iniRegularized(rhoTmp, uTmp, piTmp);
252 }
253 });
254 }
255}
256
257template<typename T, typename DESCRIPTOR>
260{
261 if (!indicator.isEmpty()) {
262 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
263 if (indicator(loc)) {
264 defineDynamics(loc, dynamics);
265 }
266 });
267 }
269
270template<typename T, typename DESCRIPTOR>
271template<typename DYNAMICS>
273{
274 if (!indicator.isEmpty()) {
275 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
276 if (indicator(loc)) {
277 setDynamics(this->getCellId(loc),
279 }
280 });
281 }
282}
283
284template<typename T, typename DESCRIPTOR>
286{
287 this->forCellIndices([&](CellID iCell) {
288 setDynamics(iCell, dynamics);
289 });
290}
291
292template<typename T, typename DESCRIPTOR, Platform PLATFORM>
294{
295 if (_customCollisionO) {
296 _customCollisionO->operator()(*this);
297 } else {
298 if constexpr (isPlatformCPU(PLATFORM)) {
299 _dynamicsMap.collide(CollisionDispatchStrategy::Dominant);
300 } else {
301 _dynamicsMap.collide(CollisionDispatchStrategy::Individual);
302 }
303 }
304}
305
306template<typename T, typename DESCRIPTOR, Platform PLATFORM>
308{
309 if constexpr (PLATFORM == Platform::GPU_CUDA) {
310 DESCRIPTOR::template filter<descriptors::is_propagatable_field>
311 ::for_each([&](auto field) {
312 auto& population = getField(field.get());
313 for (unsigned iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
314 population[iPop].rotate(this->getNeighborDistance(descriptors::c<DESCRIPTOR>(iPop)));
315 }
316 // Required for resolving populations in (gather,scatter)_any_fields kernel
317 getDataRegistry().refreshDeviceFieldArray(population);
318 });
319 } else {
320 DESCRIPTOR::template filter<descriptors::is_propagatable_field>
321 ::for_each([&](auto field) {
322 auto& population = getField(field.get());
323 for (unsigned iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
324 population[iPop].rotate(this->getNeighborDistance(descriptors::c<DESCRIPTOR>(iPop)));
325 }
326 });
327 }
328}
329
331
336
337 struct OFFSET : public descriptors::FIELD_BASE<1> { };
339
340 int getPriority() const {
341 return 0;
342 }
343
344 template <typename CELL, typename PARAMETERS>
345 void apply(CELL& cell, PARAMETERS& parameters) any_platform {
346 using V = typename CELL::value_t;
347 using DESCRIPTOR = typename CELL::descriptor_t;
348 auto offset = parameters.template get<OFFSET>();
349 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
350 cell[iPop] -= descriptors::t<V,DESCRIPTOR>(iPop) * offset;
351 }
352 }
353};
354
355template<typename T, typename DESCRIPTOR>
357{
358 if (!hasPostProcessor(typeid(StripeOffDensityOffsetO),
360 addPostProcessor(typeid(StripeOffDensityOffsetO),
362 }
363 // Update offset and execute
364 getData<OperatorParameters<StripeOffDensityOffsetO>>()
365 .template set<StripeOffDensityOffsetO::OFFSET>(offset);
366 postProcess(typeid(StripeOffDensityOffsetO));
367}
368
369template<typename T, typename DESCRIPTOR>
371 std::vector<BlockStructureD<DESCRIPTOR::d>*> partners)
372{
373 addPostProcessor<stage::Coupling>(lcGen.generate(partners));
374}
375
376template<typename T, typename DESCRIPTOR>
379 std::vector<BlockStructureD<DESCRIPTOR::d>*> partners)
381 if (!indicator.isEmpty()) {
382 this->forSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
383 if (this->getNeighborhoodRadius(loc) >= 1) {
384 if (indicator(loc)) {
385 std::unique_ptr<LatticeCouplingGenerator<T,DESCRIPTOR>> extractedLcGen{ lcGen.clone() };
386 if (extractedLcGen->extract(0, 0)) {
387 extractedLcGen->shift(loc);
388 addLatticeCoupling(*extractedLcGen, partners);
389 }
391 }
392 });
393 }
394}
395
396template<typename T, typename DESCRIPTOR>
399 postProcess<stage::Coupling>();
400}
401
402template<typename T, typename DESCRIPTOR>
408template<typename T, typename DESCRIPTOR>
410{
411 return *_statistics;
412}
413
414
415template<typename T, typename DESCRIPTOR, Platform PLATFORM>
417 : BlockLattice<T,DESCRIPTOR>(size, padding, PLATFORM),
418 _data(),
419 _descriptorFields(),
420 _dynamicsMap(*this)
422 DESCRIPTOR::fields_t::template for_each([&](auto id) {
423 using field = typename decltype(id)::type;
424 using field_type = Array<field>;
425 auto& fieldArray = _data.template allocate<field_type>(this->getNcells());
426 _descriptorFields.template set<field>(&fieldArray);
427 _communicatables[typeid(field)] = std::unique_ptr<Communicatable>(new ConcreteCommunicatable<
428 ColumnVector<typename ImplementationOf<typename field::template column_type<T>,PLATFORM>::type,
429 DESCRIPTOR::template size<field>()>
430 >(fieldArray));
431 _data.template setSerialization<field_type>(true);
432 });
433
435 for (CellID iCell=0; iCell < this->getNcells(); ++iCell) {
436 _dynamicsMap.set(iCell, noDynamics);
437 }
438}
439
440template<typename T, typename DESCRIPTOR, Platform PLATFORM>
441template<typename FIELD_TYPE>
443{
444 return _data.template provides<FIELD_TYPE>();
445}
446
447template<typename T, typename DESCRIPTOR, Platform PLATFORM>
448template<typename FIELD_TYPE>
450{
451 OLB_ASSERT(_data.template provides<FIELD_TYPE>(),
452 "FIELD_TYPE must be allocated to be accessed");
453 return _data.template get<FIELD_TYPE>();
454}
455
456template<typename T, typename DESCRIPTOR, Platform PLATFORM>
457template<typename FIELD_TYPE>
459{
460 if (_data.template provides<FIELD_TYPE>()) {
461 return _data.template get<FIELD_TYPE>();
462 } else {
463 // TODO: Implement more generic approach to constructing arbitrary data from specific args
464 auto& data = _data.template allocate<FIELD_TYPE>(this->getNcells());
465 // Manage serializables and communicatables for array fields
466 using concrete_data_t = typename FIELD_TYPE::template type<T,DESCRIPTOR,PLATFORM>;
467 if constexpr (std::is_base_of_v<ColumnVectorBase,concrete_data_t>) {
468 using field_t = typename concrete_data_t::field_t;
469 if constexpr (field_t::isSerializable()) {
470 _data.template setSerialization<FIELD_TYPE>(true);
471 }
472 _communicatables[typeid(field_t)] = std::unique_ptr<Communicatable>(new ConcreteCommunicatable<
473 ColumnVector<typename ImplementationOf<typename field_t::template column_type<T>,PLATFORM>::type,
474 DESCRIPTOR::template size<field_t>()>
475 >(data));
476 }
477 return data;
478 }
479 __builtin_unreachable();
480}
481
482template<typename T, typename DESCRIPTOR, Platform PLATFORM>
483template<typename FIELD>
485{
486 if constexpr (DESCRIPTOR::fields_t::template contains<FIELD>()) {
487 return static_cast<FieldArrayD<T,DESCRIPTOR,PLATFORM,FIELD>&>(*_descriptorFields.template get<FIELD>());
488 } else {
489 return getData<Array<FIELD>>();
490 }
491 __builtin_unreachable();
492}
493
494template<typename T, typename DESCRIPTOR, Platform PLATFORM>
495template<typename FIELD>
498 if constexpr (DESCRIPTOR::fields_t::template contains<FIELD>()) {
499 return static_cast<const FieldArrayD<T,DESCRIPTOR,PLATFORM,FIELD>&>(*_descriptorFields.template get<FIELD>());
500 } else {
501 return getData<Array<FIELD>>();
502 }
503 __builtin_unreachable();
505
506template<typename T, typename DESCRIPTOR, Platform PLATFORM>
508 std::type_index stage, PostProcessor<T,DESCRIPTOR>* postProcessor)
509{
510 auto [postProcessorsOfPriority, _] = _postProcessors[stage].try_emplace(postProcessor->getPriority(), this);
511 std::get<1>(*postProcessorsOfPriority).addLegacy(postProcessor);
512}
514template<typename T, typename DESCRIPTOR, Platform PLATFORM>
516 std::type_index stage, const PostProcessorGenerator<T,DESCRIPTOR>& ppGen)
517{
518 addPostProcessor(stage, ppGen.generate());
519}
520
521template<typename T, typename DESCRIPTOR, Platform PLATFORM>
523 std::type_index stage, BlockIndicatorF<T,DESCRIPTOR::d>& indicator, const PostProcessorGenerator<T,DESCRIPTOR>& ppGen)
524{
525 if (!indicator.isEmpty()) {
526 this->forCoreSpatialLocations([&](LatticeR<DESCRIPTOR::d> loc) {
527 if (indicator(loc)) {
528 std::unique_ptr<PostProcessorGenerator<T,DESCRIPTOR>> extractedPpGen{ ppGen.clone() };
529 if (extractedPpGen->extract(0, 0)) {
530 extractedPpGen->shift(loc);
531 addPostProcessor(stage, *extractedPpGen);
532 }
534 });
535 }
536}
537
538template<typename T, typename DESCRIPTOR, Platform PLATFORM>
540{
541 for (auto& [_, postProcessorsOfPriority] : _postProcessors[stage]) {
542 postProcessorsOfPriority.apply();
543 }
544}
545
546template<typename T, typename DESCRIPTOR, Platform PLATFORM>
548{
549 return _data.getNblock();
550}
551
552template<typename T, typename DESCRIPTOR, Platform PLATFORM>
554{
555 return _data.getSerializableSize();
556}
557
558template<typename T, typename DESCRIPTOR, Platform PLATFORM>
559bool* ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>::getBlock(std::size_t iBlock, std::size_t& sizeBlock, bool loadingMode)
560{
561 std::size_t currentBlock = 0;
562 bool* dataPtr = nullptr;
563
564 this->registerSerializableOfConstSize(iBlock, sizeBlock, currentBlock, dataPtr, _data, loadingMode);
565
566 return dataPtr;
567}
568
569template<typename T, typename DESCRIPTOR, Platform PLATFORM>
571{
572 auto& population = getField<descriptors::POPULATION>();
573 for (unsigned iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
574 population[iPop].postLoad();
575 }
576}
577
578
579#ifdef PARALLEL_MODE_MPI
580
582template <typename T, typename DESCRIPTOR, Platform PLATFORM>
583class ConcreteBlockCommunicator<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>::SendTask {
584private:
585 const std::vector<CellID>& _cells;
586
588
589 std::unique_ptr<std::uint8_t[]> _buffer;
590 MpiSendRequest _request;
591
592public:
593 SendTask(MPI_Comm comm, int tag, int rank,
594 const std::vector<std::type_index>& fields,
595 const std::vector<CellID>& cells,
597 _cells(cells),
598 _source(block, fields),
599 _buffer(new std::uint8_t[_source.size(_cells)] { }),
600 _request(_buffer.get(), _source.size(_cells),
601 rank, tag, comm)
602 { }
603
604 void send()
605 {
606 _source.serialize(_cells, _buffer.get());
607 _request.start();
608 }
609
610 void wait()
611 {
612 _request.wait();
613 }
614};
615
617template <typename T, typename DESCRIPTOR, Platform PLATFORM>
618class ConcreteBlockCommunicator<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>::RecvTask {
619private:
620 const int _tag;
621 const int _rank;
622 const std::vector<CellID>& _cells;
623
625
626 std::unique_ptr<std::uint8_t[]> _buffer;
627 MpiRecvRequest _request;
628
629public:
631
638 class ref {
639 private:
640 RecvTask& _task;
641 public:
642 ref(std::unique_ptr<RecvTask>& task): _task(*task) { };
643
644 RecvTask* operator->() const
645 {
646 return &_task;
647 }
648
649 bool operator <(const ref& rhs) const
651 return _task < rhs._task;
652 }
653 };
654
655 RecvTask(MPI_Comm comm, int tag, int rank,
656 const std::vector<std::type_index>& fields,
657 const std::vector<CellID>& cells,
659 _tag(tag),
660 _rank(rank),
661 _cells(cells),
662 _target(block, fields),
663 _buffer(new std::uint8_t[_target.size(_cells)] { }),
664 _request(_buffer.get(), _target.size(_cells),
665 _rank, _tag, comm)
666 { }
667
668 bool operator<(const RecvTask& rhs) const
669 {
670 return _rank < rhs._rank
671 || (_rank == rhs._rank && _tag < rhs._tag);
672 }
673
674 void receive()
675 {
676 _request.start();
677 };
679 bool isDone()
681 return _request.isDone();
683
684 void unpack()
685 {
686 _target.deserialize(_cells, _buffer.get());
687 }
688};
689
690#endif // PARALLEL_MODE_MPI
691
693template <typename T, typename DESCRIPTOR, Platform PLATFORM>
694struct ConcreteBlockCommunicator<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>::CopyTask {
695 virtual ~CopyTask() { }
696
697 virtual void copy() = 0;
698 virtual void wait() = 0;
699};
700
702template <typename T, typename DESCRIPTOR, Platform PLATFORM>
703class ConcreteBlockCommunicator<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>::HomogeneousCopyTask
704 : public ConcreteBlockCommunicator<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>::CopyTask {
705private:
706 const std::vector<CellID>& _targetCells;
707 const std::vector<CellID>& _sourceCells;
708
711
712 std::unique_ptr<std::uint8_t[]> _buffer;
713
714public:
716 const std::vector<std::type_index>& fields,
717 const std::vector<CellID>& targetCells, ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>& target,
718 const std::vector<CellID>& sourceCells, ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>& source):
719 _targetCells(targetCells),
720 _sourceCells(sourceCells),
721 _target(target, fields),
722 _source(source, fields),
723 _buffer(new std::uint8_t[_source.size(_sourceCells)] { })
724 {
725 OLB_ASSERT(_sourceCells.size() == _targetCells.size(),
726 "Source cell count must match target cell count");
727 }
728
729 void copy() override
730 {
731 _source.serialize(_sourceCells, _buffer.get());
732 _target.deserialize(_targetCells, _buffer.get());
733 };
734
735 void wait() override { }
736
737};
738
739
740template <typename T, typename DESCRIPTOR, Platform PLATFORM>
743 LoadBalancer<T>& loadBalancer,
744#ifdef PARALLEL_MODE_MPI
746 MPI_Comm comm,
747#endif
748 int iC,
750 _iC(iC)
751#ifdef PARALLEL_MODE_MPI
752, _mpiCommunicator(comm)
753#endif
754{
755#ifdef PARALLEL_MODE_MPI
756 neighborhood.forNeighbors([&](int remoteC) {
757 if (loadBalancer.isLocal(remoteC)) {
758 const Platform remotePlatform = loadBalancer.platform(loadBalancer.loc(remoteC));
759 if (!neighborhood.getCellsInboundFrom(remoteC).empty()) {
760 switch (remotePlatform) {
761#ifdef PLATFORM_GPU_CUDA
762 case Platform::GPU_CUDA:
763 // Use manual copy for local GPU-CPU communication due to better performance
764 _copyTasks.emplace_back(new HeterogeneousCopyTask<T,DESCRIPTOR,Platform::GPU_CUDA,PLATFORM>(
765 neighborhood.getFieldsCommonWith(remoteC),
766 neighborhood.getCellsInboundFrom(remoteC), super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(_iC),
767 neighborhood.getCellsRequestedFrom(remoteC), super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,Platform::GPU_CUDA>>(loadBalancer.loc(remoteC))));
768 break;
769#endif
770 default:
771 // Use manual copy for local CPU-CPU communication due to better performance
772 _copyTasks.emplace_back(new HomogeneousCopyTask(
773 neighborhood.getFieldsCommonWith(remoteC),
774 neighborhood.getCellsInboundFrom(remoteC), super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(_iC),
775 neighborhood.getCellsRequestedFrom(remoteC), super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(loadBalancer.loc(remoteC))));
776 break;
777 }
778 }
779 } else {
780 if (!neighborhood.getCellsOutboundTo(remoteC).empty()) {
781 _sendTasks.emplace_back(std::make_unique<SendTask>(
782 _mpiCommunicator, tagCoordinator.get(loadBalancer.glob(_iC), remoteC),
783 loadBalancer.rank(remoteC),
784 neighborhood.getFieldsCommonWith(remoteC),
785 neighborhood.getCellsOutboundTo(remoteC),
786 super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(_iC)));
787 }
788 if (!neighborhood.getCellsInboundFrom(remoteC).empty()) {
789 _recvTasks.emplace_back(std::make_unique<RecvTask>(
790 _mpiCommunicator, tagCoordinator.get(remoteC, loadBalancer.glob(_iC)),
791 loadBalancer.rank(remoteC),
792 neighborhood.getFieldsCommonWith(remoteC),
793 neighborhood.getCellsInboundFrom(remoteC),
794 super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(_iC)));
795 }
796 }
797 });
798
799#else // not using PARALLEL_MODE_MPI
800 neighborhood.forNeighbors([&](int localC) {
801 if (!neighborhood.getCellsInboundFrom(localC).empty()) {
802 _copyTasks.emplace_back(new HomogeneousCopyTask(
803 neighborhood.getFieldsCommonWith(localC),
804 neighborhood.getCellsInboundFrom(localC), super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(_iC),
805 neighborhood.getCellsRequestedFrom(localC), super.template getBlock<ConcreteBlockLattice<T,DESCRIPTOR,PLATFORM>>(loadBalancer.loc(localC))));
806 }
807 });
808#endif
809}
810
811template <typename T, typename DESCRIPTOR, Platform PLATFORM>
814
815#ifdef PARALLEL_MODE_MPI
816
817template <typename T, typename DESCRIPTOR, Platform PLATFORM>
819{
820 for (auto& task : _recvTasks) {
821 task->receive();
822 }
823}
824
825template <typename T, typename DESCRIPTOR, Platform PLATFORM>
827{
828 for (auto& task : _sendTasks) {
829 task->send();
830 }
831 for (auto& task : _copyTasks) {
832 task->copy();
833 }
834}
835
836template <typename T, typename DESCRIPTOR, Platform PLATFORM>
838{
839 std::set<typename RecvTask::ref> pending(_recvTasks.begin(), _recvTasks.end());
840 while (!pending.empty()) {
841 auto task_iterator = pending.begin();
842 while (task_iterator != pending.end()) {
843 auto& task = *task_iterator;
844 if (task->isDone()) {
845 task->unpack();
846 task_iterator = pending.erase(task_iterator);
847 }
848 else {
849 ++task_iterator;
850 }
851 }
852 }
853}
854
855template <typename T, typename DESCRIPTOR, Platform PLATFORM>
857{
858 for (auto& task : _copyTasks) {
859 task->wait();
860 }
861 for (auto& task : _sendTasks) {
862 task->wait();
863 }
864}
865
866#else // not using PARALLEL_MODE_MPI
867
868template <typename T, typename DESCRIPTOR, Platform PLATFORM>
870{
871 for (auto& task : _copyTasks) {
872 task->copy();
873 }
874}
875
876#endif
877
878}
879
880#endif
AnalyticalF are applications from DD to XD, where X is set by the constructor.
Configurable overlap communication neighborhood of a block.
const std::vector< CellID > & getCellsOutboundTo(int iC) const
const std::vector< CellID > & getCellsInboundFrom(int iC) const
void forNeighbors(F f) const
Calls f(iC) for every neighboring cuboid ID iC.
Representation of a block geometry.
Platform-abstracted block lattice for external access and inter-block interaction.
void addLatticeCoupling(LatticeCouplingGenerator< T, DESCRIPTOR > const &lcGen, std::vector< BlockStructureD< DESCRIPTOR::d > * > partners)
Add a non-local post-processing step (legacy)
void iniEquilibrium(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &rho, AnalyticalF< DESCRIPTOR::d, T, T > &u)
Initialize by equilibrium on a domain described by an indicator.
BlockLattice(Vector< int, DESCRIPTOR::d > size, int padding, Platform platform)
void defineRho(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &rho)
Define rho on a domain described by an indicator.
void defineRhoU(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &rho, AnalyticalF< DESCRIPTOR::d, T, T > &u)
Define rho and u on a domain described by an indicator.
void postProcess()
Execute post processors of STAGE.
void defineU(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &u)
Define u on a domain described by an indicator.
void iniRegularized(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &rho, AnalyticalF< DESCRIPTOR::d, T, T > &u, AnalyticalF< DESCRIPTOR::d, T, T > &pi)
Initialize by non- and equilibrium on a domain described by an indicator.
void defineDynamics(LatticeR< DESCRIPTOR::d > latticeR, DynamicsPromise< T, DESCRIPTOR > &&promise)
Assign promised DYNAMICS to latticeR.
void defineField(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &field)
Define a field on a domain described by an indicator.
virtual ~BlockLattice()
void stripeOffDensityOffset(T offset)
Subtract the given offset from all densities.
void initialize()
Initialize the lattice cells to become ready for simulation.
void executeCoupling()
Execute couplings steps (legacy)
void definePopulations(BlockIndicatorF< T, DESCRIPTOR::d > &indicator, AnalyticalF< DESCRIPTOR::d, T, T > &Pop)
Define a population on a domain described by an indicator.
LatticeStatistics< T > & getStatistics()
Return a handle to the LatticeStatistics object.
Base of a regular block.
Vector of columns.
HomogeneousCopyTask(const std::vector< std::type_index > &fields, const std::vector< CellID > &targetCells, ConcreteBlockLattice< T, DESCRIPTOR, PLATFORM > &target, const std::vector< CellID > &sourceCells, ConcreteBlockLattice< T, DESCRIPTOR, PLATFORM > &source)
RecvTask(MPI_Comm comm, int tag, int rank, const std::vector< std::type_index > &fields, const std::vector< CellID > &cells, ConcreteBlockLattice< T, DESCRIPTOR, PLATFORM > &block)
SendTask(MPI_Comm comm, int tag, int rank, const std::vector< std::type_index > &fields, const std::vector< CellID > &cells, ConcreteBlockLattice< T, DESCRIPTOR, PLATFORM > &block)
Implementation of BlockLattice on a concrete PLATFORM.
const auto & getData() const
void collide() override
Apply collision step of non-overlap interior.
void postLoad() override
Reinit population structure after deserialization.
bool * getBlock(std::size_t iBlock, std::size_t &sizeBlock, bool loadingMode) override
Return a pointer to the memory of the current block and its size for the serializable interface.
std::size_t getNblock() const override
Number of data blocks for the serializable interface.
ConcreteBlockLattice(Vector< int, DESCRIPTOR::d > size, int padding=0)
void stream() override
Perform propagation step on the whole block.
std::size_t getSerializableSize() const override
Binary size for the serializer.
void addPostProcessor(std::type_index stage, LatticeR< DESCRIPTOR::d > latticeR, PostProcessorPromise< T, DESCRIPTOR > &&promise) override
Schedule post processor for application to latticeR in stage.
const auto & getField(FIELD field=FIELD()) const
SoA storage for instances of a single FIELD.
Base class for all LoadBalancer.
bool isLocal(const int &glob)
returns whether glob is on this process
Non-blocking MPI receive request.
Definition mpiRequest.h:77
Non-blocking MPI send request.
Definition mpiRequest.h:57
std::size_t serialize(ConstSpan< CellID > indices, std::uint8_t *buffer) const override
Serialize data at locations indices to buffer
std::size_t size(ConstSpan< CellID > indices) const override
Get serialized size for data at locations indices
std::size_t deserialize(ConstSpan< CellID > indices, const std::uint8_t *buffer) override
Deserialize data at locations indices to buffer
Communication-free negotation of unique tags for inter-cuboid communication.
Super class maintaining block lattices for a cuboid decomposition.
Plain old scalar vector.
Definition vector.h:47
constexpr const T * data() const any_platform
Definition vector.h:161
Top level namespace for all of OpenLB.
std::uint32_t CellID
Type for sequential block-local cell indices.
@ Simulation
Data available on host for e.g. functor evaluation.
std::conditional_t< D==2, BlockF2D< T >, BlockF3D< T > > BlockF
Definition aliases.h:188
std::conditional_t< DESCRIPTOR::d==2, LatticeCouplingGenerator2D< T, DESCRIPTOR >, LatticeCouplingGenerator3D< T, DESCRIPTOR > > LatticeCouplingGenerator
Definition aliases.h:168
Platform
OpenLB execution targets.
Definition platform.h:36
@ GPU_CUDA
Vector CPU (AVX2 / AVX-512 collision)
std::conditional_t< D==2, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
Definition aliases.h:218
constexpr bool isPlatformCPU(Platform platform)
Returns true if platform is equal to Platform::CPU_*.
Definition platform.h:154
@ Individual
Apply all dynamics individually (async for Platform::GPU_CUDA)
@ Dominant
Apply dominant dynamics using mask and fallback to virtual dispatch for others.
std::conditional_t< D==2, IndicatorF2D< T >, IndicatorF3D< T > > IndicatorF
Definition aliases.h:258
std::conditional_t< D==2, BlockIndicatorFfromIndicatorF2D< T >, BlockIndicatorFfromIndicatorF3D< T > > BlockIndicatorFfromIndicatorF
Definition aliases.h:248
DynamicsPromise(meta::id< DYNAMICS >) -> DynamicsPromise< typename DYNAMICS::value_t, typename DYNAMICS::descriptor_t >
std::conditional_t< DESCRIPTOR::d==2, PostProcessor2D< T, DESCRIPTOR >, PostProcessor3D< T, DESCRIPTOR > > PostProcessor
Definition aliases.h:67
OperatorScope
Block-wide operator application scopes.
Definition operator.h:54
@ PerCellWithParameters
Per-cell application with parameters, i.e. OPERATOR::apply is passed a CELL concept implementation an...
std::conditional_t< DESCRIPTOR::d==2, PostProcessorGenerator2D< T, DESCRIPTOR >, PostProcessorGenerator3D< T, DESCRIPTOR > > PostProcessorGenerator
Definition aliases.h:77
#define OLB_ASSERT(COND, MESSAGE)
Definition olbDebug.h:45
#define any_platform
Define preprocessor macros for device-side functions, constant storage.
Definition platform.h:78
Describe FieldArray of a FIELD in Data.
Definition data.h:42
Interface for per-cell dynamics.
Definition interface.h:54
Specializable declarator for concrete implementations of abstract storage types.
Definition column.h:52
Operator for striping off density offset.
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
Base of a field whose size is defined by [C,U_1,...,U_N]^T * [1,V_1,...V_N].
Dynamics constructed as a tuple of momenta, equilibrium and collision.
Definition interface.h:182
Identity type to pass non-constructible types as value.
Definition meta.h:79
Plain wrapper for list of types.
Definition meta.h:276
Communication after propagation.
Definition stages.h:36
Compute number of elements of a symmetric d-dimensional tensor.
Definition util.h:210