// BONDS.C // Functions for setting up bonds among occupied sites // © 2021 Peter J. Meyer #include "iss.h" // nn_i, nn_j, nn_k, nn_l are global ints. // This function depends on the lattice type. /*----------------*/ int open_bonds(void) { int i, j, k, l, r, nn_r; int num_opened = 0, target_num_opened; unsigned char bonds, nn_bonds; num_pairs_nn = 0; if ( bond_diluted ) // bond_diluted set in SETPARAM.C. mark_all_sites_unvisited(); // below switch ( dimensionality ) { case 2: for ( i=0; i<size; i++ ) { for ( j=0; j<size; j++ ) { if ( site_diluted ) if ( !SITE_IS_OCCUPIED_2(i,j) ) continue; get_nn_sites(i,j); // nn_sites[][] now holds the indices // of the nearest neighbour sites in all directions // (no. of directions = coord_num). // Now check which nn sites are occupied // and set bonds2[i][j] appropriately. bonds = 0; // Must use following "for" so that the right-shift is done 8 times. for ( r=0; r<MAX_COORD_NUM; r++ ) { bonds >>= 1; if ( r >= coord_num ) continue; if ( ( nn_i = nn_sites[r][0] ) == NON_EXISTENT ) continue; // only with free boundary conditions nn_j = nn_sites[r][1]; // Check if nn site is occupied. if ( !SITE_IS_OCCUPIED_2(nn_i,nn_j) ) continue; // nn site exists and is occupied. num_pairs_nn++; if ( !bond_diluted ) { bonds |= OCCUPIED; num_opened++; // Done twice for each opened bond. } else // bond diluted { // Check if bonds at this nn site have already been opened // (or at least, have been considered for opening). if ( SITE_IS_VISITED_2(nn_i,nn_j) ) { // Yes, so check if bond has already been opened. nn_bonds = bonds2[nn_i][nn_j]; // Get direction from the nn site back to this one. nn_r = inverse_direction((i+j)%2,r); // DIR_TABLE.C if ( nn_bonds & bit[nn_r] ) { // Bond has been opened, so mark it here. bonds |= OCCUPIED; // set bit 7 // Don't do num_opened++ } } else // Site not yet visited. // Decide whether to open this bond. { if ( PRNG1() < bond_concentration ) { bonds |= OCCUPIED; num_opened++; } } } } bonds2[i][j] = bonds; if ( bond_diluted ) MARK_SITE_AS_VISITED_2(i,j); } } num_pairs_nn /= 2; // since each pair has been counted twice. if ( !bond_diluted ) num_opened /= 2; // since each bond has been counted twice. // If necessary, adjust bonds to get exact concentration specified. target_num_opened = (int)(num_pairs_nn*bond_concentration); while ( num_opened > target_num_opened ) { i = (int)(size*PRNG1()); j = (int)(size*PRNG1()); if ( bonds2[i][j] ) { // This spin has an open bond. for ( r=0; r<coord_num; r++ ) { if ( bonds2[i][j] & bit[r] ) { // Bond is open, so close it. bonds2[i][j] &= unbit[r]; // Mark the bond closed at the nn site. get_nn_site_in_dir(r,i,j); bonds2[nn_site[0]][nn_site[1]] &= unbit[inverse_direction((i+j)%2,r)]; num_opened--; break; } } } } while ( num_opened < target_num_opened ) { i = (int)(size*PRNG1()); j = (int)(size*PRNG1()); if ( SITE_IS_OCCUPIED_2(i,j) ) { // Look for a closed bond. for ( r=0; r<coord_num; r++ ) { if ( ! ( bonds2[i][j] & bit[r] ) ) { // Bond is closed, so open it (assuming there is // an occupied nn site in direction r). if ( get_nn_site_in_dir(r,i,j) ) { // Nearest neighbour site exists. if ( SITE_IS_OCCUPIED_2(nn_site[0],nn_site[1]) ) { bonds2[i][j] |= bit[r]; // Mark the bond open at the nn site. bonds2[nn_site[0]][nn_site[1]] |= bit[inverse_direction((i+j)%2,r)]; num_opened++; break; } } } } } } break; case 3: for ( i=0; i<size; i++ ) { for ( j=0; j<size; j++ ) { for ( k=0; k<size; k++ ) { if ( site_diluted ) if ( !SITE_IS_OCCUPIED_3(i,j,k) ) continue; get_nn_sites(i,j,k); // See comments for 2d case. bonds = 0; for ( r=0; r<MAX_COORD_NUM; r++ ) { bonds >>= 1; if ( r >= coord_num ) continue; if ( ( nn_i = nn_sites[r][0] ) == NON_EXISTENT ) continue; nn_j = nn_sites[r][1]; nn_k = nn_sites[r][2]; if ( !SITE_IS_OCCUPIED_3(nn_i,nn_j,nn_k) ) continue; num_pairs_nn++; if ( !bond_diluted ) { bonds |= OCCUPIED; num_opened++; } else { if ( SITE_IS_VISITED_3(nn_i,nn_j,nn_k) ) { nn_bonds = bonds3[nn_i][nn_j][nn_k]; nn_r = inverse_direction((i+j+k)%2,r); if ( nn_bonds & bit[nn_r] ) bonds |= OCCUPIED; } else { if ( PRNG1() < bond_concentration ) { bonds |= OCCUPIED; num_opened++; } } } } bonds3[i][j][k] = bonds; if ( bond_diluted ) MARK_SITE_AS_VISITED_3(i,j,k); } } } num_pairs_nn /= 2; // since each pair has been counted twice. if ( !bond_diluted ) num_opened /= 2; // since each bond has been counted twice. // If necessary, adjust bonds to get exact concentration specified. target_num_opened = (int)(num_pairs_nn*bond_concentration); while ( num_opened > target_num_opened ) { i = (int)(size*PRNG1()); j = (int)(size*PRNG1()); k = (int)(size*PRNG1()); if ( bonds3[i][j][k] ) { // This spin has an open bond. for ( r=0; r<coord_num; r++ ) { if ( bonds3[i][j][k] & bit[r] ) { // Bond is open, so close it. bonds3[i][j][k] &= unbit[r]; // Mark the bond closed at the nn site. get_nn_site_in_dir(r,i,j,k); bonds3[nn_site[0]][nn_site[1]][nn_site[2]] &= unbit[inverse_direction((i+j+k)%2,r)]; num_opened--; break; } } } } while ( num_opened < target_num_opened ) { i = (int)(size*PRNG1()); j = (int)(size*PRNG1()); k = (int)(size*PRNG1()); if ( SITE_IS_OCCUPIED_3(i,j,k) ) { // Look for a closed bond. for ( r=0; r<coord_num; r++ ) { if ( ! ( bonds3[i][j][k] & bit[r] ) ) { // Bond is closed, so open it (assuming there is // an occupied nn site in direction r). if ( get_nn_site_in_dir(r,i,j,k) ) { // Nearest neighbour site exists. if ( SITE_IS_OCCUPIED_3(nn_site[0],nn_site[1],nn_site[2]) ) { bonds3[i][j][k] |= bit[r]; // Mark the bond open at the nn site. bonds3[nn_site[0]][nn_site[1]][nn_site[2]] |= bit[inverse_direction((i+j+k)%2,r)]; num_opened++; break; } } } } } } break; case 4: for ( i=0; i<size; i++ ) { for ( j=0; j<size; j++ ) { for ( k=0; k<size; k++ ) { for ( l=0; l<size; l++ ) { if ( site_diluted ) if ( !SITE_IS_OCCUPIED_4(i,j,k,l) ) continue; get_nn_sites(i,j,k,l); // See comments for 2d case. bonds = 0; for ( r=0; r<MAX_COORD_NUM; r++ ) { bonds >>= 1; if ( r >= coord_num ) continue; if ( ( nn_i = nn_sites[r][0] ) == NON_EXISTENT ) continue; nn_j = nn_sites[r][1]; nn_k = nn_sites[r][2]; nn_l = nn_sites[r][3]; if ( !SITE_IS_OCCUPIED_4(nn_i,nn_j,nn_k,nn_l) ) continue; num_pairs_nn++; if ( !bond_diluted ) { bonds |= OCCUPIED; num_opened++; } else { if ( SITE_IS_VISITED_4(nn_i,nn_j,nn_k,nn_l) ) { nn_bonds = bonds4[nn_i][nn_j][nn_k][nn_k]; nn_r = inverse_direction((i+j+k+l)%2,r); if ( nn_bonds & bit[nn_r] ) bonds |= OCCUPIED; } else { if ( PRNG1() < bond_concentration ) { bonds |= OCCUPIED; num_opened++; } } } } bonds4[i][j][k][l] = bonds; if ( bond_diluted ) MARK_SITE_AS_VISITED_4(i,j,k,l); } } } } num_pairs_nn /= 2; // since each pair has been counted twice. if ( !bond_diluted ) num_opened /= 2; // since each bond has been counted twice. // If necessary, adjust bonds to get exact concentration specified. target_num_opened = (int)(num_pairs_nn*bond_concentration); while ( num_opened > target_num_opened ) { i = (int)(size*PRNG1()); j = (int)(size*PRNG1()); k = (int)(size*PRNG1()); l = (int)(size*PRNG1()); if ( bonds4[i][j][k][l] ) { // This spin has an open bond. for ( r=0; r<coord_num; r++ ) { if ( bonds4[i][j][k][l] & bit[r] ) { // Bond is open, so close it. bonds4[i][j][k][l] &= unbit[r]; // Mark the bond closed at the nn site. get_nn_site_in_dir(r,i,j,k,l); bonds4[nn_site[0]][nn_site[1]][nn_site[2]][nn_site[3]] &= unbit[inverse_direction((i+j+k+l)%2,r)]; num_opened--; break; } } } } while ( num_opened < target_num_opened ) { i = (int)(size*PRNG1()); j = (int)(size*PRNG1()); k = (int)(size*PRNG1()); l = (int)(size*PRNG1()); if ( SITE_IS_OCCUPIED_4(i,j,k,l) ) { // Look for a closed bond. for ( r=0; r<coord_num; r++ ) { if ( ! ( bonds4[i][j][k][l] & bit[r] ) ) { // Bond is closed, so open it (assuming there is // an occupied nn site in direction r). if ( get_nn_site_in_dir(r,i,j,k,l) ) { // Nearest neighbour site exists. if ( SITE_IS_OCCUPIED_4(nn_site[0],nn_site[1],nn_site[2],nn_site[3]) ) { bonds4[i][j][k][l] |= bit[r]; // Mark the bond open at the nn site. bonds4[nn_site[0]][nn_site[1]][nn_site[2]][nn_site[3]] |= bit[inverse_direction((i+j+k+l)%2,r)]; num_opened++; break; } } } } } } break; } if ( bond_diluted ) mark_all_sites_unvisited(); return ( num_opened ); }