Skip to content
Snippets Groups Projects
Gauss_field_test.cpp 7.49 KiB
/**********************************************************************
*                                                                     *
*  Copyright 2019 Max Planck Institute                                *
*                 for Dynamics and Self-Organization                  *
*                                                                     *
*  This file is part of TurTLE.                                       *
*                                                                     *
*  TurTLE 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.                             *
*                                                                     *
*  TurTLE 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 TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
*                                                                     *
* Contact: Cristian.Lalescu@ds.mpg.de                                 *
*                                                                     *
**********************************************************************/



#include <string>
#include <cmath>
#include <random>
#include "Gauss_field_test.hpp"
#include "scope_timer.hpp"



template <typename rnumber,
          field_backend be,
          field_components fc,
          kspace_dealias_type dt>
int make_gaussian_random_field(
        kspace<be, dt> *kk,
        field<rnumber, be, fc> *output_field,
        const int rseed,
        const double slope,
        const double k_cutoff,
        const double coefficient)
{
    TIMEZONE("make_gaussian_random_field");
    // initialize a separate random number generator for each thread
    std::vector<std::mt19937_64> rgen;
    std::uniform_real_distribution<rnumber> rdist;
    rgen.resize(omp_get_max_threads());
    // seed random number generators such that no seed is ever repeated if we change the value of rseed.
    // basically use a multi-dimensional array indexing technique to come up with actual seed.
    for (int thread_id=0; thread_id < omp_get_max_threads(); thread_id++)
    {
        int current_seed = (
                rseed*omp_get_max_threads()*output_field->clayout->nprocs +
                output_field->clayout->myrank*omp_get_max_threads() +
                thread_id);
        DEBUG_MSG("in make_gaussian_random_field, thread_id = %d, current_seed = %d\n", thread_id, current_seed);
        rgen[thread_id].seed(current_seed);
    }
    output_field->real_space_representation = false;
    *output_field = 0.0;
    // inside loop use only thread-local random number generator
    kk->CLOOP_K2([&](
                ptrdiff_t cindex,
                ptrdiff_t xindex,
                ptrdiff_t yindex,
                ptrdiff_t zindex,
                double k2)
                    {
                    if (k2 > 0)
                    switch(fc)
                    {
                    case ONE:
                    {
                        double temp_phase = 2*M_PI*rdist(rgen[omp_get_thread_num()]);
                        output_field->cval(cindex,0) = coefficient * cos(temp_phase) * pow(k2, slope/4.) * exp(- sqrt(k2)/k_cutoff/2.);
                        output_field->cval(cindex,1) = coefficient * sin(temp_phase) * pow(k2, slope/4.) * exp(- sqrt(k2)/k_cutoff/2.);
                        break;
                    }
                    case THREE:
                    for (int cc = 0; cc<3; cc++)
                    {
                        double temp_phase = 2*M_PI*rdist(rgen[omp_get_thread_num()]);
                        output_field->cval(cindex,cc,0) = coefficient * cos(temp_phase) * pow(k2, slope/4.) * exp(- sqrt(k2)/k_cutoff/2.);
                        output_field->cval(cindex,cc,1) = coefficient * sin(temp_phase) * pow(k2, slope/4.) * exp(- sqrt(k2)/k_cutoff/2.);
                    }
                        break;
                    case THREExTHREE:
                    for (int cc = 0; cc<3; cc++)
                    for (int ccc = 0; ccc<3; ccc++)
                    {
                        double temp_phase = 2*M_PI*rdist(rgen[omp_get_thread_num()]);
                        output_field->cval(cindex,cc,ccc,0) = coefficient * cos(temp_phase) * pow(k2, slope/4.) * exp(- sqrt(k2)/k_cutoff/2.);
                        output_field->cval(cindex,cc,ccc,1) = coefficient * sin(temp_phase) * pow(k2, slope/4.) * exp(- sqrt(k2)/k_cutoff/2.);
                    }
                        break;
                    }
            });
    output_field->symmetrize();

    return EXIT_SUCCESS;
}

template <typename rnumber>
int Gauss_field_test<rnumber>::initialize(void)
{
    TIMEZONE("Gauss_field_test::initialize");
    this->read_parameters();
    this->scalar_field = new field<rnumber, FFTW, ONE>(
            nx, ny, nz,
            this->comm,
            FFTW_ESTIMATE);
    this->vector_field = new field<rnumber, FFTW, THREE>(
            nx, ny, nz,
            this->comm,
            FFTW_ESTIMATE);
    this->kk = new kspace<FFTW, SMOOTH>(
            this->scalar_field->clayout, this->dkx, this->dky, this->dkz);

    if (this->myrank == 0)
    {
        hid_t stat_file = H5Fopen(
                (this->simname + std::string(".h5")).c_str(),
                H5F_ACC_RDWR,
                H5P_DEFAULT);
        this->kk->store(stat_file);
        H5Fclose(stat_file);
    }
    return EXIT_SUCCESS;
}

template <typename rnumber>
int Gauss_field_test<rnumber>::finalize(void)
{
    TIMEZONE("Gauss_field_test::finalize");
    delete this->vector_field;
    delete this->scalar_field;
    delete this->kk;
    return EXIT_SUCCESS;
}

template <typename rnumber>
int Gauss_field_test<rnumber>::read_parameters()
{
    TIMEZONE("Gauss_field_test::read_parameters");
    this->test::read_parameters();
    hid_t parameter_file = H5Fopen(
            (this->simname + std::string(".h5")).c_str(),
            H5F_ACC_RDONLY,
            H5P_DEFAULT);
    this->filter_length = hdf5_tools::read_value<double>(parameter_file, "/parameters/filter_length");
    H5Fclose(parameter_file);
    return EXIT_SUCCESS;
}

template <typename rnumber>
int Gauss_field_test<rnumber>::do_work(void)
{
    TIMEZONE("Gauss_field_test::do_work");
    make_gaussian_random_field(this->kk, this->scalar_field);
    make_gaussian_random_field(this->kk, this->vector_field, 3);
    DEBUG_MSG("L2norm = %g\n", this->vector_field->L2norm(this->kk));
    this->kk->template project_divfree<rnumber>(this->vector_field->get_cdata(), true);
    DEBUG_MSG("L2norm = %g\n", this->vector_field->L2norm(this->kk));
    this->kk->template project_divfree<rnumber>(this->vector_field->get_cdata());
    DEBUG_MSG("L2norm = %g\n", this->vector_field->L2norm(this->kk));
    make_gaussian_random_field(this->kk, this->vector_field, 3);
    DEBUG_MSG("L2norm = %g\n", this->vector_field->L2norm(this->kk));
    this->kk->template project_divfree<rnumber>(this->vector_field->get_cdata());
    DEBUG_MSG("L2norm = %g\n", this->vector_field->L2norm(this->kk));
    return EXIT_SUCCESS;
}

template class Gauss_field_test<float>;
template class Gauss_field_test<double>;