/* 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); }
/* * Sequential version. */ int seqsa_solver(char *stg_filename, char *ssf_filename) { int malloced; int freed; int malloced_initial; int freed_initial; int malloced_select; int freed_select; struct stg *tg; struct ssf_status *status; struct ssf *schedule; double eps; unsigned seed; int i; double t0; double t; struct iss *alpha; /* present solution */ struct iss *beta; /* neighbour solution of alpha */ double cost_alpha; double cost_beta; double r; double bf; /* Boltzmann Factor p(alpha -> beta) */ printf("** Sequential Simulated Annealing Solver\n"); /* Allocate data structures. */ malloced = 0; freed = 0; tg = new_task_graph_from_file(stg_filename, &malloced); status = new_status(&malloced); strncpy(status->name, "YASA Sequential", 20); eps = 1e-3; seed = 0; t0 = 1000.0; alpha = NULL; beta = NULL; /* Solve. */ srand(seed); print_task_graph(tg); malloced_initial = 0; freed_initial = 0; alpha = create_initial_solution(tg, &malloced_initial, &freed_initial); printf("malloced %d bytes for initial solution\n", malloced_initial); printf("freed %d bytes for initial solution\n", freed_initial); printf("difference: %d bytes\n", malloced_initial - freed_initial); cost_alpha = cost(tg, alpha); i = 0; t = t0; while (t > eps) { printf("i = %d, t = %f\n", i, t); malloced_select = 0; freed_select = 0; beta = select_neighbour(tg, alpha, &malloced_select, &freed_select); printf("malloced %d bytes for selection\n", malloced_select); printf("freed %d bytes for selection\n", freed_select); printf("difference: %d bytes\n", malloced_select - freed_select); cost_beta = cost(tg, beta); if (cost_beta <= cost_alpha) { /* TODO alpha := beta */ cost_alpha = cost_beta; } else { r = get_random_r(); /* r from (0, 1) */ bf = boltzmann_factor(t, cost_alpha, cost_beta); printf("r = %f, bf = %f\n", r, bf); if (r < bf) { /* TODO alpha := beta */ cost_alpha = cost_beta; } } i++; t = new_temp(t, i); } printf("stopping at i = %d, t = %f.\n", i, t); /* alpha to schedule */ //schedule = new_schedule(tg, alpha, &malloced); schedule = new_schedule(tg, &malloced); printf("malloced %d bytes\n", malloced); /* Display Results */ print_schedule(schedule); write_schedule_to_file(ssf_filename, schedule, status); /* Free data structures. */ free_schedule(schedule, &freed); // TODO free initial solution free_status(status, &freed); free_task_graph(tg, &freed); printf("freed %d bytes => ", freed); if (malloced == freed) printf("OK.\n"); else { printf("Error: malloced != freed!\n"); return (1); } return (0); }