16 #define MIN_DEBUG_LEVEL 1
25 #include "ComputeQMMgr.decl.h"
30 #include "ComputeMgr.decl.h"
40 #include "ComputePmeMgr.decl.h"
45 #if defined(WIN32) && !defined(__CYGWIN__)
47 #define mkdir(X,Y) _mkdir(X)
48 #define S_ISDIR(X) ((X) & S_IFDIR)
52 #define SQRT_PI 1.7724538509055160273
58 #define QMPCSCHEMENONE 1
59 #define QMPCSCHEMEROUND 2
60 #define QMPCSCHEMEZERO 3
62 #define QMPCSCALESHIFT 1
63 #define QMPCSCALESWITCH 2
75 Real qmInit,
int hiInit,
int newvdwType) {
99 #define PCMODEUPDATESEL 1
100 #define PCMODEUPDATEPOS 2
101 #define PCMODECUSTOMSEL 3
137 Real qmInit,
int hiInit,
Real newDist,
138 Mass newM,
int newvdwType) {
160 return (
id < ref.
id);
163 return (
id == ref.
id) ;
195 # define QMATOMTYPE_DUMMY 0
196 # define QMATOMTYPE_QM 1
197 # define QMPCTYPE_IGNORE 0
198 # define QMPCTYPE_CLASSICAL 1
199 # define QMPCTYPE_EXTRA 2
202 #define QMLSSCLASSICALRES 2
231 return !(*
this == ref);
275 bool returnVal =
true;
306 int bountToIndxInit,
int newType,
307 char *elementInit,
Real newDist) {
313 strncpy(
element,elementInit,3);
369 static char tmp_string[25];
370 const double maxnum = 9999999999.9999;
371 if ( X > maxnum ) X = maxnum;
372 if ( X < -maxnum ) X = -maxnum;
373 sprintf(tmp_string,
" %14.4f",X);
379 static char tmp_string[25];
380 sprintf(tmp_string,
" %14s",X);
386 static char tmp_string[21];
387 sprintf(tmp_string,
"QMENERGY: %7d",X);
398 typedef std::vector<ComputeQMPntChrg>
QMPCVec ;
430 ComputeQMMgr_SDAG_CODE
432 CProxy_ComputeQMMgr QMProxy;
436 int numArrivedQMMsg, numArrivedPntChrgMsg, numRecQMRes;
440 std::vector<int> qmPEs ;
474 Real *grpChrg, *grpMult;
504 int dcdOutFile, dcdPosOutFile;
508 void procBonds(
int numBonds,
509 const int *
const qmGrpBondsGrp,
510 const int *
const qmMMBondedIndxGrp,
511 const int *
const *
const chargeTarget,
512 const int *
const numTargs,
519 void lssUpdate(
int grpIter,
QMAtmVec &grpQMAtmVec,
QMPCVec &grpPntChrgVec);
521 void calcCSMD(
int grpIndx,
int numQMAtoms,
const QMAtomData *atmP,
Force *resForce) ;
524 int cSMDnumInstances, cSMDInitGuides;
526 int const *
const * cSMDindex;
528 int const * cSMDindxLen;
532 int const *
const * cSMDpairs;
536 Real const * cSMDVels;
538 Real const * cSMDcoffs;
543 void Write_PDB(std::string Filename,
const QMGrpCalcMsg *dataMsg);
544 void Write_PDB(std::string Filename,
const QMCoordMsg *dataMsg);
549 QMProxy(thisgroup), QMCompute(0), numSources(0), numArrivedQMMsg(0),
550 numArrivedPntChrgMsg(0), numRecQMRes(0), qmCoordMsgs(0), pntChrgCoordMsgs(0),
551 qmCoord(0), force(0), numAtoms(0), dcdOutFile(0), outputData(0), pcIDListSize(0) {
553 CkpvAccess(BOCclass_group).computeQMMgr = thisgroup;
559 if (qmCoordMsgs != 0) {
560 for (
int i=0; i<numSources; ++i ) {
561 if (qmCoordMsgs[i] != 0)
562 delete qmCoordMsgs[i];
564 delete [] qmCoordMsgs;
567 if (pntChrgCoordMsgs != 0) {
568 for (
int i=0; i<numSources; ++i ) {
569 if (pntChrgCoordMsgs[i] != 0)
570 delete pntChrgCoordMsgs[i];
572 delete [] pntChrgCoordMsgs;
585 if (dcdPosOutFile != 0)
589 delete [] outputData;
602 CProxy_ComputeQMMgr::ckLocalBranch(
603 CkpvAccess(BOCclass_group).computeQMMgr)->setCompute(
this);
631 for (
int i=0; i<meNumMMIndx; i++)
642 cutoff = simParams->
cutoff;
647 customPCLists.
resize(numQMGrps);
653 int minI = 0, maxI = 0, grpIter = 0;
655 while (grpIter < numQMGrps) {
657 maxI += custPCSizes[grpIter];
659 for (
size_t i=minI; i < maxI; i++) {
661 customPCLists[grpIter].
add( customPCIdxs[i] ) ;
665 minI += custPCSizes[grpIter];
677 CProxy_ComputeQMMgr QMProxy(CkpvAccess(BOCclass_group).computeQMMgr);
684 DebugM(4,
"----> Initiating QM work on rank " << CkMyPe() <<
691 int numLocalQMAtoms = 0, localMM1atoms = 0;
692 for (ap = ap.
begin(); ap != ap.
end(); ap++) {
694 int localNumAtoms = (*ap).p->getNumAtoms();
697 (*ap).positionBox->open(),
700 for(
int i=0; i<localNumAtoms; ++i) {
701 if ( qmAtomGroup[xExt[i].
id] > 0 ) {
704 else if (meNumMMIndx > 0) {
718 timeStep = (*ap).p->flags.step ;
721 DebugM(4,
"Node " << CkMyPe() <<
" has " << numLocalQMAtoms
722 <<
" QM atoms." << std::endl) ;
724 if (localMM1atoms > 0)
725 DebugM(4,
"Node " << CkMyPe() <<
" has " << localMM1atoms
726 <<
" MM1 atoms." << std::endl) ;
733 msg->
numAtoms = numLocalQMAtoms + localMM1atoms;
740 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
743 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
744 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
745 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
747 for(
int i=0; i<localNumAtoms; ++i) {
749 if ( qmAtomGroup[xExt[i].
id] > 0 ) {
753 for (
int qi=0; qi<numQMAtms; qi++) {
754 if (qmAtmIndx[qi] == xExt[i].
id) {
755 charge = qmAtmChrg[qi];
761 fullAtms[i].transform) ;
764 data_ptr->
id = xExt[i].
id;
765 data_ptr->
qmGrpID = qmAtomGroup[xExt[i].
id] ;
771 else if (meNumMMIndx > 0) {
780 DebugM(3,
"Found atom " << retIt->mmIndx <<
"," << retIt->qmGrp <<
"\n" );
783 fullAtms[i].transform) ;
787 data_ptr->
id = xExt[i].
id;
788 data_ptr->
qmGrpID = retIt->qmGrp ;
807 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
809 (*pdIt).posBoxP->close(&x);
813 QMProxy[0].recvPartQM(msg);
822 if ( ! numSources ) {
823 DebugM(4,
"Initializing ComputeQMMgr variables." << std::endl);
826 DebugM(4,
"There are " << numSources <<
" nodes with patches." << std::endl);
828 for (
int i=0; i<numSources; ++i ) {
834 DebugM(4,
"Getting data from molecule and simParameters." << std::endl);
845 noPC = simParams->
qmNoPC ;
847 if (noPC && meNumMMIndx == 0) {
848 pntChrgCoordMsgs = NULL;
852 for (
int i=0; i<numSources; ++i ) {
853 pntChrgCoordMsgs[i] = 0;
858 resendPCList =
false;
882 numArrivedQMMsg = 0 ;
883 numArrivedPntChrgMsg = 0 ;
906 cSMDguides =
new Position[cSMDnumInstances];
907 cSMDForces =
new Force[cSMDnumInstances];
911 DebugM(4,
"Initializing DCD file for charge information." << std::endl);
915 std::string dcdOutFileStr;
916 dcdOutFileStr.clear();
918 dcdOutFileStr.append(
".qdcd") ;
922 iout <<
iERROR <<
"DCD file " << dcdOutFile <<
" already exists!!\n" <<
endi;
923 NAMD_err(
"Could not write QM charge DCD file.");
924 }
else if (dcdOutFile < 0) {
925 iout <<
iERROR <<
"Couldn't open DCD file " << dcdOutFile <<
".\n" <<
endi;
926 NAMD_err(
"Could not write QM charge DCD file.");
927 }
else if (! dcdOutFile) {
928 NAMD_bug(
"ComputeQMMgr::recvPartQM open_dcd_write returned fileid of zero");
933 int NSAVC, NFILE, NPRIV, NSTEP;
936 NSTEP = NPRIV - NSAVC;
941 numQMAtms, NFILE, NPRIV, NSAVC, NSTEP,
945 NAMD_err(
"Writing of DCD header failed!!");
950 outputData =
new Real[3*numQMAtms];
953 DebugM(4,
"Initializing DCD file for position information." << std::endl);
956 std::string dcdPosOutFileStr;
957 dcdPosOutFileStr.clear();
959 dcdPosOutFileStr.append(
".QMonly.dcd") ;
963 iout <<
iERROR <<
"DCD file " << dcdPosOutFile <<
" already exists!!\n" <<
endi;
964 NAMD_err(
"Could not write QM charge DCD file.");
965 }
else if (dcdPosOutFile < 0) {
966 iout <<
iERROR <<
"Couldn't open DCD file " << dcdPosOutFile <<
".\n" <<
endi;
967 NAMD_err(
"Could not write QM charge DCD file.");
968 }
else if (! dcdPosOutFile) {
969 NAMD_bug(
"ComputeQMMgr::recvPartQM open_dcd_write returned fileid of zero");
974 int NSAVC, NFILE, NPRIV, NSTEP;
977 NSTEP = NPRIV - NSAVC;
981 int ret_code =
write_dcdheader(dcdPosOutFile, dcdPosOutFileStr.c_str(),
982 numQMAtms, NFILE, NPRIV, NSAVC, NSTEP,
986 NAMD_err(
"Writing of DCD header failed!!");
991 outputData =
new Real[3*numQMAtms];
996 int zeroNodeSize = CmiNumPesOnPhysicalNode(0);
999 if ( zeroNodeSize < simsPerNode ) {
1000 iout <<
iERROR <<
"There are " << zeroNodeSize <<
" cores pernode, but "
1001 << simsPerNode <<
" QM simulations per node were requested.\n" <<
endi ;
1002 NAMD_die(
"Error preparing QM simulations.");
1005 DebugM(4,
"Preparing PE list for QM execution.\n");
1008 int numNodes = CmiNumPhysicalNodes();
1009 int numPlacedQMGrps = 0;
1010 int placedOnNode = 0;
1014 if ( simsPerNode <= 0 ) {
1016 numPlacedQMGrps = 1;
1019 while ( (numPlacedQMGrps < numQMGrps) && (simsPerNode > 0) ) {
1022 if (nodeIt == numNodes) {
1028 CmiGetPesOnPhysicalNode(CmiPhysicalNodeID(nodeIt), &pelist, &nodeSize);
1030 DebugM(4,
"Checking node " << nodeIt +1 <<
" out of " << numNodes
1031 <<
" (" << nodeSize <<
" PEs: " << pelist[0] <<
" to "
1032 << pelist[nodeSize-1] <<
")." << std::endl );
1034 for (
int i=0; i<nodeSize; ++i ) {
1038 DebugM(1,
"PE " << pelist[i] <<
" has no patches! We'll skip it."
1045 qmPEs.push_back(pelist[i]);
1047 DebugM(1,
"Added PE to QM execution list: " << pelist[i] <<
"\n");
1052 if (placedOnNode == simsPerNode) {
1053 DebugM(1,
"Placed enought simulations on this node.\n");
1064 if ( numPlacedQMGrps < numQMGrps ) {
1065 iout <<
iWARN <<
"Could not compute all QM groups in parallel.\n" <<
endi ;
1068 iout <<
iINFO <<
"List of ranks running QM simulations: " << qmPEs[0] ;
1069 for (
int i=1; i < qmPEs.size(); i++) {
1070 iout <<
", " << qmPEs[i] ;
1077 <<
" a total of " << msg->
numAtoms <<
" QM atoms." << std::endl);
1081 if (meNumMMIndx > 0) {
1086 for (
int i=0; i<msg->
numAtoms; i++) {
1087 if (data_ptr[i].vdwType < 0) {
1088 tmpAtm.
add(data_ptr[i]) ;
1099 if (tmpAtm.
size() > 0) {
1107 for (
int i=0; i<msg->
numAtoms; i++) {
1108 if (data_ptr[i].vdwType < 0) {
1111 newPCData->
id = data_ptr[i].
id ;
1114 newPCData->
dist = 0 ;
1115 newPCData->
mass = 0 ;
1120 *newMsgData = data_ptr[i] ;
1129 qmCoordMsgs[numArrivedQMMsg] = newMsg;
1132 pntChrgCoordMsgs[numArrivedPntChrgMsg] = pntChrgMsg;
1133 ++numArrivedPntChrgMsg;
1136 qmCoordMsgs[numArrivedQMMsg] = msg;
1140 if ( numArrivedQMMsg < numSources )
1144 for (
int msgIt=0; msgIt < numArrivedQMMsg; msgIt++){
1146 DebugM(1,
"Getting positions for " << qmCoordMsgs[msgIt]->numAtoms
1147 <<
" QM atoms in this message." << std::endl);
1149 for (
int i=0; i < qmCoordMsgs[msgIt]->
numAtoms; ++i ) {
1150 qmCoord[qmAtmIter] = qmCoordMsgs[msgIt]->
coord[i];
1155 if (qmAtmIter != numQMAtms) {
1156 iout <<
iERROR <<
"The number of QM atoms received (" << qmAtmIter
1157 <<
") is different than expected: " << numQMAtms <<
"\n" <<
endi;
1158 NAMD_err(
"Problems broadcasting QM atoms.");
1162 numArrivedQMMsg = 0;
1165 timeStep = qmCoordMsgs[0]->
timestep;
1170 for (
int i=0; i<numAtoms; ++i ) {
1179 for (
int i=0; i<numQMAtms; i++) {
1182 if (force[qmCoord[i].
id].homeIndx != -1
1183 && force[qmCoord[i].
id].homeIndx != qmCoord[i].homeIndx
1186 << qmCoord[i].
id <<
"; home index: "
1189 NAMD_die(
"Error preparing QM simulations.");
1196 force[qmCoord[i].
id].
replace = replaceForces;
1205 QMProxy[0].recvPntChrg(pntChrgMsg);
1211 int msgPCListSize = 0;
1213 if ( qmPCFreq > 0 ) {
1214 if (timeStep % qmPCFreq == 0) {
1218 resendPCList =
true;
1236 msgPCListSize = pcIDListSize;
1237 resendPCList =
false;
1246 DebugM(1,
"Broadcasting current positions of QM atoms.\n");
1247 for (
int j=0; j < numSources; ++j ) {
1255 int *msgPCListP = qmFullMsg->
pcIndxs;
1257 for (
int i=0; i<numQMAtms; i++) {
1260 data_ptr->
id = qmCoord[i].
id;
1266 for (
int i=0; i<msgPCListSize; i++) {
1267 msgPCListP[i] = pcIDList[i] ;
1272 Write_PDB(
"qmMsg.pdb", qmFullMsg) ;
1276 QMProxy[qmCoordMsgs[j]->
sourceNode].recvFullQM(qmFullMsg);
1283 if (subsArray.
size() > 0)
1289 typedef std::map<Real, std::pair<Position,BigReal> >
GrpDistMap ;
1311 DebugM(4,
"Rank " << CkMyPe() <<
" receiving from rank " << qmFullMsg->
sourceNode
1312 <<
" a total of " << qmFullMsg->
numAtoms <<
" QM atoms and "
1313 << qmFullMsg->
numPCIndxs <<
" PC IDs." << std::endl);
1320 pcIDSortList.
clear();
1322 int *pcIndx = qmFullMsg->
pcIndxs;
1323 for (
int i=0; i< qmFullMsg->
numPCIndxs;i++) {
1324 pcIDSortList.
load(pcIndx[i]);
1327 pcIDSortList.
sort();
1330 int totalNodeAtoms = 0;
1332 int uniqueCounter = 0;
1341 DebugM(4,
"Updating PC selection.\n")
1345 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
1348 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
1349 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
1350 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
1352 totalNodeAtoms += localNumAtoms;
1355 for(
int i=0; i<localNumAtoms; ++i) {
1360 Real pcGrpID = qmAtomGroup[xExt[i].
id];
1368 for (
int qi=0; qi<numQMAtms; qi++) {
1369 if (qmAtmIndx[qi] == xExt[i].
id) {
1370 charge = qmAtmChrg[qi];
1376 qmDataPtn = qmFullMsg->
coord;
1377 for(
int j=0; j<qmFullMsg->
numAtoms; j++, ++qmDataPtn) {
1390 if (qmGrpID == pcGrpID) {
1399 if ( dist < cutoff ){
1406 auto ret = chrgGrpMap.find(qmGrpID) ;
1414 if ( ret == chrgGrpMap.end()) {
1415 chrgGrpMap.insert(std::pair<Real,PosDistPair>(qmGrpID,
1423 if (dist < ret->second.second) {
1424 ret->second.first = posMM ;
1425 ret->second.second = dist ;
1431 for(
auto mapIt = chrgGrpMap.begin();
1432 mapIt != chrgGrpMap.end(); mapIt++) {
1439 mapIt->first, atomIter, mapIt->second.second,
1446 if (chrgGrpMap.size() > 0)
1452 (*pdIt).posBoxP->close(&x);
1460 DebugM(4,
"Updating PC positions ONLY.\n")
1462 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
1465 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
1466 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
1467 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
1469 totalNodeAtoms += localNumAtoms;
1472 for(
int i=0; i<localNumAtoms; ++i) {
1474 if (pcIDSortList.
find(xExt[i].
id) != NULL ) {
1479 bool firstIngroupQM =
true;
1480 qmDataPtn = qmFullMsg->
coord;
1481 for(
int j=0; j<qmFullMsg->
numAtoms; j++, ++qmDataPtn) {
1495 if ( firstIngroupQM ) {
1501 firstIngroupQM =
false;
1506 if ( r12.
length() < dist ) {
1508 posMM = qmDataPtn->
position + r12 ;
1513 Real pcGrpID = qmAtomGroup[xExt[i].
id];
1520 for (
int qi=0; qi<numQMAtms; qi++) {
1521 if (qmAtmIndx[qi] == xExt[i].
id) {
1522 charge = qmAtmChrg[qi];
1532 fullAtms[i].mass, fullAtms[i].vdwType));
1538 (*pdIt).posBoxP->close(&x);
1545 DebugM(4,
"Updating PC positions for custom PC selection.\n")
1547 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
1550 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
1551 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
1552 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
1554 totalNodeAtoms += localNumAtoms;
1557 for(
int i=0; i<localNumAtoms; ++i) {
1563 for (
int grpIndx=0; grpIndx<numQMGrps; grpIndx++) {
1565 if (customPCLists[grpIndx].find(xExt[i].
id) != NULL){
1577 bool firstIngroupQM =
true;
1578 qmDataPtn = qmFullMsg->
coord;
1579 for(
int j=0; j<qmFullMsg->
numAtoms; j++, ++qmDataPtn) {
1583 if ( qmDataPtn->
qmGrpID != qmGrpIDArray[grpIndx] )
continue;
1590 if ( firstIngroupQM ) {
1596 firstIngroupQM =
false;
1601 if ( r12.
length() < dist ) {
1603 posMM = qmDataPtn->
position + r12 ;
1609 Real pcGrpID = qmAtomGroup[xExt[i].
id];
1616 for (
int qi=0; qi<numQMAtms; qi++) {
1617 if (qmAtmIndx[qi] == xExt[i].
id) {
1618 charge = qmAtmChrg[qi];
1626 qmGrpIDArray[grpIndx], atomIter, dist,
1627 fullAtms[i].mass, fullAtms[i].vdwType));
1635 (*pdIt).posBoxP->close(&x);
1641 DebugM(4,
"Rank " << CkMyPe() <<
" found a total of " << compPCVec.
size()
1642 <<
" point charges, out of " << totalNodeAtoms
1643 <<
" atoms in this node. " << uniqueCounter <<
" are unique." << std::endl);
1650 pntChrgMsg->numAtoms = compPCVec.
size();
1652 for (
int i=0; i<compPCVec.
size(); i++ ) {
1658 pntChrgMsg->coord[i] = compPCVec[i] ;
1662 DebugM(4,
"Rank " << pntChrgMsg->sourceNode <<
" sending a total of "
1663 << compPCVec.
size() <<
" elements to rank zero." << std::endl);
1665 CProxy_ComputeQMMgr QMProxy(CkpvAccess(BOCclass_group).computeQMMgr);
1666 QMProxy[0].recvPntChrg(pntChrgMsg);
1673 void ComputeQMMgr::procBonds(
int numBonds,
1674 const int *
const qmGrpBondsGrp,
1675 const int *
const qmMMBondedIndxGrp,
1676 const int *
const *
const chargeTarget,
1677 const int *
const numTargs,
1681 DebugM(1,
"Processing QM-MM bonds in rank zero.\n");
1684 std::map<int, int> mmPntChrgMap ;
1689 for (
size_t i=0; i<grpPntChrgVec.size(); i++) {
1691 mmPntChrgMap.insert(std::pair<int,int>(grpPntChrgVec[i].
id, (
int) i) );
1693 grpAppldChrgVec.push_back( grpPntChrgVec[i] ) ;
1700 for (
int bondIt = 0; bondIt < numBonds; bondIt++) {
1703 int bondIndx = qmGrpBondsGrp[bondIt] ;
1705 auto retIt = mmPntChrgMap.find(qmMMBondedIndxGrp[bondIt]) ;
1709 if (retIt == mmPntChrgMap.end()) {
1712 iout <<
iERROR <<
"The MM atom " << qmMMBondedIndxGrp[bondIt]
1713 <<
" is bound to a QM atom, but it was not selected as a poitn charge."
1714 <<
" Check your cutoff radius!\n" <<
endi ;
1716 NAMD_die(
"Charge placement error in QM-MM bond.");
1720 int mmIndex = (*retIt).second;
1722 Position mmPos = grpAppldChrgVec[mmIndex].position ;
1723 BigReal mmCharge = grpAppldChrgVec[mmIndex].charge/numTargs[bondIndx] ;
1726 for (
int i=0; i<numTargs[bondIndx]; i++){
1728 int targetIndxGLobal = chargeTarget[bondIndx][i] ;
1730 retIt = mmPntChrgMap.find(targetIndxGLobal);
1734 if (retIt == mmPntChrgMap.end()) {
1736 iout <<
iERROR <<
"The MM atom " << targetIndxGLobal
1737 <<
" is bound to the MM atom of a QM-MM bond and is needed for"
1738 <<
" the required bond scheme"
1739 <<
" but it was not selected as a poitn charge."
1740 <<
" Check your cutoff radius!\n" <<
endi ;
1742 NAMD_die(
"Charge placement error in QM-MM bond.");
1745 int trgIndxLocal = (*retIt).second;
1769 Position trgPos = grpAppldChrgVec[trgIndxLocal].position ;
1773 grpAppldChrgVec[trgIndxLocal].qmGrpID = -2;
1774 grpAppldChrgVec[trgIndxLocal].homeIndx = mmIndex;
1783 grpAppldChrgVec.push_back(
1789 Vector bondVec = trgPos - mmPos ;
1795 Vector bondVec1 = bondVec*Cqp ;
1796 Vector bondVec2 = bondVec*Cqm ;
1798 Position chrgPos1 = mmPos + bondVec1;
1799 Position chrgPos2 = mmPos + bondVec2;
1802 BigReal trgChrg2 = -1*mmCharge;
1804 grpAppldChrgVec.push_back(
1808 grpAppldChrgVec.push_back(
1834 Position trgPos = grpAppldChrgVec[trgIndxLocal].position ;
1838 grpAppldChrgVec[trgIndxLocal].qmGrpID = -2;
1839 grpAppldChrgVec[trgIndxLocal].homeIndx = mmIndex;
1848 grpAppldChrgVec.push_back(
1854 Vector bondVec = trgPos - mmPos ;
1858 Vector bondVec1 = bondVec*Cq1 ;
1860 Position chrgPos1 = mmPos + bondVec1;
1862 BigReal trgChrg1 = 2*mmCharge;
1864 grpAppldChrgVec.push_back(
1892 grpAppldChrgVec[trgIndxLocal].charge = 0.0;
1903 grpAppldChrgVec[mmIndex].qmGrpID = -1 ;
1921 pntChrgCoordMsgs[numArrivedPntChrgMsg] = msg;
1922 ++numArrivedPntChrgMsg;
1924 if ( numArrivedPntChrgMsg < numSources )
1933 for (
int k=0; k<3; ++k )
1934 for (
int l=0; l<3; ++l )
1935 totVirial[k][l] = 0;
1939 const char *
const *
const elementArray = molPtr->
get_qmElements() ;
1945 const int *
const *
const qmMMBond = molPtr->
get_qmMMBond() ;
1955 if ( qmPCFreq > 0 ) {
1956 DebugM(4,
"Using point charge stride of " << qmPCFreq <<
"\n")
1961 if (timeStep % qmPCFreq == 0) {
1962 DebugM(4,
"Loading a new selection of PCs.\n")
1965 pntChrgMsgVec.clear();
1966 for (
int pcMsgIt=0; pcMsgIt < numArrivedPntChrgMsg; pcMsgIt++) {
1968 for (
int i=0; i < pntChrgCoordMsgs[pcMsgIt]->
numAtoms; ++i ) {
1969 pntChrgMsgVec.push_back(pntChrgCoordMsgs[pcMsgIt]->coord[i]);
1975 pcIDListSize = pntChrgMsgVec.size();
1976 pcIDList =
new int[pcIDListSize] ;
1977 for (
size_t i=0; i<pcIDListSize; i++) {
1978 pcIDList[i] = pntChrgMsgVec[i].id;
1983 force[pntChrgMsgVec[i].id].
homeIndx = pntChrgMsgVec[i].homeIndx;
1987 DebugM(4,
"Updating position/homeIdex of old PC selection.\n")
1993 for (
int pcMsgIt=0; pcMsgIt < numArrivedPntChrgMsg; pcMsgIt++) {
1995 for (
int i=0; i < pntChrgCoordMsgs[pcMsgIt]->
numAtoms; ++i ) {
1996 pcDataSort.
load(pntChrgCoordMsgs[pcMsgIt]->coord[i]);
2001 iout <<
"Loaded new positions in sorted array: " << pcDataSort.
size() <<
"\n" <<
endi;
2005 for (
size_t i=0; i<pntChrgMsgVec.size(); i++) {
2007 auto pntr = pcDataSort.
find(pntChrgMsgVec[i]);
2009 pntChrgMsgVec[i].position = pntr->position ;
2010 pntChrgMsgVec[i].homeIndx = pntr->homeIndx ;
2015 force[pntChrgMsgVec[i].id].
homeIndx = pntChrgMsgVec[i].homeIndx;
2020 DebugM(4,
"Updating PCs at every step.\n")
2022 pntChrgMsgVec.clear();
2023 for (
int pcMsgIt=0; pcMsgIt < numArrivedPntChrgMsg; pcMsgIt++) {
2025 for (
int i=0; i < pntChrgCoordMsgs[pcMsgIt]->
numAtoms; ++i ) {
2026 pntChrgMsgVec.push_back(pntChrgCoordMsgs[pcMsgIt]->coord[i]);
2031 for (
size_t i=0; i<pntChrgMsgVec.size(); i++) {
2036 if (force[pntChrgMsgVec[i].
id].homeIndx != -1
2037 and force[pntChrgMsgVec[i].
id].homeIndx != pntChrgMsgVec[i].homeIndx
2039 iout <<
iERROR <<
"Overloading point charge "
2040 << pntChrgMsgVec[i].id <<
"; home index: "
2041 << force[pntChrgMsgVec[i].id].
homeIndx <<
" with " << pntChrgMsgVec[i].homeIndx
2043 NAMD_die(
"Error preparing QM simulations.");
2047 force[pntChrgMsgVec[i].id].
homeIndx = pntChrgMsgVec[i].homeIndx;
2052 numArrivedPntChrgMsg = 0;
2054 DebugM(4,
"A total of " << pntChrgMsgVec.size()
2055 <<
" point charges arrived." << std::endl);
2057 DebugM(4,
"Starting QM groups processing.\n");
2068 std::vector<dummyData> dummyAtoms ;
2071 thisProxy[0].recvQMResLoop() ;
2076 for (
int grpIter = 0; grpIter < numQMGrps; grpIter++) {
2078 grpQMAtmVec.clear();
2079 grpPntChrgVec.clear();
2080 grpAppldChrgVec.clear();
2083 DebugM(4,
"Calculating QM group " << grpIter +1
2084 <<
" (ID: " << grpID[grpIter] <<
")." << std::endl);
2086 DebugM(4,
"Compiling Config Lines into one string for message...\n");
2090 std::string configLines ;
2092 for ( ; current; current = current->
next ) {
2093 std::string confLineStr(current->
data);
2097 std::ostringstream itosConv ;
2098 itosConv << grpChrg[grpIter] ;
2099 confLineStr.append(
" CHARGE=" );
2100 confLineStr.append( itosConv.str() );
2104 configLines.append(confLineStr);
2105 configLines.append(
"\n");
2110 DebugM(4,
"Determining point charges...\n");
2112 Real qmTotalCharge = 0;
2114 for (
int qmIt=0; qmIt<numQMAtms; qmIt++){
2115 if (qmCoord[qmIt].qmGrpID == grpID[grpIter]) {
2116 grpQMAtmVec.push_back(qmCoord[qmIt]);
2117 qmTotalCharge += qmCoord[qmIt].
charge;
2120 if ((fabsf(roundf(qmTotalCharge) - qmTotalCharge) <= 0.001f) ) {
2121 qmTotalCharge = roundf(qmTotalCharge) ;
2127 Real pcTotalCharge = 0;
2129 for (
auto pntChrgIt = pntChrgMsgVec.begin();
2130 pntChrgIt != pntChrgMsgVec.end(); pntChrgIt++) {
2131 if ((*pntChrgIt).qmGrpID == grpID[grpIter] ) {
2132 grpPntChrgVec.push_back( (*pntChrgIt) );
2133 pcTotalCharge += (*pntChrgIt).charge;
2136 if ((fabsf(roundf(pcTotalCharge) - pcTotalCharge) <= 0.001f) ) {
2137 pcTotalCharge = roundf(pcTotalCharge) ;
2141 if (grpQMAtmVec.size() != qmGrpSize[grpIter]) {
2142 iout <<
iERROR <<
"The number of QM atoms received for group " << grpID[grpIter]
2143 <<
" does not match the expected: " << grpQMAtmVec.size()
2144 <<
" vs " << qmGrpSize[grpIter] <<
"\n" <<
endi ;
2146 NAMD_die(
"Error processing QM group.");
2150 DebugM(1,
"Found " << grpPntChrgVec.size() <<
" point charges for QM group "
2151 << grpIter <<
" (ID: " << grpID[grpIter] <<
"; Num QM atoms: "
2152 << grpQMAtmVec.size() <<
"; Num QM-MM bonds: "
2153 << grpNumBonds[grpIter] <<
")" << std::endl);
2155 DebugM(1,
"Total QM charge: " << qmTotalCharge
2156 <<
"; Total point-charge charge: " << pcTotalCharge << std::endl);
2160 if ( qmLSSFreq > 0 && ((timeStep + 1) % qmLSSFreq == 0 )) {
2161 lssUpdate(grpIter, grpQMAtmVec, grpPntChrgVec);
2168 procBonds(grpNumBonds[grpIter], qmGrpBonds[grpIter],
2169 qmMMBondedIndx[grpIter],
2170 chargeTarget, numTargs,
2171 grpPntChrgVec, grpAppldChrgVec) ;
2174 grpAppldChrgVec = grpPntChrgVec;
2179 std::vector< std::pair<int,int> > qmPCLocalIndxPairs ;
2183 for (
int dummyIt = 0; dummyIt < grpNumBonds[grpIter]; dummyIt++) {
2185 int qmMMBondIndx = qmGrpBonds[grpIter][dummyIt] ;
2187 BigReal bondVal = dummyBondVal[qmMMBondIndx] ;
2189 int mmAtmIndx = qmMMBond[qmMMBondIndx][0] ;
2190 int qmAtmIndx = qmMMBond[qmMMBondIndx][1] ;
2196 bool missingQM =
true, missingMM =
true;
2199 for (qmIt=0; qmIt<grpQMAtmVec.size(); qmIt++){
2200 if (grpQMAtmVec[qmIt].
id == qmAtmIndx) {
2201 qmPos = grpQMAtmVec[qmIt].position;
2213 for (pcIt=0; pcIt < grpPntChrgVec.size(); pcIt++) {
2214 if (grpPntChrgVec[pcIt].
id == mmAtmIndx) {
2215 mmPos = grpPntChrgVec[pcIt].position ;
2225 qmPCLocalIndxPairs.push_back(std::pair<int,int>(qmIt, pcIt) );
2230 if ( missingMM or missingQM ) {
2234 iout <<
iERROR <<
"The MM atom " << mmAtmIndx
2235 <<
" is bound to a QM atom, but it was not selected as a poitn charge."
2236 <<
" Check your cutoff radius!\n" <<
endi ;
2238 NAMD_die(
"Error in QM-MM bond processing.");
2241 iout <<
iERROR <<
"The QM atom " << qmAtmIndx
2242 <<
" is bound to an MM atom, but it was not sent to rank zero for processing."
2243 <<
" Check your configuration!\n" <<
endi ;
2245 NAMD_die(
"Error in QM-MM bond processing.");
2250 Vector bondVec = mmPos - qmPos ;
2258 bondVec = bondVec.
unit() ;
2259 bondVec *= bondVal ;
2266 bondVec *= bondVal ;
2269 Position dummyPos = qmPos + bondVec;
2271 DebugM(1,
"Creating dummy atom " << dummyPos <<
" ; QM ind: "
2272 << qmIt <<
" ; PC ind: " << pcIt << std::endl);
2274 dummyAtoms.push_back(
dummyData(dummyPos, qmIt, qmMMBondIndx)) ;
2278 DebugM(3,
"Creating data for " << grpQMAtmVec.size() <<
" QM atoms "
2279 << dummyAtoms.size() <<
" dummy atoms " << grpPntChrgVec.size()
2280 <<
" real point charges and " << grpAppldChrgVec.size() - grpPntChrgVec.size()
2281 <<
" virtual point charges\n") ;
2283 int dataSize = grpQMAtmVec.size() + dummyAtoms.size() + grpAppldChrgVec.size();
2288 msg->
charge = grpChrg[grpIter];
2291 msg->
numAllAtoms = grpQMAtmVec.size() + dummyAtoms.size();
2319 for (
int i=0; i<grpQMAtmVec.size(); i++) {
2320 dataP->
position = grpQMAtmVec[i].position ;
2321 dataP->
charge = grpQMAtmVec[i].charge ;
2322 dataP->
id = grpQMAtmVec[i].id ;
2325 strncpy(dataP->
element,elementArray[grpQMAtmVec[i].id],3);
2329 for (
int i=0; i<dummyAtoms.size(); i++) {
2330 dataP->
position = dummyAtoms[i].pos ;
2335 strncpy(dataP->
element,dummyElmArray[dummyAtoms[i].bondIndx],3);
2339 for (
int i=0; i<grpAppldChrgVec.size(); i++) {
2340 dataP->
position = grpAppldChrgVec[i].position ;
2341 dataP->
charge = grpAppldChrgVec[i].charge ;
2343 dataP->
id = grpAppldChrgVec[i].id ;
2345 dataP->
dist = grpAppldChrgVec[i].dist ;
2349 if (i < grpPntChrgVec.size()) {
2350 if (grpAppldChrgVec[i].qmGrpID == -1) {
2353 else if (grpAppldChrgVec[i].qmGrpID == -2) {
2376 for(
auto vecPtr = qmPCLocalIndxPairs.begin();
2377 vecPtr != qmPCLocalIndxPairs.end();
2380 int qmLocInd = (*vecPtr).first;
2381 int pcLocInd = (*vecPtr).second;
2391 calcCSMD(grpIter, msg->
numQMAtoms, qmP, cSMDForces) ;
2393 int targetPE = qmPEs[peIter] ;
2395 DebugM(4,
"Sending QM group " << grpIter <<
" (ID " << grpID[grpIter]
2396 <<
") to PE " << targetPE << std::endl);
2402 QMProxy[targetPE].calcORCA(msg) ;
2406 QMProxy[targetPE].calcMOPAC(msg) ;
2410 QMProxy[targetPE].calcUSR(msg) ;
2416 if (peIter == qmPEs.size())
2446 for (
int k=0; k<3; ++k )
2447 for (
int l=0; l<3; ++l )
2448 totVirial[k][l] += resMsg->
virial[k][l];
2451 Real qmTotalCharge = 0;
2455 force[ fres[i].id ].
force += fres[i].force;
2458 if (fres[i].replace == 1) {
2459 force[ fres[i].id ].
charge = fres[i].charge;
2460 qmTotalCharge += fres[i].charge;
2464 if ((fabsf(roundf(qmTotalCharge) - qmTotalCharge) <= 0.001f) ) {
2465 qmTotalCharge = roundf(qmTotalCharge) ;
2470 for (
int i=0; i < cSMDindxLen[resMsg->
grpIndx]; i++ ) {
2471 int cSMDit = cSMDindex[resMsg->
grpIndx][i];
2472 force[ cSMDpairs[cSMDit][0] ].
force += cSMDForces[cSMDit];
2476 DebugM(4,
"QM total charge received is " << qmTotalCharge << std::endl);
2478 DebugM(4,
"Current accumulated energy is " << totalEnergy << std::endl);
2490 timeStep % simParams->
qmOutFreq == 0 ) {
2492 iout <<
iINFO <<
"Writing QM charge output at step "
2493 << timeStep <<
"\n" <<
endi;
2495 Real *
x = outputData,
2499 for (
int qmIt=0; qmIt<numQMAtms; qmIt++){
2500 x[qmIt] = qmCoord[qmIt].
id;
2501 y[qmIt] = force[qmCoord[qmIt].
id].
charge ;
2513 iout <<
iINFO <<
"Writing QM position output at step "
2514 << timeStep <<
"\n" <<
endi;
2518 for(
int i=0; i<numQMAtms;i++) {
2523 Real *
x = outputData,
2527 for (
int qmIt=0; qmIt<numQMAtms; qmIt++){
2528 x[qmIt] = qmCoord[idIndx[qmIt].indx].
position.
x;
2529 y[qmIt] = qmCoord[idIndx[qmIt].indx].
position.
y;
2530 z[qmIt] = qmCoord[idIndx[qmIt].indx].
position.
z;
2537 DebugM(4,
"Distributing QM forces for all ranks.\n");
2538 for (
int j=0; j < numSources; ++j ) {
2540 std::set<int> auxset0;
2541 DebugM(1,
"Sending forces and charges to source " << j << std::endl);
2547 int sourceNode = -1;
2549 if (pntChrgCoordMsgs == NULL) {
2551 qmmsg = qmCoordMsgs[j];
2559 pcmsg = pntChrgCoordMsgs[j];
2560 pntChrgCoordMsgs[j] = 0;
2567 for (
int aux=0; aux<numSources; aux++) {
2569 if (qmCoordMsgs[aux] == 0)
2572 qmmsg = qmCoordMsgs[aux];
2575 qmCoordMsgs[aux] = 0;
2580 DebugM(1,
"Building force mesage for rank "
2588 for (
int i=0; i < qmmsg->
numAtoms; ++i ) {
2589 auxset0.insert(qmmsg->
coord[i].
id);
2591 for (
int i=0; i < pcmsg->
numAtoms; ++i ) {
2592 auxset0.insert(pcmsg->
coord[i].
id);
2594 totForces = auxset0.size();
2602 DebugM(1,
"Loading QM forces.\n");
2607 for (
int i=0; i < qmmsg->
numAtoms; ++i ) {
2610 auxset0.insert(qmmsg->
coord[i].
id);
2615 if (pntChrgCoordMsgs != NULL) {
2616 DebugM(1,
"Loading PntChrg forces.\n");
2618 for (
int i=0; i < pcmsg->
numAtoms; ++i ) {
2620 if (auxset0.find(pcmsg->
coord[i].
id) == auxset0.end()) {
2623 auxset0.insert(pcmsg->
coord[i].
id);
2630 DebugM(1,
"A total of " << forceIter <<
" forces were loaded." << std::endl);
2632 for (
int i=0; i < subsArray.
size(); ++i ) {
2633 fmsg->
lssDat[i] = subsArray[i];
2637 if (subsArray.
size() > 0)
2638 DebugM(3,
"A total of " << subsArray.
size() <<
" LSS data structures were loaded." << std::endl);
2642 fmsg->
energy = totalEnergy;
2643 for (
int k=0; k<3; ++k )
2644 for (
int l=0; l<3; ++l )
2645 fmsg->
virial[k][l] = totVirial[k][l];
2648 for (
int k=0; k<3; ++k )
2649 for (
int l=0; l<3; ++l )
2653 DebugM(4,
"Sending forces...\n");
2655 QMProxy[sourceNode].recvForce(fmsg);
2659 DebugM(4,
"All forces sent from node zero.\n");
2677 bool callReplaceForces =
false;
2685 int totalNumbAtoms = 0;
2686 for (ap = ap.
begin(); ap != ap.
end(); ap++) {
2687 totalNumbAtoms += (*ap).p->getNumAtoms();
2697 delete [] oldForces;
2698 oldForces =
new ExtForce[totalNumbAtoms] ;
2700 for (
int i=0; i < totalNumbAtoms; ++i) {
2704 DebugM(1,
"Force array has been created and zeroed in rank "
2705 << CkMyPe() << std::endl);
2708 << CkMyPe() << std::endl);
2712 for (
int i=0; i < fmsg->
numForces; ++i, ++results_ptr) {
2719 if (results_ptr->
replace == 1)
2720 callReplaceForces =
true;
2724 if (qmAtomGroup[results_ptr->
id] > 0 && (fmsg->
PMEOn || (numQMGrps > 1) ) ) {
2727 for (
int qmIter=0; qmIter<numQMAtms; qmIter++) {
2729 if (qmAtmIndx[qmIter] == results_ptr->
id) {
2730 qmAtmChrg[qmIter] = results_ptr->
charge;
2740 DebugM(1,
"Placing forces on force boxes in rank "
2741 << CkMyPe() << std::endl);
2744 int homeIndxIter = 0;
2745 for (ap = ap.
begin(); ap != ap.
end(); ap++) {
2746 Results *r = (*ap).forceBox->open();
2748 const CompAtomExt *xExt = (*ap).p->getCompAtomExtInfo();
2749 int localNumAtoms = (*ap).p->getNumAtoms();
2751 for(
int i=0; i<localNumAtoms; ++i) {
2753 f[i] += oldForces[homeIndxIter].
force;
2758 if ( callReplaceForces )
2759 (*ap).p->replaceForces(oldForces);
2761 (*ap).forceBox->close(&r);
2765 DebugM(1,
"Forces placed on force boxes in rank "
2766 << CkMyPe() << std::endl);
2770 DebugM(1,
"PME ON! Accessing PMEmgr in rank " << CkMyPe() << std::endl);
2773 CkpvAccess(BOCclass_group).computePmeMgr) ;
2775 DebugM(4,
"Initiating ComputePme::doQMWork on rank " << CkMyPe() <<
" over "
2776 <<
getComputes(mgrP).size() <<
" pmeComputes." << std::endl) ;
2784 DebugM(1,
"Submitting reduction in rank " << CkMyPe() << std::endl);
2787 reduction->
item(REDUCTION_VIRIAL_NORMAL_XX) += fmsg->
virial[0][0];
2788 reduction->
item(REDUCTION_VIRIAL_NORMAL_XY) += fmsg->
virial[0][1];
2789 reduction->
item(REDUCTION_VIRIAL_NORMAL_XZ) += fmsg->
virial[0][2];
2790 reduction->
item(REDUCTION_VIRIAL_NORMAL_YX) += fmsg->
virial[1][0];
2791 reduction->
item(REDUCTION_VIRIAL_NORMAL_YY) += fmsg->
virial[1][1];
2792 reduction->
item(REDUCTION_VIRIAL_NORMAL_YZ) += fmsg->
virial[1][2];
2793 reduction->
item(REDUCTION_VIRIAL_NORMAL_ZX) += fmsg->
virial[2][0];
2794 reduction->
item(REDUCTION_VIRIAL_NORMAL_ZY) += fmsg->
virial[2][1];
2795 reduction->
item(REDUCTION_VIRIAL_NORMAL_ZZ) += fmsg->
virial[2][2];
2804 FILE *inputFile,*outputFile,*chrgFile;
2807 const size_t lineLen = 256;
2808 char *line =
new char[lineLen];
2810 std::string qmCommand, inputFileName, outputFileName, pntChrgFileName;
2817 DebugM(4,
"Running MOPAC on PE " << CkMyPe() << std::endl);
2832 pntChrgSwitching(msg, pcPpme) ;
2841 std::string baseDir(msg->
baseDir);
2842 std::ostringstream itosConv ;
2843 if ( CmiNumPartitions() > 1 ) {
2844 baseDir.append(
"/") ;
2845 itosConv << CmiMyPartition() ;
2846 baseDir += itosConv.str() ;
2850 if (stat(msg->
baseDir, &info) != 0 ) {
2851 CkPrintf(
"Node %d cannot access directory %s\n",
2852 CkMyPe(), baseDir.c_str() );
2853 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
2855 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
2856 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
2857 retVal = mkdir(baseDir.c_str(), S_IRWXU);
2861 baseDir.append(
"/") ;
2863 baseDir += itosConv.str() ;
2865 if (stat(msg->
baseDir, &info) != 0 ) {
2866 CkPrintf(
"Node %d cannot access directory %s\n",
2867 CkMyPe(), baseDir.c_str() );
2868 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
2870 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
2871 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
2872 retVal = mkdir(baseDir.c_str(), S_IRWXU);
2876 Write_PDB(std::string(baseDir)+
"/input.pdb", msg ) ;
2879 inputFileName.clear();
2880 inputFileName.append(baseDir.c_str()) ;
2881 inputFileName.append(
"/qmmm_") ;
2882 inputFileName += itosConv.str() ;
2883 inputFileName.append(
".input") ;
2886 inputFile = fopen(inputFileName.c_str(),
"w");
2887 if ( ! inputFile ) {
2888 iout <<
iERROR <<
"Could not open input file for writing: "
2889 << inputFileName <<
"\n" <<
endi ;
2890 NAMD_err(
"Error writing QM input file.");
2895 qmCommand.append(
"cd ");
2896 qmCommand.append(baseDir);
2897 qmCommand.append(
" ; ");
2899 qmCommand.append(
" ") ;
2900 qmCommand.append(inputFileName) ;
2901 qmCommand.append(
" > /dev/null 2>&1") ;
2905 outputFileName = inputFileName ;
2906 outputFileName.append(
".aux") ;
2910 pntChrgFileName.clear();
2911 pntChrgFileName.append(baseDir.c_str()) ;
2912 pntChrgFileName.append(
"/mol.in") ;
2914 chrgFile = fopen(pntChrgFileName.c_str(),
"w");
2916 iout <<
iERROR <<
"Could not open charge file for writing: "
2917 << pntChrgFileName <<
"\n" <<
endi ;
2918 NAMD_err(
"Error writing point charge file.");
2921 iret = fprintf(chrgFile,
"\n%d %d\n",
2923 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
2928 std::string confLineStr;
2929 while (std::getline(ss, confLineStr) ) {
2930 confLineStr.append(
"\n");
2931 iret = fprintf(inputFile,confLineStr.c_str());
2932 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
2936 iret = fprintf(inputFile,
"\n");
2937 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
2941 <<
" point charges in file " << pntChrgFileName.c_str() <<
"\n");
2945 for (
size_t i=0; i<msg->
numAllAtoms; ++i, ++atmP ) {
2951 iret = fprintf(inputFile,
"%s %f 1 %f 1 %f 1\n",
2953 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
2974 BigReal rij = sqrt((x-xMM)*(x-xMM) +
2983 phi = phi*constants ;
2985 iret = fprintf(chrgFile,
"%s %f %f %f %f\n",
2987 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
2991 DebugM(4,
"Closing input and charge file\n");
3000 std::string prepProc(msg->
prepProc) ;
3001 prepProc.append(
" ") ;
3002 prepProc.append(inputFileName) ;
3003 iret = system(prepProc.c_str());
3004 if ( iret == -1 ) {
NAMD_err(
"Error running preparation command for QM calculation."); }
3005 if ( iret ) {
NAMD_die(
"Error running preparation command for QM calculation."); }
3009 DebugM(4,
"Running command ->" << qmCommand.c_str() <<
"<-" << std::endl);
3010 iret = system(qmCommand.c_str());
3012 if ( iret == -1 ) {
NAMD_err(
"Error running command for QM forces calculation."); }
3013 if ( iret ) {
NAMD_die(
"Error running command for QM forces calculation."); }
3017 std::string secProc(msg->
secProc) ;
3018 secProc.append(
" ") ;
3019 secProc.append(inputFileName) ;
3023 secProc.append(
" ") ;
3024 secProc += itosConv.str() ;
3026 iret = system(secProc.c_str());
3027 if ( iret == -1 ) {
NAMD_err(
"Error running second command for QM calculation."); }
3028 if ( iret ) {
NAMD_die(
"Error running second command for QM calculation."); }
3040 DebugM(4,
"Reading QM data from file " << outputFileName.c_str() << std::endl);
3041 outputFile = fopen(outputFileName.c_str(),
"r");
3042 if ( ! outputFile ) {
3057 for (
int k=0; k<3; ++k )
3058 for (
int l=0; l<3; ++l )
3059 resMsg->
virial[k][l] = 0;
3065 resForce[i].force = 0;
3066 resForce[i].charge = 0 ;
3067 if (i < msg->numQMAtoms) {
3070 resForce[i].replace = 1 ;
3071 resForce[i].id = atmP->
id;
3077 resForce[i].replace = 0 ;
3078 resForce[i].
id = pcP->
id;
3090 size_t atmIndx = 0, gradCount = 0;
3091 Bool gradFields =
false, chargeFields =
false;
3092 Bool chargesRead =
false, gradsRead =
false;
3093 while ( fgets(line, lineLen, outputFile) != NULL){
3103 if ( strstr(line,
"HEAT_OF_FORMATION") != NULL ) {
3105 char strEnergy[14], *endPtr ;
3108 strncpy(strEnergy, line + 28, 13) ;
3109 strEnergy[13] =
'\0';
3113 resMsg->
energyOrig = strtod(strEnergy, &endPtr);
3114 if ( *endPtr ==
'D' ) {
3116 resMsg->
energyOrig = strtod(strEnergy, &endPtr);
3129 if ( strstr(line,
"ATOM_CHARGES") != NULL ) {
3131 chargeFields =
true;
3137 chargeFields =
false;
3141 chargeFields =
true;
3149 if ( strstr(line,
"GRADIENTS") != NULL ) {
3154 NAMD_die(
"Error reading QM forces file. Wrong number of atom charges");
3160 chargeFields = false ;
3168 if ( strstr(line,
"OVERLAP_MATRIX") != NULL ) {
3173 NAMD_die(
"Error reading QM forces file. Wrong number of gradients");
3186 while ((strIndx < (strlen(line)-9)) && (strlen(line)-1 >=9 ) ) {
3188 strncpy(result, line+strIndx,9) ;
3191 Real localCharge = atof(result);
3194 if (atmIndx < msg->numQMAtoms ) {
3195 atmP[atmIndx].
charge = localCharge;
3196 resForce[atmIndx].charge = localCharge;
3202 atmIndx < msg->numAllAtoms ) {
3205 atmP[atmIndx].
charge = localCharge;
3209 resForce[qmInd].charge += localCharge;
3218 chargeFields =
false;
3230 int numfirstline = sscanf(line,
"%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
3231 &buf[0],&buf[1],&buf[2],&buf[3],&buf[4],&buf[5],
3232 &buf[6],&buf[7],&buf[8],&buf[9]);
3233 gradLength = strlen(line)/numfirstline;
3235 while ((strIndx < (strlen(line)-gradLength)) && (strlen(line)-1 >= gradLength ) ) {
3237 strncpy(result, line+strIndx,gradLength) ;
3238 result[gradLength] =
'\0';
3240 gradient[gradCount] = atof(result);
3241 if (gradCount == 2) {
3243 if (atmIndx < msg->numQMAtoms ) {
3245 resForce[atmIndx].force.x = -1*gradient[0];
3246 resForce[atmIndx].force.y = -1*gradient[1];
3247 resForce[atmIndx].force.z = -1*gradient[2];
3256 atmIndx < msg->numAllAtoms ) {
3265 Real linkDist =
Vector(atmP[atmIndx].position -
3266 atmP[qmInd].position).
length() ;
3268 Force mmForce(0), qmForce(0),
3269 linkForce(gradient[0], gradient[1], gradient[2]);
3272 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
3274 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
3279 qmForce += (linkForce*((1 - linkDist/mmqmDist)*xuv +
3280 (xDelta)*base) )*xuv;
3282 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
3283 (yDelta)*base) )*yuv;
3285 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
3286 (zDelta)*base) )*zuv;
3289 mmForce += (linkForce*((linkDist/mmqmDist)*xuv -
3290 (xDelta)*base) )*xuv;
3292 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
3293 (yDelta)*base) )*yuv;
3295 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
3296 (zDelta)*base) )*zuv;
3298 resForce[qmInd].force += qmForce;
3299 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
3308 strIndx += gradLength;
3335 for (; atmIndx < msg->
numQMAtoms; atmIndx++) {
3338 for (
int qmIter=0; qmIter<globalNumQMAtoms; qmIter++) {
3340 if (qmAtmIndx[qmIter] == atmP[atmIndx].
id) {
3342 atmP[atmIndx].
charge = qmAtmChrg[qmIter];
3343 resForce[atmIndx].charge = qmAtmChrg[qmIter];
3351 for (
size_t j=msg->
numQMAtoms; j<msg->numAllAtoms; ++j ) {
3361 if (! (chargesRead && gradsRead) ) {
3362 NAMD_die(
"Error reading QM forces file. Not all data could be read!");
3383 std::vector<Force> qmElecForce ;
3385 qmElecForce.push_back(
Force(0) );
3397 Force totalForce(0);
3407 BigReal force = pntCharge*qmCharge*constants ;
3418 totalForce += force*rVec.
unit();
3421 qmElecForce[j] += -1*force*rVec.
unit();
3427 if (qmAtomGroup[pcP[i].
id] == 0) {
3430 resForce[pcIndx].force += totalForce;
3444 Force mm1Force = (1-Cq)*totalForce ;
3445 Force mm2Force = Cq*totalForce ;
3447 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
3448 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
3457 if (j < msg->numQMAtoms ) {
3458 resForce[j].force += qmElecForce[j];
3473 atmP[qmInd].position).
length() ;
3475 Force linkForce = qmElecForce[j];
3477 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
3479 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
3484 Force qmForce = (linkForce*((1 - linkDist/mmqmDist)*xuv +
3485 (xDelta)*base) )*xuv;
3487 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
3488 (yDelta)*base) )*yuv;
3490 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
3491 (zDelta)*base) )*zuv;
3494 Force mmForce = (linkForce*((linkDist/mmqmDist)*xuv -
3495 (xDelta)*base) )*xuv;
3497 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
3498 (yDelta)*base) )*yuv;
3500 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
3501 (zDelta)*base) )*zuv;
3503 resForce[qmInd].force += qmForce;
3504 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
3512 DebugM(1,
"Correcting forces and energy for PME.\n");
3515 BigReal TwoBySqrtPi = 1.12837916709551;
3516 pi_ewaldcof = TwoBySqrtPi * ewaldcof;
3523 const BigReal kq_i = p_i_charge * constants;
3525 for (
size_t j=i+1; j < msg->
numQMAtoms; j++) {
3536 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
3539 BigReal recip_energy = (1-tmp_b)/r;
3542 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
3545 BigReal energy = kq_i * p_j_charge * recip_energy ;
3547 Force fixForce = -1*kq_i*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
3558 resForce[i].force -= fixForce ;
3559 resForce[j].force -= -1*fixForce ;
3576 const BigReal kq_i = p_i_charge * constants;
3591 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
3594 BigReal recip_energy = (1-tmp_b)/r;
3597 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
3600 BigReal energy = kq_i * p_j_charge * recip_energy ;
3602 fixForce += -1*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
3613 resForce[pcIndx].force -= kq_i*fixForce ;
3623 for (
int k=0; k<3; ++k )
3624 for (
int l=0; l<3; ++l )
3625 resMsg->
virial[k][l] = -1*resForce[i].force[k]*atmP[i].
position[l];
3632 for (
int k=0; k<3; ++k )
3633 for (
int l=0; l<3; ++l )
3634 resMsg->
virial[k][l] = -1*resForce[pcIndx].force[k]*pcP[i].
position[l];
3640 QMProxy[0].recvQMRes(resMsg);
3652 FILE *inputFile,*outputFile,*chrgFile;
3655 const size_t lineLen = 256;
3656 char *line =
new char[lineLen];
3658 std::string qmCommand, inputFileName, outputFileName, pntChrgFileName, pcGradFilename;
3659 std::string tmpRedirectFileName, pcGradFileName;
3666 DebugM(4,
"Running ORCA on PE " << CkMyPe() << std::endl);
3680 pntChrgSwitching(msg, pcPpme) ;
3689 std::string baseDir(msg->
baseDir);
3690 std::ostringstream itosConv ;
3691 if ( CmiNumPartitions() > 1 ) {
3692 baseDir.append(
"/") ;
3693 itosConv << CmiMyPartition() ;
3694 baseDir += itosConv.str() ;
3698 if (stat(msg->
baseDir, &info) != 0 ) {
3699 CkPrintf(
"Node %d cannot access directory %s\n",
3700 CkMyPe(), baseDir.c_str() );
3701 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
3703 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
3704 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
3705 retVal = mkdir(baseDir.c_str(), S_IRWXU);
3709 baseDir.append(
"/") ;
3711 baseDir += itosConv.str() ;
3713 if (stat(msg->
baseDir, &info) != 0 ) {
3714 CkPrintf(
"Node %d cannot access directory %s\n",
3715 CkMyPe(), baseDir.c_str() );
3716 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
3718 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
3719 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
3720 int retVal = mkdir(baseDir.c_str(), S_IRWXU);
3724 Write_PDB(std::string(baseDir)+
"/input.pdb", msg ) ;
3727 inputFileName.clear();
3728 inputFileName.append(baseDir.c_str()) ;
3729 inputFileName.append(
"/qmmm_") ;
3730 inputFileName += itosConv.str() ;
3731 inputFileName.append(
".input") ;
3734 inputFile = fopen(inputFileName.c_str(),
"w");
3735 if ( ! inputFile ) {
3736 iout <<
iERROR <<
"Could not open input file for writing: "
3737 << inputFileName <<
"\n" <<
endi ;
3738 NAMD_err(
"Error writing QM input file.");
3743 qmCommand.append(
"cd ");
3744 qmCommand.append(baseDir);
3745 qmCommand.append(
" ; ");
3747 qmCommand.append(
" ") ;
3748 qmCommand.append(inputFileName) ;
3752 tmpRedirectFileName = inputFileName ;
3753 tmpRedirectFileName.append(
".TmpOut") ;
3755 qmCommand.append(
" > ") ;
3756 qmCommand.append(tmpRedirectFileName) ;
3760 outputFileName = inputFileName ;
3761 outputFileName.append(
".engrad") ;
3765 pcGradFilename = inputFileName ;
3766 pcGradFilename.append(
".pcgrad") ;
3770 pntChrgFileName = inputFileName ;
3771 pntChrgFileName.append(
".pntchrg") ;
3773 pcGradFileName = inputFileName;
3774 pcGradFileName.append(
".pcgrad");
3776 chrgFile = fopen(pntChrgFileName.c_str(),
"w");
3778 iout <<
iERROR <<
"Could not open charge file for writing: "
3779 << pntChrgFileName <<
"\n" <<
endi ;
3780 NAMD_err(
"Error writing point charge file.");
3783 int numPntChrgs = 0;
3789 iret = fprintf(chrgFile,
"%d\n", numPntChrgs);
3790 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
3795 std::string confLineStr;
3796 while (std::getline(ss, confLineStr) ) {
3797 confLineStr.append(
"\n");
3798 iret = fprintf(inputFile,confLineStr.c_str());
3799 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3803 iret = fprintf(inputFile,
"%%pointcharges \"%s\"\n", pntChrgFileName.c_str());
3804 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3807 iret = fprintf(inputFile,
"\n\n%%coords\n CTyp xyz\n");
3808 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3810 iret = fprintf(inputFile,
" Charge %f\n",msg->
charge);
3811 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3813 iret = fprintf(inputFile,
" Mult %f\n",msg->
multiplicity);
3814 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3816 iret = fprintf(inputFile,
" Units Angs\n coords\n\n");
3817 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3821 " point charges in file " << pntChrgFileName.c_str() <<
"\n");
3825 for (
size_t i=0; i<msg->
numAllAtoms; ++i, ++atmP ) {
3827 double x = atmP->position.x;
3828 double y = atmP->position.y;
3829 double z = atmP->position.z;
3831 iret = fprintf(inputFile,
" %s %f %f %f\n",
3832 atmP->element,x,y,z);
3833 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3837 iret = fprintf(inputFile,
" end\nend\n");
3838 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3854 iret = fprintf(chrgFile,
"%f %f %f %f\n",
3856 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
3862 DebugM(4,
"Closing input and charge file\n");
3867 std::string prepProc(msg->
prepProc) ;
3868 prepProc.append(
" ") ;
3869 prepProc.append(inputFileName) ;
3870 iret = system(prepProc.c_str());
3871 if ( iret == -1 ) {
NAMD_err(
"Error running preparation command for QM calculation."); }
3872 if ( iret ) {
NAMD_die(
"Error running preparation command for QM calculation."); }
3876 DebugM(4,
"Running command ->" << qmCommand.c_str() <<
"<-" << std::endl);
3877 iret = system(qmCommand.c_str());
3879 if ( iret == -1 ) {
NAMD_err(
"Error running command for QM forces calculation."); }
3880 if ( iret ) {
NAMD_die(
"Error running command for QM forces calculation."); }
3884 std::string secProc(msg->
secProc) ;
3885 secProc.append(
" ") ;
3886 secProc.append(inputFileName) ;
3890 secProc.append(
" ") ;
3891 secProc += itosConv.str() ;
3893 iret = system(secProc.c_str());
3894 if ( iret == -1 ) {
NAMD_err(
"Error running second command for QM calculation."); }
3895 if ( iret ) {
NAMD_die(
"Error running second command for QM calculation."); }
3907 DebugM(4,
"Reading QM data from file " << outputFileName.c_str() << std::endl);
3908 outputFile = fopen(outputFileName.c_str(),
"r");
3909 if ( ! outputFile ) {
3924 for (
int k=0; k<3; ++k )
3925 for (
int l=0; l<3; ++l )
3926 resMsg->
virial[k][l] = 0;
3932 resForce[i].force = 0;
3933 resForce[i].charge = 0 ;
3934 if (i < msg->numQMAtoms) {
3937 resForce[i].replace = 1 ;
3938 resForce[i].id = atmP->id;
3944 resForce[i].replace = 0 ;
3945 resForce[i].id = pcP->
id;
3954 size_t atmIndx = 0, gradCount = 0;
3955 int numAtomsInFile = 0;
3961 for (
int i = 0; i < 3; i++) {
3962 fgets(line, lineLen, outputFile);
3965 iret = fscanf(outputFile,
"%d\n", &numAtomsInFile);
3967 NAMD_die(
"Error reading QM forces file.");
3972 NAMD_die(
"Error reading QM forces file. Number of atoms in QM output\
3973 does not match the expected.");
3978 for (
int i = 0; i < 3; i++) {
3979 fgets(line, lineLen, outputFile);
3982 iret = fscanf(outputFile,
"%lf\n", &resMsg->
energyOrig);
3984 NAMD_die(
"Error reading QM forces file.");
3996 for (
int i = 0; i < 3; i++) {
3997 fgets(line, lineLen, outputFile) ;
4008 iret = fscanf(outputFile,
"%lf\n", &gradient[gradCount]);
4009 if ( iret != 1 ) {
NAMD_die(
"Error reading QM forces file."); }
4011 if (gradCount == 2){
4016 if (atmIndx < msg->numQMAtoms ) {
4017 resForce[atmIndx].force.x = -1*gradient[0]*1185.82151;
4018 resForce[atmIndx].force.y = -1*gradient[1]*1185.82151;
4019 resForce[atmIndx].force.z = -1*gradient[2]*1185.82151;
4028 atmIndx < msg->numAllAtoms ) {
4031 int qmInd = atmP[atmIndx].bountToIndx ;
4032 int mmInd = atmP[qmInd].bountToIndx ;
4037 Real linkDist =
Vector(atmP[atmIndx].position - atmP[qmInd].position).
length() ;
4039 Force mmForce(0), qmForce(0), linkForce(gradient[0], gradient[1], gradient[2]);
4040 linkForce *= -1*1185.82151;
4042 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
4044 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
4045 Real xDelta = pcP[mmInd].
position.
x - atmP[qmInd].position.x;
4046 Real yDelta = pcP[mmInd].
position.
y - atmP[qmInd].position.y;
4047 Real zDelta = pcP[mmInd].
position.
z - atmP[qmInd].position.z;
4049 qmForce += (linkForce*((1 - linkDist/mmqmDist)*xuv +
4050 (xDelta)*base) )*xuv;
4052 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
4053 (yDelta)*base) )*yuv;
4055 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
4056 (zDelta)*base) )*zuv;
4059 mmForce += (linkForce*((linkDist/mmqmDist)*xuv -
4060 (xDelta)*base) )*xuv;
4062 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
4063 (yDelta)*base) )*yuv;
4065 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
4066 (zDelta)*base) )*zuv;
4068 resForce[qmInd].force += qmForce;
4069 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
4089 for (; atmIndx < msg->
numQMAtoms; atmIndx++) {
4092 for (
int qmIter=0; qmIter<globalNumQMAtoms; qmIter++) {
4094 if (qmAtmIndx[qmIter] == atmP[atmIndx].
id) {
4096 atmP[atmIndx].charge = qmAtmChrg[qmIter];
4097 resForce[atmIndx].charge = qmAtmChrg[qmIter];
4108 outputFile = fopen(tmpRedirectFileName.c_str(),
"r");
4109 if ( ! outputFile ) {
4110 iout <<
iERROR <<
"Could not find Redirect output file:"
4111 << tmpRedirectFileName << std::endl <<
endi;
4115 DebugM(4,
"Opened tmeporary output for charge reading: " << tmpRedirectFileName.c_str() <<
"\n");
4119 while ( fgets(line, lineLen, outputFile) != NULL){
4131 if ( strstr(line,
"MULLIKEN ATOMIC CHARGES") != NULL ) {
4140 if ( strstr(line,
"Sum of atomic charges") != NULL ) {
4145 strncpy(result, line + 31,12) ;
4148 DebugM(4,
"Total charge of QM region calculated by ORCA is: "
4149 << atof(result) << std::endl )
4157 if (lineState == 1) {
4163 if (lineState == 2) {
4165 strncpy(result, line+8,12) ;
4168 Real localCharge = atof(result);
4171 if (atmIndx < msg->numQMAtoms ) {
4172 atmP[atmIndx].charge = localCharge;
4173 resForce[atmIndx].charge = localCharge;
4179 atmIndx < msg->numAllAtoms ) {
4180 int qmInd = atmP[atmIndx].bountToIndx ;
4181 atmP[qmInd].charge += localCharge;
4182 resForce[qmInd].charge += localCharge;
4201 if ( strstr(line,
"CHELPG Charges") != NULL ) {
4210 if ( strstr(line,
"Total charge") != NULL ) {
4215 strncpy(result, line + 14,13) ;
4218 DebugM(4,
"Total charge of QM region calculated by ORCA is: "
4219 << atof(result) << std::endl )
4227 if (lineState == 1) {
4233 if (lineState == 2) {
4235 strncpy(result, line+12,15) ;
4238 Real localCharge = atof(result);
4241 if (atmIndx < msg->numQMAtoms ) {
4242 atmP[atmIndx].charge = localCharge;
4243 resForce[atmIndx].charge = localCharge;
4249 atmIndx < msg->numAllAtoms ) {
4250 int qmInd = atmP[atmIndx].bountToIndx ;
4251 atmP[qmInd].charge += localCharge;
4252 resForce[qmInd].charge += localCharge;
4292 outputFile = fopen(pcGradFileName.c_str(),
"r");
4293 if ( ! outputFile ) {
4294 iout <<
iERROR <<
"Could not find PC gradient output file:"
4295 << pcGradFileName << std::endl <<
endi;
4299 DebugM(4,
"Opened pc output for gradient reading: " << pcGradFileName.c_str() <<
"\n");
4301 int pcgradNumPC = 0, readPC = 0;
4302 iret = fscanf(outputFile,
"%d\n", &pcgradNumPC );
4304 NAMD_die(
"Error reading PC forces file.");
4306 DebugM(4,
"Found in pc gradient output: " << pcgradNumPC <<
" point charge grads.\n");
4314 Force totalForce(0);
4323 fgets(line, lineLen, outputFile);
4325 iret = sscanf(line,
"%lf %lf %lf\n", &totalForce[0], &totalForce[1], &totalForce[2] );
4327 NAMD_die(
"Error reading PC forces file.");
4332 totalForce *= -1185.82151;
4337 if (qmAtomGroup[pcP[i].
id] == 0) {
4340 resForce[pcIndx].force += totalForce;
4347 Force mm1Force(0), mm2Force(0);
4356 mm1Force = (1-Cq)*totalForce ;
4357 mm2Force = Cq*totalForce ;
4359 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
4360 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
4374 DebugM(1,
"Correcting forces and energy for PME.\n");
4377 BigReal TwoBySqrtPi = 1.12837916709551;
4378 pi_ewaldcof = TwoBySqrtPi * ewaldcof;
4382 BigReal p_i_charge = atmP[i].charge ;
4383 Position pos_i = atmP[i].position ;
4385 for (
size_t j=i+1; j < msg->
numQMAtoms; j++) {
4387 BigReal p_j_charge = atmP[j].charge ;
4389 Position pos_j = atmP[j].position ;
4396 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
4399 BigReal recip_energy = (1-tmp_b)/r;
4402 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
4404 const BigReal kq_i = p_i_charge * constants;
4407 BigReal energy = kq_i * p_j_charge * recip_energy ;
4409 Force fixForce = -1*kq_i*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
4419 resForce[i].force -= fixForce ;
4420 resForce[j].force -= -1*fixForce;
4435 const BigReal kq_i = p_i_charge * constants;
4441 BigReal p_j_charge = atmP[j].charge ;
4443 Position pos_j = atmP[j].position ;
4450 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
4453 BigReal recip_energy = (1-tmp_b)/r;
4456 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
4459 BigReal energy = kq_i * p_j_charge * recip_energy ;
4461 fixForce += -1*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
4473 resForce[pcIndx].force -= kq_i*fixForce ;
4478 DebugM(1,
"Determining virial...\n");
4485 for (
int k=0; k<3; ++k )
4486 for (
int l=0; l<3; ++l )
4487 resMsg->
virial[k][l] = -1*resForce[i].force[k]*atmP[i].position[l];
4494 for (
int k=0; k<3; ++k )
4495 for (
int l=0; l<3; ++l )
4496 resMsg->
virial[k][l] = -1*resForce[pcIndx].force[k]*pcP[i].
position[l];
4499 DebugM(1,
"End of QM processing. Sending result message.\n");
4502 QMProxy[0].recvQMRes(resMsg);
4513 FILE *inputFile,*outputFile;
4516 std::string qmCommand, inputFileName, outputFileName;
4521 DebugM(4,
"Running USER DEFINED SOFTWARE on PE " << CkMyPe() << std::endl);
4535 pntChrgSwitching(msg, pcPpme) ;
4544 std::string baseDir(msg->
baseDir);
4545 std::ostringstream itosConv ;
4546 if ( CmiNumPartitions() > 1 ) {
4547 baseDir.append(
"/") ;
4548 itosConv << CmiMyPartition() ;
4549 baseDir += itosConv.str() ;
4553 if (stat(msg->
baseDir, &info) != 0 ) {
4554 CkPrintf(
"Node %d cannot access directory %s\n",
4555 CkMyPe(), baseDir.c_str() );
4556 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
4558 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
4559 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
4560 retVal = mkdir(baseDir.c_str(), S_IRWXU);
4564 baseDir.append(
"/") ;
4566 baseDir += itosConv.str() ;
4568 if (stat(msg->
baseDir, &info) != 0 ) {
4569 CkPrintf(
"Node %d cannot access directory %s\n",
4570 CkMyPe(), baseDir.c_str() );
4571 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
4573 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
4574 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
4575 int retVal = mkdir(baseDir.c_str(), S_IRWXU);
4579 Write_PDB(std::string(baseDir)+
"/input.pdb", msg ) ;
4582 inputFileName.clear();
4583 inputFileName.append(baseDir.c_str()) ;
4584 inputFileName.append(
"/qmmm_") ;
4585 inputFileName += itosConv.str() ;
4586 inputFileName.append(
".input") ;
4589 inputFile = fopen(inputFileName.c_str(),
"w");
4590 if ( ! inputFile ) {
4591 iout <<
iERROR <<
"Could not open input file for writing: "
4592 << inputFileName <<
"\n" <<
endi ;
4593 NAMD_err(
"Error writing QM input file.");
4598 qmCommand.append(
"cd ");
4599 qmCommand.append(baseDir);
4600 qmCommand.append(
" ; ");
4602 qmCommand.append(
" ") ;
4603 qmCommand.append(inputFileName) ;
4607 outputFileName = inputFileName ;
4608 outputFileName.append(
".result") ;
4610 int numPntChrgs = 0;
4616 iret = fprintf(inputFile,
"%d %d\n",msg->
numAllAtoms, numPntChrgs);
4617 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
4621 " point charges." << std::endl);
4625 for (
size_t i=0; i<msg->
numAllAtoms; ++i, ++atmP ) {
4627 double x = atmP->position.x;
4628 double y = atmP->position.y;
4629 double z = atmP->position.z;
4631 iret = fprintf(inputFile,
"%f %f %f %s\n",
4632 x,y,z,atmP->element);
4633 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
4637 int numWritenPCs = 0;
4651 iret = fprintf(inputFile,
"%f %f %f %f\n",
4653 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
4658 DebugM(4,
"Closing input file\n");
4663 std::string prepProc(msg->
prepProc) ;
4664 prepProc.append(
" ") ;
4665 prepProc.append(inputFileName) ;
4666 iret = system(prepProc.c_str());
4667 if ( iret == -1 ) {
NAMD_err(
"Error running preparation command for QM calculation."); }
4668 if ( iret ) {
NAMD_die(
"Error running preparation command for QM calculation."); }
4672 DebugM(4,
"Running command ->" << qmCommand.c_str() <<
"<-" << std::endl);
4673 iret = system(qmCommand.c_str());
4675 if ( iret == -1 ) {
NAMD_err(
"Error running command for QM forces calculation."); }
4676 if ( iret ) {
NAMD_die(
"Error running command for QM forces calculation."); }
4680 std::string secProc(msg->
secProc) ;
4681 secProc.append(
" ") ;
4682 secProc.append(inputFileName) ;
4686 secProc.append(
" ") ;
4687 secProc += itosConv.str() ;
4689 iret = system(secProc.c_str());
4690 if ( iret == -1 ) {
NAMD_err(
"Error running second command for QM calculation."); }
4691 if ( iret ) {
NAMD_die(
"Error running second command for QM calculation."); }
4703 DebugM(4,
"Reading QM data from file " << outputFileName.c_str() << std::endl);
4704 outputFile = fopen(outputFileName.c_str(),
"r");
4705 if ( ! outputFile ) {
4720 for (
int k=0; k<3; ++k )
4721 for (
int l=0; l<3; ++l )
4722 resMsg->
virial[k][l] = 0;
4728 resForce[i].force = 0;
4729 resForce[i].charge = 0 ;
4730 if (i < msg->numQMAtoms) {
4733 resForce[i].replace = 1 ;
4734 resForce[i].id = atmP->id;
4740 resForce[i].replace = 0 ;
4741 resForce[i].id = pcP->
id;
4755 const size_t lineLen = 256;
4756 char *line =
new char[lineLen];
4758 fgets(line, lineLen, outputFile);
4761 iret = sscanf(line,
"%lf %i\n", &resMsg->
energyOrig, &usrPCnum);
4763 NAMD_die(
"Error reading energy from QM results file.");
4768 if (iret == 2 && numWritenPCs != usrPCnum) {
4769 iout <<
iERROR <<
"Number of point charges does not match what was provided!\n" <<
endi ;
4770 NAMD_die(
"Error reading QM results file.");
4774 double localForce[3];
4776 for (atmIndx = 0; atmIndx < msg->
numAllAtoms; atmIndx++) {
4778 iret = fscanf(outputFile,
"%lf %lf %lf %lf\n",
4784 NAMD_die(
"Error reading forces and charge from QM results file.");
4789 if (atmIndx < msg->numQMAtoms ) {
4791 resForce[atmIndx].force.x = localForce[0];
4792 resForce[atmIndx].force.y = localForce[1];
4793 resForce[atmIndx].force.z = localForce[2];
4795 atmP[atmIndx].charge = localCharge;
4796 resForce[atmIndx].charge = localCharge;
4805 atmIndx < msg->numAllAtoms ) {
4809 atmP[atmIndx].charge = localCharge;
4814 int qmInd = atmP[atmIndx].bountToIndx ;
4815 resForce[qmInd].charge += localCharge;
4819 int mmInd = atmP[qmInd].bountToIndx ;
4824 Real linkDist =
Vector(atmP[atmIndx].position -
4825 atmP[qmInd].position).
length() ;
4827 Force mmForce(0), qmForce(0),
4828 linkForce(localForce[0], localForce[1], localForce[2]);
4830 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
4832 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
4833 Real xDelta = pcP[mmInd].
position.
x - atmP[qmInd].position.x;
4834 Real yDelta = pcP[mmInd].
position.
y - atmP[qmInd].position.y;
4835 Real zDelta = pcP[mmInd].
position.
z - atmP[qmInd].position.z;
4837 qmForce += (linkForce*((1 - linkDist/mmqmDist)*xuv +
4838 (xDelta)*base) )*xuv;
4840 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
4841 (yDelta)*base) )*yuv;
4843 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
4844 (zDelta)*base) )*zuv;
4847 mmForce += (linkForce*((linkDist/mmqmDist)*xuv -
4848 (xDelta)*base) )*xuv;
4850 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
4851 (yDelta)*base) )*yuv;
4853 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
4854 (zDelta)*base) )*zuv;
4856 resForce[qmInd].force += qmForce;
4857 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
4872 Force totalForce(0);
4881 iret = fscanf(outputFile,
"%lf %lf %lf\n",
4882 &totalForce[0], &totalForce[1], &totalForce[2]);
4884 NAMD_die(
"Error reading PC forces from QM results file.");
4890 if (qmAtomGroup[pcP[i].
id] == 0) {
4893 resForce[pcIndx].force += totalForce;
4900 Force mm1Force(0), mm2Force(0);
4909 mm1Force = (1-Cq)*totalForce ;
4910 mm2Force = Cq*totalForce ;
4912 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
4913 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
4931 for (; atmIndx < msg->
numQMAtoms; atmIndx++) {
4934 for (
int qmIter=0; qmIter<globalNumQMAtoms; qmIter++) {
4936 if (qmAtmIndx[qmIter] == atmP[atmIndx].
id) {
4938 atmP[atmIndx].charge = qmAtmChrg[qmIter];
4939 resForce[atmIndx].charge = qmAtmChrg[qmIter];
4947 for (
size_t j=msg->
numQMAtoms; j<msg->numAllAtoms; ++j ) {
4957 if (usrPCnum == 0) {
4973 Force totalForce(0);
4981 BigReal qmCharge = atmP[j].charge ;
4983 BigReal force = pntCharge*qmCharge*constants ;
4985 Position rVec = posMM - atmP[j].position ;
4994 totalForce += force*rVec.
unit();
5000 if (qmAtomGroup[pcP[i].
id] == 0) {
5003 resForce[pcIndx].force += totalForce;
5010 Force mm1Force(0), mm2Force(0);
5019 mm1Force = (1-Cq)*totalForce ;
5020 mm2Force = Cq*totalForce ;
5022 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
5023 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
5033 DebugM(1,
"Correcting forces and energy for PME.\n");
5036 BigReal TwoBySqrtPi = 1.12837916709551;
5037 pi_ewaldcof = TwoBySqrtPi * ewaldcof;
5041 BigReal p_i_charge = atmP[i].charge ;
5042 Position pos_i = atmP[i].position ;
5044 for (
size_t j=i+1; j < msg->
numQMAtoms; j++) {
5046 BigReal p_j_charge = atmP[j].charge ;
5048 Position pos_j = atmP[j].position ;
5055 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
5058 BigReal recip_energy = (1-tmp_b)/r;
5061 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
5063 const BigReal kq_i = p_i_charge * constants;
5066 BigReal energy = kq_i * p_j_charge * recip_energy ;
5068 Force fixForce = -1*kq_i*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
5078 resForce[i].force -= fixForce ;
5079 resForce[j].force -= -1*fixForce;
5094 const BigReal kq_i = p_i_charge * constants;
5100 BigReal p_j_charge = atmP[j].charge ;
5102 Position pos_j = atmP[j].position ;
5109 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
5112 BigReal recip_energy = (1-tmp_b)/r;
5115 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
5118 BigReal energy = kq_i * p_j_charge * recip_energy ;
5120 fixForce += -1*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
5132 resForce[pcIndx].force -= kq_i*fixForce ;
5137 DebugM(1,
"Determining virial...\n");
5144 for (
int k=0; k<3; ++k )
5145 for (
int l=0; l<3; ++l )
5146 resMsg->
virial[k][l] = -1*resForce[i].force[k]*atmP[i].position[l];
5153 for (
int k=0; k<3; ++k )
5154 for (
int l=0; l<3; ++l )
5155 resMsg->
virial[k][l] = -1*resForce[pcIndx].force[k]*pcP[i].
position[l];
5158 DebugM(1,
"End of QM processing. Sending result message.\n");
5161 QMProxy[0].recvQMRes(resMsg);
5181 DebugM(1,
"Initiating point charge switching and processing in rank "
5182 << CkMyPe() <<
"\n" ) ;
5187 Real PCScaleCharge = 0;
5189 PCScaleCharge += pcP[i].
charge;
5191 DebugM(4,
"The initial total Point-Charge charge is " << PCScaleCharge
5192 <<
" before scaling type: " << msg->
switchType <<
"\n" );
5218 Real coef = 1- dist2;
5219 pcP[i].
charge *= coef*coef ;
5230 if (pcP[i].dist > swdist) {
5237 Real swdist2 = swdist*swdist;
5239 coef *= (cutoff2 + 2*dist2 - 3*swdist2) ;
5240 coef /= (cutoff2 - swdist2)*(cutoff2 - swdist2)*(cutoff2 - swdist2);
5250 PCScaleCharge += pcP[i].
charge;
5252 DebugM(4,
"The final total Point-Charge charge is " << PCScaleCharge
5253 <<
" after scaling.\n" );
5257 <<
" point charges were selected for point charge scheme " << msg->
pcScheme <<
"\n" );
5259 Real totalPCCharge = 0, correction = 0;
5265 totalPCCharge += pcP[i].
charge;
5267 DebugM(4,
"The total Point-Charge charge is " << totalPCCharge
5270 if ((fabsf(roundf(totalPCCharge) - totalPCCharge) <= 0.001f) ) {
5271 DebugM(4,
"Charge is already a whole number!\n" );
5274 correction = roundf(totalPCCharge) -totalPCCharge ;
5275 DebugM(4,
"Adding to system the charge: " << correction <<
"\n" );
5282 totalPCCharge += pcP[i].
charge;
5284 DebugM(4,
"The total Point-Charge charge is " << totalPCCharge <<
"\n");
5286 DebugM(4,
"Total QM system charge is: " << msg->
charge <<
"\n" );
5288 correction = -1*(totalPCCharge + msg->
charge);
5289 if ((fabsf(correction) <= 0.001f) ) {
5291 DebugM(4,
"Total QM + PC charge is already zero!\n" );
5294 DebugM(4,
"Adding a charge of " << correction <<
" to the system\n");
5299 if (correction != 0) {
5301 int maxi = sortedDists.
size(), mini = sortedDists.
size()/2;
5302 Real fraction = correction/(maxi - mini);
5304 DebugM(4,
"The charge fraction added to the " << (maxi - mini)
5305 <<
" most distant point charges is " << fraction <<
"\n");
5307 for (
size_t i=mini; i<maxi ; i++) {
5316 totalPCCharge += pcP[i].
charge;
5318 DebugM(4,
"The total Point-Charge charge is " << totalPCCharge
5325 void ComputeQMMgr::lssPrepare() {
5330 DebugM (4,
"Preparing LSS for " << numQMGrps <<
" QM groups.\n" )
5332 for (
int i=0; i<numQMGrps; i++) {
5333 lssTotRes += qmLSSSize[i];
5338 grpIDResNum.
resize(numQMGrps);
5342 lssGrpRefMass.
resize(numQMGrps);
5344 for (
int i=0; i<qmLSSResSize; i++)
5345 lssResMass += qmLSSMass[i];
5347 DebugM(4,
"Total residue mass is " << lssResMass <<
"\n" )
5351 int solvResBeg = 0, refAtmBeg = 0, locIter = 0, solvIndx = 0;
5352 int *lssIndxs, *refAtmsIndxs ;
5353 Mass *lssMasses, *refAtmMasses;
5354 while (locIter < numQMGrps) {
5355 lssIndxs = qmLSSIdxs + solvResBeg;
5357 DebugM (4,
"Loading atom IDs for QM group " << locIter
5358 <<
" with " << qmLSSSize[locIter]
5359 <<
" solvent molecules.\n" )
5366 lssMasses = qmLSSMass + solvResBeg;
5369 for (
int i=0; i<qmLSSSize[locIter]; i++) {
5371 lssPos[solvIndx] = 0;
5373 Debug(
iout <<
"Getting atom IDs from QM solvent molecule "
5374 << solvIndx <<
"\n") ;
5375 for (
int j=0; j<qmLSSResSize; j++) {
5377 int atmID = lssIndxs[i*qmLSSResSize + j];
5378 Mass atmMass = lssMasses[i*qmLSSResSize + j];
5379 Debug(
iout << atmID <<
" (" << atmMass <<
") ") ;
5390 refAtmsIndxs = qmLSSRefIDs + refAtmBeg;
5392 for (
int i=0; i<qmLSSRefSize[locIter]; i++) {
5393 lssGrpRefMass[locIter].
insert(
5394 refLSSData( refAtmsIndxs[i], refAtmMasses[i] )
5397 refAtmBeg += qmLSSRefSize[locIter] ;
5403 for (
int i=0; i<qmLSSSize[locIter]; i++) {
5405 lssPos[solvIndx] = 0;
5407 Debug(
iout <<
"Getting atom IDs from QM solvent molecule "
5408 << solvIndx <<
"\n") ;
5409 for (
int j=0; j<qmLSSResSize; j++) {
5411 int atmID = lssIndxs[i*qmLSSResSize + j];
5425 solvResBeg += qmLSSSize[locIter]*qmLSSResSize ;
5432 void ComputeQMMgr::lssUpdate(
int grpIter,
QMAtmVec& grpQMAtmVec,
5440 DebugM(3,
"LSS UPDATE...\n")
5442 int solvResBeg = 0 ;
5443 for (
int i=0; i<grpIter; i++)
5444 solvResBeg += qmLSSSize[i] ;
5450 DebugM(3,
"Using COM for LSS in group " << grpIter <<
"\n")
5453 for(
int i=0; i<grpQMAtmVec.size(); i++) {
5455 auto it = lssGrpRefMass[grpIter].
find(grpQMAtmVec[i].
id);
5456 if ( it != lssGrpRefMass[grpIter].end() ) {
5457 refCOM += grpQMAtmVec[i].position*it->second ;
5458 totMass += it->second ;
5463 DebugM ( 3,
"Reference COM position: " << refCOM <<
"\n");
5466 for (
int solvIter=solvResBeg; solvIter<solvResBeg+qmLSSSize[grpIter]; solvIter++) {
5467 lssPos[solvIter] = 0 ;
5470 DebugM(3,
"Calculating distance of QM solvent COM from reference COM of group.\n")
5477 for(
int i=0; i<grpQMAtmVec.size(); i++) {
5478 auto it = grpIDResNum[grpIter].
find(grpQMAtmVec[i].
id) ;
5479 if (it != grpIDResNum[grpIter].end()) {
5480 lssPos[it->second.resIndx] += grpQMAtmVec[i].position*it->second.mass ;
5483 auto itRes = resQMDist.find(it->second.resIndx) ;
5484 if (itRes == resQMDist.end() ) {
5485 resQMDist.insert(std::pair<int,lssDistSort >(
5494 resQMDist[it->second.resIndx].idIndx.add(
idIndxStr(grpQMAtmVec[i].
id,i)) ;
5498 DebugM(3,
"QM Solvent molecules " << solvResBeg
5499 <<
" to " << solvResBeg+qmLSSSize[grpIter] <<
"\n")
5502 for (
int solvIter=solvResBeg; solvIter<solvResBeg+qmLSSSize[grpIter]; solvIter++) {
5504 resQMDist[solvIter].dist = dist ;
5505 solvDist.
add(resQMDist[solvIter]);
5509 DebugM(3,
"We loaded the following QM solvent residues and distances:\n")
5510 for (
int i=0; i<solvDist.size(); i++) {
5511 iout << i <<
") type: " << solvDist[i].type
5512 <<
" dist " << solvDist[i].dist
5514 for (
int j=0; j<solvDist[i].idIndx.
size(); j++)
5515 iout << solvDist[i].idIndx[j].ID <<
" " ;
5525 std::map<int,lssDistSort > resPCSize ;
5527 for(
int i=0; i<grpPntChrgVec.size(); i++) {
5530 auto it = molPtr->
get_qmMMSolv().find(grpPntChrgVec[i].
id) ;
5534 auto itRes = resPCSize.find(it->second) ;
5535 if (itRes == resPCSize.end() ) {
5536 resPCSize.insert(std::pair<int,lssDistSort >(
5545 resPCSize[it->second].idIndx.add(
idIndxStr(grpPntChrgVec[i].
id,i)) ;
5552 for (
auto it=resPCSize.begin(); it!=resPCSize.end(); it++) {
5554 if (it->second.idIndx.size() == qmLSSResSize) {
5561 for (
int i=0; i<it->second.idIndx.size(); i++) {
5566 currCOM += grpPntChrgVec[it->second.idIndx[i].indx].position*grpPntChrgVec[it->second.idIndx[i].indx].mass;
5567 totalMass += grpPntChrgVec[it->second.idIndx[i].indx].mass;
5569 currCOM /= totalMass;
5573 it->second.dist = currDist ;
5575 solvDist.
add(it->second) ;
5583 DebugM(3,
"Using minimal distances for LSS in group " << grpIter <<
"\n")
5585 DebugM(3, "QM Solvent molecules " << solvResBeg
5586 << " to " << solvResBeg+qmLSSSize[grpIter] << "\n")
5596 for(
int i=0; i<grpQMAtmVec.size(); i++) {
5598 auto it = grpIDResNum[grpIter].
find(grpQMAtmVec[i].
id) ;
5599 if (it != grpIDResNum[grpIter].end()) {
5602 auto itRes = resQMDist.find(it->second.resIndx) ;
5603 if (itRes == resQMDist.end() ) {
5604 resQMDist.insert(std::pair<int,lssDistSort >(
5613 resQMDist[it->second.resIndx].idIndx.add(
idIndxStr(grpQMAtmVec[i].
id,i)) ;
5623 for (
auto it=resQMDist.begin(); it != resQMDist.end(); it++) {
5627 it->second.dist =
Vector(
5628 grpQMAtmVec[it->second.idIndx[0].indx].position -
5629 grpQMAtmVec[qmRefIndx[0]].position
5632 for (
int i=0; i<it->second.idIndx.size(); i++) {
5634 for(
int j=0; j<qmRefIndx.size(); j++) {
5636 grpQMAtmVec[it->second.idIndx[i].indx].position -
5637 grpQMAtmVec[qmRefIndx[j]].position
5640 if (currDist < it->second.dist)
5641 it->second.dist = currDist;
5647 solvDist.
add(it->second) ;
5652 DebugM(3,
"We loaded the following QM solvent residues and distances:\n")
5653 for (
int i=0; i<solvDist.size(); i++) {
5654 iout << i <<
") type: " << solvDist[i].type
5655 <<
" dist " << solvDist[i].dist
5657 for (
int j=0; j<solvDist[i].idIndx.
size(); j++)
5658 iout << solvDist[i].idIndx[j].ID <<
" " ;
5668 std::map<int,lssDistSort > resPCSize ;
5670 for(
int i=0; i<grpPntChrgVec.size(); i++) {
5673 auto it = molPtr->
get_qmMMSolv().find(grpPntChrgVec[i].
id) ;
5677 auto itRes = resPCSize.find(it->second) ;
5678 if (itRes == resPCSize.end() ) {
5679 resPCSize.insert(std::pair<int,lssDistSort >(
5688 resPCSize[it->second].idIndx.add(
idIndxStr(grpPntChrgVec[i].
id,i)) ;
5695 for (
auto it=resPCSize.begin(); it!=resPCSize.end(); it++) {
5697 if (it->second.idIndx.size() == qmLSSResSize) {
5701 it->second.dist =
Vector(
5702 grpPntChrgVec[it->second.idIndx[0].indx].position -
5703 grpQMAtmVec[qmRefIndx[0]].position
5706 for (
int i=0; i<it->second.idIndx.size(); i++) {
5708 for(
int j=0; j<qmRefIndx.size(); j++) {
5710 grpPntChrgVec[it->second.idIndx[i].indx].position -
5711 grpQMAtmVec[qmRefIndx[j]].position
5714 if (currDist < it->second.dist)
5715 it->second.dist = currDist;
5719 solvDist.
add(it->second) ;
5729 DebugM(3,
"Final selection of solvent residues and distances:\n")
5730 for (
int i=0; i<qmLSSSize[grpIter]; i++) {
5735 typeS =
"Classical";
5736 iout << i <<
") type: " << typeS
5737 <<
" dist " << solvDist[i].dist
5739 for (
int j=0; j<solvDist[i].idIndx.
size(); j++)
5740 iout << solvDist[i].idIndx[j].ID <<
" " ;
5748 DebugM(3,
"Determining residues to be swaped...\n")
5752 for (
int resIter = 0; resIter < qmLSSSize[grpIter] ; resIter++) {
5754 nearMM.add(solvDist[resIter]);
5758 for (
int resIter=qmLSSSize[grpIter]; resIter<solvDist.
size(); resIter++) {
5760 farQM.add(solvDist[resIter]);
5763 if (farQM.size() == nearMM.size())
break;
5766 if (farQM.size() != nearMM.size())
5767 NAMD_die(
"Could not find complementing residues to be swapped in LSS.") ;
5770 DebugM(3,
"Removing the following QM residues:\n")
5771 for (
int i=0; i<farQM.size();i++) {
5776 typeS =
"Classical";
5777 iout << i <<
") type: " << typeS
5778 <<
" dist " << farQM[i].dist
5780 for (
int j=0; j<farQM[i].idIndx.size(); j++)
5781 iout << farQM[i].idIndx[j].ID <<
" " ;
5785 DebugM(3,
"Replacing with the following Classical residues:\n")
5786 for (
int i=0; i<nearMM.size();i++) {
5791 typeS =
"Classical";
5792 iout << i <<
") type: " << typeS
5793 <<
" dist " << nearMM[i].dist
5795 for (
int j=0; j<nearMM[i].idIndx.size(); j++)
5796 iout << nearMM[i].idIndx[j].ID <<
" " ;
5800 DebugM(3,
"Building substitution array...\n")
5803 iout <<
iINFO <<
"LSS is swapping " << farQM.size() <<
" solvent residues in QM group "
5804 << grpIter <<
"\n" <<
endi;
5809 for (
int i=0; i<farQM.size();i++) {
5811 for(
int j=0; j<qmLSSResSize; j++) {
5813 int qIndx= farQM[i].idIndx[j].indx;
5814 int mIndx= nearMM[i].idIndx[j].indx;
5817 grpPntChrgVec[mIndx].
id,
5818 grpPntChrgVec[mIndx].vdwType,
5819 grpPntChrgVec[mIndx].
charge ) );
5822 grpQMAtmVec[qIndx].
id,
5823 grpQMAtmVec[qIndx].vdwType,
5824 grpQMAtmVec[qIndx].charge ) );
5830 for(
int i=0; i<subsArray.
size() ;i++) {
5831 DebugM(3, CkMyPe() <<
") Storing LSS atom " << subsArray[i].origID
5832 <<
" Which will become " << subsArray[i].newID
5833 <<
" - " << subsArray[i].newVdWType
5834 <<
" - " << subsArray[i].newCharge <<
"\n" );
5841 void ComputeQMMgr::calcCSMD(
int grpIndx,
int numQMAtoms,
const QMAtomData *atmP,
Force *cSMDForces) {
5845 for (
int i=0; i < cSMDindxLen[grpIndx]; i++ ) {
5852 int cSMDit = cSMDindex[grpIndx][i] ;
5853 AtomID src = -1, trgt = -1;
5856 for (
size_t indx=0; indx < numQMAtoms; ++indx) {
5858 if ( cSMDpairs[cSMDit][0] == atmP[indx].
id )
5861 if ( cSMDpairs[cSMDit][1] == atmP[indx].
id )
5864 if (src != -1 && trgt != -1)
5870 tdist = trgtDir.
length();
5874 if (cSMDInitGuides < cSMDnumInstances) {
5875 cSMDguides[cSMDit] = atmP[src].
position;
5881 if (tdist > cSMDcoffs[cSMDit]) {
5883 cSMDguides[cSMDit] += trgtDir*cSMDVels[cSMDit];
5888 guideDir *= cSMDKs[cSMDit] ;
5889 cSMDforce = guideDir ;
5895 cSMDguides[cSMDit] = atmP[src].
position;
5898 DebugM(4, cSMDit <<
") Center at " << cSMDguides[cSMDit] <<
" for target distance " <<
5899 tdist <<
" and direction " << trgtDir <<
5903 cSMDForces[cSMDit] = cSMDforce;
5905 iout <<
iINFO <<
"Calculated cSMD force vector " << cSMDforce
5906 <<
" (atom " << cSMDpairs[cSMDit][0] <<
" to " << cSMDpairs[cSMDit][1] <<
")\n" <<
endi;
5914 void ComputeQMMgr::Write_PDB(std::string Filename,
const QMGrpCalcMsg *dataMsg)
5916 std::ofstream OutputTmpPDB ;
5921 OutputTmpPDB.open( Filename.c_str(), std::fstream::out );
5923 OutputTmpPDB <<
"REMARK Information used by NAMD to create the QM simulation." << std::endl ;
5924 OutputTmpPDB <<
"REMARK Occupancy: bount to index; Beta: System ID; " << std::endl ;
5938 std::string name(
" x ");
5939 std::string resName (
" uk");
5940 std::string chainName(
"X");
5941 std::string element(
"") ;
5942 if (i < dataMsg->numAllAtoms ) {
5961 OutputTmpPDB <<
"ATOM " ;
5963 OutputTmpPDB.width(5) ;
5964 OutputTmpPDB.right ;
5967 OutputTmpPDB <<
" " ;
5969 OutputTmpPDB.width(4) ;
5970 OutputTmpPDB << name ;
5972 OutputTmpPDB <<
" " ;
5974 OutputTmpPDB.width(4) ;
5975 OutputTmpPDB << resName ;
5977 OutputTmpPDB.width(1) ;
5978 OutputTmpPDB << chainName ;
5980 OutputTmpPDB.width(4) ;
5983 OutputTmpPDB <<
" " ;
5985 OutputTmpPDB <<
" " ;
5987 OutputTmpPDB.width(8) ;
5988 OutputTmpPDB.right ;
5989 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
5990 OutputTmpPDB.precision(3) ;
5993 OutputTmpPDB.width(8) ;
5994 OutputTmpPDB.right ;
5995 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
5996 OutputTmpPDB.precision(3) ;
5999 OutputTmpPDB.width(8) ;
6000 OutputTmpPDB.right ;
6001 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6002 OutputTmpPDB.precision(3) ;
6005 OutputTmpPDB.width(6) ;
6006 OutputTmpPDB.right ;
6007 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6008 OutputTmpPDB.precision(2) ;
6011 OutputTmpPDB.width(6) ;
6012 OutputTmpPDB.right ;
6013 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6014 OutputTmpPDB.precision(2) ;
6015 OutputTmpPDB << dataP[i].
id ;
6017 OutputTmpPDB.width(6) ;
6018 OutputTmpPDB <<
" " ;
6020 OutputTmpPDB.width(4) ;
6022 OutputTmpPDB <<
"QM ";
6024 OutputTmpPDB.width(2) ;
6025 OutputTmpPDB.right ;
6026 OutputTmpPDB << element ;
6028 OutputTmpPDB.width(2) ;
6029 OutputTmpPDB.right ;