//  SETPARAM.C
//  © 2021 Peter J. Meyer

#include "iss.h"

//  Parameters for the simulation are obtained from an input data file.

static int get_divisors(void);
static int compare_function(const void *arg1, const void *arg2);

//  All flags are set to false in FLAGS.H.
/*---------------------*/
void set_parameters(void)
{
int i;
double crit_temp;

#if !DOES_PERCOLATION_THRESHOLDS
goal_is_equilibration = goal_specified = true;
#endif

if ( !goal_specified )
    display_missing_data_message("goal");               //  Does not return.

//  goal_is_percolation_threshold is set in READ.C.

free_boundary_conditions = goal_is_percolation_threshold;   

if ( !lattice_type_specified )
    display_missing_data_message("lattice type");       //  Does not return.

dimensionality = lattice_types[l_type].dimensionality;  //  Set number of dimensions
coord_num = lattice_types[l_type].coord_num;            //  Set coordination number

//  major axis is 0 by default
#if !MAJOR_AXIS_SPECIFICATION_PERMITTED
if ( major_axis != 0 )
    {
    printf("\nSpecification of major axis not permitted.\n");
    exit(1);
    }
#endif

set_direction_table();       //  Set directions to nn.
                          
set_directionalities();     //  Set directionalities for (possible) use
                            //  in trace_single_cluster().
if ( !size_specified )
    display_missing_data_message("lattice size");

if ( goal_is_percolation_threshold && size < MIN_SIZE_PT )
    {
    printf("\nIn determination of percolation threshold"
        " the lattice size must be at least %d.\n",MIN_SIZE_PT);
    exit(1);
    }    

if ( size%2 )
    {
    printf("\nLattice size must be divisible by 2.\n");
    exit(1);
    }

//  Calculate number of sites.
num_sites = 1;                                   
for ( i=0; i<dimensionality; i++ )
    num_sites *= size;

//  Largest number of sites is 16,777,216
//  so no problem with num_sites declared as int.

if ( !site_concentration_specified )
    site_concentration = 1.0;

if ( !bond_concentration_specified )
    bond_concentration = 1.0;

site_diluted = ( site_concentration < 1.0 );

bond_diluted = ( bond_concentration < 1.0 );

non_diluted = ( !site_diluted && !bond_diluted );

if ( !use_precomputed_nn_sites_specified )
    display_missing_data_message("\"precompute nn sites\"");       //  Does not return.

if ( !absolute_magnetization_specified )
    display_missing_data_message("\"absolute magnetization\"");      

if ( !timeslice_values_specified )
    display_missing_data_message("\"timeslice values\"");      

if ( goal_is_percolation_threshold )
    {
    if ( goal_is_site_percolation_threshold )
        {
        if ( site_concentration_specified )
            printf("\nsite concentration ignored.");
        }
    else if ( goal_is_bond_percolation_threshold )
        {
        if ( bond_concentration_specified )
            printf("\nbond concentration ignored.");
        }

    if ( !precision_specified )
        display_missing_data_message("precision");
    //  precision specified as number of decimal places.

    precision = 1.0;
    for ( i=0; i<num_decimal_places; i++ )
        precision /= 10;

    num_temperatures = 1;       //  so inner loop works in main()
    }
else    //  goal is equilibration
    {    
    standard_deviation_measured = true;

    if ( !model_specified )
        {
        model_is_ising = true;
        m_type = 0;
        }

    if ( model_is_ising )
        spin_value_mask = 1;                            //  00000001
    else
        {
        if ( !q_value_specified )
            display_missing_data_message("q-value");    //  Does not return.
        spin_value_mask = MAX_Q_VALUE;                  //  decimal 15 = 00001111
        }

    if ( !num_configurations_specified )
        num_configurations = 1;

    if ( !num_spin_assignments_specified )
        num_spin_assignments = 1;
    
    if ( !num_repetitions_specified )
        num_repetitions = 1;  

    if ( !percentage_range_for_mean_specified )
        percentage_range_for_mean = 20;
        //  display_missing_data_message("percentage range for mean");  

    if ( !initial_magnetization_specified )
        initial_magnetization = 1.0;

    if ( model_is_q_state_potts )
        {
        if ( initial_magnetization < -1.0/(q-1) )
            display_input_data_error("initial magnetization");
            //  Does not return.
        }

    #if false
    //  Measurement of correlation lengths not done.
    if ( non_diluted )
        {
        if ( percolation_corr_length_measured )
            {
            printf("\nMeasurement of percolation correlation length"
                   "\nis not appropriate with a non-diluted lattice.\n");
            exit(1);
            }
        }
    #endif
 
    if ( num_temperatures == 0 )
        display_missing_data_message("temperature");

    single_temperature_specified = ( num_temperatures == 1 );
    multiple_temperatures_specified = !single_temperature_specified;

    for ( i=0; i<num_temperatures; i++ )
        { 
        if ( temperatur[i] == -1 )
            {
            //  Critical temperature requested.
            if ( ( crit_temp = get_critical_temperature() ) == -1 )
                {
                sprintf(temp,models[m_type][1],q);
                printf("\nCannot ascertain critical temperature for %dd %s model.\n",
                    dimensionality,temp);
                exit(1);
                }
            temperatur[i] = crit_temp;
            }
        else if ( temperatur[i] == 0.0 )
            {
            printf("\nCannot perform equilibration for zero temperature.\n");
            exit(1);
            }
        }

    if ( multiple_temperatures_specified )
        //  Sort temperatures.
        qsort(temperatur,num_temperatures,sizeof(double),compare_function);
    else
        temperature = temperatur[0];
                
    if ( !dynamics_specified )
        display_missing_data_message("dynamics");

    if ( size > max_size[d_type][dimensionality] )
        {
        printf("\nMaximum size for a %dd lattice with %s dynamics is %d.\n",
            dimensionality,dynamics_types[d_type][1],max_size[d_type][dimensionality]);
        exit(1);
        }

    if ( dynamics_is_metropolis || dynamics_is_glauber )
        {
        //  Transition probabilities are calculated 
        //  in perform_equilibration() in EQUIL.C.
        if ( !spin_seln_specified || !ALTERNATIVE_SPIN_SELECTIONS )
            {
            spin_seln_is_checkerboard = true;
            ss_type = 0;
            }
        if ( spin_seln_is_checkerboard )
            num_divisors = get_divisors();
        }

    if ( non_diluted && num_configurations > 1 )
        {
        printf("\nInconsistent data input: Input data file specifies"
               "\na non-diluted lattice with more than one configuration.\n");
        exit(1);            
        }

    if ( !num_time_slices_specified )
        display_missing_data_message("number of time slices");          

    if ( !step_length_specified )
        display_missing_data_message("step length");

    if ( initial_magnetization == 1.0 && autocorrelation_measured )
        {
        printf("\nWith initial magnetization = 1 the autocorrelation values"
               "\nare the same as the magnetization values.\n");           
        }  

    if ( absolute_magnetization_requested && initial_magnetization < 0 )
        {
        printf("\nAbsolute magnetization values are requested"
               "\nbut the initial magnetization is negative: %f\n",initial_magnetization); 
        exit(1);                        
        }          
        
    #if false    
    //  Set site percolation threshold.
    site_perc_thr = lattice_types[l_type].site_perc_thr;    
    //  Set bond percolation threshold.
    bond_perc_thr = lattice_types[l_type].bond_perc_thr;   
    #endif                           
    }
}

/*-------------------------*/
static int get_divisors(void)
{
//  First get all factors d of size such that 2 <= d <= size/2.
int i=0, j, d=2;

do  {
    if ( !(size%d) )
        divisors[i++] = d;
    d++;
    } while ( i < MAX_DIVISORS && d <= size/2 );

//  If i > 7 reduce the number of divisors until it is 6 or 7.

while ( i > 7 )
    {
    for ( j=1; j<i-1; j++ )
        divisors[j-1] = divisors[j];
    i -= 2;
    }

return ( i );
}

/*----------------------------------------------------------*/
static int compare_function(const void *arg1, const void *arg2)
{
double x1 = *(double *)arg1;
double x2 = *(double *)arg2;

if ( x1 < x2 )
    return ( -1 );
else if ( x1 > x2 )
    return ( 1 );
else
    return ( 0 );
}