/******************************************************************************
 * @internal
 * @file        rCFD_defaults.h
 * @copyright   (C) 2021
 *              Particulate Flow Modelling,
 *              Johannes Kepler University, Linz, Austria
 * @website     www.particulate-flow.at
 * @authors     Stefan Pirker
 *****************************************************************************/

#ifndef RCFD_DEFAULTS
#define RCFD_DEFAULTS

#include "rCFD.h"
#if defined(_WIN32) || defined(_WIN64)
#include <direct.h>
#define CREATE_DIR(path, mode) _mkdir(path)
#else
#include <sys/stat.h>
#define CREATE_DIR(path, mode) mkdir(path, mode)
#endif
#include "rCFD_macros.h"
#include "rCFD_types.h"
#include "rCFD_memory.h"

#include <time.h>
#include <stdio.h>
#include <stdlib.h>


    void default_Report(rCFD_type* rcfd)
    {
        rcfd->Report->timing_on         = 1;
        rcfd->Report->file_output_on    = 1;
        rcfd->Report->console_output_on = 1;
        rcfd->Report->fflush_on         = 1;
        rcfd->Report->file_is_open      = 0;
        rcfd->Report->file0_is_open     = 0;
        rcfd->Report->priority          = RCFD_REPORT_NOTSET;
        rcfd->Report->report_file       = NULL;
#if !defined(RCFD_LIB_MPI)
        rcfd->Report->report_file0      = NULL;
#endif
        rcfd->Report->time_unit         = RCFD_TIMER_SEC;
        rcfd->Report->ticks_2_time_unit = 1.0/CLOCKS_PER_SEC;
        rcfd->Report->number_of_reports = malloc_i_2d(RCFD_REPORT_CATEGORY_MAX, RCFD_REPORT_MAX);
        memset(rcfd->Report->number_of_reports[0], 0, RCFD_REPORT_CATEGORY_MAX * RCFD_REPORT_MAX * sizeof(int));
        memset(rcfd->Report->timers, 0, RCFD_TIMER_MAX * sizeof(Timer_type*));
    }


    /* A. default Dicts */

    void default_Solver_Dict(rCFD_type* rcfd)
    {
        rcfd->Solver_Dict->report_priority =  RCFD_REPORT_WARNING;

        rcfd->Solver_Dict->profiling_on =         1;
        rcfd->Solver_Dict->multifile_output_on =  0;

        rcfd->Solver_Dict->mode = RCFD_MODE_RUN;

        rcfd->Solver_Dict->number_of_frames =     1;
        rcfd->Solver_Dict->number_of_states =     1;
        rcfd->Solver_Dict->number_of_phases =     1;
        rcfd->Solver_Dict->number_of_islands =    1;
        rcfd->Solver_Dict->number_of_layers =     1;
        rcfd->Solver_Dict->number_of_runs =       1;

        rcfd->Solver_Dict->recurrence_process_on =     1;
        rcfd->Solver_Dict->data_convection_on =        1;
        rcfd->Solver_Dict->face_swap_diffusion_on =    1;
        rcfd->Solver_Dict->local_diff_on =             0;
        rcfd->Solver_Dict->parallel_diffusion_on =     1;
        rcfd->Solver_Dict->data_binarization_on =      0;
        rcfd->Solver_Dict->data_drifting_on =          0;
        rcfd->Solver_Dict->balance_correction_on =     1;
        rcfd->Solver_Dict->on_the_fly_post_on =        1;
        rcfd->Solver_Dict->interpolation_on =          0;
        rcfd->Solver_Dict->shifts_from_displacement_fields_on = 0;

        rcfd->Solver_Dict->max_number_of_cells_per_time_step = 10;

        rcfd->Solver_Dict->time_steps_per_monitoring_interval =   10;
        rcfd->Solver_Dict->start_time_for_monitoring =            0.0;

        rcfd->Solver_Dict->single_phase_vof     = 0;
        rcfd->Solver_Dict->single_phase_vof_id  = 0;
        rcfd->Solver_Dict->vof_cutoff_limit     = 1.0e-4;

        rcfd->Solver_Dict->min_number_of_cells_per_layer =     100;
        rcfd->Solver_Dict->max_number_of_faces_per_cell =      100;
        rcfd->Solver_Dict->max_number_of_children =            100;
        rcfd->Solver_Dict->number_redist_loops_per_layer =     5;
   
        rcfd->Solver_Dict->C2C_loading_reduction = 1;

        rcfd->Solver_Dict->global_time_step = 1.0;

        rcfd->Solver_Dict->max_fill_loops =   10;

        rcfd->Solver_Dict->face_swap_max_per_loop =   (1./8.);
        rcfd->Solver_Dict->face_swap_min =            (1./64.);
        rcfd->Solver_Dict->face_swap_max_loops =      4;
        rcfd->Solver_Dict->local_diff_format =        RCFD_LOCAL_DIFF_VISCOSITY_BASED;

        rcfd->Solver_Dict->number_of_drift_loops =    1;

        rcfd->Solver_Dict->balance_correction_update = 1;
        rcfd->Solver_Dict->control_conc_sum_on = 1;
    }

    void default_File_Dict(rCFD_type* rcfd)
    {
        /* Node-0 generates folder structure */
        if(myid == 0){

            int directory_error_indicator = 0;

            directory_error_indicator += CREATE_DIR("./data",0777);
            directory_error_indicator += CREATE_DIR("./data/tmp",0777);
            directory_error_indicator += CREATE_DIR("./data/vof",0777);
            directory_error_indicator += CREATE_DIR("./data/topo",0777);
            directory_error_indicator += CREATE_DIR("./data/local_diff",0777);
            directory_error_indicator += CREATE_DIR("./data/c2c",0777);
            directory_error_indicator += CREATE_DIR("./data/cal",0777);
            directory_error_indicator += CREATE_DIR("./data/rec",0777);
            directory_error_indicator += CREATE_DIR("./data/user",0777);
            directory_error_indicator += CREATE_DIR("./post",0777);

            if(directory_error_indicator != 0){

                report_warning0(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                "default_File_Dict: could not create all sub-directories (maybe because they already exist)");
            }
        }

        rcfd->File_Dict->tracer_start_position_filename = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->C2C_filename                   = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Prep_Transscript_filename      = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Run_Transscript_filename       = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Norm_filename                  = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->vof_filename                   = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->local_diff_filename            = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->rec_cal_filename               = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->rec_user_filename              = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Jump_filename                  = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Matrix_filename                = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->frame_id_filename              = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Balance_filename               = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Rec_Frames_filename            = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Topo_filename                  = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Dump_filename                  = (char*)malloc(32*sizeof(char));
        rcfd->File_Dict->Probe_filename                 = (char*)malloc(32*sizeof(char));

        strcpy(rcfd->File_Dict->tracer_start_position_filename, "./data/tmp/tracer_start_pos.inj");
        strcpy(rcfd->File_Dict->C2C_filename,                   "./data/c2c/c2c");
        strcpy(rcfd->File_Dict->Prep_Transscript_filename,      "./rCFD_prep.trn");
        strcpy(rcfd->File_Dict->Run_Transscript_filename,       "./rCFD_run.trn");
        strcpy(rcfd->File_Dict->Norm_filename,                  "./data/tmp/norm");
        strcpy(rcfd->File_Dict->vof_filename,                   "./data/vof/vof");
        strcpy(rcfd->File_Dict->local_diff_filename,            "./data/local_diff/local_diff");
        strcpy(rcfd->File_Dict->rec_cal_filename,               "./data/cal/cal");
        strcpy(rcfd->File_Dict->rec_user_filename,              "./data/user/rec_user");
        strcpy(rcfd->File_Dict->Jump_filename,                  "./data/rec/jump");
        strcpy(rcfd->File_Dict->Matrix_filename,                "./data/rec/matrix");
        strcpy(rcfd->File_Dict->frame_id_filename,              "./data/rec/frame_id");
        strcpy(rcfd->File_Dict->Balance_filename,               "./post/balance_monitor.out");
        strcpy(rcfd->File_Dict->Rec_Frames_filename,            "./post/rec_frames_monitor.out");
        strcpy(rcfd->File_Dict->Topo_filename,                  "./data/topo/topo");
        strcpy(rcfd->File_Dict->Dump_filename,                  "./post/dump");
        strcpy(rcfd->File_Dict->Probe_filename,                 "./post/probes");
    }

    void default_Phase_Dict(rCFD_type* rcfd)
    {
#if RP_NODE
        int i_phase;

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            rcfd->Phase_Dict[i_phase].number_of_data = 1;

            rcfd->Phase_Dict[i_phase].number_of_concentration_data = 1;

            rcfd->Phase_Dict[i_phase].time_step = rcfd->Solver_Dict->global_time_step;

            rcfd->Phase_Dict[i_phase].shift_probability = 1.0;

            rcfd->Phase_Dict[i_phase].density = 1.0;

            rcfd->Phase_Dict[i_phase].heat_capacity = 1.0;

            rcfd->Phase_Dict[i_phase].reference_temperature = 300.0;

            rcfd->Phase_Dict[i_phase].vof_max = 1.0;

            rcfd->Phase_Dict[i_phase].hindered_drift_on = 0;

            rcfd->Phase_Dict[i_phase].local_drift_on = 0;

            rcfd->Phase_Dict[i_phase].drift_control_conc_sum_on = 1;

            rcfd->Phase_Dict[i_phase].d32_diam = 1.0;

            rcfd->Phase_Dict[i_phase].number_of_user_vars = 0;

            rcfd->Phase_Dict[i_phase].user = NULL;
        }
