Skip to content

Commit c315048

Browse files
committed
Make it possible to run nonpolarizable MM
Note this is a horrible, horrible, horrible HACK
1 parent 86d29ac commit c315048

File tree

9 files changed

+65
-63
lines changed

9 files changed

+65
-63
lines changed

src/interface/Input.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ void Input::reader(const std::string & filename) {
198198
const Section & mmfq = input_.getSect("MMFQ");
199199
if (mmfq.isDefined()) {
200200
isFQ_ = true;
201+
isNonPolarizable_ = mmfq.getBool("NONPOLARIZABLE");
201202
fragments_.nSitesPerFragment =
202203
static_cast<PCMSolverIndex>(mmfq.getInt("SITESPERFRAGMENT"));
203204
std::vector<double> sites = mmfq.getDblVec("SITES");

src/interface/Input.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class PCMSolver_EXPORT Input {
119119
bool isDynamic() const { return isDynamic_; }
120120
double integratorScaling() const { return integratorScaling_; }
121121
bool isFQ() const { return isFQ_; }
122+
bool isNonPolarizable() const { return isNonPolarizable_; }
122123
/// @}
123124

124125
/// Keeps track of who did the parsing: the API or the host program
@@ -248,6 +249,8 @@ class PCMSolver_EXPORT Input {
248249
std::vector<double> geometry_;
249250
/// Whether this is a FQ calculation
250251
bool isFQ_;
252+
/// Whether this is a nonpolarizable MM calculation
253+
bool isNonPolarizable_;
251254
/// Whether to calculate the MEP from the molecular geometry
252255
bool MEPfromMolecule_;
253256
/// Whether to calculate the MEP from the charge distribution

src/interface/Meddle.cpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,16 @@ void Meddle::CTORBody() {
155155
TIMER_ON("Meddle::initCavity");
156156
initCavity();
157157
TIMER_OFF("Meddle::initCavity");
158+
}
158159

159-
TIMER_ON("Meddle::initStaticSolver");
160-
initStaticSolver();
161-
TIMER_OFF("Meddle::initStaticSolver");
160+
TIMER_ON("Meddle::initStaticSolver");
161+
initStaticSolver();
162+
TIMER_OFF("Meddle::initStaticSolver");
162163

163-
if (input_.isDynamic()) {
164-
TIMER_ON("Meddle::initDynamicSolver");
165-
initDynamicSolver();
166-
TIMER_OFF("Meddle::initDynamicSolver");
167-
}
164+
if (input_.isDynamic()) {
165+
TIMER_ON("Meddle::initDynamicSolver");
166+
initDynamicSolver();
167+
TIMER_OFF("Meddle::initDynamicSolver");
168168
}
169169
}
170170

@@ -335,10 +335,12 @@ double pcm::Meddle::computePolarizationEnergy(const std::string & mep_name,
335335
// Dot product of MEP + Electronegativities times Fluctuating charges
336336
energy = (functions_.at(mep_name) + input_.fragments().chi)
337337
.dot(functions_.at(asc_name));
338+
if (input_.isNonPolarizable()) { /* HACK Nonpolarizable doesn't need 1/2 */
339+
energy *= 2.0;
340+
}
338341
} else { /* Pure PCM calculation */
339342
// Dot product of MEP and ASC surface function
340-
energy =
341-
functions_.at(mep_name).dot(functions_.at(asc_name));
343+
energy = functions_.at(mep_name).dot(functions_.at(asc_name));
342344
}
343345
return (energy / 2.0);
344346
}
@@ -372,8 +374,13 @@ void pcm::Meddle::computeASC(const std::string & mep_name,
372374
// Get the proper iterators
373375
SurfaceFunctionMapConstIter iter_pot = functions_.find(mep_name);
374376
Eigen::VectorXd asc = Eigen::VectorXd::Zero(iter_pot->second.size());
375-
if (hasFQ_) { /* MMFQ calculation */
376-
asc = FQ_->computeCharge(iter_pot->second);
377+
if (hasFQ_) { /* MMFQ calculation */
378+
if (input_.isNonPolarizable()) { /* HACK We store point charges in the eta vector
379+
*/
380+
asc = input_.fragments().eta;
381+
} else {
382+
asc = FQ_->computeCharge(iter_pot->second);
383+
}
377384
} else { /* Pure PCM calculation */
378385
asc = K_0_->computeCharge(iter_pot->second, irrep);
379386
// Renormalize
@@ -402,9 +409,11 @@ void pcm::Meddle::computeResponseASC(const std::string & mep_name,
402409
// Get the proper iterators
403410
SurfaceFunctionMapConstIter iter_pot = functions_.find(mep_name);
404411
Eigen::VectorXd asc = Eigen::VectorXd::Zero(iter_pot->second.size());
405-
if (hasFQ_) { /* MMFQ calculation */
406-
// Do NOT add classical (electronegativities) contributions to RHS
407-
asc = FQ_->computeCharge(iter_pot->second, false);
412+
if (hasFQ_) { /* MMFQ calculation */
413+
if (!input_.isNonPolarizable()) { /* HACK Can we do it more cleanly/clearly? */
414+
// Do NOT add classical (electronegativities) contributions to RHS
415+
asc = FQ_->computeCharge(iter_pot->second, false);
416+
}
408417
} else { /* Pure PCM calculation */
409418
if (hasDynamic_) {
410419
asc = K_d_->computeCharge(iter_pot->second, irrep);
@@ -726,7 +735,8 @@ void Meddle::initStaticSolver() {
726735
delete biop;
727736

728737
// Perform Gauss' theorem check for nuclear charges
729-
if (!hasFQ_) GaussCheck();
738+
if (!hasFQ_)
739+
GaussCheck();
730740

731741
infoStream_ << "========== Static solver " << std::endl;
732742
infoStream_ << *K_0_ << std::endl;
@@ -759,8 +769,8 @@ void Meddle::initDynamicSolver() {
759769
}
760770

761771
void Meddle::initMMFQ() {
762-
FQ_ = new mmfq::FQOhno(input_.fragments());
763-
size_ = pcm::make_tuple(input_.fragments().sites.cols(),
772+
FQ_ = new mmfq::FQOhno(input_.fragments(), input_.isNonPolarizable());
773+
size_ = std::make_tuple(input_.fragments().sites.cols(),
764774
input_.fragments().sites.cols());
765775
hasFQ_ = true;
766776

src/mmfq/CMakeLists.txt

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,12 @@
1+
target_sources(pcm-objlib
2+
PRIVATE
3+
${CMAKE_CURRENT_SOURCE_DIR}/FQOhno.cpp
4+
)
5+
16
# List of headers
27
list(APPEND headers_list
38
FQOhno.hpp
49
)
5-
6-
# List of sources
7-
list(APPEND sources_list
8-
FQOhno.cpp
9-
)
10-
11-
add_library(mmfq OBJECT ${sources_list} ${headers_list})
12-
set_target_properties(mmfq
13-
PROPERTIES
14-
POSITION_INDEPENDENT_CODE 1
15-
CXX_VISIBILITY_PRESET hidden
16-
VISIBILITY_INLINES_HIDDEN 1
17-
)
18-
target_compile_definitions(mmfq
19-
PUBLIC
20-
PCMSolver_EXPORTS
21-
)
22-
if(BUILD_CUSTOM_BOOST)
23-
add_dependencies(mmfq custom_boost)
24-
endif()
25-
add_dependencies(mmfq generate-config-hpp)
26-
target_compile_options(mmfq
27-
PRIVATE
28-
"$<$<CONFIG:DEBUG>:${EXDIAG_CXX_FLAGS}>"
29-
)
30-
3110
# Sets install directory for all the headers in the list
3211
foreach(_header ${headers_list})
3312
install(FILES ${_header} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/mmfq)

src/mmfq/FQOhno.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@
3434

3535
namespace pcm {
3636
namespace mmfq {
37-
using utils::MMFQ;
38-
39-
FQOhno::FQOhno(const MMFQ & ff) : mmfq_(ff) { buildSystemMatrix_impl(); }
40-
4137
void FQOhno::buildSystemMatrix_impl() {
4238
PCMSolverIndex nFragments = mmfq_.nFragments;
4339
PCMSolverIndex nSitesPerFragment = mmfq_.nSitesPerFragment;
@@ -80,6 +76,7 @@ Eigen::VectorXd FQOhno::computeCharge_impl(const Eigen::VectorXd & potential,
8076

8177
std::ostream & FQOhno::printSolver(std::ostream & os) {
8278
os << "Fluctuating charge solver type: Ohno" << std::endl;
79+
if (nonPolarizable_) os << "Nonpolarizable force field" << std::endl;
8380
os << "Number of fragments = " << mmfq_.nFragments << std::endl;
8481
os << "Number of sites per fragment = " << mmfq_.nSitesPerFragment << std::endl;
8582
os << "Number of sites = " << mmfq_.nFragments * mmfq_.nSitesPerFragment;

src/mmfq/FQOhno.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,19 @@ namespace mmfq {
4343
* to solve for the charges.
4444
* This avoids computing and storing the inverse explicitly.
4545
*/
46-
class FQOhno __final {
46+
class FQOhno final {
4747
public:
48-
FQOhno() {}
48+
FQOhno() = default;
4949
/*! \brief Construct solver
5050
* \param[in] ff the fluctuating charges force field
51+
* \param[in] nonpol whether this is a nonpolarizable MM calculation
5152
*/
52-
FQOhno(const utils::MMFQ & ff);
53+
FQOhno(const utils::MMFQ & ff, bool nonpol = false)
54+
: nonPolarizable_(nonpol), built_(false), mmfq_(ff) {
55+
if (!nonPolarizable_)
56+
buildSystemMatrix_impl();
57+
}
5358

54-
~FQOhno() {}
5559
friend std::ostream & operator<<(std::ostream & os, FQOhno & solver) {
5660
return solver.printSolver(os);
5761
}
@@ -63,6 +67,7 @@ class FQOhno __final {
6367
}
6468

6569
private:
70+
bool nonPolarizable_;
6671
bool built_;
6772
utils::MMFQ mmfq_;
6873
/*! D_\lambda matrix, not symmetry blocked */

src/utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ list(APPEND headers_list
1818
Logger.hpp
1919
LoggerImpl.hpp
2020
MathUtils.hpp
21+
MMFQ.hpp
2122
Molecule.hpp
2223
QuadratureRules.hpp
2324
Solvent.hpp

tests/mmfq/CMakeLists.txt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
add_library(mmfq-tests OBJECT mmfq-ohno.cpp)
2-
if(BUILD_CUSTOM_BOOST)
3-
add_dependencies(mmfq-tests custom_boost)
4-
endif()
5-
6-
# Copy reference files to ${PROJECT_BINARY_DIR}/tests/mmfq (aka ${CMAKE_CURRENT_BINARY_DIR})
7-
list(APPEND reference_files FQ-2xH2O.npy)
8-
file(COPY ${reference_files} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
9-
10-
# mmfq.cpp test
11-
add_Catch_test(mmfq-ohno "mmfq;ohno")
1+
target_sources(unit_tests
2+
PRIVATE
3+
${CMAKE_CURRENT_SOURCE_DIR}/mmfq-ohno.cpp
4+
)
125

6+
add_Catch_test(
7+
NAME
8+
mmfq-ohno
9+
LABELS
10+
mmfq
11+
ohno
12+
REFERENCE_FILES
13+
FQ-2xH2O.npy
14+
)

tools/pcmparser.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ def setup_keywords():
362362
# Set a classical fluctuating charge force field
363363
# No additional spheres will be generated.
364364
mmfq = Section('MMFQ', callback = verify_mmfq)
365+
# Valid values: boolean
366+
# Default: False
367+
mmfq.add_kw('NONPOLARIZABLE', 'BOOL', False)
365368
# Valid values: integer
366369
mmfq.add_kw('SITESPERFRAGMENT', 'INT', 3)
367370
# FQ force field
@@ -583,6 +586,7 @@ def verify_mmfq(section):
583586
print('Empty or incoherent SITES array')
584587
sys.exit(1)
585588

589+
586590
def verify_spheres(keyword):
587591
length = len(keyword.get())
588592
if (length % 4 != 0):

0 commit comments

Comments
 (0)