//  ALLOC.C
//  Allocation of memory for arrays
//  © 2021 Peter J. Meyer

#include "iss.h"

/*----------------------*/
void allocate_arrays(void)
{
int err_flag;
unsigned int memory_for_arrays=0;
unsigned int memory_for_precomputed_sites;

if ( dimensionality > MAX_DIMENSIONALITY )
    {
    printf("\nA %dd spin model is not currently supported.\n",dimensionality);
    exit(101);
    }

printf("\nMemory for ");

switch ( dimensionality )
    {
    case 2:
    //  Allocate a 2-dimensional array to hold the sites information.
    sites2 = (A2(unsigned char))array_alloc(&err_flag, sizeof(char), 
        NULL, 2, size, size);
    if ( err_flag )
        display_array_allocation_error(0,err_flag);    //  Does not return.
    printf("sites2");
    memory_for_arrays += num_sites;
    //  num_sites has been set in SETPARAM.C.

    //  Allocate a 2-dimensional array to hold the bonds information.
    bonds2 = (A2(unsigned char))array_alloc(&err_flag, sizeof(char), 
        NULL, 2, size, size);
    if ( err_flag )
        display_array_allocation_error(1,err_flag);
    memory_for_arrays += num_sites;
    printf(", bonds2");

    if ( dynamics_is_swendsen_wang || dynamics_is_wolff )
        {
        //  Allocate a 2-dimensional array to hold the virtual bonds information.
        v_bonds2 = (A2(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 2, size, size);
        if ( err_flag )
            display_array_allocation_error(2,err_flag);
        memory_for_arrays += num_sites;
        printf(", v_bonds2");
        }

    if ( use_precomputed_nn_sites )
        {
        precomp_nn_sites2 = (A4(short int))array_alloc(&err_flag, sizeof(short int), 
            NULL, 4, size, size, MAX_COORD_NUM, MAX_DIMENSIONALITY);
        if ( err_flag )
            display_array_allocation_error(6,err_flag);
        memory_for_precomputed_sites = num_sites*MAX_COORD_NUM*MAX_DIMENSIONALITY*sizeof(short int);
        memory_for_arrays += memory_for_precomputed_sites;
        printf(", precomp_nn_sites2 (%s KB),\n",
            ultoa_commas((unsigned long)memory_for_precomputed_sites/1024,temp));
        }

    if ( autocorrelation_measured || num_repetitions > 1 )
        {
        //  Allocate a 2-dimensional array to hold the initial spin assignments.
        initial_sites2 = (A2(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 2, size, size);
        if ( err_flag )
            display_array_allocation_error(3,err_flag);
        memory_for_arrays += num_sites;
        if ( !use_precomputed_nn_sites )
            printf(", ");
        printf("initial_sites2");
        }

    #if false
    if ( thermal_corr_length_b_measured )
        {
        //  Allocate a 2-dimensional array to hold the shifted spin assignments.
        shifted_sites2 = (A2(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 2, size, size);
        if ( err_flag )
            display_array_allocation_error(3,err_flag);
        memory_for_arrays += num_sites;
        printf(", initial_sites2");
        }
    #endif

    #if false
    //  Measurement of correlation lengths not done.
    if ( percolation_corr_length_measured || thermal_corr_length_a_measured )
        {
        //  Allocate a 2-dimensional array to hold cluster number for each spin.
        cluster_numbers2 = (A2(unsigned short int))array_alloc(&err_flag, 
            sizeof(unsigned short int), NULL, 2, size, size);
        if ( err_flag )
            display_array_allocation_error(4,err_flag);
        memory_for_arrays += num_sites*sizeof(unsigned short int);
        printf(", cluster_numbers2");

        #if RECORD_SPIN_DISTANCES
        //  Allocate a 2-dimensional array to hold spin distances in cluster trace.
        spin_distances2 = (A2(unsigned short int))array_alloc(&err_flag, 
            sizeof(unsigned short int), NULL, 2, size, size);
        if ( err_flag )
            display_array_allocation_error(5,err_flag);
        memory_for_arrays += num_sites*sizeof(unsigned short int);
        printf(", spin_distances2");
        #endif
        }
    #endif

    break;

    case 3:
    //  Allocate a 3-dimensional array to hold the sites information.
    sites3 = (A3(unsigned char))array_alloc(&err_flag, sizeof(char), 
        NULL, 3, size, size, size);
    if ( err_flag )
        display_array_allocation_error(0,err_flag);        //  Does not return.
    memory_for_arrays += num_sites;
    printf("sites3");

    //  Allocate a 3-dimensional array to hold the bonds information.
    bonds3 = (A3(unsigned char))array_alloc(&err_flag, sizeof(char), 
        NULL, 3, size, size, size);
    if ( err_flag )
        display_array_allocation_error(1,err_flag);
    memory_for_arrays += num_sites;
    printf(", bonds3");

    if ( dynamics_is_swendsen_wang || dynamics_is_wolff )
        {
        //  Allocate a 3-dimensional array to hold the virtual bonds information.
        v_bonds3 = (A3(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 3, size, size, size);
        if ( err_flag )
            display_array_allocation_error(2,err_flag);
        memory_for_arrays += num_sites;
        printf(", v_bonds3");
        }

    if ( use_precomputed_nn_sites )
        {
        precomp_nn_sites3 = (A5(short int))array_alloc(&err_flag, sizeof(short int), 
            NULL, 5, size, size, size, MAX_COORD_NUM, MAX_DIMENSIONALITY);
        if ( err_flag )
            display_array_allocation_error(6,err_flag);
        memory_for_precomputed_sites = num_sites*MAX_COORD_NUM*MAX_DIMENSIONALITY*sizeof(short int);
        memory_for_arrays += memory_for_precomputed_sites;
        printf(", precomp_nn_sites3 (%s KB),\n",
            ultoa_commas((unsigned long)memory_for_precomputed_sites/1024,temp));
        }

    if ( autocorrelation_measured || num_repetitions > 1 )
        {
        //  Allocate a 3-dimensional array to hold the initial spin assignments.
        initial_sites3 = (A3(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 3, size, size, size);
        if ( err_flag )
            display_array_allocation_error(3,err_flag);
        memory_for_arrays += num_sites;
        if ( !use_precomputed_nn_sites )
            printf(", ");
        printf("initial_sites3");
        }

    #if false
    if ( percolation_corr_length_measured || thermal_corr_length_a_measured )
        ;
    #endif

    break;

    case 4:
    //  Allocate a 4-dimensional array to hold the sites information.
    sites4 = (A4(unsigned char))array_alloc(&err_flag, sizeof(char), 
        NULL, 4, size, size, size, size);
    if ( err_flag )
        display_array_allocation_error(0,err_flag);        //  Does not return.
    memory_for_arrays += num_sites;
    printf("sites4");

    //  Allocate a 4-dimensional array to hold the bonds information.
    bonds4 = (A4(unsigned char))array_alloc(&err_flag, sizeof(char), 
        NULL, 4, size, size, size, size);
    if ( err_flag )
        display_array_allocation_error(1,err_flag);
    memory_for_arrays += num_sites;
    printf(", bonds4");

    if ( dynamics_is_swendsen_wang || dynamics_is_wolff )
        {
        //  Allocate a 4-dimensional array to hold the virtual bonds information.
        v_bonds4 = (A4(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 4, size, size, size, size);
        if ( err_flag )
            display_array_allocation_error(2,err_flag);
        memory_for_arrays += num_sites;
        printf(", v_bonds4");
        }

    if ( use_precomputed_nn_sites )
        {
        precomp_nn_sites4 = (A6(short int))array_alloc(&err_flag, sizeof(short int), 
            NULL, 6, size, size, size, size, MAX_COORD_NUM, MAX_DIMENSIONALITY);
        if ( err_flag )
            display_array_allocation_error(6,err_flag);
        memory_for_precomputed_sites = num_sites*MAX_COORD_NUM*MAX_DIMENSIONALITY*sizeof(short int);
        memory_for_arrays += memory_for_precomputed_sites;
        printf(", precomp_nn_sites4 (%s KB),\n",
            ultoa_commas((unsigned long)memory_for_precomputed_sites/1024,temp));
        }

    if ( autocorrelation_measured || num_repetitions > 1 )
        {
        //  Allocate a 4-dimensional array to hold the initial spin assignments.
        initial_sites4 = (A4(unsigned char))array_alloc(&err_flag, sizeof(char), 
            NULL, 4, size, size, size, size);
        if ( err_flag )
            display_array_allocation_error(3,err_flag);
        memory_for_arrays += num_sites;
        if ( !use_precomputed_nn_sites )
            printf(", ");
        printf("initial_sites4");
        }

    #if false
    if ( percolation_corr_length_measured || thermal_corr_length_a_measured )
        ;
    #endif

    break;
    }

fflush(stdout);

if ( goal_is_equilibration )
    {
    //  Allocate a 2d array of doubles for sum of the magnetization
    //  the sum of the square of the magnetization at each time slice,
    //  and allocate space for the second moment values.
    magnetization = (A2(double))array_alloc(&err_flag, 
        sizeof(double), NULL, 2, num_time_slices+1, 
        NUM_MAGNETIZATION_COMPONENTS);      //  See ISM_DEF.H
    if ( err_flag )
        {
        printf("\nError %d when allocating array for magnetizations.\n",err_flag);
        exit(1);
        }
    memory_for_arrays += sizeof(double)*(num_time_slices+1)*NUM_MAGNETIZATION_COMPONENTS;

    if ( internal_energy_measured )
        {
        //  Allocate a 2d array of doubles for sum of the internal energy
        //  and the sum of the square of the internal energy at each time slice.
        internal_energy = (A2(double))array_alloc(&err_flag, 
            sizeof(double), NULL, 2, num_time_slices+1, 
            NUM_INTERNAL_ENERGY_COMPONENTS);
        if ( err_flag )
            {
            printf("\nError %d when allocating array for internal energies.\n",err_flag);
            exit(1);
            }
        memory_for_arrays += sizeof(double) * (num_time_slices+1)
            * NUM_INTERNAL_ENERGY_COMPONENTS;
        }

    if ( second_moment_measured && model_is_q_state_potts )
        {
        //  Allocate a 2d array of doubles for squares of magnetizations.
        potts_magnetization_squares = (A2(double))array_alloc(&err_flag, 
            sizeof(double), NULL, 2, num_time_slices+1, q+1);
        if ( err_flag )
            {
            printf("\nError %d when allocating array for "
                   "squares of potts magnetizations.\n",err_flag);
            exit(1);
            }
        memory_for_arrays += sizeof(double) * (num_time_slices+1)*(q+1);
        }

    if ( autocorrelation_measured )
        {
        //  Allocate a 2d array of doubles for sum of the autocorrelations
        //  and the squares of the autocorrelations.
        autocorrelation = (A2(double))array_alloc(&err_flag, 
            sizeof(double), NULL, 2, num_time_slices+1, 
            NUM_AUTOCORRELATION_COMPONENTS);
        if ( err_flag )
            {
            printf("\nError %d when allocating array for autocorrelation.\n",err_flag);
            exit(1);
            }
        memory_for_arrays += sizeof(double) * (num_time_slices+1)
            * NUM_AUTOCORRELATION_COMPONENTS;
        }
    }

fflush(stdout);

//  Allocate a 2d array of MAX_DIMENSIONALITY x size chars (used in CLUSTERS.C).
edge = (A2(char))array_alloc(&err_flag, sizeof(char), NULL, 2, MAX_DIMENSIONALITY, size);
if ( err_flag )
    {
    printf("\nError %d when allocating edge[][] array.\n",err_flag);
    exit(1);
    }
memory_for_arrays += sizeof(char)*MAX_DIMENSIONALITY*size;

printf(" and other arrays:");
if ( memory_for_arrays < 10000 )
    printf(" %d bytes",memory_for_arrays);
else
    {
    ultoa_commas(memory_for_arrays/1024,temp);
    printf(" %s KB",temp);
    }

if ( goal_is_percolation_threshold || dynamics_is_swendsen_wang || dynamics_is_wolff
     || percolation_corr_length_measured || thermal_corr_length_measured )
    {
    if ( dynamics_is_swendsen_wang )
        stack_size = SHORT_INTS_PER_SWENDSEN_WANG_STACK_PUSH;
    else if ( dynamics_is_wolff )
        stack_size = SHORT_INTS_PER_WOLFF_STACK_PUSH;
    else
        stack_size = dimensionality;
    
    stack_size = stack_size*num_sites + size;     
    //  Maximum number of ints the stack can hold. 
    
    allocate_memory_for_stack();        //  STACK.C

    ultoa_commas(stack_size,temp);
    printf("\nPlus memory for stack of up to %s short ints: ",temp);
    if ( stack_size*sizeof(short int) < 10000 )
        {
        ultoa_commas(stack_size*sizeof(short int),temp);
        printf(" %s bytes",temp);
        }
    else
        {
        ultoa_commas((stack_size*sizeof(short int))/1024,temp);
        printf(" %s KB",temp);
        }
    memory_for_arrays += stack_size*sizeof(short int);
    }
else
    stack_size = 0;        

printf("\nTotal memory allocated:");
if ( memory_for_arrays < 10000 )
    printf(" %d bytes",memory_for_arrays);
else
    {
    ultoa_commas(memory_for_arrays/1024,temp);
    printf(" %s KB",temp);
    }
printf("\n");
fflush(stdout);
}

/*------------------*/
void free_arrays(void)
{
switch ( dimensionality )
    {
    case 2:
    //  Free the array holding the sites information.
    if ( !array_free(sites2, 2) )
        display_array_free_error(0);

    //  Free the array holding the bonds information.
    if ( !array_free(bonds2, 2) )
        display_array_free_error(1);

    if ( dynamics_is_swendsen_wang )
        {
        //  Free the array holding the v_bonds information.
        if ( !array_free(v_bonds2, 2) )
            display_array_free_error(2);
        }

    if ( autocorrelation_measured )
        {
        //  Free the array holding the initial_sites information.
        if ( !array_free(initial_sites2, 2) )
            display_array_free_error(3);
        }

    break;

    case 3:
    //  Free the array holding the sites information.
    if ( !array_free(sites3, 3) )
        display_array_free_error(0);

    //  Free the array holding the bonds information.
    if ( !array_free(bonds3, 3) )
        display_array_free_error(1);

    if ( dynamics_is_swendsen_wang )
        {
        //  Free the array holding the v_bonds information.
        if ( !array_free(v_bonds3, 3) )
            display_array_free_error(2);
        }

    if ( autocorrelation_measured )
        {
        //  Free the array holding the initial_sites information.
        if ( !array_free(initial_sites3, 3) )
            display_array_free_error(3);
        }

    break;

    case 4:
    //  Free the array holding the sites information.
    if ( !array_free(sites4, 4) )
        display_array_free_error(0);

    //  Free the array holding the bonds information.
    if ( !array_free(bonds4, 4) )
        display_array_free_error(1);

    if ( dynamics_is_swendsen_wang )
        {
        //  Free the array holding the v_bonds information.
        if ( !array_free(v_bonds4, 4) )
            display_array_free_error(2);
        }

    if ( autocorrelation_measured )
        {
        //  Free the array holding the initial_sites information.
        if ( !array_free(initial_sites4, 4) )
            display_array_free_error(3);
        }

    break;
   }

if ( goal_is_equilibration )
    {
    if ( !array_free(magnetization,2) )
        printf("\nError when freeing array for magnetizations.\n");

    if ( second_moment_measured && model_is_q_state_potts )
        {
        if ( !array_free(potts_magnetization_squares,2) )
            printf("\nError when freeing array for potts magnetization squares.\n");
        }

    if ( autocorrelation_measured )
        {
        if ( !array_free(autocorrelation,2) )
            printf("\nError when freeing array for autocorrelation.\n");
        }
    }

if ( stack_size != 0 )
    if ( !array_free(stack,1) )
        printf("\nError when freeing array for stack.\n");
}