#endif
    }

    void default_Tracer_Dict(rCFD_type* rcfd)
    {
#if RP_NODE

        rcfd->Tracer_Dict->format = RCFD_TRACER_FORCE_GUIDED;

        rcfd->Tracer_Dict->number_of_Tracers_per_cell = 1;

        rcfd->Tracer_Dict->region_of_interest_exists = 0;

        rcfd->Tracer_Dict->ROI_x_min = 0.0;
        rcfd->Tracer_Dict->ROI_x_max = 0.0;
        rcfd->Tracer_Dict->ROI_y_min = 0.0;
        rcfd->Tracer_Dict->ROI_y_max = 0.0;
        rcfd->Tracer_Dict->ROI_z_min = 0.0;
        rcfd->Tracer_Dict->ROI_z_max = 0.0;

        rcfd->Tracer_Dict->coarse_graining = 1;

        int i_phase;

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            rcfd->Tracer_Dict->random_walk[i_phase] = 0;
            rcfd->Tracer_Dict->random_walk_velocity_ratio[i_phase] = 0.1;
        }

        rcfd->Tracer_Dict->C2C_format = RCFD_SHIFT_C0_N0_C1_N1_W0;

        rcfd->Tracer_Dict->reverse_direction_on = 0;

        rcfd->Tracer_Dict->splitting_on = 1;

        rcfd->Tracer_Dict->avoid_information_lock_cells_on = 0;

        rcfd->Tracer_Dict->conservative_cross_partition_shifts_on = 0;

