<commit_before>// Copyright (c) 2013-2015 <NAME>, <NAME>
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
// 
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/** \file simulation.h
 *   
 *  \brief Contains definition and implementation of Simulation_parameters and Simulation_context classes.
 */

#ifndef __SIMULATION_CONTEXT_H__
#define __SIMULATION_CONTEXT_H__

#include "simulation_parameters.h"
#include "mpi_grid.h"
#include "step_function.h"
#include "real_space_prj.h"
#include "version.h"
#include "debug.hpp"

namespace sirius {

class Simulation_context
{
    private:

        /// Parameters of simulcaiton.
        Simulation_parameters parameters_; 
    
        /// Communicator for this simulation.
        Communicator comm_;

        /// MPI grid for this simulation.
        MPI_grid* mpi_grid_;
        
        /// Unit cell of the simulation.
        Unit_cell unit_cell_;

        /// Reciprocal lattice of the unit cell.
        Reciprocal_lattice* reciprocal_lattice_;

        /// Step function is used in full-potential methods.
        Step_function* step_function_;

        /// FFT wrapper for dense grid.
        std::vector<FFT3D*> fft_;

        Gvec gvec_;

        /// FFT wrapper for coarse grid.
        std::vector<FFT3D*> fft_coarse_;

        Gvec gvec_coarse_;

        int gpu_thread_id_;

        Real_space_prj* real_space_prj_;

        /// Creation time of the context.
        timeval start_time_;

        std::string start_time_tag_;

        double iterative_solver_tolerance_;

        ev_solver_t std_evp_solver_type_;

        ev_solver_t gen_evp_solver_type_;

        double time_active_;
        
        bool initialized_;

    public:
        
        Simulation_context(Simulation_parameters const& parameters__,
                           Communicator const& comm__)
            : parameters_(parameters__),
              comm_(comm__),
              unit_cell_(parameters_, comm_),
              reciprocal_lattice_(nullptr),
              step_function_(nullptr),
              real_space_prj_(nullptr),
              iterative_solver_tolerance_(parameters_.iterative_solver_input_section().tolerance_),
              std_evp_solver_type_(ev_lapack),
              gen_evp_solver_type_(ev_lapack),
              initialized_(false)
        {
            PROFILE();

            gettimeofday(&start_time_, NULL);
            
            tm const* ptm = localtime(&start_time_.tv_sec); 
            char buf[100];
            strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", ptm);
            start_time_tag_ = std::string(buf);

            unit_cell_.import(parameters_.unit_cell_input_section());

        }

        ~Simulation_context()
        {
            PROFILE();

            time_active_ += Utils::current_time();

            if (Platform::rank() == 0)
            {
                printf("Simulation_context active time: %.4f sec.\n", time_active_);
            }

            for (auto obj: fft_) delete obj;
            for (auto obj: fft_coarse_) delete obj;
            if (reciprocal_lattice_ != nullptr) delete reciprocal_lattice_;
            if (step_function_ != nullptr) delete step_function_;
            if (real_space_prj_ != nullptr) delete real_space_prj_;
            delete mpi_grid_;
        }

