From 21bac63ebfc319470e67f599704526e65c4a08cd Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 13 Nov 2025 11:25:50 -0500 Subject: [PATCH 1/4] build: Build colvarproxy_cudaglobalmaster with NAMD --- update-colvars-code.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/update-colvars-code.sh b/update-colvars-code.sh index f8c782644..40eba6c66 100755 --- a/update-colvars-code.sh +++ b/update-colvars-code.sh @@ -374,8 +374,9 @@ then # Update NAMD interface files for src in \ - ${source}/namd/src/*.h \ - ${source}/namd/src/*.C + ${source}/namd/src/*.{C,h} \ + ${source}/namd/cudaglobalmaster/*.{C,h,cu} \ + ; do \ tgt=$(basename ${src}) condcopy "${src}" "${target}/src/${tgt}" From 551ed0ac7b1fe57e084f7621cec7764a838ead18 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 13 Nov 2025 11:25:51 -0500 Subject: [PATCH 2/4] cleanup: Use enum class for PDB field in NAMD reader --- namd/src/colvarproxy_namd.C | 57 ++++++++++++++++--------------------- namd/src/colvarproxy_namd.h | 16 +++++------ 2 files changed, 32 insertions(+), 41 deletions(-) diff --git a/namd/src/colvarproxy_namd.C b/namd/src/colvarproxy_namd.C index cdda407ea..21fdc4d4e 100644 --- a/namd/src/colvarproxy_namd.C +++ b/namd/src/colvarproxy_namd.C @@ -904,36 +904,27 @@ cvm::rvector colvarproxy_namd::position_distance(cvm::atom_pos const &pos1, colvarproxy_namd::e_pdb_field colvarproxy_namd::pdb_field_str2enum(std::string const &pdb_field_str) { - colvarproxy_namd::e_pdb_field pdb_field = e_pdb_none; + auto pdb_field = e_pdb_field::none; - if (colvarparse::to_lower_cppstr(pdb_field_str) == - colvarparse::to_lower_cppstr("O")) { - pdb_field = e_pdb_occ; + if (colvarparse::to_lower_cppstr(pdb_field_str) == colvarparse::to_lower_cppstr("O")) { + pdb_field = e_pdb_field::occ; } - - if (colvarparse::to_lower_cppstr(pdb_field_str) == - colvarparse::to_lower_cppstr("B")) { - pdb_field = e_pdb_beta; + if (colvarparse::to_lower_cppstr(pdb_field_str) == colvarparse::to_lower_cppstr("B")) { + pdb_field = e_pdb_field::beta; } - - if (colvarparse::to_lower_cppstr(pdb_field_str) == - colvarparse::to_lower_cppstr("X")) { - pdb_field = e_pdb_x; + if (colvarparse::to_lower_cppstr(pdb_field_str) == colvarparse::to_lower_cppstr("X")) { + pdb_field = e_pdb_field::x; } - - if (colvarparse::to_lower_cppstr(pdb_field_str) == - colvarparse::to_lower_cppstr("Y")) { - pdb_field = e_pdb_y; + if (colvarparse::to_lower_cppstr(pdb_field_str) == colvarparse::to_lower_cppstr("Y")) { + pdb_field = e_pdb_field::y; } - - if (colvarparse::to_lower_cppstr(pdb_field_str) == - colvarparse::to_lower_cppstr("Z")) { - pdb_field = e_pdb_z; + if (colvarparse::to_lower_cppstr(pdb_field_str) == colvarparse::to_lower_cppstr("Z")) { + pdb_field = e_pdb_field::z; } - if (pdb_field == e_pdb_none) { - cvmodule->error("Error: unsupported PDB field, \""+ - pdb_field_str+"\".\n", COLVARS_INPUT_ERROR); + if (pdb_field == e_pdb_field::none) { + cvmodule->error("Error: unsupported PDB field, \"" + pdb_field_str + "\".\n", + COLVARS_INPUT_ERROR); } return pdb_field; @@ -975,19 +966,19 @@ int colvarproxy_namd::load_coords_pdb(char const *pdb_filename, double atom_pdb_field_value = 0.0; switch (pdb_field_index) { - case e_pdb_occ: + case e_pdb_field::occ: atom_pdb_field_value = (pdb->atom(ipdb))->occupancy(); break; - case e_pdb_beta: + case e_pdb_field::beta: atom_pdb_field_value = (pdb->atom(ipdb))->temperaturefactor(); break; - case e_pdb_x: + case e_pdb_field::x: atom_pdb_field_value = (pdb->atom(ipdb))->xcoor(); break; - case e_pdb_y: + case e_pdb_field::y: atom_pdb_field_value = (pdb->atom(ipdb))->ycoor(); break; - case e_pdb_z: + case e_pdb_field::z: atom_pdb_field_value = (pdb->atom(ipdb))->zcoor(); break; default: @@ -1070,19 +1061,19 @@ int colvarproxy_namd::load_atoms_pdb(char const *pdb_filename, double atom_pdb_field_value = 0.0; switch (pdb_field_index) { - case e_pdb_occ: + case e_pdb_field::occ: atom_pdb_field_value = (pdb->atom(ipdb))->occupancy(); break; - case e_pdb_beta: + case e_pdb_field::beta: atom_pdb_field_value = (pdb->atom(ipdb))->temperaturefactor(); break; - case e_pdb_x: + case e_pdb_field::x: atom_pdb_field_value = (pdb->atom(ipdb))->xcoor(); break; - case e_pdb_y: + case e_pdb_field::y: atom_pdb_field_value = (pdb->atom(ipdb))->ycoor(); break; - case e_pdb_z: + case e_pdb_field::z: atom_pdb_field_value = (pdb->atom(ipdb))->zcoor(); break; default: diff --git a/namd/src/colvarproxy_namd.h b/namd/src/colvarproxy_namd.h index 655e33db7..9cdf70a29 100644 --- a/namd/src/colvarproxy_namd.h +++ b/namd/src/colvarproxy_namd.h @@ -206,14 +206,14 @@ class colvarproxy_namd : public colvarproxy { cvm::rvector position_distance(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2) const; - enum e_pdb_field { - e_pdb_none, - e_pdb_occ, - e_pdb_beta, - e_pdb_x, - e_pdb_y, - e_pdb_z, - e_pdb_ntot + enum class e_pdb_field { + none, + occ, + beta, + x, + y, + z, + ntot }; e_pdb_field pdb_field_str2enum(std::string const &pdb_field_str); From ed621c17ad93b8822714503dfce92fdbd4e84d08 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 13 Nov 2025 11:25:55 -0500 Subject: [PATCH 3/4] refactor: Separate colvarproxy_namd setup steps (those that depend on GlobalMaster vs. those that don't) --- namd/src/GlobalMasterColvars.C | 10 +- namd/src/colvarproxy_namd.C | 234 ++++++++++++++++++++------------- namd/src/colvarproxy_namd.h | 28 ++-- 3 files changed, 169 insertions(+), 103 deletions(-) diff --git a/namd/src/GlobalMasterColvars.C b/namd/src/GlobalMasterColvars.C index 1789867c1..07cc2eea5 100644 --- a/namd/src/GlobalMasterColvars.C +++ b/namd/src/GlobalMasterColvars.C @@ -5,10 +5,18 @@ #include "colvarproxy_namd.h" -GlobalMasterColvars::GlobalMasterColvars() : proxy(new colvarproxy_namd(this)) {} +GlobalMasterColvars::GlobalMasterColvars() +{ + proxy.reset(new colvarproxy_namd()); + proxy->set_gm_object(this); + proxy->init(); + proxy->init_module(); +} + GlobalMasterColvars::~GlobalMasterColvars() { reset(); } + void GlobalMasterColvars::calculate() { proxy->calculate(); } diff --git a/namd/src/colvarproxy_namd.C b/namd/src/colvarproxy_namd.C index 21fdc4d4e..46b579f3f 100644 --- a/namd/src/colvarproxy_namd.C +++ b/namd/src/colvarproxy_namd.C @@ -48,15 +48,37 @@ #include "colvarproxy_namd_version.h" -colvarproxy_namd::colvarproxy_namd(GlobalMasterColvars *gm) - : globalmaster(gm) +colvarproxy_namd::colvarproxy_namd() + : colvarproxy() { + if (cvm::debug()) + iout << "colvars: initializing colvarproxy_namd object.\n" << endi; + engine_name_ = "NAMD"; + + version_int = get_version_from_string(COLVARPROXY_VERSION); + + boltzmann_ = 0.001987191; + + angstrom_value_ = 1.0; + + // In NAMD, masses and charges are already available when initializing Colvars + updated_masses_ = updated_charges_ = true; +} + + +void colvarproxy_namd::set_gm_object(GlobalMasterColvars *gm) +{ + globalmaster = gm; +} + + +int colvarproxy_namd::init() +{ #if CMK_SMP && USE_CKLOOP charm_lock_state = CmiCreateLock(); #endif - version_int = get_version_from_string(COLVARPROXY_VERSION); #if CMK_TRACE_ENABLED if ( 0 == CkMyPe() ) { traceRegisterUserEvent("GM COLVAR item", GLOBAL_MASTER_CKLOOP_CALC_ITEM); @@ -64,39 +86,11 @@ colvarproxy_namd::colvarproxy_namd(GlobalMasterColvars *gm) traceRegisterUserEvent("GM COLVAR scripted bias", GLOBAL_MASTER_CKLOOP_CALC_SCRIPTED_BIASES ); } #endif - first_timestep = true; - globalmaster->requestTotalForcePublic(total_force_requested); - boltzmann_ = 0.001987191; - - angstrom_value_ = 1.; - - // initialize pointers to NAMD configuration data simparams = Node::Object()->simParameters; - if (cvm::debug()) - iout << "Info: initializing the colvars proxy object.\n" << endi; - - // find the configuration file, if provided - StringList *config = Node::Object()->configList->find("colvarsConfig"); - - // find the input state file - StringList *input_restart = Node::Object()->configList->find("colvarsInput"); - colvarproxy_io::set_input_prefix(input_restart ? input_restart->data : ""); - update_target_temperature(); set_integration_timestep(simparams->dt); - set_time_step_factor(simparams->globalMasterFrequency); - - random.reset(new Random(simparams->randomSeed)); - - // both fields are taken from data structures already available - updated_masses_ = updated_charges_ = true; - - // Take the output prefixes from the NAMD input - colvarproxy_io::set_output_prefix(std::string(simparams->outputFilename)); - colvarproxy_io::set_restart_output_prefix(std::string(simparams->restartFilename)); - colvarproxy_io::set_default_restart_frequency(simparams->restartFrequency); if (simparams->accelMDOn) { accelMDOn = true; @@ -105,53 +99,84 @@ colvarproxy_namd::colvarproxy_namd(GlobalMasterColvars *gm) } amd_weight_factor = 1.0; + random.reset(new Random(simparams->randomSeed)); + +#if !defined (NAMD_UNIFIED_REDUCTION) + reduction = ReductionMgr::Object()->willSubmit(REDUCTIONS_BASIC); +#endif + +#if defined(NODEGROUP_FORCE_REGISTER) && !defined(NAMD_UNIFIED_REDUCTION) + CProxy_PatchData cpdata(CkpvAccess(BOCclass_group).patchData); + PatchData *patchData = cpdata.ckLocalBranch(); + nodeReduction = patchData->reduction; +#endif + + // If an input state file was provided for Colvars via NAMD script, record its name + auto *input_state_from_namd = Node::Object()->configList->find("colvarsInput"); + if (input_state_from_namd) { + colvarproxy_io::set_input_prefix(input_state_from_namd->data); + } + + // Take the default output prefixes from the NAMD script + colvarproxy_io::set_output_prefix(std::string(simparams->outputFilename)); + colvarproxy_io::set_restart_output_prefix(std::string(simparams->restartFilename)); + colvarproxy_io::set_default_restart_frequency(simparams->restartFrequency); + // check if it is possible to save output configuration if ((!output_prefix_str.size()) && (!restart_output_prefix_str.size())) { - error("Error: neither the final output state file or " - "the output restart file could be defined, exiting.\n"); + error("Error: neither the final output state file or the output restart file could be defined, " + "exiting.\n"); + return COLVARS_INPUT_ERROR; } - init_atoms_map(); + if (globalmaster) { + set_time_step_factor(simparams->globalMasterFrequency); + init_atoms_map(); + } - // initialize module: this object will be the communication proxy - cvmodule = new colvarmodule(this); + return COLVARS_OK; +} - cvmodule->log("Using NAMD interface, version "+ - cvm::to_str(COLVARPROXY_VERSION)+".\n"); - cvmodule->cite_feature("NAMD engine"); - cvmodule->cite_feature("Colvars-NAMD interface"); - errno = 0; - for ( ; config; config = config->next ) { - add_config("configfile", config->data); - } +int colvarproxy_namd::init_module() +{ + int error_code = COLVARS_OK; - // Trigger immediate initialization of the module - colvarproxy::parse_module_config(); - colvarproxy_namd::setup(); - cvmodule->update_engine_parameters(); - cvmodule->setup_input(); - cvmodule->setup_output(); + if (! cvmodule) { + // initialize module: this object will be the communication proxy + cvmodule = new colvarmodule(this); + + cvmodule->log("Using NAMD interface, version " + cvm::to_str(COLVARPROXY_VERSION) + ".\n"); + cvmodule->cite_feature("NAMD engine"); + cvmodule->cite_feature("Colvars-NAMD interface"); + + // save to Node for Tcl script access + Node::Object()->colvars = cvmodule; - // save to Node for Tcl script access - Node::Object()->colvars = cvmodule; + if (simparams->firstTimestep != 0) { + cvmodule->set_initial_step(static_cast(simparams->firstTimestep)); + } - if (simparams->firstTimestep != 0) { - cvmodule->set_initial_step(static_cast(simparams->firstTimestep)); + } else { + error("Error: trying to allocate the Colvars module twice"); + return COLVARS_BUG_ERROR; } -#if !defined (NAMD_UNIFIED_REDUCTION) - reduction = ReductionMgr::Object()->willSubmit(REDUCTIONS_BASIC); -#endif + // find the configuration file, if provided + StringList *config = Node::Object()->configList->find("colvarsConfig"); + errno = 0; + for ( ; config; config = config->next ) { + add_config("configfile", config->data); + } - #if defined(NODEGROUP_FORCE_REGISTER) && !defined(NAMD_UNIFIED_REDUCTION) - CProxy_PatchData cpdata(CkpvAccess(BOCclass_group).patchData); - PatchData *patchData = cpdata.ckLocalBranch(); - nodeReduction = patchData->reduction; - #endif + // Trigger immediate initialization of the module + error_code |= colvarproxy::parse_module_config(); + error_code |= colvarproxy_namd::setup(); + error_code |= cvmodule->update_engine_parameters(); + error_code |= cvmodule->setup_input(); + error_code |= cvmodule->setup_output(); - if (cvm::debug()) - iout << "Info: done initializing the colvars proxy object.\n" << endi; + return COLVARS_OK; } @@ -234,13 +259,13 @@ int colvarproxy_namd::update_atoms_map(AtomIDList::const_iterator begin, int colvarproxy_namd::setup() { - int error_code = colvarproxy::setup(); - if (cvmodule->size() == 0) { // Module is empty, nothing to do return COLVARS_OK; } + int error_code = colvarproxy::setup(); + log("Updating NAMD interface:\n"); errno = 0; @@ -251,6 +276,39 @@ int colvarproxy_namd::setup() "as is the default option in NAMD.\n"); } + if (globalmaster) { + error_code |= setup_gm_atom_buffers(); + error_code |= setup_gm_atom_group_buffers(); + error_code |= setup_gm_volmap_buffers(); + } + + if (total_force_requested && modified_atom_list()) { + if (cvm::debug()) { + log("zeroing out total forces on atoms and groups.\n"); + } + set_total_forces_invalid(); + } + + size_t const new_features_hash = std::hash{}(cvmodule->feature_report(0)); + if (new_features_hash != features_hash) { + // Nag only once, there may be many run commands with the same configuration + log(std::string("\n") + cvmodule->feature_report(0) + std::string("\n")); + features_hash = new_features_hash; + } + + update_target_temperature(); + log("updating target temperature (T = " + cvm::to_str(target_temperature()) + " K).\n"); + + // Note: not needed currently, but may be in the future if NAMD allows + // redefining the timestep + set_integration_timestep(simparams->dt); + + return error_code; +} + + +int colvarproxy_namd::setup_gm_atom_buffers() +{ log("updating atomic data ("+cvm::to_str(atoms_ids.size())+" atoms).\n"); size_t i; @@ -262,6 +320,12 @@ int colvarproxy_namd::setup() atoms_new_colvar_forces[i] = cvm::rvector(0.0, 0.0, 0.0); } + return COLVARS_OK; +} + + +int colvarproxy_namd::setup_gm_atom_group_buffers() +{ size_t n_group_atoms = 0; for (int ig = 0; ig < globalmaster->getRequestedGroups().size(); ig++) { n_group_atoms += globalmaster->getRequestedGroups()[ig].size(); @@ -280,6 +344,13 @@ int colvarproxy_namd::setup() atom_groups_coms[ig] = cvm::rvector(0.0, 0.0, 0.0); atom_groups_new_colvar_forces[ig] = cvm::rvector(0.0, 0.0, 0.0); } + return COLVARS_OK; +} + + +int colvarproxy_namd::setup_gm_volmap_buffers() +{ + int error_code = COLVARS_OK; #if NAMD_VERSION_NUMBER >= 34471681 log("updating grid object data ("+cvm::to_str(volmaps_ids.size())+ @@ -289,29 +360,6 @@ int colvarproxy_namd::setup() } #endif - if (total_force_requested && modified_atom_list()) { - if (cvm::debug()) { - log("zeroing out buffers total forces on atom and groups.\n"); - } - set_total_forces_invalid(); - } - - size_t const new_features_hash = - std::hash{}(cvmodule->feature_report(0)); - if (new_features_hash != features_hash) { - // Nag only once, there may be many run commands - log(std::string("\n")+cvmodule->feature_report(0)+std::string("\n")); - features_hash = new_features_hash; - } - - update_target_temperature(); - log("updating target temperature (T = "+ - cvm::to_str(target_temperature())+" K).\n"); - - // Note: not needed currently, but may be in the future if NAMD allows - // redefining the timestep - set_integration_timestep(simparams->dt); - return error_code; } @@ -710,7 +758,7 @@ void colvarproxy_namd::request_total_force(bool yesno) cvmodule->log("colvarproxy_namd::request_total_force()\n"); } total_force_requested = yesno; - globalmaster->requestTotalForcePublic(total_force_requested); + if (globalmaster) globalmaster->requestTotalForcePublic(total_force_requested); if (cvm::debug()) { cvmodule->log("colvarproxy_namd::request_total_force() end\n"); } @@ -894,10 +942,8 @@ cvm::rvector colvarproxy_namd::position_distance(cvm::atom_pos const &pos1, { Position const p1(pos1.x, pos1.y, pos1.z); Position const p2(pos2.x, pos2.y, pos2.z); - Lattice const *lattice = globalmaster->get_lattice(); - // For triclinic cells, use Lattice::wrap_nearest_delta instead (computes the shift vector) - Vector const d = lattice->orthogonal() ? lattice->delta(p2, p1) - : ((p2 - p1) + lattice->wrap_nearest_delta(p2 - p1)); + // return p2 - p1 + Vector const d = lattice->delta(p2, p1); return cvm::rvector(d.x, d.y, d.z); } diff --git a/namd/src/colvarproxy_namd.h b/namd/src/colvarproxy_namd.h index 9cdf70a29..7ec276e14 100644 --- a/namd/src/colvarproxy_namd.h +++ b/namd/src/colvarproxy_namd.h @@ -37,6 +37,21 @@ class SimParameters; /// Communication between colvars and NAMD (implementation of \link colvarproxy \endlink) class colvarproxy_namd : public colvarproxy { +public: + + colvarproxy_namd(); + ~colvarproxy_namd(); + + /// Tell the proxy that it will be using the GlobalMaster interface + void set_gm_object(GlobalMasterColvars *gm); + + /// Initialize proxy data based on the chosen interface + int init(); // no override + + /// Initialize the module + int init_module(); // no override + + void init_tcl_pointers() override; protected: @@ -48,7 +63,7 @@ class colvarproxy_namd : public colvarproxy { std::vector atoms_map; /// Pointer to the NAMD simulation input object - SimParameters *simparams; + SimParameters *simparams = nullptr; /// Pointer to Controller object Controller const *controller; @@ -56,8 +71,10 @@ class colvarproxy_namd : public colvarproxy { /// NAMD-style PRNG object std::unique_ptr random; - bool first_timestep; - cvm::step_number previous_NAMD_step; + /// Use to distinguish between "run 0" and actual runs + bool first_timestep = true; + + cvm::step_number previous_NAMD_step = 0L; /// Used to submit restraint energy as MISC #if !defined (NAMD_UNIFIED_REDUCTION) @@ -74,11 +91,6 @@ class colvarproxy_namd : public colvarproxy { public: - void init_tcl_pointers() override; - - colvarproxy_namd(GlobalMasterColvars *gm); - ~colvarproxy_namd(); - int setup() override; int reset() override; From b4e33e9d28db0351d7de397060a1a15276de20c3 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 13 Nov 2025 11:25:56 -0500 Subject: [PATCH 4/4] refactor: Separate colvarproxy_namd run steps --- namd/src/colvarproxy_namd.C | 148 ++++++++++++++++++++++-------------- namd/src/colvarproxy_namd.h | 52 +++++++++---- 2 files changed, 129 insertions(+), 71 deletions(-) diff --git a/namd/src/colvarproxy_namd.C b/namd/src/colvarproxy_namd.C index 46b579f3f..bfa40b014 100644 --- a/namd/src/colvarproxy_namd.C +++ b/namd/src/colvarproxy_namd.C @@ -433,24 +433,91 @@ void colvarproxy_namd::calculate() } previous_NAMD_step = step; + if (accelMDOn) update_accelMD_info(); - auto *lattice = globalmaster->get_lattice(); + update_lattice(); - { - 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, b.z); - unit_cell_z.set(c.x, c.y, c.z); + if (globalmaster) { + read_gm_atom_buffers(); + } + + if (cvm::debug()) { + print_input_atomic_data(); + } + // call the collective variable module + if (cvmodule->calc() != COLVARS_OK) { + error("Error in the collective variables module.\n"); + } + + if (total_force_requested) { + // Total forces will be valid at the next step (this function is only called once) + set_total_forces_valid(); + } + + if (cvm::debug()) { + print_output_atomic_data(); + } + + if (globalmaster) { + send_gm_atom_forces(); + } + + // send MISC energy + #if defined(NODEGROUP_FORCE_REGISTER) && !defined(NAMD_UNIFIED_REDUCTION) + if(!simparams->CUDASOAintegrate) { + reduction->submit(); + } + #else + #if !defined(NAMD_UNIFIED_REDUCTION) + reduction->submit(); + #else + // submitReduction(); + #endif + #endif + + // 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) { + post_run(); + } + +} + + +void colvarproxy_namd::update_lattice() +{ + if (globalmaster) { + // Copy the Lattice object + auto *l = globalmaster->get_lattice(); + if (!l) { + boundaries_type = boundaries_unsupported; + return; + } + if (!l->a_p() && !l->b_p() && !l->c_p()) { + boundaries_type = boundaries_non_periodic; + reset_pbc_lattice(); + return; + } else { + lattice.set(l->a(), l->b(), l->c(), l->origin()); + } } - if (!lattice->a_p() && !lattice->b_p() && !lattice->c_p()) { + unit_cell_x.set(lattice.a().x, lattice.a().y, lattice.a().z); + unit_cell_y.set(lattice.b().x, lattice.b().y, lattice.b().z); + unit_cell_z.set(lattice.c().x, lattice.c().y, lattice.c().z); + + if (cvm::debug()) { + cvmodule->log("unit_cell_x = " + cvm::to_str(unit_cell_x)); + cvmodule->log("unit_cell_y = " + cvm::to_str(unit_cell_y)); + cvmodule->log("unit_cell_z = " + cvm::to_str(unit_cell_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()) { + } 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; @@ -459,11 +526,14 @@ void colvarproxy_namd::calculate() } else { boundaries_type = boundaries_unsupported; } +} + +void colvarproxy_namd::read_gm_atom_buffers() +{ if (cvm::debug()) { - cvmodule->log(std::string(cvm::line_marker)+ - "colvarproxy_namd, step no. "+cvm::to_str(cvmodule->it)+"\n"+ - "Updating atomic data arrays.\n"); + cvmodule->log(std::string(cvm::line_marker) + "colvarproxy_namd, step no. " + + cvm::to_str(cvmodule->it) + "\n" + "Updating atomic data arrays from GlobalMaster.\n"); } // must delete the forces applied at the previous step: we can do @@ -614,25 +684,11 @@ void colvarproxy_namd::calculate() } } #endif +} - if (cvm::debug()) { - print_input_atomic_data(); - } - - // call the collective variable module - if (cvmodule->calc() != COLVARS_OK) { - cvmodule->error("Error in the collective variables module.\n", COLVARS_ERROR); - } - - if (total_force_requested) { - // Total forces will be valid at the next step (this function is only called once) - set_total_forces_valid(); - } - - if (cvm::debug()) { - print_output_atomic_data(); - } +void colvarproxy_namd::send_gm_atom_forces() +{ // 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]; @@ -665,25 +721,6 @@ void colvarproxy_namd::calculate() } } #endif - - // send MISC energy - #if defined(NODEGROUP_FORCE_REGISTER) && !defined(NAMD_UNIFIED_REDUCTION) - if(!simparams->CUDASOAintegrate) { - reduction->submit(); - } - #else - #if !defined(NAMD_UNIFIED_REDUCTION) - reduction->submit(); - #else - // submitReduction(); - #endif - #endif - - // 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) { - post_run(); - } } @@ -747,9 +784,11 @@ void colvarproxy_namd::add_energy(cvm::real energy) #if !defined(NAMD_UNIFIED_REDUCTION) reduction->item(REDUCTION_MISC_ENERGY) += energy; #else - globalmaster->addReductionEnergyPublic(REDUCTION_MISC_ENERGY, energy); - #endif - #endif + if (globalmaster) { + globalmaster->addReductionEnergyPublic(REDUCTION_MISC_ENERGY, energy); + } +#endif +#endif } void colvarproxy_namd::request_total_force(bool yesno) @@ -942,8 +981,7 @@ cvm::rvector colvarproxy_namd::position_distance(cvm::atom_pos const &pos1, { Position const p1(pos1.x, pos1.y, pos1.z); Position const p2(pos2.x, pos2.y, pos2.z); - // return p2 - p1 - Vector const d = lattice->delta(p2, p1); + Vector const d = (boundaries_type == boundaries_non_periodic) ? (p2 - p1) : lattice.delta(p2, p1); return cvm::rvector(d.x, d.y, d.z); } diff --git a/namd/src/colvarproxy_namd.h b/namd/src/colvarproxy_namd.h index 7ec276e14..85bf595de 100644 --- a/namd/src/colvarproxy_namd.h +++ b/namd/src/colvarproxy_namd.h @@ -17,6 +17,8 @@ #include +#include "Lattice.h" + #include "colvarproxy_namd_version.h" // For NAMD_UNIFIED_REDUCTION and AtomIDList @@ -52,21 +54,52 @@ class colvarproxy_namd : public colvarproxy { int init_module(); // no override void init_tcl_pointers() override; + int setup() override; + int reset() override; + + /// Get the target temperature from the NAMD thermostats supported so far + int update_target_temperature(); + + /// Create map from NAMD atom indices to colvarproxy array indices (used by GlobalMaster) + void init_atoms_map(); + + /// Update map to reflect other requested atoms, including other GlobalMaster objects + int update_atoms_map(AtomIDList::const_iterator begin, AtomIDList::const_iterator end); + + /// Create and zero out data buffers for atoms requested through GlobalMaster + int setup_gm_atom_buffers(); + + /// Create and zero out data buffers for atom groups requested through GlobalMaster + int setup_gm_atom_group_buffers(); + + /// Create and zero out data buffers for grid objects requested through GlobalMaster + int setup_gm_volmap_buffers(); + + /// Read the current simulation PBC lattice + void update_lattice(); + + /// Read the current coordinates and total forces + void read_gm_atom_buffers(); + + /// Send Colvars forces to GlobalMaster + void send_gm_atom_forces(); protected: /// Pointer to the parent GlobalMaster object GlobalMasterColvars *globalmaster = nullptr; - /// \brief Array of atom indices (relative to the colvarproxy arrays), - /// usedfor faster copy of atomic data + /// Map from NAMD atom indices to colvarproxy array indices (used by GlobalMaster) std::vector atoms_map; /// Pointer to the NAMD simulation input object SimParameters *simparams = nullptr; /// Pointer to Controller object - Controller const *controller; + Controller const *controller = nullptr; + + /// PBC lattice object + Lattice lattice; /// NAMD-style PRNG object std::unique_ptr random; @@ -91,19 +124,6 @@ class colvarproxy_namd : public colvarproxy { public: - int setup() override; - int reset() override; - - /// Get the target temperature from the NAMD thermostats supported so far - int update_target_temperature(); - - /// Allocate an atoms map with the same size as the NAMD topology - void init_atoms_map(); - - // synchronize the local arrays with requested or forced atoms - int update_atoms_map(AtomIDList::const_iterator begin, - AtomIDList::const_iterator end); - void calculate(); void log(std::string const &message) override;