#endif
    }

    void default_Calibration_Dict(rCFD_type* rcfd)
    {
#if RP_NODE
        rcfd->Calibration_Dict->format = RCFD_INTERP_NEAREST_ALIGNED_NEIGHBOR_CELLS;

        rcfd->Calibration_Dict->max_number_of_aligned_neigh_cells = 100;

        rcfd->Calibration_Dict->calibration_parallel_on = 1;

        rcfd->Calibration_Dict->calibration_pruning_on = 0;

        rcfd->Calibration_Dict->calibration_min_shifts_after_pruning = 2;

        rcfd->Calibration_Dict->calibration_pruning_weight = 0.05;

        rcfd->Calibration_Dict->multiply_shift_weights_with_vof_on = 1;

        rcfd->Calibration_Dict->small = 1.0e-6;

        rcfd->Calibration_Dict->great = 1.0e10;
#endif
    }

    void default_Norm_Dict(rCFD_type* rcfd)
    {
#if RP_NODE
        rcfd->Norm_Dict->format = RCFD_NORM_DEFAULT;

        rcfd->Norm_Dict->coarse_graining = 1;

        rcfd->Norm_Dict->larger_than_mean_norm_only = 0;
#endif
    }

    void default_Rec_Dict(rCFD_type* rcfd)
    {
        rcfd->Rec_Dict->format = RCFD_REC_QUARTER_JUMPS;

        rcfd->Rec_Dict->monitor_rec_frames_on = 0;

        rcfd->Rec_Dict->seed = -1;

        // rcfd->Rec_Dict->adapt_vof_stitching_on
        {
            if((rcfd->Solver_Dict->number_of_phases > 1) || (rcfd->Solver_Dict->single_phase_vof)){

                rcfd->Rec_Dict->adapt_vof_stitching_on = 1;
            }
            else{

                rcfd->Rec_Dict->adapt_vof_stitching_on = 0;
            }

            rcfd->Rec_Dict->number_of_adapt_vof_loops = 1;
        }

        // rcfd->Rec_Dict->min/max_seq_length
        {
            rcfd->Rec_Dict->min_seq_length = (int)((double)rcfd->Solver_Dict->number_of_frames/25.);

            if(rcfd->Rec_Dict->min_seq_length < 1){

                rcfd->Rec_Dict->min_seq_length = 1;
            }

            rcfd->Rec_Dict->max_seq_length = (int)((double)rcfd->Solver_Dict->number_of_frames/4.);

            if(rcfd->Rec_Dict->max_seq_length < 1){

                rcfd->Rec_Dict->max_seq_length = 1;
            }
        }

        // rcfd->Rec_Dict->off_diagonal_band_width
        {
            rcfd->Rec_Dict->off_diagonal_band_width = (int)((double)rcfd->Solver_Dict->number_of_frames/10.);

            if(rcfd->Rec_Dict->off_diagonal_band_width < 1){

                rcfd->Rec_Dict->off_diagonal_band_width = 1;
            }
        }
        
        rcfd->Rec_Dict->frame_id_vector_length =   1;
        rcfd->Rec_Dict->frame_id_sequence_length = 3;
        rcfd->Rec_Dict->frame_id_target_sequence_count =           100;
        rcfd->Rec_Dict->frame_id_avoid_immediate_seq_repetition =  0;
		rcfd->Rec_Dict->frame_id_normalize_on =    0;
    }

    void default_Data_Dict(rCFD_type* rcfd)
    {
#if RP_NODE
        int i_phase, i_data, i_dim;

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            for(i_data = 0; i_data < rcfd->Phase_Dict[i_phase].number_of_data; i_data++){

                rcfd->Data_Dict[i_phase][i_data].type = RCFD_DATA_GENERIC;

                rcfd->Data_Dict[i_phase][i_data].face_swap_diffusion = 1./8.;

                rcfd->Data_Dict[i_phase][i_data].binarization_art_diff = 1./8.;

                rcfd->Data_Dict[i_phase][i_data].drifting_data = 0;

                if(rcfd->Solver_Dict->data_drifting_on){

                    rcfd->Data_Dict[i_phase][i_data].drift_velocity = (double*)malloc(3 * sizeof(double));

                    for(i_dim = 0; i_dim < 3; i_dim++){

                        rcfd->Data_Dict[i_phase][i_data].drift_velocity[i_dim] = 0.0;
                    }
                }
                else{

                    rcfd->Data_Dict[i_phase][i_data].drift_velocity = NULL;
                }

                rcfd->Data_Dict[i_phase][i_data].d1_diam = 1.0;

                rcfd->Data_Dict[i_phase][i_data].d2_diam = 1.0;

                rcfd->Data_Dict[i_phase][i_data].d3_diam = 1.0;

                rcfd->Data_Dict[i_phase][i_data].number_of_user_vars = 0;

                rcfd->Data_Dict[i_phase][i_data].user = NULL;
            }
        }
