int colvarbias_abf::update() { if (cvm::debug()) cvm::log("Updating ABF bias " + this->name); size_t i; for (i = 0; i < num_variables(); i++) { bin[i] = samples->current_bin_scalar(i); } if (cvm::proxy->total_forces_same_step()) { // e.g. in LAMMPS, total forces are current force_bin = bin; } if (cvm::step_relative() > 0 || cvm::proxy->total_forces_same_step()) { if (update_bias) { // if (b_adiabatic_reweighting) { // // Update gradients non-locally based on conditional distribution of // // fictitious variable TODO // // } else if (samples->index_ok(force_bin)) { // Only if requested and within bounds of the grid... for (i = 0; i < num_variables(); i++) { // get total forces (lagging by 1 timestep) from colvars // and subtract previous ABF force if necessary update_system_force(i); } gradients->acc_force(force_bin, system_force); if ( b_integrate ) { pmf->update_div_neighbors(force_bin); } } } if ( z_gradients && update_bias ) { for (i = 0; i < num_variables(); i++) { z_bin[i] = z_samples->current_bin_scalar(i); } if ( z_samples->index_ok(z_bin) ) { for (i = 0; i < num_variables(); i++) { // If we are outside the range of xi, the force has not been obtained above // the function is just an accessor, so cheap to call again anyway update_system_force(i); } z_gradients->acc_force(z_bin, system_force); } } if ( b_integrate ) { if ( pabf_freq && cvm::step_relative() % pabf_freq == 0 ) { cvm::real err; int iter = pmf->integrate(integrate_steps, integrate_tol, err); if ( iter == integrate_steps ) { cvm::log("Warning: PMF integration did not converge to " + cvm::to_str(integrate_tol) + " in " + cvm::to_str(integrate_steps) + " steps. Residual error: " + cvm::to_str(err)); } pmf->set_zero_minimum(); // TODO: do this only when necessary } } } if (!cvm::proxy->total_forces_same_step()) { // e.g. in NAMD, total forces will be available for next timestep // hence we store the current colvar bin force_bin = bin; } // Reset biasing forces from previous timestep for (i = 0; i < num_variables(); i++) { colvar_forces[i].reset(); } // Compute and apply the new bias, if applicable if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) { cvm::real count = samples->value(bin); cvm::real fact = 1.0; // Factor that ensures smooth introduction of the force if ( count < full_samples ) { fact = (count < min_samples) ? 0.0 : (cvm::real(count - min_samples)) / (cvm::real(full_samples - min_samples)); } std::vector<cvm::real> grad(num_variables()); if ( pabf_freq ) { // In projected ABF, the force is the PMF gradient estimate pmf->vector_gradient_finite_diff(bin, grad); } else { // Normal ABF gradients->vector_value(bin, grad); } // if ( b_adiabatic_reweighting) { // // Average of force according to conditional distribution of fictitious variable // // need freshly integrated PMF, gradient TODO // } else if ( fact != 0.0 ) { if ( (num_variables() == 1) && colvars[0]->periodic_boundaries() ) { // Enforce a zero-mean bias on periodic, 1D coordinates // in other words: boundary condition is that the biasing potential is periodic // This is enforced naturally if using integrated PMF colvar_forces[0].real_value = fact * (grad[0] - gradients->average ()); } else { for (size_t i = 0; i < num_variables(); i++) { // subtracting the mean force (opposite of the FE gradient) means adding the gradient colvar_forces[i].real_value = fact * grad[i]; } } if (cap_force) { for (size_t i = 0; i < num_variables(); i++) { if ( colvar_forces[i].real_value * colvar_forces[i].real_value > max_force[i] * max_force[i] ) { colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]); } } } } } // update the output prefix; TODO: move later to setup_output() function if (cvm::main()->num_biases_feature(colvardeps::f_cvb_calc_pmf) == 1) { // This is the only bias computing PMFs output_prefix = cvm::output_prefix(); } else { output_prefix = cvm::output_prefix() + "." + this->name; } if (output_freq && (cvm::step_absolute() % output_freq) == 0) { if (cvm::debug()) cvm::log("ABF bias trying to write gradients and samples to disk"); write_gradients_samples(output_prefix); } if (b_history_files && (cvm::step_absolute() % history_freq) == 0) { // file already exists iff cvm::step_relative() > 0 // otherwise, backup and replace write_gradients_samples(output_prefix + ".hist", (cvm::step_relative() > 0)); } if (shared_on && shared_last_step >= 0 && cvm::step_absolute() % shared_freq == 0) { // Share gradients and samples for shared ABF. replica_share(); } // Prepare for the first sharing. if (shared_last_step < 0) { // Copy the current gradient and count values into last. last_gradients->copy_grid(*gradients); last_samples->copy_grid(*samples); shared_last_step = cvm::step_absolute(); cvm::log("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+"."); } // update UI estimator every step if (b_UI_estimator) { std::vector<double> x(num_variables(),0); std::vector<double> y(num_variables(),0); for (size_t i = 0; i < num_variables(); i++) { x[i] = colvars[i]->actual_value(); y[i] = colvars[i]->value(); } eabf_UI.update_output_filename(output_prefix); eabf_UI.update(cvm::step_absolute(), x, y); } return COLVARS_OK; }
int colvarbias_abf::update() { if (cvm::debug()) cvm::log("Updating ABF bias " + this->name); if (cvm::step_relative() == 0) { // At first timestep, do only: // initialization stuff (file operations relying on n_abf_biases // compute current value of colvars for (size_t i = 0; i < colvars.size(); i++) { bin[i] = samples->current_bin_scalar(i); } } else { for (size_t i = 0; i < colvars.size(); i++) { bin[i] = samples->current_bin_scalar(i); } if ( update_bias && samples->index_ok(force_bin) ) { // Only if requested and within bounds of the grid... for (size_t i = 0; i < colvars.size(); i++) { // get total forces (lagging by 1 timestep) from colvars // and subtract previous ABF force if necessary update_system_force(i); } gradients->acc_force(force_bin, system_force); } if ( z_gradients && update_bias ) { for (size_t i = 0; i < colvars.size(); i++) { z_bin[i] = z_samples->current_bin_scalar(i); } if ( z_samples->index_ok(z_bin) ) { for (size_t i = 0; i < colvars.size(); i++) { // If we are outside the range of xi, the force has not been obtained above // the function is just an accessor, so cheap to call again anyway update_system_force(i); } z_gradients->acc_force(z_bin, system_force); } } } // save bin for next timestep force_bin = bin; // Reset biasing forces from previous timestep for (size_t i = 0; i < colvars.size(); i++) { colvar_forces[i].reset(); } // Compute and apply the new bias, if applicable if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) { size_t count = samples->value(bin); cvm::real fact = 1.0; // Factor that ensures smooth introduction of the force if ( count < full_samples ) { fact = (count < min_samples) ? 0.0 : (cvm::real(count - min_samples)) / (cvm::real(full_samples - min_samples)); } const cvm::real * grad = &(gradients->value(bin)); if ( fact != 0.0 ) { if ( (colvars.size() == 1) && colvars[0]->periodic_boundaries() ) { // Enforce a zero-mean bias on periodic, 1D coordinates // in other words: boundary condition is that the biasing potential is periodic colvar_forces[0].real_value = fact * (grad[0] / cvm::real(count) - gradients->average()); } else { for (size_t i = 0; i < colvars.size(); i++) { // subtracting the mean force (opposite of the FE gradient) means adding the gradient colvar_forces[i].real_value = fact * grad[i] / cvm::real(count); } } if (cap_force) { for (size_t i = 0; i < colvars.size(); i++) { if ( colvar_forces[i].real_value * colvar_forces[i].real_value > max_force[i] * max_force[i] ) { colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]); } } } } } // update the output prefix; TODO: move later to setup_output() function if (cvm::num_biases_feature(colvardeps::f_cvb_calc_pmf) == 1) { // This is the only bias computing PMFs output_prefix = cvm::output_prefix(); } else { output_prefix = cvm::output_prefix() + "." + this->name; } if (output_freq && (cvm::step_absolute() % output_freq) == 0) { if (cvm::debug()) cvm::log("ABF bias trying to write gradients and samples to disk"); write_gradients_samples(output_prefix); } if (b_history_files && (cvm::step_absolute() % history_freq) == 0) { // file already exists iff cvm::step_relative() > 0 // otherwise, backup and replace write_gradients_samples(output_prefix + ".hist", (cvm::step_relative() > 0)); } if (shared_on && shared_last_step >= 0 && cvm::step_absolute() % shared_freq == 0) { // Share gradients and samples for shared ABF. replica_share(); } // Prepare for the first sharing. if (shared_last_step < 0) { // Copy the current gradient and count values into last. last_gradients->copy_grid(*gradients); last_samples->copy_grid(*samples); shared_last_step = cvm::step_absolute(); cvm::log("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+"."); } return COLVARS_OK; }