diff --git a/apps/showcases/PorousMediaGPU/PorousMediaGPU.cpp b/apps/showcases/PorousMediaGPU/PorousMediaGPU.cpp
index 7d7c35b673396e082fd46e31be505a5837a55bac..90c6326aa36e061a00a28f778d9e6d6d4b75fb39 100644
--- a/apps/showcases/PorousMediaGPU/PorousMediaGPU.cpp
+++ b/apps/showcases/PorousMediaGPU/PorousMediaGPU.cpp
@@ -29,6 +29,7 @@
 #include "core/logging/Logging.h"
 #include "core/math/Vector3.h"
 #include "core/math/Constants.h"
+#include "core/math/Random.h"
 #include "core/Environment.h"
 #include "core/mpi/MPIManager.h"
 #include "core/MemoryUsage.h"
@@ -109,6 +110,142 @@ inline Vector3< uint_t > inflowSliceSize( const shared_ptr< StructuredBlockStora
    return Vector3<uint_t>( uint_c(1), blocks->getNumberOfYCells( *block ), blocks->getNumberOfZCells( *block ) );
 }
 
+template< typename Field_T >
+class Inflow
+{
+ public:
+   Inflow(const std::shared_ptr< StructuredBlockForest >& blocks, const Setup& setup, const IDs& ids)
+      : blocks_(blocks), setup_(setup), ids_(ids), executionCounter_(uint_c(0))
+   {
+      nu_   = setup_.kinViscosity;
+      urms_ = setup_.urms;
+      le_   = setup_.characteristicLength;
+      n_    = setup_.numberOfFourrierModes;
+      dt_   = setup_.dt;
+      uc_   = setup_.uc;
+
+      alpha_           = (real_c(55.0) * std::tgamma(real_c(5.0) / real_c(6.0))) / (real_c(9.0) * std::sqrt(math::pi) * std::tgamma(real_c(1.0) / real_c(3.0)));
+      kappaVKP_        = (real_c(9.0) * math::pi * alpha_) / (real_c(55.0) * le_);
+      epsilonVKP_      = (std::pow(alpha_ * std::tgamma(real_c(2.0)/real_c(3.0)), (real_c(3.0)/real_c(2.0)))) * (real_c(0.5) * kappaVKP_ * std::pow(urms_, real_c(3.0)));
+      kappaKolmogorov_ = std::pow(epsilonVKP_ / std::pow(nu_, real_c(3.0)), real_c(1.0)/real_c(4.0));
+
+      s_ = std::log10(kappaVKP_ / real_c(2.0));
+      e_ = std::log10(kappaKolmogorov_ * real_c(2.0));
+      firstMode_ = std::pow(real_c(10.0), s_);
+      lastMode_  = std::pow(real_c(10.0), e_);
+      deltaKappa_ = (lastMode_ - firstMode_) / (real_c(n_) - real_c(1.0));
+
+      logging();
+   }
+
+   void operator()(){
+      ++executionCounter_;
+
+      // only evaluate in given intervals
+      // if (executionCounter_ % interval_ != uint_c(0)) { return; }
+
+      // update the inflow velocity plane
+      update();
+   }
+
+   void logging(){
+      WALBERLA_LOG_INFO_ON_ROOT( "Using turbulent injection with:" << std::setprecision(16) <<
+      "\n   + kin. viscosity:        " << nu_ << " [m^2/s]" <<
+      "\n   + uRMS:                  " << urms_ <<
+      "\n   + characteristicLength:  " << le_ <<
+      "\n   + numberOfFourrierModes: " << n_ <<
+      "\n   + alpha:                 " << alpha_ <<
+      "\n   + kappa VKP:             " << kappaVKP_ <<
+      "\n   + epsilon VKP:           " << epsilonVKP_ <<
+      "\n   + kappa Kolmogorov:      " << kappaKolmogorov_ <<
+      "\n   + firstMode:             " << firstMode_ <<
+      "\n   + lastMode:              " << lastMode_)
+   }
+
+ private:
+   const std::shared_ptr< StructuredBlockForest > blocks_;
+   const Setup setup_;
+   const IDs ids_;
+
+   real_t nu_;
+   real_t urms_;
+   real_t le_;
+   uint_t n_;
+   real_t alpha_;
+   real_t kappaVKP_;
+   real_t epsilonVKP_;
+   real_t kappaKolmogorov_;
+
+   real_t dt_;
+   Vector3<real_t> uc_;
+
+   real_t s_;
+   real_t e_;
+   real_t firstMode_;
+   real_t lastMode_;
+   real_t deltaKappa_;
+
+   uint_t executionCounter_; // number of times operator() has been called
+
+   void update(){
+      WALBERLA_LOG_INFO_ON_ROOT("Update inflow")
+      for (auto& block : *blocks_){
+      auto velocityFieldInflowSlice = block.template getData< Field_T >(ids_.velocityFieldInflowSlice);
+      WALBERLA_FOR_ALL_CELLS_INCLUDING_GHOST_LAYER_XYZ(velocityFieldInflowSlice, Cell globalCell;
+         velocityFieldInflowSlice->get(x, y, z, 0) = 0.05;
+      )
+   }
+   gpu::fieldCpy< gpu::GPUField< typename Field_T::value_type >, Field_T >(blocks_, ids_.velocityFieldInflowSliceGPU, ids_.velocityFieldInflowSlice);
+
+   }
+
+   real_t getKarmanPaoEnergy(const real_t kappa){
+      const real_t a1 = alpha_ * std::pow(urms_, real_c(2.0)) / kappaVKP_;
+      const real_t a2 = std::pow(kappa / kappaVKP_, real_c(4.0));
+      const real_t a3 = std::pow(real_c(1.0) + std::pow(kappa / kappaVKP_, real_c(2.0)), real_c(17.0) / real_c(6.0));
+      const real_t a4 = std::exp(real_c(-2.0) * std::pow(kappa / kappaKolmogorov_, real_c(2.0)));
+      return a1 * a2 / a3 * a4;
+   }
+
+   Vector3<real_t> summOfFourrierModes(Vector3<real_t> p){
+
+      Vector3<real_t> result(real_c(0.0), real_c(0.0), real_c(0.0));
+
+      for(uint_t i = 0; i < n_; ++i){
+
+         const real_t a = math::realRandom(real_c(0.0), real_c(1.0));
+         const real_t theta = std::acos(real_c(2.0) * a - real_c(1.0));
+         const real_t phi = real_c(2.0) * math::pi * math::realRandom(real_c(0.0), real_c(1.0));
+         const real_t psi = real_c(2.0) * math::pi * math::realRandom(real_c(0.0), real_c(1.0));
+
+         const real_t kappaN = firstMode_ + real_c(0.5) * deltaKappa_ + real_c(i) * deltaKappa_;
+         
+         Vector3<real_t> kappaVector(std::cos(phi) * std::sin(theta) * kappaN,
+                                     std::sin(theta) * std::sin(phi) * kappaN,
+                                     std::cos(theta) * kappaN);
+
+         Vector3<real_t> zetta(math::realRandom(real_c(-1.0), real_c(1.0)),
+                               math::realRandom(real_c(-1.0), real_c(1.0)),
+                               math::realRandom(real_c(-1.0), real_c(1.0)));
+         zetta = zetta.getNormalized();
+
+         Vector3<real_t> crossProduct = kappaVector%=zetta;
+         Vector3<real_t> sigma = crossProduct / crossProduct.getNormalized();
+
+         const real_t ut = std::sqrt(getKarmanPaoEnergy(kappaN) * deltaKappa_);
+         const real_t t = executionCounter_ * dt_;
+
+         const Vector3<real_t> x = p - t*uc_;
+         const real_t arg = std::cos(kappaVector * x + psi);
+
+         result += real_c(2.0) * ut * arg * sigma;
+      }
+
+      return result;
+   }
+
+}; // class Inflow
+
 int main(int argc, char** argv){
    Environment env( argc, argv );
    mpi::MPIManager::instance()->useWorldComm();
@@ -123,12 +260,10 @@ int main(int argc, char** argv){
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
    auto parameters        = config->getOneBlock("Parameters");
-   auto tpmsParameters    = config->getOneBlock("TPMS");
-   auto domainParameters  = config->getOneBlock("DomainSetup");
    auto loggingParameters = config->getOneBlock("Logging");
    auto boundariesConfig  = config->getBlock("Boundaries");
 
-   Setup setup(parameters, tpmsParameters, domainParameters, loggingParameters, infoMap);
+   Setup setup(config, infoMap);
    TPMS tpms(setup);
    WALBERLA_LOG_INFO_ON_ROOT( "Simulation run data:"
                               "\n- simulation parameters:"   << std::setprecision(16) <<
@@ -194,14 +329,7 @@ int main(int argc, char** argv){
    }
    sweepCollection.initialiseBlockPointer();
 
-   for (auto& block : *blocks){
-      auto velocityFieldInflowSlice = block.getData< VelocityField_T >(ids.velocityFieldInflowSlice);
-      WALBERLA_FOR_ALL_CELLS_INCLUDING_GHOST_LAYER_XYZ(velocityFieldInflowSlice, Cell globalCell;
-         velocityFieldInflowSlice->get(x, y, z, 0) = setup.latticeVelocity;
-      )
-   }
-   gpu::fieldCpy< gpu::GPUField< VelocityField_T::value_type >, VelocityField_T >(blocks, ids.velocityFieldInflowSliceGPU, ids.velocityFieldInflowSlice);
-
+   Inflow<VelocityField_T> inflow(blocks, setup, ids);
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                      LB SWEEPS AND BOUNDARY HANDLING                                       ///
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -250,6 +378,8 @@ int main(int argc, char** argv){
    auto defaultStream = gpu::StreamRAII::newPriorityStream(streamLowPriority);
    SweepTimeloop timeloop(blocks->getBlockStorage(), setup.timesteps);
 
+   timeloop.addFuncBeforeTimeStep(inflow, "Update inflow velocity");
+
    lbm_generated::BasicRecursiveTimeStepGPU< GPUPdfField_T, SweepCollection_T, BoundaryCollection_T >
       LBMMeshRefinement(blocks, ids.pdfFieldGPU, sweepCollection, boundaryCollection, nonUniformCommunication, nonUniformPackInfo);
 
diff --git a/apps/showcases/PorousMediaGPU/PorousMediaGPU.prm b/apps/showcases/PorousMediaGPU/PorousMediaGPU.prm
index 60899bae570ffab5329b640d2d43db90d1880639..877f46b3db8d69208e127a2fbe5d37a5d3bf059c 100644
--- a/apps/showcases/PorousMediaGPU/PorousMediaGPU.prm
+++ b/apps/showcases/PorousMediaGPU/PorousMediaGPU.prm
@@ -9,8 +9,6 @@ Parameters
 
     timesteps 11;
 
-    useGrid false;
-
     processMemoryLimit 512; // MiB
     innerOuterSplit <1, 1, 1>;
 
@@ -18,6 +16,15 @@ Parameters
     gpuEnabledMPI false;
 }
 
+Turbulence
+{
+    useGrid false;
+    U_rms  0.1;
+    characteristicLength 0.3333333333333333;
+    numberOfFourrierModes 5;
+    U_c < 1.0, 0.0, 0.0 >;
+}
+
 TPMS
 {
     waveNumber 6.2831853072;
diff --git a/apps/showcases/PorousMediaGPU/Setup.h b/apps/showcases/PorousMediaGPU/Setup.h
index ac994ad3f063ed6423e2f52a3400c68a8455a5e7..d45dfa2dc9d63fb0c1643c8d1006a0c5e143fdde 100644
--- a/apps/showcases/PorousMediaGPU/Setup.h
+++ b/apps/showcases/PorousMediaGPU/Setup.h
@@ -32,9 +32,16 @@ namespace walberla
 struct Setup
 {
 
-   Setup(const Config::BlockHandle & parameters, const Config::BlockHandle & tpms, 
-         const Config::BlockHandle & domainParameters, const Config::BlockHandle & logging, std::map<std::string, std::string>& infoMap)
+   Setup(std::shared_ptr<Config>& config, std::map<std::string, std::string>& infoMap)
    {
+
+      auto parameters        = config->getOneBlock("Parameters");
+      auto domainParameters  = config->getOneBlock("DomainSetup");
+      auto logging           = config->getOneBlock("Logging");
+      auto tpms              = config->getOneBlock("TPMS");
+      auto turbulence        = config->getOneBlock("Turbulence");
+
+
       blockForestFilestem = domainParameters.getParameter< std::string >("blockForestFilestem", "blockforest");
       numProcesses        = domainParameters.getParameter< uint_t >("numberProcesses");
       domainSize          = domainParameters.getParameter< Vector3< real_t > >("domainSize");
@@ -52,7 +59,12 @@ struct Setup
       reynoldsNumber    = parameters.getParameter< real_t >("reynoldsNumber");
       referenceVelocity = parameters.getParameter< real_t >("referenceVelocity");
       latticeVelocity   = parameters.getParameter< real_t >("latticeVelocity");
-      useGrid           = parameters.getParameter< bool >("useGrid");
+
+      useGrid               = turbulence.getParameter< bool >("useGrid");
+      urms                  = turbulence.getParameter< real_t >("U_rms");
+      characteristicLength  = turbulence.getParameter< real_t >("characteristicLength");
+      numberOfFourrierModes = turbulence.getParameter< uint_t >("numberOfFourrierModes");
+      uc                    = turbulence.getParameter< Vector3< real_t > >("U_c");
 
       waveNumber = tpms.getParameter< real_t >("waveNumber");
       scaling    = tpms.getParameter< real_t >("scaling");
@@ -112,7 +124,12 @@ struct Setup
    real_t referenceVelocity;
    real_t referenceLength;
    real_t latticeVelocity;
+
    bool useGrid;
+   real_t urms;
+   real_t characteristicLength;
+   uint_t numberOfFourrierModes;
+   Vector3<real_t> uc;
 
    real_t waveNumber;
    real_t scaling;