#endif
    }

    void default_Balance_Dict(rCFD_type* rcfd)
    {
#if RP_NODE
        int i_phase, i_data;

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            for(i_data = 0; i_data < rcfd->Phase_Dict[i_phase].number_of_data; i_data++){

                rcfd->Balance_Dict[i_phase][i_data].type = RCFD_BALANCE_GLOBAL;

                rcfd->Balance_Dict[i_phase][i_data].max_correction_loops = 10;

                rcfd->Balance_Dict[i_phase][i_data].accuracy_level = 0.01;

                rcfd->Balance_Dict[i_phase][i_data].write_balance_to_file = 1;

                rcfd->Balance_Dict[i_phase][i_data].write_balance_to_file_interval = 1;
            }
        }
#endif
    }

    void default_Topo_Dict(rCFD_type* rcfd)
    {
        rcfd->Topo_Dict->Cell_Dict = NULL;
        rcfd->Topo_Dict->Face_Dict = NULL;
        rcfd->Topo_Dict->Node_Dict = NULL;
    }

    void default_Cell_Dict(rCFD_type* rcfd)
    {
        int i_layer;

        // set Cell_Dict Vars
        for(i_layer = 0; i_layer < rcfd->Solver_Dict->number_of_layers; i_layer++){

            _CELL_DICT(i_layer).number_of_int_cells = 0;
            _CELL_DICT(i_layer).number_of_ext_cells = 0;
            _CELL_DICT(i_layer).number_of_cells = 0;

            _CELL_DICT(i_layer).number_of_user_vars = 0;
            _CELL_DICT(i_layer).number_of_rec_user_vars = 0;

            _CELL_DICT(i_layer).next_neigh_cell_skin_factor = 2.0;
        }

        // Note: must be set by user via user_set_cell_dict(rcfd, i_layer)
    }

    void default_Face_Dict(rCFD_type* rcfd)
    {
        int i_layer;

        // set Face_Dict vars
        for(i_layer = 0; i_layer < rcfd->Solver_Dict->number_of_layers; i_layer++){

            _FACE_DICT(i_layer).number_of_int_faces = 0;
            _FACE_DICT(i_layer).number_of_ext_faces = 0;
            _FACE_DICT(i_layer).number_of_faces = 0;
        }

        // Note: must be set by user via user_set_face_dict(rcfd, i_layer)
    }

    void default_Node_Dict(rCFD_type* rcfd)
    {
        int i_layer;

        // set Node_Dict vars
        for(i_layer = 0; i_layer < rcfd->Solver_Dict->number_of_layers; i_layer++){

            _NODE_DICT(i_layer).number_of_nodes = 0;
            _NODE_DICT(i_layer).number_of_int_node_references = 0;
            _NODE_DICT(i_layer).number_of_ext_node_references = 0;
        }
    }

    void default_Dump_Dict(rCFD_type* rcfd)
    {
#if RP_NODE
        int i_phase, i_data, i_user, i_layer = 0;

        rcfd->Dump_Dict->dump_interval = 0;

        rcfd->Dump_Dict->overwrite_interval = 0;

        rcfd->Dump_Dict->multifile_output_on = 0;

        rcfd->Dump_Dict->dump_file_type = RCFD_FILE_BINARY;

        rcfd->Dump_Dict->dump_vof = 0;

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            for(i_data = 0; i_data < rcfd->Phase_Dict[i_phase].number_of_data; i_data++){

                rcfd->Dump_Dict->dump_cell_data[i_phase][i_data] = 0;
            }
        }

        for(i_user = 0; i_user < _CELL_DICT(i_layer).number_of_user_vars; i_user++){

            rcfd->Dump_Dict->dump_user_data[i_user] = 0;
        }

        for(i_user = 0; i_user < _CELL_DICT(i_layer).number_of_rec_user_vars; i_user++){

            rcfd->Dump_Dict->dump_rec_user_data[i_user] = 0;
        }

        rcfd->Dump_Dict->probe_count = 0;
        rcfd->Dump_Dict->probe_interval = 0;
        rcfd->Dump_Dict->probe_layer = NULL;
        rcfd->Dump_Dict->probe_cell = NULL;
        rcfd->Dump_Dict->probe_type = NULL;
        rcfd->Dump_Dict->probe_phase = NULL;
        rcfd->Dump_Dict->probe_data = NULL;
        rcfd->Dump_Dict->probe_value = NULL;
        rcfd->Dump_Dict->probe_x = NULL;
