void electric_field_zero_core( int grid_size , float *elec_grid , float *surface_grid , float internal_value ) { /************/ /* Co-ordinates */ int x , y , z ; /************/ for( x = 0 ; x < grid_size ; x ++ ) { for( y = 0 ; y < grid_size ; y ++ ) { for( z = 0 ; z < grid_size ; z ++ ) { if( surface_grid[gaddress(x,y,z,grid_size)] == (float)internal_value ) elec_grid[gaddress(x,y,z,grid_size)] = (float)0 ; } } } /************/ return ; }
void electric_field_init(struct Structure This_Structure, struct atom_values **atoms_out, int *natoms_in_out, fftw_real * grid, int grid_size) { // Bien, vamos a arrejuntar todo lo interesante... int natoms = 0, residue, atom, x, y, z; for (residue = 1; residue <= This_Structure.length; residue++) natoms += This_Structure.Residue[residue].size; int natoms_in = natoms % IN_NFLOATS == 0 ? natoms / IN_NFLOATS : natoms / IN_NFLOATS + 1; // El array debe estar alineado a IN_NFLOATS * 4 bytes struct atom_values *atoms = memalign(IN_NFLOATS * 4, natoms_in * sizeof(struct atom_values)); int i = 0; for (residue = 1; residue <= This_Structure.length; residue++) for (atom = 1; atom <= This_Structure.Residue[residue].size; atom++) { if (This_Structure.Residue[residue].Atom[atom].charge == 0) { natoms--; continue; } atoms[i/IN_NFLOATS].xs[i%IN_NFLOATS] = This_Structure.Residue[residue].Atom[atom].coord[1]; atoms[i/IN_NFLOATS].ys[i%IN_NFLOATS] = This_Structure.Residue[residue].Atom[atom].coord[2]; atoms[i/IN_NFLOATS].zs[i%IN_NFLOATS] = This_Structure.Residue[residue].Atom[atom].coord[3]; atoms[i/IN_NFLOATS].charges[i%IN_NFLOATS] = This_Structure.Residue[residue].Atom[atom].charge; i++; } // Me aseguro de que todos los átomos quedan inicializados en caso de que // su número no sea múltiplo de IN_NFLOATS. Los átomos con carga 0 no afectan al // cálculo ya que la carga se usa para multiplicar el incremento de phi, // así que es seguro computar estos "átomos" de más. for (; i % IN_NFLOATS != 0; i++) { atoms[i/IN_NFLOATS].xs[i%IN_NFLOATS] = 0; atoms[i/IN_NFLOATS].ys[i%IN_NFLOATS] = 0; atoms[i/IN_NFLOATS].zs[i%IN_NFLOATS] = 0; atoms[i/IN_NFLOATS].charges[i%IN_NFLOATS] = 0; } *natoms_in_out = natoms % IN_NFLOATS == 0 ? natoms / IN_NFLOATS : natoms / IN_NFLOATS + 1; *atoms_out = atoms; /************/ for (x = 0; x < grid_size; x++) { for (y = 0; y < grid_size; y++) { for (z = 0; z < grid_size; z++) { grid[gaddress(x, y, z, grid_size)] = (fftw_real) 0; } } } /************/ setvbuf(stdout, (char *)NULL, _IONBF, 0); }
void discretise_structure( struct Structure This_Structure , float grid_span , int grid_size , float *grid ) { /************/ /* Counters */ int residue , atom ; /* Co-ordinates */ int x , y , z ; int steps , x_step , y_step , z_step ; float x_centre , y_centre , z_centre ; /* Variables */ float distance , one_span ; /************/ one_span = grid_span / (float)grid_size ; distance = 1.8 ; /************/ for( x = 0 ; x < grid_size ; x ++ ) { for( y = 0 ; y < grid_size ; y ++ ) { for( z = 0 ; z < grid_size ; z ++ ) { grid[gaddress(x,y,z,grid_size)] = (float)0 ; } } } /************/ steps = (int)( ( distance / one_span ) + 1.5 ) ; for( residue = 1 ; residue <= This_Structure.length ; residue ++ ) { for( atom = 1 ; atom <= This_Structure.Residue[residue].size ; atom ++ ) { x = gord( This_Structure.Residue[residue].Atom[atom].coord[1] , grid_span , grid_size ) ; y = gord( This_Structure.Residue[residue].Atom[atom].coord[2] , grid_span , grid_size ) ; z = gord( This_Structure.Residue[residue].Atom[atom].coord[3] , grid_span , grid_size ) ; for( x_step = max( ( x - steps ) , 0 ) ; x_step <= min( ( x + steps ) , ( grid_size - 1 ) ) ; x_step ++ ) { x_centre = gcentre( x_step , grid_span , grid_size ) ; for( y_step = max( ( y - steps ) , 0 ) ; y_step <= min( ( y + steps ) , ( grid_size - 1 ) ) ; y_step ++ ) { y_centre = gcentre( y_step , grid_span , grid_size ) ; for( z_step = max( ( z - steps ) , 0 ) ; z_step <= min( ( z + steps ) , ( grid_size - 1 ) ) ; z_step ++ ) { z_centre = gcentre( z_step , grid_span , grid_size ) ; if( pythagoras( This_Structure.Residue[residue].Atom[atom].coord[1] , This_Structure.Residue[residue].Atom[atom].coord[2] , This_Structure.Residue[residue].Atom[atom].coord[3] , x_centre , y_centre , z_centre ) < distance ) grid[gaddress(x_step,y_step,z_step,grid_size)] = (float)1 ; } } } } } /************/ return ; }
void surface_grid( float grid_span , int grid_size , float *grid , float surface , float internal_value ) { /************/ /* Counters */ int x , y , z ; int steps , x_step , y_step , z_step ; /* Variables */ float one_span ; int at_surface ; /************/ one_span = grid_span / (float)grid_size ; /************/ /* Surface grid atoms */ steps = (int)( ( surface / one_span ) + 1.5 ) ; for( x = 0 ; x < grid_size ; x ++ ) { for( y = 0 ; y < grid_size ; y ++ ) { for( z = 0 ; z < grid_size ; z ++ ) { if( (int)grid[gaddress(x,y,z,grid_size)] == 1 ) { at_surface = 0 ; for( x_step = max( x - steps , 0 ) ; x_step <= min( x + steps , grid_size - 1 ) ; x_step ++ ) { for( y_step = max( y - steps , 0 ) ; y_step <= min( y + steps , grid_size - 1 ) ; y_step ++ ) { for( z_step = max( z - steps , 0 ) ; z_step <= min( z + steps , grid_size - 1 ) ; z_step ++ ) { if( (int)grid[gaddress(x_step,y_step,z_step,grid_size)] == 0 ) { if( ( (float)( ( ( x_step - x ) * ( x_step - x ) ) + ( ( y_step - y ) * ( y_step - y ) ) + ( ( z_step - z ) * ( z_step - z ) ) ) * one_span * one_span ) < ( surface * surface ) ) at_surface = 1 ; } } } } if( at_surface == 0 ) grid[gaddress(x,y,z,grid_size)] = (float)internal_value ; } } } } /************/ return ; }
void electric_field(struct Structure This_Structure, float grid_span, int grid_size, float *grid) { /************/ /* Counters */ int residue, atom; /* Co-ordinates */ int x, y, z; float x_centre, y_centre, z_centre; /* Variables */ float distance; float phi, epsilon; /************/ for (x = 0; x < grid_size; x++) { for (y = 0; y < grid_size; y++) { for (z = 0; z < grid_size; z++) { grid[gaddress(x, y, z, grid_size)] = (float)0; } } } /************/ setvbuf(stdout, (char *)NULL, _IONBF, 0); printf(" electric field calculations ( one dot / grid sheet ) "); for (residue = 1; residue <= This_Structure.length; residue++) { printf("."); for (atom = 1; atom <= This_Structure.Residue[residue].size; atom++) { if (This_Structure.Residue[residue].Atom[atom].charge == 0) continue; for (x = 0; x < grid_size; x++) { x_centre = gcentre(x, grid_span, grid_size); for (y = 0; y < grid_size; y++) { y_centre = gcentre(y, grid_span, grid_size); for (z = 0; z < grid_size; z++) { z_centre = gcentre(z, grid_span, grid_size); // Inlined pythagoras function with a macro to avoid call overhead distance = PYTHAGORAS(This_Structure.Residue[residue].Atom[atom].coord[1], This_Structure.Residue[residue].Atom[atom].coord[2], This_Structure.Residue[residue].Atom[atom].coord[3], x_centre, y_centre, z_centre); if (distance < 2.0) distance = 2.0; if (distance >= 2.0) { if (distance >= 8.0) { epsilon = 80; } else { if (distance <= 6.0) { epsilon = 4; } else { epsilon = (38 * distance) - 224; } } grid[gaddress(x, y, z, grid_size)] += (This_Structure.Residue[residue].Atom[atom].charge / (epsilon * distance)); } } } } } } printf("\n"); /************/ }
void electric_point_charge(struct Structure This_Structure, float grid_span, int grid_size, float *grid) { /************/ /* Counters */ int residue, atom; /* Co-ordinates */ int x, y, z; int x_low, x_high, y_low, y_high, z_low, z_high; float a, b, c; float x_corner, y_corner, z_corner; float w; /* Variables */ float one_span; /************/ for (x = 0; x < grid_size; x++) { for (y = 0; y < grid_size; y++) { for (z = 0; z < grid_size; z++) { grid[gaddress(x, y, z, grid_size)] = (float)0; } } } /************/ one_span = grid_span / (float)grid_size; for (residue = 1; residue <= This_Structure.length; residue++) { for (atom = 1; atom <= This_Structure.Residue[residue].size; atom++) { if (This_Structure.Residue[residue].Atom[atom].charge != 0) { x_low = gord(This_Structure.Residue[residue].Atom[atom].coord[1] - (one_span / 2), grid_span, grid_size); y_low = gord(This_Structure.Residue[residue].Atom[atom].coord[2] - (one_span / 2), grid_span, grid_size); z_low = gord(This_Structure.Residue[residue].Atom[atom].coord[3] - (one_span / 2), grid_span, grid_size); x_high = x_low + 1; y_high = y_low + 1; z_high = z_low + 1; a = This_Structure.Residue[residue].Atom[atom].coord[1] - gcentre(x_low, grid_span, grid_size) - (one_span / 2); b = This_Structure.Residue[residue].Atom[atom].coord[2] - gcentre(y_low, grid_span, grid_size) - (one_span / 2); c = This_Structure.Residue[residue].Atom[atom].coord[3] - gcentre(z_low, grid_span, grid_size) - (one_span / 2); for (x = x_low; x <= x_high; x++) { x_corner = one_span * ((float)(x - x_high) + .5); for (y = y_low; y <= y_high; y++) { y_corner = one_span * ((float)(y - y_high) + .5); for (z = z_low; z <= z_high; z++) { z_corner = one_span * ((float)(z - z_high) + .5); w = ((x_corner + a) * (y_corner + b) * (z_corner + c)) / (8.0 * x_corner * y_corner * z_corner); grid[gaddress(x, y, z, grid_size)] += (float)(w * This_Structure.Residue[residue].Atom[atom].charge); } } } } } } /************/ }
void electric_field(struct Structure This_Structure, float grid_span, int grid_size, fftw_real * grid, int *shared_x, struct atom_values *atoms, int natoms_in) { /************/ /* Counters */ int residue, atom, i; /* Co-ordinates */ int x, y, z; float x_centre, y_centre, z_centre; /* Variables */ float distance; float phi, epsilon; while (1) { pthread_mutex_lock(&shared_x_mutex); x = *shared_x; *shared_x = *shared_x + 1; pthread_mutex_unlock(&shared_x_mutex); if (x >= grid_size) break; printf("."); x_centre = gcentre(x, grid_span, grid_size); __mtype mx_centre = _set1_ps(x_centre); for (y = 0; y < grid_size; y++) { y_centre = gcentre(y, grid_span, grid_size); __mtype my_centre = _set1_ps(y_centre); for (z = 0; z < grid_size; z++) { z_centre = gcentre(z, grid_span, grid_size); __mtype mz_centre = _set1_ps(z_centre); phi = 0; __mtype phis = _set1_ps(0.0); for (i = 0; i < natoms_in; i++) { __mtype xs = _load_ps(atoms[i].xs); __mtype ys = _load_ps(atoms[i].ys); __mtype zs = _load_ps(atoms[i].zs); __mtype charges = _load_ps(atoms[i].charges); __mtype distances; // Calculo distancias (el original pythagoras) __mtype diffxs = _sub_ps(xs, mx_centre); __mtype diffys = _sub_ps(ys, my_centre); __mtype diffzs = _sub_ps(zs, mz_centre); diffxs = _mul_ps(diffxs, diffxs); diffys = _mul_ps(diffys, diffys); diffzs = _mul_ps(diffzs, diffzs); distances = _add_ps(diffxs, diffys); distances = _add_ps(distances, diffzs); distances = _sqrt_ps(distances); // A partir de aquí implemento los if's originales usando solo máscaras de bits // Trunco a 2 como mínimo distances = _max_ps(distances, _set1_ps(2.0)); __mtype epsilons = _set1_ps(0.0); __mtype tmp; __mtype tmp2; // if >= 8 tmp = _cmpge_ps(distances, _set1_ps(8.0)); epsilons = _and_ps(tmp, _set1_ps(80.0)); // else if <= 6 tmp = _cmple_ps(distances, _set1_ps(6.0)); tmp = _and_ps(tmp, _set1_ps(4.0)); epsilons = _or_ps(epsilons, tmp); // else tmp = _cmpgt_ps(distances, _set1_ps(6.0)); tmp2 = _cmpeq_ps(epsilons, _set1_ps(0.0)); tmp = _and_ps(tmp, tmp2); tmp2 = _mul_ps(distances, _set1_ps(38.0)); tmp2 = _sub_ps(tmp2, _set1_ps(224.0)); tmp = _and_ps(tmp, tmp2); // Valor final epsilons = _or_ps(epsilons, tmp); // Calculo las phis tmp = _mul_ps(epsilons, distances); tmp = _div_ps(charges, tmp); // Acumulo las phis phis = _add_ps(phis, tmp); } #ifdef USE_AVX phis = _mm256_hadd_ps(phis, phis); phis = _mm256_hadd_ps(phis, phis); phi = phis[0] + phis[4]; #else float tmp, tmp2; tmp = phis[0] + phis[1]; tmp2 = phis[2] + phis[3]; phi = tmp + tmp2; #endif grid[gaddress(x, y, z, grid_size)] = (fftw_real) phi; } } } /************/ return; }
void electric_field( struct Structure This_Structure , float grid_span , int grid_size , fftw_real *grid ) { /* Counters */ int residue , atom ; /* Co-ordinates */ int x, y, z, i, k; float *coord1, *coord2, *coord3, *charge; /* Blocking stuff */ int block_size = 512; /* Threads stuff */ int num_threads = 2; ready_threads = 0; Thinfo *thinfo; pthread_t threads[num_threads]; int maxTotalElements = 0; int totalElements = 0; for (residue = 1; residue <= This_Structure.length; residue++) maxTotalElements += This_Structure.Residue[residue].size; allocatedata_electric_field(&charge, &coord1, &coord2, &coord3, maxTotalElements); for (residue = 1; residue <= This_Structure.length; residue++) for (atom = 1; atom <= This_Structure.Residue[residue].size; atom++) if (This_Structure.Residue[residue].Atom[atom].charge != 0){ charge[totalElements] = This_Structure.Residue[residue].Atom[atom].charge; coord1[totalElements] = This_Structure.Residue[residue].Atom[atom].coord[1]; coord2[totalElements] = This_Structure.Residue[residue].Atom[atom].coord[2]; coord3[totalElements] = This_Structure.Residue[residue].Atom[atom].coord[3]; totalElements++; } for (x = 0; x < grid_size; x++) for (y = 0; y < grid_size; y++) for (z = 0; z < grid_size; z++) grid[gaddress(x,y,z,grid_size)] = (fftw_real)0; setvbuf( stdout , (char *)NULL , _IONBF , 0 ) ; printf( " electric field calculations ( one dot / grid sheet ) " ) ; thinfo = (Thinfo *) malloc (sizeof(Thinfo)*num_threads); if (thinfo == NULL) { printf("No memory.\n"); exit(-1); } int elements_per_thread = grid_size/num_threads; for (i = 0; i < num_threads; i++) { thinfo[i].coord1 = coord1; thinfo[i].coord2 = coord2; thinfo[i].coord3 = coord3; thinfo[i].charge = charge; thinfo[i].grid_size = grid_size; thinfo[i].grid_span = grid_span; thinfo[i].grid = grid; thinfo[i].block_size = block_size; thinfo[i].totalElements = totalElements; thinfo[i].x_start = elements_per_thread*i; thinfo[i].x_end = elements_per_thread*i+elements_per_thread; thinfo[i].num_threads = num_threads; } //Ensures repartition of all elements thinfo[num_threads-1].x_end = grid_size; int rc; for (i=0; i < num_threads; i++) { rc = pthread_create(&threads[i], NULL, th_electric_field, (void *) &thinfo[i]); if (rc) { printf("ERROR creating thread\n"); exit(-1); } } for (i=0; i < num_threads; i++) { rc = pthread_join(threads[i], NULL); if (rc) { printf("ERROR joining thread\n"); exit(-1); } } printf( "\n" ) ; #ifdef grid_out FILE *f = fopen("grid_dolent", "w"); for (x = 0; x < grid_size; x++) for (y = 0; y < grid_size; y++) for (z = 0; z < grid_size; z++) fprintf(f,"%f\n",grid[gaddress(x,y,z,grid_size)]); #endif return ; }
void *th_electric_field(void *argthinfo) { Thinfo *thinfo = (Thinfo *) argthinfo; float * charge = thinfo->charge; float * coord1 = thinfo->coord1; float * coord2 = thinfo->coord2; float * coord3 = thinfo->coord3; float grid_span = thinfo->grid_span; int grid_size = thinfo->grid_size; int totalElements = thinfo->totalElements; int block_size = thinfo->block_size; int x_start = thinfo->x_start; int x_end = thinfo->x_end; int num_threads = thinfo->num_threads; fftw_real *grid = thinfo->grid; float phi; int block_ini, block_fin; float x_centre, y_centre, z_centre; int x, y, z, i, k; __m128 _phi_tmp; __m128 _phiSet; float *phiSet = (float *) &_phiSet; float * distance; float * epsilon; if ((posix_memalign((void**)&distance, 16, 4*sizeof(float))!=0)) { printf("No memory.\n"); exit(-1); } if ((posix_memalign((void**)&epsilon, 16, 4*sizeof(float))!=0)) { printf("No memory.\n"); exit(-1); } for (block_ini = 0; block_ini < totalElements-(block_size-1); block_ini += block_size) { block_fin = block_ini + block_size; for (x = x_start; x < x_end; x++) { x_centre = gcentre(x ,grid_span, grid_size ) ; for (y = 0; y < grid_size; y++) { y_centre = gcentre(y ,grid_span ,grid_size ) ; for (z = 0; z < grid_size; z++) { z_centre = gcentre( z , grid_span , grid_size ) ; phi = 0 ; computeBlock(block_ini, block_fin); grid[gaddress(x,y,z,grid_size)] += (fftw_real)phi; } } } //Changing block. Must wait for others threads to finish. pthread_mutex_lock(&mut); ready_threads++; if (ready_threads==num_threads) { ready_threads=0; pthread_cond_broadcast(&cond); } else { pthread_cond_wait(&cond, &mut); } pthread_mutex_unlock(&mut); } //Last block is not a multiple of block_size if (block_ini != totalElements) { for (x = x_start; x < x_end; x++ ) { x_centre = gcentre(x, grid_span, grid_size) ; for (y = 0; y < grid_size; y++) { y_centre = gcentre(y, grid_span, grid_size) ; for (z = 0; z < grid_size; z++) { z_centre = gcentre(z, grid_span, grid_size) ; phi = 0 ; computeEndBlock(block_ini, totalElements); grid[gaddress(x,y,z,grid_size)] += (fftw_real)phi ; } } } } pthread_exit(NULL); return ; }