diff --git a/hooks/hoomd/Driver.cpp b/hooks/hoomd/Driver.cpp index 764d3c80..548e15d4 100644 --- a/hooks/hoomd/Driver.cpp +++ b/hooks/hoomd/Driver.cpp @@ -48,8 +48,11 @@ namespace SSAGES py::object exec_conf_obj = py::cast(exec_conf_); hoomd_module.attr("context").attr("exec_conf") = exec_conf_obj; + // Evaluate in scope of main module + py::object scope = py::module::import("__main__").attr("__dict__"); + // Evaluate the user script file - py::eval_file(rh_->GetInput().c_str()); + py::eval_file(rh_->GetInput().c_str(),scope); py::object context = hoomd_module.attr("context").attr("current"); // Get the current C++ SystemDefinition and update the HOOMDHook @@ -73,6 +76,7 @@ namespace SSAGES // Run HOOMD hook_->update(0); // this is a hack for initialization + hook_->setPyScope(scope); hook_->PreSimulationHook(); hoomd_module.attr("run")(run_steps_); hook_->PostSimulationHook(); @@ -117,8 +121,9 @@ namespace SSAGES execution_mode = ExecutionConfiguration::executionMode::GPU; } + std::vector gpu_id(1,-1); auto exec_conf = std::make_shared( - execution_mode, -1, false, false, + execution_mode, gpu_id, false, false, std::shared_ptr(), 0, rh->GetLocalComm()); auto hook = std::make_shared(); diff --git a/hooks/hoomd/HOOMDHook.cpp b/hooks/hoomd/HOOMDHook.cpp index 7b909b11..bfa9a747 100644 --- a/hooks/hoomd/HOOMDHook.cpp +++ b/hooks/hoomd/HOOMDHook.cpp @@ -6,7 +6,7 @@ using namespace SSAGES; HOOMDHook::HOOMDHook() : -Hook(), HalfStepHook() +Hook(), HalfStepHook(), timestep_(0) { std::cerr << "Installing SSAGES HOOMD-blue hook." << std::endl; } diff --git a/hooks/hoomd/HOOMDHook.h b/hooks/hoomd/HOOMDHook.h index ceacebd3..6528ff5d 100644 --- a/hooks/hoomd/HOOMDHook.h +++ b/hooks/hoomd/HOOMDHook.h @@ -2,11 +2,14 @@ #define SSAGES_HOOMD_HOOK_H #include "Hook.h" +#include "CVs/CVManager.h" + #include "hoomd/ExecutionConfiguration.h" #include "hoomd/SystemDefinition.h" #include "hoomd/HalfStepHook.h" #include "hoomd/ComputeThermo.h" +#include "hoomd/extern/pybind/include/pybind11/pybind11.h" // SSAGES Hook class for HOOMD class HOOMDHook : public SSAGES::Hook, public HalfStepHook @@ -21,6 +24,9 @@ class HOOMDHook : public SSAGES::Hook, public HalfStepHook // HOOMD ComputeThermo std::shared_ptr thermo_; + // Python interpreter scope + pybind11::object scope_; + protected: // Implementation of the SyncToEngine interface. void SyncToEngine() override; @@ -31,12 +37,35 @@ class HOOMDHook : public SSAGES::Hook, public HalfStepHook public: HOOMDHook(); + //! Pre-simulation hook + /*! + * This should be called at the appropriate + * time by the Hook implementation. + */ + virtual void PreSimulationHook() override + { + // call base class method + Hook::PreSimulationHook(); + + // Set simulation engine hook on CVs + for(auto& cv : cvmanager_->GetCVs()) + { + cv->SetHook(*this); + } + } + // Sets SystemDefinition to enable particle data access - void setSystemDefinition(std::shared_ptr sysdef) + void setSystemDefinition(std::shared_ptr sysdef) override { sysdef_ = sysdef; } + // Get the SystemDefinition + std::shared_ptr getSystemDefinition() + { + return sysdef_; + } + // Sets ComputeThermo to enable temperature and energy computation void setComputeThermo(std::shared_ptr thermo) { @@ -44,7 +73,25 @@ class HOOMDHook : public SSAGES::Hook, public HalfStepHook } // Synchronize snapshot with SSAGES after computing forces - void update(unsigned int timestep); + void update(unsigned int timestep) override; + + // Return the current time step + unsigned int getTimeStep() + { + return timestep_; + } + + // Set the python interpreter scope + void setPyScope(pybind11::object scope) + { + scope_ = scope; + } + + // Set the python interpreter scope + pybind11::object getPyScope() + { + return scope_; + } ~HOOMDHook(); }; diff --git a/hooks/hoomd/HOOMDWrapCV.h b/hooks/hoomd/HOOMDWrapCV.h new file mode 100644 index 00000000..9416a15d --- /dev/null +++ b/hooks/hoomd/HOOMDWrapCV.h @@ -0,0 +1,172 @@ +/** + * This file is part of + * SSAGES - Suite for Advanced Generalized Ensemble Simulations + * + * Copyright 2016 Yamil Colon + * Hythem Sidky + * + * SSAGES is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SSAGES is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SSAGES. If not, see . + */ +#pragma once + +#include "CVs/CollectiveVariable.h" +#include "Validator/ObjectRequirement.h" +#include "Drivers/DriverException.h" +#include "Snapshot.h" +#include "schema.h" + +#include "hoomd/ForceCompute.h" + +namespace SSAGES +{ + //! Collective variable to calculate angle. + class HOOMDWrapCV : public CollectiveVariable + { + private: + //! The ForceCompute we wrap + std::shared_ptr fc_; + + //! A reference to the HOOMD hook + HOOMDHook& hook_; + + public: + + //! Constructor. + /*! + * \param fc The force compute to wrap + * + * Wrap a HOOMD ForceCompute into a CollectiveVariable + * + * \todo Bounds needs to be an input and periodic boundary conditions + */ + HOOMDWrapCV(std::shared_ptr fc); + fc_(fc) + { } + + //! Initialize necessary variables. + /*! + * \param snapshot Current simulation snapshot. + */ + void Initialize(const Snapshot& snapshot) override + { + #if 0 + using std::to_string; + + std::vector found; + snapshot.GetLocalIndices(atomids_, &found); + int nfound = found.size(); + MPI_Allreduce(MPI_IN_PLACE, &nfound, 1, MPI_INT, MPI_SUM, snapshot.GetCommunicator()); + + if(nfound != 3) + throw BuildException({ + "TorsionalCV: Expected to find " + + to_string(3) + + " atoms, but only found " + + to_string(nfound) + "." + }); + #endif + } + + //! This sets a reference to the simulation engine hook. + /*! + * This method is called during initialization and can be used by the CV + * to access engine-specific data structures. + */ + virtual void SetHook(const HOOMDHook& hook) + { + hook_ = hook; + } + + //! Evaluate the CV. + /*! + * \param snapshot Current simulation snapshot. + */ + void Evaluate(const Snapshot& snapshot) override + { + // evaluate the underlying ForceCompute + fc_->compute(hook_.getTimeStep()); + + // reduce CV + val_ = fc->calcEnergySum(); + } + + //! Compute the particle forces and virial by scaling the gradient with a constant + /*! + * \param bias The constant scaling factor to apply to all particle forces + * \param snapshot The snapshot that contains the forces + * + */ + virtual void ApplyBias(double bias, const Snapshot& snapshot) const + { + // evaluate the underlying ForceCompute (only if necessary) + fc_->compute(hook_.getTimeStep()); + + ArrayHandle h_force(fc_->getForce(), access_location::host, access_mode::readwrite); + ArrayHandle h_virial(fc_->getVirial(), access_location::host, access_mode::readwrite); + ArrayHandle h_torque(fc_->getTorque(), access_location::host, access_mode::readwrite); + + unsigned int virial_pitch = fc_->getVirial().getPitch(); + + auto pdata = hook_->getSystemDefinition()->getParticleData(); + unsigned int n = pdata->getN(); + + // multiply particle forces with bias + for (unsigned int i = 0; i < n; ++i) + h_force.data[i] *= bias; + + for (unsigned int j = 0; j < 6; ++j) + for (unsigned int i = 0; i < n; ++i) + h_virial.data[j*virial_pitch + i] *= bias; + + #if 0 + // currently cannot set the external virial + for (unsigned int j = 0; j < 6; ++j) + fc_->setExternalVirial(j,fc_->getExternalVirial(j)*bias); + #endif + } + + //! \copydoc CollectiveVariable::BuildCV() + static HOOMDWrapCV* Build(const Json::Value& json, const std::string& path) + { + Json::ObjectRequirement validator; + Json::Value schema; + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader = rbuilder.newCharReader(); + + reader->parse(JsonSchema::HOOMDWrapCV.c_str(), + JsonSchema::HOOMDWrapCV.c_str() + JsonSchema::HOOMDWrapCV.size(), + &schema, NULL); + validator.Parse(schema, path); + + // Validate inputs. + validator.Validate(json, path); + if(validator.HasErrors()) + throw BuildException(validator.GetErrors()); + + std::vector atomids; + auto force = json["force"].asString(); + + std::shared_ptr fc = context.attr(force).attr("cpp_force"); + return new HOOMDWrapCV(fc); + } + + //! Returns true if this CV can modify the particle forces in the snapshot + virtual bool ModifiesParticleForces() const + { + return false; + } + + + }; +} diff --git a/schema/CVs/HOOMD.cv.json b/schema/CVs/HOOMD.cv.json new file mode 100644 index 00000000..140071e1 --- /dev/null +++ b/schema/CVs/HOOMD.cv.json @@ -0,0 +1,23 @@ +{ + "type" : "object", + "varname" : "HOOMDCV", + "properties" : { + "type" : { + "type" : "string", + "enum" : ["HOOMDCV"] + }, + "force" : { + "type" : "string" + }, + "bounds" : { + "type" : "array", + "minItems" : 2, + "maxItems" : 2, + "items" : { + "type" : "number" + } + } + }, + "required" : ["type", "force"], + "additionalProperties" : false +} diff --git a/src/CVs/CollectiveVariable.cpp b/src/CVs/CollectiveVariable.cpp index 134010dd..cdddea66 100644 --- a/src/CVs/CollectiveVariable.cpp +++ b/src/CVs/CollectiveVariable.cpp @@ -36,6 +36,10 @@ #include "json/json.h" #include +#ifdef ENABLE_HOOMD +#include "../../hooks/hoomd/HOOMDWrapCV.h" +#endif + namespace SSAGES { CollectiveVariable* CollectiveVariable::BuildCV(const Json::Value &json, const std::string& path) @@ -67,6 +71,12 @@ namespace SSAGES return ParallelBetaRMSDCV::Build(json, path); else if (type == "AntiBetaRMSD") return AntiBetaRMSDCV::Build(json, path); + else if (type == "HOOMDCV") + #ifdef ENABLE_HOOMD + return HOOMDWrapCV::Build(json, path); + #else + throw std::invalid_argument(path + ": HOOMDCV not available. Compile with HOOMD Hook."); + #endif else throw std::invalid_argument(path + ": Unknown CV type specified."); } diff --git a/src/CVs/CollectiveVariable.h b/src/CVs/CollectiveVariable.h index 4889510a..532c7d05 100644 --- a/src/CVs/CollectiveVariable.h +++ b/src/CVs/CollectiveVariable.h @@ -25,6 +25,9 @@ #include #include +#include "Hook.h" +#include "Snapshot.h" + // Forward declare. namespace Json { class Value; @@ -67,6 +70,13 @@ namespace SSAGES */ virtual void Initialize(const class Snapshot&) {} + //! This sets a reference to the simulation engine hook. + /*! + * This method is called during initialization and can be used by the CV + * to access engine-specific data structures. + */ + virtual void SetHook(const Hook&) { } + //! Evaluate CV. /*! * Evaluation of the CV. This function is called by the Hook in the @@ -114,6 +124,35 @@ namespace SSAGES return location; } + //! Compute the particle forces and virial by scaling the gradient with a constant + /*! + * \param bias The constant scaling factor to apply to all particle forces + * \param snapshot The snapshot that contains the forces + * + */ + virtual void ApplyBias(double bias, Snapshot& snapshot) const + { + auto& grad = GetGradient(); + auto& forces = snapshot.GetForces(); + + // apply bias to particles + for (size_t j = 0; j < forces.size(); ++j) + for(size_t k = 0; k < 3; ++k) + forces[j][k] -= bias*grad[j][k]; + + // apply bias to virial + auto& boxgrad = GetBoxGradient(); + auto& virial = snapshot.GetVirial(); + + virial += bias*boxgrad; + } + + //! Returns true if this CV can modify the particle forces in the snapshot + virtual bool ModifiesParticleForces() const + { + return true; + } + //! Get current gradient of the CV. /*! * \return Per-atom gradient of the CV. @@ -123,7 +162,7 @@ namespace SSAGES * element in the vector is the derivative of the CV with respect to * the atom's coordinate (dCV/dxi). */ - const std::vector& GetGradient() const + virtual const std::vector& GetGradient() const { return grad_; } @@ -134,7 +173,7 @@ namespace SSAGES * * Returns the gradient of the CV with respect to the box. */ - const Matrix3& GetBoxGradient() const + virtual const Matrix3& GetBoxGradient() const { return boxgrad_; } diff --git a/src/Hook.h b/src/Hook.h index 6a45f7eb..b3ec1ba9 100644 --- a/src/Hook.h +++ b/src/Hook.h @@ -38,10 +38,10 @@ namespace SSAGES //! Vector of event listeners. std::vector listeners_; - //! Collective variable manager. - class CVManager* cvmanager_; - protected: + //! Collective variable manager. + class CVManager* cvmanager_; + //! Local snapshot. class Snapshot* snapshot_; @@ -94,7 +94,7 @@ namespace SSAGES * This should be called at the appropriate * time by the Hook implementation. */ - void PreSimulationHook(); + virtual void PreSimulationHook(); //! Post-integration hook. /*! @@ -124,4 +124,4 @@ namespace SSAGES //! Destructor virtual ~Hook(){} }; -} \ No newline at end of file +} diff --git a/src/Methods/ABF.cpp b/src/Methods/ABF.cpp index f564f124..e5b6b1f3 100644 --- a/src/Methods/ABF.cpp +++ b/src/Methods/ABF.cpp @@ -53,7 +53,7 @@ namespace SSAGES Fold_.setZero(dim_); // Initialize biases. - biases_.resize(snapshot->GetPositions().size(), Vector3{0, 0, 0}); + biases_.resize(dim_); // Initialize w \dot p's for finite difference. wdotp1_.setZero(dim_); @@ -78,7 +78,6 @@ namespace SSAGES auto cvs = cvmanager.GetCVs(cvmask_); auto& vels = snapshot->GetVelocities(); auto& mass = snapshot->GetMasses(); - auto& forces = snapshot->GetForces(); auto n = snapshot->GetNumAtoms(); @@ -102,6 +101,9 @@ namespace SSAGES //* Calculate W using Darve's approach (http://mc.stanford.edu/cgi-bin/images/0/06/Darve_2008.pdf). Eigen::MatrixXd Jmass = J.transpose(); + + auto& forces = snapshot->GetForces(); + if(massweigh_) { for(size_t i = 0; i < forces.size(); ++i) @@ -163,8 +165,8 @@ namespace SSAGES // Update the forces in snapshot by adding in the force bias from each // CV to each atom based on the gradient of the CV. - for (size_t j = 0; j < forces.size(); ++j) - forces[j] += biases_[j]; + for (size_t i = 0; i < dim_; ++i) + cvs[i]->ApplyBias(biases_[i],*snapshot); } // Post-simulation hook. @@ -176,18 +178,14 @@ namespace SSAGES void ABF::CalcBiasForce(const Snapshot* snapshot, const CVList& cvs, const std::vector &cvVals) { // Reset the bias. - biases_.resize(snapshot->GetNumAtoms(), Vector3{0,0,0}); - for(auto& b : biases_) - b.setZero(); + biases_.resize(dim_, 0.0); // Compute bias if within bounds. if(boundsCheck(cvVals)) { - for(size_t i = 0; i < dim_; ++i) + for(size_t i = 0; i < biases_.size(); ++i) { - auto& grad = cvs[i]->GetGradient(); - for(size_t j = 0; j < biases_.size(); ++j) - biases_[j] -= (Fworld_[i]->at(cvVals))*grad[j]/std::max(min_,Nworld_->at(cvVals)); + biases_[i] = Fworld_[i]->at(cvVals)/std::max(min_,Nworld_->at(cvVals)); } } // Otherwise, apply harmonic restraint if enabled. @@ -220,9 +218,7 @@ namespace SSAGES x0 = restraint_[i][1]; } - auto& grad = cvs[i]->GetGradient(); - for(size_t j = 0; j < biases_.size(); ++j) - biases_[j] -= (cvVal - x0)*k*grad[j]; + biases_[i] = (cvVal - x0)*k; } } } diff --git a/src/Methods/ABF.h b/src/Methods/ABF.h index 74e4f752..6fc1ac5a 100644 --- a/src/Methods/ABF.h +++ b/src/Methods/ABF.h @@ -110,7 +110,7 @@ namespace SSAGES bool massweigh_; //! Biases applied to atoms each timestep. - std::vector biases_; + std::vector biases_; //! Number of CVs in system. unsigned int dim_; diff --git a/src/Methods/ANN.cpp b/src/Methods/ANN.cpp index b05d4c31..00d20536 100644 --- a/src/Methods/ANN.cpp +++ b/src/Methods/ANN.cpp @@ -145,20 +145,9 @@ namespace SSAGES } // Apply bias to atoms. - auto& forces = snapshot->GetForces(); - auto& virial = snapshot->GetVirial(); - for(size_t i = 0; i < cvs.size(); ++i) { - auto& grad = cvs[i]->GetGradient(); - auto& boxgrad = cvs[i]->GetBoxGradient(); - - // Update the forces in snapshot by adding in the force bias from each - // CV to each atom based on the gradient of the CV. - for (size_t j = 0; j < forces.size(); ++j) - forces[j] -= derivatives[i]*grad[j]; - - virial += derivatives[i]*boxgrad; + cvs[i]->ApplyBias(derivatives[i], *snapshot); } } diff --git a/src/Methods/BasisFunc.cpp b/src/Methods/BasisFunc.cpp index a0c2580b..b86bfda5 100644 --- a/src/Methods/BasisFunc.cpp +++ b/src/Methods/BasisFunc.cpp @@ -139,21 +139,10 @@ namespace SSAGES } // Take each CV and add its biased forces to the atoms using the chain rule - auto& forces = snapshot->GetForces(); - auto& virial = snapshot->GetVirial(); for(size_t i = 0; i < cvs.size(); ++i) - { - auto& grad = cvs[i]->GetGradient(); - auto& boxgrad = cvs[i]->GetBoxGradient(); - - /* Update the forces in snapshot by adding in the force bias from each - *CV to each atom based on the gradient of the CV. - */ - for (size_t j = 0; j < forces.size(); ++j) - forces[j] += bias_grad[i]*grad[j]; - - virial -= bias_grad[i]*boxgrad; - } + { + cvs[i]->ApplyBias(-bias_grad[i],*snapshot); + } } // Post-simulation hook. diff --git a/src/Methods/ElasticBand.cpp b/src/Methods/ElasticBand.cpp index bc3ec5f2..068199d4 100644 --- a/src/Methods/ElasticBand.cpp +++ b/src/Methods/ElasticBand.cpp @@ -29,7 +29,6 @@ namespace SSAGES // Post-integration hook. void ElasticBand::PostIntegration(Snapshot* snapshot, const CVManager& cvmanager) { - auto& forces = snapshot->GetForces(); auto cvs = cvmanager.GetCVs(cvmask_); // Apply umbrella to cvs @@ -37,16 +36,13 @@ namespace SSAGES { // Get current CV and gradient. auto& cv = cvs[i]; - auto& grad = cv->GetGradient(); // Compute dV/dCV. auto diff = cv->GetDifference(centers_[i]); auto D = cvspring_[i] * diff; // Update forces. - for(size_t j = 0; j < forces.size(); ++j) - for(int k = 0; k < forces[j].size(); ++k) - forces[j][k] -= D*grad[j][k]; + cv->ApplyBias(D, *snapshot); // If not equilibrating and has evolved enough steps, // generate the gradient diff --git a/src/Methods/FiniteTempString.cpp b/src/Methods/FiniteTempString.cpp index 5ca544e4..c7447d2e 100644 --- a/src/Methods/FiniteTempString.cpp +++ b/src/Methods/FiniteTempString.cpp @@ -107,14 +107,12 @@ namespace SSAGES { // Get current cv and gradient auto& cv = cvs[i]; - auto& grad = cv->GetGradient(); // Compute dV/dCV auto D = cvspring_[i]*(cv->GetDifference(centers_[i])); // Update forces - for(size_t j = 0; j < forces.size(); j++) - forces[j] -= D*grad[j]; + cv->ApplyBias(D,*snapshot); } umbrella_iter_++; //Progress toward checkpoint } diff --git a/src/Methods/Meta.cpp b/src/Methods/Meta.cpp index f02b7ec0..f8be24d9 100644 --- a/src/Methods/Meta.cpp +++ b/src/Methods/Meta.cpp @@ -109,21 +109,9 @@ namespace SSAGES // Take each CV and add its biased forces to the atoms // using the chain rule. - auto& forces = snapshot->GetForces(); - auto& virial = snapshot->GetVirial(); - for(size_t i = 0; i < cvs.size(); ++i) { - auto& grad = cvs[i]->GetGradient(); - auto& boxgrad = cvs[i]->GetBoxGradient(); - - // Update the forces in snapshot by adding in the force bias from each - // CV to each atom based on the gradient of the CV. - for (size_t j = 0; j < forces.size(); ++j) - for(size_t k = 0; k < 3; ++k) - forces[j][k] -= derivatives_[i]*grad[j][k]; - - virial += derivatives_[i]*boxgrad; + cvs[i]->ApplyBias(derivatives_[i], *snapshot); } } diff --git a/src/Methods/Swarm.cpp b/src/Methods/Swarm.cpp index e0e5b030..9f7746c6 100644 --- a/src/Methods/Swarm.cpp +++ b/src/Methods/Swarm.cpp @@ -70,7 +70,6 @@ namespace SSAGES void Swarm::PostIntegration(Snapshot* snapshot, const CVManager& cvmanager) { auto cvs = cvmanager.GetCVs(cvmask_); - auto& forces = snapshot->GetForces(); auto& positions = snapshot->GetPositions(); auto& velocities = snapshot->GetVelocities(); @@ -109,25 +108,19 @@ namespace SSAGES { //Get current CV and gradient auto& cv = cvs[i]; - auto& grad = cv->GetGradient(); //Compute dV/dCV auto D = cvspring_[i]*(cv->GetDifference(centers_[i])); //Update forces - for(size_t j = 0; j < forces.size(); j++) - { - for(int k = 0; k < forces[j].size(); k++) - { - forces[j][k] -= (double)D*grad[j][k]; - } - } + cv->ApplyBias(D,*snapshot); } } else { //If the system was already initialized, simply reset the positions and velocities; this keeps them in their initialized states index_ = 0; + auto &forces = snapshot->GetForces(); for(auto& force: forces) force.setZero(); @@ -166,19 +159,12 @@ namespace SSAGES } //Get current CV and gradient auto& cv = cvs[i]; - auto& grad = cv->GetGradient(); //Compute dV/dCV auto D = cvspring_[i]*(cv->GetDifference(centers_[i])); //Update forces - for(size_t j = 0; j < forces.size(); j++) - { - for(int k = 0; k < forces[j].size(); k++) - { - forces[j][k] -= (double)D*grad[j][k]; - } - } + cv->ApplyBias((double) D, *snapshot); } if(iterator_ > initialize_steps_) { @@ -195,6 +181,7 @@ namespace SSAGES { //Reset positions and forces before first call to unrestrained sampling index_ = 0; + auto &forces = snapshot->GetForces(); for(auto& force: forces) force.setZero(); @@ -231,6 +218,7 @@ namespace SSAGES if(index_ < number_trajectories_) { + auto &forces = snapshot->GetForces(); for(auto& force: forces) force.setZero(); diff --git a/src/config.h.in b/src/config.h.in index 1deb80d3..5e9f07bb 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -30,6 +30,7 @@ #cmakedefine ENABLE_GROMACS #cmakedefine ENABLE_QBOX #cmakedefine ENABLE_OPENMD +#cmakedefine ENABLE_HOOMD #define EXTRA_CONFIG "@EXTRA_CONFIG@"