#endif
    }

    /* B. default vars settings */

    void default_Solver(rCFD_type* rcfd)
    {
        rcfd->Solver->current_state = 0;

        rcfd->Solver->upcoming_state = 0;

        rcfd->Solver->current_layer = 0;

        rcfd->Solver->analyse_CFD_counter = 0;

        rcfd->Solver->displ_reset_counter = 0;

        rcfd->Solver->global_run_counter = 0;

        rcfd->Solver->timestep_width = (double*)malloc(rcfd->Solver_Dict->number_of_layers * sizeof(double));

        int i_layer;

        for(i_layer = 0; i_layer < rcfd->Solver_Dict->number_of_layers; i_layer++){

            rcfd->Solver->timestep_width[i_layer] = rcfd->Solver_Dict->global_time_step * (1 << i_layer);//pow(2.0, (double) i_layer);
        }

        rcfd->Solver->global_time = 0.0;

        rcfd->Solver->balance_file_opened = 0;

        rcfd->Solver->rec_frames_monitor_file_opened = 0;
        
    }

    void default_Topo(rCFD_type* rcfd)
    {
#if RP_NODE
        rcfd->Topo->Cell = NULL;
        rcfd->Topo->Face = NULL;
        rcfd->Topo->Node = NULL;
#endif
    }

    void default_Cell_L0(rCFD_type* rcfd)
    {
#if RP_NODE

#if 1   // local vars

        int     i_layer, i_phase, i_cell, i_frame, i_user, i_rec_user, i_data, i_tmp, i_dim;

#endif

        i_layer = 0;

        // Note: user must have set _C(i_layer).x, _C(i_layer).volume

        // Note: neigh_cells will be set later

        for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

            _C(i_layer).grid_spacing[i_cell] = pow(_C(i_layer).volume[i_cell], (1.0/3.0));
        }

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                _C(i_layer).average_velocity[i_phase][i_cell] =  0.0;
                _C(i_layer).crossing_time[i_phase][i_cell] =     0.0;
            }
        }

        for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

            _C(i_layer).hit_by_other_cell[i_cell] = 0;
            _C(i_layer).island_id[i_cell] = 0;

            _C(i_layer).weight_after_shift[i_cell] = 0.0;
            _C(i_layer).weight_after_swap[i_cell] =  0.0;
        }

        if(_C(i_layer).vof != NULL){

            if(rcfd->Solver_Dict->mode == RCFD_MODE_PREPARATION){

                i_frame = 0;
                i_phase = 0;

                for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                    _C(i_layer).vof[i_frame][i_cell][i_phase] = 1.0;
                }

                for(i_phase = 1; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                    for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                        _C(i_layer).vof[i_frame][i_cell][i_phase] = 0.0;
                    }
                }
            }
            else{ // run mode

                if((rcfd->Solver_Dict->number_of_phases == 1) && (rcfd->Solver_Dict->single_phase_vof == 0)){

                    i_phase = 0;

                    for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                        for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                            _C(i_layer).vof[i_frame][i_cell][i_phase] = 1.0;
                        }
                    }
                }
                else{   // multi-phase or single-phase with vof

                    int     i_state, i_tmp;
                    short   vof_file_exists = 1;
                    FILE    *f_in = NULL;
                    char    file_name[80];

                    i_state = 0;    // TODO multiple DBs

                    for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                        sprintf(file_name,"%s_%d_%d_%d", rcfd->File_Dict->vof_filename, i_state, i_phase, myid);

                        f_in = fopen(file_name, "r");

                        if(f_in == NULL){

                            for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                                for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                                    if(i_phase == 0){

                                        _C(i_layer).vof[i_frame][i_cell][i_phase] = 1.0;
                                    }
                                    else{

                                        _C(i_layer).vof[i_frame][i_cell][i_phase] = 0.0;
                                    }
                                }
                            }

                            vof_file_exists = 0;
                        }
                        // read vof field
                        else{

                            for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                                fscanf(f_in,"%d\n", &i_tmp);

                                if(i_tmp != _CELL_DICT(i_layer).number_of_cells){

                                    report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                                 "[%d] default_Cell: _C(i_layer).vof: i_tmp != _CELL_DICT(i_layer).number_of_cells ...", myid);
                                    return;
                                }

                                for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                                    fscanf(f_in,"%le\n", &_C(i_layer).vof[i_frame][i_cell][i_phase]);

                                    if((_C(i_layer).vof[i_frame][i_cell][i_phase] < 0.0) || (_C(i_layer).vof[i_frame][i_cell][i_phase] > 1.0)){

                                        report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                                     "[%d] i_frame %d i_cell %d i_phase %d vof %e",
                                                     myid, i_frame, i_cell, i_phase, _C(i_layer).vof[i_frame][i_cell][i_phase]);
                                        return;
                                    }
                                }
                            }

                            fclose(f_in);
                        }
                    }

                    vof_file_exists = PRF_GILOW1(vof_file_exists);

                    if(!vof_file_exists){

                        report_warning0(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                        "default_Cell_L0: at least one vof file doesn't exist");
                    }
                }
            }
        }

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                for(i_data = 0; i_data < rcfd->Phase_Dict[i_phase].number_of_data; i_data++){

                    _C(i_layer).data[i_phase][i_cell][i_data] =      0.0;
                    _C(i_layer).data_shift[i_phase][i_cell][i_data] = 0.0;
                    _C(i_layer).data_swap[i_phase][i_cell][i_data] =     0.0;
                }
            }
        }

        if(rcfd->Solver_Dict->local_diff_on){

            if(rcfd->Solver_Dict->mode == RCFD_MODE_PREPARATION){

                for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                    for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                        _C(i_layer).local_diff[0][i_phase][i_cell] = 0.0;
                    }
                }
            }
            else{   // run mode

                int     i_state;
                char    local_diff_filename[80];
                FILE    *f_local_diff = NULL;

                // read _C(i_layer).local_diff
                for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                    // open & check file
                    {
                        i_state = 0;    // TODO: How do we incorporate changes in operating conditions ?

                        sprintf(local_diff_filename,"%s_%d_%d_%d", rcfd->File_Dict->local_diff_filename, i_state, i_phase, myid);

                        f_local_diff = fopen(local_diff_filename, "r");

                        if(!f_local_diff){

                            report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                         "[%d] default_Cell_L0: could not open %s",
                                         myid, local_diff_filename);

                            return;
                        }
                    }

                    for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                        fscanf(f_local_diff, "%d \n", &i_tmp);

                        if(i_tmp != _CELL_DICT(i_layer).number_of_cells){

                            report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                         "[%d] default_Cell_L0: number of cells in %s does not match _Cell.Dict (%d %d - %d)",
                                         myid, local_diff_filename, i_tmp, _CELL_DICT(i_layer).number_of_cells, i_frame);
                            return;
                        }

                        for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                            fscanf(f_local_diff, "%le \n", &_C(i_layer).local_diff[i_frame][i_phase][i_cell]);

                            if(_C(i_layer).local_diff[i_frame][i_phase][i_cell] < 0.0){

                                report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                             "[%d] default_Cell_L0: _C(i_layer).local_diff < 0.0", myid);
                                return;
                            }
                        }
                    }

                    fclose( f_local_diff);
                }
            }
        }

        if(_C(i_layer).drift_exchange != NULL){

            for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                _C(i_layer).drift_exchange[i_cell] = 0.0;
            }
        }

        if(_C(i_layer).cfd_displ != NULL){

            for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                    for(i_dim = 0; i_dim < 3; i_dim++){

                        _C(i_layer).cfd_displ[i_phase][i_cell][i_dim] = 0.0;
                    }
                }
            }
        }

        if(_C(i_layer).cfd_diff != NULL){

            for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                    for(i_dim = 0; i_dim < 6; i_dim++){

                        _C(i_layer).cfd_diff[i_phase][i_cell][i_dim] = 0.0;
                    }
                }
            }
        }

        for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

            _C(i_layer).tmp[i_cell] = 0.0;
        }

        if(_C(i_layer).user != NULL){

            for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                for(i_user = 0; i_user < _CELL_DICT(i_layer).number_of_user_vars; i_user++){

                    _C(i_layer).user[i_cell][i_user] = 0.0;
                }
            }
        }

        if(_C(i_layer).rec_user != NULL){

            if(rcfd->Solver_Dict->mode == RCFD_MODE_PREPARATION){

                for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                    for(i_rec_user = 0; i_rec_user < _CELL_DICT(i_layer).number_of_rec_user_vars; i_rec_user++){

                        _C(i_layer).rec_user[0][i_cell][i_rec_user] = 0.0;
                    }
                }
            }
            else{   // run mode

                FILE    *f_in = NULL;
                char    file_name[80];

                // first initialization
                for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                    for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_cells; i_cell++){

                        for(i_rec_user = 0; i_rec_user < _CELL_DICT(i_layer).number_of_rec_user_vars; i_rec_user++){

                            _C(i_layer).rec_user[i_frame][i_cell][i_rec_user] = 0.0;
                        }
                    }
                }

                // open file
                {
                    sprintf(file_name,"%s_%d_%d", rcfd->File_Dict->rec_user_filename, rcfd->Solver->current_state, myid);

                    f_in = fopen(file_name, "r");

                    if(f_in == NULL){

                        report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                     "[%d] default_Cell_L0: failed to open file %s", myid, file_name);
                        return;
                    }
                }

                // read rec_user field
                {
                    for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                        fscanf(f_in, "%d\n", &i_tmp);

                        if(i_tmp != _CELL_DICT(i_layer).number_of_int_cells){

                            report_error(rcfd, RCFD_REPORT_CATEGORY_INITIALIZE,
                                         "[%d] default_Cell_L0: number of rec_user variables != _CELL_DICT(i_layer).number_of_int_cells", myid);
                            return;
                        }

                        for(i_cell = 0; i_cell < _CELL_DICT(i_layer).number_of_int_cells; i_cell++){

                            for(i_rec_user = 0; i_rec_user < _CELL_DICT(i_layer).number_of_rec_user_vars; i_rec_user++){

                                fscanf(f_in, "%lf ", &_C(i_layer).rec_user[i_frame][i_cell][i_rec_user]);
                            }

                            fscanf(f_in, "\n");
                        }
                    }
                }
            }
        }
