void GlobalMasterFreeEnergy::calculate() { DebugM(4,"Calculating forces on master\n"); /* zero out the forces */ modifyForcedAtoms().resize(0); modifyAppliedForces().resize(0); /* XXX is this line needed at all? */ modifyGroupForces().resize(getGroupMassEnd() - getGroupMassBegin()); modifyGroupForces().setall(Vector(0,0,0)); // iout << iDEBUG << "Free energy perturbation - calculate()\n" << endi; user_calculate(); // Send results to clients DebugM(3,"Sending results (" << forcedAtoms().size() << " forces) on master\n"); if ( changedAtoms() || changedGroups() ) { DebugM(4,"Sending new configuration (" << requestedAtoms().size() << " atoms) on master\n"); } }
void colvarproxy_namd::calculate() { if (first_timestep) { this->setup(); colvars->setup(); colvars->setup_input(); colvars->setup_output(); first_timestep = false; } else { // Use the time step number inherited from GlobalMaster if ( step - previous_NAMD_step == 1 ) { colvars->it++; } // Other cases could mean: // - run 0 // - beginning of a new run statement // then the internal counter should not be incremented } previous_NAMD_step = step; { Vector const a = lattice->a(); Vector const b = lattice->b(); Vector const c = lattice->c(); unit_cell_x.set(a.x, a.y, a.z); unit_cell_y.set(b.x, b.y, c.z); unit_cell_z.set(c.x, c.y, c.z); } if (!lattice->a_p() && !lattice->b_p() && !lattice->c_p()) { boundaries_type = boundaries_non_periodic; reset_pbc_lattice(); } else if (lattice->a_p() && lattice->b_p() && lattice->c_p()) { if (lattice->orthogonal()) { boundaries_type = boundaries_pbc_ortho; } else { boundaries_type = boundaries_pbc_triclinic; } colvarproxy_system::update_pbc_lattice(); } else { boundaries_type = boundaries_unsupported; } if (cvm::debug()) { log(std::string(cvm::line_marker)+ "colvarproxy_namd, step no. "+cvm::to_str(colvars->it)+"\n"+ "Updating atomic data arrays.\n"); } // must delete the forces applied at the previous step: we can do // that because they have already been used and copied to other // memory locations modifyForcedAtoms().clear(); modifyAppliedForces().clear(); // prepare local arrays for (size_t i = 0; i < atoms_ids.size(); i++) { atoms_positions[i] = cvm::rvector(0.0, 0.0, 0.0); atoms_total_forces[i] = cvm::rvector(0.0, 0.0, 0.0); atoms_new_colvar_forces[i] = cvm::rvector(0.0, 0.0, 0.0); } for (size_t i = 0; i < atom_groups_ids.size(); i++) { atom_groups_total_forces[i] = cvm::rvector(0.0, 0.0, 0.0); atom_groups_new_colvar_forces[i] = cvm::rvector(0.0, 0.0, 0.0); } // create the atom map if needed size_t const n_all_atoms = Node::Object()->molecule->numAtoms; if (atoms_map.size() != n_all_atoms) { atoms_map.resize(n_all_atoms); atoms_map.assign(n_all_atoms, -1); update_atoms_map(getAtomIdBegin(), getAtomIdEnd()); } // if new atomic positions or forces have been communicated by other GlobalMasters, add them to the atom map if ((int(atoms_ids.size()) < (getAtomIdEnd() - getAtomIdBegin())) || (int(atoms_ids.size()) < (getForceIdEnd() - getForceIdBegin()))) { update_atoms_map(getAtomIdBegin(), getAtomIdEnd()); update_atoms_map(getForceIdBegin(), getForceIdEnd()); } { if (cvm::debug()) { log("Updating positions arrays.\n"); } size_t n_positions = 0; AtomIDList::const_iterator a_i = getAtomIdBegin(); AtomIDList::const_iterator a_e = getAtomIdEnd(); PositionList::const_iterator p_i = getAtomPositionBegin(); for ( ; a_i != a_e; ++a_i, ++p_i ) { atoms_positions[atoms_map[*a_i]] = cvm::rvector((*p_i).x, (*p_i).y, (*p_i).z); n_positions++; } // The following had to be relaxed because some atoms may be forced without their position being requested // if (n_positions < atoms_ids.size()) { // cvm::error("Error: did not receive the positions of all atoms.\n", BUG_ERROR); // } } if (total_force_requested && cvm::step_relative() > 0) { // sort the force arrays the previous step // (but only do so if there *is* a previous step!) { if (cvm::debug()) { log("Updating total forces arrays.\n"); } size_t n_total_forces = 0; AtomIDList::const_iterator a_i = getForceIdBegin(); AtomIDList::const_iterator a_e = getForceIdEnd(); ForceList::const_iterator f_i = getTotalForce(); for ( ; a_i != a_e; ++a_i, ++f_i ) { atoms_total_forces[atoms_map[*a_i]] = cvm::rvector((*f_i).x, (*f_i).y, (*f_i).z); n_total_forces++; } if (n_total_forces < atoms_ids.size()) { cvm::error("Error: total forces were requested, but total forces " "were not received for all atoms.\n" "The most probable cause is combination of energy " "minimization with a biasing method that requires MD (e.g. ABF).\n" "Always run minimization and ABF separately.", INPUT_ERROR); } } { if (cvm::debug()) { log("Updating group total forces arrays.\n"); } ForceList::const_iterator f_i = getGroupTotalForceBegin(); ForceList::const_iterator f_e = getGroupTotalForceEnd(); size_t i = 0; if ((f_e - f_i) != ((int) atom_groups_ids.size())) { cvm::error("Error: total forces were requested for scalable groups, " "but they are not in the same number from the number of groups.\n" "The most probable cause is combination of energy " "minimization with a biasing method that requires MD (e.g. ABF).\n" "Always run minimization and ABF separately.", INPUT_ERROR); } for ( ; f_i != f_e; f_i++, i++) { atom_groups_total_forces[i] = cvm::rvector((*f_i).x, (*f_i).y, (*f_i).z); } } } { if (cvm::debug()) { log("Updating group positions arrays.\n"); } // update group data (only coms available so far) size_t ig; // note: getGroupMassBegin() could be used here, but masses and charges // have already been calculated from the last call to setup() PositionList::const_iterator gp_i = getGroupPositionBegin(); for (ig = 0; gp_i != getGroupPositionEnd(); gp_i++, ig++) { atom_groups_coms[ig] = cvm::rvector(gp_i->x, gp_i->y, gp_i->z); } } if (cvm::debug()) { log("atoms_ids = "+cvm::to_str(atoms_ids)+"\n"); log("atoms_ncopies = "+cvm::to_str(atoms_ncopies)+"\n"); log("atoms_masses = "+cvm::to_str(atoms_masses)+"\n"); log("atoms_charges = "+cvm::to_str(atoms_charges)+"\n"); log("atoms_positions = "+cvm::to_str(atoms_positions)+"\n"); log("atoms_total_forces = "+cvm::to_str(atoms_total_forces)+"\n"); log(cvm::line_marker); log("atom_groups_ids = "+cvm::to_str(atom_groups_ids)+"\n"); log("atom_groups_ncopies = "+cvm::to_str(atom_groups_ncopies)+"\n"); log("atom_groups_masses = "+cvm::to_str(atom_groups_masses)+"\n"); log("atom_groups_charges = "+cvm::to_str(atom_groups_charges)+"\n"); log("atom_groups_coms = "+cvm::to_str(atom_groups_coms)+"\n"); log("atom_groups_total_forces = "+cvm::to_str(atom_groups_total_forces)+"\n"); log(cvm::line_marker); } // call the collective variable module if (colvars->calc() != COLVARS_OK) { cvm::error("Error in the collective variables module.\n", COLVARS_ERROR); } if (cvm::debug()) { log(cvm::line_marker); log("atoms_new_colvar_forces = "+cvm::to_str(atoms_new_colvar_forces)+"\n"); log(cvm::line_marker); log("atom_groups_new_colvar_forces = "+cvm::to_str(atom_groups_new_colvar_forces)+"\n"); log(cvm::line_marker); } // communicate all forces to the MD integrator for (size_t i = 0; i < atoms_ids.size(); i++) { cvm::rvector const &f = atoms_new_colvar_forces[i]; modifyForcedAtoms().add(atoms_ids[i]); modifyAppliedForces().add(Vector(f.x, f.y, f.z)); } { // zero out the applied forces on each group modifyGroupForces().resize(modifyRequestedGroups().size()); ForceList::iterator gf_i = modifyGroupForces().begin(); for (int ig = 0; gf_i != modifyGroupForces().end(); gf_i++, ig++) { cvm::rvector const &f = atom_groups_new_colvar_forces[ig]; *gf_i = Vector(f.x, f.y, f.z); } } // send MISC energy reduction->submit(); // NAMD does not destruct GlobalMaster objects, so we must remember // to write all output files at the end of a run if (step == simparams->N) { colvars->write_restart_file(cvm::output_prefix()+".colvars.state"); colvars->write_output_files(); } }
int colvarproxy_namd::init_atom_group(std::vector<int> const &atoms_ids) { if (cvm::debug()) log("Reguesting from NAMD a group of size "+cvm::to_str(atoms_ids.size())+ " for collective variables calculation.\n"); // Note: modifyRequestedGroups is supposed to be in sync with the colvarproxy arrays, // and to stay that way during a simulation // compare this new group to those already allocated inside GlobalMaster int ig; for (ig = 0; ig < modifyRequestedGroups().size(); ig++) { AtomIDList const &namd_group = modifyRequestedGroups()[ig]; bool b_match = true; if (namd_group.size() != ((int) atoms_ids.size())) { b_match = false; } else { int ia; for (ia = 0; ia < namd_group.size(); ia++) { int const aid = atoms_ids[ia]; if (namd_group[ia] != aid) { b_match = false; break; } } } if (b_match) { if (cvm::debug()) log("Group was already added.\n"); // this group already exists atom_groups_ncopies[ig] += 1; return ig; } } // add this group (note: the argument of add_atom_group_slot() is redundant for NAMD, and provided only for consistency) size_t const index = add_atom_group_slot(atom_groups_ids.size()); modifyRequestedGroups().resize(atom_groups_ids.size()); // the following is done in calculate() // modifyGroupForces().resize(atom_groups_ids.size()); AtomIDList &namd_group = modifyRequestedGroups()[index]; namd_group.resize(atoms_ids.size()); int const n_all_atoms = Node::Object()->molecule->numAtoms; for (size_t ia = 0; ia < atoms_ids.size(); ia++) { int const aid = atoms_ids[ia]; if (cvm::debug()) log("Adding atom "+cvm::to_str(aid+1)+ " for collective variables calculation.\n"); if ( (aid < 0) || (aid >= n_all_atoms) ) { cvm::error("Error: invalid atom number specified, "+ cvm::to_str(aid+1)+"\n", INPUT_ERROR); return -1; } namd_group[ia] = aid; } update_group_properties(index); if (cvm::debug()) { log("Group has index "+cvm::to_str(index)+"\n"); log("modifyRequestedGroups length = "+cvm::to_str(modifyRequestedGroups().size())+ ", modifyGroupForces length = "+cvm::to_str(modifyGroupForces().size())+"\n"); } return index; }