From 32e9dbfb6d55958ac8dae05d270141a7637d315c Mon Sep 17 00:00:00 2001
From: Cristian C Lalescu <Cristian.Lalescu@mpcdf.mpg.de>
Date: Thu, 17 Dec 2020 15:08:53 +0100
Subject: [PATCH] adds simple Kraichan scalar model for profiling

---
 TurTLE/test/profile_scalar.py                |  33 +-
 TurTLE/test/profiler/Kraichnan_scalar_v1.cpp | 311 +++++++++++++++++++
 TurTLE/test/profiler/Kraichnan_scalar_v1.hpp |  80 +++++
 setup.py                                     |   2 +
 4 files changed, 411 insertions(+), 15 deletions(-)
 create mode 100644 TurTLE/test/profiler/Kraichnan_scalar_v1.cpp
 create mode 100644 TurTLE/test/profiler/Kraichnan_scalar_v1.hpp

diff --git a/TurTLE/test/profile_scalar.py b/TurTLE/test/profile_scalar.py
index ce7c6eda..135ca33e 100644
--- a/TurTLE/test/profile_scalar.py
+++ b/TurTLE/test/profile_scalar.py
@@ -18,7 +18,9 @@ cpp_location = os.path.join(os.path.join(
 class ADNS(TurTLE.DNS):
     def __init__(
             self,
+            dns_type = 'scalar_evolution',
             **kwargs):
+        self.dns_type = dns_type
         TurTLE.DNS.__init__(self, **kwargs)
         return None
     def write_src(
@@ -56,13 +58,12 @@ class ADNS(TurTLE.DNS):
                 ['#include ' + hh
                  for hh in self.include_list])
         self.name = 'scalar_evolution'
-        self.dns_type = 'scalar_evolution'
         self.definitions += open(
             os.path.join(
-                cpp_location, 'scalar_evolution.hpp'), 'r').read()
+                cpp_location, self.dns_type + '.hpp'), 'r').read()
         self.definitions += open(
             os.path.join(
-                cpp_location, 'scalar_evolution.cpp'), 'r').read()
+                cpp_location, self.dns_type + '.cpp'), 'r').read()
         with open(self.name + '.cpp', 'w') as outfile:
             outfile.write(self.version_message + '\n\n')
             outfile.write(self.includes + '\n\n')
@@ -84,12 +85,14 @@ class ADNS(TurTLE.DNS):
         self.parameters['dt'] = float(0.0001)
         self.parameters['histogram_bins'] = int(64)
         self.parameters['max_value_estimate'] = float(1)
+        self.parameters['field_random_seed'] = int(1)
 
         self.parameters['nu'] = float(0.1)
-        self.parameters['mu'] = float(0.2)
-        self.parameters['injection_rate'] = float(0.4)
-        self.parameters['fk0'] = float(2.0)
-        self.parameters['fk1'] = float(4.0)
+        if self.dns_type == 'scalar_evolution':
+            self.parameters['mu'] = float(0.2)
+            self.parameters['injection_rate'] = float(0.4)
+            self.parameters['fk0'] = float(2.0)
+            self.parameters['fk1'] = float(4.0)
 
         self.parameters['spectrum_dissipation'] = float(0.027)
         self.parameters['spectrum_Lint'] = float(1.3)
@@ -108,7 +111,6 @@ class ADNS(TurTLE.DNS):
         opt = parser.parse_args(args)
         self.simname=opt.simname
         self.set_precision(opt.precision)
-        self.dns_type = 'scalar_evolution'
         self.name = self.dns_type + '-' + self.fluid_precision + '-v' + TurTLE.__version__
         if ((self.parameters['niter_todo'] % self.parameters['niter_out']) != 0):
             self.parameters['niter_out'] = self.parameters['niter_todo']
@@ -126,12 +128,13 @@ class ADNS(TurTLE.DNS):
             opt.ny = opt.n
         if type(opt.nz) == type(None):
             opt.nz = opt.n
