//record parameters. we will determine which ones need to be adjusted later param_g *record_params(system_t *system) { char last_atomtype[MAXLINE]; last_atomtype[0] = '\0'; //initialize last_atomtype atom_t *atom_ptr; param_g *rval = calloc(1, sizeof(param_g)); memnullcheck(rval, sizeof(param_g), __LINE__ - 1, __FILE__); param_t *param_list = calloc(1, sizeof(param_t)); //return value memnullcheck(param_list, sizeof(param_t), __LINE__ - 1, __FILE__); param_t *param_ptr = param_list; //used to seek through param list param_t *prev_param_ptr = 0; rval->alpha = system->polar_damp; rval->last_alpha = system->polar_damp; for (atom_ptr = system->molecules->atoms; atom_ptr; atom_ptr = atom_ptr->next) { if (strcasecmp(atom_ptr->atomtype, last_atomtype)) { strcpy(param_ptr->atomtype, atom_ptr->atomtype); param_ptr->charge = atom_ptr->charge; param_ptr->epsilon = atom_ptr->epsilon; param_ptr->sigma = atom_ptr->sigma; param_ptr->omega = atom_ptr->omega; param_ptr->pol = atom_ptr->polarizability; param_ptr->c6 = atom_ptr->c6; param_ptr->c8 = atom_ptr->c8; param_ptr->c10 = atom_ptr->c10; param_ptr->last_charge = param_ptr->charge; param_ptr->last_epsilon = param_ptr->epsilon; param_ptr->last_sigma = param_ptr->sigma; param_ptr->last_omega = param_ptr->omega; param_ptr->last_pol = param_ptr->pol; param_ptr->last_c6 = param_ptr->c6; param_ptr->last_c8 = param_ptr->c8; param_ptr->last_c10 = param_ptr->c10; param_ptr->next = calloc(1, sizeof(param_t)); memnullcheck(param_ptr->next, sizeof(param_t), __LINE__ - 1, __FILE__); prev_param_ptr = param_ptr; param_ptr = param_ptr->next; strcpy(last_atomtype, atom_ptr->atomtype); } } prev_param_ptr->next = NULL; free(param_ptr); //count ntypes for (param_ptr = param_list; param_ptr; param_ptr = param_ptr->next) { for (atom_ptr = system->molecules->atoms; atom_ptr; atom_ptr = atom_ptr->next) if (!strcasecmp(param_ptr->atomtype, atom_ptr->atomtype)) ++(param_ptr->ntypes); } rval->type_params = param_list; return rval; }
void free_my_pairs ( molecule_t * molecule ) { int i = 0; pair_t ** ptr_array = NULL; atom_t * aptr; pair_t * pptr; //build an array of pairs for ( aptr = molecule->atoms; aptr; aptr = aptr->next ) { for ( pptr = aptr->pairs; pptr; pptr = pptr->next ) { ptr_array = realloc(ptr_array, sizeof(pair_t *)*(i+1)); memnullcheck(ptr_array,sizeof(pair_t *)*(i+1),__LINE__-1, __FILE__); ptr_array[i] = pptr; ++i; } } //free the pairs for (--i; i>=0; i--) free(ptr_array[i]); //zero out the heads for (aptr = molecule->atoms; aptr; aptr=aptr->next ) aptr->pairs = NULL; //free the temp array free(ptr_array); return; }
// free all pairs void free_all_pairs(system_t * system) { int i, j; pair_t *pair_ptr; pair_t **ptr_array = NULL; j=0; //pair array index //build an array of all pair pointers for ( i=0; i< system->natoms ; i++ ) { for ( pair_ptr = system->atom_array[i]->pairs; pair_ptr; pair_ptr = pair_ptr->next ) { ptr_array = realloc(ptr_array, sizeof(pair_t *)*(j + 1)); memnullcheck(ptr_array,sizeof(pair_t *)*(j+1),__LINE__-1, __FILE__); ptr_array[j] = pair_ptr; j++; } } /* free the whole array of ptrs */ while ( j-- ) free(ptr_array[j]); /* zero out the heads */ for ( i=0; i< system->natoms; i++ ) system->atom_array[i]->pairs = NULL; /* free our temporary array */ if(ptr_array) free(ptr_array); }
void allocqmrotation(system_t *system, molecule_t *molecule_ptr) { int i; molecule_ptr->quantum_rotational_energies = calloc(system->quantum_rotation_level_max, sizeof(double)); memnullcheck(molecule_ptr->quantum_rotational_energies, system->quantum_rotation_level_max * sizeof(double), __LINE__ - 1, __FILE__); molecule_ptr->quantum_rotational_eigenvectors = calloc(system->quantum_rotation_level_max, sizeof(complex_t *)); memnullcheck(molecule_ptr->quantum_rotational_eigenvectors, system->quantum_rotation_level_max * sizeof(complex_t *), __LINE__ - 1, __FILE__); for (i = 0; i < system->quantum_rotation_level_max; i++) { molecule_ptr->quantum_rotational_eigenvectors[i] = calloc((system->quantum_rotation_l_max + 1) * (system->quantum_rotation_l_max + 1), sizeof(complex_t)); memnullcheck(molecule_ptr->quantum_rotational_eigenvectors[i], (system->quantum_rotation_l_max + 1) * (system->quantum_rotation_l_max + 1) * sizeof(complex_t), __LINE__ - 1, __FILE__); } molecule_ptr->quantum_rotational_eigensymmetry = calloc(system->quantum_rotation_level_max, sizeof(int)); memnullcheck(molecule_ptr->quantum_rotational_eigensymmetry, system->quantum_rotation_level_max * sizeof(int), __LINE__ - 1, __FILE__); return; }
void addSorbateToList( system_t * system, char *sorbate_type ){ // grow array system->sorbateInfo = realloc(system->sorbateInfo, system->sorbateCount*sizeof(sorbateInfo_t)); memnullcheck(system->sorbateInfo, system->sorbateCount*sizeof(sorbateInfo_t), __LINE__-1, __FILE__); // set sorbate type for the new element strcpy( system->sorbateInfo[system->sorbateCount-1].id, sorbate_type ); // send a status update to stdout char buffer[MAXLINE]; sprintf(buffer, "INPUT: System will track individual stats for sorbate %s.\n", system->sorbateInfo[system->sorbateCount-1].id ); output( buffer ); return; }
//free vdw pointer which keeps track of e_iso energies void free_vdw_eiso(vdw_t * vdw_eiso_info) { vdw_t * vp; vdw_t ** varray = NULL; int i=0; for ( vp = vdw_eiso_info; vp; vp=vp->next ) { varray = realloc(varray, sizeof(vdw_t *)*(i+1)); memnullcheck(varray,sizeof(vdw_t *)*(i+1), __LINE__-1, __FILE__); varray[i]=vp; i++; } while ( i>0 ) { i--; free(varray[i]); } free(varray); return; }
void free_my_atoms ( molecule_t * molecules ) { int i = 0; atom_t * aptr; atom_t ** aarray = NULL; //build an array of atoms for ( aptr= molecules->atoms; aptr; aptr=aptr->next ) { aarray = realloc(aarray, sizeof(atom_t *)*(i+1)); memnullcheck(aarray,sizeof(atom_t *)*(i+1), __LINE__-1, __FILE__); aarray[i] = aptr; i++; } //free the atoms while ( i-- ) free(aarray[i]); //free the temp array free(aarray); return; }
// free all molecules void free_all_molecules(system_t * system, molecule_t * molecules) { int i; molecule_t **marray = NULL; molecule_t *mptr; /* build the ptr array */ // we can't free all of system->molecule_array since it's redundant for(mptr = molecules, i = 0; mptr; mptr = mptr->next) { free_my_atoms(mptr); marray = realloc(marray, sizeof(molecule_t *)*(i + 1)); memnullcheck(marray,sizeof(molecule_t *)*(i + 1),__LINE__-1, __FILE__); marray[i] = mptr; i++; } /* free the whole array of ptrs */ for(--i; i >= 0; i--) free(marray[i]); /* free our temporary arrays */ free(marray); return; }
/* apply what was already determined in checkpointing */ void make_move(system_t *system) { int i, j, k, p, q; cavity_t *cavities_array; int cavities_array_counter, random_index; double com[3], rand[3]; molecule_t *molecule_ptr; atom_t *atom_ptr; pair_t *pair_ptr; /* update the cavity grid prior to making a move */ if (system->cavity_bias) { cavity_update_grid(system); system->checkpoint->biased_move = 0; } switch (system->checkpoint->movetype) { case MOVETYPE_INSERT: /* insert a molecule at a random pos and orientation */ /* umbrella sampling */ if (system->cavity_bias && system->cavities_open) { /* doing a biased move - this flag lets mc.c know about it */ system->checkpoint->biased_move = 1; /* make an array of possible insertion points */ cavities_array = calloc(system->cavities_open, sizeof(cavity_t)); memnullcheck(cavities_array, system->cavities_open * sizeof(cavity_t), __LINE__ - 1, __FILE__); for (i = 0, cavities_array_counter = 0; i < system->cavity_grid_size; i++) { for (j = 0; j < system->cavity_grid_size; j++) { for (k = 0; k < system->cavity_grid_size; k++) { if (!system->cavity_grid[i][j][k].occupancy) { for (p = 0; p < 3; p++) cavities_array[cavities_array_counter].pos[p] = system->cavity_grid[i][j][k].pos[p]; ++cavities_array_counter; } } /* end k */ } /* end j */ } /* end i */ /* insert randomly at one of the free cavity points */ random_index = (system->cavities_open - 1) - (int)rint(((double)(system->cavities_open - 1)) * get_rand(system)); for (p = 0; p < 3; p++) com[p] = cavities_array[random_index].pos[p]; /* free the insertion array */ free(cavities_array); } // end umbrella else { /* insert the molecule to a random location within the unit cell */ for (p = 0; p < 3; p++) rand[p] = 0.5 - get_rand(system); for (p = 0; p < 3; p++) for (q = 0, com[p] = 0; q < 3; q++) com[p] += system->pbc->basis[q][p] * rand[q]; } /* process the inserted molecule */ for (atom_ptr = system->checkpoint->molecule_backup->atoms; atom_ptr; atom_ptr = atom_ptr->next) { /* move the molecule back to the origin and then assign it to com */ for (p = 0; p < 3; p++) atom_ptr->pos[p] += com[p] - system->checkpoint->molecule_backup->com[p]; } /* update the molecular com */ for (p = 0; p < 3; p++) system->checkpoint->molecule_backup->com[p] = com[p]; /* give it a random orientation */ rotate(system, system->checkpoint->molecule_backup, system->pbc, 1.0); // insert into the list if (system->num_insertion_molecules) { // If inserting a molecule from an insertion list, we will always insert at the end system->checkpoint->head->next = system->checkpoint->molecule_backup; system->checkpoint->molecule_backup->next = NULL; } else { if (!system->checkpoint->head) { // if we're at the start of the list: system->molecules = system->checkpoint->molecule_backup; } else { system->checkpoint->head->next = system->checkpoint->molecule_backup; } system->checkpoint->molecule_backup->next = system->checkpoint->molecule_altered; } /* set new altered and tail to reflect the insertion */ system->checkpoint->molecule_altered = system->checkpoint->molecule_backup; system->checkpoint->tail = system->checkpoint->molecule_altered->next; system->checkpoint->molecule_backup = NULL; if (system->num_insertion_molecules) { //multi sorbate // Free all pair memory in the list for (molecule_ptr = system->molecules; molecule_ptr; molecule_ptr = molecule_ptr->next) { for (atom_ptr = molecule_ptr->atoms; atom_ptr; atom_ptr = atom_ptr->next) { pair_ptr = atom_ptr->pairs; while (pair_ptr) { pair_t *temp = pair_ptr; pair_ptr = pair_ptr->next; free(temp); } } } // Generate new pairs lists for all atoms in system setup_pairs(system); } // only one sorbate else update_pairs_insert(system); //reset atom and molecule id's enumerate_particles(system); break; case MOVETYPE_REMOVE: /* remove a randomly chosen molecule */ if (system->cavity_bias) { if (get_rand(system) < pow((1.0 - system->avg_observables->cavity_bias_probability), ((double)system->cavity_grid_size * system->cavity_grid_size * system->cavity_grid_size))) system->checkpoint->biased_move = 0; else system->checkpoint->biased_move = 1; } /* remove 'altered' from the list */ if (!system->checkpoint->head) { /* handle the case where we're removing from the start of the list */ system->checkpoint->molecule_altered = system->molecules; system->molecules = system->molecules->next; } else { system->checkpoint->head->next = system->checkpoint->tail; } free_molecule(system, system->checkpoint->molecule_altered); system->checkpoint->molecule_altered = NULL; /* Insurance against memory errors */ update_pairs_remove(system); //reset atom and molecule id's enumerate_particles(system); break; case MOVETYPE_DISPLACE: /* change coords of 'altered' */ if (system->rd_anharmonic) displace_1D(system, system->checkpoint->molecule_altered, system->move_factor); else if (system->spectre) spectre_displace(system, system->checkpoint->molecule_altered, system->move_factor, system->spectre_max_charge, system->spectre_max_target); else if (system->gwp) { if (system->checkpoint->molecule_altered->atoms->gwp_spin) { displace(system, system->checkpoint->molecule_altered, system->pbc, system->gwp_probability, system->rot_factor); displace_gwp(system, system->checkpoint->molecule_altered, system->gwp_probability); } else displace(system, system->checkpoint->molecule_altered, system->pbc, system->move_factor, system->rot_factor); } else displace(system, system->checkpoint->molecule_altered, system->pbc, system->move_factor, system->rot_factor); break; case MOVETYPE_ADIABATIC: /* change coords of 'altered' */ displace(system, system->checkpoint->molecule_altered, system->pbc, system->adiabatic_probability, 1.0); break; case MOVETYPE_SPINFLIP: if (get_rand(system) < 0.5) system->checkpoint->molecule_altered->nuclear_spin = NUCLEAR_SPIN_PARA; else system->checkpoint->molecule_altered->nuclear_spin = NUCLEAR_SPIN_ORTHO; break; case MOVETYPE_VOLUME: volume_change(system); // I don't want to contribute to the god damned mess -- kmclaugh break; default: error( "MC_MOVES: invalid mc move\n"); die(-1); } return; }
int surface_dimer_parameters(system_t *system, param_g *params) { int i = 0; // generic counter molecule_t *molecule_ptr; atom_t *atom_ptr; param_t *param_ptr; // Default bond partner for atoms without explicit site neighbor atom_t *origin = calloc( sizeof(atom_t), 1 ); // calloc sets pos[] fields all to 0 memnullcheck( origin, sizeof(atom_t), __LINE__-1, __FILE__); system->polar_damp = params->alpha; for (molecule_ptr = system->molecules; molecule_ptr; molecule_ptr = molecule_ptr->next) { for (atom_ptr = molecule_ptr->atoms; atom_ptr; atom_ptr = atom_ptr->next) { for (param_ptr = params->type_params; param_ptr; param_ptr = param_ptr->next) { if( !strcasecmp( param_ptr->atomtype, atom_ptr->atomtype )) { atom_ptr->charge = param_ptr->charge; atom_ptr->epsilon = param_ptr->epsilon; atom_ptr->sigma = param_ptr->sigma; atom_ptr->omega = param_ptr->omega; atom_ptr->polarizability = param_ptr->pol; atom_ptr->c6 = param_ptr->c6; atom_ptr->c8 = param_ptr->c8; atom_ptr->c10 = param_ptr->c10; double perturbation_vector[3]; // Find the the atom that defines the bond axis and store for easy reference atom_t *snPtr = 0; if( atom_ptr->site_neighbor_id == 0 ) snPtr = origin; else { snPtr = find_atom_by_id( system, atom_ptr->site_neighbor_id ); if( !snPtr ) { snPtr = origin; printf( "\n*** WARNING ***\n" ); printf( "Bonding partner for atom %d not found ", atom_ptr->bond_id ); printf( "--> %d, possibly invalid. Using origin.\n\n", atom_ptr->site_neighbor_id ); } } // Generate the vector along which the dr perturbations will occur for (i = 0; i < 3; i++) perturbation_vector[i] = atom_ptr->pos[i] - snPtr->pos[i]; // Determine how much the bond vector should be scaled to increase the length by dr. double scale = find_scale_factor(perturbation_vector[0], perturbation_vector[1], perturbation_vector[2], param_ptr->dr); // Scale the perturbation vector for (i = 0; i < 3; i++) perturbation_vector[i] *= scale; // Add the vector back to the bond partner coordinates to get the new position. for (i = 0; i < 3; i++) atom_ptr->pos[i] = snPtr->pos[i] + perturbation_vector[i]; } } // for param_ptr } // for atom_ptr } // for molecule_ptr free(origin); return (0); }
/* make an exact copy of src */ molecule_t *copy_molecule(system_t *system, molecule_t *src) { molecule_t *dst; atom_t *atom_dst_ptr, *prev_atom_dst_ptr, *atom_src_ptr; pair_t *pair_dst_ptr, *prev_pair_dst_ptr, *pair_src_ptr; /* allocate the start of the new lists */ dst = calloc(1, sizeof(molecule_t)); memnullcheck(dst, sizeof(molecule_t), __LINE__ - 1, __FILE__); /* copy molecule attributes */ dst->id = src->id; strcpy(dst->moleculetype, src->moleculetype); dst->mass = src->mass; dst->frozen = src->frozen; dst->adiabatic = src->adiabatic; dst->spectre = src->spectre; dst->target = src->target; dst->nuclear_spin = src->nuclear_spin; dst->rot_partfunc_g = src->rot_partfunc_g; dst->rot_partfunc_u = src->rot_partfunc_u; dst->rot_partfunc = src->rot_partfunc; memcpy(dst->com, src->com, 3 * sizeof(double)); memcpy(dst->wrapped_com, src->wrapped_com, 3 * sizeof(double)); #ifdef QM_ROTATION int i, j; if (system->quantum_rotation) { dst->quantum_rotational_energies = calloc(system->quantum_rotation_level_max, sizeof(double)); memnullcheck(dst->quantum_rotational_energies, system->quantum_rotation_level_max * sizeof(double), __LINE__ - 1, __FILE__); dst->quantum_rotational_eigenvectors = calloc(system->quantum_rotation_level_max, sizeof(complex_t *)); memnullcheck(dst->quantum_rotational_eigenvectors, system->quantum_rotation_level_max * sizeof(complex_t *), __LINE__ - 1, __FILE__); for (i = 0; i < system->quantum_rotation_level_max; i++) { dst->quantum_rotational_eigenvectors[i] = calloc((system->quantum_rotation_l_max + 1) * (system->quantum_rotation_l_max + 1), sizeof(complex_t)); memnullcheck(dst->quantum_rotational_eigenvectors[i], (system->quantum_rotation_l_max + 1) * (system->quantum_rotation_l_max + 1) * sizeof(complex_t), __LINE__ - 1, __FILE__); } dst->quantum_rotational_eigensymmetry = calloc(system->quantum_rotation_level_max, sizeof(int)); memnullcheck(dst->quantum_rotational_eigensymmetry, system->quantum_rotation_level_max * sizeof(int), __LINE__ - 1, __FILE__); memcpy(dst->quantum_rotational_energies, src->quantum_rotational_energies, system->quantum_rotation_level_max * sizeof(double)); for (i = 0; i < system->quantum_rotation_level_max; i++) { for (j = 0; j < (system->quantum_rotation_l_max + 1) * (system->quantum_rotation_l_max + 1); j++) { dst->quantum_rotational_eigenvectors[i][j].real = src->quantum_rotational_eigenvectors[i][j].real; dst->quantum_rotational_eigenvectors[i][j].imaginary = src->quantum_rotational_eigenvectors[i][j].imaginary; } } memcpy(dst->quantum_rotational_eigensymmetry, src->quantum_rotational_eigensymmetry, system->quantum_rotation_level_max * sizeof(int)); } #endif /* QM_ROTATION */ dst->next = NULL; /* new atoms list */ dst->atoms = calloc(1, sizeof(atom_t)); memnullcheck(dst->atoms, sizeof(atom_t), __LINE__ - 1, __FILE__); prev_atom_dst_ptr = dst->atoms; for (atom_dst_ptr = dst->atoms, atom_src_ptr = src->atoms; atom_src_ptr; atom_dst_ptr = atom_dst_ptr->next, atom_src_ptr = atom_src_ptr->next) { atom_dst_ptr->id = atom_src_ptr->id; strcpy(atom_dst_ptr->atomtype, atom_src_ptr->atomtype); atom_dst_ptr->frozen = atom_src_ptr->frozen; atom_dst_ptr->adiabatic = atom_src_ptr->adiabatic; atom_dst_ptr->spectre = atom_src_ptr->spectre; atom_dst_ptr->target = atom_src_ptr->target; atom_dst_ptr->mass = atom_src_ptr->mass; atom_dst_ptr->charge = atom_src_ptr->charge; atom_dst_ptr->gwp_alpha = atom_src_ptr->gwp_alpha; atom_dst_ptr->gwp_spin = atom_src_ptr->gwp_spin; atom_dst_ptr->polarizability = atom_src_ptr->polarizability; atom_dst_ptr->omega = atom_src_ptr->omega; atom_dst_ptr->epsilon = atom_src_ptr->epsilon; atom_dst_ptr->sigma = atom_src_ptr->sigma; atom_dst_ptr->gwp_spin = atom_src_ptr->gwp_spin; atom_dst_ptr->c6 = atom_src_ptr->c6; atom_dst_ptr->c8 = atom_src_ptr->c8; atom_dst_ptr->c10 = atom_src_ptr->c10; atom_dst_ptr->c9 = atom_src_ptr->c9; memcpy(atom_dst_ptr->pos, atom_src_ptr->pos, 3 * sizeof(double)); memcpy(atom_dst_ptr->wrapped_pos, atom_src_ptr->wrapped_pos, 3 * sizeof(double)); memcpy(atom_dst_ptr->ef_static, atom_src_ptr->ef_static, 3 * sizeof(double)); memcpy(atom_dst_ptr->ef_induced, atom_src_ptr->ef_induced, 3 * sizeof(double)); memcpy(atom_dst_ptr->mu, atom_src_ptr->mu, 3 * sizeof(double)); memcpy(atom_dst_ptr->old_mu, atom_src_ptr->old_mu, 3 * sizeof(double)); memcpy(atom_dst_ptr->new_mu, atom_src_ptr->new_mu, 3 * sizeof(double)); atom_dst_ptr->pairs = calloc(1, sizeof(pair_t)); memnullcheck(atom_dst_ptr->pairs, sizeof(pair_t), __LINE__ - 1, __FILE__); pair_dst_ptr = atom_dst_ptr->pairs; prev_pair_dst_ptr = pair_dst_ptr; for (pair_src_ptr = atom_src_ptr->pairs; pair_src_ptr; pair_src_ptr = pair_src_ptr->next) { pair_dst_ptr->rd_energy = pair_src_ptr->rd_energy; pair_dst_ptr->es_real_energy = pair_src_ptr->es_real_energy; pair_dst_ptr->es_self_intra_energy = pair_src_ptr->es_self_intra_energy; pair_dst_ptr->frozen = pair_src_ptr->frozen; pair_dst_ptr->rd_excluded = pair_src_ptr->rd_excluded; pair_dst_ptr->es_excluded = pair_src_ptr->es_excluded; // pair_dst_ptr->charge = pair_src_ptr->charge; // pair_dst_ptr->gwp_alpha = pair_src_ptr->gwp_alpha; // pair_dst_ptr->gwp_spin = pair_src_ptr->gwp_spin; pair_dst_ptr->epsilon = pair_src_ptr->epsilon; pair_dst_ptr->lrc = pair_src_ptr->lrc; pair_dst_ptr->sigma = pair_src_ptr->sigma; pair_dst_ptr->r = pair_src_ptr->r; pair_dst_ptr->rimg = pair_src_ptr->rimg; pair_dst_ptr->next = calloc(1, sizeof(pair_t)); memnullcheck(pair_dst_ptr->next, sizeof(pair_t), __LINE__ - 1, __FILE__); prev_pair_dst_ptr = pair_dst_ptr; pair_dst_ptr = pair_dst_ptr->next; } prev_pair_dst_ptr->next = NULL; free(pair_dst_ptr); /* handle an empty list */ if (!atom_src_ptr->pairs) atom_dst_ptr->pairs = NULL; prev_atom_dst_ptr = atom_dst_ptr; atom_dst_ptr->next = calloc(1, sizeof(atom_t)); memnullcheck(atom_dst_ptr->next, sizeof(atom_t), __LINE__ - 1, __FILE__); } prev_atom_dst_ptr->next = NULL; free(atom_dst_ptr); return (dst); }
int main(int argc, char **argv) { char linebuf[MAXLINE]; char input_file[MAXLINE]; system_t *system; time_t t = time(NULL); struct tm tm = *localtime(&t); /* set the default rank */ rank = 0; size = 1; /* check args */ if(argc < 2) usage(argv[0]); /* start up the MPI chain */ #ifdef MPI MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); #endif /* MPI */ if( !rank ) { sprintf(linebuf, "MPMC (Massively Parallel Monte Carlo) r%d - 2012-2017 GNU Public License\n", VERSION); output(linebuf); sprintf(linebuf, "MAIN: processes started on %d cores @ %d-%d-%d %d:%d:%d\n", size, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); output(linebuf); } #ifndef MPI FILE *procfile; FILE *host; char nodename[MAXLINE]; char cpu[MAXLINE]; struct stat info; // These system calls were causing a fork() that does not play nice with some // MPI implementations (causing some processes to never end... ) /* Collect and output hostname & processor info */ if(access("/proc/cpuinfo",R_OK)!=-1) { // Linux host = popen("hostname","r"); fgets(nodename, MAXLINE, host); sprintf(linebuf, "MAIN: Job running on node -> %s", nodename); output(linebuf); pclose(host); procfile = fopen("/proc/cpuinfo", "r"); while (!feof(procfile)) { fgets(cpu, MAXLINE, procfile); if(strncasecmp(cpu,"model name",10)==0) { sprintf(linebuf, "MAIN: CPU -> %s", cpu); output(linebuf); break; } } fclose(procfile); } else if (stat("/Applications",&info)==0) { // Mac OS output("MAIN: Mac OS detected\n"); host = popen("hostname", "r"); fgets(nodename, MAXLINE, host); sprintf(linebuf, "MAIN: Job running on node -> %s", nodename); output(linebuf); pclose(host); procfile = popen("sysctl -n machdep.cpu.brand_string","r"); fgets(cpu, MAXLINE, procfile); sprintf(linebuf, "MAIN: CPU -> %s", cpu); output(linebuf); pclose(procfile); } #endif // !MPI /* get the config file arg */ strcpy(input_file, argv[1]); sprintf(linebuf, "MAIN: running parameters found in %s\n", input_file); output(linebuf); /* read the input files and setup the simulation */ system = setup_system(input_file); if(!system) { error("MAIN: could not initialize the simulation\n"); die(1); } else { output("MAIN: the simulation has been initialized\n"); } /* install the signal handler to catch SIGTERM cleanly */ terminate_handler(-1, system); signal(SIGTERM, ((void *)(terminate_handler))); signal(SIGUSR1, ((void *)(terminate_handler))); signal(SIGUSR2, ((void *)(terminate_handler))); output("MAIN: signal handler installed\n"); /* allocate space for the statistics */ system->nodestats = calloc(1, sizeof(nodestats_t)); memnullcheck(system->nodestats,sizeof(nodestats_t), __LINE__-1, __FILE__); system->avg_nodestats = calloc(1, sizeof(avg_nodestats_t)); memnullcheck(system->avg_nodestats,sizeof(avg_nodestats_t), __LINE__-1, __FILE__); system->observables = calloc(1, sizeof(observables_t)); memnullcheck(system->observables,sizeof(observables_t), __LINE__-1, __FILE__); system->avg_observables = calloc(1, sizeof(avg_observables_t)); memnullcheck(system->avg_observables,sizeof(avg_observables_t), __LINE__-1, __FILE__); system->checkpoint = calloc(1, sizeof(checkpoint_t)); memnullcheck(system->checkpoint,sizeof(checkpoint_t), __LINE__-1, __FILE__); system->checkpoint->observables = calloc(1, sizeof(observables_t)); memnullcheck(system->checkpoint->observables,sizeof(observables_t), __LINE__-1, __FILE__); system->grids = calloc(1,sizeof(grid_t)); memnullcheck(system->grids,sizeof(grid_t), __LINE__-1, __FILE__); system->grids->histogram = calloc(1,sizeof(histogram_t)); memnullcheck(system->grids->histogram,sizeof(histogram_t), __LINE__-1, __FILE__); system->grids->avg_histogram = calloc(1,sizeof(histogram_t)); memnullcheck(system->grids->avg_histogram,sizeof(histogram_t), __LINE__-1, __FILE__); /* if polarization active, allocate the necessary matrices */ if(system->polarization && !system->cuda && !system->polar_zodid) thole_resize_matrices(system); /* if histogram calculation flag is set, allocate grid */ if(system->calc_hist){ setup_histogram(system); allocate_histogram_grid(system); } /* seed the rng if neccessary */ if ( system->ensemble != ENSEMBLE_TE && system->ensemble != ENSEMBLE_REPLAY ) seed_rng(system, rank); #ifdef MPI MPI_Barrier(MPI_COMM_WORLD); sprintf(linebuf, "MAIN: all %d cores are in sync\n", size); output(linebuf); #endif /* MPI */ /* start the MC simulation */ if(system->ensemble == ENSEMBLE_UVT) { output("MAIN: *******************************************************\n"); output("MAIN: *** starting Grand Canonical Monte Carlo simulation ***\n"); output("MAIN: *******************************************************\n"); } else if(system->ensemble == ENSEMBLE_NVT) { output("MAIN: *************************************************\n"); output("MAIN: *** starting Canonical Monte Carlo simulation ***\n"); output("MAIN: *************************************************\n"); } else if(system->ensemble == ENSEMBLE_NVE) { output("MAIN: ******************************************************\n"); output("MAIN: *** starting Microcanonical Monte Carlo simulation ***\n"); output("MAIN: ******************************************************\n"); } else if(system->ensemble == ENSEMBLE_SURF) { /* surface run */ output("MAIN: *****************************************************\n"); output("MAIN: *** starting potential energy surface calculation ***\n"); output("MAIN: *****************************************************\n"); } else if(system->ensemble == ENSEMBLE_REPLAY) { /* surface fitting run */ output("MAIN: **********************************\n"); output("MAIN: *** starting trajectory replay ***\n"); output("MAIN: **********************************\n"); } else if(system->ensemble == ENSEMBLE_SURF_FIT) { /* surface fitting run */ output("MAIN: *************************************************************\n"); output("MAIN: *** starting potential energy surface fitting calculation ***\n"); output("MAIN: *************************************************************\n"); } else if(system->ensemble == ENSEMBLE_TE) { /* surface fitting run */ output("MAIN: *************************************************\n"); output("MAIN: *** starting single-point energy calculation ***\n"); output("MAIN: *************************************************\n"); } if(system->ensemble == ENSEMBLE_SURF) { /* surface */ if(surface(system) < 0) { error("MAIN: surface module failed on error, exiting\n"); die(1); } } else if(system->ensemble == ENSEMBLE_SURF_FIT) { /* surface fitting */ if( system->surf_fit_arbitrary_configs ) { if( surface_fit_arbitrary( system ) < 0 ) { error("MAIN: surface fitting module (for arbitrary configurations) failed on error, exiting\n"); die(1); } } else if(surface_fit(system) < 0) { error("MAIN: surface fitting module failed on error, exiting\n"); die(1); } } else if(system->ensemble == ENSEMBLE_REPLAY) { /* replay trajectory and recalc energies, etc. */ if(replay_trajectory(system) < 0) { error("MAIN: trajectory replay failed, exiting\n"); die(1); } } else if(system->ensemble == ENSEMBLE_TE) { if(calculate_te(system) < 0) { error("MAIN: single-point energy calculation failed, exiting\n"); die(1); } } else { //else run monte carlo if(mc(system) < 0) { error("MAIN: MC failed on error, exiting\n"); die(1); } } /* cleanup */ output("MAIN: freeing all data structures...."); cleanup(system); output("...done\n"); output("MAIN: simulation exiting successfully\n\n"); die(0); return 0; }
/* returns the number of iterations required */ int thole_iterative(system_t *system) { int i, N, p; int iteration_counter, keep_iterating; atom_t **aa; //atom array int *ranked_array; aa = system->atom_array; N = system->natoms; /* array for ranking */ ranked_array = calloc(N, sizeof(int)); memnullcheck(ranked_array, N * sizeof(int), __LINE__ - 1, __FILE__); for (i = 0; i < N; i++) ranked_array[i] = i; //set all dipoles to alpha*E_static * polar_gamma init_dipoles(system); /* if ZODID is enabled, then stop here and just return the alpha*E dipoles */ if (system->polar_zodid) { free(ranked_array); return (0); } /* iterative solver of the dipole field equations */ keep_iterating = 1; iteration_counter = 0; while (keep_iterating) { iteration_counter++; /* divergence detection */ /* if we fail to converge, then return dipoles as alpha*E */ if (iteration_counter >= MAX_ITERATION_COUNT && system->polar_precision) { for (i = 0; i < N; i++) for (p = 0; p < 3; p++) { aa[i]->mu[p] = aa[i]->polarizability * (aa[i]->ef_static[p] + aa[i]->ef_static_self[p]); aa[i]->ef_induced_change[p] = 0.0; //so we don't break palmo } //set convergence failure flag system->iter_success = 1; free(ranked_array); return (iteration_counter); } //zero out induced e-field for (i = 0; i < system->natoms; i++) for (p = 0; p < 3; p++) aa[i]->ef_induced[p] = 0; //save the current dipole information if we want to calculate precision (or if needed for relaxation) if (system->polar_rrms || system->polar_precision > 0 || system->polar_sor || system->polar_esor) { for (i = 0; i < N; i++) for (p = 0; p < 3; p++) aa[i]->old_mu[p] = aa[i]->mu[p]; } // contract the dipoles with the field tensor (gauss-seidel/gs-ranked optional) contract_dipoles(system, ranked_array); if (system->polar_rrms || system->polar_precision > 0) calc_dipole_rrms(system); /* determine if we are done... */ keep_iterating = are_we_done_yet(system, iteration_counter); // if we would be finished, we want to contract once more to get the next induced field for palmo if (system->polar_palmo && !keep_iterating) palmo_contraction(system, ranked_array); //new gs_ranking if needed if (system->polar_gs_ranked && keep_iterating) update_ranking(system, ranked_array); /* save the dipoles for the next pass */ for (i = 0; i < N; i++) { for (p = 0; p < 3; p++) { /* allow for different successive over-relaxation schemes */ if (system->polar_sor) aa[i]->mu[p] = system->polar_gamma * aa[i]->new_mu[p] + (1.0 - system->polar_gamma) * aa[i]->old_mu[p]; else if (system->polar_esor) aa[i]->mu[p] = (1.0 - exp(-system->polar_gamma * iteration_counter)) * aa[i]->new_mu[p] + exp(-system->polar_gamma * iteration_counter) * aa[i]->old_mu[p]; else aa[i]->mu[p] = aa[i]->new_mu[p]; } } } //end iterate free(ranked_array); /* return the iteration count */ return (iteration_counter); }
molecule_t *read_insertion_molecules(system_t *system) { int j; molecule_t *molecules, *molecule_ptr; atom_t *atom_ptr, *prev_atom_ptr; char linebuf[MAXLINE], *n; FILE *fp; char token_atom[MAXLINE], token_atomid[MAXLINE], token_atomtype[MAXLINE], token_moleculetype[MAXLINE], token_frozen[MAXLINE], token_moleculeid[MAXLINE], token_x[MAXLINE], token_y[MAXLINE], token_z[MAXLINE], token_mass[MAXLINE], token_charge[MAXLINE], token_alpha[MAXLINE], token_epsilon[MAXLINE], token_sigma[MAXLINE], token_omega[MAXLINE], token_gwp_alpha[MAXLINE], token_c6[MAXLINE], token_c8[MAXLINE], token_c10[MAXLINE], token_c9[MAXLINE]; int current_frozen, current_adiabatic, current_spectre, current_target, current_moleculeid, current_atomid, current_site_neighbor; double current_x, current_y, current_z, current_mass, current_charge, current_alpha, current_epsilon, current_sigma, current_omega, current_gwp_alpha, current_c6, current_c8, current_c10, current_c9; int atom_counter; // allocate the start of the list molecules = calloc(1, sizeof(molecule_t)); memnullcheck(molecules,sizeof(molecule_t),__LINE__-1, __FILE__); molecule_ptr = molecules; molecule_ptr->id = 1; molecule_ptr->atoms = calloc(1, sizeof(atom_t)); memnullcheck(molecule_ptr->atoms,sizeof(atom_t),__LINE__-1, __FILE__); atom_ptr = molecule_ptr->atoms; prev_atom_ptr = atom_ptr; // open the molecule input file fp = fopen(system->insert_input, "r"); filecheck(fp,system->insert_input,READ); // clear the linebuffer and read the tokens in atom_counter = 0; memset(linebuf, 0, MAXLINE); n = fgets(linebuf, MAXLINE, fp); while(n) { // clear the tokens memset( token_atom, 0, MAXLINE); memset( token_atomid, 0, MAXLINE); memset( token_atomtype, 0, MAXLINE); memset( token_moleculetype, 0, MAXLINE); memset( token_frozen, 0, MAXLINE); memset( token_moleculeid, 0, MAXLINE); memset( token_x, 0, MAXLINE); memset( token_y, 0, MAXLINE); memset( token_z, 0, MAXLINE); memset( token_mass, 0, MAXLINE); memset( token_charge, 0, MAXLINE); memset( token_alpha, 0, MAXLINE); memset( token_epsilon, 0, MAXLINE); memset( token_sigma, 0, MAXLINE); memset( token_omega, 0, MAXLINE); memset( token_gwp_alpha, 0, MAXLINE); memset(token_c6, 0, MAXLINE); memset(token_c8, 0, MAXLINE); memset(token_c10, 0, MAXLINE); memset(token_c9, 0, MAXLINE); // parse the input line sscanf(linebuf, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n", token_atom, token_atomid, token_atomtype, token_moleculetype, token_frozen, token_moleculeid, token_x, token_y, token_z, token_mass, token_charge, token_alpha, token_epsilon, token_sigma, token_omega, token_gwp_alpha, token_c6, token_c8, token_c10, token_c9 ); if(!strcasecmp(token_atom, "ATOM") && strcasecmp(token_moleculetype, "BOX")) { current_frozen = 0; current_adiabatic = 0; current_spectre = 0; current_target = 0; if(!strcasecmp(token_frozen, "F")) current_frozen = 1; if(!strcasecmp(token_frozen, "A")) current_adiabatic = 1; if(!strcasecmp(token_frozen, "S")) current_spectre = 1; if(!strcasecmp(token_frozen, "T")) current_target = 1; current_moleculeid = atoi(token_moleculeid); current_atomid = atoi(token_atomid); current_x = atof(token_x); current_y = atof(token_y); current_z = atof(token_z); current_mass = atof(token_mass); // mass in amu current_charge = atof(token_charge); current_charge *= E2REDUCED; // convert charge into reduced units current_alpha = atof(token_alpha); current_epsilon = atof(token_epsilon); current_sigma = atof(token_sigma); current_omega = atof(token_omega); current_gwp_alpha = atof(token_gwp_alpha); current_c6 = atof(token_c6); current_c8 = atof(token_c8); current_c10 = atof(token_c10); current_c9 = atof(token_c9); if ( system->cdvdw_sig_repulsion ) { if ( current_epsilon != 1.0 ) { error("warning: setting epsilon to 1.0 (due to sig_repulsion)\n"); current_epsilon = 1.0; } } else if ( system->polarvdw ) { if ( current_sigma != 1.0 ) { error("warning: setting sigma to 1.0 (due to polarvdw)\n"); current_sigma = 1.0; } } // Functionality of site_neighbor disabled in favor of omega/gwp_alpha parameters // Current behavior is to default to atom 0, typically the center of mass for // the molecule. current_site_neighbor = 0; if(current_frozen) current_charge *= system->scale_charge; if(molecule_ptr->id != current_moleculeid) { molecule_ptr->next = calloc(1, sizeof(molecule_t)); memnullcheck(molecule_ptr->next,sizeof(molecule_t),__LINE__-1, __FILE__); molecule_ptr = molecule_ptr->next; molecule_ptr->atoms = calloc(1, sizeof(atom_t)); memnullcheck(molecule_ptr->atoms,sizeof(atom_t),__LINE__-1, __FILE__); prev_atom_ptr->next = NULL; free(atom_ptr); atom_ptr = molecule_ptr->atoms; } strcpy(molecule_ptr->moleculetype, token_moleculetype); molecule_ptr->id = current_moleculeid; molecule_ptr->frozen = current_frozen; molecule_ptr->adiabatic = current_adiabatic; molecule_ptr->spectre = current_spectre; molecule_ptr->target = current_target; molecule_ptr->mass += current_mass; #ifdef QM_ROTATION /* if quantum rot calc. enabled, allocate the necessary structures */ if(system->quantum_rotation && !molecule_ptr->frozen && !molecule_ptr->quantum_rotational_energies ) allocqmrotation(system,molecule_ptr); #endif /* QM_ROTATION */ #ifdef XXX /* if quantum vib calc. enabled, allocate the necessary structures */ if(system->quantum_vibration && !molecule_ptr->frozen) allocqmvibration(system,molecule_ptr); #endif /* XXX */ ++atom_counter; atom_ptr->id = atom_counter; atom_ptr->bond_id = current_atomid; memset(atom_ptr->atomtype, 0, MAXLINE); strcpy(atom_ptr->atomtype, token_atomtype); atom_ptr->frozen = current_frozen; atom_ptr->adiabatic = current_adiabatic; atom_ptr->spectre = current_spectre; atom_ptr->target = current_target; atom_ptr->pos[0] = current_x; atom_ptr->pos[1] = current_y; atom_ptr->pos[2] = current_z; atom_ptr->mass = current_mass; atom_ptr->charge = current_charge; atom_ptr->polarizability = current_alpha; atom_ptr->epsilon = current_epsilon; atom_ptr->sigma = current_sigma; atom_ptr->omega = current_omega; atom_ptr->gwp_alpha = current_gwp_alpha; atom_ptr->c6 = current_c6; atom_ptr->c8 = current_c8; atom_ptr->c10 = current_c10; atom_ptr->c9 = current_c9; if(current_gwp_alpha != 0.) atom_ptr->gwp_spin = 1; else atom_ptr->gwp_spin = 0; atom_ptr->site_neighbor_id = current_site_neighbor; atom_ptr->next = calloc(1, sizeof(atom_t)); memnullcheck(atom_ptr->next,sizeof(atom_t),__LINE__-1, __FILE__); prev_atom_ptr = atom_ptr; atom_ptr = atom_ptr->next; } memset(linebuf, 0, MAXLINE); n = fgets(linebuf, MAXLINE, fp); } // terminate the atom list prev_atom_ptr->next = NULL; free(atom_ptr); // Count the molecules and create an array of pointers, where each pointer // points directly to a molecule in the linked list. While counting the // molecules, check to see whether or not each sorbate is included in the // sorbate statistics list, if it is not, we will create an entry for it // so that each unique class of sorbate will have its own node in the stats // list. ///////////////////////////////////////////////////////////////////////////// // count int molecule_counter = 0; for(molecule_ptr = molecules; molecule_ptr; molecule_ptr = molecule_ptr->next) { molecule_counter++; // Check to see if this molecule is a new sorbate. if( sorbateIs_Not_InList(system, molecule_ptr->moleculetype) ) { system->sorbateCount++; addSorbateToList(system, molecule_ptr->moleculetype); for ( j=0; j<system->sorbateCount; j++ ) { if( !strcasecmp( system->sorbateInfo[j].id, molecule_ptr->moleculetype )){ system->sorbateInfo[j].mass = molecule_ptr->mass; break; } } } } // allocate space for array that will give direct access to insertion-candidate // molecules in the linked list. system->insertion_molecules_array = malloc( molecule_counter * sizeof(molecule_t*) ); memnullcheck(system->insertion_molecules_array, molecule_counter*sizeof(molecule_t *), __LINE__-1, __FILE__); // point array pointers to their corresponding molecules molecule_counter=0; for(molecule_ptr = molecules; molecule_ptr; molecule_ptr = molecule_ptr->next) { system->insertion_molecules_array[ molecule_counter ] = molecule_ptr; molecule_counter++; } system->num_insertion_molecules = molecule_counter; // ERROR CHECKING OF SOME SORT MAY NEED TO GO HERE // WHAT'S ALLOWED/DISALLOWED FOR INSERTED MOLECULES? ///////////////////////////////////////////////////////// fclose(fp); return(molecules); }
molecule_t *read_molecules(FILE * fp, system_t *system) { molecule_t *molecules, *molecule_ptr; atom_t *atom_ptr, *prev_atom_ptr; char linebuf[MAXLINE]; char token_atom[MAXLINE], token_atomid[MAXLINE], token_atomtype[MAXLINE], token_moleculetype[MAXLINE], token_frozen[MAXLINE], token_moleculeid[MAXLINE], token_x[MAXLINE], token_y[MAXLINE], token_z[MAXLINE], token_mass[MAXLINE], token_charge[MAXLINE], token_alpha[MAXLINE], token_epsilon[MAXLINE], token_sigma[MAXLINE], token_omega[MAXLINE], token_gwp_alpha[MAXLINE], token_c6[MAXLINE], token_c8[MAXLINE], token_c10[MAXLINE], token_c9[MAXLINE]; int current_frozen, current_adiabatic, current_spectre, current_target, current_moleculeid, current_atomid, current_site_neighbor, moveable, spectres, targets, atom_counter; double current_x, current_y, current_z, current_mass, current_charge, current_alpha, current_epsilon, current_sigma, current_omega, current_gwp_alpha, current_c6, current_c8, current_c10, current_c9; //, current_molecule_mass; (unused variable) fpos_t file_pos; fgetpos(fp,&file_pos); //get file pointer position, we will restore this when done /* allocate the start of the list */ molecules = calloc(1, sizeof(molecule_t)); memnullcheck(molecules,sizeof(molecule_t), __LINE__-1, __FILE__); molecule_ptr = molecules; molecule_ptr->id = 1; molecule_ptr->atoms = calloc(1, sizeof(atom_t)); memnullcheck(molecule_ptr->atoms,sizeof(atom_t),__LINE__-1, __FILE__); atom_ptr = molecule_ptr->atoms; prev_atom_ptr = atom_ptr; /* clear the linebuffer and read the tokens in */ atom_counter = 0; memset(linebuf, 0, MAXLINE); while(fgets(linebuf,MAXLINE,fp)) { /* clear the tokens */ memset(token_atom, 0, MAXLINE); memset(token_atomid, 0, MAXLINE); memset(token_atomtype, 0, MAXLINE); memset(token_moleculetype, 0, MAXLINE); memset(token_frozen, 0, MAXLINE); memset(token_moleculeid, 0, MAXLINE); memset(token_x, 0, MAXLINE); memset(token_y, 0, MAXLINE); memset(token_z, 0, MAXLINE); memset(token_mass, 0, MAXLINE); memset(token_charge, 0, MAXLINE); memset(token_alpha, 0, MAXLINE); memset(token_epsilon, 0, MAXLINE); memset(token_sigma, 0, MAXLINE); memset(token_omega, 0, MAXLINE); memset(token_gwp_alpha, 0, MAXLINE); memset(token_c6, 0, MAXLINE); memset(token_c8, 0, MAXLINE); memset(token_c10, 0, MAXLINE); memset(token_c9, 0, MAXLINE); /* parse the line */ sscanf(linebuf, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n", token_atom, token_atomid, token_atomtype, token_moleculetype, token_frozen, token_moleculeid, token_x, token_y, token_z, token_mass, token_charge, token_alpha, token_epsilon, token_sigma, token_omega, token_gwp_alpha, token_c6, token_c8, token_c10, token_c9); if(!strncasecmp(token_atom, "END", 3)) break; //we've reached the end of the current molecule, quit looping if(!strcasecmp(token_atom, "ATOM") && strcasecmp(token_moleculetype, "BOX")) { current_frozen = 0; current_adiabatic = 0; current_spectre = 0; current_target = 0; if(!strcasecmp(token_frozen, "F")) current_frozen = 1; if(!strcasecmp(token_frozen, "A")) current_adiabatic = 1; if(!strcasecmp(token_frozen, "S")) current_spectre = 1; if(!strcasecmp(token_frozen, "T")) current_target = 1; current_moleculeid = atoi(token_moleculeid); current_atomid = atoi(token_atomid); current_x = atof(token_x); current_y = atof(token_y); current_z = atof(token_z); current_mass = atof(token_mass); /* mass in amu */ current_charge = atof(token_charge); current_charge *= E2REDUCED; /* convert charge into reduced units */ current_alpha = atof(token_alpha); current_epsilon = atof(token_epsilon); current_sigma = atof(token_sigma); current_omega = atof(token_omega); current_gwp_alpha = atof(token_gwp_alpha); current_c6 = atof(token_c6); current_c8 = atof(token_c8); current_c10 = atof(token_c10); current_c9 = atof(token_c9); if ( system->cdvdw_sig_repulsion ) { if ( current_epsilon != 1.0 ) { error("warning: setting epsilon to 1.0 (due to sig_repulsion)\n"); current_epsilon = 1.0; } } else if ( system->polarvdw && !system->cdvdw_exp_repulsion ) { if ( current_sigma != 1.0 ) { error("warning: setting sigma to 1.0 (due to polarvdw)\n"); current_sigma = 1.0; } } // Functionality of site_neighbor disabled in favor of omega/gwp_alpha parameters // Current behavior is to default to atom 0, typically the center of mass for // the molecule. current_site_neighbor = 0; //atoi( token_site_neighbor ); if(current_frozen) current_charge *= system->scale_charge; if(molecule_ptr->id != current_moleculeid) { molecule_ptr->next = calloc(1, sizeof(molecule_t)); memnullcheck(molecule_ptr,sizeof(molecule_t),__LINE__-1, __FILE__); molecule_ptr = molecule_ptr->next; molecule_ptr->atoms = calloc(1, sizeof(atom_t)); memnullcheck(molecule_ptr->atoms,sizeof(atom_t),__LINE__-1, __FILE__); prev_atom_ptr->next = NULL; free(atom_ptr); atom_ptr = molecule_ptr->atoms; } strcpy(molecule_ptr->moleculetype, token_moleculetype); molecule_ptr->id = current_moleculeid; molecule_ptr->frozen = current_frozen; molecule_ptr->adiabatic = current_adiabatic; molecule_ptr->spectre = current_spectre; molecule_ptr->target = current_target; molecule_ptr->mass += current_mass; #ifdef QM_ROTATION /* if quantum rot calc. enabled, allocate the necessary structures */ if(system->quantum_rotation && !molecule_ptr->frozen && !molecule_ptr->quantum_rotational_energies ) allocqmrotation(system,molecule_ptr); #endif /* QM_ROTATION */ #ifdef XXX /* if quantum vib calc. enabled, allocate the necessary structures */ if(system->quantum_vibration && !molecule_ptr->frozen) allocqmvibration(system,molecule_ptr); #endif /* XXX */ ++atom_counter; atom_ptr->id = atom_counter; atom_ptr->bond_id = current_atomid; memset(atom_ptr->atomtype, 0, MAXLINE); strcpy(atom_ptr->atomtype, token_atomtype); atom_ptr->frozen = current_frozen; atom_ptr->adiabatic = current_adiabatic; atom_ptr->spectre = current_spectre; atom_ptr->target = current_target; atom_ptr->pos[0] = current_x; atom_ptr->pos[1] = current_y; atom_ptr->pos[2] = current_z; atom_ptr->mass = current_mass; atom_ptr->charge = current_charge; atom_ptr->polarizability = current_alpha; atom_ptr->epsilon = current_epsilon; atom_ptr->sigma = current_sigma; atom_ptr->omega = current_omega; atom_ptr->gwp_alpha = current_gwp_alpha; atom_ptr->c6 = current_c6; atom_ptr->c8 = current_c8; atom_ptr->c10 = current_c10; atom_ptr->c9 = current_c9; if(current_gwp_alpha != 0.) atom_ptr->gwp_spin = 1; else atom_ptr->gwp_spin = 0; atom_ptr->site_neighbor_id = current_site_neighbor; atom_ptr->next = calloc(1, sizeof(atom_t)); memnullcheck(atom_ptr->next,sizeof(atom_t),__LINE__-1, __FILE__); prev_atom_ptr = atom_ptr; atom_ptr = atom_ptr->next; } memset(linebuf, 0, MAXLINE); } /* terminate the atom list */ prev_atom_ptr->next = NULL; free(atom_ptr); /* scan the list, make sure that there is at least one moveable molecule */ moveable = 0; spectres = 0; targets = 0; for(molecule_ptr = molecules; molecule_ptr; molecule_ptr = molecule_ptr->next) { if(!molecule_ptr->frozen ) ++moveable; if(molecule_ptr ->target ) ++targets; if(molecule_ptr ->spectre) ++spectres; } if(system->spectre) { if(!spectres || !targets) { error("INPUT: either no targets or spectres found\n"); return(NULL); } } else { if(!moveable) { error("INPUT: no moveable molecules found, there must be at least one in your PQR file\n"); return(NULL); } } if (!atom_counter) { free(molecules); free(molecule_ptr); return(NULL); } //if we're going to read box info, we need to rewind our file if ( system->read_pqr_box_on ) fsetpos(fp,&file_pos); return(molecules); }
/* implements the Markov chain */ int mc(system_t *system) { int j, msgsize; double initial_energy, final_energy, current_energy; double rot_partfunc; observables_t *observables_mpi; avg_nodestats_t *avg_nodestats_mpi; sorbateInfo_t *sinfo_mpi = 0; double *temperature_mpi = 0; char *snd_strct = 0, *rcv_strct = 0; system->count_autorejects = 0; // initialize counter for skipped close (unphysical) contacts // char linebuf[MAXLINE]; (unused variable) #ifdef MPI MPI_Datatype msgtype; #endif /* MPI */ /* allocate the statistics structures */ observables_mpi = calloc(1, sizeof(observables_t)); memnullcheck(observables_mpi, sizeof(observables_t), __LINE__ - 1, __FILE__); avg_nodestats_mpi = calloc(1, sizeof(avg_nodestats_t)); memnullcheck(avg_nodestats_mpi, sizeof(avg_nodestats_t), __LINE__ - 1, __FILE__); // if multiple-sorbates, allocate sorb statistics struct if (system->sorbateCount > 1) { sinfo_mpi = calloc(system->sorbateCount, sizeof(sorbateInfo_t)); memnullcheck(sinfo_mpi, sizeof(sorbateInfo_t), __LINE__ - 1, __FILE__); system->sorbateGlobal = calloc(system->sorbateCount, sizeof(sorbateAverages_t)); memnullcheck(system->sorbateGlobal, sizeof(sorbateAverages_t), __LINE__ - 1, __FILE__); } // compute message size msgsize = sizeof(observables_t) + sizeof(avg_nodestats_t); if (system->calc_hist) msgsize += system->n_histogram_bins * sizeof(int); if (system->sorbateCount > 1) msgsize += system->sorbateCount * sizeof(sorbateInfo_t); #ifdef MPI MPI_Type_contiguous(msgsize, MPI_BYTE, &msgtype); MPI_Type_commit(&msgtype); #endif /* MPI */ /* allocate MPI structures */ snd_strct = calloc(msgsize, 1); memnullcheck(snd_strct, sizeof(msgsize), __LINE__ - 1, __FILE__); if (!rank) { rcv_strct = calloc(size, msgsize); memnullcheck(rcv_strct, size * sizeof(msgsize), __LINE__ - 1, __FILE__); temperature_mpi = calloc(size, sizeof(double)); //temperature list for parallel tempering memnullcheck(temperature_mpi, size * sizeof(double), __LINE__ - 1, __FILE__); } /* update the grid for the first time */ if (system->cavity_bias) cavity_update_grid(system); /* set volume observable */ system->observables->volume = system->pbc->volume; /* get the initial energy of the system */ initial_energy = energy(system); #ifdef QM_ROTATION /* solve for the rotational energy levels */ if (system->quantum_rotation) quantum_system_rotational_energies(system); #endif /* QM_ROTATION */ /* be a bit forgiving of the initial state */ if (!isfinite(initial_energy)) initial_energy = system->observables->energy = MAXVALUE; /* if root, open necessary output files */ if (!rank) if (open_files(system) < 0) { error( "MC: could not open files\n"); return (-1); } // write initial observables to stdout and logs if (!rank) { calc_system_mass(system); // average in the initial values once (we don't want to double-count the initial state when using MPI) update_root_averages(system, system->observables, system->avg_observables); // average in the initial sorbate values if (system->sorbateCount > 1) { update_sorbate_info(system); //local update update_root_sorb_averages(system, system->sorbateInfo); //global update } // write initial observables exactly once if (system->file_pointers.fp_energy) write_observables(system->file_pointers.fp_energy, system, system->observables, system->temperature); if (system->file_pointers.fp_energy_csv) write_observables_csv(system->file_pointers.fp_energy_csv, system, system->observables, system->temperature); output( "MC: initial values:\n"); write_averages(system); } /* save the initial state */ checkpoint(system); /* main MC loop */ for (system->step = 1; system->step <= system->numsteps; (system->step)++) { /* restore the last accepted energy */ initial_energy = system->observables->energy; /* perturb the system */ make_move(system); /* calculate the energy change */ final_energy = energy(system); #ifdef QM_ROTATION /* solve for the rotational energy levels */ if (system->quantum_rotation && (system->checkpoint->movetype == MOVETYPE_SPINFLIP)) quantum_system_rotational_energies(system); #endif /* QM_ROTATION */ if (system->checkpoint->movetype != MOVETYPE_REMOVE) rot_partfunc = system->checkpoint->molecule_altered->rot_partfunc; else rot_partfunc = system->checkpoint->molecule_backup->rot_partfunc; /* treat a bad contact as a reject */ if (!isfinite(final_energy)){ system->observables->energy = MAXVALUE; system->nodestats->boltzmann_factor = 0; } else boltzmann_factor(system, initial_energy, final_energy, rot_partfunc); /* Metropolis function */ if ((get_rand(system) < system->nodestats->boltzmann_factor) && (system->iter_success == 0)) { /////////// ACCEPT current_energy = final_energy; /* checkpoint */ checkpoint(system); register_accept(system); /* SA */ if (system->simulated_annealing) { if (system->simulated_annealing_linear == 1) { system->temperature = system->temperature + (system->simulated_annealing_target - system->temperature) / (system->numsteps - system->step); if (system->numsteps - system->step == 0) system->temperature = system->simulated_annealing_target; } else system->temperature = system->simulated_annealing_target + (system->temperature - system->simulated_annealing_target) * system->simulated_annealing_schedule; } } else { /////////////// REJECT current_energy = initial_energy; //used in parallel tempering //reset the polar iterative failure flag system->iter_success = 0; /* restore from last checkpoint */ restore(system); register_reject(system); } // END REJECT // perform parallel_tempering if ((system->parallel_tempering) && (system->step % system->ptemp_freq == 0)) temper_system(system, current_energy); /* track the acceptance_rate */ track_ar(system->nodestats); /* each node calculates its stats */ update_nodestats(system->nodestats, system->avg_nodestats); /* do this every correlation time, and at the very end */ if (!(system->step % system->corrtime) || (system->step == system->numsteps)) { /* copy observables and avgs to the mpi send buffer */ /* histogram array is at the end of the message */ if (system->calc_hist) { zero_grid(system->grids->histogram->grid, system); population_histogram(system); } // update frozen and total system mass calc_system_mass(system); // update sorbate info on each node if (system->sorbateCount > 1) update_sorbate_info(system); /*write trajectory files for each node -> one at a time to avoid disk congestion*/ #ifdef MPI for (j = 0; j < size; j++) { MPI_Barrier(MPI_COMM_WORLD); if (j == rank) write_states(system); } #else write_states(system); #endif /*restart files for each node -> one at a time to avoid disk congestion*/ if (write_molecules_wrapper(system, system->pqr_restart) < 0) { error( "MC: could not write restart state to disk\n"); return (-1); } /*dipole/field data for each node -> one at a time to avoid disk congestion*/ #ifdef MPI if (system->polarization) { for (j = 0; j < size; j++) { MPI_Barrier(MPI_COMM_WORLD); if (j == rank) { write_dipole(system); write_field(system); } } } #else if (system->polarization) { write_dipole(system); write_field(system); } #endif /* zero the send buffer */ memset(snd_strct, 0, msgsize); memcpy(snd_strct, system->observables, sizeof(observables_t)); memcpy(snd_strct + sizeof(observables_t), system->avg_nodestats, sizeof(avg_nodestats_t)); if (system->calc_hist) mpi_copy_histogram_to_sendbuffer(snd_strct + sizeof(observables_t) + sizeof(avg_nodestats_t), system->grids->histogram->grid, system); if (system->sorbateCount > 1) memcpy(snd_strct + sizeof(observables_t) + sizeof(avg_nodestats_t) + (system->calc_hist) * system->n_histogram_bins * sizeof(int), //compensate for the size of hist data, if neccessary system->sorbateInfo, system->sorbateCount * sizeof(sorbateInfo_t)); if (!rank) memset(rcv_strct, 0, size * msgsize); #ifdef MPI MPI_Gather(snd_strct, 1, msgtype, rcv_strct, 1, msgtype, 0, MPI_COMM_WORLD); MPI_Gather(&(system->temperature), 1, MPI_DOUBLE, temperature_mpi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); //need to gather shit for sorbate stats also #else memcpy(rcv_strct, snd_strct, msgsize); temperature_mpi[0] = system->temperature; #endif /* MPI */ /* head node collects all observables and averages */ if (!rank) { /* clear avg_nodestats to avoid double-counting */ clear_avg_nodestats(system); //loop for each core -> shift data into variable_mpi, then average into avg_observables for (j = 0; j < size; j++) { /* copy from the mpi buffer */ memcpy(observables_mpi, rcv_strct + j * msgsize, sizeof(observables_t)); memcpy(avg_nodestats_mpi, rcv_strct + j * msgsize + sizeof(observables_t), sizeof(avg_nodestats_t)); if (system->calc_hist) mpi_copy_rcv_histogram_to_data(rcv_strct + j * msgsize + sizeof(observables_t) + sizeof(avg_nodestats_t), system->grids->histogram->grid, system); if (system->sorbateCount > 1) memcpy(sinfo_mpi, rcv_strct + j * msgsize + sizeof(observables_t) + sizeof(avg_nodestats_t) + (system->calc_hist) * system->n_histogram_bins * sizeof(int), //compensate for the size of hist data, if neccessary system->sorbateCount * sizeof(sorbateInfo_t)); /* write observables */ if (system->file_pointers.fp_energy) write_observables(system->file_pointers.fp_energy, system, observables_mpi, temperature_mpi[j]); if (system->file_pointers.fp_energy_csv) write_observables_csv(system->file_pointers.fp_energy_csv, system, observables_mpi, temperature_mpi[j]); if (system->file_pointers.fp_xyz) { write_molecules_xyz(system, system->file_pointers.fp_xyz); //L } /* collect the averages */ /* if parallel tempering, we will collect obserables from the coldest bath. this can't be done for * nodestats though, since nodestats are averaged over each corrtime, rather than based on a single * taken at the corrtime */ update_root_nodestats(system, avg_nodestats_mpi, system->avg_observables); if (!system->parallel_tempering) { update_root_averages(system, observables_mpi, system->avg_observables); if (system->calc_hist) update_root_histogram(system); if (system->sorbateCount > 1) update_root_sorb_averages(system, sinfo_mpi); } else if (system->ptemp->index[j] == 0) { update_root_averages(system, observables_mpi, system->avg_observables); if (system->calc_hist) update_root_histogram(system); if (system->sorbateCount > 1) update_root_sorb_averages(system, sinfo_mpi); } } /* write the averages to stdout */ if (system->file_pointers.fp_histogram) write_histogram(system->file_pointers.fp_histogram, system->grids->avg_histogram->grid, system); if (write_performance(system->step, system) < 0) { error( "MC: could not write performance data to stdout\n"); return (-1); } if (write_averages(system) < 0) { error( "MC: could not write statistics to stdout\n"); return (-1); } } /* !rank */ } /* corrtime */ } /* main loop */ /* write output, close any open files */ free(snd_strct); // restart files for each node if (write_molecules_wrapper(system, system->pqr_output) < 0) { error( "MC: could not write final state to disk\n"); return (-1); } if (!rank) { close_files(system); free(rcv_strct); free(temperature_mpi); } if (system->sorbateCount > 1) { free(system->sorbateGlobal); free(sinfo_mpi); } free(observables_mpi); free(avg_nodestats_mpi); printf( "MC: Total auto-rejected moves: %i\n", system->count_autorejects); return (0); }
/* changing it so it rotates around the three principal axises - Adam Hogan */ void molecule_rotate_quaternion(molecule_t *molecule, double alpha, double beta, double gamma, int reverse_flag) { atom_t *atom_ptr; double com[3]; int i, ii, n; double *new_coord_array; /* count the number of atoms in a molecule, and allocate new coords array */ for(atom_ptr = molecule->atoms, n = 0; atom_ptr; atom_ptr = atom_ptr->next) ++n; new_coord_array = calloc(n*3, sizeof(double)); memnullcheck(new_coord_array,n*3*sizeof(double),__LINE__-1, __FILE__); /* save the com coordinate */ com[0] = molecule->com[0]; com[1] = molecule->com[1]; com[2] = molecule->com[2]; /* translate the molecule to the origin */ for(atom_ptr = molecule->atoms; atom_ptr; atom_ptr = atom_ptr->next) { atom_ptr->pos[0] -= com[0]; atom_ptr->pos[1] -= com[1]; atom_ptr->pos[2] -= com[2]; } /* construct the rotation quaternions */ struct quaternion first, second, third, total, total_conjugate, position, answer; //total = quaternion with no rotation quaternion_construct_xyzw(&total,0.,0.,0.,1.); //first = rotation around z axis quaternion_construct_axis_angle_degree(&first,0.,0.,1.,alpha); //second = rotation around y axis quaternion_construct_axis_angle_degree(&second,0.,1.,0.,beta); //third = rotation around z axis quaternion_construct_axis_angle_degree(&third,1.,0.,0.,gamma); //combine all rotations into total quaternion_multiplication(&first,&total,&total); quaternion_multiplication(&second,&total,&total); quaternion_multiplication(&third,&total,&total); //if we are undoing a rotation we need to conjugate total if (reverse_flag) quaternion_conjugate(&total,&total); quaternion_conjugate(&total,&total_conjugate); for(atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i*3; //position = position vector quaternion_construct_xyzw(&position,atom_ptr->pos[0],atom_ptr->pos[1],atom_ptr->pos[2],0.); //answer = total*(position*total_conjugate) quaternion_multiplication(&position,&total_conjugate,&answer); quaternion_multiplication(&total,&answer,&answer); //set the new coords new_coord_array[ii+0] = answer.x; new_coord_array[ii+1] = answer.y; new_coord_array[ii+2] = answer.z; } /* set the new coordinates and then translate back from the origin */ for(atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i*3; atom_ptr->pos[0] = new_coord_array[ii+0]; atom_ptr->pos[1] = new_coord_array[ii+1]; atom_ptr->pos[2] = new_coord_array[ii+2]; atom_ptr->pos[0] += com[0]; atom_ptr->pos[1] += com[1]; atom_ptr->pos[2] += com[2]; } /* free our temporary array */ free(new_coord_array); }
/* now with quaternions AH */ void rotate(system_t *system, molecule_t *molecule, pbc_t *pbc, double scale) { atom_t *atom_ptr; double u1, u2, u3; double com[3]; int i, ii, n; double *new_coord_array; struct quaternion position_vector, rnd_rotation, rnd_rotation_conjugate, answer; // create a random rotation // http://planning.cs.uiuc.edu/node198.html u1 = get_rand(system); u2 = get_rand(system); u3 = get_rand(system); // simple linear interpolation for adjusting the scale quaternion_construct_xyzw(&rnd_rotation, scale*sqrt(1-u1)*sin(2*M_PI*u2), scale*sqrt(1-u1)*cos(2*M_PI*u2), scale*sqrt(u1)*sin(2*M_PI*u3), 1-scale+scale*sqrt(u1)*cos(2*M_PI*u3)); /* make a random quaternion */ quaternion_normalize(&rnd_rotation); quaternion_conjugate(&rnd_rotation, &rnd_rotation_conjugate); /* needed to transform coordinates */ /* count the number of atoms in a molecule, and allocate new coords array */ for (atom_ptr = molecule->atoms, n = 0; atom_ptr; atom_ptr = atom_ptr->next) ++n; new_coord_array = calloc(n * 3, sizeof(double)); memnullcheck(new_coord_array, n * 3 * sizeof(double), __LINE__ - 1, __FILE__); /* save the com coordinate */ com[0] = molecule->com[0]; com[1] = molecule->com[1]; com[2] = molecule->com[2]; /* translate the molecule to the origin */ for (atom_ptr = molecule->atoms; atom_ptr; atom_ptr = atom_ptr->next) { atom_ptr->pos[0] -= com[0]; atom_ptr->pos[1] -= com[1]; atom_ptr->pos[2] -= com[2]; } /* quaternion multiply */ for (atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i * 3; //position_vector = position quaternion_construct_xyzw(&position_vector, atom_ptr->pos[0], atom_ptr->pos[1], atom_ptr->pos[2], 0.); //answer = rnd_rotation*(position*rnd_rotation_conjugate) quaternion_multiplication(&position_vector, &rnd_rotation_conjugate, &answer); quaternion_multiplication(&rnd_rotation, &answer, &answer); //set the new coords new_coord_array[ii + 0] = answer.x; new_coord_array[ii + 1] = answer.y; new_coord_array[ii + 2] = answer.z; } /* set the new coordinates and then translate back from the origin */ for (atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i * 3; atom_ptr->pos[0] = new_coord_array[ii + 0]; atom_ptr->pos[1] = new_coord_array[ii + 1]; atom_ptr->pos[2] = new_coord_array[ii + 2]; atom_ptr->pos[0] += com[0]; atom_ptr->pos[1] += com[1]; atom_ptr->pos[2] += com[2]; } /* free our temporary array */ free(new_coord_array); }
/* rotate a molecule about three Euler angles - same as normal function but for a single mol and without random angles */ void molecule_rotate_euler(molecule_t *molecule, double alpha, double beta, double gamma, int reverse_flag) { atom_t *atom_ptr; double rotation_matrix[3][3]; double com[3]; int i, ii, n; double *new_coord_array; //reverse the rotation? if (reverse_flag) { //switch around alpha and gamma double temp; temp = alpha; alpha = gamma; gamma = temp; alpha *= -1.; beta *= -1.; gamma *= -1.; } /* count the number of atoms in a molecule, and allocate new coords array */ for(atom_ptr = molecule->atoms, n = 0; atom_ptr; atom_ptr = atom_ptr->next) ++n; new_coord_array = calloc(n*3, sizeof(double)); memnullcheck(new_coord_array,n*3*sizeof(double),__LINE__-1, __FILE__); /* save the com coordinate */ com[0] = molecule->com[0]; com[1] = molecule->com[1]; com[2] = molecule->com[2]; /* translate the molecule to the origin */ for(atom_ptr = molecule->atoms; atom_ptr; atom_ptr = atom_ptr->next) { atom_ptr->pos[0] -= com[0]; atom_ptr->pos[1] -= com[1]; atom_ptr->pos[2] -= com[2]; } /* construct the 3D rotation matrix */ rotation_matrix[0][0] = cos(gamma)*cos(beta)*cos(alpha) - sin(gamma)*sin(alpha); rotation_matrix[0][1] = sin(gamma)*cos(beta)*cos(alpha) + cos(gamma)*sin(alpha); rotation_matrix[0][2] = -sin(beta)*cos(alpha); rotation_matrix[1][0] = -cos(gamma)*cos(beta)*sin(alpha) - sin(gamma)*cos(alpha); rotation_matrix[1][1] = -sin(gamma)*cos(beta)*sin(alpha) + cos(gamma)*cos(alpha); rotation_matrix[1][2] = sin(beta)*sin(alpha); rotation_matrix[2][0] = cos(gamma)*sin(beta); rotation_matrix[2][1] = sin(gamma)*sin(beta); rotation_matrix[2][2] = cos(beta); /* matrix multiply */ for(atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i*3; new_coord_array[ii+0] = rotation_matrix[0][0]*atom_ptr->pos[0] + rotation_matrix[0][1]*atom_ptr->pos[1] + rotation_matrix[0][2]*atom_ptr->pos[2]; new_coord_array[ii+1] = rotation_matrix[1][0]*atom_ptr->pos[0] + rotation_matrix[1][1]*atom_ptr->pos[1] + rotation_matrix[1][2]*atom_ptr->pos[2]; new_coord_array[ii+2] = rotation_matrix[2][0]*atom_ptr->pos[0] + rotation_matrix[2][1]*atom_ptr->pos[1] + rotation_matrix[2][2]*atom_ptr->pos[2]; } /* set the new coordinates and then translate back from the origin */ for(atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i*3; atom_ptr->pos[0] = new_coord_array[ii+0]; atom_ptr->pos[1] = new_coord_array[ii+1]; atom_ptr->pos[2] = new_coord_array[ii+2]; atom_ptr->pos[0] += com[0]; atom_ptr->pos[1] += com[1]; atom_ptr->pos[2] += com[2]; } /* free our temporary array */ free(new_coord_array); }
/* parallel tempering is treated differently than the other types of MC moves, because it is done * IN ADDITION to any other moves: i.e. some random move is performed and the energy is calculated * before and after. once that is all figured out, we then perform a temper step. The boltzmann factor * that is calculated will NOT be averaged into the BF quantity. It can be, but care must be taken so * there is no double-counting, and it really isn't so important to do so. */ void temper_system(system_t *system, double current_energy) { #ifdef MPI // system->ptemp->index[j] is a mapping from core -> bath_index (bath_index 0 is lowest temperature, etc.) // bath2core maps from bath_index -> core // only half of the cores will be responsible for carrying out the calculations // partner_list maps from core -> swap partner, if core is a master. core -> -1, if core is a slave. int *bath2core, *partner_list, *is_master, master, slave, *update_index, new_index_val; double slave_energy, boltzmann_factor, *update_templist, new_templist_val; int i, j, lucky, accept_move; MPI_Status status; slave_energy = 0; //make the bath index bath2core = calloc(size, sizeof(int)); memnullcheck(bath2core, size * sizeof(int), __LINE__ - 1, __FILE__); for (i = 0; i < size; i++) for (j = 0; j < size; j++) if (system->ptemp->index[j] == i) bath2core[i] = j; //choose the lucky bath. it's not really lucky.. this is just the first bath that we consider for swapping if (!rank) lucky = floor(get_rand(system) * size); MPI_Bcast(&lucky, 1, MPI_INT, 0, MPI_COMM_WORLD); //we will use this array to designate whether a particular core is a master or slave is_master = calloc(size, sizeof(int)); memnullcheck(is_master, size * sizeof(int), __LINE__ - 1, __FILE__); //build the partner list partner_list = calloc(size, sizeof(int)); memnullcheck(partner_list, size * sizeof(int), __LINE__ - 1, __FILE__); master = lucky; slave = (lucky + 1) % size; //this assigns the slave bath index to the variable do { partner_list[bath2core[slave]] = bath2core[master]; //partner_list maps slave to master core partner_list[bath2core[master]] = bath2core[slave]; //partner_list maps master to slave is_master[bath2core[master]] = 1; //master flag is on is_master[bath2core[slave]] = 0; //master flag is off //now generate the next master master = (master + 2) % size; slave = (slave + 2) % size; } while ((master != lucky) && (slave != lucky)); if (slave == lucky) { partner_list[bath2core[master]] = -1; //if odd # of cores, we have one member unassigned is_master[bath2core[master]] = -1; //neither master nor slave } //all cores (except 1 if size is odd) are mapped //communicate the energy to the master nodes if (!is_master[rank]) { MPI_Send(¤t_energy, 1, MPI_DOUBLE, partner_list[rank], 0, MPI_COMM_WORLD); //slave sends it's energy MPI_Recv(&accept_move, 1, MPI_INT, partner_list[rank], 1, MPI_COMM_WORLD, &status); //receive result (accept/reject) } else if (is_master[rank] == 1) { //master receives energy from slave MPI_Recv(&slave_energy, 1, MPI_DOUBLE, partner_list[rank], 0, MPI_COMM_WORLD, &status); //calculate boltzmann factor exp(dE*dB) boltzmann_factor = exp((current_energy - slave_energy) * (1.0 / system->ptemp->templist[rank] - 1.0 / system->ptemp->templist[partner_list[rank]])); if (get_rand(system) < boltzmann_factor) accept_move = 1; else accept_move = 0; //communicate the move result to slave MPI_Send(&accept_move, 1, MPI_INT, partner_list[rank], 1, MPI_COMM_WORLD); } else accept_move = 0; //no partner if (accept_move) { //reassign local temperature system->temperature = system->ptemp->templist[partner_list[rank]]; //update our temperature and index values to prepare for transmission to root new_templist_val = system->ptemp->templist[partner_list[rank]]; new_index_val = system->ptemp->index[partner_list[rank]]; //reassign fugacities if (!system->user_fugacities && system->fugacities) { MPI_Send(system->fugacities, 1, MPI_DOUBLE, partner_list[rank], 2, MPI_COMM_WORLD); //send fugacity MPI_Recv(system->fugacities, 1, MPI_DOUBLE, partner_list[rank], 2, MPI_COMM_WORLD, &status); //receive fugacity } } else { //reject new_templist_val = system->ptemp->templist[rank]; new_index_val = system->ptemp->index[rank]; } //now we need to update the templist and index on each core update_templist = calloc(size, sizeof(double)); update_index = calloc(size, sizeof(int)); memnullcheck(update_templist, size * sizeof(double), __LINE__ - 1, __FILE__); memnullcheck(update_index, size * sizeof(int), __LINE__ - 1, __FILE__); // create updated arrays on head node MPI_Gather(&new_templist_val, 1, MPI_DOUBLE, update_templist, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Gather(&new_index_val, 1, MPI_INT, update_index, 1, MPI_INT, 0, MPI_COMM_WORLD); // build the updated array if (!rank) { for (i = 0; i < size; i++) { system->ptemp->templist[i] = update_templist[i]; system->ptemp->index[i] = update_index[i]; } } // transmit to each core MPI_Bcast(system->ptemp->templist, size, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(system->ptemp->index, size, MPI_INT, 0, MPI_COMM_WORLD); if (accept_move) system->nodestats->accept_ptemp++; else if (is_master[rank] != -1) system->nodestats->reject_ptemp++; free(update_templist); free(update_index); free(bath2core); free(is_master); free(partner_list); #endif //MPI return; }