// PERC.C // Determination of percolation thresholds // © 2021 Peter J. Meyer #include "iss.h" #define NUM_ANOMALIES (5) #define INITIAL_NUM_CONFIGS (500) #define NUM_CONFIGURATONS_FACTOR (2) #define MAX_NUM_CONFIGURATIONS (100000) #define MAX_REPEATS 5 #define INITIAL_EPSILON (8) #define EPSILON_FACTOR (2) #define W 13 double min_p, max_p, precision2; int total_num_configs; char anomalies[NUM_ANOMALIES+1][64] = { /* 0 */ "", /* 1 */ "must have first percentage < 50", /* 2 */ "must have final percentage > 50", /* 3 */ "a percentage decrease occurred", /* 4 */ "percentage within epsilon of 50", /* 5 */ "too many repeats for same range" }; /* Outline of algorithm: min_p = 0 max_p = 1 While ( max_p - min_p > precision ) For p=min_p, p<=max_p, P += (max_p-min_p)/5 Generate multiple configurations and get percentage with spanning cluster. End For If percentages not increasing (or other anomaly) repeat Else min_p = largest p with percentage < 50 max_p = smallest p with percentage > 50 End If End While */ /*-------------------------------*/ int get_percolation_threshold(void) { int iter, p_num, i, level, num_times_exceeded_50; int num_with_spanning_cluster, halfway_check_done; int map_displayed; double p, epsilon, range; iter = -1; level = 0; min_p = 0.0; max_p = 1.0; epsilon = INITIAL_EPSILON; num_configurations = INITIAL_NUM_CONFIGS; total_num_configs = 0; // free_boundary_conditions set to true in SETPARAM.C. do { level++; map_displayed = false; do { if ( ++iter > 0 ) { if ( iter == MAX_ITERATIONS ) goto done; if ( iterations[iter-1].repeat ) printf("\nRepeating because %s.",anomalies[iterations[iter-1].anom_code]); else { if ( iterations[iter-1].anom_code == 4 ) printf("\nAdjusting range because %s.",anomalies[4]); epsilon /= EPSILON_FACTOR; } // To avoid percentage decreases at the later stages // we need to increase the number of configurations. num_configurations = (int)(num_configurations*NUM_CONFIGURATONS_FACTOR); if ( num_configurations > MAX_NUM_CONFIGURATIONS ) num_configurations = MAX_NUM_CONFIGURATIONS; } printf("\nIteration #%d, level #%d, epsilon = %.*f", iter+1,level,num_decimal_places+1,epsilon); // num_decimal_places read from input file ("precision"). range = max_p - min_p; printf("\nRange %.*f - %.*f, %.*f in steps of %.*f, %s configurations.\n", num_decimal_places+1,min_p, num_decimal_places+1,max_p, num_decimal_places+1,range, num_decimal_places+1,range/(NUM_CONCENTRATIONS-1), ultoa_commas(num_configurations,temp)); // Copy data to array of structs for use // when writing results to disk file. iterations[iter].level = level; iterations[iter].max_p = max_p; iterations[iter].min_p = min_p; iterations[iter].range = range; iterations[iter].num_configurations = num_configurations; iterations[iter].epsilon = epsilon; for ( p_num=0; p_num<NUM_CONCENTRATIONS; p_num++ ) { iterations[iter].perc_data[p_num][0] = p = min_p + p_num*(range/(NUM_CONCENTRATIONS-1)); iterations[iter].perc_data[p_num][1] = 200; // 200 = no measurement made printf("%*.*f",W,num_decimal_places+1,p); } printf("\n"); iterations[iter].repeat = false; iterations[iter].anom_code = 0; num_times_exceeded_50 = 0; for ( p_num=0; p_num<NUM_CONCENTRATIONS; p_num++ ) { p = iterations[iter].perc_data[p_num][0]; if ( goal_is_site_percolation_threshold ) { site_concentration = p; // bond_concentration set in SETPARAM.C site_diluted = ( site_concentration < 1.0 ); } else // goal is bond_percolation; { bond_concentration = p; // site_concentration set in SETPARAM.C bond_diluted = ( bond_concentration < 1.0 ); } if ( p == 0.0 ) iterations[iter].perc_data[p_num][1] = 0.0; // never a spanning cluster else { // Even if p = 1.0 there may not be a spanning cluster // (e.g. if seeking bond percolation threshold with low site concentration). num_with_spanning_cluster = 0; halfway_check_done = false; for ( i=0; i<num_configurations; i++ ) { // Occupy (some or all) sites and open (some or all) bonds. set_up_configuration(); // S&B.C total_num_configs++; ct_data.cluster_type = CT_OPEN_BOND; ct_data.stop_on_spanning_cluster = true; trace_all_clusters(&ct_data); // Look for spanning cluster. if ( ct_data.spanning_cluster_found ) { num_with_spanning_cluster++; if ( map_file_requested ) { if ( !map_displayed ) { display_map(map_filepath,1); map_displayed = true; } } } // If we are halfway through and percentage < 40 then give up. if ( !halfway_check_done ) { if ( i >= num_configurations/2 ) { if ( ((double)num_with_spanning_cluster*200) /num_configurations < 40 ) { num_with_spanning_cluster *= 2; break; } halfway_check_done = true; } } // Check for Escape key after each 100 configurations. if ( !(i%100) ) if ( kbhit() ) if ( getch() == ESCAPE ) { printf("\nEscape pressed."); escape_key_termination = true; goto done; } } iterations[iter].perc_data[p_num][1] = ((double)num_with_spanning_cluster*100)/num_configurations; } if ( iterations[iter].perc_data[p_num][1] == 0 ) printf("%*d",W,0); else if ( iterations[iter].perc_data[p_num][1] == 100 ) printf("%*d",W,100); else printf("%*.2f",W,iterations[iter].perc_data[p_num][1]); // Check that results show no anomalies. if ( p_num == 0 && iterations[iter].perc_data[p_num][1] >= 50 ) { iterations[iter].repeat = true; iterations[iter].anom_code = 1; break; // because must have first percentage < 50 } if ( p_num == NUM_CONCENTRATIONS - 1 && iterations[iter].perc_data[p_num][1] <= 50 ) { iterations[iter].repeat = true; iterations[iter].anom_code = 2; break; // because must have final percentage > 50 } if ( p_num > 0 ) { if ( iterations[iter].perc_data[p_num][1] < iterations[iter].perc_data[p_num-1][1] ) { iterations[iter].repeat = true; iterations[iter].anom_code = 3; break; // because a percentage decrease occurred } } num_times_exceeded_50 += ( iterations[iter].perc_data[p_num][1] > 50 ); // If the percentage has exceeded 50% twice // or has reached 80% then no need to continue; if ( num_times_exceeded_50 == 2 || iterations[iter].perc_data[p_num][1] >= 80 ) break; } printf("\n"); if ( iter >= MAX_REPEATS-1 && iterations[iter].repeat ) { if ( iterations[iter].level == iterations[iter-MAX_REPEATS+1].level ) { // About to do a further repeat after MAX_REPEATS // for the same range, so give up. iterations[iter].anom_code = 5; printf("\nQuit because %s.\n",anomalies[5]); goto done; } } } while ( iterations[iter].repeat ); // At this point percolation_data[iter][0][1] < 50 and // percolation_data[iter][NUM_CONCENTRATIONS-1][1] > 50. // Set min_p to the largest p with percentage less than 50%. p_num = 1; while ( iterations[iter].perc_data[p_num][1] < 50 ) p_num++; min_p = iterations[iter].perc_data[--p_num][0]; // If percentage for min_p is too close to 50 then widen range. if ( 50 - iterations[iter].perc_data[p_num][1] < epsilon ) { // Subtract step length from min_p. min_p -= range/(NUM_CONCENTRATIONS-1); if ( min_p < 0 ) min_p = 0; iterations[iter].anom_code = 4; } // Set max_p to the smallest p with percentage greater than 50%. p_num = NUM_CONCENTRATIONS - 2; while ( iterations[iter].perc_data[p_num][1] > 50 ) p_num--; max_p = iterations[iter].perc_data[++p_num][0]; // If percentage for max_p is too close to 50 then widen range. if ( iterations[iter].perc_data[p_num][1] - 50 < epsilon ) { max_p += range/(NUM_CONCENTRATIONS-1); if ( max_p > 1 ) max_p = 1; iterations[iter].anom_code = 4; } } while ( max_p - min_p > precision ); done: precision2 = max_p - min_p; // The final value is ( max_p + min_p )/2 +/- precision2. if ( precision < 0.5 ) { printf("\nThe %s percolation threshold for this lattice" "\n(with %s concentration %.3f)", ( goal_is_site_percolation_threshold ? "site" : "bond" ), ( goal_is_site_percolation_threshold ? "bond" : "site" ), ( goal_is_site_percolation_threshold ? bond_concentration : site_concentration )); printf("\nis %.*f +/- %.*f (%.*f - %.*f)\n", num_decimal_places+1, (max_p+min_p)/2, num_decimal_places+1, precision2, num_decimal_places+1, (max_p+min_p)/2-precision2, num_decimal_places+1, (max_p+min_p)/2+precision2); } printf("\n%s configurations generated.\n",ultoa_commas(total_num_configs,temp)); return ( ++iter ); }