#endif
    }

    void default_Face_L0(rCFD_type* rcfd)
    {
#if RP_NODE

#if 1   // local vars

        int     i_layer, i_phase, i_data, i_face;

#endif

        i_layer = 0;

        // Note: _F(i_layer).c0/c1 and _F(i_layer).area must be set by user

        // eventually, set _F(i_layer).local_drift_adaption
        if(rcfd->Solver_Dict->data_drifting_on){

            for(i_face = 0; i_face < _FACE_DICT(i_layer).number_of_faces; i_face++){

                for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){    // in order to reach max of i_data;

                    for(i_data = 0; i_data < rcfd->Phase_Dict[i_phase].number_of_data; i_data++){

                        _F(i_layer).local_drift_adaption[i_face][i_data] = 1.0;
                    }
                }
            }
        }
#endif
    }

    void default_Tracer(rCFD_type* rcfd)
    {
#if RP_NODE
        rcfd->Tracer->allocated =     0;
        rcfd->Tracer->initialized =   0;
        rcfd->Tracer->ready2write =   0;
        rcfd->Tracer->monitoring_started  = 0;

        rcfd->Tracer->frame_counter =     0;

        int     i_phase;

        for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

            rcfd->Tracer->monitor_counter[i_phase] =  0;

            rcfd->Tracer->number_of_shifts[i_phase] = 0;

            rcfd->Tracer->shifts[i_phase] = NULL;
        }

        if(rcfd->Solver_Dict->shifts_from_displacement_fields_on == 1){

            int i_layer = 0;

            for(i_phase = 0; i_phase < rcfd->Solver_Dict->number_of_phases; i_phase++){

                // each cell is hit only once and then max. three additional C2Cs are added by calibration
                rcfd->Tracer->number_of_shifts[i_phase] = 4 * _CELL_DICT(i_layer).number_of_int_cells;

                rcfd->Tracer->shifts[i_phase] = (C2C_shift_type*)malloc(rcfd->Tracer->number_of_shifts[i_phase] * sizeof(C2C_shift_type));
            }

            rcfd->Tracer->allocated = 1;
        }