        /// Initialize the similation (can only be called once).
        void initialize()
        {
            PROFILE();

            if (initialized_) TERMINATE("Simulation context is already initialized.");
            
            /* check if we can use a GPU device */
            if (parameters_.processing_unit() == GPU)
            {
                #ifndef __GPU
                TERMINATE_NO_GPU
                #endif
            }

            switch (parameters_.esm_type())
            {
                case full_potential_lapwlo:
                {
                    break;
                }
                case full_potential_pwlo:
                {
                    parameters_.set_lmax_pw(parameters_.lmax_apw());
                    parameters_.set_lmax_apw(-1);
                    break;
                }
                case ultrasoft_pseudopotential:
                case norm_conserving_pseudopotential:
                {
                    parameters_.set_lmax_apw(-1);
                    parameters_.set_lmax_rho(-1);
                    parameters_.set_lmax_pot(-1);
                    break;
                }
            }

            /* check MPI grid dimensions and set a default grid if needed */
            auto mpi_grid_dims = parameters_.mpi_grid_dims();
            if (!mpi_grid_dims.size()) 
            {
                mpi_grid_dims = std::vector<int>(1);
                mpi_grid_dims[0] = comm_.size();
            }
            parameters_.set_mpi_grid_dims(mpi_grid_dims);

            /* setup MPI grid */
            mpi_grid_ = new MPI_grid(mpi_grid_dims, comm_);

            /* initialize variables, related to the unit cell */
            unit_cell_.initialize();

            #ifdef __PRINT_MEMORY_USAGE
            MEMORY_USAGE_INFO();
            #endif

            if (comm_.rank() == 0)
            {
                unit_cell_.write_cif();
                unit_cell_.write_json();
            }

            parameters_.set_lmax_beta(unit_cell_.lmax_beta());

            auto rlv = unit_cell_.reciprocal_lattice_vectors();

            int nfft_threads = parameters_.num_fft_threads();
            int nfft_workers = parameters_.num_fft_workers();

            bool do_parallel_fft = false; //parameters_.full_potential() || mpi_grid_->dimension_size(_dim_row_) == 1)

            if (do_parallel_fft)
            {
                nfft_workers *= nfft_threads;
                nfft_threads = 1;
            }

            gpu_thread_id_ = -1;
            if (nfft_threads > 1) gpu_thread_id_ = nfft_threads - 1;

            for (int tid = 0; tid < nfft_threads; tid++)
            {
                /* in case of parallel FFT */
                if (do_parallel_fft)
                {
                    fft_.push_back(new FFT3D(Utils::find_translation_limits(parameters_.pw_cutoff(), rlv),
                                             nfft_workers, mpi_grid_->communicator(1 << _dim_row_), CPU));
                    if (!parameters_.full_potential())
                    {
                        fft_coarse_.push_back(new FFT3D(Utils::find_translation_limits(2 * parameters_.gk_cutoff(), rlv),
                                                        nfft_workers, mpi_grid_->communicator(1 << _dim_row_), CPU));
                    }
                }
                else /* serial FFT driver */
                {
                    if (tid == gpu_thread_id_)
                    {
                        fft_.push_back(new FFT3D(Utils::find_translation_limits(parameters_.pw_cutoff(), rlv),
                                                 nfft_workers, MPI_COMM_SELF, parameters_.processing_unit()));
                    }
                    else
                    {
                        fft_.push_back(new FFT3D(Utils::find_translation_limits(parameters_.pw_cutoff(), rlv),
                                                 nfft_workers, MPI_COMM_SELF, CPU));
                    }
                    if (!parameters_.full_potential())
                    {
                        if (tid == gpu_thread_id_)
                        {
                            fft_coarse_.push_back(new FFT3D(Utils::find_translation_limits(2 * parameters_.gk_cutoff(), rlv),
                                                            nfft_workers, MPI_COMM_SELF, parameters_.processing_unit()));
                        }
                        else
                        {
                            fft_coarse_.push_back(new FFT3D(Utils::find_translation_limits(2 * parameters_.gk_cutoff(), rlv),
                                                            nfft_workers, MPI_COMM_SELF, CPU));
                        }
                    }
                }
            }

            /* create a list of G-vectors for dense FFT grid */
            gvec_ = Gvec(vector3d<double>(0, 0, 0), parameters_.pw_cutoff(), rlv, fft_[0], true);

            if (!parameters_.full_potential())
            {
                /* create a list of G-vectors for corase FFT grid */
                gvec_coarse_ = Gvec(vector3d<double>(0, 0, 0), parameters_.gk_cutoff() * 2, rlv, fft_coarse_[0], false);
            }

            #ifdef __PRINT_MEMORY_USAGE
            MEMORY_USAGE_INFO();
            #endif
    
            if (unit_cell_.num_atoms() != 0) unit_cell_.symmetry()->check_gvec_symmetry(gvec_);

            /* create a reciprocal lattice */
            int lmax = -1;<commit_msg>cleaning mpi_comm interface<commit_after>// Copyright (c) 2013-2015 <NAME>, <NAME>
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
// 
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/** \file simulation.h
 *   
 *  \brief Contains definition and implementation of Simulation_parameters and Simulation_context classes.
 */

#ifndef __SIMULATION_CONTEXT_H__
#define __SIMULATION_CONTEXT_H__

#include "simulation_parameters.h"
#include "mpi_grid.h"
#include "step_function.h"
#include "real_space_prj.h"
#include "version.h"
#include "debug.hpp"

namespace sirius {

class Simulation_context
{
    private:

        /// Parameters of simulcaiton.
        Simulation_parameters parameters_; 
    
        /// Communicator for this simulation.
        Communicator const& comm_;

        /// MPI grid for this simulation.
        MPI_grid* mpi_grid_;
        
        /// Unit cell of the simulation.
        Unit_cell unit_cell_;

        /// Reciprocal lattice of the unit cell.
        Reciprocal_lattice* reciprocal_lattice_;

        /// Step function is used in full-potential methods.
        Step_function* step_function_;

        /// FFT wrapper for dense grid.
        std::vector<FFT3D*> fft_;

        Gvec gvec_;

        /// FFT wrapper for coarse grid.
        std::vector<FFT3D*> fft_coarse_;

        Gvec gvec_coarse_;

        int gpu_thread_id_;

        Real_space_prj* real_space_prj_;

        /// Creation time of the context.
        timeval start_time_;

        std::string start_time_tag_;

        double iterative_solver_tolerance_;

        ev_solver_t std_evp_solver_type_;

        ev_solver_t gen_evp_solver_type_;

        double time_active_;
        
        bool initialized_;

    public:
        
        Simulation_context(Simulation_parameters const& parameters__,
                           Communicator const& comm__)
            : parameters_(parameters__),
              comm_(comm__),
              unit_cell_(parameters_, comm_),
              reciprocal_lattice_(nullptr),
              step_function_(nullptr),
              real_space_prj_(nullptr),
              iterative_solver_tolerance_(parameters_.iterative_solver_input_section().tolerance_),
              std_evp_solver_type_(ev_lapack),
              gen_evp_solver_type_(ev_lapack),
              initialized_(false)
        {
            PROFILE();

            gettimeofday(&start_time_, NULL);
            
            tm const* ptm = localtime(&start_time_.tv_sec); 
            char buf[100];
            strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", ptm);
            start_time_tag_ = std::string(buf);

            unit_cell_.import(parameters_.unit_cell_input_section());

        }

        ~Simulation_context()
        {
            PROFILE();

            time_active_ += Utils::current_time();

            if (Platform::rank() == 0)
            {
                printf("Simulation_context active time: %.4f sec.\n", time_active_);
            }

            for (auto obj: fft_) delete obj;
            for (auto obj: fft_coarse_) delete obj;
            if (reciprocal_lattice_ != nullptr) delete reciprocal_lattice_;
            if (step_function_ != nullptr) delete step_function_;
            if (real_space_prj_ != nullptr) delete real_space_prj_;
            delete mpi_grid_;
        }

        /// Initialize the similation (can only be called once).
        void initialize()
        {
            PROFILE();

            if (initialized_) TERMINATE("Simulation context is already initialized.");
            
            /* check if we can use a GPU device */
            if (parameters_.processing_unit() == GPU)
            {
                #ifndef __GPU
                TERMINATE_NO_GPU
                #endif
            }

            switch (parameters_.esm_type())
            {
                case full_potential_lapwlo:
                {
                    break;
                }
                case full_potential_pwlo:
                {
                    parameters_.set_lmax_pw(parameters_.lmax_apw());
                    parameters_.set_lmax_apw(-1);
                    break;
                }
                case ultrasoft_pseudopotential:
                case norm_conserving_pseudopotential:
                {
                    parameters_.set_lmax_apw(-1);
                    parameters_.set_lmax_rho(-1);
                    parameters_.set_lmax_pot(-1);
                    break;
                }
            }

            /* check MPI grid dimensions and set a default grid if needed */
            auto mpi_grid_dims = parameters_.mpi_grid_dims();
            if (!mpi_grid_dims.size()) 
            {
                mpi_grid_dims = std::vector<int>(1);
                mpi_grid_dims[0] = comm_.size();
            }
            parameters_.set_mpi_grid_dims(mpi_grid_dims);

            /* setup MPI grid */
            mpi_grid_ = new MPI_grid(mpi_grid_dims, comm_);

            /* initialize variables, related to the unit cell */
            unit_cell_.initialize();

            #ifdef __PRINT_MEMORY_USAGE
            MEMORY_USAGE_INFO();
            #endif

            if (comm_.rank() == 0)
            {
                unit_cell_.write_cif();
                unit_cell_.write_json();
            }

            parameters_.set_lmax_beta(unit_cell_.lmax_beta());

            auto rlv = unit_cell_.reciprocal_lattice_vectors();

            int nfft_threads = parameters_.num_fft_threads();
            int nfft_workers = parameters_.num_fft_workers();

            bool do_parallel_fft = false; //parameters_.full_potential() || mpi_grid_->dimension_size(_dim_row_) == 1)

            if (do_parallel_fft)
            {
                nfft_workers *= nfft_threads;
                nfft_threads = 1;
            }

            gpu_thread_id_ = -1;
            if (nfft_threads > 1) gpu_thread_id_ = nfft_threads - 1;

            for (int tid = 0; tid < nfft_threads; tid++)
            {
                /* in case of parallel FFT */
                if (do_parallel_fft)
                {
                    fft_.push_back(new FFT3D(Utils::find_translation_limits(parameters_.pw_cutoff(), rlv),
                                             nfft_workers, mpi_grid_->communicator(1 << _dim_row_), CPU));
                    if (!parameters_.full_potential())
                    {
                        fft_coarse_.push_back(new FFT3D(Utils::find_translation_limits(2 * parameters_.gk_cutoff(), rlv),
                                                        nfft_workers, mpi_grid_->communicator(1 << _dim_row_), CPU));
                    }
                }
                else /* serial FFT driver */
                {
                    if (tid == gpu_thread_id_)
                    {
                        fft_.push_back(new FFT3D(Utils::find_translation_limits(parameters_.pw_cutoff(), rlv),
                                                 nfft_workers, mpi_comm_self, parameters_.processing_unit()));
                    }
                    else
                    {
                        fft_.push_back(new FFT3D(Utils::find_translation_limits(parameters_.pw_cutoff(), rlv),
                                                 nfft_workers, mpi_comm_self, CPU));
                    }
                    if (!parameters_.full_potential())
                    {
                        if (tid == gpu_thread_id_)
                        {
                            fft_coarse_.push_back(new FFT3D(Utils::find_translation_limits(2 * parameters_.gk_cutoff(), rlv),
                                                            nfft_workers, mpi_comm_self, parameters_.processing_unit()));
                        }
                        else
                        {
                            fft_coarse_.push_back(new FFT3D(Utils::find_translation_limits(2 * parameters_.gk_cutoff(), rlv),
                                                            nfft_workers, mpi_comm_self, CPU));
                        }
                    }
                }
            }

            /* create a list of G-vectors for dense FFT grid */
            gvec_ = Gvec(vector3d<double>(0, 0, 0), parameters_.pw_cutoff(), rlv, fft_[0], true);

            if (!parameters_.full_potential())
            {
                /* create a list of G-vectors for corase FFT grid */
                gvec_coarse_ = Gvec(vector3d<double>(0, 0, 0), parameters_.gk_cutoff() * 2, rlv, fft_coarse_[0], false);
            }

            #ifdef __PRINT_MEMORY_USAGE
            MEMORY_USAGE_INFO();
            #endif
    
            if (unit_cell_.num_atoms() != 0) unit_cell_.symmetry()->check_gvec_symmetry(gvec_);

            /* create a reciprocal lattice */
            int lmax = -1;
{'fraction_non_alphanumeric': 0.08250262986525071, 'fraction_numerical': 0.005410008515754145, 'mean_word_length': 1.5994791666666666, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5076472', 'n_tokens_mistral': 5601, 'n_tokens_neox': 5153, 'n_words': 1272}