ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
EKinWalberlaImpl.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022-2023 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <blockforest/communication/UniformBufferedScheme.h>
23#include <field/AddToStorage.h>
24#include <field/FlagField.h>
25#include <field/FlagUID.h>
26#include <field/GhostLayerField.h>
27#include <field/communication/PackInfo.h>
28#include <field/vtk/FlagFieldCellFilter.h>
29#include <field/vtk/VTKWriter.h>
30#include <stencil/D3Q27.h>
31#if defined(__CUDACC__)
32#include <gpu/AddGPUFieldToStorage.h>
33#include <gpu/HostFieldAllocator.h>
34#include <gpu/communication/MemcpyPackInfo.h>
35#include <gpu/communication/UniformGPUScheme.h>
36#endif
37
38#include "../BoundaryHandling.hpp"
39#include "../BoundaryPackInfo.hpp"
40#include "../utils/boundary.hpp"
41#include "../utils/types_conversion.hpp"
42#include "ek_kernels.hpp"
43#if defined(__CUDACC__)
44#include "ek_kernels.cuh"
45#endif
46
51
52#include <utils/Vector.hpp>
53
54#include <cstddef>
55#include <iterator>
56#include <memory>
57#include <optional>
58#include <stdexcept>
59#include <string>
60#include <type_traits>
61#include <variant>
62#include <vector>
63
64namespace walberla {
65
66/** @brief Class that runs and controls the EK on waLBerla. */
67template <std::size_t FluxCount = 13, typename FloatType = double,
68 lbmpy::Arch Architecture = lbmpy::Arch::CPU>
70 using ContinuityKernel =
72 using DiffusiveFluxKernelUnthermalized =
73 typename detail::KernelTrait<FloatType,
74 Architecture>::DiffusiveFluxKernel;
75 using DiffusiveFluxKernelThermalized = typename detail::KernelTrait<
76 FloatType, Architecture>::DiffusiveFluxKernelThermalized;
77 using AdvectiveFluxKernel =
78 typename detail::KernelTrait<FloatType,
79 Architecture>::AdvectiveFluxKernel;
80 using FrictionCouplingKernel =
81 typename detail::KernelTrait<FloatType,
82 Architecture>::FrictionCouplingKernel;
83 using DiffusiveFluxKernelElectrostaticUnthermalized =
84 typename detail::KernelTrait<
85 FloatType, Architecture>::DiffusiveFluxKernelElectrostatic;
86 using DiffusiveFluxKernelElectrostaticThermalized =
87 typename detail::KernelTrait<
88 FloatType, Architecture>::DiffusiveFluxKernelElectrostaticThermalized;
89
90 using DiffusiveFluxKernel = std::variant<DiffusiveFluxKernelUnthermalized,
91 DiffusiveFluxKernelThermalized>;
92 using DiffusiveFluxKernelElectrostatic =
93 std::variant<DiffusiveFluxKernelElectrostaticUnthermalized,
94 DiffusiveFluxKernelElectrostaticThermalized>;
95
96 using Dirichlet =
98 using FixedFlux =
100
103 using BoundaryModelFlux =
105
106public:
107 /** @brief Stencil for collision and streaming operations. */
108 using Stencil = stencil::D3Q27;
109 /** @brief Lattice model (e.g. blockforest). */
111
112protected:
113 template <typename FT, lbmpy::Arch AT = lbmpy::Arch::CPU> struct FieldTrait {
114 // Type definitions
115 using FluxField = GhostLayerField<FT, FluxCount>;
116 using DensityField = GhostLayerField<FT, 1>;
117 template <class Field>
118 using PackInfo = field::communication::PackInfo<Field>;
119 template <class Stencil>
121 blockforest::communication::UniformBufferedScheme<Stencil>;
122 template <class Stencil>
124 blockforest::communication::UniformBufferedScheme<Stencil>;
125 };
126 using FlagField = walberla::FlagField<walberla::uint8_t>;
127#if defined(__CUDACC__)
128 template <typename FT> struct FieldTrait<FT, lbmpy::Arch::GPU> {
129 private:
130 static auto constexpr AT = lbmpy::Arch::GPU;
131 template <class Field>
132 using MemcpyPackInfo = gpu::communication::MemcpyPackInfo<Field>;
133
134 public:
135 template <typename Stencil>
136 class UniformGPUScheme
137 : public gpu::communication::UniformGPUScheme<Stencil> {
138 public:
139 explicit UniformGPUScheme(auto const &bf)
140 : gpu::communication::UniformGPUScheme<Stencil>(
141 bf, /* sendDirectlyFromGPU */ false,
142 /* useLocalCommunication */ false) {}
143 };
144 using FluxField = gpu::GPUField<FT>;
145 using DensityField = gpu::GPUField<FT>;
146 template <class Field> using PackInfo = MemcpyPackInfo<Field>;
147 template <class Stencil>
148 using RegularCommScheme = UniformGPUScheme<Stencil>;
149 template <class Stencil>
150 using BoundaryCommScheme =
151 blockforest::communication::UniformBufferedScheme<Stencil>;
152 };
153 using GPUField = gpu::GPUField<FloatType>;
154#endif
155
156 struct GhostComm {
157 /** @brief Ghost communication operations. */
158 enum GhostCommFlags : unsigned {
159 FLB, ///< flux boundary communication
160 DENS, ///< density communication
161 SIZE
162 };
163 };
164
165 // "underlying" field types (`GPUField` has no f-size info at compile time)
168
169public:
173
174#if defined(__CUDACC__)
177#endif
178
179 template <typename T> FloatType FloatType_c(T t) {
180 return numeric_cast<FloatType>(t);
181 }
182
183 [[nodiscard]] std::size_t stencil_size() const noexcept override {
184 return FluxCount;
185 }
186
187 [[nodiscard]] bool is_double_precision() const noexcept override {
188 return std::is_same_v<FloatType, double>;
189 }
190
191private:
192 FloatType m_diffusion;
193 FloatType m_kT;
194 FloatType m_valency;
195 Utils::Vector3d m_ext_efield;
196 bool m_advection;
197 bool m_friction_coupling;
198 unsigned int m_seed;
199
200protected:
201 // Block data access handles
203
204 BlockDataID m_flux_field_id;
205
208
209#if defined(__CUDACC__)
210 std::optional<BlockDataID> m_density_cpu_field_id;
211 std::optional<BlockDataID> m_flux_cpu_field_id;
212#endif
213
214 /** Flag for domain cells, i.e. all cells. */
215 FlagUID const Domain_flag{"domain"};
216 /** Flag for boundary cells. */
217 FlagUID const Boundary_flag{"boundary"};
218
219 /** Block forest */
220 std::shared_ptr<LatticeWalberla> m_lattice;
221
222 std::unique_ptr<BoundaryModelDensity> m_boundary_density;
223 std::shared_ptr<BoundaryModelFlux> m_boundary_flux;
224
225 std::unique_ptr<DiffusiveFluxKernel> m_diffusive_flux;
226 std::unique_ptr<DiffusiveFluxKernelElectrostatic>
228 std::unique_ptr<ContinuityKernel> m_continuity;
229
230#if defined(__CUDACC__)
231 std::shared_ptr<gpu::HostFieldAllocator<FloatType>> m_host_field_allocator;
232#endif
233
234 // ResetFlux + external force
235 // TODO: kernel for that
236 // std::shared_ptr<ResetForce<PdfField, VectorField>> m_reset_force;
237
238 /**
239 * @brief Convenience function to add a field with a custom allocator.
240 *
241 * When vectorization is off, let waLBerla decide which memory allocator
242 * to use. When vectorization is on, the aligned memory allocator is
243 * required, otherwise <tt>cpu_vectorize_info["assume_aligned"]</tt> will
244 * trigger assertions. That is because for single-precision kernels the
245 * waLBerla heuristic in <tt>src/field/allocation/FieldAllocator.h</tt>
246 * will fall back to @c StdFieldAlloc, yet @c AllocateAligned is needed
247 * for intrinsics to work.
248 */
249 template <typename Field>
250 auto add_to_storage(std::string const tag, FloatType value) {
251 auto const &blocks = m_lattice->get_blocks();
252 auto const n_ghost_layers = m_lattice->get_ghost_layers();
253 if constexpr (Architecture == lbmpy::Arch::CPU) {
254 return field::addToStorage<Field>(blocks, tag, FloatType{value},
255 field::fzyx, n_ghost_layers);
256 }
257#if defined(__CUDACC__)
258 else {
259 auto field_id = gpu::addGPUFieldToStorage<GPUField>(
260 blocks, tag, Field::F_SIZE, field::fzyx, n_ghost_layers);
261 if constexpr (std::is_same_v<Field, _DensityField>) {
262 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
263 auto field = block->template getData<GPUField>(field_id);
264 ek::accessor::Scalar::initialize(field, FloatType{value});
265 }
266 } else if constexpr (std::is_same_v<Field, _FluxField>) {
267 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
268 auto field = block->template getData<GPUField>(field_id);
270 std::array<FloatType, FluxCount>{});
271 }
272 }
273 return field_id;
274 }
275#endif
276 }
277
278 void
279 reset_density_boundary_handling(std::shared_ptr<BlockStorage> const &blocks) {
280 auto const [lc, uc] = m_lattice->get_local_grid_range(true);
281 m_boundary_density = std::make_unique<BoundaryModelDensity>(
283 CellInterval{to_cell(lc), to_cell(uc)});
284 }
285
286 void
287 reset_flux_boundary_handling(std::shared_ptr<BlockStorage> const &blocks) {
288 auto const [lc, uc] = m_lattice->get_local_grid_range(true);
289 m_boundary_flux = std::make_shared<BoundaryModelFlux>(
291 CellInterval{to_cell(lc), to_cell(uc)});
292 }
293
295 typename FieldTrait<FloatType, Architecture>::template RegularCommScheme<
296 typename stencil::D3Q27>;
298 typename FieldTrait<FloatType, Architecture>::template BoundaryCommScheme<
299 typename stencil::D3Q27>;
300 std::shared_ptr<FullCommunicator> m_full_communication;
301 std::shared_ptr<BoundaryFullCommunicator> m_boundary_communicator;
302 std::bitset<GhostComm::SIZE> m_pending_ghost_comm;
303 template <class Field>
304 using PackInfo =
306
307public:
308 EKinWalberlaImpl(std::shared_ptr<LatticeWalberla> lattice, double diffusion,
309 double kT, double valency, Utils::Vector3d const &ext_efield,
310 double density, bool advection, bool friction_coupling,
311 bool thermalized, unsigned int seed)
312 : m_diffusion(FloatType_c(diffusion)), m_kT(FloatType_c(kT)),
313 m_valency(FloatType_c(valency)), m_ext_efield(ext_efield),
314 m_advection(advection), m_friction_coupling(friction_coupling),
315 m_seed(seed), m_lattice(std::move(lattice)) {
316
317 auto const &blocks = m_lattice->get_blocks();
318 auto const n_ghost_layers = m_lattice->get_ghost_layers();
319
321 add_to_storage<_DensityField>("density field", FloatType_c(density));
323 add_to_storage<_FluxField>("flux field", FloatType_c(0.0));
324
326 std::make_unique<ContinuityKernel>(m_flux_field_id, m_density_field_id);
327
328#if defined(__CUDACC__)
329 m_host_field_allocator =
330 std::make_shared<gpu::HostFieldAllocator<FloatType>>();
331#endif
332
333 if (thermalized) {
334 set_diffusion_kernels(*m_lattice, seed);
335 } else {
336 set_diffusion_kernels();
337 }
338
339 // Init boundary related stuff
340 m_flag_field_density_id = field::addFlagFieldToStorage<FlagField>(
341 blocks, "flag field density", n_ghost_layers);
343
344 m_flag_field_flux_id = field::addFlagFieldToStorage<FlagField>(
345 blocks, "flag field flux", n_ghost_layers);
347
348 m_full_communication = std::make_shared<FullCommunicator>(blocks);
349 m_full_communication->addPackInfo(
350 std::make_shared<PackInfo<DensityField>>(m_density_field_id));
352 std::make_shared<BoundaryFullCommunicator>(blocks);
353 m_boundary_communicator->addPackInfo(
356 auto flux_boundary_packinfo = std::make_shared<
359 flux_boundary_packinfo->setup_boundary_handle(m_lattice, m_boundary_flux);
360 m_boundary_communicator->addPackInfo(flux_boundary_packinfo);
361
363 }
364
365 // Global parameters
366 [[nodiscard]] double get_diffusion() const noexcept override {
367 return m_diffusion;
368 }
369 [[nodiscard]] double get_kT() const noexcept override { return m_kT; }
370 [[nodiscard]] double get_valency() const noexcept override {
371 return m_valency;
372 }
373 [[nodiscard]] bool get_advection() const noexcept override {
374 return m_advection;
375 }
376 [[nodiscard]] bool get_friction_coupling() const noexcept override {
377 return m_friction_coupling;
378 }
379 [[nodiscard]] Utils::Vector3d get_ext_efield() const noexcept override {
380 return m_ext_efield;
381 }
382 [[nodiscard]] bool is_thermalized() const noexcept override {
383 return static_cast<bool>(
384 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux));
385 }
386 [[nodiscard]] unsigned int get_seed() const noexcept override {
387 return m_seed;
388 }
389 [[nodiscard]] std::optional<uint64_t> get_rng_state() const override {
390 auto const kernel =
391 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
392 if (!kernel) {
393 return std::nullopt;
394 }
395 return {static_cast<uint64_t>(kernel->getTime_step())};
396 }
397
398 void set_diffusion(double diffusion) override {
399 m_diffusion = FloatType_c(diffusion);
400 auto visitor = [m_diffusion = m_diffusion](auto &kernel) {
401 kernel.setD(m_diffusion);
402 };
403 std::visit(visitor, *m_diffusive_flux);
404 std::visit(visitor, *m_diffusive_flux_electrostatic);
405 }
406
407 void set_kT(double kT) override {
408 m_kT = FloatType_c(kT);
409 std::visit([m_kT = m_kT](auto &kernel) { kernel.setKt(m_kT); },
411 }
412
413 void set_valency(double valency) override {
414 m_valency = FloatType_c(valency);
415 std::visit(
416 [m_valency = m_valency](auto &kernel) { kernel.setZ(m_valency); },
418 }
419
420 void set_advection(bool advection) override { m_advection = advection; }
421
422 void set_friction_coupling(bool friction_coupling) override {
423 m_friction_coupling = friction_coupling;
424 }
425
426 void set_rng_state(uint64_t counter) override {
427 auto const kernel =
428 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
429 auto const kernel_electrostatic =
430 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
432
433 if (!kernel or !kernel_electrostatic) {
434 throw std::runtime_error("This EK instance is unthermalized");
435 }
436 assert(counter <=
437 static_cast<uint32_t>(std::numeric_limits<uint_t>::max()));
438 kernel->setTime_step(static_cast<uint32_t>(counter));
439 kernel_electrostatic->setTime_step(static_cast<uint32_t>(counter));
440 }
441
442 void set_ext_efield(Utils::Vector3d const &field) override {
443 m_ext_efield = field;
444
445 std::visit(
446 [this](auto &kernel) {
447 kernel.setF_ext_0(FloatType_c(m_ext_efield[0]));
448 kernel.setF_ext_1(FloatType_c(m_ext_efield[1]));
449 kernel.setF_ext_2(FloatType_c(m_ext_efield[2]));
450 },
452 }
453
454 void ghost_communication() override {
456 (*m_full_communication)();
458 }
460 }
461
468
469private:
470 void set_diffusion_kernels() {
471 auto kernel = DiffusiveFluxKernelUnthermalized(
473 m_diffusive_flux = std::make_unique<DiffusiveFluxKernel>(std::move(kernel));
474
475 auto kernel_electrostatic = DiffusiveFluxKernelElectrostaticUnthermalized(
476 m_flux_field_id, BlockDataID{}, m_density_field_id,
477 FloatType_c(m_diffusion), FloatType_c(m_ext_efield[0]),
478 FloatType_c(m_ext_efield[1]), FloatType_c(m_ext_efield[2]),
479 FloatType_c(m_kT), FloatType_c(m_valency));
480
482 std::make_unique<DiffusiveFluxKernelElectrostatic>(
483 std::move(kernel_electrostatic));
484 }
485
486 void set_diffusion_kernels(LatticeWalberla const &lattice,
487 unsigned int seed) {
488 auto const grid_dim = lattice.get_grid_dimensions();
489
490 auto kernel = DiffusiveFluxKernelThermalized(
492 grid_dim[0], grid_dim[1], grid_dim[2], seed, 0);
493
494 auto kernel_electrostatic = DiffusiveFluxKernelElectrostaticThermalized(
495 m_flux_field_id, BlockDataID{}, m_density_field_id,
496 FloatType_c(m_diffusion), FloatType_c(m_ext_efield[0]),
497 FloatType_c(m_ext_efield[1]), FloatType_c(m_ext_efield[2]), grid_dim[0],
498 grid_dim[1], grid_dim[2], FloatType_c(m_kT), seed, 0,
499 FloatType_c(m_valency));
500
501 auto const blocks = lattice.get_blocks();
502
503 for (auto &block : *blocks) {
504 kernel.configure(blocks, &block);
505 kernel_electrostatic.configure(blocks, &block);
506 }
507
508 m_diffusive_flux = std::make_unique<DiffusiveFluxKernel>(std::move(kernel));
510 std::make_unique<DiffusiveFluxKernelElectrostatic>(
511 std::move(kernel_electrostatic));
512 }
513
514 void kernel_boundary_density() {
515 for (auto &block : *m_lattice->get_blocks()) {
516 (*m_boundary_density)(&block);
517 }
518 }
519
520 void kernel_boundary_flux() {
521 for (auto &block : *m_lattice->get_blocks()) {
522 (*m_boundary_flux)(&block);
523 }
524 }
525
526 void kernel_continuity() {
527 for (auto &block : *m_lattice->get_blocks()) {
528 (*m_continuity).run(&block);
529 }
530 }
531
532 void kernel_diffusion() {
533 for (auto &block : *m_lattice->get_blocks()) {
534 std::visit([&block](auto &kernel) { kernel.run(&block); },
536 }
537
538 if (auto *kernel =
539 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux)) {
540 kernel->setTime_step(kernel->getTime_step() + 1u);
541
542 auto *kernel_electrostatic =
543 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
545 kernel_electrostatic->setTime_step(kernel_electrostatic->getTime_step() +
546 1u);
547 }
548 }
549
550 void kernel_advection(std::size_t const velocity_id) {
551 auto kernel = AdvectiveFluxKernel(m_flux_field_id, m_density_field_id,
552 BlockDataID(velocity_id));
553 for (auto &block : *m_lattice->get_blocks()) {
554 kernel.run(&block);
555 }
556 }
557
558 void kernel_friction_coupling(std::size_t const force_id,
559 double const lb_density) {
560 auto kernel = FrictionCouplingKernel(
561 BlockDataID(force_id), m_flux_field_id, FloatType_c(get_diffusion()),
562 FloatType_c(get_kT()), FloatType(lb_density));
563 for (auto &block : *m_lattice->get_blocks()) {
564 kernel.run(&block);
565 }
566 }
567
568 void kernel_diffusion_electrostatic(std::size_t const potential_id) {
569 auto const phiID = BlockDataID(potential_id);
570 std::visit([phiID](auto &kernel) { kernel.setPhiID(phiID); },
572
573 for (auto &block : *m_lattice->get_blocks()) {
574 std::visit([&block](auto &kernel) { kernel.run(&block); },
576 }
577
578 if (auto *kernel_electrostatic =
579 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
581 kernel_electrostatic->setTime_step(kernel_electrostatic->getTime_step() +
582 1u);
583
584 auto *kernel =
585 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
586 kernel->setTime_step(kernel->getTime_step() + 1u);
587 }
588 }
589
590 void kernel_migration() {}
591
592 void updated_boundary_fields() {
593 m_boundary_flux->boundary_update();
594 m_boundary_density->boundary_update();
595 }
596
597protected:
598 void integrate_vtk_writers() override {
599 for (auto const &it : m_vtk_auto) {
600 auto &vtk_handle = it.second;
601 if (vtk_handle->enabled) {
602 vtk::writeFiles(vtk_handle->ptr)();
603 vtk_handle->execution_count++;
604 }
605 }
606 }
607
608public:
609 void integrate(std::size_t potential_id, std::size_t velocity_id,
610 std::size_t force_id, double lb_density) override {
611
612 updated_boundary_fields();
613
614 if (get_diffusion() == 0.)
615 return;
616
617 if (get_valency() != 0.) {
618 if (potential_id == walberla::BlockDataID{}) {
619 throw std::runtime_error("Walberla EK: electrostatic potential enabled "
620 "but no field accessible. potential id is " +
621 std::to_string(potential_id));
622 }
623 kernel_diffusion_electrostatic(potential_id);
624 } else {
625 kernel_diffusion();
626 }
627
628 kernel_migration();
629 kernel_boundary_flux();
630 // friction coupling
631 if (get_friction_coupling()) {
632 if (force_id == walberla::BlockDataID{}) {
633 throw std::runtime_error("Walberla EK: friction coupling enabled but "
634 "no force field accessible. force_id is " +
635 std::to_string(force_id) +
636 ". Hint: LB may be inactive.");
637 }
638 kernel_friction_coupling(force_id, lb_density);
639 }
640
641 if (get_advection()) {
642 if (velocity_id == walberla::BlockDataID{}) {
643 throw std::runtime_error("Walberla EK: advection enabled but no "
644 "velocity field accessible. velocity_id is " +
645 std::to_string(velocity_id) +
646 ". Hint: LB may be inactive.");
647 }
648 kernel_advection(velocity_id);
649 kernel_boundary_flux();
650 }
651 kernel_continuity();
652
653 // is this the expected behavior when reactions are included?
654 kernel_boundary_density();
656
657 // Handle VTK writers
659 }
660
661 [[nodiscard]] std::size_t get_density_id() const noexcept override {
662 static_assert(std::is_same_v<std::size_t, walberla::uint_t>);
663 return static_cast<std::size_t>(m_density_field_id);
664 }
665
666 bool set_node_density(Utils::Vector3i const &node, double density) override {
668 auto bc = get_block_and_cell(get_lattice(), node, false);
669 if (!bc)
670 return false;
671
672 auto density_field =
673 bc->block->template getData<DensityField>(m_density_field_id);
674 ek::accessor::Scalar::set(density_field, FloatType_c(density), bc->cell);
675 return true;
676 }
677
678 [[nodiscard]] std::optional<double>
680 bool consider_ghosts = false) const override {
681 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
682
683 if (!bc)
684 return std::nullopt;
685
686 auto const density_field =
687 bc->block->template getData<DensityField>(m_density_field_id);
688 return {double_c(ek::accessor::Scalar::get(density_field, bc->cell))};
689 }
690
691 [[nodiscard]] std::vector<double>
693 Utils::Vector3i const &upper_corner) const override {
694 std::vector<double> out;
695 uint_t values_size = 0;
696 auto const &lattice = get_lattice();
697 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
698 out = std::vector<double>(ci->numCells());
699 for (auto &block : *lattice.get_blocks()) {
700 auto const block_offset = lattice.get_block_corner(block, true);
701 if (auto const bci = get_block_interval(
702 lattice, lower_corner, upper_corner, block_offset, block)) {
703 auto const density_field =
704 block.template getData<DensityField>(m_density_field_id);
705 auto const values = ek::accessor::Scalar::get(density_field, *bci);
706 assert(values.size() == bci->numCells());
707 values_size += bci->numCells();
708 auto kernel = [&values, &out](unsigned const block_index,
709 unsigned const local_index,
710 Utils::Vector3i const &) {
711 out[local_index] = double_c(values[block_index]);
712 };
713
714 copy_block_buffer(*bci, *ci, block_offset, lower_corner, kernel);
715 }
716 }
717 assert(values_size == ci->numCells());
718 }
719 return out;
720 }
721
722 void set_slice_density(Utils::Vector3i const &lower_corner,
723 Utils::Vector3i const &upper_corner,
724 std::vector<double> const &density) override {
726 auto const &lattice = get_lattice();
727 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
728 assert(density.size() == ci->numCells());
729 for (auto &block : *lattice.get_blocks()) {
730 auto const block_offset = lattice.get_block_corner(block, true);
731 if (auto const bci = get_block_interval(
732 lattice, lower_corner, upper_corner, block_offset, block)) {
733 auto const density_field =
734 block.template getData<DensityField>(m_density_field_id);
735 std::vector<FloatType> values(bci->numCells());
736
737 auto kernel = [&values, &density](unsigned const block_index,
738 unsigned const local_index,
739 Utils::Vector3i const &) {
740 values[block_index] = numeric_cast<FloatType>(density[local_index]);
741 };
742
743 copy_block_buffer(*bci, *ci, block_offset, lower_corner, kernel);
744 ek::accessor::Scalar::set(density_field, values, *bci);
745 }
746 }
747 }
748 }
749
750 [[nodiscard]] std::optional<Utils::Vector3d>
752 bool consider_ghosts = false) const override {
753 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
754
755 if (!bc)
756 return std::nullopt;
757
758 auto const flux_field =
759 bc->block->template getData<FluxField>(m_flux_field_id);
760 return to_vector3d(ek::accessor::Flux::get_vector(flux_field, bc->cell));
761 }
762
763 std::vector<double>
765 Utils::Vector3i const &upper_corner) const override {
766 std::vector<double> out;
767 uint_t values_size = 0;
768 auto const &lattice = get_lattice();
769 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
770 out = std::vector<double>(3u * ci->numCells());
771 for (auto &block : *lattice.get_blocks()) {
772 auto const block_offset = lattice.get_block_corner(block, true);
773 if (auto const bci = get_block_interval(
774 lattice, lower_corner, upper_corner, block_offset, block)) {
775 auto const flux_field =
776 block.template getData<FluxField>(m_flux_field_id);
777 auto const values = ek::accessor::Flux::get_vector(flux_field, *bci);
778 assert(values.size() == 3u * bci->numCells());
779 values_size += 3u * bci->numCells();
780
781 auto kernel = [&values, &out, this](unsigned const block_index,
782 unsigned const local_index,
783 Utils::Vector3i const &node) {
784 if (m_boundary_flux->node_is_boundary(node)) {
785 auto const &vec =
786 m_boundary_flux->get_node_value_at_boundary(node);
787 for (uint_t f = 0u; f < 3u; ++f) {
788 out[3u * local_index + f] = double_c(vec[f]);
789 }
790 } else {
791 for (uint_t f = 0u; f < 3u; ++f) {
792 out[3u * local_index + f] =
793 double_c(values[3u * block_index + f]);
794 }
795 }
796 };
797
798 copy_block_buffer(*bci, *ci, block_offset, lower_corner, kernel);
799 }
800 }
801 assert(values_size == 3u * ci->numCells());
802 }
803 return out;
804 }
805
810
811 void clear_density_boundaries() override {
813 }
814
816 Utils::Vector3d const &flux) override {
818 auto bc = get_block_and_cell(get_lattice(), node, true);
819 if (!bc)
820 return false;
821
822 m_boundary_flux->set_node_value_at_boundary(
823 node, to_vector3<FloatType>(flux), *bc);
824 return true;
825 }
826
827 [[nodiscard]] std::optional<Utils::Vector3d>
829 bool consider_ghosts = false) const override {
830 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::FLB)));
831 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
832 if (!bc or !m_boundary_flux->node_is_boundary(node))
833 return std::nullopt;
834
835 return {to_vector3d(m_boundary_flux->get_node_value_at_boundary(node))};
836 }
837
840 auto bc = get_block_and_cell(get_lattice(), node, true);
841 if (!bc)
842 return false;
843
844 m_boundary_flux->remove_node_from_boundary(node, *bc);
845 return true;
846 }
847
849 double density) override {
850 auto bc = get_block_and_cell(get_lattice(), node, true);
851 if (!bc)
852 return false;
853
854 m_boundary_density->set_node_value_at_boundary(node, FloatType_c(density),
855 *bc);
856
857 return true;
858 }
859
860 [[nodiscard]] std::optional<double>
862 bool consider_ghosts = false) const override {
863 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
864 if (!bc or !m_boundary_density->node_is_boundary(node))
865 return std::nullopt;
866
867 return {double_c(m_boundary_density->get_node_value_at_boundary(node))};
868 }
869
871 Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner,
872 std::vector<std::optional<double>> const &density) override {
873 auto const &lattice = get_lattice();
874 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
875 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
876 auto const lower_cell = ci->min();
877 auto const upper_cell = ci->max();
878 auto it = density.begin();
879 assert(density.size() == ci->numCells());
880 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
881 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
882 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
883 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
884 auto const bc = get_block_and_cell(lattice, node, false);
885 auto const &opt = *it;
886 if (opt) {
887 m_boundary_density->set_node_value_at_boundary(
888 node, FloatType_c(*opt), *bc);
889 } else {
890 m_boundary_density->remove_node_from_boundary(node, *bc);
891 }
892 ++it;
893 }
894 }
895 }
896 }
897 }
898
899 [[nodiscard]] std::vector<std::optional<double>>
901 Utils::Vector3i const &lower_corner,
902 Utils::Vector3i const &upper_corner) const override {
903 std::vector<std::optional<double>> out;
904 auto const &lattice = get_lattice();
905 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
906 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
907 auto const lower_cell = ci->min();
908 auto const upper_cell = ci->max();
909 auto const n_values = ci->numCells();
910 out.reserve(n_values);
911 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
912 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
913 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
914 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
915 if (m_boundary_density->node_is_boundary(node)) {
916 out.emplace_back(double_c(
917 m_boundary_density->get_node_value_at_boundary(node)));
918 } else {
919 out.emplace_back(std::nullopt);
920 }
921 }
922 }
923 }
924 assert(out.size() == n_values);
925 }
926 return out;
927 }
928
930 Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner,
931 std::vector<std::optional<Utils::Vector3d>> const &flux) override {
933 auto const &lattice = get_lattice();
934 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
935 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
936 auto const lower_cell = ci->min();
937 auto const upper_cell = ci->max();
938 auto it = flux.begin();
939 assert(flux.size() == ci->numCells());
940 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
941 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
942 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
943 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
944 auto const bc = get_block_and_cell(lattice, node, false);
945 auto const &opt = *it;
946 if (opt) {
947 m_boundary_flux->set_node_value_at_boundary(
948 node, to_vector3<FloatType>(*opt), *bc);
949 } else {
950 m_boundary_flux->remove_node_from_boundary(node, *bc);
951 }
952 ++it;
953 }
954 }
955 }
956 }
957 }
958
959 [[nodiscard]] std::vector<std::optional<Utils::Vector3d>>
961 Utils::Vector3i const &lower_corner,
962 Utils::Vector3i const &upper_corner) const override {
963 std::vector<std::optional<Utils::Vector3d>> out;
964 auto const &lattice = get_lattice();
965 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
966 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
967 auto const lower_cell = ci->min();
968 auto const upper_cell = ci->max();
969 auto const n_values = ci->numCells();
970 out.reserve(n_values);
971 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
972 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
973 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
974 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
975 if (m_boundary_flux->node_is_boundary(node)) {
976 out.emplace_back(to_vector3d(
977 m_boundary_flux->get_node_value_at_boundary(node)));
978 } else {
979 out.emplace_back(std::nullopt);
980 }
981 }
982 }
983 }
984 assert(out.size() == n_values);
985 }
986 return out;
987 }
988
989 [[nodiscard]] std::vector<bool>
991 Utils::Vector3i const &upper_corner) const override {
992 std::vector<bool> out;
993 auto const &lattice = get_lattice();
994 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
995 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
996 auto const lower_cell = ci->min();
997 auto const upper_cell = ci->max();
998 auto const n_values = ci->numCells();
999 out.reserve(n_values);
1000 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
1001 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
1002 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
1003 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
1004 out.emplace_back(m_boundary_density->node_is_boundary(node) or
1005 m_boundary_flux->node_is_boundary(node));
1006 }
1007 }
1008 }
1009 assert(out.size() == n_values);
1010 }
1011 return out;
1012 }
1013
1015 auto bc = get_block_and_cell(get_lattice(), node, true);
1016 if (!bc)
1017 return false;
1018
1019 m_boundary_density->remove_node_from_boundary(node, *bc);
1020
1021 return true;
1022 }
1023
1024 [[nodiscard]] std::optional<bool>
1026 bool consider_ghosts) const override {
1027 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::FLB)));
1028 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1029 if (!bc)
1030 return std::nullopt;
1031
1032 return {m_boundary_flux->node_is_boundary(node)};
1033 }
1034
1035 [[nodiscard]] std::optional<bool>
1037 bool consider_ghosts) const override {
1038 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1039 if (!bc)
1040 return std::nullopt;
1041
1042 return {m_boundary_density->node_is_boundary(node)};
1043 }
1044
1045 [[nodiscard]] std::optional<bool>
1047 bool consider_ghosts = false) const override {
1048 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1049 if (!bc)
1050 return std::nullopt;
1051
1052 return {m_boundary_density->node_is_boundary(node) or
1053 m_boundary_flux->node_is_boundary(node)};
1054 }
1055
1057 const std::vector<int> &raster_flat,
1058 const std::vector<double> &data_flat) override {
1060 auto const grid_size = get_lattice().get_grid_dimensions();
1061 auto const data = fill_3D_vector_array(data_flat, grid_size);
1062 set_boundary_from_grid(*m_boundary_flux, get_lattice(), raster_flat, data);
1064 }
1065
1067 const std::vector<int> &raster_flat,
1068 const std::vector<double> &data_flat) override {
1069 auto const grid_size = get_lattice().get_grid_dimensions();
1070 auto const data = fill_3D_scalar_array(data_flat, grid_size);
1072 data);
1074 }
1075
1077
1079 m_boundary_density->boundary_update();
1080 }
1081
1082 [[nodiscard]] LatticeWalberla const &get_lattice() const noexcept override {
1083 return *m_lattice;
1084 }
1085
1086 [[nodiscard]] bool is_gpu() const noexcept override {
1087 return Architecture == lbmpy::Arch::GPU;
1088 }
1089
1090 void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override {
1091 field::FlagFieldCellFilter<FlagField> fluid_filter(m_flag_field_density_id);
1092 fluid_filter.addFlag(Boundary_flag);
1093 vtk_obj.addCellExclusionFilter(fluid_filter);
1094 }
1095
1096protected:
1097 template <typename Field_T, uint_t F_SIZE_ARG, typename OutputType>
1098 class VTKWriter : public vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG> {
1099 public:
1100 VTKWriter(ConstBlockDataID const &block_id, std::string const &id,
1101 FloatType unit_conversion)
1102 : vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG>(id),
1103 m_block_id(block_id), m_field(nullptr),
1104 m_conversion(unit_conversion) {}
1105
1106 protected:
1107 void configure() override {
1108 WALBERLA_ASSERT_NOT_NULLPTR(this->block_);
1109 m_field = this->block_->template getData<Field_T>(m_block_id);
1110 }
1111
1112 ConstBlockDataID const m_block_id;
1113 Field_T const *m_field;
1114 FloatType const m_conversion;
1115 };
1116
1117#if defined(__CUDACC__)
1118 template <typename OutputType = float>
1119 class DensityVTKWriter : public VTKWriter<DensityFieldCpu, 1u, OutputType> {
1120 public:
1122 using Base::Base;
1123 using Base::evaluate;
1124
1125 protected:
1126 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1127 cell_idx_t const z, cell_idx_t const) override {
1128 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1129 auto const density = ek::accessor::Scalar::get(this->m_field, {x, y, z});
1130 return numeric_cast<OutputType>(this->m_conversion * density);
1131 }
1132 };
1133#else
1134 template <typename OutputType = float>
1135 class DensityVTKWriter : public VTKWriter<DensityField, 1u, OutputType> {
1136 public:
1138 using Base::Base;
1139 using Base::evaluate;
1140
1141 protected:
1142 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1143 cell_idx_t const z, cell_idx_t const) override {
1144 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1145 auto const density = ek::accessor::Scalar::get(this->m_field, {x, y, z});
1146 return numeric_cast<OutputType>(this->m_conversion * density);
1147 }
1148 };
1149#endif
1150
1151#if defined(__CUDACC__)
1152 template <typename OutputType = float>
1153 class FluxVTKWriter : public VTKWriter<FluxFieldCpu, 3u, OutputType> {
1154 public:
1155 using Base = VTKWriter<FluxFieldCpu, 3u, OutputType>;
1156 using Base::Base;
1157 using Base::evaluate;
1158
1159 protected:
1160 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1161 cell_idx_t const z, cell_idx_t const f) override {
1162 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1163 auto const flux =
1164 ek::accessor::Flux::get_vector(this->m_field, {x, y, z});
1165 return numeric_cast<OutputType>(this->m_conversion * flux[uint_c(f)]);
1166 }
1167 };
1168#else
1169 template <typename OutputType = float>
1170 class FluxVTKWriter : public VTKWriter<FluxField, 3u, OutputType> {
1171 public:
1173 using Base::Base;
1174 using Base::evaluate;
1175
1176 protected:
1177 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1178 cell_idx_t const z, cell_idx_t const f) override {
1179 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1180 auto const flux =
1181 ek::accessor::Flux::get_vector(this->m_field, {x, y, z});
1182 return numeric_cast<OutputType>(this->m_conversion * flux[uint_c(f)]);
1183 }
1184 };
1185#endif
1186
1187public:
1188 void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj,
1189 LatticeModel::units_map const &units,
1190 int flag_observables) override {
1191#if defined(__CUDACC__)
1192 auto const allocate_cpu_field_if_empty =
1193 [&]<typename Field>(auto const &blocks, std::string name,
1194 std::optional<BlockDataID> &cpu_field) {
1195 if (not cpu_field) {
1196 cpu_field = field::addToStorage<Field>(
1197 blocks, name, FloatType{0}, field::fzyx,
1198 m_lattice->get_ghost_layers(), m_host_field_allocator);
1199 }
1200 };
1201#endif
1202 if (flag_observables & static_cast<int>(EKOutputVTK::density)) {
1203 auto const unit_conversion = FloatType_c(units.at("density"));
1204#if defined(__CUDACC__)
1205 if constexpr (Architecture == lbmpy::Arch::GPU) {
1206 auto const &blocks = m_lattice->get_blocks();
1207 allocate_cpu_field_if_empty.template operator()<DensityFieldCpu>(
1208 blocks, "density_cpu", m_density_cpu_field_id);
1209 vtk_obj.addBeforeFunction(
1210 gpu::fieldCpyFunctor<DensityFieldCpu, DensityField>(
1211 blocks, *m_density_cpu_field_id, m_density_field_id));
1212 vtk_obj.addCellDataWriter(make_shared<DensityVTKWriter<float>>(
1213 *m_density_cpu_field_id, "density", unit_conversion));
1214 } else {
1215#endif
1216 vtk_obj.addCellDataWriter(make_shared<DensityVTKWriter<float>>(
1217 m_density_field_id, "density", unit_conversion));
1218#if defined(__CUDACC__)
1219 }
1220#endif
1221 }
1222 if (flag_observables & static_cast<int>(EKOutputVTK::flux)) {
1223 auto const unit_conversion = FloatType_c(units.at("flux"));
1224#if defined(__CUDACC__)
1225 if constexpr (Architecture == lbmpy::Arch::GPU) {
1226 auto const &blocks = m_lattice->get_blocks();
1227 allocate_cpu_field_if_empty.template operator()<FluxFieldCpu>(
1228 blocks, "flux_cpu", m_flux_cpu_field_id);
1229 vtk_obj.addBeforeFunction(gpu::fieldCpyFunctor<FluxFieldCpu, FluxField>(
1230 blocks, *m_flux_cpu_field_id, m_flux_field_id));
1231 vtk_obj.addCellDataWriter(make_shared<FluxVTKWriter<float>>(
1232 *m_flux_cpu_field_id, "flux", unit_conversion));
1233 } else {
1234#endif
1235 vtk_obj.addCellDataWriter(make_shared<FluxVTKWriter<float>>(
1236 m_flux_field_id, "flux", unit_conversion));
1237#if defined(__CUDACC__)
1238 }
1239#endif
1240 }
1241 }
1242
1243 ~EKinWalberlaImpl() override = default;
1244};
1245
1246} // namespace walberla
Vector implementation and trait types for boost qvm interoperability.
Interface of a lattice-based electrokinetic model.
std::map< std::string, std::shared_ptr< VTKHandle > > m_vtk_auto
VTK writers that are executed automatically.
std::unordered_map< std::string, double > units_map
Class that runs and controls the BlockForest in waLBerla.
walberla::blockforest::StructuredBlockForest Lattice_T
std::pair< Utils::Vector3i, Utils::Vector3i > get_local_grid_range(bool with_halo=false) const
Utils::Vector3i get_block_corner(IBlock const &block, bool lower) const
Boundary class optimized for sparse data.
VTKWriter< DensityField, 1u, OutputType > Base
OutputType evaluate(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z, cell_idx_t const) override
OutputType evaluate(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z, cell_idx_t const f) override
VTKWriter< FluxField, 3u, OutputType > Base
VTKWriter(ConstBlockDataID const &block_id, std::string const &id, FloatType unit_conversion)
Class that runs and controls the EK on waLBerla.
~EKinWalberlaImpl() override=default
void set_slice_flux_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< std::optional< Utils::Vector3d > > const &flux) override
void set_kT(double kT) override
std::optional< double > get_node_density_at_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
double get_kT() const noexcept override
std::unique_ptr< DiffusiveFluxKernelElectrostatic > m_diffusive_flux_electrostatic
walberla::FlagField< walberla::uint8_t > FlagField
void set_friction_coupling(bool friction_coupling) override
void set_rng_state(uint64_t counter) override
void integrate(std::size_t potential_id, std::size_t velocity_id, std::size_t force_id, double lb_density) override
bool set_node_density_boundary(Utils::Vector3i const &node, double density) override
void set_slice_density(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< double > const &density) override
std::shared_ptr< FullCommunicator > m_full_communication
std::bitset< GhostComm::SIZE > m_pending_ghost_comm
std::vector< double > get_slice_density(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void update_density_boundary_from_shape(const std::vector< int > &raster_flat, const std::vector< double > &data_flat) override
void update_flux_boundary_from_shape(const std::vector< int > &raster_flat, const std::vector< double > &data_flat) override
std::vector< bool > get_slice_is_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void set_ext_efield(Utils::Vector3d const &field) override
bool set_node_density(Utils::Vector3i const &node, double density) override
double get_diffusion() const noexcept override
void set_valency(double valency) override
bool is_thermalized() const noexcept override
auto add_to_storage(std::string const tag, FloatType value)
Convenience function to add a field with a custom allocator.
std::optional< double > get_node_density(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::size_t get_density_id() const noexcept override
unsigned int get_seed() const noexcept override
std::unique_ptr< ContinuityKernel > m_continuity
double get_valency() const noexcept override
typename FieldTrait< FloatType, Architecture >::FluxField FluxField
std::shared_ptr< BoundaryModelFlux > m_boundary_flux
void set_slice_density_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< std::optional< double > > const &density) override
void reset_flux_boundary_handling(std::shared_ptr< BlockStorage > const &blocks)
bool get_advection() const noexcept override
std::optional< Utils::Vector3d > get_node_flux_vector(Utils::Vector3i const &node, bool consider_ghosts=false) const override
typename FieldTrait< FloatType, Architecture >::template BoundaryCommScheme< typename stencil::D3Q27 > BoundaryFullCommunicator
typename FieldTrait< FloatType, Architecture >::template RegularCommScheme< typename stencil::D3Q27 > FullCommunicator
std::optional< uint64_t > get_rng_state() const override
void set_advection(bool advection) override
bool remove_node_from_density_boundary(Utils::Vector3i const &node) override
typename FieldTrait< FloatType, Architecture >::template PackInfo< Field > PackInfo
bool get_friction_coupling() const noexcept override
Utils::Vector3d get_ext_efield() const noexcept override
stencil::D3Q27 Stencil
Stencil for collision and streaming operations.
LatticeWalberla const & get_lattice() const noexcept override
bool remove_node_from_flux_boundary(Utils::Vector3i const &node) override
bool is_double_precision() const noexcept override
typename FieldTrait< FloatType, Architecture >::DensityField DensityField
bool is_gpu() const noexcept override
void clear_density_boundaries() override
std::optional< bool > get_node_is_flux_boundary(Utils::Vector3i const &node, bool consider_ghosts) const override
LatticeWalberla::Lattice_T BlockStorage
Lattice model (e.g.
void reset_density_boundary_handling(std::shared_ptr< BlockStorage > const &blocks)
std::vector< std::optional< Utils::Vector3d > > get_slice_flux_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
std::vector< std::optional< double > > get_slice_density_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj, LatticeModel::units_map const &units, int flag_observables) override
std::optional< Utils::Vector3d > get_node_flux_at_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::vector< double > get_slice_flux_vector(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
typename FieldTrait< FloatType >::DensityField _DensityField
std::shared_ptr< BoundaryFullCommunicator > m_boundary_communicator
std::optional< bool > get_node_is_density_boundary(Utils::Vector3i const &node, bool consider_ghosts) const override
std::unique_ptr< DiffusiveFluxKernel > m_diffusive_flux
void set_diffusion(double diffusion) override
std::size_t stencil_size() const noexcept override
FlagUID const Boundary_flag
Flag for boundary cells.
bool set_node_flux_boundary(Utils::Vector3i const &node, Utils::Vector3d const &flux) override
typename FieldTrait< FloatType >::FluxField _FluxField
std::optional< bool > get_node_is_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::unique_ptr< BoundaryModelDensity > m_boundary_density
EKinWalberlaImpl(std::shared_ptr< LatticeWalberla > lattice, double diffusion, double kT, double valency, Utils::Vector3d const &ext_efield, double density, bool advection, bool friction_coupling, bool thermalized, unsigned int seed)
std::shared_ptr< LatticeWalberla > m_lattice
Block forest.
FlagUID const Domain_flag
Flag for domain cells, i.e.
void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override
void setup_boundary_handle(std::shared_ptr< LatticeWalberla > lattice, std::shared_ptr< Boundary_T > boundary)
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:176
STL namespace.
auto get_vector(GhostLayerField< double, uint_t{13u}> const *flux_field, Cell const &cell)
void initialize(GhostLayerField< double, uint_t{13u}> *flux_field, std::array< double, 13 > const &values)
void initialize(GhostLayerField< double, 1u > *scalar_field, double const &value)
void set(GhostLayerField< double, 1u > *scalar_field, double const &value, Cell const &cell)
auto get(GhostLayerField< double, 1u > const *scalar_field, Cell const &cell)
static FUNC_PREFIX double *RESTRICT const double *RESTRICT const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const uint32_t uint32_t uint32_t uint32_t uint32_t uint32_t uint32_t seed
\file PackInfoPdfDoublePrecision.cpp \author pystencils
auto to_vector3d(Vector3< T > const &v) noexcept
std::vector< double > fill_3D_scalar_array(std::vector< double > const &vec_flat, Utils::Vector3i const &grid_size)
Definition boundary.hpp:60
void set_boundary_from_grid(BoundaryModel &boundary, LatticeWalberla const &lattice, std::vector< int > const &raster_flat, std::vector< DataType > const &data_flat)
Definition boundary.hpp:81
std::optional< BlockAndCell > get_block_and_cell(::LatticeWalberla const &lattice, signed_integral_vector auto const &node, bool consider_ghost_layers)
Cell to_cell(signed_integral_vector auto const &xyz)
std::optional< walberla::cell::CellInterval > get_block_interval(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, Utils::Vector3i const &block_offset, IBlock const &block)
void copy_block_buffer(CellInterval const &bci, CellInterval const &ci, Utils::Vector3i const &block_offset, Utils::Vector3i const &lower_corner, Kernel &&kernel)
Synchronize data between a sliced block and a container.
std::optional< walberla::cell::CellInterval > get_interval(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner)
std::vector< Utils::Vector3d > fill_3D_vector_array(std::vector< double > const &vec_flat, Utils::Vector3i const &grid_size)
Definition boundary.hpp:36
blockforest::communication::UniformBufferedScheme< Stencil > RegularCommScheme
GhostLayerField< FT, FluxCount > FluxField
field::communication::PackInfo< Field > PackInfo
blockforest::communication::UniformBufferedScheme< Stencil > BoundaryCommScheme
GhostCommFlags
Ghost communication operations.