-        if type(opt.fk0) == type(None):
-            opt.fk0 = self.parameters['fk0']
-        if type(opt.fk1) == type(None):
-            opt.fk1 = self.parameters['fk1']
-        if type(opt.injection_rate) == type(None):
-            opt.injection_rate = self.parameters['injection_rate']
+        if self.dns_type == 'scalar_evolution':
+            if type(opt.fk0) == type(None):
+                opt.fk0 = self.parameters['fk0']
+            if type(opt.fk1) == type(None):
+                opt.fk1 = self.parameters['fk1']
+            if type(opt.injection_rate) == type(None):
+                opt.injection_rate = self.parameters['injection_rate']
         if type(opt.dealias_type) == type(None):
             opt.dealias_type = self.parameters['dealias_type']
         if (opt.nx > opt.n or
@@ -213,7 +216,7 @@ class ADNS(TurTLE.DNS):
         return None
 
 def main():
-    bla = ADNS()
+    bla = ADNS('Kraichnan_scalar_v1')
     bla.launch(sys.argv[1:])
     return None
 
diff --git a/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp b/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp
new file mode 100644
index 00000000..e180ca95
--- /dev/null
+++ b/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp
@@ -0,0 +1,311 @@
+/******************************************************************************
+*                                                                             *
+*  Copyright 2019 Max Planck Institute for Dynamics and Self-Organization     *
+*                                                                             *
+*  This file is part of bfps.                                                 *
+*                                                                             *
+*  bfps 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.                                     *
+*                                                                             *
+*  bfps 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 bfps.  If not, see <http://www.gnu.org/licenses/>               *
+*                                                                             *
+* Contact: Cristian.Lalescu@ds.mpg.de                                         *
+*                                                                             *
+******************************************************************************/
+
+
+
+#include <string>
+#include <cmath>
+//#include "Kraichnan_scalar_v1.hpp"
+#include "scope_timer.hpp"
+#include "fftw_tools.hpp"
+
+
+template <typename rnumber>
+int Kraichnan_scalar_v1<rnumber>::initialize(void)
+{
+    TIMEZONE("Kraichnan_scalar_v1::initialize");
+    this->read_iteration();
+    this->read_parameters();
+    if (this->myrank == 0)
+    {
+        // set caching parameters
+        hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
+        herr_t cache_err = H5Pset_cache(fapl, 0, 521, 134217728, 1.0);
+        variable_used_only_in_assert(cache_err);
+        DEBUG_MSG("when setting stat_file cache I got %d\n", cache_err);
+        this->stat_file = H5Fopen(
+                (this->simname + ".h5").c_str(),
+                H5F_ACC_RDWR,
+                fapl);
+    }
+    int data_file_problem;
+    if (this->myrank == 0)
+        data_file_problem = this->grow_file_datasets();
+    MPI_Bcast(&data_file_problem, 1, MPI_INT, 0, this->comm);
+    if (data_file_problem > 0)
+    {
+        std::cerr <<
+            data_file_problem <<
+            " problems growing file datasets.\ntrying to exit now." <<
+            std::endl;
+        return EXIT_FAILURE;
+    }
+
+    this->scalar = new field<rnumber, FFTW, ONE>(
+            this->nx, this->ny, this->nz,
+            this->comm,
+            fftw_planner_string_to_flag[this->fftw_plan_rigor]);
+
+    this->tscal0 = new field<rnumber, FFTW, ONE>(
+            this->nx, this->ny, this->nz,
+            this->comm,
+            fftw_planner_string_to_flag[this->fftw_plan_rigor]);
+
+    this->ux = new field<rnumber, FFTW, ONE>(
+            this->nx, this->ny, this->nz,
+            this->comm,
+            fftw_planner_string_to_flag[this->fftw_plan_rigor]);
+    this->uy = new field<rnumber, FFTW, ONE>(
+            this->nx, this->ny, this->nz,
+            this->comm,
+            fftw_planner_string_to_flag[this->fftw_plan_rigor]);
+    this->uz = new field<rnumber, FFTW, ONE>(
+            this->nx, this->ny, this->nz,
+            this->comm,
+            fftw_planner_string_to_flag[this->fftw_plan_rigor]);
+
+    this->kk = new kspace<FFTW, SMOOTH>(
+            this->scalar->clayout,
+            this->dkx, this->dky, this->dkz);
+
+    make_gaussian_random_field<rnumber, FFTW, ONE, SMOOTH>(
+            this->kk,
+            this->scalar,
+            this->random_seed,
+            this->spectrum_dissipation,
+            this->spectrum_Lint,
+            this->spectrum_etaK,
+            this->spectrum_large_scale_const,
+            this->spectrum_small_scale_const);
+
+    this->scalar->symmetrize();
+    this->kk->template dealias<rnumber, ONE>(this->scalar->get_cdata());
+
+    if (this->myrank == 0 && this->iteration == 0)
+        this->kk->store(stat_file);
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int Kraichnan_scalar_v1<rnumber>::step(void)
+{
+    TIMEZONE("Kraichnan_scalar_v1::step");
+    this->iteration++;
+
+    // store scalar
+    *(this->tscal0) = *(this->scalar);
+
+    // generate random velocity field
+    make_gaussian_random_field<rnumber, FFTW, ONE, SMOOTH>(
+            this->kk,
+            this->ux,
+            3*(this->random_seed+this->iteration),
+            this->spectrum_dissipation,
+            this->spectrum_Lint,
+            this->spectrum_etaK,
+            this->spectrum_large_scale_const,
+            this->spectrum_small_scale_const,
+            double(3)/2); // normalization required because we will impose incompressibility
+    make_gaussian_random_field<rnumber, FFTW, ONE, SMOOTH>(
+            this->kk,
+            this->uy,
+            3*(this->random_seed+this->iteration)+1,
+            this->spectrum_dissipation,
+            this->spectrum_Lint,
+            this->spectrum_etaK,
+            this->spectrum_large_scale_const,
+            this->spectrum_small_scale_const,
+            double(3)/2);
+    make_gaussian_random_field<rnumber, FFTW, ONE, SMOOTH>(
+            this->kk,
+            this->uz,
+            3*(this->random_seed+this->iteration)+2,
+            this->spectrum_dissipation,
+            this->spectrum_Lint,
+            this->spectrum_etaK,
+            this->spectrum_large_scale_const,
+            this->spectrum_small_scale_const,
+            double(3)/2);
+
+    // ensure velocity field is solenoidal
+    {
+        TIMEZONE("Kraichnan_scalar_v1::divfree");
+        this->kk->CLOOP_K2(
+                [&](const ptrdiff_t cindex,
+                    const ptrdiff_t xindex,
+                    const ptrdiff_t yindex,
+                    const ptrdiff_t zindex,
+                    const double k2){
+                if (k2 > 0)
+                {
+                const typename fftw_interface<rnumber>::complex tval = {
+                    rnumber((this->kk->kx[xindex]*this->ux->cval(cindex, 0) +
+                             this->kk->ky[yindex]*this->uy->cval(cindex, 0) +
+                             this->kk->kz[zindex]*this->uz->cval(cindex, 0) ) / k2),
+                    rnumber((this->kk->kx[xindex]*this->ux->cval(cindex, 1) +
+                             this->kk->ky[yindex]*this->uy->cval(cindex, 1) +
+                             this->kk->kz[zindex]*this->uz->cval(cindex, 1) ) / k2)};
+                for (unsigned int imag_part=0; imag_part<2; imag_part++)
+                {
+                    this->ux->cval(cindex, imag_part) -= tval[imag_part]*this->kk->kx[xindex];
+                    this->uy->cval(cindex, imag_part) -= tval[imag_part]*this->kk->ky[yindex];
+                    this->uz->cval(cindex, imag_part) -= tval[imag_part]*this->kk->kz[zindex];
+                }
+                }
+        });
+    }
+
+    // take fields to real space
+    this->ux->ift();
+    this->uy->ift();
+    this->uz->ift();
+    this->tscal0->ift();
+
+    // compute nonlinear term
+    this->tscal0->RLOOP (
+                [&](const ptrdiff_t rindex,
+                    const ptrdiff_t xindex,
+                    const ptrdiff_t yindex,
+                    const ptrdiff_t zindex){
+                this->ux->rval(rindex) *= this->tscal0->rval(rindex) / this->scalar->npoints;
+                this->uy->rval(rindex) *= this->tscal0->rval(rindex) / this->scalar->npoints;
+                this->uz->rval(rindex) *= this->tscal0->rval(rindex) / this->scalar->npoints;
+        }
+        );
+
+    // take fields back to Fourier space
+    this->ux->dft();
+    this->uy->dft();
+    this->uz->dft();
+
+    this->kk->template dealias<rnumber, ONE>(this->ux->get_cdata());
+    this->kk->template dealias<rnumber, ONE>(this->uy->get_cdata());
+    this->kk->template dealias<rnumber, ONE>(this->uz->get_cdata());
+
+    // Euler step
+    this->kk->CLOOP_K2(
+                [&](const ptrdiff_t cindex,
+                    const ptrdiff_t xindex,
+                    const ptrdiff_t yindex,
+                    const ptrdiff_t zindex,
+                    const double k2){
+        if (k2 <= this->kk->kM2)
+        {
+            this->scalar->cval(cindex,0) -= this->dt*(
+                      this->nu*k2 * this->scalar->cval(cindex, 0) + // linear term
+                      this->kk->kx[xindex] * this->ux->cval(cindex, 1) +
+                      this->kk->ky[yindex] * this->uy->cval(cindex, 1) +
+                      this->kk->kz[zindex] * this->uz->cval(cindex, 1)
+                    );
+            this->scalar->cval(cindex,0) += this->dt*(
+                     -this->nu*k2 * this->scalar->cval(cindex, 0) + // linear term
+                      this->kk->kx[xindex] * this->ux->cval(cindex, 0) +
+                      this->kk->ky[yindex] * this->uy->cval(cindex, 0) +
+                      this->kk->kz[zindex] * this->uz->cval(cindex, 0)
+                    );
+        }
+        else
+            std::fill_n((rnumber*)(this->scalar->get_cdata()+cindex), 2, 0.0);
+    });
+
+    // symmetrize
+    this->scalar->symmetrize();
+
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int Kraichnan_scalar_v1<rnumber>::write_checkpoint(void)
+{
+    TIMEZONE("Kraichnan_scalar_v1::write_checkpoint");
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int Kraichnan_scalar_v1<rnumber>::finalize(void)
+{
+    TIMEZONE("Kraichnan_scalar_v1::finalize");
+    if (this->myrank == 0)
+        H5Fclose(this->stat_file);
+    delete this->tscal0;
+    delete this->ux;
+    delete this->uy;
+    delete this->uz;
+    delete this->scalar;
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int Kraichnan_scalar_v1<rnumber>::do_stats()
+{
+    TIMEZONE("Kraichnan_scalar_v1::do_stats");
+    if (!(this->iteration % this->niter_stat == 0))
+        return EXIT_SUCCESS;
+    hid_t stat_group;
+    if (this->myrank == 0)
+        stat_group = H5Gopen(
+                this->stat_file,
+                "statistics",
+                H5P_DEFAULT);
+    else
+        stat_group = 0;
+
+    *(this->tscal0) = *(this->scalar);
+
+    this->tscal0->compute_stats(
+            this->kk,
+            stat_group,
+            "scalar",
+            this->iteration / niter_stat,
+            max_value_estimate);
+
+    if (this->myrank == 0)
+        H5Gclose(stat_group);
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int Kraichnan_scalar_v1<rnumber>::read_parameters(void)
+{
+    TIMEZONE("Kraichnan_scalar_v1::read_parameters");
+    this->direct_numerical_simulation::read_parameters();
+    hid_t parameter_file = H5Fopen((this->simname + ".h5").c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
+    this->nu = hdf5_tools::read_value<double>(parameter_file, "parameters/nu");
+    this->dt = hdf5_tools::read_value<double>(parameter_file, "parameters/dt");
+    this->histogram_bins = hdf5_tools::read_value<int>(parameter_file, "parameters/histogram_bins");
+    this->max_value_estimate = hdf5_tools::read_value<double>(parameter_file, "parameters/max_value_estimate");
+    this->fftw_plan_rigor = hdf5_tools::read_string(parameter_file, "parameters/fftw_plan_rigor");
+
+    this->spectrum_dissipation = hdf5_tools::read_value<double>(parameter_file, "parameters/spectrum_dissipation");
+    this->spectrum_Lint = hdf5_tools::read_value<double>(parameter_file, "parameters/spectrum_Lint");
+    this->spectrum_etaK = hdf5_tools::read_value<double>(parameter_file, "parameters/spectrum_etaK");
+    this->spectrum_large_scale_const = hdf5_tools::read_value<double>(parameter_file, "parameters/spectrum_large_scale_const");
+    this->spectrum_small_scale_const = hdf5_tools::read_value<double>(parameter_file, "parameters/spectrum_small_scale_const");
+    this->random_seed = hdf5_tools::read_value<int>(parameter_file, "/parameters/field_random_seed");
+    H5Fclose(parameter_file);
+    return EXIT_SUCCESS;
+}
+
+template class Kraichnan_scalar_v1<float>;
+template class Kraichnan_scalar_v1<double>;
+
diff --git a/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp b/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp
new file mode 100644
index 00000000..e57735cd
--- /dev/null
+++ b/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp
@@ -0,0 +1,80 @@
+/**********************************************************************
+*                                                                     *
+*  Copyright 2017 Max Planck Institute                                *
+*                 for Dynamics and Self-Organization                  *
+*                                                                     *
+*  This file is part of bfps.                                         *
+*                                                                     *
+*  bfps 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.                             *
+*                                                                     *
+*  bfps 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 bfps.  If not, see <http://www.gnu.org/licenses/>       *
+*                                                                     *
+* Contact: Cristian.Lalescu@ds.mpg.de                                 *
+*                                                                     *
+**********************************************************************/
+
+
+
+#ifndef SCALAR_EVOLUTION_HPP
+#define SCALAR_EVOLUTION_HPP
+
+
+
+#include <cstdlib>
+#include "base.hpp"
+#include "full_code/direct_numerical_simulation.hpp"
+
+template <typename rnumber>
+class Kraichnan_scalar_v1: public direct_numerical_simulation
+{
+    public:
+
+        /* parameters that are read in read_parameters */
+        double dt;
+        int histogram_bins;
+        double max_value_estimate;
+        double nu;
+        std::string fftw_plan_rigor;
+
+        int random_seed;
+        double spectrum_dissipation;
+        double spectrum_Lint;
+        double spectrum_etaK;
+        double spectrum_large_scale_const;
+        double spectrum_small_scale_const;
+
+        /* other stuff */
+        field<rnumber, FFTW, ONE> *scalar;
+        field<rnumber, FFTW, ONE> *tscal0;
+        field<rnumber, FFTW, ONE> *ux, *uy, *uz;
+        kspace<FFTW, SMOOTH> *kk;
+
+
+        Kraichnan_scalar_v1(
+                const MPI_Comm COMMUNICATOR,
+                const std::string &simulation_name):
+            direct_numerical_simulation(
+                    COMMUNICATOR,
+                    simulation_name){}
+        ~Kraichnan_scalar_v1(){}
+
+        int initialize(void);
+        int step(void);
+        int finalize(void);
+
+        virtual int read_parameters(void);
+        int write_checkpoint(void);
+        int do_stats(void);
+};
+
+#endif//SCALAR_EVOLUTION_HPP
+
diff --git a/setup.py b/setup.py
index 21dc139f..a4f43074 100644
--- a/setup.py
+++ b/setup.py
@@ -82,6 +82,8 @@ setup(
                                    'test/particle_set/NSVEparticle_set.cpp',
                                    'test/profiler/scalar_evolution.hpp',
                                    'test/profiler/scalar_evolution.cpp',
+                                   'test/profiler/Kraichnan_scalar_v1.hpp',
+                                   'test/profiler/Kraichnan_scalar_v1.cpp',
                                    ]},
         entry_points = {
             'console_scripts': [
-- 
GitLab