#endif
    }

    void default_Norms(rCFD_type* rcfd)
    {
#if RP_NODE
        rcfd->Norms->frame_counter = 0;
#endif
    }

    void default_Rec(rCFD_type* rcfd)
    {
        rcfd->Rec->global_frame = 0;

        rcfd->Rec->prev_global_frame = 0;
        
        // set rcfd->Rec->global_frame_of_island, rcfd->Rec->prev_global_frame_of_island
        {
#ifdef RCFD_LIB_ISLANDS

            if(( rcfd->Rec->global_frame_of_island      != NULL) &&
               ( rcfd->Rec->prev_global_frame_of_island != NULL){

                for(i_island = 0; i_island < rcfd->Solver_Dict->number_of_islands; i_island++){

                    rcfd->Rec->global_frame_of_island      [i_island] = 0;
                    rcfd->Rec->prev_global_frame_of_island [i_island] = 0;
                }
            }
#endif
        }

        rcfd->Rec->frame_in_sequence = 0;

        // set rcfd->Rec->sequence_length
        {
            rcfd->Rec->sequence_length = rcfd->Rec_Dict->min_seq_length;

            if(rcfd->Rec_Dict->format == RCFD_REC_FRAME_ID){

                rcfd->Rec->sequence_length = rcfd->Rec_Dict->frame_id_sequence_length;
            }
        }

        rcfd->Rec->jumped_at_last_frame = 0;
        
        // read rcfd->Rec->jumps
        {
            if(rcfd->Rec->jumps != NULL){

                int i_state, i_state2, i_island, i_frame;

                int number_of_jump_files = 0;
            
                for(i_state = 0; i_state < rcfd->Solver_Dict->number_of_states; i_state++){

                    for(i_state2 = 0; i_state2 < rcfd->Solver_Dict->number_of_states; i_state2++){

                        for(i_island = 0; i_island < rcfd->Solver_Dict->number_of_islands; i_island++){

                            for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                                rcfd->Rec->jumps[i_state][i_state2][i_island][i_frame] = -1;
                            }

#if RP_HOST
                            char    filename[40];
                            FILE    *fi;

                            sprintf(filename,"%s_%d_%d_%d", rcfd->File_Dict->Jump_filename, i_state, i_state2, i_island);

                            fi = fopen(filename, "r");

                            if(fi != NULL){

                                for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                                    fscanf(fi, "%d \n", &rcfd->Rec->jumps[i_state][i_state2][i_island][i_frame]);
                                }

                                fclose(fi);

                                number_of_jump_files++;
                            }
#endif
                            for(i_frame = 0; i_frame < rcfd->Solver_Dict->number_of_frames; i_frame++){

                                host_to_node_int_1(rcfd->Rec->jumps[i_state][i_state2][i_island][i_frame]);
                            }
                        }
                    }
                }

                host_to_node_int_1(number_of_jump_files);

                report_print0(rcfd, "\n...default_Rec: Read %d jump files from %s",
                              number_of_jump_files, rcfd->File_Dict->Jump_filename);
            }
        }
        
        // set rcfd->Rec->frame_id (_means, vars, _database)
        {
            int frame_id_length = rcfd->Rec_Dict->frame_id_vector_length;
			
            if(rcfd->Rec->frame_id != NULL){
                 
                memset(rcfd->Rec->frame_id, 0.0, frame_id_length * sizeof(double));
            }
            
			if(rcfd->Rec->frame_id_means != NULL){
                 
                memset(rcfd->Rec->frame_id_means, 0.0, frame_id_length * sizeof(double));
            }

            if(rcfd->Rec->frame_id_vars != NULL){
                 
                memset(rcfd->Rec->frame_id_vars, 0.0, frame_id_length * sizeof(double));
            }
            			
            if(rcfd->Rec->frame_id_database != NULL){

                int i_frame, i_id;

                int frame_count =     rcfd->Solver_Dict->number_of_frames;

                for(i_frame = 0; i_frame < frame_count; i_frame++){

                    for(i_id = 0; i_id < frame_id_length; i_id++){

                        rcfd->Rec->frame_id_database[i_frame][i_id] = 0.0;
                    }
                }
            }
        }
    
    }

#endif
