26#ifndef BLOCK_LATTICE_HH
27#define BLOCK_LATTICE_HH
34template<
typename T,
typename DESCRIPTOR>
38 _statisticsEnabled{true},
42template<
typename T,
typename DESCRIPTOR>
50template<
typename T,
typename DESCRIPTOR>
63template<
typename T,
typename DESCRIPTOR>
67 if (!indicator.isEmpty()) {
68 T physR[DESCRIPTOR::d] = { };
72 indicator.getBlockGeometry().getPhysR(physR, loc);
74 get(loc).defineRho(rhoTmp);
80template<
typename T,
typename DESCRIPTOR>
84 if (!indicator.isEmpty()) {
85 T physR[DESCRIPTOR::d] = { };
86 T uTmp[DESCRIPTOR::d] = { };
89 indicator.getBlockGeometry().getPhysR(physR, loc);
91 get(loc).defineU(uTmp);
97template<
typename T,
typename DESCRIPTOR>
102 if (!indicator.isEmpty()) {
103 T physR[DESCRIPTOR::d] = { };
104 T uTmp[DESCRIPTOR::d] = { };
107 if (indicator(loc)) {
108 indicator.getBlockGeometry().getPhysR(physR, loc);
111 get(loc).defineRhoU(rhoTmp,uTmp);
117template<
typename T,
typename DESCRIPTOR>
121 if (!indicator.isEmpty()) {
122 T physR[DESCRIPTOR::d] = { };
123 T pop[DESCRIPTOR::q];
125 if (indicator(loc)) {
126 indicator.getBlockGeometry().getPhysR(physR, loc);
128 get(loc).definePopulations(pop);
134template<
typename T,
typename DESCRIPTOR>
138 if (!indicator.isEmpty()) {
139 T pop[DESCRIPTOR::q];
141 if (indicator(loc)) {
143 get(loc).definePopulations(pop);
149template<
typename T,
typename DESCRIPTOR>
150template<
typename FIELD>
154 if (!indicator.isEmpty()) {
156 std::array<T,DESCRIPTOR::template size<FIELD>()> fieldTmp;
157 T physR[DESCRIPTOR::d] = { };
159 if (indicator(loc)) {
160 indicator.getBlockGeometry().getPhysR(physR, loc);
161 field(fieldTmp.data(), physR);
162 get(loc).template setField<FIELD>(fieldTmp.data());
168template<
typename T,
typename DESCRIPTOR>
169template<
typename FIELD>
173 if (!indicator.isEmpty()) {
176 if (indicator(loc)) {
178 get(loc).template setField<FIELD>(fieldTmp);
184template<
typename T,
typename DESCRIPTOR>
185template<
typename FIELD>
191 defineField<FIELD>(indicator, field);
194template<
typename T,
typename DESCRIPTOR>
199 if (!indicator.isEmpty()) {
200 T physR[DESCRIPTOR::d] = { };
201 T uTmp[DESCRIPTOR::d] = { };
204 if (indicator(loc)) {
205 indicator.getBlockGeometry().getPhysR(physR, loc);
208 get(loc).iniEquilibrium(rhoTmp, uTmp);
214template<
typename T,
typename DESCRIPTOR>
219 if (!indicator.isEmpty()) {
220 T physR[DESCRIPTOR::d] = { };
221 T uTmp[DESCRIPTOR::d] = { };
224 if (indicator(loc)) {
225 indicator.getBlockGeometry().getPhysR(physR, loc);
228 get(loc).iniEquilibrium(rhoTmp, uTmp);
234template<
typename T,
typename DESCRIPTOR>
240 if (!indicator.isEmpty()) {
241 T physR[DESCRIPTOR::d] = { };
242 T uTmp[DESCRIPTOR::d] = { };
246 if (indicator(loc)) {
247 indicator.getBlockGeometry().getPhysR(physR, loc);
251 get(loc).iniRegularized(rhoTmp, uTmp, piTmp);
257template<
typename T,
typename DESCRIPTOR>
261 if (!indicator.isEmpty()) {
263 if (indicator(loc)) {
264 defineDynamics(loc, dynamics);
270template<
typename T,
typename DESCRIPTOR>
271template<
typename DYNAMICS>
274 if (!indicator.isEmpty()) {
276 if (indicator(loc)) {
277 setDynamics(this->getCellId(loc),
284template<
typename T,
typename DESCRIPTOR>
287 this->forCellIndices([&](
CellID iCell) {
288 setDynamics(iCell, dynamics);
292template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
295 if (_customCollisionO) {
296 _customCollisionO->operator()(*this);
306template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
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)));
317 getDataRegistry().refreshDeviceFieldArray(population);
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)));
344 template <
typename CELL,
typename PARAMETERS>
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;
355template<
typename T,
typename DESCRIPTOR>
364 getData<OperatorParameters<StripeOffDensityOffsetO>>()
365 .
template set<StripeOffDensityOffsetO::OFFSET>(offset);
369template<
typename T,
typename DESCRIPTOR>
373 addPostProcessor<stage::Coupling>(lcGen.generate(partners));
376template<
typename T,
typename DESCRIPTOR>
381 if (!indicator.isEmpty()) {
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);
396template<
typename T,
typename DESCRIPTOR>
399 postProcess<stage::Coupling>();
402template<
typename T,
typename DESCRIPTOR>
408template<
typename T,
typename DESCRIPTOR>
415template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
422 DESCRIPTOR::fields_t::template for_each([&](
auto id) {
423 using field =
typename decltype(id)::type;
425 auto& fieldArray = _data.template allocate<field_type>(this->getNcells());
426 _descriptorFields.template set<field>(&fieldArray);
429 DESCRIPTOR::template size<field>()>
431 _data.template setSerialization<field_type>(
true);
435 for (
CellID iCell=0; iCell < this->getNcells(); ++iCell) {
436 _dynamicsMap.set(iCell, noDynamics);
440template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
441template<
typename FIELD_TYPE>
444 return _data.template provides<FIELD_TYPE>();
447template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
448template<
typename FIELD_TYPE>
451 OLB_ASSERT(_data.template provides<FIELD_TYPE>(),
452 "FIELD_TYPE must be allocated to be accessed");
453 return _data.template get<FIELD_TYPE>();
456template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
457template<
typename FIELD_TYPE>
460 if (_data.template provides<FIELD_TYPE>()) {
461 return _data.template get<FIELD_TYPE>();
464 auto& data = _data.template allocate<FIELD_TYPE>(this->getNcells());
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);
474 DESCRIPTOR::template size<field_t>()>
479 __builtin_unreachable();
482template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
483template<
typename FIELD>
486 if constexpr (DESCRIPTOR::fields_t::template contains<FIELD>()) {
489 return getData<Array<FIELD>>();
491 __builtin_unreachable();
494template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
495template<
typename FIELD>
498 if constexpr (DESCRIPTOR::fields_t::template contains<FIELD>()) {
501 return getData<Array<FIELD>>();
503 __builtin_unreachable();
506template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
510 auto [postProcessorsOfPriority, _] = _postProcessors[stage].try_emplace(postProcessor->getPriority(),
this);
511 std::get<1>(*postProcessorsOfPriority).addLegacy(postProcessor);
514template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
518 addPostProcessor(stage, ppGen.generate());
521template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
525 if (!indicator.isEmpty()) {
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);
538template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
541 for (
auto& [_, postProcessorsOfPriority] : _postProcessors[stage]) {
542 postProcessorsOfPriority.apply();
546template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
549 return _data.getNblock();
552template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
555 return _data.getSerializableSize();
558template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
561 std::size_t currentBlock = 0;
562 bool* dataPtr =
nullptr;
564 this->registerSerializableOfConstSize(iBlock, sizeBlock, currentBlock, dataPtr, _data, loadingMode);
569template<
typename T,
typename DESCRIPTOR, Platform PLATFORM>
572 auto& population = getField<descriptors::POPULATION>();
573 for (
unsigned iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
574 population[iPop].postLoad();
579#ifdef PARALLEL_MODE_MPI
582template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
585 const std::vector<CellID>& _cells;
589 std::unique_ptr<std::uint8_t[]> _buffer;
594 const std::vector<std::type_index>& fields,
595 const std::vector<CellID>& cells,
598 _source(block, fields),
599 _buffer(new std::uint8_t[_source.size(_cells)] { }),
600 _request(_buffer.get(), _source.
size(_cells),
606 _source.
serialize(_cells, _buffer.get());
617template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
622 const std::vector<CellID>& _cells;
626 std::unique_ptr<std::uint8_t[]> _buffer;
642 ref(std::unique_ptr<RecvTask>& task): _task(*task) { };
649 bool operator <(
const ref& rhs)
const
651 return _task < rhs._task;
656 const std::vector<std::type_index>& fields,
657 const std::vector<CellID>& cells,
662 _target(block, fields),
663 _buffer(new std::uint8_t[_target.size(_cells)] { }),
664 _request(_buffer.get(), _target.
size(_cells),
670 return _rank < rhs._rank
671 || (_rank == rhs._rank && _tag < rhs._tag);
693template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
702template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
706 const std::vector<CellID>& _targetCells;
707 const std::vector<CellID>& _sourceCells;
712 std::unique_ptr<std::uint8_t[]> _buffer;
716 const std::vector<std::type_index>& fields,
719 _targetCells(targetCells),
720 _sourceCells(sourceCells),
721 _target(target, fields),
722 _source(source, fields),
723 _buffer(new std::uint8_t[_source.size(_sourceCells)] { })
725 OLB_ASSERT(_sourceCells.size() == _targetCells.size(),
726 "Source cell count must match target cell count");
731 _source.
serialize(_sourceCells, _buffer.get());
740template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
744#ifdef PARALLEL_MODE_MPI
751#ifdef PARALLEL_MODE_MPI
752, _mpiCommunicator(comm)
755#ifdef PARALLEL_MODE_MPI
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:
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))));
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))));
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)));
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)));
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))));
811template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
815#ifdef PARALLEL_MODE_MPI
817template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
820 for (
auto& task : _recvTasks) {
825template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
828 for (
auto& task : _sendTasks) {
831 for (
auto& task : _copyTasks) {
836template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
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()) {
846 task_iterator = pending.erase(task_iterator);
855template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
858 for (
auto& task : _copyTasks) {
861 for (
auto& task : _sendTasks) {
868template <
typename T,
typename DESCRIPTOR, Platform PLATFORM>
871 for (
auto& task : _copyTasks) {
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.
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.
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)
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.
Non-blocking MPI send request.
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.
constexpr const T * data() const any_platform
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
std::conditional_t< DESCRIPTOR::d==2, LatticeCouplingGenerator2D< T, DESCRIPTOR >, LatticeCouplingGenerator3D< T, DESCRIPTOR > > LatticeCouplingGenerator
Platform
OpenLB execution targets.
@ GPU_CUDA
Vector CPU (AVX2 / AVX-512 collision)
std::conditional_t< D==2, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
constexpr bool isPlatformCPU(Platform platform)
Returns true if platform is equal to Platform::CPU_*.
@ 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
std::conditional_t< D==2, BlockIndicatorFfromIndicatorF2D< T >, BlockIndicatorFfromIndicatorF3D< T > > BlockIndicatorFfromIndicatorF
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
OperatorScope
Block-wide operator application scopes.
@ 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
#define OLB_ASSERT(COND, MESSAGE)
Describe FieldArray of a FIELD in Data.
Interface for per-cell dynamics.
Specializable declarator for concrete implementations of abstract storage types.
Operator for striping off density offset.
void apply(CELL &cell, PARAMETERS ¶meters) 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.
Communication after propagation.
Compute number of elements of a symmetric d-dimensional tensor.