diff --git a/.clang-tidy b/.clang-tidy
index f0e5933ad55dc18c06f14f2c6ef06dc3226eda22..fffab0ce372641ebabd3468a5c106d2c9b0ce039 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -4,16 +4,30 @@ Checks:          '
 -*,
 
 boost-*,
+-boost-use-ranges,
 
 bugprone-*,
 -bugprone-branch-clone,
 -bugprone-exception-escape,
 -bugprone-easily-swappable-parameters,
+-bugprone-crtp-constructor-accessibility,
+-bugprone-implicit-widening-of-multiplication-result,
+-bugprone-macro-parentheses,
+-bugprone-narrowing-conversions,
+-bugprone-switch-missing-default-case,
+-bugprone-assignment-in-if-condition,
+-bugprone-reserved-identifier,
 
 misc-*,
 -misc-misplaced-const,
+-misc-const-correctness,
+-misc-unused-parameters,
 -misc-no-recursion,
 -misc-non-private-member-variables-in-classes,
+-misc-include-cleaner,
+-misc-header-include-cycle,
+-misc-use-internal-linkage,
+-misc-use-anonymous-namespace,
 
 modernize-*,
 -modernize-use-auto,
@@ -23,12 +37,18 @@ modernize-*,
 -modernize-use-using,
 -modernize-avoid-bind,
 -modernize-return-braced-init-list,
+-modernize-min-max-use-initializer-list,
 -modernize-use-transparent-functors,
 -modernize-redundant-void-arg,
 -modernize-use-trailing-return-type,
+-modernize-use-default-member-init,
+-modernize-use-equals-delete,
+-modernize-macro-to-enum,
 -modernize-avoid-c-arrays,
 -modernize-concat-nested-namespaces,
 -modernize-use-nodiscard,
+-modernize-type-traits,
+-modernize-make-shared,
 
 mpi-*,
 -mpi-type-mismatch,
@@ -38,25 +58,26 @@ openmp-*,
 -openmp-use-default-none,
 
 performance-*,
+-performance-enum-size,
+-performance-noexcept-swap,
+-performance-move-const-arg,
+-performance-unnecessary-value-param,
+-performance-avoid-endl,
+-performance-no-int-to-ptr,
 
 portability-*,
 
-readability-const-return-type,
 readability-container-size-empty,
 readability-delete-null-pointer,
 readability-deleted-default,
-readability-isolate-declaration,
-readability-misleading-indentation,
 readability-misplaced-array-index,
 readability-non-const-parameter,
-readability-redundant-access-specifiers,
 readability-redundant-control-flow,
 readability-redundant-declaration,
 readability-redundant-function-ptr-dereference,
 readability-redundant-preprocessor,
 readability-redundant-smartptr-get,
 readability-redundant-string-cstr,
-readability-simplify-boolean-expr,
 readability-simplify-subscript-expr,
 readability-static-accessed-through-instance,
 readability-static-definition-in-anonymous-namespace,
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1ee46ddc0af7fd8dfd8e859d18ce0bce05e4184d..f3918112bbc1acfab3b974399bab35b2b506b92e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2035,24 +2035,23 @@ doc:
 ##                                                                           ##
 ###############################################################################
 
-#clang-tidy:
-#   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang-15
-#   script:
-#      - $CXX --version
-#      - clang-tidy -version
-#      - cmake --version
-#      - mkdir $CI_PROJECT_DIR/build
-#      - cd $CI_PROJECT_DIR/build
-#      - cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DWALBERLA_BUFFER_DEBUG=ON -DWALBERLA_BUILD_TESTS=ON -DWALBERLA_BUILD_BENCHMARKS=ON -DWALBERLA_BUILD_TUTORIALS=ON -DWALBERLA_BUILD_TOOLS=ON -DWALBERLA_BUILD_WITH_MPI=ON -DWALBERLA_BUILD_WITH_OPENMP=ON -DCMAKE_BUILD_TYPE=Debug -DWALBERLA_BUILD_WITH_METIS=ON -DWALBERLA_BUILD_WITH_PARMETIS=ON -DWALBERLA_BUILD_WITH_OPENMESH=ON -DWALBERLA_DOUBLE_ACCURACY=ON -DWALBERLA_LOGLEVEL=DETAIL
-#      - cmake . -LA
-#      - utilities/filterCompileCommands.py compile_commands.json
-#      - wget https://raw.githubusercontent.com/llvm/llvm-project/main/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
-#      - python3 run-clang-tidy.py -quiet | tee clang-tidy-output.txt
-#   artifacts:
-#      paths:
-#         - $CI_PROJECT_DIR/build/clang-tidy-output.txt
-#   tags:
-#      - docker
+clang-tidy:
+   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang-17
+   script:
+      - $CXX --version
+      - clang-tidy -version
+      - cmake --version
+      - mkdir $CI_PROJECT_DIR/build
+      - cd $CI_PROJECT_DIR/build
+      - cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DWALBERLA_BUFFER_DEBUG=ON -DWALBERLA_BUILD_TESTS=ON -DWALBERLA_BUILD_BENCHMARKS=ON -DWALBERLA_BUILD_TUTORIALS=ON -DWALBERLA_BUILD_TOOLS=ON -DWALBERLA_BUILD_WITH_MPI=ON -DWALBERLA_BUILD_WITH_OPENMP=ON -DCMAKE_BUILD_TYPE=Debug -DWALBERLA_BUILD_WITH_METIS=ON -DWALBERLA_BUILD_WITH_PARMETIS=ON -DWALBERLA_BUILD_WITH_OPENMESH=ON -DWALBERLA_DOUBLE_ACCURACY=ON -DWALBERLA_LOGLEVEL=DETAIL
+      - cmake . -LA
+      - utilities/filterCompileCommands.py --file compile_commands.json --exclude "*" --include src/core src/field src/stencil src/blockforest src/domain_decomposition src/communication src/gpu src/vtk src/fft --exclude extern tests
+      - run-clang-tidy -quiet | tee clang-tidy-output.txt
+   artifacts:
+      paths:
+         - $CI_PROJECT_DIR/build/clang-tidy-output.txt
+   tags:
+      - docker
 
 
 cppcheck:
diff --git a/apps/benchmarks/FluidParticleCouplingWithLoadBalancing/Utility.h b/apps/benchmarks/FluidParticleCouplingWithLoadBalancing/Utility.h
index f9e4c05f1273a463486ef7b18647d31020d5bfda..8a394f6bb6ab168cb97841abba5cd54902157845 100644
--- a/apps/benchmarks/FluidParticleCouplingWithLoadBalancing/Utility.h
+++ b/apps/benchmarks/FluidParticleCouplingWithLoadBalancing/Utility.h
@@ -10,21 +10,21 @@ namespace amr {
  * Result from the workload evaluation as described in
  *  Rettinger, Ruede - "Dynamic Load Balancing Techniques for Particulate Flow Simulations", 2019, Computation
  */
-real_t fittedLBMWeightEvaluationFunction(const BlockInfo& blockInfo)
+inline real_t fittedLBMWeightEvaluationFunction(const BlockInfo& blockInfo)
 {
    uint_t Ce = blockInfo.numberOfCells;
    uint_t F  = blockInfo.numberOfFluidCells;
    real_t weight = real_t(7.597476065046571e-06) * real_c(Ce) + real_t(8.95723566283202e-05) * real_c(F) + real_t(-0.1526111388616016);
    return std::max(weight,real_t(0));
 }
-real_t fittedBHWeightEvaluationFunction(const BlockInfo& blockInfo)
+inline real_t fittedBHWeightEvaluationFunction(const BlockInfo& blockInfo)
 {
    uint_t Ce = blockInfo.numberOfCells;
    uint_t NB = blockInfo.numberOfNearBoundaryCells;
    real_t weight = real_t(1.3067711379655123e-07) * real_c(Ce) + real_t(0.0007289549127205142) * real_c(NB) + real_t(-0.1575698071795788);
    return std::max(weight,real_t(0));
 }
-real_t fittedRPDWeightEvaluationFunction(const BlockInfo& blockInfo)
+inline real_t fittedRPDWeightEvaluationFunction(const BlockInfo& blockInfo)
 {
    uint_t Pl = blockInfo.numberOfLocalParticles;
    uint_t Pg = blockInfo.numberOfGhostParticles;
@@ -36,7 +36,7 @@ real_t fittedRPDWeightEvaluationFunction(const BlockInfo& blockInfo)
    real_t weight = real_c(Sc) * ( cPlPg2 * real_c(Pl+Pg) * real_c(Pl+Pg) + cPl * real_c(Pl) + cPg * real_c(Pg) + c );
    return std::max(weight,real_t(0));
 }
-real_t fittedCoup1WeightEvaluationFunction(const BlockInfo& blockInfo)
+inline real_t fittedCoup1WeightEvaluationFunction(const BlockInfo& blockInfo)
 {
    uint_t Ce = blockInfo.numberOfCells;
    uint_t F  = blockInfo.numberOfFluidCells;
@@ -45,7 +45,7 @@ real_t fittedCoup1WeightEvaluationFunction(const BlockInfo& blockInfo)
    real_t weight = real_t(5.610203409278647e-06) * real_c(Ce) + real_t(-7.257635845636656e-07) * real_c(F) + real_t(0.02049703546054693) * real_c(Pl) + real_t(0.04248208493809902) * real_c(Pg) + real_t(-0.26609470510074784);
    return std::max(weight,real_t(0));
 }
-real_t fittedCoup2WeightEvaluationFunction(const BlockInfo& blockInfo)
+inline real_t fittedCoup2WeightEvaluationFunction(const BlockInfo& blockInfo)
 {
    uint_t Ce = blockInfo.numberOfCells;
    uint_t F  = blockInfo.numberOfFluidCells;
@@ -54,7 +54,7 @@ real_t fittedCoup2WeightEvaluationFunction(const BlockInfo& blockInfo)
    real_t weight = real_t(7.198479654682179e-06) * real_c(Ce) + real_t(1.178247475854302e-06) * real_c(F) + real_t(-0.0026401549115124628) * real_c(Pl) + real_t(0.008459646786179298) * real_c(Pg) + real_t(-0.001077320113275954);
    return std::max(weight,real_t(0));
 }
-real_t fittedTotalWeightEvaluationFunction(const BlockInfo& blockInfo)
+inline real_t fittedTotalWeightEvaluationFunction(const BlockInfo& blockInfo)
 {
    return fittedLBMWeightEvaluationFunction(blockInfo) + fittedBHWeightEvaluationFunction(blockInfo) +
           fittedRPDWeightEvaluationFunction(blockInfo) + fittedCoup1WeightEvaluationFunction(blockInfo) +
diff --git a/apps/benchmarks/GranularGas/check.h b/apps/benchmarks/GranularGas/check.h
index 73c457592ce0e78e976e8163e86dc346a16504bc..71652dcdce7fffbf4ee3219150f46f0c8ccfa20c 100644
--- a/apps/benchmarks/GranularGas/check.h
+++ b/apps/benchmarks/GranularGas/check.h
@@ -27,7 +27,7 @@
 namespace walberla {
 namespace mesa_pd {
 
-void check( data::ParticleStorage& ps, blockforest::BlockForest& forest, real_t spacing, const Vec3& shift )
+inline void check( data::ParticleStorage& ps, blockforest::BlockForest& forest, real_t spacing, const Vec3& shift )
 {
    WALBERLA_LOG_INFO_ON_ROOT("*** CHECKING RESULT - START ***");
    auto pIt = ps.begin();
diff --git a/apps/showcases/HeatConduction/ThermalExpansion.h b/apps/showcases/HeatConduction/ThermalExpansion.h
index c56ee0732258220a0b8e67edbaaeb519843d2db3..0818d527d58476684361c9ece4beb5d502611242 100644
--- a/apps/showcases/HeatConduction/ThermalExpansion.h
+++ b/apps/showcases/HeatConduction/ThermalExpansion.h
@@ -47,7 +47,7 @@ private:
    std::vector<real_t> linearExpansionCoefficient_ {};
 };
 
-ThermalExpansion::ThermalExpansion(const uint_t numParticleTypes)
+inline ThermalExpansion::ThermalExpansion(const uint_t numParticleTypes)
 {
    numParticleTypes_ = numParticleTypes;
 
diff --git a/extern/lodepng/lodepng.cpp b/extern/lodepng/lodepng.cpp
index 51492b887fde87faf0fbfc87899b79d2cc5e7969..3cf94e5929dc33f7f064e3731e0d20db122622ad 100644
--- a/extern/lodepng/lodepng.cpp
+++ b/extern/lodepng/lodepng.cpp
@@ -224,7 +224,7 @@ typedef struct uivector {
 static void uivector_cleanup(void* p) {
   ((uivector*)p)->size = ((uivector*)p)->allocsize = 0;
   lodepng_free(((uivector*)p)->data);
-  ((uivector*)p)->data = NULL;
+  ((uivector*)p)->data = nullptr;
 }
 
 /*returns 1 if success, 0 if failure ==> nothing done*/
@@ -244,7 +244,7 @@ static unsigned uivector_resize(uivector* p, size_t size) {
 }
 
 static void uivector_init(uivector* p) {
-  p->data = NULL;
+  p->data = nullptr;
   p->size = p->allocsize = 0;
 }
 
@@ -296,7 +296,7 @@ static ucvector ucvector_init(unsigned char* buffer, size_t size) {
 /*free string pointer and set it to NULL*/
 static void string_cleanup(char** out) {
   lodepng_free(*out);
-  *out = NULL;
+  *out = nullptr;
 }
 
 /*also appends null termination character*/
@@ -665,10 +665,10 @@ typedef struct HuffmanTree {
 } HuffmanTree;
 
 static void HuffmanTree_init(HuffmanTree* tree) {
-  tree->codes = 0;
-  tree->lengths = 0;
-  tree->table_len = 0;
-  tree->table_value = 0;
+  tree->codes = nullptr;
+  tree->lengths = nullptr;
+  tree->table_len = nullptr;
+  tree->table_value = nullptr;
 }
 
 static void HuffmanTree_cleanup(HuffmanTree* tree) {
@@ -897,8 +897,8 @@ static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMN
     for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0;
     for(i = 0; i != lists->listsize; ++i) {
       BPMNode* node;
-      for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1;
-      for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1;
+      for(node = lists->chains0[i]; node != nullptr; node = node->tail) node->in_use = 1;
+      for(node = lists->chains1[i]; node != nullptr; node = node->tail) node->in_use = 1;
     }
     /*collect those that are free*/
     lists->numfree = 0;
@@ -945,7 +945,7 @@ static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int
   if(c == 0) {
     if(lastindex >= numpresent) return;
     lists->chains0[c] = lists->chains1[c];
-    lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0);
+    lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, nullptr);
   } else {
     /*sum of the weights of the head nodes of the previous lookahead chains.*/
     int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight;
@@ -1016,8 +1016,8 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen
     if(!error) {
       for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i];
 
-      bpmnode_create(&lists, leaves[0].weight, 1, 0);
-      bpmnode_create(&lists, leaves[1].weight, 2, 0);
+      bpmnode_create(&lists, leaves[0].weight, 1, nullptr);
+      bpmnode_create(&lists, leaves[1].weight, 2, nullptr);
 
       for(i = 0; i != lists.listsize; ++i) {
         lists.chains0[i] = &lists.memory[0];
@@ -1134,10 +1134,10 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
   unsigned n, HLIT, HDIST, HCLEN, i;
 
   /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
-  unsigned* bitlen_ll = 0; /*lit,len code lengths*/
-  unsigned* bitlen_d = 0; /*dist code lengths*/
+  unsigned* bitlen_ll = nullptr; /*lit,len code lengths*/
+  unsigned* bitlen_d = nullptr; /*dist code lengths*/
   /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
-  unsigned* bitlen_cl = 0;
+  unsigned* bitlen_cl = nullptr;
   HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
 
   if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/
@@ -1825,11 +1825,11 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash,
   HuffmanTree tree_ll; /*tree for lit,len values*/
   HuffmanTree tree_d; /*tree for distance codes*/
   HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/
-  unsigned* frequencies_ll = 0; /*frequency of lit,len codes*/
-  unsigned* frequencies_d = 0; /*frequency of dist codes*/
-  unsigned* frequencies_cl = 0; /*frequency of code length codes*/
-  unsigned* bitlen_lld = 0; /*lit,len,dist code lengths (int bits), literally (without repeat codes).*/
-  unsigned* bitlen_lld_e = 0; /*bitlen_lld encoded with repeat codes (this is a rudimentary run length compression)*/
+  unsigned* frequencies_ll = nullptr; /*frequency of lit,len codes*/
+  unsigned* frequencies_d = nullptr; /*frequency of dist codes*/
+  unsigned* frequencies_cl = nullptr; /*frequency of code length codes*/
+  unsigned* bitlen_lld = nullptr; /*lit,len,dist code lengths (int bits), literally (without repeat codes).*/
+  unsigned* bitlen_lld_e = nullptr; /*bitlen_lld encoded with repeat codes (this is a rudimentary run length compression)*/
   size_t datasize = dataend - datapos;
 
   /*
@@ -2256,12 +2256,12 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig
                                size_t insize, const LodePNGCompressSettings* settings) {
   size_t i;
   unsigned error;
-  unsigned char* deflatedata = 0;
+  unsigned char* deflatedata = nullptr;
   size_t deflatesize = 0;
 
   error = deflate(&deflatedata, &deflatesize, in, insize, settings);
 
-  *out = NULL;
+  *out = nullptr;
   *outsize = 0;
   if(!error) {
     *outsize = deflatesize + 6;
@@ -2339,12 +2339,12 @@ void lodepng_compress_settings_init(LodePNGCompressSettings* settings) {
   settings->nicematch = 128;
   settings->lazymatching = 1;
 
-  settings->custom_zlib = 0;
-  settings->custom_deflate = 0;
-  settings->custom_context = 0;
+  settings->custom_zlib = nullptr;
+  settings->custom_deflate = nullptr;
+  settings->custom_context = nullptr;
 }
 
-const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0};
+const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, nullptr, nullptr, nullptr};
 
 
 #endif /*LODEPNG_COMPILE_ENCODER*/
@@ -2356,12 +2356,12 @@ void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) {
   settings->ignore_nlen = 0;
   settings->max_output_size = 0;
 
-  settings->custom_zlib = 0;
-  settings->custom_inflate = 0;
-  settings->custom_context = 0;
+  settings->custom_zlib = nullptr;
+  settings->custom_inflate = nullptr;
+  settings->custom_context = nullptr;
 }
 
-const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0, 0};
+const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, nullptr, nullptr, nullptr};
 
 #endif /*LODEPNG_COMPILE_DECODER*/
 
@@ -2547,7 +2547,7 @@ const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const
 
 unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]) {
   for(;;) {
-    if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */
+    if(chunk >= end || end - chunk < 12) return nullptr; /* past file end: chunk + 12 > end */
     if(lodepng_chunk_type_equals(chunk, type)) return chunk;
     chunk = lodepng_chunk_next(chunk, end);
   }
@@ -2555,7 +2555,7 @@ unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, cons
 
 const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]) {
   for(;;) {
-    if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */
+    if(chunk >= end || end - chunk < 12) return nullptr; /* past file end: chunk + 12 > end */
     if(lodepng_chunk_type_equals(chunk, type)) return chunk;
     chunk = lodepng_chunk_next_const(chunk, end);
   }
@@ -2669,7 +2669,7 @@ void lodepng_color_mode_init(LodePNGColorMode* info) {
   info->key_r = info->key_g = info->key_b = 0;
   info->colortype = LCT_RGBA;
   info->bitdepth = 8;
-  info->palette = 0;
+  info->palette = nullptr;
   info->palettesize = 0;
 }
 
@@ -2733,7 +2733,7 @@ static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColo
 
 void lodepng_palette_clear(LodePNGColorMode* info) {
   if(info->palette) lodepng_free(info->palette);
-  info->palette = 0;
+  info->palette = nullptr;
   info->palettesize = 0;
 }
 
@@ -2846,7 +2846,7 @@ static int lodepng_pixel_overflow(unsigned w, unsigned h,
 
 static void LodePNGUnknownChunks_init(LodePNGInfo* info) {
   unsigned i;
-  for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0;
+  for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = nullptr;
   for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0;
 }
 
@@ -2877,8 +2877,8 @@ static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo*
 
 static void LodePNGText_init(LodePNGInfo* info) {
   info->text_num = 0;
-  info->text_keys = NULL;
-  info->text_strings = NULL;
+  info->text_keys = nullptr;
+  info->text_strings = nullptr;
 }
 
 static void LodePNGText_cleanup(LodePNGInfo* info) {
@@ -2893,8 +2893,8 @@ static void LodePNGText_cleanup(LodePNGInfo* info) {
 
 static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) {
   size_t i = 0;
-  dest->text_keys = NULL;
-  dest->text_strings = NULL;
+  dest->text_keys = nullptr;
+  dest->text_strings = nullptr;
   dest->text_num = 0;
   for(i = 0; i != source->text_num; ++i) {
     CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i]));
@@ -2931,10 +2931,10 @@ void lodepng_clear_text(LodePNGInfo* info) {
 
 static void LodePNGIText_init(LodePNGInfo* info) {
   info->itext_num = 0;
-  info->itext_keys = NULL;
-  info->itext_langtags = NULL;
-  info->itext_transkeys = NULL;
-  info->itext_strings = NULL;
+  info->itext_keys = nullptr;
+  info->itext_langtags = nullptr;
+  info->itext_transkeys = nullptr;
+  info->itext_strings = nullptr;
 }
 
 static void LodePNGIText_cleanup(LodePNGInfo* info) {
@@ -2953,10 +2953,10 @@ static void LodePNGIText_cleanup(LodePNGInfo* info) {
 
 static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) {
   size_t i = 0;
-  dest->itext_keys = NULL;
-  dest->itext_langtags = NULL;
-  dest->itext_transkeys = NULL;
-  dest->itext_strings = NULL;
+  dest->itext_keys = nullptr;
+  dest->itext_langtags = nullptr;
+  dest->itext_transkeys = nullptr;
+  dest->itext_strings = nullptr;
   dest->itext_num = 0;
   for(i = 0; i != source->itext_num; ++i) {
     CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i],
@@ -3023,7 +3023,7 @@ unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned cha
 void lodepng_clear_icc(LodePNGInfo* info) {
   string_cleanup(&info->iccp_name);
   lodepng_free(info->iccp_profile);
-  info->iccp_profile = NULL;
+  info->iccp_profile = nullptr;
   info->iccp_profile_size = 0;
   info->iccp_defined = 0;
 }
@@ -3048,8 +3048,8 @@ void lodepng_info_init(LodePNGInfo* info) {
   info->chrm_defined = 0;
   info->srgb_defined = 0;
   info->iccp_defined = 0;
-  info->iccp_name = NULL;
-  info->iccp_profile = NULL;
+  info->iccp_name = nullptr;
+  info->iccp_profile = nullptr;
 
   LodePNGUnknownChunks_init(info);
 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
@@ -4038,7 +4038,7 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state,
                          const unsigned char* in, size_t insize) {
   unsigned width, height;
   LodePNGInfo* info = &state->info_png;
-  if(insize == 0 || in == 0) {
+  if(insize == 0 || in == nullptr) {
     CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/
   }
   if(insize < 33) {
@@ -4205,7 +4205,7 @@ static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w
   */
 
   unsigned y;
-  unsigned char* prevline = 0;
+  unsigned char* prevline = nullptr;
 
   /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
   size_t bytewidth = (bpp + 7u) / 8u;
@@ -4430,7 +4430,7 @@ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, siz
 /*text chunk (tEXt)*/
 static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {
   unsigned error = 0;
-  char *key = 0, *str = 0;
+  char *key = nullptr, *str = nullptr;
 
   while(!error) /*not really a while loop, only used to break on error*/ {
     unsigned length, string2_begin;
@@ -4476,8 +4476,8 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings*
   LodePNGDecompressSettings zlibsettings = decoder->zlibsettings;
 
   unsigned length, string2_begin;
-  char *key = 0;
-  unsigned char* str = 0;
+  char *key = nullptr;
+  unsigned char* str = nullptr;
   size_t size = 0;
 
   while(!error) /*not really a while loop, only used to break on error*/ {
@@ -4524,7 +4524,7 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings*
   LodePNGDecompressSettings zlibsettings = decoder->zlibsettings;
 
   unsigned length, begin, compressed;
-  char *key = 0, *langtag = 0, *transkey = 0;
+  char *key = nullptr, *langtag = nullptr, *transkey = nullptr;
 
   while(!error) /*not really a while loop, only used to break on error*/ {
     /*Quick check if the chunk length isn't too small. Even without check
@@ -4577,7 +4577,7 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings*
     length = (unsigned)chunkLength < begin ? 0 : (unsigned)chunkLength - begin;
 
     if(compressed) {
-      unsigned char* str = 0;
+      unsigned char* str = nullptr;
       size_t size = 0;
       zlibsettings.max_output_size = decoder->max_text_size;
       /*will fail if zlib error, e.g. if length is too small*/
@@ -4761,7 +4761,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
   const unsigned char* chunk;
   unsigned char* idat; /*the data from idat chunks, zlib compressed*/
   size_t idatsize = 0;
-  unsigned char* scanlines = 0;
+  unsigned char* scanlines = nullptr;
   size_t scanlines_size = 0, expected_size = 0;
   size_t outsize = 0;
 
@@ -4773,7 +4773,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
 
 
   /* safe output values in case error happens */
-  *out = 0;
+  *out = nullptr;
   *w = *h = 0;
 
   state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/
@@ -4951,7 +4951,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
 unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
                         LodePNGState* state,
                         const unsigned char* in, size_t insize) {
-  *out = 0;
+  *out = nullptr;
   decodeGeneric(out, w, h, state, in, insize);
   if(state->error) return state->error;
   if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) {
@@ -5013,11 +5013,11 @@ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const u
 #ifdef LODEPNG_COMPILE_DISK
 unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename,
                              LodePNGColorType colortype, unsigned bitdepth) {
-  unsigned char* buffer = 0;
+  unsigned char* buffer = nullptr;
   size_t buffersize;
   unsigned error;
   /* safe output values in case error happens */
-  *out = 0;
+  *out = nullptr;
   *w = *h = 0;
   error = lodepng_load_file(&buffer, &buffersize, filename);
   if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth);
@@ -5133,7 +5133,7 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) {
 }
 
 static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) {
-  unsigned char* chunk = 0;
+  unsigned char* chunk = nullptr;
 
   if(info->colortype == LCT_PALETTE) {
     size_t i, amount = info->palettesize;
@@ -5172,7 +5172,7 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) {
 static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize,
                               LodePNGCompressSettings* zlibsettings) {
   unsigned error = 0;
-  unsigned char* zlib = 0;
+  unsigned char* zlib = nullptr;
   size_t zlibsize = 0;
 
   error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings);
@@ -5184,13 +5184,13 @@ static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t d
 }
 
 static unsigned addChunk_IEND(ucvector* out) {
-  return lodepng_chunk_createv(out, 0, "IEND", 0);
+  return lodepng_chunk_createv(out, 0, "IEND", nullptr);
 }
 
 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
 
 static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) {
-  unsigned char* chunk = 0;
+  unsigned char* chunk = nullptr;
   size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring);
   size_t size = keysize + 1 + textsize;
   if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/
@@ -5205,8 +5205,8 @@ static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* te
 static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring,
                               LodePNGCompressSettings* zlibsettings) {
   unsigned error = 0;
-  unsigned char* chunk = 0;
-  unsigned char* compressed = 0;
+  unsigned char* chunk = nullptr;
+  unsigned char* compressed = nullptr;
   size_t compressedsize = 0;
   size_t textsize = lodepng_strlen(textstring);
   size_t keysize = lodepng_strlen(keyword);
@@ -5233,8 +5233,8 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te
 static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyword, const char* langtag,
                               const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) {
   unsigned error = 0;
-  unsigned char* chunk = 0;
-  unsigned char* compressed = 0;
+  unsigned char* chunk = nullptr;
+  unsigned char* compressed = nullptr;
   size_t compressedsize = 0;
   size_t textsize = lodepng_strlen(textstring);
   size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), transsize = lodepng_strlen(transkey);
@@ -5275,7 +5275,7 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyw
 }
 
 static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) {
-  unsigned char* chunk = 0;
+  unsigned char* chunk = nullptr;
   if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) {
     CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "bKGD"));
     chunk[8] = (unsigned char)(info->background_r >> 8);
@@ -5350,8 +5350,8 @@ static unsigned addChunk_sRGB(ucvector* out, const LodePNGInfo* info) {
 
 static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCompressSettings* zlibsettings) {
   unsigned error = 0;
-  unsigned char* chunk = 0;
-  unsigned char* compressed = 0;
+  unsigned char* chunk = nullptr;
+  unsigned char* compressed = nullptr;
   size_t compressedsize = 0;
   size_t keysize = lodepng_strlen(info->iccp_name);
 
@@ -5455,7 +5455,7 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
 
   /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
   size_t bytewidth = (bpp + 7u) / 8u;
-  const unsigned char* prevline = 0;
+  const unsigned char* prevline = nullptr;
   unsigned x, y;
   unsigned error = 0;
   LodePNGFilterStrategy strategy = settings->filter_strategy;
@@ -5600,8 +5600,8 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
     zlibsettings.btype = 1;
     /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
     images only, so disable it*/
-    zlibsettings.custom_zlib = 0;
-    zlibsettings.custom_deflate = 0;
+    zlibsettings.custom_zlib = nullptr;
+    zlibsettings.custom_deflate = nullptr;
     for(type = 0; type != 5; ++type) {
       attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
       if(!attempt[type]) error = 83; /*alloc fail*/
@@ -5614,7 +5614,7 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
 
           filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
           size[type] = 0;
-          dummy = 0;
+          dummy = nullptr;
           zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings);
           lodepng_free(dummy);
           /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
@@ -5814,16 +5814,16 @@ static unsigned isRGBICCProfile(const unsigned char* profile, unsigned size) {
 unsigned lodepng_encode(unsigned char** out, size_t* outsize,
                         const unsigned char* image, unsigned w, unsigned h,
                         LodePNGState* state) {
-  unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/
+  unsigned char* data = nullptr; /*uncompressed version of the IDAT chunk data*/
   size_t datasize = 0;
-  ucvector outv = ucvector_init(NULL, 0);
+  ucvector outv = ucvector_init(nullptr, 0);
   LodePNGInfo info;
   const LodePNGInfo* info_png = &state->info_png;
 
   lodepng_info_init(&info);
 
   /*provide some proper output values if error will happen*/
-  *out = 0;
+  *out = nullptr;
   *outsize = 0;
   state->error = 0;
 
@@ -6121,7 +6121,7 @@ void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) {
   settings->filter_strategy = LFS_MINSUM;
   settings->auto_convert = 1;
   settings->force_palette = 0;
-  settings->predefined_filters = 0;
+  settings->predefined_filters = nullptr;
 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
   settings->add_id = 0;
   settings->text_compression = 1;
@@ -6282,7 +6282,7 @@ unsigned load_file(std::vector<unsigned char>& buffer, const std::string& filena
 
 /*write given buffer to the file, overwriting the file, it doesn't append to it.*/
 unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename) {
-  return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str());
+  return lodepng_save_file(buffer.empty() ? nullptr : &buffer[0], buffer.size(), filename.c_str());
 }
 #endif /* LODEPNG_COMPILE_DISK */
 
@@ -6290,7 +6290,7 @@ unsigned save_file(const std::vector<unsigned char>& buffer, const std::string&
 #ifdef LODEPNG_COMPILE_DECODER
 unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
                     const LodePNGDecompressSettings& settings) {
-  unsigned char* buffer = 0;
+  unsigned char* buffer = nullptr;
   size_t buffersize = 0;
   unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);
   if(buffer) {
@@ -6302,14 +6302,14 @@ unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, si
 
 unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
                     const LodePNGDecompressSettings& settings) {
-  return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings);
+  return decompress(out, in.empty() ? nullptr : &in[0], in.size(), settings);
 }
 #endif /* LODEPNG_COMPILE_DECODER */
 
 #ifdef LODEPNG_COMPILE_ENCODER
 unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
                   const LodePNGCompressSettings& settings) {
-  unsigned char* buffer = 0;
+  unsigned char* buffer = nullptr;
   size_t buffersize = 0;
   unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
   if(buffer) {
@@ -6321,7 +6321,7 @@ unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size
 
 unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
                   const LodePNGCompressSettings& settings) {
-  return compress(out, in.empty() ? 0 : &in[0], in.size(), settings);
+  return compress(out, in.empty() ? nullptr : &in[0], in.size(), settings);
 }
 #endif /* LODEPNG_COMPILE_ENCODER */
 #endif /* LODEPNG_COMPILE_ZLIB */
@@ -6351,7 +6351,7 @@ State& State::operator=(const State& other) {
 
 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in,
                 size_t insize, LodePNGColorType colortype, unsigned bitdepth) {
-  unsigned char* buffer = 0;
+  unsigned char* buffer = nullptr;
   unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth);
   if(buffer && !error) {
     State state;
@@ -6366,13 +6366,13 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const
 
 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
                 const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth) {
-  return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth);
+  return decode(out, w, h, in.empty() ? nullptr : &in[0], (unsigned)in.size(), colortype, bitdepth);
 }
 
 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
                 State& state,
                 const unsigned char* in, size_t insize) {
-  unsigned char* buffer = NULL;
+  unsigned char* buffer = nullptr;
   unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
   if(buffer && !error) {
     size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
@@ -6385,7 +6385,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
                 State& state,
                 const std::vector<unsigned char>& in) {
-  return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size());
+  return decode(out, w, h, state, in.empty() ? nullptr : &in[0], in.size());
 }
 
 #ifdef LODEPNG_COMPILE_DISK
@@ -6418,7 +6418,7 @@ unsigned encode(std::vector<unsigned char>& out,
                 const std::vector<unsigned char>& in, unsigned w, unsigned h,
                 LodePNGColorType colortype, unsigned bitdepth) {
   if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
-  return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
+  return encode(out, in.empty() ? nullptr : &in[0], w, h, colortype, bitdepth);
 }
 
 unsigned encode(std::vector<unsigned char>& out,
@@ -6438,7 +6438,7 @@ unsigned encode(std::vector<unsigned char>& out,
                 const std::vector<unsigned char>& in, unsigned w, unsigned h,
                 State& state) {
   if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84;
-  return encode(out, in.empty() ? 0 : &in[0], w, h, state);
+  return encode(out, in.empty() ? nullptr : &in[0], w, h, state);
 }
 
 #ifdef LODEPNG_COMPILE_DISK
@@ -6455,7 +6455,7 @@ unsigned encode(const std::string& filename,
                 const std::vector<unsigned char>& in, unsigned w, unsigned h,
                 LodePNGColorType colortype, unsigned bitdepth) {
   if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
-  return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
+  return encode(filename, in.empty() ? nullptr : &in[0], w, h, colortype, bitdepth);
 }
 #endif /* LODEPNG_COMPILE_DISK */
 #endif /* LODEPNG_COMPILE_ENCODER */
diff --git a/python/lbmpy_walberla/templates/LatticeModel.tmpl.h b/python/lbmpy_walberla/templates/LatticeModel.tmpl.h
index 769ae027ce76a0c334dfe9107487f99aaa5fb488..9c41706914f016adf9320f46808f68ce7beb0536 100644
--- a/python/lbmpy_walberla/templates/LatticeModel.tmpl.h
+++ b/python/lbmpy_walberla/templates/LatticeModel.tmpl.h
@@ -109,7 +109,7 @@ public:
     class Sweep
     {
     public:
-        Sweep( BlockDataID _pdfsID ) : pdfsID(_pdfsID) {};
+        Sweep( BlockDataID _pdfsID ) : pdfsID(_pdfsID) {}
 
         //void stream       ( IBlock * const block, const uint_t numberOfGhostLayersToInclude = uint_t(0) );
         void collide      ( IBlock * const block, const uint_t numberOfGhostLayersToInclude = uint_t(0) );
@@ -134,7 +134,7 @@ public:
 
     {{class_name}}( {{stream_collide_kernel|generate_constructor_parameters(lmIgnores+lmOffsets) }} )
         : {{ stream_collide_kernel|generate_constructor_initializer_list(lmIgnores+lmOffsets) }}, currentLevel(0)
-    {};
+    {}
 
     void configure( IBlock & block, StructuredBlockStorage & storage )  { configureBlock( &block, &storage ); }
 
diff --git a/python/pystencils_walberla/sweep.py b/python/pystencils_walberla/sweep.py
index f6e190fded98f6063d5ccad4043daa34d3cb21da..85de00f06f151787e3d8025c6c357660933239ef 100644
--- a/python/pystencils_walberla/sweep.py
+++ b/python/pystencils_walberla/sweep.py
@@ -98,10 +98,10 @@ def generate_selective_sweep(generation_context, class_name, selection_tree, int
         ghost_layers_to_include: see documentation of `generate_sweep`
         cpu_vectorize_info: Dictionary containing information about CPU vectorization applied to the kernels
         cpu_openmp: Whether or not CPU kernels use OpenMP parallelization
-        max_threads: only relevant for GPU kernels. Will be argument of `__launch_bounds__
+        max_threads: only relevant for GPU kernels. Will be argument of `__launch_bounds__`
         block_offset: A tuple of TypedSymbols that will function as internal variable to store
                       storage.getBlockCellBB(block).min())
-`
+
     """
     def to_name(f):
         return f.name if isinstance(f, Field) else f
diff --git a/python/pystencils_walberla/templates/Boundary.tmpl.h b/python/pystencils_walberla/templates/Boundary.tmpl.h
index 43fd409eaaa9ba80cfb79bfc45016a5e02f13efb..8fcce482036fd762f867b0d37e1fea8571f95d6d 100644
--- a/python/pystencils_walberla/templates/Boundary.tmpl.h
+++ b/python/pystencils_walberla/templates/Boundary.tmpl.h
@@ -204,7 +204,7 @@ public:
         auto createForceVector = []( IBlock * const , StructuredBlockStorage * const ) { return new ForceVector(); };
         forceVectorID = blocks->addStructuredBlockData< ForceVector >( createForceVector, "forceVector_{{class_name}}");
         {%- endif %}
-    };
+    }
 
     void run (
         {{- ["IBlock * block", kernel.kernel_selection_parameters, ["gpuStream_t stream = nullptr"] if target == 'gpu' else []] | type_identifier_list -}}
diff --git a/python/pystencils_walberla/templates/CpuPackInfo.tmpl.cpp b/python/pystencils_walberla/templates/CpuPackInfo.tmpl.cpp
index 0191994f3f3a29ef9384b2a2270294be9df59f43..15c5d7bef76b9b51d310ec0a823a4a61c24df833 100644
--- a/python/pystencils_walberla/templates/CpuPackInfo.tmpl.cpp
+++ b/python/pystencils_walberla/templates/CpuPackInfo.tmpl.cpp
@@ -117,7 +117,7 @@ uint_t {{class_name}}::size(stencil::Direction dir, const IBlock * block) const
     CellInterval ci;
     {{field_name}}->getGhostRegion(dir, ci, 1, false);
 
-    uint_t elementsPerCell = 0;
+    uint_t elementsPerCell = uint_t{ 0u };
 
     switch( dir )
     {
@@ -125,11 +125,11 @@ uint_t {{class_name}}::size(stencil::Direction dir, const IBlock * block) const
         {%- for dir in direction_set %}
         case stencil::{{dir}}:
         {%- endfor %}
-            elementsPerCell = {{elements}};
+            elementsPerCell = uint_t{ {{elements}}u };
             break;
         {% endfor %}
         default:
-            elementsPerCell = 0;
+            elementsPerCell = uint_t{ 0u };
     }
     return ci.numCells() * elementsPerCell * sizeof( {{dtype}} );
 }
diff --git a/python/pystencils_walberla/templates/CpuPackInfo.tmpl.h b/python/pystencils_walberla/templates/CpuPackInfo.tmpl.h
index 716da04458518664fa050047b499023d90780be2..4e1f85fd171c81899b327b0695d8565e0bc0c645 100644
--- a/python/pystencils_walberla/templates/CpuPackInfo.tmpl.h
+++ b/python/pystencils_walberla/templates/CpuPackInfo.tmpl.h
@@ -46,13 +46,13 @@ class {{class_name}} : public ::walberla::communication::UniformPackInfo
 public:
     {{class_name}}( {{fused_kernel|generate_constructor_parameters(parameters_to_ignore=['buffer'])}} )
         : {{ fused_kernel|generate_constructor_initializer_list(parameters_to_ignore=['buffer']) }}
-    {};
-    virtual ~{{class_name}}() {}
+    {}
+    ~{{class_name}}() override = default;
 
-   bool constantDataExchange() const { return true; }
-   bool threadsafeReceiving()  const { return true; }
+   bool constantDataExchange() const override { return true; }
+   bool threadsafeReceiving()  const override { return true; }
 
-   void unpackData(IBlock * receiver, stencil::Direction dir, mpi::RecvBuffer & buffer) {
+   void unpackData(IBlock * receiver, stencil::Direction dir, mpi::RecvBuffer & buffer) override {
         const auto dataSize = size(dir, receiver);
         auto bufferSize = dataSize + sizeof({{dtype}});
         auto bufferPtr = reinterpret_cast<void*>(buffer.skip(bufferSize));
@@ -60,7 +60,7 @@ public:
         unpack(dir, reinterpret_cast<unsigned char*>(bufferPtr), receiver);
    }
 
-   void communicateLocal(const IBlock * sender, IBlock * receiver, stencil::Direction dir) {
+   void communicateLocal(const IBlock * sender, IBlock * receiver, stencil::Direction dir) override {
        //TODO: optimize by generating kernel for this case
        mpi::SendBuffer sBuffer;
        packData( sender, dir, sBuffer );
@@ -68,7 +68,7 @@ public:
        unpackData( receiver, stencil::inverseDir[dir], rBuffer );
    }
 
-   void packDataImpl(const IBlock * sender, stencil::Direction dir, mpi::SendBuffer & outBuffer) const {
+   void packDataImpl(const IBlock * sender, stencil::Direction dir, mpi::SendBuffer & outBuffer) const override {
         const auto dataSize = size(dir, sender);
         auto bufferSize = dataSize + sizeof({{dtype}});
         auto bufferPtr = reinterpret_cast<void*>(outBuffer.forward(bufferSize));
diff --git a/python/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp b/python/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp
index 48440b5b4366204157b0486cadf5c14295dbfcc0..6a385fa851f525155d5f919c6de14868627aa11a 100644
--- a/python/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp
+++ b/python/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp
@@ -17,6 +17,13 @@
 //! \\author pystencils
 //======================================================================================================================
 
+#include "core/DataTypes.h"
+#include "core/cell/CellInterval.h"
+
+#include "domain_decomposition/IBlock.h"
+
+#include "stencil/Directions.h"
+
 #include "{{class_name}}.h"
 
 {% if target is equalto 'cpu' -%}
diff --git a/python/pystencils_walberla/templates/GpuPackInfo.tmpl.h b/python/pystencils_walberla/templates/GpuPackInfo.tmpl.h
index cd5b23677e963266ea02247be3473c57bc4aac43..06312a1474cf9d7f2b3fa1ab583e04cf7c739a32 100644
--- a/python/pystencils_walberla/templates/GpuPackInfo.tmpl.h
+++ b/python/pystencils_walberla/templates/GpuPackInfo.tmpl.h
@@ -20,7 +20,6 @@
 #pragma once
 
 #include "core/DataTypes.h"
-#include "core/cell/CellInterval.h"
 
 #include "domain_decomposition/IBlock.h"
 
@@ -53,8 +52,8 @@ class {{class_name}} : public ::walberla::gpu::GeneratedGPUPackInfo
 public:
     {{class_name}}( {{fused_kernel|generate_constructor_parameters(parameters_to_ignore=['buffer'])}} )
         : {{ fused_kernel|generate_constructor_initializer_list(parameters_to_ignore=['buffer']) }}
-    {};
-    virtual ~{{class_name}}() {}
+    {}
+    ~{{class_name}}() override = default;
 
     void pack  (stencil::Direction dir, unsigned char * buffer, IBlock * block, gpuStream_t stream) override;
     void communicateLocal  ( stencil::Direction /*dir*/, const IBlock* /* sender */, IBlock* /* receiver */, gpuStream_t /* stream */ ) override
diff --git a/python/pystencils_walberla/templates/Sweep.tmpl.h b/python/pystencils_walberla/templates/Sweep.tmpl.h
index bebbe855c33cf00fc825ca51d5a057f05fa079a1..b146a848cf33a72c319428d81f3a13676d0b0657 100644
--- a/python/pystencils_walberla/templates/Sweep.tmpl.h
+++ b/python/pystencils_walberla/templates/Sweep.tmpl.h
@@ -32,7 +32,9 @@
 #include "domain_decomposition/BlockDataID.h"
 #include "domain_decomposition/IBlock.h"
 #include "domain_decomposition/StructuredBlockStorage.h"
-#include <set>
+
+#include <functional>
+#include <unordered_map>
 
 {% for header in interface_spec.headers %}
 #include {{header}}
@@ -60,8 +62,8 @@ class {{class_name}}
 {
 public:
    {{class_name}}( {{kernel|generate_constructor_parameters(parameters_to_ignore=parameters_to_ignore)}} {%if inner_outer_split%}, const Cell & outerWidth=Cell(1, 1, 1){% endif %})
-     : {{ kernel|generate_constructor_initializer_list(parameters_to_ignore=parameters_to_ignore) }}{%if inner_outer_split%}{% if kernel|generate_constructor_initializer_list|length %},{% endif %} outerWidth_(outerWidth){% endif %}{%if block_offset%}, configured_(false){% endif %}
-   {};
+     : {{ kernel|generate_constructor_initializer_list(parameters_to_ignore=parameters_to_ignore) }}{%if inner_outer_split%}{% if kernel|generate_constructor_initializer_list|length %},{% endif %} outerWidth_(outerWidth){% endif %}{%if block_offset%}{% for offset in block_offset -%}, {{offset[0]}}_({{offset[1]}}(0)) {% endfor -%}, configured_(false){% endif %}
+   {}
 
    {{ kernel| generate_destructor(class_name) |indent(3) }}
 
diff --git a/src/blockforest/BlockForest.cpp b/src/blockforest/BlockForest.cpp
index 50ebc8c27db75b4f309cec7ef6cebb9620c0e0d1..495da585dd97ab39679cebdd38e1267c1c44e018 100644
--- a/src/blockforest/BlockForest.cpp
+++ b/src/blockforest/BlockForest.cpp
@@ -74,7 +74,7 @@ void BlockForest::BlockInformation::getAllBlocks( std::vector< shared_ptr< IBloc
 
       std::stack< std::pair< const Node *, BlockID > > stack;
 
-      stack.push( std::make_pair( nodes_[i].get(), BlockID( i, treeIdMarker ) ) );
+      stack.emplace( nodes_[i].get(), BlockID( i, treeIdMarker ) );
 
       while( !stack.empty() ) {
 
@@ -85,7 +85,7 @@ void BlockForest::BlockInformation::getAllBlocks( std::vector< shared_ptr< IBloc
 
          if( !node.first->children_.empty() ) {
             for( uint_t c = 8; c-- != 0; )
-               stack.push( std::make_pair( node.first->children_[c].get(), BlockID( node.second, c ) ) );
+               stack.emplace( node.first->children_[c].get(), BlockID( node.second, c ) );
          }
          else {
             blocks.push_back( make_shared< BlockID >( node.second ) );
@@ -2540,7 +2540,7 @@ void BlockForest::update( PhantomBlockForest & phantomForest )
          if( phantom->sourceBlockHasTheSameSize() || phantom->sourceBlockIsLarger() )
          {
             WALBERLA_ASSERT( blocksToUnpack.find( block ) == blocksToUnpack.end() );
-            blocksToUnpack[ block ].push_back( std::make_pair( state, &(*buffer) ) );
+            blocksToUnpack[ block ].emplace_back( state, &(*buffer) );
          }
          else
          {
diff --git a/src/blockforest/BlockForest.h b/src/blockforest/BlockForest.h
index 58df1ba4cfa8d99f7a5c1b437c67dfec61109d4e..c000ecff5f8fd484857b06ebda0bed7be79e4907 100644
--- a/src/blockforest/BlockForest.h
+++ b/src/blockforest/BlockForest.h
@@ -27,6 +27,7 @@
 #include "PhantomBlockForest.h"
 #include "Types.h"
 
+#include "core/EndianIndependentSerialization.h"
 #include "core/debug/Debug.h"
 #include "core/math/Uint.h"
 #include "core/timing/TimingPool.h"
diff --git a/src/blockforest/CMakeLists.txt b/src/blockforest/CMakeLists.txt
index 5be89206166c2e638975e3f41265de0fe43cbb44..0c4e8f8bcf26d9fad475aada504f7a8ff088f9a1 100644
--- a/src/blockforest/CMakeLists.txt
+++ b/src/blockforest/CMakeLists.txt
@@ -45,7 +45,6 @@ target_sources( blockforest
       SetupBlock.cpp
       SetupBlockForest.cpp
       StructuredBlockForest.cpp
-      Utility.cpp
       )
 
 add_subdirectory( communication )
diff --git a/src/blockforest/GlobalLoadBalancing.h b/src/blockforest/GlobalLoadBalancing.h
index ba92b73f23d751e2592e253b3a5f001fba227365..ca1509453d683bf2457c1d91a0c6a1b9f465fb75 100644
--- a/src/blockforest/GlobalLoadBalancing.h
+++ b/src/blockforest/GlobalLoadBalancing.h
@@ -497,7 +497,7 @@ inline uint_t GlobalLoadBalancing::minimizeProcesses( const std::vector< BLOCK*
 
 #ifdef WALBERLA_BUILD_WITH_METIS
 
-   if( numberOfProcesses > 1 && metisConfig.includeMetis() && processesWork == NULL && processesMemory == NULL ) {
+   if( numberOfProcesses > 1 && metisConfig.includeMetis() && processesWork == nullptr && processesMemory == nullptr ) {
 
       uint_t max = numberOfProcesses;
       uint_t min = uint_c( real_c(0.5) + ( real_c( memorySum( blocks ) ) / memoryLimit ) );
@@ -819,8 +819,8 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me
 
    // first call to METIS: always try to balance the workload as good as possible, but allow large imbalances concerning the memory (-> ubvec[1])
 
-   int ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL,
-                                             &(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) );
+   int ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), nullptr, &(adjwgt[0]), &nparts, nullptr,
+                                             &(ubvec[0]), nullptr /*idx t *options*/, &objval, &(part[0]) );
 
    // if METIS was successful AND the memory limit of each process is not violated (which is highly unlikely due to a large value for ubvec[1])
    // then the algorithm is finished
@@ -844,8 +844,8 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me
    real_t minUbvec = real_t(1);
    ubvec[1] = minUbvec;
 
-   ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL,
-                                         &(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) );
+   ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), nullptr, &(adjwgt[0]), &nparts, nullptr,
+                                         &(ubvec[0]), nullptr /*idx t *options*/, &objval, &(part[0]) );
 
    // ... if this doesn't work OR if the memory limit is still violated then METIS is unable to find a valid partitioning
 
@@ -881,8 +881,8 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me
 
       ubvec[1] = ( maxUbvec + minUbvec ) / real_c(2);
 
-      ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL,
-                                            &(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) );
+      ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), nullptr, &(adjwgt[0]), &nparts, nullptr,
+                                            &(ubvec[0]), nullptr /*idx t *options*/, &objval, &(part[0]) );
 
       if( ret == core::METIS_OK && metisMaxMemory( blocks, numberOfProcesses, part ) <= memoryLimit ) {
 
@@ -998,8 +998,8 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
    options[ core::METIS_OPTION_NSEPS ] = 100;
    options[ core::METIS_OPTION_NCUTS ] = 100;
    
-   int ret = core::METIS_PartGraphKway( &nvtxs, &ncon, &( xadj[ 0 ] ), &( adjncy[ 0 ] ), &( vwgt[ 0 ] ), NULL, &( adjwgt[0] ), 
-                                  &nparts, NULL, NULL, options, &objval, &( part[ 0 ] ) );
+   int ret = core::METIS_PartGraphKway( &nvtxs, &ncon, &( xadj[ 0 ] ), &( adjncy[ 0 ] ), &( vwgt[ 0 ] ), nullptr, &( adjwgt[0] ),
+                                  &nparts, nullptr, nullptr, options, &objval, &( part[ 0 ] ) );
 
    if( ret != core::METIS_OK ) 
    {
diff --git a/src/blockforest/Utility.cpp b/src/blockforest/Utility.cpp
deleted file mode 100644
index b31f4147532ecd719773fde8c343348f3f3fd9ec..0000000000000000000000000000000000000000
--- a/src/blockforest/Utility.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-//======================================================================================================================
-//
-//  This file is part of waLBerla. waLBerla is free software: you can 
-//  redistribute it and/or modify it under the terms of the GNU General Public
-//  License as published by the Free Software Foundation, either version 3 of 
-//  the License, or (at your option) any later version.
-//  
-//  waLBerla is distributed in the hope that it will be useful, but WITHOUT 
-//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
-//  for more details.
-//  
-//  You should have received a copy of the GNU General Public License along
-//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
-//
-//! \file Utility.cpp
-//! \ingroup blockforest
-//! \author Florian Schornbaum <florian.schornbaum@fau.de>
-//
-//======================================================================================================================
-
-#include "Utility.h"
-
-#include <iomanip>
-#include <sstream>
-#include <stack>
-
-
-namespace walberla {
-namespace blockforest {
-
-
-
-std::string naturalNumberToGroupedThousandsString( uint_t number, const char separator ) { // for the documentation see the header file
-
-   std::ostringstream oss;
-
-   std::stack< uint_t > numbers;
-
-   while( true ) {
-
-      numbers.push( number % 1000 );
-
-      if( number <= 999 ) break;
-
-      number /= 1000;
-   }
-
-   oss << numbers.top();
-   numbers.pop();
-
-   while( !numbers.empty() ) {
-
-      oss << separator << std::setfill( '0' ) << std::setw( 3 ) << numbers.top();
-      oss << std::setw( 0 );
-      numbers.pop();
-   }
-
-   return oss.str();
-}
-
-
-
-} // namespace blockforest
-} // namespace walberla
diff --git a/src/blockforest/Utility.h b/src/blockforest/Utility.h
index 8a6f304619e83a1f3cfad138b81e8124f60f50ab..842b916629cdc6ce4fe32891c4b9bae229d83b99 100644
--- a/src/blockforest/Utility.h
+++ b/src/blockforest/Utility.h
@@ -28,9 +28,7 @@
 #include "core/math/Uint.h"
 
 #include <limits>
-#include <ostream>
 #include <string>
-#include <vector>
 
 
 namespace walberla {
@@ -110,27 +108,5 @@ inline memory_t bytesToMiB( memory_t bytes ) {
 }
 
 
-
-//**********************************************************************************************************************
-/*!
-*   \brief Returns the string representation of 'number', every three digits the character 'separator' is inserted
-*          (172408725 -> "172 408 725")
-*/
-//**********************************************************************************************************************
-std::string naturalNumberToGroupedThousandsString( const uint_t number, const char separator = ' ' );
-
-inline std::string naturalNumberToGroupedThousandsString( const real_t number, const char separator = ' ' ) {
-
-   return naturalNumberToGroupedThousandsString( static_cast< uint_t >( 0.5 + number ), separator );
-}
-
-
-
-inline void fillStream( std::ostream& ostream, const char fill, uint_t length ) {
-   while( length-- > 0 ) ostream << fill;
-}
-
-
-
 } // namespace blockforest
 } // namespace walberla
diff --git a/src/blockforest/communication/NonUniformBufferedScheme.h b/src/blockforest/communication/NonUniformBufferedScheme.h
index ff1d3ba3b85f97d558378f1125b00816d734307b..0a6a453abacef502f5620d2d9c3c59514e9e8fc6 100644
--- a/src/blockforest/communication/NonUniformBufferedScheme.h
+++ b/src/blockforest/communication/NonUniformBufferedScheme.h
@@ -851,7 +851,7 @@ void NonUniformBufferedScheme<Stencil>::startCommunicationCoarseToFine( const ui
 
       resetBufferSystem( bufferSystem );
 
-      for( auto sender : sendFunctions )
+      for( auto const &sender : sendFunctions )
          bufferSystem->addSendingFunction( int_c(sender.first), std::bind(  NonUniformBufferedScheme<Stencil>::send, std::placeholders::_1, sender.second ) );
 
       for(auto receiver : ranksToReceiveFrom)
@@ -996,7 +996,7 @@ void NonUniformBufferedScheme<Stencil>::startCommunicationFineToCoarse( const ui
 
       resetBufferSystem( bufferSystem );
 
-      for( auto sender : sendFunctions )
+      for( auto const &sender : sendFunctions )
          bufferSystem->addSendingFunction( int_c(sender.first), std::bind(  NonUniformBufferedScheme<Stencil>::send, std::placeholders::_1, sender.second ) );
 
       for(auto receiver : ranksToReceiveFrom)
diff --git a/src/blockforest/communication/UniformToNonUniformPackInfoAdapter.h b/src/blockforest/communication/UniformToNonUniformPackInfoAdapter.h
index f0e5838b4f8879019d2ede96538db39dc6182860..6c792bd6e21b20d2f3e14b76d78ee4b7bc3a6124 100644
--- a/src/blockforest/communication/UniformToNonUniformPackInfoAdapter.h
+++ b/src/blockforest/communication/UniformToNonUniformPackInfoAdapter.h
@@ -44,7 +44,7 @@ public:
    /*! \name Construction & Destruction */
    //@{
    UniformToNonUniformPackInfoAdapter( const shared_ptr<walberla::communication::UniformPackInfo> & uniformPackInfo ) : uniformPackInfo_( uniformPackInfo ) { }
-   virtual ~UniformToNonUniformPackInfoAdapter() { }
+   ~UniformToNonUniformPackInfoAdapter() override = default;
    //@}
    //****************************************************************************************************************
 
@@ -55,7 +55,7 @@ public:
    * Falsely return true will lead to errors! However, if the data can be guaranteed to remain
    * constant over time, returning true enables performance optimizations during the communication.
    */
-   virtual bool constantDataExchange() const { return uniformPackInfo_->constantDataExchange(); }
+   bool constantDataExchange() const override { return uniformPackInfo_->constantDataExchange(); }
 
    /**
    * Must return false if calling `unpackData*()` and/or `communicateLocal*()` methods is not thread-safe.
@@ -64,29 +64,29 @@ public:
    * Falsely return true will most likely lead to errors! However, if both `unpackData*()` AND
    * `communicateLocal*()` are thread-safe, returning true can lead to performance improvements.
    */
-   virtual bool threadsafeReceiving() const { return uniformPackInfo_->threadsafeReceiving(); }
+   bool threadsafeReceiving() const override { return uniformPackInfo_->threadsafeReceiving(); }
 
    /// If NOT thread-safe, \ref threadsafeReceiving must return false!
-   virtual void unpackDataEqualLevel( Block * receiver, stencil::Direction dir, mpi::RecvBuffer & buffer ) { uniformPackInfo_->unpackData( receiver, dir, buffer ); }
+   void unpackDataEqualLevel( Block * receiver, stencil::Direction dir, mpi::RecvBuffer & buffer ) override { uniformPackInfo_->unpackData( receiver, dir, buffer ); }
 
    /// If NOT thread-safe, \ref threadsafeReceiving must return false!
-   virtual void communicateLocalEqualLevel( const Block * sender, Block * receiver, stencil::Direction dir ) { uniformPackInfo_->communicateLocal( sender, receiver, dir ); }
+   void communicateLocalEqualLevel( const Block * sender, Block * receiver, stencil::Direction dir ) override { uniformPackInfo_->communicateLocal( sender, receiver, dir ); }
 
-   virtual void unpackDataCoarseToFine( Block * /*fineReceiver*/, const BlockID & /*coarseSender*/, stencil::Direction /*dir*/, mpi::RecvBuffer & /*buffer*/ ) { }
-   virtual void communicateLocalCoarseToFine( const Block * /*coarseSender*/, Block * /*fineReceiver*/, stencil::Direction /*dir*/ ) { }
+   void unpackDataCoarseToFine( Block * /*fineReceiver*/, const BlockID & /*coarseSender*/, stencil::Direction /*dir*/, mpi::RecvBuffer & /*buffer*/ ) override { }
+   void communicateLocalCoarseToFine( const Block * /*coarseSender*/, Block * /*fineReceiver*/, stencil::Direction /*dir*/ ) override { }
 
-   virtual void unpackDataFineToCoarse( Block * /*coarseReceiver*/, const BlockID & /*fineSender*/, stencil::Direction /*dir*/, mpi::RecvBuffer & /*buffer*/ ) { }
-   virtual void communicateLocalFineToCoarse( const Block * /*fineSender*/, Block * /*coarseReceiver*/, stencil::Direction /*dir*/ ) { }
+   void unpackDataFineToCoarse( Block * /*coarseReceiver*/, const BlockID & /*fineSender*/, stencil::Direction /*dir*/, mpi::RecvBuffer & /*buffer*/ ) override { }
+   void communicateLocalFineToCoarse( const Block * /*fineSender*/, Block * /*coarseReceiver*/, stencil::Direction /*dir*/ ) override { }
 
 protected:
 
    shared_ptr<walberla::communication::UniformPackInfo> uniformPackInfo_;
 
    /// Must be thread-safe!
-   virtual void packDataEqualLevelImpl( const Block * sender, stencil::Direction dir, mpi::SendBuffer & buffer ) const { uniformPackInfo_->packData( sender, dir, buffer ); }
+   void packDataEqualLevelImpl( const Block * sender, stencil::Direction dir, mpi::SendBuffer & buffer ) const override { uniformPackInfo_->packData( sender, dir, buffer ); }
 
-   virtual void packDataCoarseToFineImpl( const Block * /*coarseSender*/, const BlockID &   /*fineReceiver*/, stencil::Direction /*dir*/, mpi::SendBuffer & /*buffer*/ ) const { }
-   virtual void packDataFineToCoarseImpl( const Block *   /*fineSender*/, const BlockID & /*coarseReceiver*/, stencil::Direction /*dir*/, mpi::SendBuffer & /*buffer*/ ) const { }
+   void packDataCoarseToFineImpl( const Block * /*coarseSender*/, const BlockID &   /*fineReceiver*/, stencil::Direction /*dir*/, mpi::SendBuffer & /*buffer*/ ) const override { }
+   void packDataFineToCoarseImpl( const Block *   /*fineSender*/, const BlockID & /*coarseReceiver*/, stencil::Direction /*dir*/, mpi::SendBuffer & /*buffer*/ ) const override { }
 };
 
 
diff --git a/src/boundary/BoundaryHandling.h b/src/boundary/BoundaryHandling.h
index 9aa5a34390fb71d7479d512130dca4d81dc982b6..a3bff17631f979719fe1354c0a00b2b8c75f8b23 100644
--- a/src/boundary/BoundaryHandling.h
+++ b/src/boundary/BoundaryHandling.h
@@ -432,7 +432,7 @@ private:
          WALBERLA_ABORT( "The requested boundary condition " << uid.getIdentifier() << " is not part of this boundary handling." );
 
 #ifdef __IBMCPP__
-      return *(reinterpret_cast< Boundary_T * >( NULL )); // silencing incorrect IBM compiler warning
+      return *(static_cast< Boundary_T * >( nullptr )); // silencing incorrect IBM compiler warning
 #endif
    }
 
@@ -457,7 +457,7 @@ private:
 
    template< typename Boundary_T, typename BoundariesTuple, int N = std::tuple_size<BoundariesTuple>::value - 1 >
    inline const typename std::enable_if<(N!=0), Boundary_T>::type & getBoundaryCondition_TypeExists( const BoundaryUID & uid, const BoundariesTuple & boundaryConditions,
-                                                              typename std::enable_if< std::is_same< Boundary_T, typename std::tuple_element<N, BoundariesTuple>::type >::value >::type* /*dummy*/ = 0 ) const
+                                                              typename std::enable_if< std::is_same< Boundary_T, typename std::tuple_element<N, BoundariesTuple>::type >::value >::type* /*dummy*/ = nullptr ) const
    {
       if( uid == std::get<N>( boundaryConditions ).getUID() )
          return std::get<N>( boundaryConditions );
@@ -475,7 +475,7 @@ private:
          WALBERLA_ABORT( "The requested boundary condition " << uid.getIdentifier() << " is not part of this boundary handling." );
 
 #ifdef __IBMCPP__
-      return *(reinterpret_cast< Boundary_T * >( NULL )); // silencing incorrect IBM compiler warning
+      return *(static_cast< Boundary_T * >( nullptr )); // silencing incorrect IBM compiler warning
 #endif
    }
 
@@ -495,7 +495,7 @@ private:
       WALBERLA_ABORT( "The requested boundary condition " << uid.getIdentifier() << " is not part of this boundary handling." );
 
 #ifdef __IBMCPP__
-      return *(reinterpret_cast< Boundary_T * >( NULL )); // silencing incorrect IBM compiler warning
+      return *(static_cast< Boundary_T * >( nullptr )); // silencing incorrect IBM compiler warning
 #endif
    }
 
@@ -2501,7 +2501,7 @@ inline typename std::enable_if<(N==-1), BoundaryUID>::type BoundaryHandling< Fla
                    "boundary handling " << uid_.getIdentifier() << "!" );
 
 #ifdef __IBMCPP__
-   return *(reinterpret_cast< BoundaryUID * >( NULL )); // silencing incorrect IBM compiler warning
+   return *(static_cast< BoundaryUID * >( nullptr )); // silencing incorrect IBM compiler warning
 #endif
 }
 
diff --git a/src/core/Array.h b/src/core/Array.h
index 42ab4efe51118b5edecb211b9066299466725ebc..dcb69e89bf146de133e64553dec79378970c0d2e 100644
--- a/src/core/Array.h
+++ b/src/core/Array.h
@@ -46,7 +46,7 @@ public:
    inline Array( const std::vector<T>& vector );
    inline Array( const Array& array );
 
-   ~Array() { if( array_ != nullptr ) delete[] array_; }
+   ~Array() { delete[] array_; }
 
    uint_t size() const { return size_; }
    bool  empty() const { return size_ == 0; }
@@ -78,7 +78,7 @@ protected:
 
 
 template< typename T >
-inline Array<T>::Array( const uint_t n, const T& t ) : array_( n == 0 ? NULL : new T[n] ), size_( n )
+inline Array<T>::Array( const uint_t n, const T& t ) : array_( n == 0 ? nullptr : new T[n] ), size_( n )
 {
    for( uint_t i = 0; i != n; ++i )
       array_[i] = t;
@@ -89,7 +89,7 @@ inline Array<T>::Array( const uint_t n, const T& t ) : array_( n == 0 ? NULL : n
 template< typename T >
 inline Array<T>::Array( const std::vector<T>& vector ) :
 
-   array_( vector.size() == 0 ? NULL : new T[ vector.size() ] ), size_( vector.size() )
+   array_( vector.empty() ? nullptr : new T[ vector.size() ] ), size_( vector.size() )
 {
    for( uint_t i = 0; i != size_; ++i )
       array_[i] = vector[i];
@@ -100,7 +100,7 @@ inline Array<T>::Array( const std::vector<T>& vector ) :
 template< typename T >
 inline Array<T>::Array( const Array& array ) :
 
-   array_( array.size_ == 0 ? NULL : new T[ array.size_ ] ), size_( array.size_ )
+   array_( array.size_ == 0 ? nullptr : new T[ array.size_ ] ), size_( array.size_ )
 {
    for( uint_t i = 0; i != size_; ++i )
       array_[i] = array.array_[i];
diff --git a/src/core/OpenMP.h b/src/core/OpenMP.h
index b8ae3d6077ea8e5467fa84deecc959f5be80bb4c..5e454f37fdf463a117c17d0711ecd2901c5e4fb1 100644
--- a/src/core/OpenMP.h
+++ b/src/core/OpenMP.h
@@ -131,7 +131,7 @@ inline int   omp_get_num_teams (void) { WALBERLA_OPENMP_FUNCTION_ERROR }
 inline int   omp_get_team_num (void) { WALBERLA_OPENMP_FUNCTION_ERROR }
 inline int   omp_get_cancellation (void) { WALBERLA_OPENMP_FUNCTION_ERROR }
 
-#   include <stdlib.h>
+#   include <stdlib.h> // NOLINT(modernize-deprecated-headers)
 /* OpenMP 4.5 */
 inline int    omp_get_initial_device (void) { WALBERLA_OPENMP_FUNCTION_ERROR }
 inline void*  omp_target_alloc(size_t, int) { WALBERLA_OPENMP_FUNCTION_ERROR }
diff --git a/src/core/Set.h b/src/core/Set.h
index cbc0d5c1196404f4fb71d72492c40a7a326b03c2..de9ca7841336a1282ee99322c0b210830bfa7d46 100644
--- a/src/core/Set.h
+++ b/src/core/Set.h
@@ -130,7 +130,7 @@ public:
 
    inline size_t size() const { return set_.size(); }
 
-   inline void swap( Set<T>& set ) { set_.swap( set.set_ ); }
+   inline void swap( Set<T>& set ) noexcept { set_.swap( set.set_ ); }
 
           void        toStream( std::ostream& os ) const;
    inline std::string toString() const;
diff --git a/src/core/StringUtility.impl.h b/src/core/StringUtility.impl.h
index 02b5f3937216ea5345368505ef8664ec53b1eb34..ac3b298875a0676a5311ca8bac2873f5f1a703d5 100644
--- a/src/core/StringUtility.impl.h
+++ b/src/core/StringUtility.impl.h
@@ -21,8 +21,6 @@
 
 #pragma once
 
-#include "core/StringUtility.h"
-
 #include <algorithm>
 #include <cctype>
 #include <string>
diff --git a/src/core/all.h b/src/core/all.h
index 2e804b55a1b2a6ec878d7321612dfe97d56f047d..0315463dac86c2de50c01b292df89e088b8d4771 100644
--- a/src/core/all.h
+++ b/src/core/all.h
@@ -26,7 +26,6 @@
 #include "AllSet.h"
 #include "Array.h"
 #include "DataTypes.h"
-#include "EndianIndependentSerialization.h"
 #include "Environment.h"
 #include "FunctionTraits.h"
 #include "GetPID.h"
diff --git a/src/core/cell/CellInterval.h b/src/core/cell/CellInterval.h
index 7b766fa3763bb890aca15b5f5c31e6891c54ee7d..6019ac71ce9a188998e7c13e463796f18df0336c 100644
--- a/src/core/cell/CellInterval.h
+++ b/src/core/cell/CellInterval.h
@@ -236,6 +236,7 @@ inline bool CellInterval::overlaps( const CellInterval& other ) const
    if( empty() || other.empty() )
       return false;
 
+   // NOLINTNEXTLINE(readability-simplify-boolean-expr)
    return !(other.min_.x() > max_.x() || other.min_.y() > max_.y() || other.min_.z() > max_.z() ||
        other.max_.x() < min_.x() || other.max_.y() < min_.y() || other.max_.z() < min_.z());
 }
diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp
index 6b5899e9b414d0aa1885c5ffacb2c54e74d32af9..75a9cf41127ce25f633796fbbe3e37a0c2b6182c 100644
--- a/src/core/config/Config.cpp
+++ b/src/core/config/Config.cpp
@@ -224,7 +224,7 @@ void Config::parseFromFile( const char* filename, Block& block, unsigned int lev
       }
 
       //Adding the line to the input string
-      lineNumbers.push_back( Pair( input.tellp(), lineCounter ) );
+      lineNumbers.emplace_back( input.tellp(), lineCounter );
       input << line << "\n";
    }
 
@@ -572,7 +572,7 @@ void Config::Block::getBlocks( const std::string& key, Blocks& blocks, size_t mi
    size_t c = 0;
    for( List::const_iterator it=blocks_.begin(); it!=blocks_.end(); ++it ) {
       if( string_icompare( key, it->getKey() ) == 0 ) {
-         blocks.push_back( BlockHandle( &*it ) );
+         blocks.emplace_back( &*it );
          ++c;
       }
    }
@@ -595,7 +595,7 @@ void Config::Block::getBlocks( const std::string& key, Blocks& blocks, size_t mi
 void Config::Block::getBlocks( Blocks& blocks ) const
 {
    for( List::const_iterator it=blocks_.begin(); it!=blocks_.end(); ++it ) {
-      blocks.push_back( BlockHandle( &*it ) );
+      blocks.emplace_back( &*it );
    }
 }
 //**********************************************************************************************************************
@@ -610,7 +610,7 @@ void Config::Block::getBlocks( Blocks& blocks ) const
 void Config::Block::getWritableBlocks( std::vector<Block*> & blocks )
 {
    for( List::iterator it=blocks_.begin(); it!=blocks_.end(); ++it ) {
-      blocks.push_back( &*it );
+      blocks.emplace_back( &*it );
    }
 }
 //**********************************************************************************************************************
@@ -630,7 +630,7 @@ void Config::Block::getWritableBlocks( const std::string & key, std::vector<Bloc
    size_t c = 0;
    for( List::iterator it=blocks_.begin(); it!=blocks_.end(); ++it ) {
       if( string_icompare( key, it->getKey() ) == 0 ) {
-         blocks.push_back(  &*it );
+         blocks.emplace_back( &*it );
          ++c;
       }
    }
@@ -676,7 +676,7 @@ bool Config::Block::addParameter( const std::string& key, const std::string& val
  */
 Config::Block& Config::Block::createBlock( const std::string& key )
 {
-   blocks_.push_back( Block( key ) );
+   blocks_.emplace_back( key );
    return *blocks_.rbegin();
 }
 //**********************************************************************************************************************
diff --git a/src/core/debug/PrintStacktrace.cpp b/src/core/debug/PrintStacktrace.cpp
index 94f2aa89b34c307b5da5f7b54685f7dc7a4ad0b9..6e0a4fef0a4a80a217d20f5818e604e36868e014 100644
--- a/src/core/debug/PrintStacktrace.cpp
+++ b/src/core/debug/PrintStacktrace.cpp
@@ -42,6 +42,7 @@ void printStacktrace()
 #include WALBERLA_BACKTRACE_HEADER
 #include <cstdlib>
 #include <string>
+#include <utility>
 
 namespace walberla {
 namespace debug {
@@ -92,12 +93,12 @@ namespace debug {
 
          string appName     = line.substr( 0, leftBracket );
          string bracketPart = line.substr( leftBracket+1, rightBracket - leftBracket -1 );
-         string rest        = line.substr( rightBracket +1 );
+         std::ignore        = line.substr( rightBracket +1 ); /*rest*/
 
          // split the bracketPart on plus sign
          size_t plusPos = bracketPart.find_first_of('+');
          string functionName = bracketPart.substr(0, plusPos );
-         string offset       = bracketPart.substr( plusPos+1 );
+         std::ignore = bracketPart.substr( plusPos+1 ); /*offset*/
 #endif
 
          // try to demangle -> no return code if successful
@@ -109,7 +110,7 @@ namespace debug {
 
          os << "\t" << appName << " \t " << demangled << endl;
       }
-      free (strings);
+      free (reinterpret_cast<void*>(strings));
    }
 
 
diff --git a/src/core/math/Matrix2.h b/src/core/math/Matrix2.h
index 308108649ce4d6583194c73521824be91c99d638..3827333a4aef26fe1c2db7599724181b6df78a84 100644
--- a/src/core/math/Matrix2.h
+++ b/src/core/math/Matrix2.h
@@ -323,7 +323,7 @@ inline Matrix2<Type>& Matrix2<Type>::operator=( Type set )
 // Explicit definition of a copy assignment operator for performance reasons.
 */
 template< typename Type >
-inline Matrix2<Type>& Matrix2<Type>::operator=( const Matrix2& set )
+inline Matrix2<Type>& Matrix2<Type>::operator=( const Matrix2& set ) // NOLINT(bugprone-unhandled-self-assignment)
 {
    // This implementation is faster than the synthesized default copy assignment operator and
    // faster than an implementation with the C library function 'memcpy' in combination with a
@@ -347,7 +347,7 @@ inline Matrix2<Type>& Matrix2<Type>::operator=( const Matrix2& set )
 */
 template< typename Type >
 template< typename Other >
-inline Matrix2<Type>& Matrix2<Type>::operator=( const Matrix2<Other>& set )
+inline Matrix2<Type>& Matrix2<Type>::operator=( const Matrix2<Other>& set ) // NOLINT(bugprone-unhandled-self-assignment)
 {
    // This implementation is faster than the synthesized default copy assignment operator and
    // faster than an implementation with the C library function 'memcpy' in combination with a
diff --git a/src/core/math/extern/.clang-tidy b/src/core/math/extern/.clang-tidy
deleted file mode 100644
index 8f3d2744dd68901ffa8d4a7d993c8c5a93bc506b..0000000000000000000000000000000000000000
--- a/src/core/math/extern/.clang-tidy
+++ /dev/null
@@ -1,3 +0,0 @@
-# Disable all checks in this folder.
-Checks: '-*'
-
diff --git a/src/core/math/extern/exprtk.h b/src/core/math/extern/exprtk.h
index da493c5917a08bbd01ad8369895421f9ef77db3b..4f14480b9ff5ea09ba74801c7bba4f301c236d8e 100644
--- a/src/core/math/extern/exprtk.h
+++ b/src/core/math/extern/exprtk.h
@@ -55,6 +55,7 @@
 #include <utility>
 #include <vector>
 
+//NOLINTBEGIN(modernize-*,readability-*,performance-no-int-to-ptr,bugprone-empty-catch,bugprone-inc-dec-in-conditions)
 
 namespace exprtk
 {
@@ -71,10 +72,12 @@ namespace exprtk
       #define exprtk_override override
       #define exprtk_final    final
       #define exprtk_delete   = delete
+      #define exprtk_default  = default
    #else
       #define exprtk_override
       #define exprtk_final
       #define exprtk_delete
+      #define exprtk_default  {}
    #endif
 
    #if __cplusplus >= 201603L
@@ -823,15 +826,15 @@ namespace exprtk
 
          namespace details
          {
-            struct unknown_type_tag { unknown_type_tag() {} };
-            struct real_type_tag    { real_type_tag   () {} };
-            struct int_type_tag     { int_type_tag    () {} };
+            struct unknown_type_tag { unknown_type_tag() exprtk_default; };
+            struct real_type_tag    { real_type_tag   () exprtk_default; };
+            struct int_type_tag     { int_type_tag    () exprtk_default; };
 
             template <typename T>
             struct number_type
             {
                typedef unknown_type_tag type;
-               number_type() {}
+               number_type() exprtk_default;
             };
 
             #define exprtk_register_real_type_tag(T)          \
@@ -2161,8 +2164,7 @@ namespace exprtk
          throw std::runtime_error("ExprTk Loop runtime violation.");
       }
 
-      virtual ~loop_runtime_check()
-      {}
+      virtual ~loop_runtime_check() exprtk_default;
    };
 
    typedef loop_runtime_check* loop_runtime_check_ptr;
@@ -2177,8 +2179,7 @@ namespace exprtk
          std::size_t type_size;
       };
 
-      virtual ~vector_access_runtime_check()
-      {}
+      virtual ~vector_access_runtime_check() exprtk_default;
 
       virtual bool handle_runtime_violation(violation_context& /*context*/)
       {
@@ -2201,8 +2202,7 @@ namespace exprtk
          std::size_t offet;
       };
 
-      virtual ~assert_check()
-      {}
+      virtual ~assert_check() exprtk_default;
 
       virtual void handle_assert(const assert_context& /*context*/)
       {
@@ -2220,8 +2220,7 @@ namespace exprtk
 
       virtual bool continue_compilation(compilation_context& /*context*/) = 0;
 
-      virtual ~compilation_check()
-      {}
+      virtual ~compilation_check() exprtk_default;
    };
 
    typedef compilation_check* compilation_check_ptr;
@@ -3119,15 +3118,14 @@ namespace exprtk
          virtual void reset()                    {              }
          virtual bool result()                   { return true; }
          virtual std::size_t process(generator&) { return 0;    }
-         virtual ~helper_interface()             {              }
+         virtual ~helper_interface() exprtk_default;
       };
 
       class token_scanner : public helper_interface
       {
       public:
 
-         virtual ~token_scanner()
-         {}
+         ~token_scanner() exprtk_override exprtk_default;
 
          explicit token_scanner(const std::size_t& stride)
          : stride_(stride)
@@ -5551,8 +5549,7 @@ namespace exprtk
          typedef Node** node_pp_t;
          typedef std::vector<node_pp_t> noderef_list_t;
 
-         virtual ~node_collector_interface()
-         {}
+         virtual ~node_collector_interface() exprtk_default;
 
          virtual void collect_nodes(noderef_list_t&)
          {}
@@ -5616,15 +5613,14 @@ namespace exprtk
          typedef typename nci_t::noderef_list_t noderef_list_t;
          typedef node_depth_base<expression_node<T> > ndb_t;
 
-         virtual ~expression_node()
-         {}
+         ~expression_node() exprtk_override exprtk_default;
 
          inline virtual T value() const
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
 
-         inline virtual expression_node<T>* branch(const std::size_t& index = 0) const
+         inline virtual expression_node<T>* branch([[maybe_unused]] const std::size_t& index = 0) const
          {
             return reinterpret_cast<expression_ptr>(index * 0);
          }
@@ -6067,8 +6063,7 @@ namespace exprtk
          , depth(0)
          {}
 
-         virtual ~node_depth_base()
-         {}
+         virtual ~node_depth_base() exprtk_default;
 
          virtual std::size_t node_depth() const { return 1; }
 
@@ -6308,8 +6303,7 @@ namespace exprtk
          {
          public:
 
-            virtual ~vector_holder_base()
-            {}
+            virtual ~vector_holder_base() exprtk_default;
 
             inline value_ptr operator[](const std::size_t& index) const
             {
@@ -6363,6 +6357,8 @@ namespace exprtk
             , size_(vec_size)
             {}
 
+            ~array_vector_impl() exprtk_override exprtk_default;
+
          protected:
 
             value_ptr value_at(const std::size_t& index) const exprtk_override
@@ -6402,6 +6398,8 @@ namespace exprtk
             : sequence_(seq)
             {}
 
+            ~sequence_vector_impl() exprtk_override exprtk_default;
+
          protected:
 
             value_ptr value_at(const std::size_t& index) const exprtk_override
@@ -6478,6 +6476,8 @@ namespace exprtk
                return vec_view_.base_size();
             }
 
+            ~vector_view_impl() exprtk_override exprtk_default;
+
          private:
 
             vector_view_impl(const vector_view_impl&) exprtk_delete;
@@ -6501,8 +6501,7 @@ namespace exprtk
                assert(size_ <= vector_base_size());
             }
 
-            virtual ~resizable_vector_impl()
-            {}
+            ~resizable_vector_impl() exprtk_override exprtk_default;
 
          protected:
 
@@ -6527,7 +6526,7 @@ namespace exprtk
                return true;
             }
 
-            virtual vector_view<Type>* rebaseable_instance() exprtk_override
+            vector_view<Type>* rebaseable_instance() exprtk_override
             {
                return &vec_view_holder_;
             }
@@ -6785,8 +6784,7 @@ namespace exprtk
 
          typedef range_pack<T> range_t;
 
-         virtual ~range_interface()
-         {}
+         virtual ~range_interface() exprtk_default;
 
          virtual range_t& range_ref() = 0;
 
@@ -6801,8 +6799,7 @@ namespace exprtk
 
          typedef range_data_type<T> range_data_type_t;
 
-         virtual ~string_base_node()
-         {}
+         virtual ~string_base_node() exprtk_default;
 
          virtual std::string str () const = 0;
 
@@ -7125,7 +7122,7 @@ namespace exprtk
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
-         std::size_t node_depth() const exprtk_override exprtk_final
+         std::size_t node_depth() const exprtk_final
          {
             return expression_node<T>::ndb_t::template compute_node_depth<3>(branch_);
          }
@@ -7169,7 +7166,7 @@ namespace exprtk
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
-         std::size_t node_depth() const exprtk_override exprtk_final
+         std::size_t node_depth() const exprtk_final
          {
             return expression_node<T>::ndb_t::template compute_node_depth<4>(branch_);
          }
@@ -7526,7 +7523,7 @@ namespace exprtk
 
          using parent_t::valid;
 
-         bool valid() const exprtk_override exprtk_final
+         bool valid() const exprtk_final
          {
             return parent_t::valid() &&
                    loop_runtime_checker::valid();
@@ -7627,7 +7624,7 @@ namespace exprtk
 
          using parent_t::valid;
 
-         inline bool valid() const exprtk_override exprtk_final
+         inline bool valid() const exprtk_final
          {
             return parent_t::valid() &&
                    loop_runtime_checker::valid();
@@ -7763,7 +7760,7 @@ namespace exprtk
 
          using parent_t::valid;
 
-         inline bool valid() const exprtk_override exprtk_final
+         inline bool valid() const exprtk_final
          {
             return parent_t::valid() &&
                    loop_runtime_checker::valid();
@@ -7852,7 +7849,7 @@ namespace exprtk
 
          using parent_t::valid;
 
-         inline bool valid() const exprtk_override exprtk_final
+         inline bool valid() const exprtk_final
          {
             return parent_t::valid() &&
                    loop_runtime_checker::valid();
@@ -7942,7 +7939,7 @@ namespace exprtk
 
          using parent_t::valid;
 
-         inline bool valid() const exprtk_override exprtk_final
+         inline bool valid() const exprtk_final
          {
             return parent_t::valid() &&
                    loop_runtime_checker::valid();
@@ -8082,7 +8079,7 @@ namespace exprtk
 
          using parent_t::valid;
 
-         inline bool valid() const exprtk_override exprtk_final
+         inline bool valid() const exprtk_final
          {
             return parent_t::valid() &&
                    loop_runtime_checker::valid();
@@ -8141,7 +8138,7 @@ namespace exprtk
             return arg_list_[upper_bound].first->value();
          }
 
-         inline typename expression_node<T>::node_type type() const exprtk_override exprtk_final
+         inline typename expression_node<T>::node_type type() const exprtk_final
          {
             return expression_node<T>::e_switch;
          }
@@ -8156,7 +8153,7 @@ namespace exprtk
             expression_node<T>::ndb_t::collect(arg_list_, node_delete_list);
          }
 
-         std::size_t node_depth() const exprtk_override exprtk_final
+         std::size_t node_depth() const exprtk_final
          {
             return expression_node<T>::ndb_t::compute_node_depth(arg_list_);
          }
@@ -8253,7 +8250,7 @@ namespace exprtk
             expression_node<T>::ndb_t::collect(arg_list_, node_delete_list);
          }
 
-         std::size_t node_depth() const exprtk_override exprtk_final
+         std::size_t node_depth() const exprtk_final
          {
             return expression_node<T>::ndb_t::compute_node_depth(arg_list_);
          }
@@ -8268,8 +8265,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~ivariable()
-         {}
+         virtual ~ivariable() exprtk_default;
 
          virtual T& ref() = 0;
          virtual const T& ref() const = 0;
@@ -8504,8 +8500,7 @@ namespace exprtk
          typedef vector_node<T>*   vector_node_ptr;
          typedef vec_data_store<T> vds_t;
 
-         virtual ~vector_interface()
-         {}
+         virtual ~vector_interface() exprtk_default;
 
          virtual std::size_t size     () const = 0;
 
@@ -8546,7 +8541,7 @@ namespace exprtk
          , vds_(vds)
          {}
 
-        ~vector_node()
+        ~vector_node() exprtk_override
          {
             assert(valid());
             vector_holder_->remove_ref(&vds_.ref());
@@ -8626,7 +8621,7 @@ namespace exprtk
          : vector_holder_(vh)
          {}
 
-        ~vector_size_node()
+        ~vector_size_node() exprtk_override
          {
             assert(valid());
          }
@@ -10234,7 +10229,7 @@ namespace exprtk
          , rp_(rp)
          {}
 
-         virtual ~string_range_node()
+         ~string_range_node() exprtk_override
          {
             rp_.free();
          }
@@ -10318,7 +10313,7 @@ namespace exprtk
          , rp_(rp)
          {}
 
-        ~const_string_range_node()
+        ~const_string_range_node() exprtk_override
          {
             rp_.free();
          }
@@ -10419,7 +10414,7 @@ namespace exprtk
             assert(valid());
          }
 
-        ~generic_string_range_node()
+        ~generic_string_range_node() exprtk_override
          {
             base_range_.free();
          }
@@ -11510,27 +11505,27 @@ namespace exprtk
             return std::numeric_limits<T>::quiet_NaN();
          }
 
-         std::string str() const
+         std::string str() const exprtk_override
          {
             return value_;
          }
 
-         char_cptr base() const
+         char_cptr base() const exprtk_override
          {
             return &value_[0];
          }
 
-         std::size_t size() const
+         std::size_t size() const exprtk_override
          {
             return value_.size();
          }
 
-         range_t& range_ref()
+         range_t& range_ref() exprtk_override
          {
             return range_;
          }
 
-         const range_t& range_ref() const
+         const range_t& range_ref() const exprtk_override
          {
             return range_;
          }
@@ -13618,7 +13613,7 @@ namespace exprtk
             assert(valid());
          }
 
-        ~vec_binop_vecvec_node()
+        ~vec_binop_vecvec_node() exprtk_override
          {
             memory_context_.clear();
          }
@@ -13788,7 +13783,7 @@ namespace exprtk
             assert(valid());
          }
 
-        ~vec_binop_vecval_node()
+        ~vec_binop_vecval_node() exprtk_override
          {
             memory_context_.clear();
          }
@@ -13952,7 +13947,7 @@ namespace exprtk
             assert(valid());
          }
 
-        ~vec_binop_valvec_node()
+        ~vec_binop_valvec_node() exprtk_override
          {
             memory_context_.clear();
          }
@@ -14115,7 +14110,7 @@ namespace exprtk
             assert(valid());
          }
 
-        ~unary_vector_node()
+        ~unary_vector_node() exprtk_override
          {
             memory_context_.clear();
          }
@@ -14292,7 +14287,7 @@ namespace exprtk
             assert(initialised_);
          }
 
-        ~conditional_vector_node()
+        ~conditional_vector_node() exprtk_override
          {
             memory_context_.clear();
          }
@@ -14910,7 +14905,7 @@ namespace exprtk
          , arg_list_(arg_list)
          {}
 
-         virtual ~generic_function_node()
+         ~generic_function_node() exprtk_override
          {
             for (std::size_t i = 0; i < vv_list_.size(); ++i)
             {
@@ -14928,7 +14923,7 @@ namespace exprtk
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
-         std::size_t node_depth() const exprtk_override exprtk_final
+         std::size_t node_depth() const exprtk_final
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
@@ -15245,7 +15240,7 @@ namespace exprtk
             return std::numeric_limits<T>::quiet_NaN();
          }
 
-         inline typename expression_node<T>::node_type type() const exprtk_override exprtk_final
+         inline typename expression_node<T>::node_type type() const exprtk_final
          {
             return expression_node<T>::e_genfunction;
          }
@@ -15312,8 +15307,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~null_igenfunc()
-         {}
+         virtual ~null_igenfunc() exprtk_default;
 
          typedef type_store<T> generic_type;
          typedef typename generic_type::parameter_list parameter_list_t;
@@ -16665,8 +16659,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~vov_base_node()
-         {}
+         ~vov_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16683,8 +16676,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~cov_base_node()
-         {}
+         ~cov_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16701,8 +16693,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~voc_base_node()
-         {}
+         ~voc_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16719,8 +16710,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~vob_base_node()
-         {}
+         ~vob_base_node() exprtk_override exprtk_default;
 
          virtual const T& v() const = 0;
       };
@@ -16730,8 +16720,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~bov_base_node()
-         {}
+         ~bov_base_node() exprtk_override exprtk_default;
 
          virtual const T& v() const = 0;
       };
@@ -16741,8 +16730,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~cob_base_node()
-         {}
+         ~cob_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16761,8 +16749,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~boc_base_node()
-         {}
+         ~boc_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16781,8 +16768,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~uv_base_node()
-         {}
+         ~uv_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16797,8 +16783,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~sos_base_node()
-         {}
+         ~sos_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16811,8 +16796,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~sosos_base_node()
-         {}
+         ~sosos_base_node() exprtk_override exprtk_default;
 
          inline virtual operator_type operation() const
          {
@@ -16825,8 +16809,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~T0oT1oT2_base_node()
-         {}
+         ~T0oT1oT2_base_node() exprtk_override exprtk_default;
 
          virtual std::string type_id() const = 0;
       };
@@ -16836,8 +16819,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~T0oT1oT2oT3_base_node()
-         {}
+         ~T0oT1oT2oT3_base_node() exprtk_override exprtk_default;
 
          virtual std::string type_id() const = 0;
       };
@@ -17566,7 +17548,7 @@ namespace exprtk
             return f_;
          }
 
-         std::string type_id() const
+         std::string type_id() const exprtk_override
          {
             return id();
          }
@@ -17600,8 +17582,7 @@ namespace exprtk
       {
       public:
 
-         virtual ~sf3ext_type_node()
-         {}
+         ~sf3ext_type_node() exprtk_override exprtk_default;
 
          virtual T0 t0() const = 0;
 
@@ -17702,6 +17683,8 @@ namespace exprtk
       {
       public:
 
+         ~T0oT1oT2oT3_sf4() exprtk_override exprtk_default;
+
          typedef typename details::functor_t<T> functor_t;
          typedef typename functor_t::qfunc_t    qfunc_t;
          typedef T value_type;
@@ -17756,7 +17739,7 @@ namespace exprtk
             return f_;
          }
 
-         std::string type_id() const
+         std::string type_id() const exprtk_override
          {
             return id();
          }
@@ -18373,7 +18356,7 @@ namespace exprtk
          , rp0_(rp0)
          {}
 
-        ~str_xrox_node()
+        ~str_xrox_node() exprtk_override
          {
             rp0_.free();
          }
@@ -18437,7 +18420,7 @@ namespace exprtk
          , rp1_(rp1)
          {}
 
-        ~str_xoxr_node()
+        ~str_xoxr_node() exprtk_override
          {
             rp1_.free();
          }
@@ -18508,7 +18491,7 @@ namespace exprtk
          , rp1_(rp1)
          {}
 
-        ~str_xroxr_node()
+        ~str_xroxr_node() exprtk_override
          {
             rp0_.free();
             rp1_.free();
@@ -19617,8 +19600,7 @@ namespace exprtk
       : param_count(pc)
       {}
 
-      virtual ~ifunction()
-      {}
+      virtual ~ifunction() exprtk_default;
 
       #define empty_method_body(N)                   \
       {                                              \
@@ -19709,8 +19691,7 @@ namespace exprtk
    {
    public:
 
-      virtual ~ivararg_function()
-      {}
+      virtual ~ivararg_function() exprtk_default;
 
       inline virtual T operator() (const std::vector<T>&)
       {
@@ -19740,8 +19721,7 @@ namespace exprtk
       , rtrn_type(rtr_type)
       {}
 
-      virtual ~igeneric_function()
-      {}
+      virtual ~igeneric_function() exprtk_default;
 
       #define igeneric_function_empty_body(N)        \
       {                                              \
@@ -21661,10 +21641,7 @@ namespace exprtk
                }
             }
 
-            if (results)
-            {
-               delete results;
-            }
+            delete results;
          }
 
          static inline cntrl_blck_ptr_t create(expression_ptr e)
@@ -21938,7 +21915,7 @@ namespace exprtk
          }
       }
 
-      inline void set_retinvk(bool* retinvk_ptr)
+      inline void set_retinvk(bool* const retinvk_ptr)
       {
          if (control_block_)
          {
@@ -23516,8 +23493,7 @@ namespace exprtk
          : mode(m)
          {}
 
-         virtual ~unknown_symbol_resolver()
-         {}
+         virtual ~unknown_symbol_resolver() exprtk_default;
 
          virtual bool process(const std::string& /*unknown_symbol*/,
                               usr_symbol_type&   st,
@@ -24444,8 +24420,7 @@ namespace exprtk
          expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled());
       }
 
-     ~parser()
-      {}
+     ~parser() exprtk_default;
 
       inline void init_precompilation()
       {
@@ -25011,7 +24986,9 @@ namespace exprtk
 
                end_token = current_token();
 
+               #ifdef exprtk_enable_debugging
                const std::string sub_expr = construct_subexpr(begin_token, end_token);
+               #endif
 
                exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n",
                              static_cast<int>(arg_list.size() - 1),
@@ -28461,7 +28438,7 @@ namespace exprtk
 
             for (std::size_t i = 0; i < function_definition_list_.size(); ++i)
             {
-               if (std::string::npos != function_definition_list_[i].param_seq.find("Z"))
+               if (std::string::npos != function_definition_list_[i].param_seq.find('Z'))
                {
                   return true;
                }
@@ -41836,9 +41813,9 @@ namespace exprtk
             : usr_t(usr_t::e_usrmode_extended)
             {}
 
-            virtual bool process(const std::string& unknown_symbol,
-                                 symbol_table_t& symbol_table,
-                                 std::string&) exprtk_override
+            bool process(const std::string& unknown_symbol,
+                         symbol_table_t& symbol_table,
+                         std::string&) exprtk_override
             {
                static T v[1];
                symbol_table.add_vector(unknown_symbol,v);
@@ -42490,98 +42467,97 @@ namespace exprtk
          disable_has_side_effects(*this);
       }
 
-      virtual ~polynomial()
-      {}
+      ~polynomial() exprtk_override exprtk_default;
 
       #define poly_rtrn(NN) \
       return (NN != N) ? std::numeric_limits<T>::quiet_NaN() :
 
-      inline virtual T operator() (const T& x, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(1) (poly_impl<T,1>::evaluate(x, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(2) (poly_impl<T,2>::evaluate(x, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(3) (poly_impl<T,3>::evaluate(x, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1,
-                                   const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1,
+                           const T& c0) exprtk_override
       {
          poly_rtrn(4) (poly_impl<T,4>::evaluate(x, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2,
-                                   const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2,
+                           const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(5) (poly_impl<T,5>::evaluate(x, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3,
-                                   const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3,
+                           const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(6) (poly_impl<T,6>::evaluate(x, c6, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4,
-                                   const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4,
+                           const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(7) (poly_impl<T,7>::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5,
-                                   const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5,
+                           const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(8) (poly_impl<T,8>::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6,
-                                   const T& c5, const T& c4, const T& c3, const T& c2, const T& c1,
-                                   const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6,
+                           const T& c5, const T& c4, const T& c3, const T& c2, const T& c1,
+                           const T& c0) exprtk_override
       {
          poly_rtrn(9) (poly_impl<T,9>::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7,
-                                   const T& c6, const T& c5, const T& c4, const T& c3, const T& c2,
-                                   const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7,
+                           const T& c6, const T& c5, const T& c4, const T& c3, const T& c2,
+                           const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(10) (poly_impl<T,10>::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8,
-                                   const T& c7, const T& c6, const T& c5, const T& c4, const T& c3,
-                                   const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8,
+                           const T& c7, const T& c6, const T& c5, const T& c4, const T& c3,
+                           const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(11) (poly_impl<T,11>::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0));
       }
 
-      inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9,
-                                   const T& c8, const T& c7, const T& c6, const T& c5, const T& c4,
-                                   const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
+      inline T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9,
+                           const T& c8, const T& c7, const T& c6, const T& c5, const T& c4,
+                           const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override
       {
          poly_rtrn(12) (poly_impl<T,12>::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0));
       }
 
       #undef poly_rtrn
 
-      inline virtual T operator() () exprtk_override
+      inline T operator() () exprtk_override
       {
          return std::numeric_limits<T>::quiet_NaN();
       }
 
-      inline virtual T operator() (const T&) exprtk_override
+      inline T operator() (const T&) exprtk_override
       {
          return std::numeric_limits<T>::quiet_NaN();
       }
 
-      inline virtual T operator() (const T&, const T&) exprtk_override
+      inline T operator() (const T&, const T&) exprtk_override
       {
          return std::numeric_limits<T>::quiet_NaN();
       }
@@ -42599,8 +42575,7 @@ namespace exprtk
 
       struct function
       {
-         function()
-         {}
+         function() exprtk_default;
 
          function(const std::string& n)
          : name_(n)
@@ -42755,8 +42730,7 @@ namespace exprtk
             v.resize(pc);
          }
 
-         virtual ~base_func()
-         {}
+         ~base_func() exprtk_override exprtk_default;
 
          #define exprtk_assign(Index) \
          (*v[Index]) = v##Index;      \
@@ -43190,13 +43164,13 @@ namespace exprtk
       inline bool add(const std::string& name,
                       const std::string& expression,
                       const Sequence<std::string,Allocator>& var_list,
-                      const bool override = false)
+                      const bool allow_override = false)
       {
          const typename std::map<std::string,expression_t>::iterator itr = expr_map_.find(name);
 
          if (expr_map_.end() != itr)
          {
-            if (!override)
+            if (!allow_override)
             {
                exprtk_debug(("Compositor error(add): function '%s' already defined\n",
                              name.c_str()));
@@ -43327,9 +43301,9 @@ namespace exprtk
          clear_compilation_timeout_check  ();
       }
 
-      inline bool add(const function& f, const bool override = false)
+      inline bool add(const function& f, const bool allow_override = false)
       {
-         return add(f.name_, f.expression_, f.v_,override);
+         return add(f.name_, f.expression_, f.v_, allow_override);
       }
 
       inline std::string error() const
@@ -46061,6 +46035,12 @@ namespace exprtk
    #undef exprtk_delete
    #endif
 
+   #ifdef exprtk_default
+   #undef exprtk_default
+   #endif
+
 } // namespace exprtk
 
+//NOLINTEND(modernize-*,readability-*,performance-no-int-to-ptr,bugprone-empty-catch,bugprone-inc-dec-in-conditions)
+
 #endif
diff --git a/src/core/mpi/BufferSystem.impl.h b/src/core/mpi/BufferSystem.impl.h
index 3715a7ea9f3daf95c0bde6163954ca72159e48d3..b927d242daa869ec294916f0991c6a94e5bce88d 100644
--- a/src/core/mpi/BufferSystem.impl.h
+++ b/src/core/mpi/BufferSystem.impl.h
@@ -165,21 +165,24 @@ GenericBufferSystem<Rb, Sb> & GenericBufferSystem<Rb, Sb>::operator=( const Gene
 {
    WALBERLA_ASSERT( !communicationRunning_, "Can't copy GenericBufferSystem while communication is running" )
 
-   sizeChangesEverytime_ = other.sizeChangesEverytime_;
-   communicationRunning_ = other.communicationRunning_;
-   recvInfos_ = other.recvInfos_;
-   sendInfos_ = other.sendInfos_;
+   if (&other != this)
+   {
+      sizeChangesEverytime_ = other.sizeChangesEverytime_;
+      communicationRunning_ = other.communicationRunning_;
+      recvInfos_ = other.recvInfos_;
+      sendInfos_ = other.sendInfos_;
 
-   if( other.currentComm_ == &other.knownSizeComm_ )
-      currentComm_ = &knownSizeComm_;
-   else if ( other.currentComm_ == &other.unknownSizeComm_ )
-      currentComm_ = &unknownSizeComm_;
-   else if ( other.currentComm_ == &other.unknownSizeCommIProbe_ )
-      currentComm_ = &unknownSizeCommIProbe_;
-   else if ( other.currentComm_ == &other.noMPIComm_ )
-      currentComm_ = &noMPIComm_;
-   else
-      currentComm_ = nullptr; // receiver information not yet set
+      if( other.currentComm_ == &other.knownSizeComm_ )
+         currentComm_ = &knownSizeComm_;
+      else if ( other.currentComm_ == &other.unknownSizeComm_ )
+         currentComm_ = &unknownSizeComm_;
+      else if ( other.currentComm_ == &other.unknownSizeCommIProbe_ )
+         currentComm_ = &unknownSizeCommIProbe_;
+      else if ( other.currentComm_ == &other.noMPIComm_ )
+         currentComm_ = &noMPIComm_;
+      else
+         currentComm_ = nullptr; // receiver information not yet set
+   }
 
    return *this;
 }
diff --git a/src/core/mpi/RecvBuffer.h b/src/core/mpi/RecvBuffer.h
index 0b3df4abffd48550221cf321c94c4a5c6f95cb77..69c0a26d213176f42b5eba8bf604b0d24915c530 100644
--- a/src/core/mpi/RecvBuffer.h
+++ b/src/core/mpi/RecvBuffer.h
@@ -400,11 +400,11 @@ GenericRecvBuffer<T>::get( V& value )
 
 
    // Checking the validity of the read operation
-   WALBERLA_ASSERT_LESS_EQUAL( cur_ + (sizeof(V) / sizeof(T)), end_ );
+   WALBERLA_ASSERT_LESS_EQUAL( cur_ + (sizeof(V) / sizeof(T)), end_ ); // NOLINT(bugprone-sizeof-expression)
 
    // Extracting the data value
    std::memcpy( &value, cur_, sizeof(V) );
-   cur_ += sizeof(V) / sizeof(T);
+   cur_ += sizeof(V) / sizeof(T); // NOLINT(bugprone-sizeof-expression)
 
    // Invariants check
    WALBERLA_ASSERT_LESS_EQUAL( cur_, end_);
diff --git a/src/core/mpi/SendBuffer.h b/src/core/mpi/SendBuffer.h
index 3fac958a74fec25adb8cb4396845f8a184a4b7eb..f167a4459f5aadb411b30f891bc5bff6b010a41f 100644
--- a/src/core/mpi/SendBuffer.h
+++ b/src/core/mpi/SendBuffer.h
@@ -449,7 +449,7 @@ GenericSendBuffer<T,G>::put( V value )
    static_assert( sizeof(V) >= sizeof(T), "Type that is stored has to be bigger than T" );
    static_assert( sizeof(V)  % sizeof(T) == 0, "V has to be divisible by T ");
 
-   size_t count =  sizeof(V) / sizeof(T) ;
+   size_t count =  sizeof(V) / sizeof(T); // NOLINT(bugprone-sizeof-expression)
    const size_t rest = numeric_cast< size_t >( end_ - cur_ );
 
    // Checking the size of the remaining memory
diff --git a/src/core/timing/TimingNode.h b/src/core/timing/TimingNode.h
index 0b6326e71096625d30ab69b2c850702473f7c04c..404feb7d5a2308e4f2131f111e0bc8ffd6e87998 100644
--- a/src/core/timing/TimingNode.h
+++ b/src/core/timing/TimingNode.h
@@ -97,8 +97,11 @@ TimingNode<TP>::TimingNode(const TimingNode<TP>& tn)
 template< typename TP >  // Timing policy
 TimingNode<TP>& TimingNode<TP>::operator=(const TimingNode<TP>& tn)
 {
-   TimingNode<TP> tmp (tn);
-   tmp.swap(*this);
+   if (&tn != this)
+   {
+      TimingNode<TP> tmp (tn);
+      tmp.swap(*this);
+   }
    return *this;
 }
 
diff --git a/src/core/timing/TimingTree.h b/src/core/timing/TimingTree.h
index 5cf06167e00875f9ead6300ac7f1750d4f9f376a..5584b2be3ca6b6a121b329c01d812d3aece55b55 100644
--- a/src/core/timing/TimingTree.h
+++ b/src/core/timing/TimingTree.h
@@ -128,8 +128,11 @@ TimingTree<TP>::TimingTree(const TimingTree<TP>& tt)
 template< typename TP >  // Timing policy
 TimingTree<TP>& TimingTree<TP>::operator=(const TimingTree<TP>& tt)
 {
-   TimingTree<TP> tmp (tt);
-   tmp.swap(*this);
+   if (&tt != this)
+   {
+      TimingTree<TP> tmp (tt);
+      tmp.swap(*this);
+   }
    return *this;
 }
 
diff --git a/src/core/uid/UIDGenerators.h b/src/core/uid/UIDGenerators.h
index 265beeaac89babc29eade08b85a6012157f5377d..3d715c9de807582197070fbc64ca87662b812cac 100644
--- a/src/core/uid/UIDGenerators.h
+++ b/src/core/uid/UIDGenerators.h
@@ -275,11 +275,11 @@ public:
 
    static uint_type firstUID() { return 1; }
 
-   static uint_type nextUID( const uint_type /*uid*/ ) { WALBERLA_ASSERT( false ); return 1; }
+   static uint_type nextUID( [[maybe_unused]] const uint_type uid ) { WALBERLA_ASSERT( false ); return 1; }
 
-   static uint_type toIndex( const uint_type uid ) { WALBERLA_ASSERT_EQUAL( uid, 1 ); return 0; }
+   static uint_type toIndex( [[maybe_unused]] const uint_type uid ) { WALBERLA_ASSERT_EQUAL( uid, 1 ); return 0; }
 
-   static uint_type toBitMask( const uint_type uid ) { WALBERLA_ASSERT_EQUAL( uid, 1 ); return 1; }
+   static uint_type toBitMask( [[maybe_unused]] const uint_type uid ) { WALBERLA_ASSERT_EQUAL( uid, 1 ); return 1; }
 
    static const char* getType() { static const char* const type = "singleton generator"; return type; }
 
diff --git a/src/core/waLBerlaBuildInfo.in.cpp b/src/core/waLBerlaBuildInfo.in.cpp
index 65fa8887d9c2dec1d6f6e81a3c3a4295f0c687af..29efeaa8fb012fb0417334602e2071d63eaba622 100644
--- a/src/core/waLBerlaBuildInfo.in.cpp
+++ b/src/core/waLBerlaBuildInfo.in.cpp
@@ -5,6 +5,7 @@
  */
 //======================================================================================================================
 
+#include "core/waLBerlaBuildInfo.h"
 
 namespace walberla {
 namespace core {
diff --git a/src/domain_decomposition/BlockStorage.h b/src/domain_decomposition/BlockStorage.h
index 2f29acdb7fd45c1e287ebf6d4601b641f303506b..551ff5f6803c0e6f740db717ccf7b2a220048ebb 100644
--- a/src/domain_decomposition/BlockStorage.h
+++ b/src/domain_decomposition/BlockStorage.h
@@ -273,7 +273,7 @@ public:
    *   \code
    *     for( const_iterator block = begin(); block != end(); ++block )
    *        if( block->getId() == id ) return *block;
-   *     return NULL;
+   *     return nullptr;
    *   \endcode
    */
    //*******************************************************************************************************************
@@ -294,7 +294,7 @@ public:
    *   \code
    *     for( iterator block = begin(); block != end(); ++block )
    *        if( block->getId() == id ) return *block;
-   *     return NULL;
+   *     return nullptr;
    *   \endcode
    */
    //*******************************************************************************************************************
@@ -315,7 +315,7 @@ public:
    *   \code
    *     for( const_iterator block = begin(); block != end(); ++block )
    *        if( block->getAABB().contains(x,y,z) ) return *block;
-   *     return NULL;
+   *     return nullptr;
    *   \endcode
    *
    *   Periodicity is not considered! For mapping points to the periodic simulation space see 'mapToPeriodicDomain'.
@@ -332,7 +332,7 @@ public:
    *   \code
    *     for( iterator block = begin(); block != end(); ++block )
    *        if( block->getAABB().contains(x,y,z) ) return *block;
-   *     return NULL;
+   *     return nullptr;
    *   \endcode
    *
    *   Periodicity is not considered! For mapping points to the periodic simulation space see 'mapToPeriodicDomain'.
@@ -716,7 +716,7 @@ inline BlockDataID BlockStorage::loadBlockData( const std::string & file, const
 /*!
 *   This function can be used for removing all data that corresponds to block data ID 'id'.
 *   Please note: The block data ID 'id' will still be valid, but blocks won't return anything anymore,
-*                they will only return NULL for 'id'.
+*                they will only return nullptr for 'id'.
 */
 //**********************************************************************************************************************
 inline void BlockStorage::clearBlockData( const BlockDataID & id )
diff --git a/src/domain_decomposition/IBlock.h b/src/domain_decomposition/IBlock.h
index ef563cc057b2e9157330420f09beb1ad74050168..a1641d5a5ac2d2297514fc9da429fe2faee7e5b2 100644
--- a/src/domain_decomposition/IBlock.h
+++ b/src/domain_decomposition/IBlock.h
@@ -100,8 +100,8 @@ public:
    template< typename U >
    const U* get() const {
       try { thr_(ptr_); }
-      catch ( U* ptr ) { return ptr; }
-      catch (...) {}
+      catch ( U* ptr ) { return ptr; } // NOLINT(misc-throw-by-value-catch-by-reference)
+      catch (...) {} // NOLINT(bugprone-empty-catch)
 #ifndef NDEBUG
       WALBERLA_ABORT( "BlockData access type violation! (The block data you added is of a different type than the block data you are trying to access!)"
                       "\nThe original data type was:       " << debug::demangle( typeInfo_ ) <<
@@ -135,8 +135,8 @@ public:
    template< typename U >
    bool isClassOrSubclassOf() const {
       try { thr_(ptr_); }
-      catch ( U* ) { return true; }
-      catch (...) {}
+      catch ( U* ) { return true; } // NOLINT(misc-throw-by-value-catch-by-reference)
+      catch (...) {} // NOLINT(bugprone-empty-catch)
       return false;
    }
 
@@ -156,7 +156,9 @@ private:
 #  pragma warning( disable : 4670 )
 #  pragma warning( disable : 4673 )
 #endif //_MSC_VER
-   template< typename T > static void thrower( void* ptr ) { throw static_cast< T* >( ptr ); }
+   template< typename T > static void thrower( void* ptr ) {
+      throw static_cast< T* >( ptr ); // NOLINT(misc-throw-by-value-catch-by-reference)
+   }
 #ifdef _MSC_VER
 #  pragma warning(pop)
 #endif //_MSC_VER
@@ -359,7 +361,7 @@ inline T* IBlock::getData( const BlockDataID & index ) {
 //**********************************************************************************************************************
 /*!
 *   Function for removing all data that corresponds to block data ID 'index'.
-*   Further calls to "getData" with 'index' will return NULL.
+*   Further calls to "getData" with 'index' will return nullptr.
 */
 //**********************************************************************************************************************
 inline void IBlock::deleteData( const BlockDataID & index )
diff --git a/src/field/Field.impl.h b/src/field/Field.impl.h
index af93706e467f1735c8989230779b1d5a378293cd..3eb80bd583192b5ffb5ea9e7d6f5a3c7450b720c 100644
--- a/src/field/Field.impl.h
+++ b/src/field/Field.impl.h
@@ -103,7 +103,7 @@ namespace field {
    Field<T,fSize_>::Field( uint_t _xSize, uint_t _ySize, uint_t _zSize,
                            const std::vector<T> & fValues, const Layout & l,
                            const shared_ptr<FieldAllocator<T> > &alloc)
-        : values_( NULL ), valuesWithOffset_( NULL )
+        : values_( nullptr ), valuesWithOffset_( nullptr )
    {
       init(_xSize,_ySize,_zSize,l,alloc);
       set(fValues);
@@ -301,7 +301,7 @@ namespace field {
     * \param _ySize  size of y dimension
     * \param _zSize  size of z dimension
     * \param l       memory layout of the field (see Field::Layout)
-    * \param alloc   the allocator to use. If a NULL shared pointer is given, a sensible default is selected,
+    * \param alloc   the allocator to use. If a nullptr is given, a sensible default is selected,
     *                depending on layout
     * \param innerGhostLayerSizeForAlignedAlloc
     *                This parameter should be set to zero for field that have no ghost layers.
@@ -319,23 +319,7 @@ namespace field {
       // Automatically select allocator if none was given
       if ( alloc == nullptr )
       {
-#if defined(__ARM_FEATURE_SVE) && defined(__ARM_FEATURE_SVE_BITS) && __ARM_FEATURE_SVE_BITS > 0
-         const uint_t alignment = __ARM_FEATURE_SVE_BITS/8;
-#elif defined(__ARM_FEATURE_SVE)
-         const uint_t alignment = 64;
-#elif defined(__ARM_NEON)
-         const uint_t alignment = 16;
-#elif defined(__AVX512F__)
-         const uint_t alignment = 64;
-#elif defined(__AVX__)
-         const uint_t alignment = 32;
-#elif defined(__SSE__) || defined(_MSC_VER)
-         const uint_t alignment = 16;
-#elif defined(__BIGGEST_ALIGNMENT__)
-         const uint_t alignment = __BIGGEST_ALIGNMENT__;
-#else
-         const uint_t alignment = 64;
-#endif
+         constexpr uint_t alignment = SIMDAlignment();
 
          // aligned allocator only used (by default) if ...
          if ( l == fzyx                      && // ... we use a structure of arrays layout
diff --git a/src/field/FieldClone.h b/src/field/FieldClone.h
index ebb6dddfaede4fa86db5c9e09707edb0f370929b..eb2a3a42547c5e031b31a04a6352bb1356ea7c33 100644
--- a/src/field/FieldClone.h
+++ b/src/field/FieldClone.h
@@ -60,7 +60,7 @@ class FieldClone
 {
 
 public:
-   FieldClone( ConstBlockDataID fieldID ) : fieldID_( fieldID ), dstField_( NULL ){}
+   FieldClone( ConstBlockDataID fieldID ) : fieldID_( fieldID ), dstField_( nullptr ){}
 
    ~FieldClone(){
       // Free allocated temporary fields
@@ -126,7 +126,7 @@ class FieldCreator
 {
 
 public:
-   FieldCreator() : dstField_( NULL ){}
+   FieldCreator() : dstField_( nullptr ){}
 
    ~FieldCreator(){
       // Free allocated temporary fields
diff --git a/src/field/adaptors/GhostLayerFieldAdaptor.h b/src/field/adaptors/GhostLayerFieldAdaptor.h
index 13ac8f0e289b6bf5300ac70647816a44dbb034f1..e7e4d630a6ed1ea327de70709af98ad3588b3c03 100644
--- a/src/field/adaptors/GhostLayerFieldAdaptor.h
+++ b/src/field/adaptors/GhostLayerFieldAdaptor.h
@@ -302,7 +302,7 @@ typename GhostLayerFieldAdaptor<Functor,glD>::const_iterator GhostLayerFieldAdap
 
 template< typename Functor, uint_t glD >
 typename GhostLayerFieldAdaptor<Functor,glD>::const_iterator GhostLayerFieldAdaptor<Functor,glD>::beginGhostLayerOnlyXYZ(
-         stencil::Direction dir, cell_idx_t f ) const
+         stencil::Direction dir, cell_idx_t /*f*/ ) const
 {
    CellInterval ci;
    getGhostRegion(dir,ci);
@@ -326,7 +326,7 @@ typename GhostLayerFieldAdaptor<Functor,glD>::const_iterator GhostLayerFieldAdap
 
 template< typename Functor, uint_t glD >
 typename GhostLayerFieldAdaptor<Functor,glD>::const_iterator GhostLayerFieldAdaptor<Functor,glD>::beginSliceBeforeGhostLayerXYZ(
-         stencil::Direction dir, cell_idx_t width, cell_idx_t f) const
+         stencil::Direction dir, cell_idx_t width, cell_idx_t /*f*/) const
 {
    CellInterval ci;
    getSliceBeforeGhostLayer(dir,ci,width);
diff --git a/src/field/allocation/FieldAllocator.h b/src/field/allocation/FieldAllocator.h
index 7a3164edee1dacc3dafb8675bdb15740b33a5322..eb93be118447d799a2c1c984f3e91235d55d2067 100644
--- a/src/field/allocation/FieldAllocator.h
+++ b/src/field/allocation/FieldAllocator.h
@@ -351,6 +351,26 @@ namespace field {
    };
 
 
+constexpr uint_t SIMDAlignment() {
+#if defined(__ARM_FEATURE_SVE) && defined(__ARM_FEATURE_SVE_BITS) && __ARM_FEATURE_SVE_BITS > 0
+   return uint_c(__ARM_FEATURE_SVE_BITS / 8);
+#elif defined(__ARM_FEATURE_SVE)
+   return 64u;
+#elif defined(__ARM_NEON)
+   return 16u;
+#elif defined(__AVX512F__)
+   return 64u;
+#elif defined(__AVX__)
+   return 32u;
+#elif defined(__SSE__) || defined(_MSC_VER)
+   return 16u;
+#elif defined(__BIGGEST_ALIGNMENT__)
+   return uint_c(__BIGGEST_ALIGNMENT__);
+#else
+   return 64u;
+#endif
+}
+
 } // namespace field
 } // namespace walberla
 
diff --git a/src/field/vtk/FlagFieldMapping.h b/src/field/vtk/FlagFieldMapping.h
index f8cb572b5682f4faaed44832758f45efb5886fa8..e9bfe963b3c577fc7758f595f514dd74fd6b01c0 100644
--- a/src/field/vtk/FlagFieldMapping.h
+++ b/src/field/vtk/FlagFieldMapping.h
@@ -38,7 +38,7 @@ private:
 public:
 
    FlagFieldMapping( const ConstBlockDataID flagId, const std::string& id ) :
-      vtk::BlockCellDataWriter<T,1>( id ), flagId_( flagId ), flagField_( NULL ) {}
+      vtk::BlockCellDataWriter<T,1>( id ), flagId_( flagId ), flagField_( nullptr ) {}
 
    FlagFieldMapping( const ConstBlockDataID flagId, const std::string& id, const std::map< FlagUID, T > mapping ) :
       vtk::BlockCellDataWriter<T,1>( id ), flagId_( flagId ), flagField_( nullptr ), mapping_( mapping ) {}
@@ -90,16 +90,16 @@ class BinarizationFieldWriter : public vtk::BlockCellDataWriter<TargetType,1>
 
 public:
    BinarizationFieldWriter( const ConstBlockDataID fieldID, const std::string& id, SrcType mask) :
-           vtk::BlockCellDataWriter<TargetType,1>( id ), fieldID_( fieldID ), field_( NULL ), mask_( mask ) {}
+           vtk::BlockCellDataWriter<TargetType,1>( id ), fieldID_( fieldID ), field_( nullptr ), mask_( mask ) {}
 
 protected:
 
-   void configure()  {
+   void configure() override {
       WALBERLA_ASSERT_NOT_NULLPTR( this->block_ );
       field_ = this->block_->template getData< FieldType >( fieldID_ );
    }
 
-   TargetType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ )
+   TargetType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) override
    {
       WALBERLA_ASSERT_NOT_NULLPTR( field_ );
       if (field_->get(x,y,z) & mask_) {
diff --git a/src/field/vtk/VTKWriter.h b/src/field/vtk/VTKWriter.h
index 9b2232908b09766e9296c5529ff5dc205ae3a1d9..c9852b7f8bf034af797938161b75252b276f13db 100644
--- a/src/field/vtk/VTKWriter.h
+++ b/src/field/vtk/VTKWriter.h
@@ -126,13 +126,10 @@ protected:
          // common case that can be handled faster
          return numeric_cast<OutputType>( OutputTrait::get( field_->get(x,y,z,0), uint_c(f) )  );
       }
-      else
-      {
-         const cell_idx_t fField = f / cell_idx_c( OutputTrait::F_SIZE );
-         const cell_idx_t fType  = f % cell_idx_c( OutputTrait::F_SIZE );
+      const cell_idx_t fField = f / cell_idx_c( OutputTrait::F_SIZE );
+      const cell_idx_t fType  = f % cell_idx_c( OutputTrait::F_SIZE );
 
-         return numeric_cast<OutputType>( OutputTrait::get( field_->get(x,y,z,fField), uint_c(fType) )  );
-      }
+      return numeric_cast<OutputType>( OutputTrait::get( field_->get(x,y,z,fField), uint_c(fType) )  );
    }
 
    const ConstBlockDataID bdid_;
diff --git a/src/gather/CellGatherPackInfo.impl.h b/src/gather/CellGatherPackInfo.impl.h
index ff3e1dcdd687c077773494a0ea30c9d5717cb4dc..1dc7e14c190f36cc3f3284b009fa44d3084687f8 100644
--- a/src/gather/CellGatherPackInfo.impl.h
+++ b/src/gather/CellGatherPackInfo.impl.h
@@ -99,8 +99,8 @@ void CellGatherPackInfo<Field_T,CC>::unpackData( mpi::RecvBuffer & buffer )
 
    for( size_t i=0; i< nrPoints; ++i )
    {
-      receivedData.push_back(std::vector<real_t>(fieldSize+1)); //+1 because we also store t value as first entry
-      std::vector<real_t> & pointVec = receivedData[receivedData.size()-1];
+      receivedData.emplace_back(std::vector<real_t>(fieldSize+1)); //+1 because we also store t value as first entry
+      std::vector<real_t> & pointVec = receivedData.back();
 
       uint_t t;
       real_t val;
diff --git a/src/gather/CurveGatherPackInfo.h b/src/gather/CurveGatherPackInfo.h
index ea42f21dfb326ac7719052125417dffbd1956a2d..05af4398b5f4bf40b31f443cb945123111fedb5d 100644
--- a/src/gather/CurveGatherPackInfo.h
+++ b/src/gather/CurveGatherPackInfo.h
@@ -106,7 +106,7 @@ class CurveGatherPackInfo : public GatherPackInfo
                            const shared_ptr<DataProcessor> & dp);
 
 
-      ~CurveGatherPackInfo() override {}
+      ~CurveGatherPackInfo() override = default;
 
       //@}
       //****************************************************************************************************************
diff --git a/src/gather/CurveGatherPackInfo.impl.h b/src/gather/CurveGatherPackInfo.impl.h
index 0039b2a05cb1f3c16adb1ab427bb8ae925fc9923..5c61a90703f143d4ca35338f874c5b348932b849 100644
--- a/src/gather/CurveGatherPackInfo.impl.h
+++ b/src/gather/CurveGatherPackInfo.impl.h
@@ -185,8 +185,8 @@ void CurveGatherPackInfo<GlF,IP>::unpackData( mpi::RecvBuffer & buffer )
 
    for( size_t i=0; i< nrPoints; ++i )
    {
-      receivedData.push_back(std::vector<real_t>(fieldSize+1)); //+1 because we also store t value as first entry
-      std::vector<real_t> & pointVec = receivedData[receivedData.size()-1];
+      receivedData.emplace_back(std::vector<real_t>(fieldSize+1)); //+1 because we also store t value as first entry
+      std::vector<real_t> & pointVec = receivedData.back();
 
       real_t t;
       real_t val;
diff --git a/src/geometry/containment_octree/BranchNode.h b/src/geometry/containment_octree/BranchNode.h
index 2b160ad5b3641e5adcbcdba3c6c245bcbc2f89c8..cb10fdabbf1b0f54406c2fd853838fbca114c7dd 100644
--- a/src/geometry/containment_octree/BranchNode.h
+++ b/src/geometry/containment_octree/BranchNode.h
@@ -46,7 +46,7 @@ public:
    inline BranchNode( const shared_ptr<const DistanceObject> & distanceObject, const AABB & aabb, const Scalar epsilon,
                       const uint_t maxDepth, const Scalar minAABBVolume );
 
-   virtual ~BranchNode() { for( int i = 0; i < 8; ++i ) delete children_[i]; }
+   ~BranchNode() override { for( int i = 0; i < 8; ++i ) delete children_[i]; }
 
    virtual inline bool contains( const Point & p ) const;
 
@@ -74,7 +74,7 @@ BranchNode<ContainmentOctreeT>::BranchNode( const shared_ptr<const DistanceObjec
                                             const uint_t maxDepth, const Scalar minAABBVolume ) : center_( this->toPoint( aabb.center() ) )
 {
    for( int i = 0; i < 8; ++i )
-      children_[i] = NULL;
+      children_[i] = nullptr;
 
    const auto & min = aabb.minCorner();
    const auto & max = aabb.maxCorner();
diff --git a/src/geometry/containment_octree/IndeterminateLeafNode.h b/src/geometry/containment_octree/IndeterminateLeafNode.h
index 382620f5767bbc746dbc7873448c42532a24aa46..f21fa5a653531244560d28cfcb9dab4327e3021c 100644
--- a/src/geometry/containment_octree/IndeterminateLeafNode.h
+++ b/src/geometry/containment_octree/IndeterminateLeafNode.h
@@ -44,12 +44,12 @@ public:
    IndeterminateLeafNode( const shared_ptr<const DistanceObject> & distanceObject, const Scalar epsilon )
       :  distanceObject_( distanceObject ), sqEpsilon_( epsilon * epsilon ) { }
 
-   virtual ~IndeterminateLeafNode() = default;
+   ~IndeterminateLeafNode() override = default;
 
-   virtual bool contains( const Point & p ) const { return distanceObject_->sqSignedDistance(p) <= sqEpsilon_; }
+   bool contains( const Point & p ) const override { return distanceObject_->sqSignedDistance(p) <= sqEpsilon_; }
 
-   virtual void numNodes( uint_t & /*numInside*/, uint_t & /*numOutside*/, uint_t & numIndeterminate, uint_t & /*numBranch*/ ) const { ++numIndeterminate; }
-   virtual void volumes( KahanAccumulator & /*insideVolume*/, KahanAccumulator & /*outsideVolume*/, KahanAccumulator & indeterminateVolume, Scalar volume ) const { indeterminateVolume += volume; }
+   void numNodes( uint_t & /*numInside*/, uint_t & /*numOutside*/, uint_t & numIndeterminate, uint_t & /*numBranch*/ ) const override { ++numIndeterminate; }
+   void volumes( KahanAccumulator & /*insideVolume*/, KahanAccumulator & /*outsideVolume*/, KahanAccumulator & indeterminateVolume, Scalar volume ) const override { indeterminateVolume += volume; }
 
 protected:
    shared_ptr<const DistanceObject> distanceObject_;
diff --git a/src/geometry/containment_octree/InsideLeafNode.h b/src/geometry/containment_octree/InsideLeafNode.h
index 0c46290f13148bcd3d2451301512d6ae5a62df0d..30b83eb93f6c962f3fb9efccabfbc8449bbd4eec 100644
--- a/src/geometry/containment_octree/InsideLeafNode.h
+++ b/src/geometry/containment_octree/InsideLeafNode.h
@@ -41,12 +41,12 @@ public:
     
    using KahanAccumulator = typename LeafNode<ContainmentOctreeT>::KahanAccumulator;
 
-   virtual ~InsideLeafNode() = default;
+   ~InsideLeafNode() override = default;
 
-   virtual bool contains( const Point & /*p*/ ) const { return true; }
+   bool contains( const Point & /*p*/ ) const override { return true; }
 
-   virtual void numNodes( uint_t & numInside, uint_t & /*numOutside*/, uint_t & /*numIndeterminate*/, uint_t & /*numBranch*/ ) const { ++numInside; }
-   virtual void volumes( KahanAccumulator & insideVolume, KahanAccumulator & /*outsideVolume*/, KahanAccumulator & /*indeterminateVolume*/, Scalar volume ) const { insideVolume += volume; }
+   void numNodes( uint_t & numInside, uint_t & /*numOutside*/, uint_t & /*numIndeterminate*/, uint_t & /*numBranch*/ ) const override { ++numInside; }
+   void volumes( KahanAccumulator & insideVolume, KahanAccumulator & /*outsideVolume*/, KahanAccumulator & /*indeterminateVolume*/, Scalar volume ) const override { insideVolume += volume; }
 };
 
    
diff --git a/src/geometry/containment_octree/LeafNode.h b/src/geometry/containment_octree/LeafNode.h
index 177a352dc1f07300f09f6058df8755b98d57e96f..231ab10891ec7cd9120b7d0484feea95c9de089b 100644
--- a/src/geometry/containment_octree/LeafNode.h
+++ b/src/geometry/containment_octree/LeafNode.h
@@ -42,13 +42,13 @@ public:
    
    using KahanAccumulator = typename Node<ContainmentOctreeT>::KahanAccumulator;
 
-   virtual ~LeafNode() = default;
+   ~LeafNode() override = default;
 
-   virtual uint_t height() const { return uint_t(0); }
-   virtual uint_t numNodes() const { return uint_t(0); }
-   virtual uint_t numChildren() const { return uint_t(0); }
+   uint_t height() const override { return uint_t(0); }
+   uint_t numNodes() const override { return uint_t(0); }
+   uint_t numChildren() const override { return uint_t(0); }
 
-   virtual const Node<ContainmentOctreeT> * getChild( const uint_t ) const { WALBERLA_ABORT("ContainmentOctree: You are requesting access to children of a Leaf Node!"); return 0; }
+   const Node<ContainmentOctreeT> * getChild( const uint_t ) const override { WALBERLA_ABORT("ContainmentOctree: You are requesting access to children of a Leaf Node!"); return 0; }
 };
 
 
diff --git a/src/geometry/containment_octree/OutsideLeafNode.h b/src/geometry/containment_octree/OutsideLeafNode.h
index 6328ce593bfa29ad81ec0414f816eadc7580296f..782faaad4213434d974da1fd4afca7cc3ea3efcc 100644
--- a/src/geometry/containment_octree/OutsideLeafNode.h
+++ b/src/geometry/containment_octree/OutsideLeafNode.h
@@ -42,12 +42,12 @@ public:
    
    using KahanAccumulator = typename LeafNode<ContainmentOctreeT>::KahanAccumulator;
       
-   virtual ~OutsideLeafNode() = default;
+   ~OutsideLeafNode() override = default;
 
-   virtual bool contains( const Point & /*p*/ ) const { return false; }
+   bool contains( const Point & /*p*/ ) const override { return false; }
 
-   virtual void numNodes( uint_t & /*numInside*/, uint_t & numOutside, uint_t & /*numIndeterminate*/, uint_t & /*numBranch*/ ) const { ++numOutside; }
-   virtual void volumes( KahanAccumulator & /*insideVolume*/, KahanAccumulator & outsideVolume, KahanAccumulator & /*indeterminateVolume*/, Scalar volume ) const { outsideVolume += volume; }
+   void numNodes( uint_t & /*numInside*/, uint_t & numOutside, uint_t & /*numIndeterminate*/, uint_t & /*numBranch*/ ) const override { ++numOutside; }
+   void volumes( KahanAccumulator & /*insideVolume*/, KahanAccumulator & outsideVolume, KahanAccumulator & /*indeterminateVolume*/, Scalar volume ) const override { outsideVolume += volume; }
 };
 
    
diff --git a/src/geometry/initializer/BoundarySetterFlagFieldSpecialization.h b/src/geometry/initializer/BoundarySetterFlagFieldSpecialization.h
index e154678f0afb0392184d144a8ebe98389cf6bde4..dd5a376ee4649ed4c01a388902c624a23664afc8 100644
--- a/src/geometry/initializer/BoundarySetterFlagFieldSpecialization.h
+++ b/src/geometry/initializer/BoundarySetterFlagFieldSpecialization.h
@@ -109,13 +109,13 @@ namespace initializer {
    }
 
    template<typename Flag_T>
-   void BoundarySetter<FlagField<Flag_T> >::setBoundaryConfigBlock( const BoundaryUID & boundaryUID, const Config::BlockHandle & blockHandle )
+   void BoundarySetter<FlagField<Flag_T> >::setBoundaryConfigBlock( [[maybe_unused]] const BoundaryUID & boundaryUID, [[maybe_unused]] const Config::BlockHandle & blockHandle )
    {
       WALBERLA_ABORT("Passed boundary information to an initializer that sets up a pure flag field only");
    }
 
    template<typename Flag_T>
-   void BoundarySetter<FlagField<Flag_T>>::setBoundaryConfig( const BoundaryUID & boundaryUID, const shared_ptr<BoundaryConfiguration> & conf )
+   void BoundarySetter<FlagField<Flag_T>>::setBoundaryConfig( [[maybe_unused]] const BoundaryUID & boundaryUID, [[maybe_unused]] const shared_ptr<BoundaryConfiguration> & conf )
    {
       WALBERLA_ABORT("Passed boundary information to an initializer that sets up a pure flag field only");
    }
diff --git a/src/geometry/initializer/ScalarFieldFromBody.impl.h b/src/geometry/initializer/ScalarFieldFromBody.impl.h
index 7c96eea77189949df6c8e6b3c3f92491406eab27..95ade01e0dc2a71abb82aa07a964484f4c9883e6 100644
--- a/src/geometry/initializer/ScalarFieldFromBody.impl.h
+++ b/src/geometry/initializer/ScalarFieldFromBody.impl.h
@@ -32,6 +32,8 @@
 #include "core/mpi/Reduce.h"
 #include "core/stringToNum.h"
 
+#include <utility>
+
 
 namespace walberla {
 namespace geometry {
@@ -60,7 +62,7 @@ namespace initializer {
          addOrSet = false;
       
       auto        id         = subBlock.getParameter< std::vector<BlockDataID>::size_type > ( "id", 0 );
-      std::string shape      = subBlock.getParameter< std::string >                         ( "shape" );
+      std::ignore            = subBlock.getParameter< std::string >                         ( "shape" );
       std::string expression = subBlock.getParameter< std::string >                         ( "value" );
       
       try
diff --git a/src/gpu/DeviceWrapper.h b/src/gpu/DeviceWrapper.h
index 3bdf1be008dbe166565e1f131020f7bb3e53714d..b5270a57c52b9b52092e74340cd185e358a9e00c 100644
--- a/src/gpu/DeviceWrapper.h
+++ b/src/gpu/DeviceWrapper.h
@@ -66,10 +66,12 @@ namespace gpustubs {
                   "available and shouldn't be called!");
 
 #ifndef __CUDACC__
+   //NOLINTBEGIN(bugprone-reserved-identifier)
    #define __device__
    #define __global__
    #define __host__
    #define __forceinline__
+   //NOLINTEND(bugprone-reserved-identifier)
 #endif
 
 using gpuError_t = int;
diff --git a/src/gpu/HostFieldAllocator.h b/src/gpu/HostFieldAllocator.h
index 8b24c3a47cd06dbf97a5ef07177a4f152f3fb509..e6a97c061927642c223125f708ba550074ff7f81 100644
--- a/src/gpu/HostFieldAllocator.h
+++ b/src/gpu/HostFieldAllocator.h
@@ -34,10 +34,10 @@ namespace gpu
 
    //*******************************************************************************************************************
    /*!
-   * Allocator that allocates a CPU! field using gpuHostAlloc without padding
+   * Allocator that allocates a CPU! field using gpuHostAlloc without padding.
    *
-   * Uses gpuHostAlloc for the allocation - which allocates page-locked memory that is faster to transfer to the GPU
-   * This allocator should be used for CPU fields that are often transferred to GPU and back
+   * Uses gpuHostAlloc for the allocation - which allocates page-locked memory that is faster to transfer to the GPU.
+   * This allocator should be used for CPU fields that are often transferred to GPU and back.
    *
    * \ingroup gpu
    *
@@ -47,10 +47,10 @@ namespace gpu
    class HostFieldAllocator : public field::FieldAllocator<T>
    {
    public:
-      virtual ~HostFieldAllocator() = default;
+      ~HostFieldAllocator() override = default;
 
-      virtual T * allocateMemory (  uint_t size0, uint_t size1, uint_t size2, uint_t size3,
-                                    uint_t & allocSize1, uint_t & allocSize2, uint_t & allocSize3 )
+      T * allocateMemory (  uint_t size0, uint_t size1, uint_t size2, uint_t size3,
+                            uint_t & allocSize1, uint_t & allocSize2, uint_t & allocSize3 ) override
       {
          WALBERLA_NON_DEVICE_SECTION()
          {
@@ -65,7 +65,7 @@ namespace gpu
          return (T*)(result);
       }
 
-      virtual T * allocateMemory ( uint_t size )
+      T * allocateMemory ( uint_t size ) override
       {
          WALBERLA_NON_DEVICE_SECTION()
          {
@@ -77,7 +77,7 @@ namespace gpu
          return (T*)(result);
       }
 
-      virtual void deallocate(T *& values) {
+      void deallocate(T *& values) override {
          WALBERLA_NON_DEVICE_SECTION() {
             WALBERLA_ABORT(__FUNCTION__ << "Using GPU method without WALBERLA_BUILD_WITH_GPU_SUPPORT being enabled.")
          }
diff --git a/src/lbm/MassEvaluation.h b/src/lbm/MassEvaluation.h
index 7efe2daaebf0d9e89134f77702a889b49e306fea..0a02e1ea065b15cc5cd50a4243e438bc19c9659a 100644
--- a/src/lbm/MassEvaluation.h
+++ b/src/lbm/MassEvaluation.h
@@ -33,7 +33,7 @@ namespace lbm {
 
 namespace internal {
 
-Vector3<real_t> massEvaluationDomain( const shared_ptr< StructuredBlockStorage > & blocks, const uint_t level )
+inline Vector3<real_t> massEvaluationDomain( const shared_ptr< StructuredBlockStorage > & blocks, const uint_t level )
 {
    return Vector3<real_t>( real_c( blocks->getNumberOfXCells(level) ),
                            real_c( blocks->getNumberOfYCells(level) ),
diff --git a/src/lbm/PerformanceEvaluation.h b/src/lbm/PerformanceEvaluation.h
index d1deed9c17fd6c7f1b5a0e24da699bc1229ffd45..25bd56517a06b983a547b77b51d112076a4cac96 100644
--- a/src/lbm/PerformanceEvaluation.h
+++ b/src/lbm/PerformanceEvaluation.h
@@ -226,7 +226,7 @@ PerformanceEvaluationBase< CellCounter_T, FluidCellCounter_T >::PerformanceEvalu
      fluidCells_( fluidCellCounter )
 {
 #ifdef _OPENMP
-   if( std::getenv( "OMP_NUM_THREADS" ) == NULL )
+   if( std::getenv( "OMP_NUM_THREADS" ) == nullptr )
       WALBERLA_ABORT( "If you are using a version of the program that was compiled with OpenMP you have to "
                       "specify the environment variable \'OMP_NUM_THREADS\' accordingly!" );
    threadsPerProcess_ = std::atoi( std::getenv( "OMP_NUM_THREADS" ) );
diff --git a/src/lbm/boundary/DiffusionDirichlet.h b/src/lbm/boundary/DiffusionDirichlet.h
index 7ffa062a01770210b398a4ba5fa9ff3fa475cbaf..a79292a01ded5a5167d153c2829fbd8b4ef48c4b 100644
--- a/src/lbm/boundary/DiffusionDirichlet.h
+++ b/src/lbm/boundary/DiffusionDirichlet.h
@@ -82,7 +82,7 @@ public:
 
    static shared_ptr<SingleScalarConfiguration> createConfiguration( const Config::BlockHandle & config ) { return make_shared<SingleScalarConfiguration>( config ); }
 
-   inline DiffusionDirichlet( const BoundaryUID & boundaryUID, const FlagUID & uid, PDFField* const pdfField, FlagField<flag_t> * const flagField = NULL );
+   inline DiffusionDirichlet( const BoundaryUID & boundaryUID, const FlagUID & uid, PDFField* const pdfField, FlagField<flag_t> * const flagField = nullptr );
 
    void pushFlags( std::vector< FlagUID > & uids ) const { uids.push_back( uid_ ); }
 
diff --git a/src/lbm/boundary/ParserUBB.h b/src/lbm/boundary/ParserUBB.h
index 309b44c472ed80ad7168145c252b6a312bb5f614..8559af959fd29f619b3d2284b8a7453de9fa1db9 100644
--- a/src/lbm/boundary/ParserUBB.h
+++ b/src/lbm/boundary/ParserUBB.h
@@ -220,19 +220,19 @@ template< typename LatticeModel_T, typename flag_t, bool AdaptVelocityToExternal
 inline ParserUBB<LatticeModel_T, flag_t, AdaptVelocityToExternalForce, StoreForce>::Parser::Parser( const std::array< std::string, 3 > & equations )
 : parsers_(), equations_( equations ), timeDependent_( false )
 {
-   if( equations_[0].length() > 0 )
+   if( not equations_[0].empty() )
    {
       parsers_[0].parse( equations_[0] );
       if( parsers_[0].symbolExists( "t" ) )
          timeDependent_ = true;
    }
-   if( equations_[1].length() > 0 )
+   if( not equations_[1].empty() )
    {
       parsers_[1].parse( equations_[1] );
       if( parsers_[1].symbolExists( "t" ) )
          timeDependent_ = true;
    }
-   if( equations_[2].length() > 0 )
+   if( not equations_[2].empty() )
    {
       parsers_[2].parse( equations_[2] );
       if( parsers_[2].symbolExists( "t" ) )
@@ -297,7 +297,7 @@ inline ParserUBB<LatticeModel_T, flag_t, AdaptVelocityToExternalForce, StoreForc
    origin_[1] = aabb.yMin() + real_c(0.5) * dx_[1];
    origin_[2] = aabb.zMin() + real_c(0.5) * dx_[2];
 
-   if(flagField != NULL)
+   if(flagField != nullptr)
    {
       parserField_   = make_shared<ParserField>  ( pdfField->xSize(), pdfField->ySize(), pdfField->zSize(), flagField->nrOfGhostLayers(), field::fzyx );
       velocityField_ = make_shared<VelocityField>( pdfField->xSize(), pdfField->ySize(), pdfField->zSize(), flagField->nrOfGhostLayers(), field::fzyx );
diff --git a/src/lbm/boundary/Pressure.h b/src/lbm/boundary/Pressure.h
index 51dc64c2aa5ce044d830ea302a050ef43ba386c8..0ac8e13b319f8335293bf1d605ac16ed1b2eb8b8 100644
--- a/src/lbm/boundary/Pressure.h
+++ b/src/lbm/boundary/Pressure.h
@@ -72,7 +72,7 @@ public:
    static shared_ptr<LatticeDensity> createConfiguration( const Config::BlockHandle & config ) { return make_shared<LatticeDensity>( config ); }
 
 
-   inline Pressure( const BoundaryUID & boundaryUID, const FlagUID & uid, PDFField* const pdfField, FlagField<flag_t> * const flagField = NULL );
+   inline Pressure( const BoundaryUID & boundaryUID, const FlagUID & uid, PDFField* const pdfField, FlagField<flag_t> * const flagField = nullptr );
 
    void pushFlags( std::vector< FlagUID > & uids ) const { uids.push_back( uid_ ); }
 
@@ -124,7 +124,7 @@ inline Pressure< LatticeModel_T, flag_t>::Pressure( const BoundaryUID & boundary
    WALBERLA_ASSERT_NOT_NULLPTR( pdfField_ );
 
    WALBERLA_ASSERT_NOT_NULLPTR( pdfField_ );
-   if (flagField != NULL)
+   if (flagField != nullptr)
       latticeDensityField_ = make_shared<LatticeDensityField>( pdfField_->xSize(), pdfField_->ySize(), pdfField_->zSize(), flagField->nrOfGhostLayers(), field::fzyx );
    else
       latticeDensityField_ = make_shared<LatticeDensityField>( pdfField_->xSize(), pdfField_->ySize(), pdfField_->zSize(), pdfField_->nrOfGhostLayers(), field::fzyx );
diff --git a/src/lbm/boundary/VelocityBoundary.h b/src/lbm/boundary/VelocityBoundary.h
index 72901642c3d261e9cfd4496d80f5e16ce743a306..bfeb31f461032fb5fe6aa5db668017afad22cae2 100644
--- a/src/lbm/boundary/VelocityBoundary.h
+++ b/src/lbm/boundary/VelocityBoundary.h
@@ -89,7 +89,7 @@ public:
 
 
 
-   inline VelocityBoundary( const BoundaryUID & boundaryUID, const FlagUID & uid, PDFField* const pdfField, FlagField<flag_t> * const flagField = NULL );
+   inline VelocityBoundary( const BoundaryUID & boundaryUID, const FlagUID & uid, PDFField* const pdfField, FlagField<flag_t> * const flagField = nullptr );
 
    void pushFlags( std::vector< FlagUID > & uids ) const { uids.push_back( uid_ ); }
 
@@ -142,7 +142,7 @@ inline VelocityBoundary< LatticeModel_T, flag_t >::VelocityBoundary( const Bound
    Boundary<flag_t>( boundaryUID ), uid_( uid ), pdfField_( pdfField )
 {
    WALBERLA_ASSERT_NOT_NULLPTR( pdfField_ );
-   if (flagField != NULL)
+   if (flagField != nullptr)
       vel_ = make_shared<VelField>( pdfField_->xSize(), pdfField_->ySize(), pdfField_->zSize(), flagField->nrOfGhostLayers(), field::fzyx );
    else
       vel_ = make_shared<VelField>( pdfField_->xSize(), pdfField_->ySize(), pdfField_->zSize(), pdfField_->nrOfGhostLayers(), field::fzyx );
diff --git a/src/lbm/communication/SparsePdfFieldPackInfo.h b/src/lbm/communication/SparsePdfFieldPackInfo.h
index 6b4a86af6073ad113d47f0f8fcb067066a74508e..aebdd204c47667f991c9386dc6843e808a476b90 100644
--- a/src/lbm/communication/SparsePdfFieldPackInfo.h
+++ b/src/lbm/communication/SparsePdfFieldPackInfo.h
@@ -68,7 +68,7 @@ public:
    SparsePdfFieldPackInfo( const BlockDataID & pdfFieldId, const BlockDataID & flagFieldId, FlagUID flag, bool flagFieldConstant )
       : pdfFieldId_( pdfFieldId ), flagFieldId_( flagFieldId ), flag_( flag ), flagFieldConstant_( flagFieldConstant ) {}
 
-   virtual ~SparsePdfFieldPackInfo() {}
+   ~SparsePdfFieldPackInfo() override = default;
 
    bool constantDataExchange() const { return flagFieldConstant_; }
    bool threadsafeReceiving()  const { return true; }
diff --git a/src/lbm/field/DensityVelocityCallback.h b/src/lbm/field/DensityVelocityCallback.h
index acf99efbe6bb19706bbdda5ca0372fd2229292f2..925129f36b3678022d2b2eded43d6dfda13e24c9 100644
--- a/src/lbm/field/DensityVelocityCallback.h
+++ b/src/lbm/field/DensityVelocityCallback.h
@@ -320,7 +320,7 @@ class VelocityCallback
 {
 public:
 
-   VelocityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( NULL ) {}
+   VelocityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( nullptr ) {}
 
    void operator()( IBlock & block )
    {
@@ -349,7 +349,7 @@ template< typename VelocityField_T  >
 class VelocityCallback<VelocityField_T, typename std::enable_if< std::is_same< typename VelocityField_T::value_type, Vector3<real_t> >::value >::type >
 {
 public:
-   VelocityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( NULL ) {}
+   VelocityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( nullptr ) {}
 
    void operator()( IBlock & block )
    {
@@ -377,7 +377,7 @@ class DensityCallback
 {
 public:
 
-   DensityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( NULL ) {}
+   DensityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( nullptr ) {}
 
    void operator()( IBlock & block )
    {
@@ -407,7 +407,7 @@ class DensityVelocityCallback
 public:
 
    DensityVelocityCallback( const BlockDataID & velocityFieldId, const BlockDataID & densityFieldId ) :
-      vId_( velocityFieldId ), dId_( densityFieldId ), vfield_( NULL ), dfield_( NULL ) {}
+      vId_( velocityFieldId ), dId_( densityFieldId ), vfield_( nullptr ), dfield_( nullptr ) {}
 
    void operator()( IBlock & block )
    {
@@ -715,7 +715,7 @@ private:
 //{
 //public:
 //
-//   VelocityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( NULL ) {}
+//   VelocityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( nullptr ) {}
 //
 //   void operator()( IBlock & block )
 //   {
@@ -744,7 +744,7 @@ private:
 //{
 //public:
 //
-//   DensityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( NULL ) {}
+//   DensityCallback( const BlockDataID & fieldId ) : fieldId_( fieldId ), field_( nullptr ) {}
 //
 //   void operator()( IBlock & block )
 //   {
@@ -774,7 +774,7 @@ private:
 //public:
 //
 //   DensityVelocityCallback( const BlockDataID & velocityFieldId, const BlockDataID & densityFieldId ) :
-//      vId_( velocityFieldId ), dId_( densityFieldId ), vfield_( NULL ), dfield_( NULL ) {}
+//      vId_( velocityFieldId ), dId_( densityFieldId ), vfield_( nullptr ), dfield_( nullptr ) {}
 //
 //   void operator()( IBlock & block )
 //   {
diff --git a/src/lbm/field/initializer/PdfFieldInitializer.impl.h b/src/lbm/field/initializer/PdfFieldInitializer.impl.h
index 757cb180e1e8725b954b75c19a049fbd4139cc86..1a60e350cf171e1c2b435165e23073685e719ed9 100644
--- a/src/lbm/field/initializer/PdfFieldInitializer.impl.h
+++ b/src/lbm/field/initializer/PdfFieldInitializer.impl.h
@@ -25,7 +25,7 @@ namespace lbm {
 namespace initializer {
 
 template<>
-auto getCoordinates<false>(const Cell& globalCell, const real_t dx) {
+inline auto getCoordinates<false>(const Cell& globalCell, const real_t dx) {
 
    Cell coords;
    for(uint_t d = 0; d < 3; ++d) {
@@ -36,7 +36,7 @@ auto getCoordinates<false>(const Cell& globalCell, const real_t dx) {
 }
 
 template<>
-auto getCoordinates<true>(const Cell& globalCell, const real_t dx) {
+inline auto getCoordinates<true>(const Cell& globalCell, const real_t dx) {
 
    Vector3<real_t> coords;
    for(uint_t d = 0; d < 3; ++d) {
diff --git a/src/lbm/free_surface/LoadBalancing.h b/src/lbm/free_surface/LoadBalancing.h
index c9df54478e5c4af223f0be17fe128f86427f21ed..f1638263be4adfd77b7c87d08bfca1444dd52a39 100644
--- a/src/lbm/free_surface/LoadBalancing.h
+++ b/src/lbm/free_surface/LoadBalancing.h
@@ -50,10 +50,10 @@ class ProcessLoadEvaluator;
 /***********************************************************************************************************************
  * Create non-uniform block forest to be used for load balancing.
  **********************************************************************************************************************/
-std::shared_ptr< StructuredBlockForest > createNonUniformBlockForest(const Vector3< uint_t >& domainSize,
-                                                                     const Vector3< uint_t >& cellsPerBlock,
-                                                                     const Vector3< uint_t >& numBlocks,
-                                                                     const Vector3< bool >& periodicity)
+inline std::shared_ptr< StructuredBlockForest > createNonUniformBlockForest(const Vector3< uint_t >& domainSize,
+                                                                            const Vector3< uint_t >& cellsPerBlock,
+                                                                            const Vector3< uint_t >& numBlocks,
+                                                                            const Vector3< bool >& periodicity)
 {
    WALBERLA_CHECK_EQUAL(domainSize[0], cellsPerBlock[0] * numBlocks[0],
                         "The domain size is not divisible by the specified \"cellsPerBlock\" in x-direction.");
diff --git a/src/lbm/free_surface/boundary/FreeSurfaceBoundaryHandling.impl.h b/src/lbm/free_surface/boundary/FreeSurfaceBoundaryHandling.impl.h
index 1fdb69f9889978eb80c891181d27150940374b79..d9bd6420e2035bc5f997a854ac60a96c12aa9efd 100644
--- a/src/lbm/free_surface/boundary/FreeSurfaceBoundaryHandling.impl.h
+++ b/src/lbm/free_surface/boundary/FreeSurfaceBoundaryHandling.impl.h
@@ -59,8 +59,10 @@ class BoundaryBlockDataHandling
       : boundary_(boundary)
    {}
 
+   ~BoundaryBlockDataHandling() override = default;
+
    // initialize standard waLBerla boundary handling
-   BoundaryHandling_T* initialize(IBlock* const block)
+   BoundaryHandling_T* initialize(IBlock* const block) override
    {
       using B      = FreeSurfaceBoundaryHandling< LatticeModel_T, FlagField_T, ScalarField_T >;
       using flag_t = typename B::flag_t;
@@ -91,16 +93,16 @@ class BoundaryBlockDataHandling
                                     pressureOutflow, outlet, freeSlip);
    }
 
-   void serialize(IBlock* const block, const BlockDataID& id, mpi::SendBuffer& buffer)
+   void serialize(IBlock* const block, const BlockDataID& id, mpi::SendBuffer& buffer) override
    {
       BoundaryHandling_T* const boundaryHandlingPtr = block->getData< BoundaryHandling_T >(id);
       CellInterval everyCell                        = boundaryHandlingPtr->getFlagField()->xyzSizeWithGhostLayer();
       boundaryHandlingPtr->pack(buffer, everyCell, true);
    }
 
-   BoundaryHandling_T* deserialize(IBlock* const block) { return initialize(block); }
+   BoundaryHandling_T* deserialize(IBlock* const block) override { return initialize(block); }
 
-   void deserialize(IBlock* const block, const BlockDataID& id, mpi::RecvBuffer& buffer)
+   void deserialize(IBlock* const block, const BlockDataID& id, mpi::RecvBuffer& buffer) override
    {
       BoundaryHandling_T* const boundaryHandlingPtr = block->getData< BoundaryHandling_T >(id);
       CellInterval everyCell                        = boundaryHandlingPtr->getFlagField()->xyzSizeWithGhostLayer();
diff --git a/src/lbm/free_surface/dynamics/PdfRefillingSweep.h b/src/lbm/free_surface/dynamics/PdfRefillingSweep.h
index 8c1c745130aa0f37bb3fe353dc3251bc44e02801..7cc5ef225ab17397ac1ab6986e28ef02cfb06081 100644
--- a/src/lbm/free_surface/dynamics/PdfRefillingSweep.h
+++ b/src/lbm/free_surface/dynamics/PdfRefillingSweep.h
@@ -121,9 +121,9 @@ class ExtrapolationRefillingSweepBase : public RefillingSweepBase< LatticeModel_
         extrapolationOrder_(extrapolationOrder)
    {}
 
-   virtual ~ExtrapolationRefillingSweepBase() = default;
+   ~ExtrapolationRefillingSweepBase() override = default;
 
-   virtual void operator()(IBlock* const block) = 0;
+   void operator()(IBlock* const block) override = 0;
 
    /********************************************************************************************************************
     * Find the lattice direction in the given stencil that corresponds best to the provided direction.
diff --git a/src/lbm/free_surface/dynamics/functionality/ReconstructInterfaceCellABB.h b/src/lbm/free_surface/dynamics/functionality/ReconstructInterfaceCellABB.h
index b0f45113c95155be79c6118406bcd911890b9ffa..1172b721d04f9079e58a6c7d68923e8ae3f6f0b3 100644
--- a/src/lbm/free_surface/dynamics/functionality/ReconstructInterfaceCellABB.h
+++ b/src/lbm/free_surface/dynamics/functionality/ReconstructInterfaceCellABB.h
@@ -38,12 +38,12 @@ namespace walberla
 namespace free_surface
 {
 // get index of largest entry in n_dot_ci with isInterfaceOrLiquid==true && isPdfAvailable==false
-uint_t getIndexOfMaximum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
-                         const std::vector< real_t >& n_dot_ci);
+inline uint_t getIndexOfMaximum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
+                                const std::vector< real_t >& n_dot_ci);
 
 // get index of smallest entry in n_dot_ci with isInterfaceOrLiquid==true && isPdfAvailable==false
-uint_t getIndexOfMinimum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
-                         const std::vector< real_t >& n_dot_ci);
+inline uint_t getIndexOfMinimum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
+                                const std::vector< real_t >& n_dot_ci);
 
 // reconstruct PDFs according to pressure anti bounce back boundary condition (page 31, equation 4.5 in dissertation of
 // N. Thuerey, 2007)
@@ -384,8 +384,8 @@ void reconstructInterfaceCellLegacy(const FlagField_T* flagField, const ConstPdf
    }
 }
 
-uint_t getIndexOfMaximum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
-                         const std::vector< real_t >& n_dot_ci)
+inline uint_t getIndexOfMaximum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
+                                const std::vector< real_t >& n_dot_ci)
 {
    real_t maximum = -std::numeric_limits< real_t >::max();
    uint_t index   = std::numeric_limits< uint_t >::max();
@@ -411,8 +411,8 @@ uint_t getIndexOfMaximum(const std::vector< bool >& isInterfaceOrLiquid, const s
    return index;
 }
 
-uint_t getIndexOfMinimum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
-                         const std::vector< real_t >& n_dot_ci)
+inline uint_t getIndexOfMinimum(const std::vector< bool >& isInterfaceOrLiquid, const std::vector< bool >& isPdfAvailable,
+                                const std::vector< real_t >& n_dot_ci)
 {
    real_t minimum = std::numeric_limits< real_t >::max();
    uint_t index   = std::numeric_limits< uint_t >::max();
diff --git a/src/lbm/free_surface/surface_geometry/CurvatureSweep.impl.h b/src/lbm/free_surface/surface_geometry/CurvatureSweep.impl.h
index f6d46d10334e86a23e20593a06de5af1b37e5b2b..1e279596befa20302cfce7bcc4ca97d795a168a7 100644
--- a/src/lbm/free_surface/surface_geometry/CurvatureSweep.impl.h
+++ b/src/lbm/free_surface/surface_geometry/CurvatureSweep.impl.h
@@ -327,8 +327,8 @@ void CurvatureSweepLocalTriangulation< Stencil_T, FlagField_T, ScalarField_T, Ve
                {
                   const real_t diff = nIt1->dist2 - nIt2->dist2;
 
-                  if (diff < real_c(1e-4)) { nIt1->valid = nIt1->wall ? true : false; }
-                  if (diff > real_c(-1e-4)) { nIt2->valid = nIt2->wall ? true : false; }
+                  if (diff < real_c(1e-4)) { nIt1->valid = nIt1->wall; }
+                  if (diff > real_c(-1e-4)) { nIt2->valid = nIt2->wall; }
                }
             }
          }
diff --git a/src/lbm/lattice_model/ForceModel.h b/src/lbm/lattice_model/ForceModel.h
index 527b5f5f395d8164b10cde47e6015e91424b72b4..aa1f35752554aadbdd7e1060129437b93b08f8c9 100644
--- a/src/lbm/lattice_model/ForceModel.h
+++ b/src/lbm/lattice_model/ForceModel.h
@@ -287,7 +287,7 @@ public:
    static const bool constant = false;
 
    EDMField( const BlockDataID & forceDensityFieldId ) :
-      forceDensityFieldId_( forceDensityFieldId ), forceDensityField_( NULL ) {}
+      forceDensityFieldId_( forceDensityFieldId ), forceDensityField_( nullptr ) {}
 
    void pack( mpi::SendBuffer & buffer ) const { buffer << forceDensityFieldId_; }
    void unpack( mpi::RecvBuffer & buffer ) { buffer >> forceDensityFieldId_; }
@@ -414,7 +414,7 @@ public:
    static const bool constant = false;
 
    LuoField( const BlockDataID & forceDensityFieldId ) :
-      forceDensityFieldId_( forceDensityFieldId ), forceDensityField_( NULL ) {}
+      forceDensityFieldId_( forceDensityFieldId ), forceDensityField_( nullptr ) {}
 
    void pack( mpi::SendBuffer & buffer ) const { buffer << forceDensityFieldId_; }
    void unpack( mpi::RecvBuffer & buffer ) { buffer >> forceDensityFieldId_; }
diff --git a/src/lbm/sweeps/ActiveCellSweep.h b/src/lbm/sweeps/ActiveCellSweep.h
index 4874c36af4fc4c666aaef3f37610d8faeded25c6..91fa31bc563cb9a6360f61d92d3a708769f3c204 100644
--- a/src/lbm/sweeps/ActiveCellSweep.h
+++ b/src/lbm/sweeps/ActiveCellSweep.h
@@ -84,9 +84,9 @@ private:
 template< typename LatticeModel_T, typename FlagField_T, typename CellOperation >
 void ActiveCellSweep< LatticeModel_T, FlagField_T, CellOperation >::operator()( IBlock * const block )
 {
-   PdfField_T * src( NULL );
-   PdfField_T * dst( NULL );
-   const FlagField_T * flagField( NULL );
+   PdfField_T * src( nullptr );
+   PdfField_T * dst( nullptr );
+   const FlagField_T * flagField( nullptr );
 
    auto lbm = this->getLbmMaskAndFields( block, src, dst, flagField );
 
diff --git a/src/lbm/sweeps/CellwiseSweep.h b/src/lbm/sweeps/CellwiseSweep.h
index e35e32f64b630a998edff5829c7d2f961b707618..70f6bc89922867840a16b028ebc318b033e2bcf3 100644
--- a/src/lbm/sweeps/CellwiseSweep.h
+++ b/src/lbm/sweeps/CellwiseSweep.h
@@ -139,8 +139,8 @@ class CellwiseSweep
    void CellwiseSweep< LatticeModel_T, Filter_T, DensityVelocityIn_T, DensityVelocityOut_T, typename std::enable_if< specialization >::type \
       >::stream( IBlock * const block, const uint_t numberOfGhostLayersToInclude ) \
    { \
-      PdfField_T * src( NULL ); \
-      PdfField_T * dst( NULL ); \
+      PdfField_T * src( nullptr ); \
+      PdfField_T * dst( nullptr ); \
       this->getFields( block, src, dst ); \
       StreamPull< LatticeModel_T >::execute( src, dst, block, this->filter_, numberOfGhostLayersToInclude ); \
    }
@@ -152,8 +152,8 @@ class CellwiseSweep
    void CellwiseSweep< LatticeModel_T, Filter_T, DensityVelocityIn_T, DensityVelocityOut_T, typename std::enable_if< specialization >::type \
       >::streamCollide( IBlock * const block, const uint_t numberOfGhostLayersToInclude ) \
    { \
-      PdfField_T * src( NULL ); \
-      PdfField_T * dst( NULL ); \
+      PdfField_T * src( nullptr ); \
+      PdfField_T * dst( nullptr ); \
       \
       this->getFields( block, src, dst ); \
       \
diff --git a/src/lbm/vtk/CurlMagnitude.h b/src/lbm/vtk/CurlMagnitude.h
index 0aa89feab888184a4f716d8e29df58ceb712c724..473fc87978c5757656918c9db1b39f6f3aa8d947 100644
--- a/src/lbm/vtk/CurlMagnitude.h
+++ b/src/lbm/vtk/CurlMagnitude.h
@@ -43,16 +43,16 @@ public:
    CurlMagnitudeVTKWriter(const shared_ptr<StructuredBlockStorage> blockStorage, Filter_T & filter,
          const ConstBlockDataID & velocityFieldId, const std::string & id, const real_t lengthScaleWeight = real_t(-1)) :
          vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter),
-         velocityFieldId_(velocityFieldId), velocityField_(NULL), lengthScaleWeight_(lengthScaleWeight) {}
+         velocityFieldId_(velocityFieldId), velocityField_(nullptr), lengthScaleWeight_(lengthScaleWeight) {}
 
 protected:
 
-   void configure() {
+   void configure() override {
       WALBERLA_ASSERT_NOT_NULLPTR( this->block_ );
       velocityField_ = this->block_->template getData< VelocityField_T >(velocityFieldId_ );
    }
 
-   OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ )
+   OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) override
    {
       WALBERLA_ASSERT_NOT_NULLPTR(velocityField_ );
 
diff --git a/src/lbm/vtk/Density.h b/src/lbm/vtk/Density.h
index f40bc63599f003a7a13cb2303d256651b336d6dd..ba5b65d35bcbbe3689012d9c229d642853285e52 100644
--- a/src/lbm/vtk/Density.h
+++ b/src/lbm/vtk/Density.h
@@ -66,7 +66,7 @@ public:
    using PdfField_T = PdfField<LatticeModel_T>;
 
    DensitySIVTKWriter( const ConstBlockDataID & pdf, const real_t rho_SI, const std::string & id ) :
-      vtk::BlockCellDataWriter< OutputType >( id ), bdid_( pdf ), pdf_( NULL ), rho_SI_( rho_SI ) {}
+      vtk::BlockCellDataWriter< OutputType >( id ), bdid_( pdf ), pdf_( nullptr ), rho_SI_( rho_SI ) {}
 
 protected:
 
diff --git a/src/lbm/vtk/PressureTensor.h b/src/lbm/vtk/PressureTensor.h
index 60c3afe53ce06253e5d689f489f0ddf9d119b2c7..0f43e04dafec65e6dc77d4b070061ea7b2d6e015 100644
--- a/src/lbm/vtk/PressureTensor.h
+++ b/src/lbm/vtk/PressureTensor.h
@@ -39,7 +39,7 @@ public:
    using PdfField_T = PdfField<LatticeModel_T>;
 
    PressureTensorVTKWriter( const ConstBlockDataID & pdfFieldId, const std::string & id ) :
-      vtk::BlockCellDataWriter< OutputType, 9 >( id ), bdid_( pdfFieldId ), pdf_( NULL ) {}
+      vtk::BlockCellDataWriter< OutputType, 9 >( id ), bdid_( pdfFieldId ), pdf_( nullptr ) {}
 
 protected:
 
diff --git a/src/lbm/vtk/QCriterion.h b/src/lbm/vtk/QCriterion.h
index e3b2748ec0156c3d1df0a29d28c5d3404ead1ccf..5675c65db614bba4b97386084413d933dd7211d9 100644
--- a/src/lbm/vtk/QCriterion.h
+++ b/src/lbm/vtk/QCriterion.h
@@ -38,16 +38,16 @@ class QCriterionVTKWriter : public vtk::BlockCellDataWriter< OutputType, 1 >
 public:
    QCriterionVTKWriter(const shared_ptr<StructuredBlockStorage> blockStorage, Filter_T & filter,
                    const ConstBlockDataID & velocityFieldId, const std::string & id ) :
-         vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter), velocityFieldId_(velocityFieldId), velocityField_(NULL) {}
+         vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter), velocityFieldId_(velocityFieldId), velocityField_(nullptr) {}
 
 protected:
 
-   void configure() {
+   void configure() override {
       WALBERLA_ASSERT_NOT_NULLPTR( this->block_ );
       velocityField_ = this->block_->template getData< VelocityField_T >(velocityFieldId_ );
    }
 
-   OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ )
+   OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) override
    {
       WALBERLA_ASSERT_NOT_NULLPTR(velocityField_ );
 
diff --git a/src/lbm/vtk/Velocity.h b/src/lbm/vtk/Velocity.h
index 8a31c07d2ec5cb4c73f354e2d27daf11b0ceb9ad..f208158bc3e516078cad28b6cdf1aa79053571a8 100644
--- a/src/lbm/vtk/Velocity.h
+++ b/src/lbm/vtk/Velocity.h
@@ -93,7 +93,7 @@ public:
    using PdfField_T = PdfField<LatticeModel_T>;
 
    VelocitySIVTKWriter( const ConstBlockDataID & pdfFieldId, const real_t dx_SI, const real_t dt_SI, const std::string & id ) :
-      vtk::BlockCellDataWriter< OutputType, 3 >( id ), bdid_( pdfFieldId ), pdf_( NULL ), dxDividedByDt_SI_( dx_SI / dt_SI ) {}
+      vtk::BlockCellDataWriter< OutputType, 3 >( id ), bdid_( pdfFieldId ), pdf_( nullptr ), dxDividedByDt_SI_( dx_SI / dt_SI ) {}
 
 protected:
 
@@ -121,7 +121,7 @@ public:
    using PdfField_T = PdfField<LatticeModel_T>;
 
    VelocitySIMagnitudeVTKWriter( const ConstBlockDataID & pdfFieldId, const real_t dx_SI, const real_t dt_SI, const std::string & id ) :
-      vtk::BlockCellDataWriter< OutputType, 1 >( id ), bdid_( pdfFieldId ), pdf_( NULL ), dxDividedByDt_SI_( dx_SI / dt_SI ) {}
+      vtk::BlockCellDataWriter< OutputType, 1 >( id ), bdid_( pdfFieldId ), pdf_( nullptr ), dxDividedByDt_SI_( dx_SI / dt_SI ) {}
 
 protected:
 
diff --git a/src/lbm/vtk/Vorticity.h b/src/lbm/vtk/Vorticity.h
index 237b711d5778656ec5066176aa2acd5b2e561167..13ac64540c3d9de68a3778e673803e7f7f08874a 100644
--- a/src/lbm/vtk/Vorticity.h
+++ b/src/lbm/vtk/Vorticity.h
@@ -40,7 +40,7 @@ public:
          const ConstBlockDataID & velocityFieldId, const uint_t componentIdx, const std::string & id,
          const real_t normalizationConstant = real_t(1)) :
          vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter),
-         velocityFieldId_(velocityFieldId), componentIdx_(componentIdx), velocityField_(NULL),
+         velocityFieldId_(velocityFieldId), componentIdx_(componentIdx), velocityField_(nullptr),
          normalizationConstant_(normalizationConstant) {
       WALBERLA_ASSERT(componentIdx < uint_t(3),
             "The vorticity vector only has three components, i.e. the highest possible component index is 2.");
@@ -48,12 +48,12 @@ public:
 
 protected:
 
-   void configure() {
+   void configure() override {
       WALBERLA_ASSERT_NOT_NULLPTR( this->block_ );
       velocityField_ = this->block_->template getData< VelocityField_T >(velocityFieldId_ );
    }
 
-   OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) {
+   OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) override {
       WALBERLA_ASSERT_NOT_NULLPTR(velocityField_ );
 
       const real_t dx = blockStorage_->dx(blockStorage_->getLevel(*this->block_));
diff --git a/src/lbm_mesapd_coupling/amr/InfoCollection.h b/src/lbm_mesapd_coupling/amr/InfoCollection.h
index 621ab8f7b2826d8d3a4ce3ebbb5d9818cfc87fe9..8783a945cdd9c3831e2b295c5f977209f2de6111 100644
--- a/src/lbm_mesapd_coupling/amr/InfoCollection.h
+++ b/src/lbm_mesapd_coupling/amr/InfoCollection.h
@@ -115,6 +115,7 @@ void updateAndSyncInfoCollection(BlockForest& bf, const BlockDataID boundaryHand
    }
 }
 
+inline
 void getBlockInfoFromInfoCollection( const PhantomBlock * block, const shared_ptr<InfoCollection>& ic,
                                      BlockInfo & blockInfo )
 {
diff --git a/src/lbm_mesapd_coupling/mapping/ParticleBoundingBox.h b/src/lbm_mesapd_coupling/mapping/ParticleBoundingBox.h
index aa32158a99094b283016cace0a35632aae300dff..7c2f49a3b8ea4808d9ea8306917579c83b0c3d52 100644
--- a/src/lbm_mesapd_coupling/mapping/ParticleBoundingBox.h
+++ b/src/lbm_mesapd_coupling/mapping/ParticleBoundingBox.h
@@ -36,9 +36,9 @@ namespace lbm_mesapd_coupling {
  * Obtain a block-local cell bounding box from a given AABB (e.g. the particle's AABB)
  * If the given AABB is (partly) infinite, AABBIsInfinite should be set to true (e.g. for infinite particles)
  */
-CellInterval getCellBBFromAABB( const math::AABB & aabb, bool AABBIsInfinite,
-                                const IBlock & block, StructuredBlockStorage & blockStorage,
-                                const uint_t numberOfGhostLayersToInclude)
+inline CellInterval getCellBBFromAABB( const math::AABB & aabb, bool AABBIsInfinite,
+                                       const IBlock & block, StructuredBlockStorage & blockStorage,
+                                       const uint_t numberOfGhostLayersToInclude)
 {
 
    CellInterval cellBB;
diff --git a/src/lbm_mesapd_coupling/overlapping/shapes/BoxWithOverlap.h b/src/lbm_mesapd_coupling/overlapping/shapes/BoxWithOverlap.h
index 6bf00ca38a31365ee68b6b440977d8062ca62cee..8ad69fceef274eb16a6489b6ef8d0b0bb4de4366 100644
--- a/src/lbm_mesapd_coupling/overlapping/shapes/BoxWithOverlap.h
+++ b/src/lbm_mesapd_coupling/overlapping/shapes/BoxWithOverlap.h
@@ -46,7 +46,9 @@ class BoxWithOverlap : public geometry::AbstractBody
       : idx_(idx), ac_(ac), box_(box)
    {}
 
-   bool contains(const Vector3< real_t >& point) const
+   ~BoxWithOverlap() override = default;
+
+   bool contains(const Vector3< real_t >& point) const override
    {
       return mesa_pd::isPointInsideBoxBF(mesa_pd::transformPositionFromWFtoBF(idx_, ac_, point), box_.getEdgeLength());
    }
diff --git a/src/lbm_mesapd_coupling/overlapping/shapes/CylindricalBoundaryWithOverlap.h b/src/lbm_mesapd_coupling/overlapping/shapes/CylindricalBoundaryWithOverlap.h
index 56a14bfecf244b24b65512819e7a60ba9f2ebb1e..f6f5d597c968ce180ced0c0bdfbc3f4924d632cc 100644
--- a/src/lbm_mesapd_coupling/overlapping/shapes/CylindricalBoundaryWithOverlap.h
+++ b/src/lbm_mesapd_coupling/overlapping/shapes/CylindricalBoundaryWithOverlap.h
@@ -47,7 +47,9 @@ class CylindricalBoundaryWithOverlap : public geometry::AbstractBody
       : idx_(idx), ac_(ac), cylindricalBoundary_(cylindricalBoundary)
    {}
 
-   bool contains(const Vector3< real_t >& point) const
+   ~CylindricalBoundaryWithOverlap() override = default;
+
+   bool contains(const Vector3< real_t >& point) const override
    {
       return mesa_pd::isPointInsideCylindricalBoundary(point, ac_->getPosition(idx_), cylindricalBoundary_.getRadius(),
                                                        cylindricalBoundary_.getAxis());
diff --git a/src/lbm_mesapd_coupling/overlapping/shapes/EllipsoidWithOverlap.h b/src/lbm_mesapd_coupling/overlapping/shapes/EllipsoidWithOverlap.h
index 3c8ffe185c6a4a64e7455046a574a12e4dc07f92..295021fe0ee887c9f35204fe91626b2a52bf9e20 100644
--- a/src/lbm_mesapd_coupling/overlapping/shapes/EllipsoidWithOverlap.h
+++ b/src/lbm_mesapd_coupling/overlapping/shapes/EllipsoidWithOverlap.h
@@ -46,7 +46,9 @@ class EllipsoidWithOverlap : public geometry::AbstractBody
       : idx_(idx), ac_(ac), ellipsoid_(ellipsoid)
    {}
 
-   bool contains(const Vector3< real_t >& point) const
+   ~EllipsoidWithOverlap() override = default;
+
+   bool contains(const Vector3< real_t >& point) const override
    {
       return mesa_pd::isPointInsideEllipsoidBF(mesa_pd::transformPositionFromWFtoBF(idx_, ac_, point),
                                                ellipsoid_.getSemiAxes());
diff --git a/src/lbm_mesapd_coupling/overlapping/shapes/HalfSpaceWithOverlap.h b/src/lbm_mesapd_coupling/overlapping/shapes/HalfSpaceWithOverlap.h
index 9f50d6d37e23ad6f0c70113968d17b7cf28aed9d..555e515991ae750252e15f76e03b1f9984a38392 100644
--- a/src/lbm_mesapd_coupling/overlapping/shapes/HalfSpaceWithOverlap.h
+++ b/src/lbm_mesapd_coupling/overlapping/shapes/HalfSpaceWithOverlap.h
@@ -46,7 +46,9 @@ class HalfSpaceWithOverlap : public geometry::AbstractBody
       : idx_(idx), ac_(ac), halfSpace_(halfSpace)
    {}
 
-   bool contains(const Vector3< real_t >& point) const
+   ~HalfSpaceWithOverlap() override = default;
+
+   bool contains(const Vector3< real_t >& point) const override
    {
       return mesa_pd::isPointInsideHalfSpace(point, ac_->getPosition(idx_), halfSpace_.getNormal());
    }
diff --git a/src/lbm_mesapd_coupling/overlapping/shapes/SphereWithOverlap.h b/src/lbm_mesapd_coupling/overlapping/shapes/SphereWithOverlap.h
index 1db48699c5be30638e8c732ef71826cd67a6fa0b..ad80bdc009acfd4d61699deb4fe6c5fc339d23a5 100644
--- a/src/lbm_mesapd_coupling/overlapping/shapes/SphereWithOverlap.h
+++ b/src/lbm_mesapd_coupling/overlapping/shapes/SphereWithOverlap.h
@@ -45,7 +45,9 @@ class SphereWithOverlap : public geometry::AbstractBody
       : idx_(idx), ac_(ac), sphere_(sphere)
    {}
 
-   bool contains(const Vector3< real_t >& point) const
+   ~SphereWithOverlap() override = default;
+
+   bool contains(const Vector3< real_t >& point) const override
    {
       return mesa_pd::isPointInsideSphere(point, ac_->getPosition(idx_), sphere_.getRadius());
    }
diff --git a/src/lbm_mesapd_coupling/utility/OmegaBulkAdaption.h b/src/lbm_mesapd_coupling/utility/OmegaBulkAdaption.h
index 226c03c2f16a2a8ba1b399545a5f38057ed29340..f8a60c3a943e3e046d45038c8d86513f5c088c55 100644
--- a/src/lbm_mesapd_coupling/utility/OmegaBulkAdaption.h
+++ b/src/lbm_mesapd_coupling/utility/OmegaBulkAdaption.h
@@ -29,20 +29,20 @@ namespace lbm_mesapd_coupling {
 
 // utility functions
 
-real_t bulkViscosityFromOmegaBulk(real_t omegaBulk)
+inline real_t bulkViscosityFromOmegaBulk(real_t omegaBulk)
 {
    return real_t(2) / real_t(9) * ( real_t(1) / omegaBulk - real_t(0.5) );
 }
 
 
-real_t omegaBulkFromBulkViscosity(real_t bulkViscosity)
+inline real_t omegaBulkFromBulkViscosity(real_t bulkViscosity)
 {
    return real_t(2) / ( real_t(9) * bulkViscosity + real_t(1) );
 }
 
 // see Khirevich et al. - Coarse- and fine-grid numerical behavior of MRT/TRT lattice-Boltzmann schemes in regular and random sphere packings
 // LambdaBulk is the "magic parameter" here, i.e. the ratio between Lambda_e and Lambda_nu, Eq. 19
-real_t omegaBulkFromOmega(real_t omega, real_t LambdaBulk = real_t(1))
+inline real_t omegaBulkFromOmega(real_t omega, real_t LambdaBulk = real_t(1))
 {
    return real_t(1) / (LambdaBulk * ( real_t(1) / omega - real_t(1)/ real_t(2) ) + real_t(1)/ real_t(2) );
 }
diff --git a/src/mesa_pd/collision_detection/EPA.cpp b/src/mesa_pd/collision_detection/EPA.cpp
index 70c39daeea9ff9c2686df4a9043255c6be127cea..240b3e93857a20e9bea653a8f3605d14bbf7b3a2 100644
--- a/src/mesa_pd/collision_detection/EPA.cpp
+++ b/src/mesa_pd/collision_detection/EPA.cpp
@@ -142,7 +142,7 @@ void EPA::EPA_Triangle::silhouette( size_t index, const Vec3& w,
    if (!obsolete_) {
       real_t test = (closest_ * w);
       if (test < sqrDist_) {
-         edgeBuffer.push_back(EPA_Edge(this, index));
+         edgeBuffer.emplace_back(this, index);
       }
       else {
          obsolete_ = true; // Facet is visible
@@ -271,7 +271,7 @@ bool EPA::doEPA( Support &geom1,
 
    for(EPA_EntryBuffer::iterator it=entryBuffer.begin(); it != entryBuffer.end(); ++it) {
       if(it->isClosestInternal()) {
-         entryHeap.push_back(&(*it));
+         entryHeap.emplace_back(&(*it));
       }
    }
 
@@ -402,7 +402,7 @@ bool EPA::doEPA( Support &geom1,
          }
 
          EPA_EdgeBuffer::const_iterator it = edgeBuffer.begin();
-         entryBuffer.push_back(EPA_Triangle(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume));
+         entryBuffer.emplace_back(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume);
 
          EPA_Triangle* firstTriangle = &(entryBuffer.back());
          //if it is expanding candidate add to heap
@@ -416,7 +416,7 @@ bool EPA::doEPA( Support &geom1,
                && firstTriangle->getSqrDist() > lowerBoundSqr
                && firstTriangle->getSqrDist() < upperBoundSqr)
          {
-            entryHeap.push_back(firstTriangle);
+            entryHeap.emplace_back(firstTriangle);
             std::push_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
          }
 
@@ -431,7 +431,7 @@ bool EPA::doEPA( Support &geom1,
                break;
             }
 
-            entryBuffer.push_back(EPA_Triangle(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume));
+            entryBuffer.emplace_back(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume);
             EPA_Triangle* newTriangle = &(entryBuffer.back());
 
             //std::cerr << "Considering Triangle (" << newTriangle->getSqrDist() << ") {"  << (*newTriangle)[0] <<  "," << (*newTriangle)[1] <<  ","<< (*newTriangle)[2] << "} ("<< epaVolume[(*newTriangle)[0]] * newTriangle->getNormal() << ")" << std::endl;
@@ -446,7 +446,7 @@ bool EPA::doEPA( Support &geom1,
                   &&  newTriangle->getSqrDist() > lowerBoundSqr
                   &&  newTriangle->getSqrDist() < upperBoundSqr)
             {
-               entryHeap.push_back(newTriangle);
+               entryHeap.emplace_back(newTriangle);
                std::push_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
             }
 
@@ -572,11 +572,11 @@ inline void EPA::createInitialSimplex( size_t numPoints,
       //check for containment inside
       if(originInTetrahedron(epaVolume[0], epaVolume[2], epaVolume[3], epaVolume[4]) || originInTetrahedron(epaVolume[1], epaVolume[2], epaVolume[3], epaVolume[4]) ){
          //insert triangle 1
-         entryBuffer.push_back(EPA_Triangle(1, 2, 3, epaVolume)); //[0] up->ccw1->ccw2
+         entryBuffer.emplace_back(1, 2, 3, epaVolume); //[0] up->ccw1->ccw2
          //insert triangle 2
-         entryBuffer.push_back(EPA_Triangle(1, 3, 4, epaVolume)); //[1] up->ccw2->ccw3
+         entryBuffer.emplace_back(1, 3, 4, epaVolume); //[1] up->ccw2->ccw3
          //insert triangle 3
-         entryBuffer.push_back(EPA_Triangle(1, 4, 2, epaVolume)); //[2] up->ccw3->ccw1
+         entryBuffer.emplace_back(1, 4, 2, epaVolume); //[2] up->ccw3->ccw1
 
          //link these 3 triangles
          entryBuffer[0].link(2, &(entryBuffer[1]), 0); //edge up->ccw1
@@ -585,11 +585,11 @@ inline void EPA::createInitialSimplex( size_t numPoints,
 
 
          //insert triangle 4
-         entryBuffer.push_back(EPA_Triangle(0, 2, 4, epaVolume)); //[3] down->ccw1->ccw3
+         entryBuffer.emplace_back(0, 2, 4, epaVolume); //[3] down->ccw1->ccw3
          //insert triangle 5
-         entryBuffer.push_back(EPA_Triangle(0, 4, 3, epaVolume)); //[4] down->ccw3->ccw2
+         entryBuffer.emplace_back(0, 4, 3, epaVolume); //[4] down->ccw3->ccw2
          //insert triangle 6
-         entryBuffer.push_back(EPA_Triangle(0, 3, 2, epaVolume)); //[5] down->ccw2->ccw1
+         entryBuffer.emplace_back(0, 3, 2, epaVolume); //[5] down->ccw2->ccw1
 
          //link these 3 triangles
          entryBuffer[3].link(2, &(entryBuffer[4]), 0); //edge down->ccw3
@@ -643,11 +643,11 @@ inline void EPA::createInitialSimplex( size_t numPoints,
       else {
          //Build the hexahedron as it is convex
          //insert triangle 1
-         entryBuffer.push_back(EPA_Triangle(3, 2, 1, epaVolume)); //[0] support1->A->B
+         entryBuffer.emplace_back(3, 2, 1, epaVolume); //[0] support1->A->B
          //insert triangle 2
-         entryBuffer.push_back(EPA_Triangle(3, 1, 0, epaVolume)); //[1] support1->B->C
+         entryBuffer.emplace_back(3, 1, 0, epaVolume); //[1] support1->B->C
          //insert triangle 3
-         entryBuffer.push_back(EPA_Triangle(3, 0, 2, epaVolume)); //[2] support1->C->A
+         entryBuffer.emplace_back(3, 0, 2, epaVolume); //[2] support1->C->A
 
          //link these 3 triangles
          entryBuffer[0].link(2, &(entryBuffer[1]), 0); //edge support1->A
@@ -656,11 +656,11 @@ inline void EPA::createInitialSimplex( size_t numPoints,
 
 
          //insert triangle 4
-         entryBuffer.push_back(EPA_Triangle(4, 2, 0, epaVolume)); //[3] support2->A->C
+         entryBuffer.emplace_back(4, 2, 0, epaVolume); //[3] support2->A->C
          //insert triangle 5
-         entryBuffer.push_back(EPA_Triangle(4, 0, 1, epaVolume)); //[4] support2->C->B
+         entryBuffer.emplace_back(4, 0, 1, epaVolume); //[4] support2->C->B
          //insert triangle 6
-         entryBuffer.push_back(EPA_Triangle(4, 1, 2, epaVolume)); //[5] support2->B->A
+         entryBuffer.emplace_back(4, 1, 2, epaVolume); //[5] support2->B->A
 
          //link these 3 triangles
          entryBuffer[3].link(2, &(entryBuffer[4]), 0); //edge support2->C
@@ -768,13 +768,13 @@ inline void EPA::createInitialTetrahedron( size_t top,
                                            EPA_EntryBuffer& entryBuffer )
 {
    //insert triangle 1
-   entryBuffer.push_back(EPA_Triangle(top, frontLeft, frontRight, epaVolume)); //[0] vorne
+   entryBuffer.emplace_back(top, frontLeft, frontRight, epaVolume); //[0] vorne
    //insert triangle 2
-   entryBuffer.push_back(EPA_Triangle(top, frontRight, back, epaVolume)); //[1] rechts hinten
+   entryBuffer.emplace_back(top, frontRight, back, epaVolume); //[1] rechts hinten
    //insert triangle 3
-   entryBuffer.push_back(EPA_Triangle(top, back, frontLeft, epaVolume)); //[2] links hinten
+   entryBuffer.emplace_back(top, back, frontLeft, epaVolume); //[2] links hinten
    //insert triangle 4
-   entryBuffer.push_back(EPA_Triangle(back, frontRight, frontLeft, epaVolume)); //[3] unten
+   entryBuffer.emplace_back(back, frontRight, frontLeft, epaVolume); //[3] unten
 
    //make links between the triangles
    entryBuffer[0].link(0, &(entryBuffer[2]), 2); //Kante vorne links
diff --git a/src/mesa_pd/collision_detection/GeneralContactDetection.h b/src/mesa_pd/collision_detection/GeneralContactDetection.h
index 9564916c02a97432793a09f5805bf9f9072f73ac..c9101312667fde8afaa7761a05201dde518fec97 100644
--- a/src/mesa_pd/collision_detection/GeneralContactDetection.h
+++ b/src/mesa_pd/collision_detection/GeneralContactDetection.h
@@ -191,7 +191,7 @@ bool GeneralContactDetection::operator()(const size_t idx1,
    return operator()(idx2, idx1, geo2, geo1, ac);
 }
 
-bool GeneralContactDetection::collideGJKEPA(Support& geom0, Support& geom1)
+inline bool GeneralContactDetection::collideGJKEPA(Support& geom0, Support& geom1)
 {
    real_t margin = real_t(1e-4);
    GJK gjk;
diff --git a/src/mesa_pd/common/AABBConversion.h b/src/mesa_pd/common/AABBConversion.h
index c105d1ed2b336b91c671e203bba786601b613ffd..be579b9701d74a4879046327f331c0c5131d3b7d 100644
--- a/src/mesa_pd/common/AABBConversion.h
+++ b/src/mesa_pd/common/AABBConversion.h
@@ -30,7 +30,7 @@
 namespace walberla {
 namespace mesa_pd {
 
-math::AABB getAABBFromInteractionRadius(const Vector3<real_t> & pos, const real_t interactionRadius )
+inline math::AABB getAABBFromInteractionRadius(const Vector3<real_t> & pos, const real_t interactionRadius )
 {
    WALBERLA_ASSERT_GREATER(interactionRadius, 0_r, "Did you forget to set the interaction radius?");
    return math::AABB( pos[0]-interactionRadius, pos[1]-interactionRadius, pos[2]-interactionRadius,
diff --git a/src/mesa_pd/common/Contains.h b/src/mesa_pd/common/Contains.h
index 00e74bb3990d29436d1a4507796d315c5d050ea7..8c707388bda2b541dee4eecab28518fac685d8a5 100644
--- a/src/mesa_pd/common/Contains.h
+++ b/src/mesa_pd/common/Contains.h
@@ -42,18 +42,21 @@ namespace mesa_pd {
  * or in body frame coordinates (BF) which requires the point to be first transformed
  */
 
+inline
 bool isPointInsideSphere(const Vec3& point,
                          const Vec3& spherePosition, const real_t sphereRadius )
 {
    return !((point - spherePosition).sqrLength() > sphereRadius * sphereRadius);
 }
 
+inline
 bool isPointInsideHalfSpace(const Vec3& point,
                             const Vec3& halfSpacePosition, const Vec3& halfSpaceNormal )
 {
    return !((point - halfSpacePosition) * halfSpaceNormal > real_t(0));
 }
 
+inline
 bool isPointInsideBoxBF(const Vec3& pointBF,
                         const Vec3& edgeLengths )
 {
@@ -62,6 +65,7 @@ bool isPointInsideBoxBF(const Vec3& pointBF,
           std::fabs(pointBF[2]) <= real_t(0.5)*edgeLengths[2];
 }
 
+inline
 bool isPointInsideEllipsoidBF(const Vec3& pointBF,
                               const Vec3& semiAxes )
 {
@@ -69,6 +73,7 @@ bool isPointInsideEllipsoidBF(const Vec3& pointBF,
             + (pointBF[2] * pointBF[2])/(semiAxes[2] * semiAxes[2]) <= 1_r );
 }
 
+inline
 bool isPointInsideCylindricalBoundary(const Vec3& point,
                                       const Vec3& cylindricalBoundaryPosition, const real_t radius, const Vec3& axis  )
 {
@@ -77,6 +82,7 @@ bool isPointInsideCylindricalBoundary(const Vec3& point,
 }
 
 #ifdef WALBERLA_MESAPD_CONVEX_POLYHEDRON_AVAILABLE
+inline
 bool isPointInsideConvexPolyhedronBF(const Vec3& point, const mesh::TriangleMesh& mesh)
 {
    WALBERLA_ASSERT(mesh.has_face_normals(), "Provided mesh has no face normals! E.g., call `mesh.request_face_normals(); mesh.update_face_normals();` to add them.")
diff --git a/src/mesa_pd/common/RayParticleIntersection.h b/src/mesa_pd/common/RayParticleIntersection.h
index b62306aa5dd6014d301ddbd6943a8a0f45b700b9..79c7910a6a3aae6108383a8b8e7b0729dd228d20 100644
--- a/src/mesa_pd/common/RayParticleIntersection.h
+++ b/src/mesa_pd/common/RayParticleIntersection.h
@@ -38,6 +38,7 @@ namespace mesa_pd {
  * or in body frame coordinates (BF) which requires the point to be first transformed
  */
 
+inline
 real_t raySphereIntersectionRatio( const Vec3& rayOrigin, const Vec3& rayDirection,
                                    const Vec3& spherePosition, const real_t sphereRadius )
 {
@@ -62,6 +63,7 @@ real_t raySphereIntersectionRatio( const Vec3& rayOrigin, const Vec3& rayDirecti
    return delta;
 }
 
+inline
 real_t rayHalfSpaceIntersectionRatio( const Vec3& rayOrigin, const Vec3& rayDirection,
                                       const Vec3& halfSpacePosition, const Vec3& halfSpaceNormal)
 {
@@ -82,6 +84,7 @@ real_t rayHalfSpaceIntersectionRatio( const Vec3& rayOrigin, const Vec3& rayDire
    return delta;
 }
 
+inline
 real_t rayEllipsoidIntersectionRatioBF( const Vec3& rayOriginBF, const Vec3& rayDirectionBF,
                                         const Vec3& ellipsoidSemiAxes)
 {
diff --git a/src/mesa_pd/data/HashGrids.h b/src/mesa_pd/data/HashGrids.h
index 83c210b6534a5a1b0fba9675a1585d29f8522486..d847aef68b72f1aec5c0a9d6584b5f3945fa0000 100644
--- a/src/mesa_pd/data/HashGrids.h
+++ b/src/mesa_pd/data/HashGrids.h
@@ -351,7 +351,7 @@ private:
 
 // HashGrids::HashGrid member function implementations
 
-HashGrids::HashGrid::HashGrid( real_t cellSpan )
+inline HashGrids::HashGrid::HashGrid( real_t cellSpan )
 {
    // Initialization of all member variables and ...
    xCellCount_   = math::uintIsPowerOfTwo( xCellCount ) ? xCellCount : 16;
@@ -386,7 +386,7 @@ HashGrids::HashGrid::HashGrid( real_t cellSpan )
    particleCount_ = 0;
 }
 
-HashGrids::HashGrid::~HashGrid()
+inline HashGrids::HashGrid::~HashGrid()
 {
    clear();
 
@@ -396,7 +396,7 @@ HashGrids::HashGrid::~HashGrid()
    delete[] cell_;
 }
 
-void HashGrids::HashGrid::clear()
+inline void HashGrids::HashGrid::clear()
 {
    for( auto cellIt = occupiedCells_.begin(); cellIt < occupiedCells_.end(); ++cellIt ) {
       delete (*cellIt)->particles_;
@@ -412,7 +412,7 @@ void HashGrids::HashGrid::clear()
  * This function is used to initialize the offset arrays of all grid cells. The offsets are required
  * for ensuring fast direct access to all directly adjacent cells for each cell in the hash grid.
  */
-void HashGrids::HashGrid::initializeNeighborOffsets()
+inline void HashGrids::HashGrid::initializeNeighborOffsets()
 {
    offset_t xc   = static_cast<offset_t>( xCellCount_ );
    offset_t yc   = static_cast<offset_t>( yCellCount_ );
@@ -516,7 +516,7 @@ void HashGrids::HashGrid::addParticle( size_t p_idx, Accessor& ac )
 //*************************************************************************************************
 /*!\brief Adds a particle to a specific cell in this hash grid.
  */
-void HashGrids::HashGrid::addParticleToCell( size_t p_idx, Cell* cell )
+inline void HashGrids::HashGrid::addParticleToCell( size_t p_idx, Cell* cell )
 {
    // If this cell is already occupied by other particles, which means the pointer to the particle
    // container holds a valid address and thus the container itself is properly initialized, then
@@ -564,7 +564,7 @@ size_t HashGrids::HashGrid::hashOfParticle( size_t p_idx, Accessor& ac ) const
  * Note that the modulo calculations are replaced with fast bitwise AND operations - hence, the
  * spatial dimensions of the hash grid must be restricted to powers of two!
  */
-size_t HashGrids::HashGrid::hashPoint(real_t x, real_t y, real_t z) const {
+inline size_t HashGrids::HashGrid::hashPoint(real_t x, real_t y, real_t z) const {
    size_t xHash;
    size_t yHash;
    size_t zHash;
@@ -773,7 +773,7 @@ void HashGrids::HashGrid::checkAgainstVectorEachParticlePairHalf( const Particle
 //*************************************************************************************************
 
 // clear all particles and grids
-void HashGrids::clearAll()
+inline void HashGrids::clearAll()
 {
    gridList_.clear();
    infiniteParticles_.clear();
@@ -781,7 +781,7 @@ void HashGrids::clearAll()
 
 // clear only all particles from the hash grids, but maintain the overall grid hierarchy
 // useful for "updating" the data structure in each time step, but also prevents clean-up of unnecessary grids
-void HashGrids::clear()
+inline void HashGrids::clear()
 {
    for( auto gridIt = gridList_.begin(); gridIt != gridList_.end(); ++gridIt ) {
       (*gridIt)->clear();
@@ -849,7 +849,7 @@ void HashGrids::operator()(const size_t p_idx, Accessor& ac)
    }
 }
 
-void HashGrids::addInfiniteParticle(size_t p_idx)
+inline void HashGrids::addInfiniteParticle(size_t p_idx)
 {
    infiniteParticles_.push_back(p_idx);
 }
diff --git a/src/mesa_pd/data/LinkedCells.h b/src/mesa_pd/data/LinkedCells.h
index 9ba699fd0da4a36afc1d76472b1c37c1917a3bde..26ac5c7972edca90e5c5e4833ae42d7d8ff152a6 100644
--- a/src/mesa_pd/data/LinkedCells.h
+++ b/src/mesa_pd/data/LinkedCells.h
@@ -171,7 +171,7 @@ LinkedCells::LinkedCells(const math::AABB& domain, const Vec3& cellDiameter)
    std::fill(cells_.begin(), cells_.end(), -1);
 }
 
-void LinkedCells::clear()
+inline void LinkedCells::clear()
 {
    const uint64_t cellsSize = cells_.size();
    //clear existing linked cells
diff --git a/src/mesa_pd/data/SparseLinkedCells.h b/src/mesa_pd/data/SparseLinkedCells.h
index 2c184de476a67c8a02eaf19aae72540d625e2bd9..3e98b174c3a8c2a0c2985891259e0463f902c198 100644
--- a/src/mesa_pd/data/SparseLinkedCells.h
+++ b/src/mesa_pd/data/SparseLinkedCells.h
@@ -187,7 +187,7 @@ SparseLinkedCells::SparseLinkedCells(const math::AABB& domain, const Vec3& cellD
    std::fill(cells_.begin(), cells_.end(), -1);
 }
 
-void SparseLinkedCells::clear()
+inline void SparseLinkedCells::clear()
 {
    for (const auto v : nonEmptyCells_)
    {
diff --git a/src/mesa_pd/kernel/ForceLJ.h b/src/mesa_pd/kernel/ForceLJ.h
index 1affbc8f82ca99fa1fae40e2fb3fef1f22cbdd58..14d0877728fc578e67a7021639c2e404827cd682 100644
--- a/src/mesa_pd/kernel/ForceLJ.h
+++ b/src/mesa_pd/kernel/ForceLJ.h
@@ -80,7 +80,7 @@ private:
    std::vector<real_t> sigma {};
 };
 
-ForceLJ::ForceLJ(const uint_t numParticleTypes)
+inline ForceLJ::ForceLJ(const uint_t numParticleTypes)
 {
    numParticleTypes_ = numParticleTypes;
    
diff --git a/src/mesa_pd/kernel/HeatConduction.h b/src/mesa_pd/kernel/HeatConduction.h
index e41d117047bce400a4e9d6601c70aa1d46fe7f69..efedff4efaf8b6bba407a141f13155ae4e294c9d 100644
--- a/src/mesa_pd/kernel/HeatConduction.h
+++ b/src/mesa_pd/kernel/HeatConduction.h
@@ -81,7 +81,7 @@ private:
    std::vector<real_t> conductance_ {};
 };
 
-HeatConduction::HeatConduction(const uint_t numParticleTypes)
+inline HeatConduction::HeatConduction(const uint_t numParticleTypes)
 {
    numParticleTypes_ = numParticleTypes;
    
diff --git a/src/mesa_pd/kernel/LinearSpringDashpot.h b/src/mesa_pd/kernel/LinearSpringDashpot.h
index c2d41674b023e11f71316897f9b97905bd21f593..5907132172d45aa0a9f58685fde5c1ba9aebd124 100644
--- a/src/mesa_pd/kernel/LinearSpringDashpot.h
+++ b/src/mesa_pd/kernel/LinearSpringDashpot.h
@@ -133,7 +133,7 @@ private:
    std::vector<real_t> frictionCoefficientDynamic_ {};
 };
 
-LinearSpringDashpot::LinearSpringDashpot(const uint_t numParticleTypes)
+inline LinearSpringDashpot::LinearSpringDashpot(const uint_t numParticleTypes)
 {
    numParticleTypes_ = numParticleTypes;
    
diff --git a/src/mesa_pd/kernel/NonLinearSpringDashpot.h b/src/mesa_pd/kernel/NonLinearSpringDashpot.h
index b5d732c6d2b27ea535c62404baa3b75d81ace8a6..fc1e0515be1d3f7c90dbb6f30744ab1f729a75e5 100644
--- a/src/mesa_pd/kernel/NonLinearSpringDashpot.h
+++ b/src/mesa_pd/kernel/NonLinearSpringDashpot.h
@@ -120,7 +120,7 @@ private:
    std::vector<real_t> frictionCoefficientDynamic_ {};
 };
 
-NonLinearSpringDashpot::NonLinearSpringDashpot(const uint_t numParticleTypes, const real_t collisionTime)
+inline NonLinearSpringDashpot::NonLinearSpringDashpot(const uint_t numParticleTypes, const real_t collisionTime)
 {
    numParticleTypes_ = numParticleTypes;
    
diff --git a/src/mesa_pd/kernel/SpringDashpot.h b/src/mesa_pd/kernel/SpringDashpot.h
index 7c59af5dcd977c56ff937a5f0aeb46e5f7f557ba..eecd2ee0f302db8efddad1986b35a768b40db391 100644
--- a/src/mesa_pd/kernel/SpringDashpot.h
+++ b/src/mesa_pd/kernel/SpringDashpot.h
@@ -132,7 +132,7 @@ private:
    std::vector<real_t> friction_ {};
 };
 
-SpringDashpot::SpringDashpot(const uint_t numParticleTypes)
+inline SpringDashpot::SpringDashpot(const uint_t numParticleTypes)
 {
    numParticleTypes_ = numParticleTypes;
    
diff --git a/src/mesa_pd/kernel/SpringDashpotSpring.h b/src/mesa_pd/kernel/SpringDashpotSpring.h
index 07eed81524cb9712b3ee027886947b28c973e0ce..ece97ace1ab459e82a21050e7a356df402c424d0 100644
--- a/src/mesa_pd/kernel/SpringDashpotSpring.h
+++ b/src/mesa_pd/kernel/SpringDashpotSpring.h
@@ -116,7 +116,7 @@ private:
    std::vector<real_t> coefficientOfFriction_ {};
 };
 
-SpringDashpotSpring::SpringDashpotSpring(const uint_t numParticleTypes)
+inline SpringDashpotSpring::SpringDashpotSpring(const uint_t numParticleTypes)
 {
    numParticleTypes_ = numParticleTypes;
    
diff --git a/src/mesa_pd/kernel/TemperatureIntegration.h b/src/mesa_pd/kernel/TemperatureIntegration.h
index 8f8a771cec0217ab8b4d096637e50c850cb8ba36..905973f8da70828b7e68de953c759ad8df4f21cc 100644
--- a/src/mesa_pd/kernel/TemperatureIntegration.h
+++ b/src/mesa_pd/kernel/TemperatureIntegration.h
@@ -81,7 +81,7 @@ private:
    std::vector<real_t> invSpecificHeat_ {};
 };
 
-TemperatureIntegration::TemperatureIntegration(const real_t dt, const uint_t numParticleTypes)
+inline TemperatureIntegration::TemperatureIntegration(const real_t dt, const uint_t numParticleTypes)
    : dt_(dt)
 {
    numParticleTypes_ = numParticleTypes;
diff --git a/src/mesa_pd/kernel/cnt/IsotropicVDWContact.h b/src/mesa_pd/kernel/cnt/IsotropicVDWContact.h
index a92ecda09637c90da12722611665836875016328..c3ffbfffe80be84e453bd5c51356a2d222718b31 100644
--- a/src/mesa_pd/kernel/cnt/IsotropicVDWContact.h
+++ b/src/mesa_pd/kernel/cnt/IsotropicVDWContact.h
@@ -95,7 +95,7 @@ void IsotropicVDWContact::operator()(const size_t p_idx1,
    addForceAtomic(p_idx2, ac, -force);
 }
 
-real_t IsotropicVDWContact::equilibriumDistance()
+inline real_t IsotropicVDWContact::equilibriumDistance()
 {
    return r * ( std::pow( (alpha*A)/(beta*B), 1_r/(alpha-beta)) + 2_r);
 }
diff --git a/src/mesa_pd/mpi/ReduceContactHistory.h b/src/mesa_pd/mpi/ReduceContactHistory.h
index efd4e9bd85dfe65d2d38c9be5bb9fac4250ed652..a741c79526874f30fda0d5b90cc5b4555ed77e49 100644
--- a/src/mesa_pd/mpi/ReduceContactHistory.h
+++ b/src/mesa_pd/mpi/ReduceContactHistory.h
@@ -85,7 +85,7 @@ private:
    int numProcesses_ = walberla::mpi::MPIManager::instance()->numProcesses();
 };
 
-void ReduceContactHistory::operator()(data::ParticleStorage& ps) const
+inline void ReduceContactHistory::operator()(data::ParticleStorage& ps) const
 {
    //no need to reduce if run with only one process
    if (numProcesses_ != 1)
diff --git a/src/mesa_pd/mpi/notifications/ContactHistoryNotification.h b/src/mesa_pd/mpi/notifications/ContactHistoryNotification.h
index 3785f0ffbbb0e92e184c9635d1626e95ec9ef388..7d46c26de144724624bb164412695335436d4f82 100644
--- a/src/mesa_pd/mpi/notifications/ContactHistoryNotification.h
+++ b/src/mesa_pd/mpi/notifications/ContactHistoryNotification.h
@@ -58,12 +58,12 @@ public:
 };
 
 template <>
-void reset<ContactHistoryNotification>(data::Particle& p)
+inline void reset<ContactHistoryNotification>(data::Particle& p)
 {
    p.setNewContactHistory(std::map<walberla::id_t, walberla::mesa_pd::data::ContactHistory>());
 }
 
-void reduce(data::Particle&& p, const ContactHistoryNotification::Parameters& objparam)
+inline void reduce(data::Particle&& p, const ContactHistoryNotification::Parameters& objparam)
 {
    auto& ch = p.getNewContactHistoryRef();
    for (auto& entry : objparam.contactHistory_)
diff --git a/src/mesa_pd/mpi/notifications/ForceTorqueNotification.h b/src/mesa_pd/mpi/notifications/ForceTorqueNotification.h
index 5c8ad6f79507d114423115d9e3082808a166e3e1..54fe3902675020ab1fd9d5f2a61e3fe3b40bbc03 100644
--- a/src/mesa_pd/mpi/notifications/ForceTorqueNotification.h
+++ b/src/mesa_pd/mpi/notifications/ForceTorqueNotification.h
@@ -57,19 +57,19 @@ public:
 };
 
 template <>
-void reset<ForceTorqueNotification>(data::Particle& p)
+inline void reset<ForceTorqueNotification>(data::Particle& p)
 {
    p.setForce( Vec3(real_t(0)) );
    p.setTorque( Vec3(real_t(0)) );
 }
 
-void reduce(data::Particle&& p, const ForceTorqueNotification::Parameters& objparam)
+inline void reduce(data::Particle&& p, const ForceTorqueNotification::Parameters& objparam)
 {
    p.getForceRef() += objparam.force_;
    p.getTorqueRef() += objparam.torque_;
 }
 
-void update(data::Particle&& p, const ForceTorqueNotification::Parameters& objparam)
+inline void update(data::Particle&& p, const ForceTorqueNotification::Parameters& objparam)
 {
    p.setForce( objparam.force_ );
    p.setTorque( objparam.torque_ );
diff --git a/src/mesa_pd/mpi/notifications/HeatFluxNotification.h b/src/mesa_pd/mpi/notifications/HeatFluxNotification.h
index 6b580a50083295eb7c40646ef95dbc5af94c1d34..53ebde522e2a70606e0af6e1471914ecac692426 100644
--- a/src/mesa_pd/mpi/notifications/HeatFluxNotification.h
+++ b/src/mesa_pd/mpi/notifications/HeatFluxNotification.h
@@ -56,17 +56,17 @@ public:
 };
 
 template <>
-void reset<HeatFluxNotification>(data::Particle& p)
+inline void reset<HeatFluxNotification>(data::Particle& p)
 {
    p.setHeatFlux( real_t(0) );
 }
 
-void reduce(data::Particle&& p, const HeatFluxNotification::Parameters& objparam)
+inline void reduce(data::Particle&& p, const HeatFluxNotification::Parameters& objparam)
 {
    p.getHeatFluxRef() += objparam.heatFlux_;
 }
 
-void update(data::Particle&& p, const HeatFluxNotification::Parameters& objparam)
+inline void update(data::Particle&& p, const HeatFluxNotification::Parameters& objparam)
 {
    p.setHeatFlux( objparam.heatFlux_ );
 }
diff --git a/src/mesa_pd/mpi/notifications/HydrodynamicForceTorqueNotification.h b/src/mesa_pd/mpi/notifications/HydrodynamicForceTorqueNotification.h
index ce874188127bd4cfa0c11e6d7087ce7e1ef61bd5..a8f1c3376f9a5af5ce4cee6b45d075ad78846553 100644
--- a/src/mesa_pd/mpi/notifications/HydrodynamicForceTorqueNotification.h
+++ b/src/mesa_pd/mpi/notifications/HydrodynamicForceTorqueNotification.h
@@ -57,19 +57,19 @@ public:
 };
 
 template <>
-void reset<HydrodynamicForceTorqueNotification>(data::Particle& p)
+inline void reset<HydrodynamicForceTorqueNotification>(data::Particle& p)
 {
    p.setHydrodynamicForce( Vec3(real_t(0)) );
    p.setHydrodynamicTorque( Vec3(real_t(0)) );
 }
 
-void reduce(data::Particle&& p, const HydrodynamicForceTorqueNotification::Parameters& objparam)
+inline void reduce(data::Particle&& p, const HydrodynamicForceTorqueNotification::Parameters& objparam)
 {
    p.getHydrodynamicForceRef() += objparam.hydrodynamicForce_;
    p.getHydrodynamicTorqueRef() += objparam.hydrodynamicTorque_;
 }
 
-void update(data::Particle&& p, const HydrodynamicForceTorqueNotification::Parameters& objparam)
+inline void update(data::Particle&& p, const HydrodynamicForceTorqueNotification::Parameters& objparam)
 {
    p.setHydrodynamicForce( objparam.hydrodynamicForce_ );
    p.setHydrodynamicTorque( objparam.hydrodynamicTorque_ );
diff --git a/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h b/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h
index 7f9347f918ca77ea079c12988e8d3d03f3254fea..6d4a88399d6655a361b334f5599d4effae83df27 100644
--- a/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h
+++ b/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h
@@ -61,14 +61,14 @@ public:
 
 
 // Reduce method for reduction (add up the velocity corrections)
-void reduce(data::Particle&& p, const VelocityCorrectionNotification::Parameters& objparam)
+inline void reduce(data::Particle&& p, const VelocityCorrectionNotification::Parameters& objparam)
 {
    p.getDvRef() += objparam.dv_;
    p.getDwRef() += objparam.dw_;
 }
 
 template<>
-void reset<VelocityCorrectionNotification>(data::Particle& p )
+inline void reset<VelocityCorrectionNotification>(data::Particle& p )
 {
    p.setDv( Vec3(real_t(0)) );
    p.setDw( Vec3(real_t(0)) );
diff --git a/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h b/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h
index f526d99c8f21c50f7b2b7ac224498d3f58d19125..7c2ef66d63079342f4e3c050cf39d1b4c5a18a8a 100644
--- a/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h
+++ b/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h
@@ -66,7 +66,7 @@ public:
 real_t VelocityUpdateNotification::Parameters::relaxationParam = real_t(0.8);
 
 // Update method for broadcast
-void update(data::Particle&& p, const VelocityUpdateNotification::Parameters& objparam) {
+inline void update(data::Particle&& p, const VelocityUpdateNotification::Parameters& objparam) {
    // Reset the velocity corrections dv/dw of ghost particle
    p.getDvRef() = Vec3();
    p.getDwRef() = Vec3();
@@ -75,7 +75,7 @@ void update(data::Particle&& p, const VelocityUpdateNotification::Parameters& ob
 }
 
 template<>
-void reset<VelocityUpdateNotification>(data::Particle& p )
+inline void reset<VelocityUpdateNotification>(data::Particle& p )
 {
    p.setDv( Vec3(real_t(0)) );
    p.setDw( Vec3(real_t(0)) );
diff --git a/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/FaceDataSource.h b/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/FaceDataSource.h
index 4ab4de70f5f4fe4650165e6cb3f6d386d91f6149..c9f0af18551cfd266f2e22b8f5bd841a49d84901 100644
--- a/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/FaceDataSource.h
+++ b/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/FaceDataSource.h
@@ -40,7 +40,7 @@ public:
                         const ParticleIdxFacePropertyManager<MeshType> & faceToParticleIdxManager,
                         shared_ptr<walberla::mesa_pd::data::ParticleStorage> ps) = 0;
 
-   virtual ~FaceDataSource() {}
+   virtual ~FaceDataSource() = default;
 
 protected:
    std::string name_;
diff --git a/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/OutputSelectorFaceDataSource.h b/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/OutputSelectorFaceDataSource.h
index 02c5fec6bc04b991db03342fc70bbf2fd6db6066..c1de1ca54fd7453280971e050a3a7975b037ddc7 100644
--- a/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/OutputSelectorFaceDataSource.h
+++ b/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/OutputSelectorFaceDataSource.h
@@ -44,14 +44,14 @@ public:
 
    OutputSelectorFaceDataSource(const std::string& name, Selector selector) : Base(name), selector_(selector) { }
 
-   virtual uint_t numComponents() {
+   uint_t numComponents() override {
       return uint_t(1);
    }
 
    using Base::getData;
-   virtual void getData( const MeshType &, const Faces & faces, std::vector<Type> & data,
-                         const ParticleIdxFacePropertyManager<MeshType> & faceToParticleIdxManager,
-                         shared_ptr<walberla::mesa_pd::data::ParticleStorage> ps) {
+   void getData( const MeshType &, const Faces & faces, std::vector<Type> & data,
+                 const ParticleIdxFacePropertyManager<MeshType> & faceToParticleIdxManager,
+                 shared_ptr<walberla::mesa_pd::data::ParticleStorage> ps) override {
       for (const auto & face: faces) {
          size_t particleIdx = faceToParticleIdxManager[face];
          auto p = (*ps)[particleIdx];
@@ -79,14 +79,14 @@ public:
 
    OutputSelectorFaceDataSource(const std::string& name, Selector selector) : Base(name), selector_(selector) { }
 
-   virtual uint_t numComponents() {
+   uint_t numComponents() override {
       return uint_t(3);
    }
 
    using Base::getData;
-   virtual void getData( const MeshType &, const Faces & faces, std::vector<Type> & data,
-                         const ParticleIdxFacePropertyManager<MeshType> & faceToParticleIdxManager,
-                         shared_ptr<walberla::mesa_pd::data::ParticleStorage> ps) {
+   void getData( const MeshType &, const Faces & faces, std::vector<Type> & data,
+                 const ParticleIdxFacePropertyManager<MeshType> & faceToParticleIdxManager,
+                 shared_ptr<walberla::mesa_pd::data::ParticleStorage> ps) override {
       for (const auto & face: faces) {
          size_t particleIdx = faceToParticleIdxManager[face];
          auto p = (*ps)[particleIdx];
diff --git a/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/VertexDataSource.h b/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/VertexDataSource.h
index 41adedfd914abb90426df5c6e4a06fad86011265..cc8524635fda4f62fa3c544d2f41bfac8642e8d8 100644
--- a/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/VertexDataSource.h
+++ b/src/mesa_pd/vtk/ConvexPolyhedron/data_sources/VertexDataSource.h
@@ -39,7 +39,7 @@ public:
          const ParticleIdxVertexPropertyManager<MeshType> & vertexToParticleIdxManager,
          shared_ptr<walberla::mesa_pd::data::ParticleStorage> ps) = 0;
 
-   virtual ~VertexDataSource() {}
+   virtual ~VertexDataSource() = default;
 
 protected:
    std::string name_;
diff --git a/src/mesa_pd/vtk/ParticleVtkOutput.cpp b/src/mesa_pd/vtk/ParticleVtkOutput.cpp
index 6093eeb30cce7c8fafa526c0c8d52608ae7c41e7..9731e1e68fcc0d9e9b6003f18e1babe689eb2734 100644
--- a/src/mesa_pd/vtk/ParticleVtkOutput.cpp
+++ b/src/mesa_pd/vtk/ParticleVtkOutput.cpp
@@ -27,6 +27,7 @@ namespace vtk {
 std::vector< ParticleVtkOutput::Attributes > ParticleVtkOutput::getAttributes() const
 {
    std::vector< Attributes > attributes;
+   attributes.reserve(selectors_.size());
    for (const auto& s : selectors_)
    {
       attributes.emplace_back( s.second->type_string, s.first, s.second->components );
diff --git a/src/mesh_common/distance_octree/BranchNode.h b/src/mesh_common/distance_octree/BranchNode.h
index cf2c2b1920504e7823bc33e5728a3dd087e51f9d..e86821474996699332ee993b40f79cd3b8286261 100644
--- a/src/mesh_common/distance_octree/BranchNode.h
+++ b/src/mesh_common/distance_octree/BranchNode.h
@@ -122,7 +122,7 @@ BranchNode<MeshType>::BranchNode( const shared_ptr< TriangleDistance<MeshType> >
    : Node<MeshType>( triDistance->getMesh(), beginFh, endFh )
 {
    for( int i = 0; i < 8; ++i )
-      children_[i] = NULL;
+      children_[i] = nullptr;
 
    const auto &    min = this->aabb_.minCorner();
    const auto &    max = this->aabb_.maxCorner();
diff --git a/src/pde/sweeps/Multigrid.impl.h b/src/pde/sweeps/Multigrid.impl.h
index da7c0ab6615781b492adcb4e6a9ce55c804e0d6f..47080ea6385542720405ff4ab257dc2331bce38e 100644
--- a/src/pde/sweeps/Multigrid.impl.h
+++ b/src/pde/sweeps/Multigrid.impl.h
@@ -168,7 +168,7 @@ void CoarsenStencilFieldsDCA<Stencil_T >::operator()( const std::vector<BlockDat
 
 
 template< >
-void CoarsenStencilFieldsGCA< stencil::D3Q7 >::operator()( const std::vector<BlockDataID> & stencilFieldId ) const
+inline void CoarsenStencilFieldsGCA< stencil::D3Q7 >::operator()( const std::vector<BlockDataID> & stencilFieldId ) const
 {
 
    WALBERLA_ASSERT_EQUAL(numLvl_, stencilFieldId.size(), "This function can only be called when operating with stencil fields!");
diff --git a/src/pe/Types.h b/src/pe/Types.h
index 463aab78893043c1503bc491b6df181a81fab251..7e45fff691f71fc7c4029709bc434fb18f7d3657 100644
--- a/src/pe/Types.h
+++ b/src/pe/Types.h
@@ -27,6 +27,7 @@
 
 #include <array>
 #include <memory>
+#include <utility>
 #include <vector>
 
 namespace walberla{
diff --git a/src/pe/ccd/SimpleCCD.cpp b/src/pe/ccd/SimpleCCD.cpp
index c9af4591633a3984a696f575081e9c26fe0a6d0c..02cd8860f860dea4f176f814501284e6898cd38b 100644
--- a/src/pe/ccd/SimpleCCD.cpp
+++ b/src/pe/ccd/SimpleCCD.cpp
@@ -62,9 +62,9 @@ PossibleContacts& SimpleCCD::generatePossibleContacts( WcTimingTree* tt ){
          if (!((*it1)->hasInfiniteMass() && (*it2)->hasInfiniteMass()))
          {
             if ( (*it1)->getSystemID() > (*it2)->getSystemID() )
-               contacts_.push_back(std::make_pair(*it2, *it1));
+               contacts_.emplace_back(*it2, *it1);
             else
-               contacts_.push_back(std::make_pair(*it1, *it2));
+               contacts_.emplace_back(*it1, *it2);
          }
       }
 
@@ -73,9 +73,9 @@ PossibleContacts& SimpleCCD::generatePossibleContacts( WcTimingTree* tt ){
          if (!((*it1)->hasInfiniteMass() && it2->hasInfiniteMass()))
          {
             if ( (*it1)->getSystemID() > it2->getSystemID() )
-               contacts_.push_back(std::make_pair(it2.getBodyID(), *it1));
+               contacts_.emplace_back(it2.getBodyID(), *it1);
             else
-               contacts_.push_back(std::make_pair(*it1, it2.getBodyID()));
+               contacts_.emplace_back(*it1, it2.getBodyID());
          }
       }
    }
diff --git a/src/pe/collision/EPA.cpp b/src/pe/collision/EPA.cpp
index e8d54f178d8e46392fee521524f988eb41b1dd53..26264c277df17ececc30f57cbce9de618963b204 100644
--- a/src/pe/collision/EPA.cpp
+++ b/src/pe/collision/EPA.cpp
@@ -150,7 +150,7 @@ void EPA::EPA_Triangle::silhouette( size_t index, const Vec3& w,
    if (!obsolete_) {
       real_t test = (closest_ * w);
       if (test < sqrDist_) {
-         edgeBuffer.push_back(EPA_Edge(this, index));
+         edgeBuffer.emplace_back(this, index);
       }
       else {
          obsolete_ = true; // Facet is visible
@@ -259,7 +259,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
 
    for(EPA_EntryBuffer::iterator it=entryBuffer.begin(); it != entryBuffer.end(); ++it) {
       if(it->isClosestInternal()) {
-         entryHeap.push_back(&(*it));
+         entryHeap.emplace_back(&(*it));
       }
    }
 
@@ -390,7 +390,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
          }
 
          EPA_EdgeBuffer::const_iterator it = edgeBuffer.begin();
-         entryBuffer.push_back(EPA_Triangle(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume));
+         entryBuffer.emplace_back(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume);
 
          EPA_Triangle* firstTriangle = &(entryBuffer.back());
          //if it is expanding candidate add to heap
@@ -404,7 +404,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
                && firstTriangle->getSqrDist() > lowerBoundSqr
                && firstTriangle->getSqrDist() < upperBoundSqr)
          {
-            entryHeap.push_back(firstTriangle);
+            entryHeap.emplace_back(firstTriangle);
             std::push_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
          }
 
@@ -419,7 +419,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
                break;
             }
 
-            entryBuffer.push_back(EPA_Triangle(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume));
+            entryBuffer.emplace_back(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume);
             EPA_Triangle* newTriangle = &(entryBuffer.back());
 
             //std::cerr << "Considering Triangle (" << newTriangle->getSqrDist() << ") {"  << (*newTriangle)[0] <<  "," << (*newTriangle)[1] <<  ","<< (*newTriangle)[2] << "} ("<< epaVolume[(*newTriangle)[0]] * newTriangle->getNormal() << ")" << std::endl;
@@ -434,7 +434,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
                   &&  newTriangle->getSqrDist() > lowerBoundSqr
                   &&  newTriangle->getSqrDist() < upperBoundSqr)
             {
-               entryHeap.push_back(newTriangle);
+               entryHeap.emplace_back(newTriangle);
                std::push_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
             }
 
@@ -555,11 +555,11 @@ inline void EPA::createInitialSimplex( size_t numPoints, GeomPrimitive &geom1, G
       //check for containment inside
       if(originInTetrahedron(epaVolume[0], epaVolume[2], epaVolume[3], epaVolume[4]) || originInTetrahedron(epaVolume[1], epaVolume[2], epaVolume[3], epaVolume[4]) ){
          //insert triangle 1
-         entryBuffer.push_back(EPA_Triangle(1, 2, 3, epaVolume)); //[0] up->ccw1->ccw2
+         entryBuffer.emplace_back(1, 2, 3, epaVolume); //[0] up->ccw1->ccw2
          //insert triangle 2
-         entryBuffer.push_back(EPA_Triangle(1, 3, 4, epaVolume)); //[1] up->ccw2->ccw3
+         entryBuffer.emplace_back(1, 3, 4, epaVolume); //[1] up->ccw2->ccw3
          //insert triangle 3
-         entryBuffer.push_back(EPA_Triangle(1, 4, 2, epaVolume)); //[2] up->ccw3->ccw1
+         entryBuffer.emplace_back(1, 4, 2, epaVolume); //[2] up->ccw3->ccw1
 
          //link these 3 triangles
          entryBuffer[0].link(2, &(entryBuffer[1]), 0); //edge up->ccw1
@@ -568,11 +568,11 @@ inline void EPA::createInitialSimplex( size_t numPoints, GeomPrimitive &geom1, G
 
 
          //insert triangle 4
-         entryBuffer.push_back(EPA_Triangle(0, 2, 4, epaVolume)); //[3] down->ccw1->ccw3
+         entryBuffer.emplace_back(0, 2, 4, epaVolume); //[3] down->ccw1->ccw3
          //insert triangle 5
-         entryBuffer.push_back(EPA_Triangle(0, 4, 3, epaVolume)); //[4] down->ccw3->ccw2
+         entryBuffer.emplace_back(0, 4, 3, epaVolume); //[4] down->ccw3->ccw2
          //insert triangle 6
-         entryBuffer.push_back(EPA_Triangle(0, 3, 2, epaVolume)); //[5] down->ccw2->ccw1
+         entryBuffer.emplace_back(0, 3, 2, epaVolume); //[5] down->ccw2->ccw1
 
          //link these 3 triangles
          entryBuffer[3].link(2, &(entryBuffer[4]), 0); //edge down->ccw3
@@ -626,11 +626,11 @@ inline void EPA::createInitialSimplex( size_t numPoints, GeomPrimitive &geom1, G
       else {
          //Build the hexahedron as it is convex
          //insert triangle 1
-         entryBuffer.push_back(EPA_Triangle(3, 2, 1, epaVolume)); //[0] support1->A->B
+         entryBuffer.emplace_back(3, 2, 1, epaVolume); //[0] support1->A->B
          //insert triangle 2
-         entryBuffer.push_back(EPA_Triangle(3, 1, 0, epaVolume)); //[1] support1->B->C
+         entryBuffer.emplace_back(3, 1, 0, epaVolume); //[1] support1->B->C
          //insert triangle 3
-         entryBuffer.push_back(EPA_Triangle(3, 0, 2, epaVolume)); //[2] support1->C->A
+         entryBuffer.emplace_back(3, 0, 2, epaVolume); //[2] support1->C->A
 
          //link these 3 triangles
          entryBuffer[0].link(2, &(entryBuffer[1]), 0); //edge support1->A
@@ -639,11 +639,11 @@ inline void EPA::createInitialSimplex( size_t numPoints, GeomPrimitive &geom1, G
 
 
          //insert triangle 4
-         entryBuffer.push_back(EPA_Triangle(4, 2, 0, epaVolume)); //[3] support2->A->C
+         entryBuffer.emplace_back(4, 2, 0, epaVolume); //[3] support2->A->C
          //insert triangle 5
-         entryBuffer.push_back(EPA_Triangle(4, 0, 1, epaVolume)); //[4] support2->C->B
+         entryBuffer.emplace_back(4, 0, 1, epaVolume); //[4] support2->C->B
          //insert triangle 6
-         entryBuffer.push_back(EPA_Triangle(4, 1, 2, epaVolume)); //[5] support2->B->A
+         entryBuffer.emplace_back(4, 1, 2, epaVolume); //[5] support2->B->A
 
          //link these 3 triangles
          entryBuffer[3].link(2, &(entryBuffer[4]), 0); //edge support2->C
@@ -748,13 +748,13 @@ inline void EPA::createInitialTetrahedron( size_t top, size_t frontLeft, size_t
                                            EPA_EntryBuffer& entryBuffer )
 {
    //insert triangle 1
-   entryBuffer.push_back(EPA_Triangle(top, frontLeft, frontRight, epaVolume)); //[0] vorne
+   entryBuffer.emplace_back(top, frontLeft, frontRight, epaVolume); //[0] vorne
    //insert triangle 2
-   entryBuffer.push_back(EPA_Triangle(top, frontRight, back, epaVolume)); //[1] rechts hinten
+   entryBuffer.emplace_back(top, frontRight, back, epaVolume); //[1] rechts hinten
    //insert triangle 3
-   entryBuffer.push_back(EPA_Triangle(top, back, frontLeft, epaVolume)); //[2] links hinten
+   entryBuffer.emplace_back(top, back, frontLeft, epaVolume); //[2] links hinten
    //insert triangle 4
-   entryBuffer.push_back(EPA_Triangle(back, frontRight, frontLeft, epaVolume)); //[3] unten
+   entryBuffer.emplace_back(back, frontRight, frontLeft, epaVolume); //[3] unten
 
    //make links between the triangles
    entryBuffer[0].link(0, &(entryBuffer[2]), 2); //Kante vorne links
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index ed4c6c864bdb3f8fc2d80170dd113bafa3c9d681..ad26fb238d29debb866cc3a9684c5471b8a8021b 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -614,7 +614,7 @@ void Raytracer::generateImage(const size_t timestep, WcTimingTree* tt) {
          WALBERLA_LOG_WARNING(pixelErrors << " pixel errors found!");
          
          std::stringstream ss;
-         for (auto it: correctToIncorrectBodyIDsMap) {
+         for (auto const &it: correctToIncorrectBodyIDsMap) {
             const BodyID correctBody = it.first;
             if (it.first != nullptr) {
                ss << " correct body: " << correctBody->getID() << "(" << correctBody->getHash() << ")";
diff --git a/src/pe/rigidbody/RigidBodyCastIterator.h b/src/pe/rigidbody/RigidBodyCastIterator.h
index 3486472b4e501d577edd594b784fbf28d1061b3b..6f3bda568c3a1c28d47c453c67a510c28a19c225 100644
--- a/src/pe/rigidbody/RigidBodyCastIterator.h
+++ b/src/pe/rigidbody/RigidBodyCastIterator.h
@@ -80,7 +80,7 @@ public:
    //**Access operators****************************************************************************
    /*!\name Access operators */
    //@{
-   inline reference operator*()   {return static_cast<reference>( *(cur_->get()) );}
+   inline reference operator*()   {return static_cast<reference>( **cur_ );}
    inline pointer   operator->()  {return static_cast<pointer>(     cur_->get()  );}
    //@}
    //**********************************************************************************************
@@ -228,7 +228,7 @@ public:
    //**Access operators****************************************************************************
    /*!\name Access operators */
    //@{
-   inline reference operator*()   {return static_cast<reference>( *(cur_->get()) );}
+   inline reference operator*()   {return static_cast<reference>( **cur_ );}
    inline pointer   operator->()  {return static_cast<pointer>(     cur_->get()  );}
    //@}
    //**********************************************************************************************
diff --git a/src/pe_coupling/discrete_particle_methods/correlations/AddedMassForceCorrelations.h b/src/pe_coupling/discrete_particle_methods/correlations/AddedMassForceCorrelations.h
index 4574cbc19d02d50b964cb402ba2e8595f5fb36f1..81651697744351f57a7597600f74211a3dd74cbe 100644
--- a/src/pe_coupling/discrete_particle_methods/correlations/AddedMassForceCorrelations.h
+++ b/src/pe_coupling/discrete_particle_methods/correlations/AddedMassForceCorrelations.h
@@ -36,6 +36,7 @@ namespace discrete_particle_methods {
  *                   const real_t & bodyVolume, const real_t & fluidDensity )
  */
 
+inline
 Vector3<real_t> addedMassForceFinn( const Vector3<real_t> & timeDerivativeFluidVel, const Vector3<real_t> & timeDerivativeBodyVel,
                                     const real_t & bodyVolume, const real_t & fluidDensity )
 {
@@ -44,6 +45,7 @@ Vector3<real_t> addedMassForceFinn( const Vector3<real_t> & timeDerivativeFluidV
    return bodyVolume * fluidDensity * Coeffam * ( timeDerivativeFluidVel - timeDerivativeBodyVel );
 }
 
+inline
 Vector3<real_t> noAddedMassForce( const Vector3<real_t> &, const Vector3<real_t> &, const real_t &, const real_t & )
 {
    return Vector3<real_t>(real_t(0));
diff --git a/src/pe_coupling/discrete_particle_methods/correlations/DragForceCorrelations.h b/src/pe_coupling/discrete_particle_methods/correlations/DragForceCorrelations.h
index 1db90c9457a398846ba1f478ee33ebc3a5da2333..002be4a30685445cd5806423dec90b721c134be1 100644
--- a/src/pe_coupling/discrete_particle_methods/correlations/DragForceCorrelations.h
+++ b/src/pe_coupling/discrete_particle_methods/correlations/DragForceCorrelations.h
@@ -45,7 +45,7 @@ namespace discrete_particle_methods {
 
 // equation to calculate the drag coefficient on isolated spherical particle
 // Schiller, L., Naumann, A., 1935. A drag coefficient correlation. Vdi Zeitung 77, 318-320.
-real_t dragCoeffSchillerNaumann( real_t reynoldsNumber )
+inline real_t dragCoeffSchillerNaumann( real_t reynoldsNumber )
 {
    WALBERLA_ASSERT_GREATER_EQUAL( reynoldsNumber, real_t(0) );
 
@@ -55,7 +55,7 @@ real_t dragCoeffSchillerNaumann( real_t reynoldsNumber )
 
 // Coefficient from Stokes' law for drag, only valid for Stokes regime (low Reynolds numbers)
 // = 3 * math::pi * mu * D * fluidVolumeFraction
-real_t dragCoeffStokes ( real_t fluidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity )
+inline real_t dragCoeffStokes ( real_t fluidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity )
 {
    return real_t(3) * math::pi * diameter * fluidDynamicViscosity * fluidVolumeFraction;
 }
@@ -72,6 +72,7 @@ const real_t thresholdAbsoluteVelocityDifference = real_t(1e-10);
 //////////////////////
 
 // Stokes drag law
+inline
 Vector3<real_t> dragForceStokes( const Vector3<real_t> & fluidVel, const Vector3<real_t> & particleVel,
                                  real_t solidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity, real_t /*fluidDensity*/ )
 {
@@ -92,6 +93,7 @@ Vector3<real_t> dragForceStokes( const Vector3<real_t> & fluidVel, const Vector3
 // S. Ergun, Fluid flow through packed columns. Chemical Engineering Progress 48 (1952), 89-94.
 // Y. C. Wen, Y.H. Yu, Mechanics of fluidization. Chemical Engineering Progress Symposium Series 62 (1966), 100-111.
 // see also Beetstra, van der Hoef, Kuipers, "Drag Force of Intermediate Reynolds Number Flow Past Mono- and Bidisperse Arrays of Spheres" (2007)
+inline
 Vector3<real_t>  dragForceErgunWenYu( const Vector3<real_t> & fluidVel, const Vector3<real_t> & particleVel,
                                       real_t solidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity, real_t fluidDensity )
 {
@@ -123,6 +125,7 @@ Vector3<real_t>  dragForceErgunWenYu( const Vector3<real_t> & fluidVel, const Ve
 
 // drag correlation proposed by Tang et al. - "A New Drag Correlation from Fully Resolved Simulations of Flow Past
 // Monodisperse Static Arrays of Spheres", AiChE, 2014
+inline
 Vector3<real_t> dragForceTang( const Vector3<real_t> & fluidVel, const Vector3<real_t> & particleVel,
                                real_t solidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity, real_t fluidDensity )
 {
@@ -151,6 +154,7 @@ Vector3<real_t> dragForceTang( const Vector3<real_t> & fluidVel, const Vector3<r
 
 // drag correlation based on findings from Felice (1994)
 // used e.g. in Kafui et al (2002)
+inline
 Vector3<real_t> dragForceFelice( const Vector3<real_t> & fluidVel, const Vector3<real_t> & particleVel,
                                  real_t solidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity, real_t fluidDensity )
 {
@@ -180,6 +184,7 @@ Vector3<real_t> dragForceFelice( const Vector3<real_t> & fluidVel, const Vector3
 // drag correlation based on findings from Tenneti, Garg, Subramaniam (2011)
 // used e.g. in Finn, Li, Apte - Particle based modelling and simulation of natural sand dynamics in the wave bottom boundary layer (2016)
 // could be generalized also for non-spherical particles, see Finn et al (2016)
+inline
 Vector3<real_t> dragForceTenneti( const Vector3<real_t> & fluidVel, const Vector3<real_t> & particleVel,
                                   real_t solidVolumeFraction, real_t diameter, real_t fluidDynamicViscosity, real_t fluidDensity )
 {
@@ -211,6 +216,7 @@ Vector3<real_t> dragForceTenneti( const Vector3<real_t> & fluidVel, const Vector
 }
 
 
+inline
 Vector3<real_t> noDragForce( const Vector3<real_t> & /*fluidVel*/, const Vector3<real_t> & /*particleVel*/,
                              real_t /*solidVolumeFraction*/, real_t /*diameter*/, real_t /*fluidDynamicViscosity*/, real_t /*fluidDensity*/ )
 {
diff --git a/src/pe_coupling/discrete_particle_methods/correlations/LiftForceCorrelations.h b/src/pe_coupling/discrete_particle_methods/correlations/LiftForceCorrelations.h
index 8e66b93dab441da4fc7e95bd03f915dac930392a..a5e762d21bfa8ef1b2a08fc68e684ce64f9feeb1 100644
--- a/src/pe_coupling/discrete_particle_methods/correlations/LiftForceCorrelations.h
+++ b/src/pe_coupling/discrete_particle_methods/correlations/LiftForceCorrelations.h
@@ -37,6 +37,7 @@ namespace discrete_particle_methods {
  */
 
 // Saffman lift force
+inline
 Vector3<real_t> liftForceSaffman ( const Vector3<real_t> & fluidVel, const Vector3<real_t> & curlFluidVel, const Vector3<real_t> & particleVel,
                                    real_t diameter, real_t fluidDynamicViscosity, real_t fluidDensity )
 {
@@ -53,7 +54,7 @@ Vector3<real_t> liftForceSaffman ( const Vector3<real_t> & fluidVel, const Vecto
 
 }
 
-Vector3<real_t> noLiftForce ( const Vector3<real_t> &, const Vector3<real_t> &, const Vector3<real_t> &, real_t, real_t, real_t )
+inline Vector3<real_t> noLiftForce ( const Vector3<real_t> &, const Vector3<real_t> &, const Vector3<real_t> &, real_t, real_t, real_t )
 {
    return Vector3<real_t>(real_t(0));
 }
diff --git a/src/pe_coupling/discrete_particle_methods/evaluators/EffectiveViscosityFieldEvaluator.h b/src/pe_coupling/discrete_particle_methods/evaluators/EffectiveViscosityFieldEvaluator.h
index f8039c7e6382121f7e19417476a188ca8cbe8914..10c85b125886e65fabef67be3854560e18fa6060 100644
--- a/src/pe_coupling/discrete_particle_methods/evaluators/EffectiveViscosityFieldEvaluator.h
+++ b/src/pe_coupling/discrete_particle_methods/evaluators/EffectiveViscosityFieldEvaluator.h
@@ -32,20 +32,20 @@ namespace discrete_particle_methods {
 // correlations for the viscosity
 
 // no change in viscosity
-real_t calculateUnchangedEffectiveViscosity( real_t fluidViscosity, real_t /*porosity*/ )
+inline real_t calculateUnchangedEffectiveViscosity( real_t fluidViscosity, real_t /*porosity*/ )
 {
    return fluidViscosity;
 }
 
 // see: Fattahi, Waluga, Wohlmuth - "Large scale lattice Boltzmann simulation for the coupling of free and porous media flow"
-real_t calculateRescaledEffectiveViscosity( real_t fluidViscosity, real_t porosity )
+inline real_t calculateRescaledEffectiveViscosity( real_t fluidViscosity, real_t porosity )
 {
    return fluidViscosity / porosity;
 }
 
 // see: J. R. Finn, M. Li, S. V. Apte - "Particle based modelling and simulation of natural sand dynamics in the wave
 // bottom boundary layer", Journal of Fluid Mechanics 796 (2016) 340–385. doi:10.1017/jfm.2016.246.
-real_t calculateEilersEffectiveViscosity( real_t fluidViscosity, real_t porosity )
+inline real_t calculateEilersEffectiveViscosity( real_t fluidViscosity, real_t porosity )
 {
    const real_t closePackingFraction = real_t(0.64);
    const real_t intrinsicViscosity = real_t(2.5); //for monosized spheres
diff --git a/src/pe_coupling/discrete_particle_methods/evaluators/LubricationForceEvaluator.h b/src/pe_coupling/discrete_particle_methods/evaluators/LubricationForceEvaluator.h
index 2de86148379f3ed7391a09477be7712b44f264e7..7b40b3a57e60e09c5ce7f250874e2d4e5b4f3105 100644
--- a/src/pe_coupling/discrete_particle_methods/evaluators/LubricationForceEvaluator.h
+++ b/src/pe_coupling/discrete_particle_methods/evaluators/LubricationForceEvaluator.h
@@ -88,7 +88,7 @@ private:
 }; // class LubricationForceEvaluator
 
 
-void LubricationForceEvaluator::operator ()()
+inline void LubricationForceEvaluator::operator ()()
 {
    WALBERLA_LOG_PROGRESS( "Calculating Lubrication Force" );
 
@@ -142,7 +142,7 @@ void LubricationForceEvaluator::operator ()()
    }
 }
 
-void LubricationForceEvaluator::treatLubricationSphrSphr( const pe::SphereID sphereI, const pe::SphereID sphereJ, const math::AABB & blockAABB )
+inline void LubricationForceEvaluator::treatLubricationSphrSphr( const pe::SphereID sphereI, const pe::SphereID sphereJ, const math::AABB & blockAABB )
 {
 
    WALBERLA_ASSERT_UNEQUAL( sphereI->getSystemID(), sphereJ->getSystemID() );
@@ -182,7 +182,7 @@ void LubricationForceEvaluator::treatLubricationSphrSphr( const pe::SphereID sph
 
 }
 
-void LubricationForceEvaluator::treatLubricationSphrPlane( const pe::SphereID sphereI, const pe::ConstPlaneID planeJ )
+inline void LubricationForceEvaluator::treatLubricationSphrPlane( const pe::SphereID sphereI, const pe::ConstPlaneID planeJ )
 {
 
    real_t gap = pe::getSurfaceDistance( sphereI, planeJ );
@@ -207,7 +207,7 @@ void LubricationForceEvaluator::treatLubricationSphrPlane( const pe::SphereID sp
 }
 
 
-pe::Vec3 LubricationForceEvaluator::compLubricationSphrSphr( real_t gap, const pe::SphereID sphereI, const pe::SphereID sphereJ) const
+inline pe::Vec3 LubricationForceEvaluator::compLubricationSphrSphr( real_t gap, const pe::SphereID sphereI, const pe::SphereID sphereJ) const
 {
    const pe::Vec3 &posSphereI = sphereI->getPosition();
    const pe::Vec3 &posSphereJ = sphereJ->getPosition();
@@ -260,7 +260,7 @@ pe::Vec3 LubricationForceEvaluator::compLubricationSphrSphr( real_t gap, const p
    return fLub;
 }
 
-pe::Vec3 LubricationForceEvaluator::compLubricationSphrPlane( real_t gap, const pe::SphereID sphereI, const pe::ConstPlaneID planeJ) const
+inline pe::Vec3 LubricationForceEvaluator::compLubricationSphrPlane( real_t gap, const pe::SphereID sphereI, const pe::ConstPlaneID planeJ) const
 {
    const pe::Vec3 &posSphereI( sphereI->getPosition() );
    real_t radiusSphereI = sphereI->getRadius();
diff --git a/src/pe_coupling/geometry/SphereEquivalentDiameter.h b/src/pe_coupling/geometry/SphereEquivalentDiameter.h
index 7e40a843dac7f0d5aca20cb996a5c28eb2914e08..e32dc239388de89c53bbb9b4cffbf7f56352d934 100644
--- a/src/pe_coupling/geometry/SphereEquivalentDiameter.h
+++ b/src/pe_coupling/geometry/SphereEquivalentDiameter.h
@@ -31,7 +31,7 @@ namespace pe_coupling {
 
 
 // calculates sphere-equivalent diameter (diameter of a sphere with same volume as given body)
-real_t getSphereEquivalentDiameter( pe::RigidBody & body )
+inline real_t getSphereEquivalentDiameter( pe::RigidBody & body )
 {
    if( body.getTypeID() == pe::Sphere::getStaticTypeID() || body.getTypeID() == pe::Squirmer::getStaticTypeID() )
    {
diff --git a/src/python_coupling/export/FieldExport.impl.h b/src/python_coupling/export/FieldExport.impl.h
index 60ba3fd102d2c05cf252f9385e1a2f816f25eb33..6d9916c71acfed3519155d2353ddd3a8aec0d937 100644
--- a/src/python_coupling/export/FieldExport.impl.h
+++ b/src/python_coupling/export/FieldExport.impl.h
@@ -129,7 +129,9 @@ class GhostLayerFieldDataHandling : public field::BlockDataHandling< GhostLayerF
         alignment_(alignment)
    {}
 
-   GhostLayerField_T* allocate(IBlock* const block)
+   ~GhostLayerFieldDataHandling() override = default;
+
+   GhostLayerField_T* allocate(IBlock* const block) override
    {
       auto blocks = blocks_.lock();
       WALBERLA_CHECK_NOT_NULLPTR(blocks, "Trying to access 'AlwaysInitializeBlockDataHandling' for a block "
@@ -140,7 +142,7 @@ class GhostLayerFieldDataHandling : public field::BlockDataHandling< GhostLayerF
       return field;
    }
 
-   GhostLayerField_T* reallocate(IBlock* const block) { return allocate(block); }
+   GhostLayerField_T* reallocate(IBlock* const block) override { return allocate(block); }
 
  private:
    weak_ptr< StructuredBlockStorage > blocks_;
diff --git a/src/stencil/Directions.h b/src/stencil/Directions.h
index 5be0d72223712c7cc8f4aa2b991bb9456f09aadb..9071405a2604c49980a3734ba592b3427f70fb90 100644
--- a/src/stencil/Directions.h
+++ b/src/stencil/Directions.h
@@ -317,7 +317,7 @@ namespace stencil {
       else if ( axis==1 && !minOrMax ) return N;
       else if ( axis==2 &&  minOrMax ) return B;
       else if ( axis==2 && !minOrMax ) return T;
-      else                             return INVALID_DIR;
+      return INVALID_DIR;
    }
 
    /// Maps (direction,axis) pair to direction
@@ -333,7 +333,7 @@ namespace stencil {
       else if ( axis==1 && !minOrMax ) return N;
       else if ( axis==2 &&  minOrMax ) return B;
       else if ( axis==2 && !minOrMax ) return T;
-      else                             return INVALID_DIR;
+      return INVALID_DIR;
    }
 
 
diff --git a/src/vtk/Base64Writer.h b/src/vtk/Base64Writer.h
index 43631d2a924381ecbe9a6c14c5ca4de2af349cb4..c9af5528e15ecef564e64419de622745e57228c6 100644
--- a/src/vtk/Base64Writer.h
+++ b/src/vtk/Base64Writer.h
@@ -75,7 +75,7 @@ public:
 
 private:
 
-   void encodeblock( unsigned char in[3], unsigned char out[4], int len )
+   void encodeblock( unsigned char const in[3], unsigned char out[4], int len )
    {
       static const unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
diff --git a/src/vtk/VTKOutput.cpp b/src/vtk/VTKOutput.cpp
index 42d7d9ef434b92b720a95115ed6dbbdd638905e2..1039abe54e946409f8d692b4933e36fda6237f8f 100644
--- a/src/vtk/VTKOutput.cpp
+++ b/src/vtk/VTKOutput.cpp
@@ -1784,8 +1784,8 @@ void VTKOutput::writeCollectors( const bool barrier )
       }
       else
       {
-         writePVTU( *collector ); // also applies for outputDomainDecomposition_ == true and pointDataSource_ != NULL
-                                  // and polylineDataSource_ != NULL (uniformGrid_ will be false)
+         writePVTU( *collector ); // also applies for outputDomainDecomposition_ == true and pointDataSource_ != nullptr
+                                  // and polylineDataSource_ != nullptr (uniformGrid_ will be false)
       }
    }
 
@@ -1882,7 +1882,7 @@ void VTKOutput::writeVTHBSeries()
    {
       for( std::string line; std::getline(ofs, line); )
       {
-         if( line.find("]") != std::string::npos )
+         if( line.find(']') != std::string::npos )
          {
             WALBERLA_ASSERT_GREATER( ofs.tellg(), 0 );
             pvdEnd_ = ofs.tellg();
diff --git a/tests/field/FieldOfCustomTypesTest.cpp b/tests/field/FieldOfCustomTypesTest.cpp
index 883d7951059cc3fe435fe53725089a4bf1c1e08f..4a7144a4763811433962f4bd64c215e533c6cd49 100644
--- a/tests/field/FieldOfCustomTypesTest.cpp
+++ b/tests/field/FieldOfCustomTypesTest.cpp
@@ -31,12 +31,6 @@
 using namespace walberla;
 
 
-using std::cout;
-using std::endl;
-
-
-
-
 struct MyClass
 {
    MyClass() {
diff --git a/tests/field/FlagFieldTest.cpp b/tests/field/FlagFieldTest.cpp
index 97b9d382ee34b5bfd732756b893faf298eb4de70..4e91c68b1e7cf8feb52ad53613368b644e3e0f12 100644
--- a/tests/field/FlagFieldTest.cpp
+++ b/tests/field/FlagFieldTest.cpp
@@ -33,10 +33,6 @@
 using namespace walberla;
 namespace wlb = walberla;
 
-using std::vector;
-using std::string;
-using std::cout;
-using std::endl;
 
 void registerTest()
 {
@@ -64,7 +60,7 @@ void registerTest()
    }
    WALBERLA_CHECK(overFlow);
 
-   vector<string> names;
+   std::vector<std::string> names;
    names.emplace_back("Flag1");
    names.emplace_back("Flag2");
    names.emplace_back("Flag3");
@@ -82,7 +78,7 @@ void registerTest()
       WALBERLA_CHECK_EQUAL( ff.getFlagUID( numeric_cast<FlagField<walberla::uint8_t>::flag_t>( 1 << i ) ), FlagUID(names[i]) );
    }
 
-   //ff.printRegistered(cout);
+   //ff.printRegistered(std::cout);
 }
 
 void accessTest()
@@ -167,7 +163,7 @@ void printingTest()
    ff.addFlag(0,1,0,ob);
    ff.addFlag(1,0,0,ob);
 
-   //printSlice( cout,ff, 2,0 );
+   //printSlice( std::cout,ff, 2,0 );
 }
 
 void neighborhoodTest()
diff --git a/tests/lbm/evaluations/PermeabilityTest.cpp b/tests/lbm/evaluations/PermeabilityTest.cpp
index 2cc1fffafc70721dee63b0143e588542e663dcf0..887c524f329ca54a61e56eab951029faee63192b 100644
--- a/tests/lbm/evaluations/PermeabilityTest.cpp
+++ b/tests/lbm/evaluations/PermeabilityTest.cpp
@@ -284,8 +284,6 @@ int main( int argc, char ** argv )
    else
       WALBERLA_ABORT( "This app can only be executed with 1, 4, or 8 processes! Aborting ..." );
 
-   std::string collisionModel( "TRT" );
-
    try {
       if( std::strcmp( setup.collisionModel.c_str(), "SRT" ) == 0 )
          return setupAndExecute< lbm::D3Q19< lbm::collision_model::SRT          , false > >( setup );
diff --git a/tests/pe/MinMaxRefinement.cpp b/tests/pe/MinMaxRefinement.cpp
index 6cd56cb0962c8a210c7453ef00ccaf0572c5220a..35c75825bedadaf4b670c6315bd13126faeb24ff 100644
--- a/tests/pe/MinMaxRefinement.cpp
+++ b/tests/pe/MinMaxRefinement.cpp
@@ -109,14 +109,14 @@ int main( int argc, char ** argv )
    blockforest.setRefreshPhantomBlockMigrationPreparationFunction(
             blockforest::DynamicCurveBalance< blockforest::WeightAssignmentFunctor::PhantomBlockWeight >( false, true, false ) );
 
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,1,1), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,1,3), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,3,1), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,3,3), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,1,1), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,1,3), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,3,1), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,3,3), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(1,1,1), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(1,1,3), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(1,3,1), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(1,3,3), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(3,1,1), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(3,1,3), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(3,3,1), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(3,3,3), 1);
 
    WALBERLA_MPI_BARRIER();
    WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 1" );
@@ -152,7 +152,7 @@ int main( int argc, char ** argv )
 
    for (unsigned int i = 0; i < 30; ++i)
    {
-      createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(real_t(2.1), real_t(2.1), real_t(2.1)), 1);
+      createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(real_t(2.1), real_t(2.1), real_t(2.1)), 1);
    }
 
    WALBERLA_MPI_BARRIER();
diff --git a/tests/pe/Refinement.cpp b/tests/pe/Refinement.cpp
index 96900a6251fc8972f2ec382cbf98c4311c00eea9..5a8ab40adff62e13f02d81839df4685ad9d63d46 100644
--- a/tests/pe/Refinement.cpp
+++ b/tests/pe/Refinement.cpp
@@ -164,8 +164,8 @@ int main( int argc, char ** argv )
 
    blockforest.setRefreshPhantomBlockMigrationPreparationFunction( simpleLB );
 
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(5,5,5), 1);
-   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(15,6,6), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(5,5,5), 1);
+   createSphere(*globalStorage, forest->getBlockStorage(), storageID, 0, Vec3(15,6,6), 1);
 
    SweepTimeloop timeloop( forest->getBlockStorage(), 1 );
    timeloop.addFuncBeforeTimeStep( simpleLB, "refreshFunctorName" );
diff --git a/tests/pe/SyncEquivalence.cpp b/tests/pe/SyncEquivalence.cpp
index 6c03180186aaf7f4bb42e26bc7930414269ee6c9..1ad70b8322fa2501e87ebc061ff35575d13550e2 100644
--- a/tests/pe/SyncEquivalence.cpp
+++ b/tests/pe/SyncEquivalence.cpp
@@ -122,7 +122,7 @@ void createSimulation(math::AABB& simulationDomain,
         IBlock & currentBlock = *blkIt;
         for (auto it = grid_generator::HCPIterator(currentBlock.getAABB(), Vector3<real_t>(-5,-5,-5), spacing); it != grid_generator::HCPIterator(); ++it)
         {
-            SphereID sp = pe::createSphere( *(info.globalBodyStorage.get()), info.forest->getBlockStorage(), info.storageID, static_cast<walberla::id_t>(mpi::MPIManager::instance()->worldRank() * 1000000 + numParticles), *it, radius);
+            SphereID sp = pe::createSphere( *info.globalBodyStorage, info.forest->getBlockStorage(), info.storageID, static_cast<walberla::id_t>(mpi::MPIManager::instance()->worldRank()) * 1000000u + static_cast<walberla::id_t>(numParticles), *it, radius);
             Vec3 rndVel(math::realRandom<real_t>(-vMax, vMax, generator), math::realRandom<real_t>(-vMax, vMax, generator), math::realRandom<real_t>(-vMax, vMax, generator));
             if (sp != nullptr) sp->setLinearVel(rndVel);
             if (sp != nullptr) ++numParticles;
diff --git a/tests/postprocessing/SphereTriangulate.cpp b/tests/postprocessing/SphereTriangulate.cpp
index 325f0ad449a2752c76ab4eff9ef94fea3d4d8267..b74985465fa0d1aeef787a0bfc241b8cc8794672 100644
--- a/tests/postprocessing/SphereTriangulate.cpp
+++ b/tests/postprocessing/SphereTriangulate.cpp
@@ -38,10 +38,6 @@ using namespace postprocessing;
 
 using geometry::TriangleMesh;
 
-using std::cout;
-using std::endl;
-using std::ofstream;
-
 typedef GhostLayerField<real_t,1> ScalarField;
 
 
@@ -106,7 +102,7 @@ void singleField()
 
    TriangleMesh m;
    generateIsoSurface(f,0.5,m);
-   //ofstream file ("out.obj");
+   //std::ofstream file ("out.obj");
    //writeMeshObj(file,m);
 }
 
@@ -143,11 +139,11 @@ void multipleFields()
       generateIsoSurface( **i, real_c(0.5), m, Vector3<real_t>(real_t(1)), uint_t(0), offset );
    }
 
-   //ofstream file1("meshWithDoubles.obj");
+   //std::ofstream file1("meshWithDoubles.obj");
    //writeMeshObj(file1,m);
    size_t verticesRemoved =  m.removeDuplicateVertices();
    WALBERLA_CHECK_EQUAL(verticesRemoved, expectedDoubles);
-   //ofstream file2("meshWithoutDoubles.obj");
+   //std::ofstream file2("meshWithoutDoubles.obj");
    //writeMeshObj(file2,m);
 }
 
diff --git a/tests/simd/SIMD_Equivalence.cpp b/tests/simd/SIMD_Equivalence.cpp
index f90c69f4f119b571740da1ac6b97657ea1e7c6cc..9a86ae0de3974d1d7bb662fcf4245bddc4610cd1 100644
--- a/tests/simd/SIMD_Equivalence.cpp
+++ b/tests/simd/SIMD_Equivalence.cpp
@@ -166,7 +166,7 @@ void print1( const is1::double4_t& vec)
 
 void checkVecEqual ( is0::double4_t a, is1::double4_t b, const std::string & description = "" )
 {
-   if ( description.size() > 0) 
+   if ( not description.empty() )
    {
       double meanError = std::abs( is0::getComponent(a, 0 )- is1::getComponent(b,0 ) ) +
 			 std::abs( is0::getComponent(a, 1 )- is1::getComponent(b,1 ) ) +
diff --git a/tests/stencil/StencilTest.cpp b/tests/stencil/StencilTest.cpp
index 2e282ac625e85c53c1f4edb00c71ed0f67393d7a..3ddee03e389d8a36d8e9647acfb6746a66742045 100644
--- a/tests/stencil/StencilTest.cpp
+++ b/tests/stencil/StencilTest.cpp
@@ -19,9 +19,6 @@
 using namespace walberla;
 using namespace stencil;
 
-using std::cout;
-using std::endl;
-
 
 template <typename S>
 void stencilIteration()
diff --git a/utilities/filterCompileCommands.py b/utilities/filterCompileCommands.py
index 361ee2f356df41e6c30848f16fe1f9b264fee9f2..a8d7df721e66b706b0159057f72cf2f7b34608f5 100755
--- a/utilities/filterCompileCommands.py
+++ b/utilities/filterCompileCommands.py
@@ -1,11 +1,42 @@
 #!/usr/bin/env python3
 
+import argparse
+import pathlib
 import json
 import sys
 
 
-def compileCommandSelector(x):
-    return not (("extern" in x["file"]) or ("tests" in x["file"]))
+class QualifiedSequence(argparse.Action):
+    """Append qualified values from different arguments into the same destination."""
+    def __call__(self, parser, namespace, values, option_string=None):
+        accumulator = getattr(namespace, self.dest, None) or []
+        assert option_string is not None
+        mode = "include" if option_string in ("-i", "--include") else "exclude"
+        accumulator.append((mode, values))
+        setattr(namespace, self.dest, accumulator)
+
+
+parser = argparse.ArgumentParser(description="Filter out source files from CMake database.")
+parser.add_argument("-f", "--file", action="store", type=str, required=True,
+                    help="Database file to edit")
+parser.add_argument("-i", "--include", action=QualifiedSequence, dest="filters",
+                    nargs="+", help="Include paths containing these folder names")
+parser.add_argument("-e", "--exclude", action=QualifiedSequence, dest="filters",
+                    nargs="+", help="Exclude paths containing these folder names")
+
+
+def compileCommandSelector(x, filters=None):
+    if filters is None:
+        filters = [("exclude", ("extern", "tests"))]
+    path = "/".join(pathlib.Path(x["file"]).parts)[1:]
+    keep = True
+    for mode, components in filters:
+        for component in components:
+            subpath = "/".join(("", ) + pathlib.Path(component).parts + ("", ))
+            if subpath in path or component == "*":
+                keep = (mode == "include")
+                break
+    return keep
 
 
 def removePrecompiler(x):
@@ -17,25 +48,20 @@ def removePrecompiler(x):
 
 
 if __name__ == "__main__":
-    if len(sys.argv) != 2:
-        print("usage: ./filterCompileCommands.py compile_commands.json")
-        exit(-1)
+    args = parser.parse_args()
 
-    filename = sys.argv[1]
-    print("loading compile commands file: {}".format(filename))
+    print(f"loading compile commands file: {args.file}")
 
-    fin = open(filename, "r")
-    cc = json.load(fin)
-    fin.close()
+    with open(args.file, "r") as f:
+        cc = json.load(f)
 
-    print("compile commands read: {}".format(len(cc)))
+    print(f"compile commands read: {len(cc)}")
 
-    cc_filtered = list(filter(compileCommandSelector, cc))
+    cc_filtered = list(filter(lambda x: compileCommandSelector(x, args.filters), cc))
     for x in cc_filtered:
         x["command"] = removePrecompiler(x["command"])
 
-    print("compile commands filtered: {}".format(len(cc_filtered)))
+    print(f"compile commands filtered: {len(cc_filtered)}")
 
-    fout = open(filename, "w")
-    json.dump(cc_filtered, fout)
-    fout.close()
+    with open(args.file, "w") as f:
+        json.dump(cc_filtered, f, indent=2)