16 #define MIN_DEBUG_LEVEL 1 25 #include "ComputeQMMgr.decl.h" 30 #include "ComputeMgr.decl.h" 41 #include "ComputePmeMgr.decl.h" 46 #if defined(WIN32) && !defined(__CYGWIN__) 48 #define mkdir(X,Y) _mkdir(X) 49 #define S_ISDIR(X) ((X) & S_IFDIR) 53 #define SQRT_PI 1.7724538509055160273 59 #define QMPCSCHEMENONE 1 60 #define QMPCSCHEMEROUND 2 61 #define QMPCSCHEMEZERO 3 63 #define QMPCSCALESHIFT 1 64 #define QMPCSCALESWITCH 2 76 Real qmInit,
int hiInit,
int newvdwType) {
100 #define PCMODEUPDATESEL 1 101 #define PCMODEUPDATEPOS 2 102 #define PCMODECUSTOMSEL 3 138 Real qmInit,
int hiInit,
Real newDist,
139 Mass newM,
int newvdwType) {
161 return (
id < ref.
id);
164 return (
id == ref.
id) ;
196 # define QMATOMTYPE_DUMMY 0 197 # define QMATOMTYPE_QM 1 198 # define QMPCTYPE_IGNORE 0 199 # define QMPCTYPE_CLASSICAL 1 200 # define QMPCTYPE_EXTRA 2 203 #define QMLSSCLASSICALRES 2 232 return !(*
this == ref);
276 bool returnVal =
true;
307 int bountToIndxInit,
int newType,
308 char *elementInit,
Real newDist) {
314 strncpy(
element,elementInit,3);
370 static char tmp_string[25];
371 const double maxnum = 9999999999.9999;
372 if (
X > maxnum )
X = maxnum;
373 if (
X < -maxnum )
X = -maxnum;
374 sprintf(tmp_string,
" %14.4f",
X);
380 static char tmp_string[25];
381 sprintf(tmp_string,
" %14s",
X);
387 static char tmp_string[21];
388 sprintf(tmp_string,
"QMENERGY: %7d",
X);
399 typedef std::vector<ComputeQMPntChrg>
QMPCVec ;
431 ComputeQMMgr_SDAG_CODE
433 CProxy_ComputeQMMgr QMProxy;
437 int numArrivedQMMsg, numArrivedPntChrgMsg, numRecQMRes;
441 std::vector<int> qmPEs ;
475 Real *grpChrg, *grpMult;
505 int dcdOutFile, dcdPosOutFile;
509 void procBonds(
int numBonds,
510 const int *
const qmGrpBondsGrp,
511 const int *
const qmMMBondedIndxGrp,
512 const int *
const *
const chargeTarget,
513 const int *
const numTargs,
520 void lssUpdate(
int grpIter,
QMAtmVec &grpQMAtmVec,
QMPCVec &grpPntChrgVec);
522 void calcCSMD(
int grpIndx,
int numQMAtoms,
const QMAtomData *atmP,
Force *resForce) ;
525 int cSMDnumInstances, cSMDInitGuides;
527 int const *
const * cSMDindex;
529 int const * cSMDindxLen;
533 int const *
const * cSMDpairs;
537 Real const * cSMDVels;
539 Real const * cSMDcoffs;
544 void Write_PDB(std::string Filename,
const QMGrpCalcMsg *dataMsg);
545 void Write_PDB(std::string Filename,
const QMCoordMsg *dataMsg);
550 QMProxy(thisgroup), QMCompute(0), numSources(0), numArrivedQMMsg(0),
551 numArrivedPntChrgMsg(0), numRecQMRes(0), qmCoordMsgs(0), pntChrgCoordMsgs(0),
552 qmCoord(0), force(0), numAtoms(0), dcdOutFile(0), outputData(0), pcIDListSize(0) {
554 CkpvAccess(BOCclass_group).computeQMMgr = thisgroup;
560 if (qmCoordMsgs != 0) {
561 for (
int i=0; i<numSources; ++i ) {
562 if (qmCoordMsgs[i] != 0)
563 delete qmCoordMsgs[i];
565 delete [] qmCoordMsgs;
568 if (pntChrgCoordMsgs != 0) {
569 for (
int i=0; i<numSources; ++i ) {
570 if (pntChrgCoordMsgs[i] != 0)
571 delete pntChrgCoordMsgs[i];
573 delete [] pntChrgCoordMsgs;
586 if (dcdPosOutFile != 0)
590 delete [] outputData;
603 CProxy_ComputeQMMgr::ckLocalBranch(
604 CkpvAccess(BOCclass_group).computeQMMgr)->setCompute(
this);
632 for (
int i=0; i<meNumMMIndx; i++)
643 cutoff = simParams->
cutoff;
648 customPCLists.
resize(numQMGrps);
654 int minI = 0, maxI = 0, grpIter = 0;
656 while (grpIter < numQMGrps) {
658 maxI += custPCSizes[grpIter];
660 for (
size_t i=minI; i < maxI; i++) {
662 customPCLists[grpIter].
add( customPCIdxs[i] ) ;
666 minI += custPCSizes[grpIter];
678 CProxy_ComputeQMMgr QMProxy(CkpvAccess(BOCclass_group).computeQMMgr);
685 DebugM(4,
"----> Initiating QM work on rank " << CkMyPe() <<
692 int numLocalQMAtoms = 0, localMM1atoms = 0;
693 for (ap = ap.
begin(); ap != ap.
end(); ap++) {
695 int localNumAtoms = (*ap).p->getNumAtoms();
698 (*ap).positionBox->open(),
701 for(
int i=0; i<localNumAtoms; ++i) {
702 if ( qmAtomGroup[xExt[i].
id] > 0 ) {
705 else if (meNumMMIndx > 0) {
719 timeStep = (*ap).p->flags.step ;
722 DebugM(4,
"Node " << CkMyPe() <<
" has " << numLocalQMAtoms
723 <<
" QM atoms." << std::endl) ;
725 if (localMM1atoms > 0)
726 DebugM(4,
"Node " << CkMyPe() <<
" has " << localMM1atoms
727 <<
" MM1 atoms." << std::endl) ;
734 msg->
numAtoms = numLocalQMAtoms + localMM1atoms;
741 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
744 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
745 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
746 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
748 for(
int i=0; i<localNumAtoms; ++i) {
750 if ( qmAtomGroup[xExt[i].
id] > 0 ) {
754 for (
int qi=0; qi<numQMAtms; qi++) {
755 if (qmAtmIndx[qi] == xExt[i].
id) {
756 charge = qmAtmChrg[qi];
762 fullAtms[i].transform) ;
764 data_ptr->
charge = charge;
765 data_ptr->
id = xExt[i].
id;
766 data_ptr->
qmGrpID = qmAtomGroup[xExt[i].
id] ;
772 else if (meNumMMIndx > 0) {
781 DebugM(3,
"Found atom " << retIt->mmIndx <<
"," << retIt->qmGrp <<
"\n" );
784 fullAtms[i].transform) ;
788 data_ptr->
id = xExt[i].
id;
789 data_ptr->
qmGrpID = retIt->qmGrp ;
808 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
810 (*pdIt).posBoxP->close(&x);
814 QMProxy[0].recvPartQM(msg);
823 if ( ! numSources ) {
824 DebugM(4,
"Initializing ComputeQMMgr variables." << std::endl);
827 DebugM(4,
"There are " << numSources <<
" nodes with patches." << std::endl);
829 for (
int i=0; i<numSources; ++i ) {
835 DebugM(4,
"Getting data from molecule and simParameters." << std::endl);
846 noPC = simParams->
qmNoPC ;
848 if (noPC && meNumMMIndx == 0) {
849 pntChrgCoordMsgs = NULL;
853 for (
int i=0; i<numSources; ++i ) {
854 pntChrgCoordMsgs[i] = 0;
859 resendPCList =
false;
883 numArrivedQMMsg = 0 ;
884 numArrivedPntChrgMsg = 0 ;
907 cSMDguides =
new Position[cSMDnumInstances];
908 cSMDForces =
new Force[cSMDnumInstances];
912 DebugM(4,
"Initializing DCD file for charge information." << std::endl);
916 std::string dcdOutFileStr;
917 dcdOutFileStr.clear();
919 dcdOutFileStr.append(
".qdcd") ;
923 iout <<
iERROR <<
"DCD file " << dcdOutFile <<
" already exists!!\n" <<
endi;
924 NAMD_err(
"Could not write QM charge DCD file.");
925 }
else if (dcdOutFile < 0) {
926 iout <<
iERROR <<
"Couldn't open DCD file " << dcdOutFile <<
".\n" <<
endi;
927 NAMD_err(
"Could not write QM charge DCD file.");
928 }
else if (! dcdOutFile) {
929 NAMD_bug(
"ComputeQMMgr::recvPartQM open_dcd_write returned fileid of zero");
934 int NSAVC, NFILE, NPRIV, NSTEP;
937 NSTEP = NPRIV - NSAVC;
942 numQMAtms, NFILE, NPRIV, NSAVC, NSTEP,
946 NAMD_err(
"Writing of DCD header failed!!");
951 outputData =
new Real[3*numQMAtms];
954 DebugM(4,
"Initializing DCD file for position information." << std::endl);
957 std::string dcdPosOutFileStr;
958 dcdPosOutFileStr.clear();
960 dcdPosOutFileStr.append(
".QMonly.dcd") ;
964 iout <<
iERROR <<
"DCD file " << dcdPosOutFile <<
" already exists!!\n" <<
endi;
965 NAMD_err(
"Could not write QM charge DCD file.");
966 }
else if (dcdPosOutFile < 0) {
967 iout <<
iERROR <<
"Couldn't open DCD file " << dcdPosOutFile <<
".\n" <<
endi;
968 NAMD_err(
"Could not write QM charge DCD file.");
969 }
else if (! dcdPosOutFile) {
970 NAMD_bug(
"ComputeQMMgr::recvPartQM open_dcd_write returned fileid of zero");
975 int NSAVC, NFILE, NPRIV, NSTEP;
978 NSTEP = NPRIV - NSAVC;
982 int ret_code =
write_dcdheader(dcdPosOutFile, dcdPosOutFileStr.c_str(),
983 numQMAtms, NFILE, NPRIV, NSAVC, NSTEP,
987 NAMD_err(
"Writing of DCD header failed!!");
992 outputData =
new Real[3*numQMAtms];
997 int zeroNodeSize = CmiNumPesOnPhysicalNode(0);
1000 if ( zeroNodeSize < simsPerNode ) {
1001 iout <<
iERROR <<
"There are " << zeroNodeSize <<
" cores pernode, but " 1002 << simsPerNode <<
" QM simulations per node were requested.\n" <<
endi ;
1003 NAMD_die(
"Error preparing QM simulations.");
1006 DebugM(4,
"Preparing PE list for QM execution.\n");
1009 int numNodes = CmiNumPhysicalNodes();
1010 int numPlacedQMGrps = 0;
1011 int placedOnNode = 0;
1015 if ( simsPerNode <= 0 ) {
1017 numPlacedQMGrps = 1;
1020 while ( (numPlacedQMGrps < numQMGrps) && (simsPerNode > 0) ) {
1023 if (nodeIt == numNodes) {
1029 CmiGetPesOnPhysicalNode(CmiPhysicalNodeID(nodeIt), &pelist, &nodeSize);
1031 DebugM(4,
"Checking node " << nodeIt +1 <<
" out of " << numNodes
1032 <<
" (" << nodeSize <<
" PEs: " << pelist[0] <<
" to " 1033 << pelist[nodeSize-1] <<
")." << std::endl );
1035 for (
int i=0; i<nodeSize; ++i ) {
1039 DebugM(1,
"PE " << pelist[i] <<
" has no patches! We'll skip it." 1046 qmPEs.push_back(pelist[i]);
1048 DebugM(1,
"Added PE to QM execution list: " << pelist[i] <<
"\n");
1053 if (placedOnNode == simsPerNode) {
1054 DebugM(1,
"Placed enought simulations on this node.\n");
1065 if ( numPlacedQMGrps < numQMGrps ) {
1066 iout <<
iWARN <<
"Could not compute all QM groups in parallel.\n" <<
endi ;
1069 iout <<
iINFO <<
"List of ranks running QM simulations: " << qmPEs[0] ;
1070 for (
int i=1; i < qmPEs.size(); i++) {
1071 iout <<
", " << qmPEs[i] ;
1078 <<
" a total of " << msg->
numAtoms <<
" QM atoms." << std::endl);
1082 if (meNumMMIndx > 0) {
1087 for (
int i=0; i<msg->
numAtoms; i++) {
1088 if (data_ptr[i].vdwType < 0) {
1089 tmpAtm.
add(data_ptr[i]) ;
1100 if (tmpAtm.
size() > 0) {
1108 for (
int i=0; i<msg->
numAtoms; i++) {
1109 if (data_ptr[i].vdwType < 0) {
1112 newPCData->
id = data_ptr[i].
id ;
1115 newPCData->
dist = 0 ;
1116 newPCData->
mass = 0 ;
1121 *newMsgData = data_ptr[i] ;
1130 qmCoordMsgs[numArrivedQMMsg] = newMsg;
1133 pntChrgCoordMsgs[numArrivedPntChrgMsg] = pntChrgMsg;
1134 ++numArrivedPntChrgMsg;
1137 qmCoordMsgs[numArrivedQMMsg] = msg;
1141 if ( numArrivedQMMsg < numSources )
1145 for (
int msgIt=0; msgIt < numArrivedQMMsg; msgIt++){
1147 DebugM(1,
"Getting positions for " << qmCoordMsgs[msgIt]->numAtoms
1148 <<
" QM atoms in this message." << std::endl);
1150 for (
int i=0; i < qmCoordMsgs[msgIt]->
numAtoms; ++i ) {
1151 qmCoord[qmAtmIter] = qmCoordMsgs[msgIt]->
coord[i];
1156 if (qmAtmIter != numQMAtms) {
1157 iout <<
iERROR <<
"The number of QM atoms received (" << qmAtmIter
1158 <<
") is different than expected: " << numQMAtms <<
"\n" <<
endi;
1159 NAMD_err(
"Problems broadcasting QM atoms.");
1163 numArrivedQMMsg = 0;
1166 timeStep = qmCoordMsgs[0]->
timestep;
1171 for (
int i=0; i<numAtoms; ++i ) {
1180 for (
int i=0; i<numQMAtms; i++) {
1183 if (force[qmCoord[i].
id].homeIndx != -1
1184 && force[qmCoord[i].
id].homeIndx != qmCoord[i].homeIndx
1187 << qmCoord[i].
id <<
"; home index: " 1190 NAMD_die(
"Error preparing QM simulations.");
1197 force[qmCoord[i].
id].
replace = replaceForces;
1206 QMProxy[0].recvPntChrg(pntChrgMsg);
1212 int msgPCListSize = 0;
1214 if ( qmPCFreq > 0 ) {
1215 if (timeStep % qmPCFreq == 0) {
1219 resendPCList =
true;
1237 msgPCListSize = pcIDListSize;
1238 resendPCList =
false;
1247 DebugM(1,
"Broadcasting current positions of QM atoms.\n");
1248 for (
int j=0; j < numSources; ++j ) {
1256 int *msgPCListP = qmFullMsg->
pcIndxs;
1258 for (
int i=0; i<numQMAtms; i++) {
1261 data_ptr->
id = qmCoord[i].
id;
1267 for (
int i=0; i<msgPCListSize; i++) {
1268 msgPCListP[i] = pcIDList[i] ;
1273 Write_PDB(
"qmMsg.pdb", qmFullMsg) ;
1277 QMProxy[qmCoordMsgs[j]->
sourceNode].recvFullQM(qmFullMsg);
1284 if (subsArray.
size() > 0)
1290 typedef std::map<Real, std::pair<Position,BigReal> >
GrpDistMap ;
1312 DebugM(4,
"Rank " << CkMyPe() <<
" receiving from rank " << qmFullMsg->
sourceNode 1313 <<
" a total of " << qmFullMsg->
numAtoms <<
" QM atoms and " 1314 << qmFullMsg->
numPCIndxs <<
" PC IDs." << std::endl);
1321 pcIDSortList.
clear();
1323 int *pcIndx = qmFullMsg->
pcIndxs;
1324 for (
int i=0; i< qmFullMsg->
numPCIndxs;i++) {
1325 pcIDSortList.
load(pcIndx[i]);
1328 pcIDSortList.
sort();
1331 int totalNodeAtoms = 0;
1333 int uniqueCounter = 0;
1342 DebugM(4,
"Updating PC selection.\n")
1346 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
1349 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
1350 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
1351 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
1353 totalNodeAtoms += localNumAtoms;
1356 for(
int i=0; i<localNumAtoms; ++i) {
1361 Real pcGrpID = qmAtomGroup[xExt[i].
id];
1369 for (
int qi=0; qi<numQMAtms; qi++) {
1370 if (qmAtmIndx[qi] == xExt[i].
id) {
1371 charge = qmAtmChrg[qi];
1377 qmDataPtn = qmFullMsg->
coord;
1378 for(
int j=0; j<qmFullMsg->
numAtoms; j++, ++qmDataPtn) {
1391 if (qmGrpID == pcGrpID) {
1400 if ( dist < cutoff ){
1407 auto ret = chrgGrpMap.find(qmGrpID) ;
1415 if ( ret == chrgGrpMap.end()) {
1416 chrgGrpMap.insert(std::pair<Real,PosDistPair>(qmGrpID,
1424 if (dist < ret->second.second) {
1425 ret->second.first = posMM ;
1426 ret->second.second = dist ;
1432 for(
auto mapIt = chrgGrpMap.begin();
1433 mapIt != chrgGrpMap.end(); mapIt++) {
1440 mapIt->first, atomIter, mapIt->second.second,
1447 if (chrgGrpMap.size() > 0)
1453 (*pdIt).posBoxP->close(&x);
1461 DebugM(4,
"Updating PC positions ONLY.\n")
1463 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
1466 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
1467 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
1468 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
1470 totalNodeAtoms += localNumAtoms;
1473 for(
int i=0; i<localNumAtoms; ++i) {
1475 if (pcIDSortList.
find(xExt[i].
id) != NULL ) {
1480 bool firstIngroupQM =
true;
1481 qmDataPtn = qmFullMsg->
coord;
1482 for(
int j=0; j<qmFullMsg->
numAtoms; j++, ++qmDataPtn) {
1496 if ( firstIngroupQM ) {
1502 firstIngroupQM =
false;
1507 if ( r12.
length() < dist ) {
1509 posMM = qmDataPtn->
position + r12 ;
1514 Real pcGrpID = qmAtomGroup[xExt[i].
id];
1521 for (
int qi=0; qi<numQMAtms; qi++) {
1522 if (qmAtmIndx[qi] == xExt[i].
id) {
1523 charge = qmAtmChrg[qi];
1533 fullAtms[i].mass, fullAtms[i].vdwType));
1539 (*pdIt).posBoxP->close(&x);
1546 DebugM(4,
"Updating PC positions for custom PC selection.\n")
1548 for (
auto pdIt = patchData.begin(); pdIt != patchData.end(); pdIt++ ) {
1551 const CompAtomExt *xExt = (*pdIt).homePatchP->getCompAtomExtInfo();
1552 int localNumAtoms = (*pdIt).homePatchP->getNumAtoms();
1553 const FullAtom* fullAtms = (*pdIt).homePatchP->getAtomList().const_begin() ;
1555 totalNodeAtoms += localNumAtoms;
1558 for(
int i=0; i<localNumAtoms; ++i) {
1564 for (
int grpIndx=0; grpIndx<numQMGrps; grpIndx++) {
1566 if (customPCLists[grpIndx].find(xExt[i].
id) != NULL){
1578 bool firstIngroupQM =
true;
1579 qmDataPtn = qmFullMsg->
coord;
1580 for(
int j=0; j<qmFullMsg->
numAtoms; j++, ++qmDataPtn) {
1584 if ( qmDataPtn->
qmGrpID != qmGrpIDArray[grpIndx] )
continue;
1591 if ( firstIngroupQM ) {
1597 firstIngroupQM =
false;
1602 if ( r12.
length() < dist ) {
1604 posMM = qmDataPtn->
position + r12 ;
1610 Real pcGrpID = qmAtomGroup[xExt[i].
id];
1617 for (
int qi=0; qi<numQMAtms; qi++) {
1618 if (qmAtmIndx[qi] == xExt[i].
id) {
1619 charge = qmAtmChrg[qi];
1627 qmGrpIDArray[grpIndx], atomIter, dist,
1628 fullAtms[i].mass, fullAtms[i].vdwType));
1636 (*pdIt).posBoxP->close(&x);
1642 DebugM(4,
"Rank " << CkMyPe() <<
" found a total of " << compPCVec.
size()
1643 <<
" point charges, out of " << totalNodeAtoms
1644 <<
" atoms in this node. " << uniqueCounter <<
" are unique." << std::endl);
1651 pntChrgMsg->numAtoms = compPCVec.
size();
1653 for (
int i=0; i<compPCVec.
size(); i++ ) {
1659 pntChrgMsg->coord[i] = compPCVec[i] ;
1663 DebugM(4,
"Rank " << pntChrgMsg->sourceNode <<
" sending a total of " 1664 << compPCVec.
size() <<
" elements to rank zero." << std::endl);
1666 CProxy_ComputeQMMgr QMProxy(CkpvAccess(BOCclass_group).computeQMMgr);
1667 QMProxy[0].recvPntChrg(pntChrgMsg);
1674 void ComputeQMMgr::procBonds(
int numBonds,
1675 const int *
const qmGrpBondsGrp,
1676 const int *
const qmMMBondedIndxGrp,
1677 const int *
const *
const chargeTarget,
1678 const int *
const numTargs,
1682 DebugM(1,
"Processing QM-MM bonds in rank zero.\n");
1685 std::map<int, int> mmPntChrgMap ;
1690 for (
size_t i=0; i<grpPntChrgVec.size(); i++) {
1692 mmPntChrgMap.insert(std::pair<int,int>(grpPntChrgVec[i].
id, (
int) i) );
1694 grpAppldChrgVec.push_back( grpPntChrgVec[i] ) ;
1701 for (
int bondIt = 0; bondIt < numBonds; bondIt++) {
1704 int bondIndx = qmGrpBondsGrp[bondIt] ;
1706 auto retIt = mmPntChrgMap.find(qmMMBondedIndxGrp[bondIt]) ;
1710 if (retIt == mmPntChrgMap.end()) {
1713 iout <<
iERROR <<
"The MM atom " << qmMMBondedIndxGrp[bondIt]
1714 <<
" is bound to a QM atom, but it was not selected as a poitn charge." 1715 <<
" Check your cutoff radius!\n" <<
endi ;
1717 NAMD_die(
"Charge placement error in QM-MM bond.");
1721 int mmIndex = (*retIt).second;
1723 Position mmPos = grpAppldChrgVec[mmIndex].position ;
1724 BigReal mmCharge = grpAppldChrgVec[mmIndex].charge/numTargs[bondIndx] ;
1727 for (
int i=0; i<numTargs[bondIndx]; i++){
1729 int targetIndxGLobal = chargeTarget[bondIndx][i] ;
1731 retIt = mmPntChrgMap.find(targetIndxGLobal);
1735 if (retIt == mmPntChrgMap.end()) {
1737 iout <<
iERROR <<
"The MM atom " << targetIndxGLobal
1738 <<
" is bound to the MM atom of a QM-MM bond and is needed for" 1739 <<
" the required bond scheme" 1740 <<
" but it was not selected as a poitn charge." 1741 <<
" Check your cutoff radius!\n" <<
endi ;
1743 NAMD_die(
"Charge placement error in QM-MM bond.");
1746 int trgIndxLocal = (*retIt).second;
1770 Position trgPos = grpAppldChrgVec[trgIndxLocal].position ;
1774 grpAppldChrgVec[trgIndxLocal].qmGrpID = -2;
1775 grpAppldChrgVec[trgIndxLocal].homeIndx = mmIndex;
1784 grpAppldChrgVec.push_back(
1790 Vector bondVec = trgPos - mmPos ;
1796 Vector bondVec1 = bondVec*Cqp ;
1797 Vector bondVec2 = bondVec*Cqm ;
1799 Position chrgPos1 = mmPos + bondVec1;
1800 Position chrgPos2 = mmPos + bondVec2;
1803 BigReal trgChrg2 = -1*mmCharge;
1805 grpAppldChrgVec.push_back(
1809 grpAppldChrgVec.push_back(
1835 Position trgPos = grpAppldChrgVec[trgIndxLocal].position ;
1839 grpAppldChrgVec[trgIndxLocal].qmGrpID = -2;
1840 grpAppldChrgVec[trgIndxLocal].homeIndx = mmIndex;
1849 grpAppldChrgVec.push_back(
1855 Vector bondVec = trgPos - mmPos ;
1859 Vector bondVec1 = bondVec*Cq1 ;
1861 Position chrgPos1 = mmPos + bondVec1;
1863 BigReal trgChrg1 = 2*mmCharge;
1865 grpAppldChrgVec.push_back(
1893 grpAppldChrgVec[trgIndxLocal].charge = 0.0;
1904 grpAppldChrgVec[mmIndex].qmGrpID = -1 ;
1922 pntChrgCoordMsgs[numArrivedPntChrgMsg] = msg;
1923 ++numArrivedPntChrgMsg;
1925 if ( numArrivedPntChrgMsg < numSources )
1934 for (
int k=0; k<3; ++k )
1935 for (
int l=0; l<3; ++l )
1936 totVirial[k][l] = 0;
1940 const char *
const *
const elementArray = molPtr->
get_qmElements() ;
1946 const int *
const *
const qmMMBond = molPtr->
get_qmMMBond() ;
1956 if ( qmPCFreq > 0 ) {
1957 DebugM(4,
"Using point charge stride of " << qmPCFreq <<
"\n")
1962 if (timeStep % qmPCFreq == 0) {
1963 DebugM(4,
"Loading a new selection of PCs.\n")
1966 pntChrgMsgVec.clear();
1967 for (
int pcMsgIt=0; pcMsgIt < numArrivedPntChrgMsg; pcMsgIt++) {
1969 for (
int i=0; i < pntChrgCoordMsgs[pcMsgIt]->
numAtoms; ++i ) {
1970 pntChrgMsgVec.push_back(pntChrgCoordMsgs[pcMsgIt]->coord[i]);
1976 pcIDListSize = pntChrgMsgVec.size();
1977 pcIDList =
new int[pcIDListSize] ;
1978 for (
size_t i=0; i<pcIDListSize; i++) {
1979 pcIDList[i] = pntChrgMsgVec[i].id;
1984 force[pntChrgMsgVec[i].id].
homeIndx = pntChrgMsgVec[i].homeIndx;
1988 DebugM(4,
"Updating position/homeIdex of old PC selection.\n")
1994 for (
int pcMsgIt=0; pcMsgIt < numArrivedPntChrgMsg; pcMsgIt++) {
1996 for (
int i=0; i < pntChrgCoordMsgs[pcMsgIt]->
numAtoms; ++i ) {
1997 pcDataSort.
load(pntChrgCoordMsgs[pcMsgIt]->coord[i]);
2002 iout <<
"Loaded new positions in sorted array: " << pcDataSort.
size() <<
"\n" <<
endi;
2006 for (
size_t i=0; i<pntChrgMsgVec.size(); i++) {
2008 auto pntr = pcDataSort.
find(pntChrgMsgVec[i]);
2010 pntChrgMsgVec[i].position = pntr->position ;
2011 pntChrgMsgVec[i].homeIndx = pntr->homeIndx ;
2016 force[pntChrgMsgVec[i].id].
homeIndx = pntChrgMsgVec[i].homeIndx;
2021 DebugM(4,
"Updating PCs at every step.\n")
2023 pntChrgMsgVec.clear();
2024 for (
int pcMsgIt=0; pcMsgIt < numArrivedPntChrgMsg; pcMsgIt++) {
2026 for (
int i=0; i < pntChrgCoordMsgs[pcMsgIt]->
numAtoms; ++i ) {
2027 pntChrgMsgVec.push_back(pntChrgCoordMsgs[pcMsgIt]->coord[i]);
2032 for (
size_t i=0; i<pntChrgMsgVec.size(); i++) {
2037 if (force[pntChrgMsgVec[i].
id].homeIndx != -1
2038 and force[pntChrgMsgVec[i].
id].homeIndx != pntChrgMsgVec[i].homeIndx
2040 iout <<
iERROR <<
"Overloading point charge " 2041 << pntChrgMsgVec[i].id <<
"; home index: " 2042 << force[pntChrgMsgVec[i].id].
homeIndx <<
" with " << pntChrgMsgVec[i].homeIndx
2044 NAMD_die(
"Error preparing QM simulations.");
2048 force[pntChrgMsgVec[i].id].
homeIndx = pntChrgMsgVec[i].homeIndx;
2053 numArrivedPntChrgMsg = 0;
2055 DebugM(4,
"A total of " << pntChrgMsgVec.size()
2056 <<
" point charges arrived." << std::endl);
2058 DebugM(4,
"Starting QM groups processing.\n");
2069 std::vector<dummyData> dummyAtoms ;
2072 thisProxy[0].recvQMResLoop() ;
2077 for (
int grpIter = 0; grpIter < numQMGrps; grpIter++) {
2079 grpQMAtmVec.clear();
2080 grpPntChrgVec.clear();
2081 grpAppldChrgVec.clear();
2084 DebugM(4,
"Calculating QM group " << grpIter +1
2085 <<
" (ID: " << grpID[grpIter] <<
")." << std::endl);
2087 DebugM(4,
"Compiling Config Lines into one string for message...\n");
2091 std::string configLines ;
2093 for ( ; current; current = current->
next ) {
2094 std::string confLineStr(current->
data);
2098 std::ostringstream itosConv ;
2099 itosConv << grpChrg[grpIter] ;
2100 confLineStr.append(
" CHARGE=" );
2101 confLineStr.append( itosConv.str() );
2105 configLines.append(confLineStr);
2106 configLines.append(
"\n");
2111 DebugM(4,
"Determining point charges...\n");
2113 Real qmTotalCharge = 0;
2115 for (
int qmIt=0; qmIt<numQMAtms; qmIt++){
2116 if (qmCoord[qmIt].qmGrpID == grpID[grpIter]) {
2117 grpQMAtmVec.push_back(qmCoord[qmIt]);
2118 qmTotalCharge += qmCoord[qmIt].
charge;
2121 if ((fabsf(roundf(qmTotalCharge) - qmTotalCharge) <= 0.001f) ) {
2122 qmTotalCharge = roundf(qmTotalCharge) ;
2128 Real pcTotalCharge = 0;
2130 for (
auto pntChrgIt = pntChrgMsgVec.begin();
2131 pntChrgIt != pntChrgMsgVec.end(); pntChrgIt++) {
2132 if ((*pntChrgIt).qmGrpID == grpID[grpIter] ) {
2133 grpPntChrgVec.push_back( (*pntChrgIt) );
2134 pcTotalCharge += (*pntChrgIt).charge;
2137 if ((fabsf(roundf(pcTotalCharge) - pcTotalCharge) <= 0.001f) ) {
2138 pcTotalCharge = roundf(pcTotalCharge) ;
2142 if (grpQMAtmVec.size() != qmGrpSize[grpIter]) {
2143 iout <<
iERROR <<
"The number of QM atoms received for group " << grpID[grpIter]
2144 <<
" does not match the expected: " << grpQMAtmVec.size()
2145 <<
" vs " << qmGrpSize[grpIter] <<
"\n" <<
endi ;
2147 NAMD_die(
"Error processing QM group.");
2151 DebugM(1,
"Found " << grpPntChrgVec.size() <<
" point charges for QM group " 2152 << grpIter <<
" (ID: " << grpID[grpIter] <<
"; Num QM atoms: " 2153 << grpQMAtmVec.size() <<
"; Num QM-MM bonds: " 2154 << grpNumBonds[grpIter] <<
")" << std::endl);
2156 DebugM(1,
"Total QM charge: " << qmTotalCharge
2157 <<
"; Total point-charge charge: " << pcTotalCharge << std::endl);
2161 if ( qmLSSFreq > 0 && ((timeStep + 1) % qmLSSFreq == 0 )) {
2162 lssUpdate(grpIter, grpQMAtmVec, grpPntChrgVec);
2169 procBonds(grpNumBonds[grpIter], qmGrpBonds[grpIter],
2170 qmMMBondedIndx[grpIter],
2171 chargeTarget, numTargs,
2172 grpPntChrgVec, grpAppldChrgVec) ;
2175 grpAppldChrgVec = grpPntChrgVec;
2180 std::vector< std::pair<int,int> > qmPCLocalIndxPairs ;
2184 for (
int dummyIt = 0; dummyIt < grpNumBonds[grpIter]; dummyIt++) {
2186 int qmMMBondIndx = qmGrpBonds[grpIter][dummyIt] ;
2188 BigReal bondVal = dummyBondVal[qmMMBondIndx] ;
2190 int mmAtmIndx = qmMMBond[qmMMBondIndx][0] ;
2191 int qmAtmIndx = qmMMBond[qmMMBondIndx][1] ;
2197 bool missingQM =
true, missingMM =
true;
2200 for (qmIt=0; qmIt<grpQMAtmVec.size(); qmIt++){
2201 if (grpQMAtmVec[qmIt].
id == qmAtmIndx) {
2202 qmPos = grpQMAtmVec[qmIt].position;
2214 for (pcIt=0; pcIt < grpPntChrgVec.size(); pcIt++) {
2215 if (grpPntChrgVec[pcIt].
id == mmAtmIndx) {
2216 mmPos = grpPntChrgVec[pcIt].position ;
2226 qmPCLocalIndxPairs.push_back(std::pair<int,int>(qmIt, pcIt) );
2231 if ( missingMM or missingQM ) {
2235 iout <<
iERROR <<
"The MM atom " << mmAtmIndx
2236 <<
" is bound to a QM atom, but it was not selected as a poitn charge." 2237 <<
" Check your cutoff radius!\n" <<
endi ;
2239 NAMD_die(
"Error in QM-MM bond processing.");
2242 iout <<
iERROR <<
"The QM atom " << qmAtmIndx
2243 <<
" is bound to an MM atom, but it was not sent to rank zero for processing." 2244 <<
" Check your configuration!\n" <<
endi ;
2246 NAMD_die(
"Error in QM-MM bond processing.");
2251 Vector bondVec = mmPos - qmPos ;
2259 bondVec = bondVec.
unit() ;
2260 bondVec *= bondVal ;
2267 bondVec *= bondVal ;
2270 Position dummyPos = qmPos + bondVec;
2272 DebugM(1,
"Creating dummy atom " << dummyPos <<
" ; QM ind: " 2273 << qmIt <<
" ; PC ind: " << pcIt << std::endl);
2275 dummyAtoms.push_back(
dummyData(dummyPos, qmIt, qmMMBondIndx)) ;
2279 DebugM(3,
"Creating data for " << grpQMAtmVec.size() <<
" QM atoms " 2280 << dummyAtoms.size() <<
" dummy atoms " << grpPntChrgVec.size()
2281 <<
" real point charges and " << grpAppldChrgVec.size() - grpPntChrgVec.size()
2282 <<
" virtual point charges\n") ;
2284 int dataSize = grpQMAtmVec.size() + dummyAtoms.size() + grpAppldChrgVec.size();
2289 msg->
charge = grpChrg[grpIter];
2292 msg->
numAllAtoms = grpQMAtmVec.size() + dummyAtoms.size();
2320 for (
int i=0; i<grpQMAtmVec.size(); i++) {
2321 dataP->
position = grpQMAtmVec[i].position ;
2322 dataP->
charge = grpQMAtmVec[i].charge ;
2323 dataP->
id = grpQMAtmVec[i].id ;
2326 strncpy(dataP->
element,elementArray[grpQMAtmVec[i].id],3);
2330 for (
int i=0; i<dummyAtoms.size(); i++) {
2331 dataP->
position = dummyAtoms[i].pos ;
2336 strncpy(dataP->
element,dummyElmArray[dummyAtoms[i].bondIndx],3);
2340 for (
int i=0; i<grpAppldChrgVec.size(); i++) {
2341 dataP->
position = grpAppldChrgVec[i].position ;
2342 dataP->
charge = grpAppldChrgVec[i].charge ;
2344 dataP->
id = grpAppldChrgVec[i].id ;
2346 dataP->
dist = grpAppldChrgVec[i].dist ;
2350 if (i < grpPntChrgVec.size()) {
2351 if (grpAppldChrgVec[i].qmGrpID == -1) {
2354 else if (grpAppldChrgVec[i].qmGrpID == -2) {
2377 for(
auto vecPtr = qmPCLocalIndxPairs.begin();
2378 vecPtr != qmPCLocalIndxPairs.end();
2381 int qmLocInd = (*vecPtr).first;
2382 int pcLocInd = (*vecPtr).second;
2392 calcCSMD(grpIter, msg->
numQMAtoms, qmP, cSMDForces) ;
2394 int targetPE = qmPEs[peIter] ;
2396 DebugM(4,
"Sending QM group " << grpIter <<
" (ID " << grpID[grpIter]
2397 <<
") to PE " << targetPE << std::endl);
2403 QMProxy[targetPE].calcORCA(msg) ;
2407 QMProxy[targetPE].calcMOPAC(msg) ;
2411 QMProxy[targetPE].calcUSR(msg) ;
2417 if (peIter == qmPEs.size())
2447 for (
int k=0; k<3; ++k )
2448 for (
int l=0; l<3; ++l )
2449 totVirial[k][l] += resMsg->
virial[k][l];
2452 Real qmTotalCharge = 0;
2456 force[ fres[i].id ].
force += fres[i].force;
2459 if (fres[i].replace == 1) {
2460 force[ fres[i].id ].
charge = fres[i].charge;
2461 qmTotalCharge += fres[i].charge;
2465 if ((fabsf(roundf(qmTotalCharge) - qmTotalCharge) <= 0.001f) ) {
2466 qmTotalCharge = roundf(qmTotalCharge) ;
2471 for (
int i=0; i < cSMDindxLen[resMsg->
grpIndx]; i++ ) {
2472 int cSMDit = cSMDindex[resMsg->
grpIndx][i];
2473 force[ cSMDpairs[cSMDit][0] ].
force += cSMDForces[cSMDit];
2477 DebugM(4,
"QM total charge received is " << qmTotalCharge << std::endl);
2479 DebugM(4,
"Current accumulated energy is " << totalEnergy << std::endl);
2491 timeStep % simParams->
qmOutFreq == 0 ) {
2493 iout <<
iINFO <<
"Writing QM charge output at step " 2494 << timeStep <<
"\n" <<
endi;
2496 Real *x = outputData,
2500 for (
int qmIt=0; qmIt<numQMAtms; qmIt++){
2501 x[qmIt] = qmCoord[qmIt].
id;
2502 y[qmIt] = force[qmCoord[qmIt].
id].
charge ;
2514 iout <<
iINFO <<
"Writing QM position output at step " 2515 << timeStep <<
"\n" <<
endi;
2519 for(
int i=0; i<numQMAtms;i++) {
2524 Real *x = outputData,
2528 for (
int qmIt=0; qmIt<numQMAtms; qmIt++){
2529 x[qmIt] = qmCoord[idIndx[qmIt].indx].
position.
x;
2530 y[qmIt] = qmCoord[idIndx[qmIt].indx].
position.
y;
2531 z[qmIt] = qmCoord[idIndx[qmIt].indx].
position.
z;
2538 DebugM(4,
"Distributing QM forces for all ranks.\n");
2539 for (
int j=0; j < numSources; ++j ) {
2541 std::set<int> auxset0;
2542 DebugM(1,
"Sending forces and charges to source " << j << std::endl);
2548 int sourceNode = -1;
2550 if (pntChrgCoordMsgs == NULL) {
2552 qmmsg = qmCoordMsgs[j];
2560 pcmsg = pntChrgCoordMsgs[j];
2561 pntChrgCoordMsgs[j] = 0;
2568 for (
int aux=0; aux<numSources; aux++) {
2570 if (qmCoordMsgs[aux] == 0)
2573 qmmsg = qmCoordMsgs[aux];
2576 qmCoordMsgs[aux] = 0;
2581 DebugM(1,
"Building force mesage for rank " 2589 for (
int i=0; i < qmmsg->
numAtoms; ++i ) {
2590 auxset0.insert(qmmsg->
coord[i].
id);
2592 for (
int i=0; i < pcmsg->
numAtoms; ++i ) {
2593 auxset0.insert(pcmsg->
coord[i].
id);
2595 totForces = auxset0.size();
2603 DebugM(1,
"Loading QM forces.\n");
2608 for (
int i=0; i < qmmsg->
numAtoms; ++i ) {
2611 auxset0.insert(qmmsg->
coord[i].
id);
2616 if (pntChrgCoordMsgs != NULL) {
2617 DebugM(1,
"Loading PntChrg forces.\n");
2619 for (
int i=0; i < pcmsg->
numAtoms; ++i ) {
2621 if (auxset0.find(pcmsg->
coord[i].
id) == auxset0.end()) {
2624 auxset0.insert(pcmsg->
coord[i].
id);
2631 DebugM(1,
"A total of " << forceIter <<
" forces were loaded." << std::endl);
2633 for (
int i=0; i < subsArray.
size(); ++i ) {
2634 fmsg->
lssDat[i] = subsArray[i];
2638 if (subsArray.
size() > 0)
2639 DebugM(3,
"A total of " << subsArray.
size() <<
" LSS data structures were loaded." << std::endl);
2643 fmsg->
energy = totalEnergy;
2644 for (
int k=0; k<3; ++k )
2645 for (
int l=0; l<3; ++l )
2646 fmsg->
virial[k][l] = totVirial[k][l];
2649 for (
int k=0; k<3; ++k )
2650 for (
int l=0; l<3; ++l )
2654 DebugM(4,
"Sending forces...\n");
2656 QMProxy[sourceNode].recvForce(fmsg);
2660 DebugM(4,
"All forces sent from node zero.\n");
2678 bool callReplaceForces =
false;
2686 int totalNumbAtoms = 0;
2687 for (ap = ap.
begin(); ap != ap.
end(); ap++) {
2688 totalNumbAtoms += (*ap).p->getNumAtoms();
2698 delete [] oldForces;
2699 oldForces =
new ExtForce[totalNumbAtoms] ;
2701 for (
int i=0; i < totalNumbAtoms; ++i) {
2705 DebugM(1,
"Force array has been created and zeroed in rank " 2706 << CkMyPe() << std::endl);
2709 << CkMyPe() << std::endl);
2713 for (
int i=0; i < fmsg->
numForces; ++i, ++results_ptr) {
2720 if (results_ptr->
replace == 1)
2721 callReplaceForces =
true;
2725 if (qmAtomGroup[results_ptr->
id] > 0 && (fmsg->
PMEOn || (numQMGrps > 1) ) ) {
2728 for (
int qmIter=0; qmIter<numQMAtms; qmIter++) {
2730 if (qmAtmIndx[qmIter] == results_ptr->
id) {
2731 qmAtmChrg[qmIter] = results_ptr->
charge;
2741 DebugM(1,
"Placing forces on force boxes in rank " 2742 << CkMyPe() << std::endl);
2745 int homeIndxIter = 0;
2746 for (ap = ap.
begin(); ap != ap.
end(); ap++) {
2747 Results *r = (*ap).forceBox->open();
2749 const CompAtomExt *xExt = (*ap).p->getCompAtomExtInfo();
2750 int localNumAtoms = (*ap).p->getNumAtoms();
2752 for(
int i=0; i<localNumAtoms; ++i) {
2754 f[i] += oldForces[homeIndxIter].
force;
2759 if ( callReplaceForces )
2760 (*ap).p->replaceForces(oldForces);
2762 (*ap).forceBox->close(&r);
2766 DebugM(1,
"Forces placed on force boxes in rank " 2767 << CkMyPe() << std::endl);
2771 DebugM(1,
"PME ON! Accessing PMEmgr in rank " << CkMyPe() << std::endl);
2774 CkpvAccess(BOCclass_group).computePmeMgr) ;
2776 DebugM(4,
"Initiating ComputePme::doQMWork on rank " << CkMyPe() <<
" over " 2777 <<
getComputes(mgrP).size() <<
" pmeComputes." << std::endl) ;
2785 DebugM(1,
"Submitting reduction in rank " << CkMyPe() << std::endl);
2788 reduction->
item(REDUCTION_VIRIAL_NORMAL_XX) += fmsg->
virial[0][0];
2789 reduction->
item(REDUCTION_VIRIAL_NORMAL_XY) += fmsg->
virial[0][1];
2790 reduction->
item(REDUCTION_VIRIAL_NORMAL_XZ) += fmsg->
virial[0][2];
2791 reduction->
item(REDUCTION_VIRIAL_NORMAL_YX) += fmsg->
virial[1][0];
2792 reduction->
item(REDUCTION_VIRIAL_NORMAL_YY) += fmsg->
virial[1][1];
2793 reduction->
item(REDUCTION_VIRIAL_NORMAL_YZ) += fmsg->
virial[1][2];
2794 reduction->
item(REDUCTION_VIRIAL_NORMAL_ZX) += fmsg->
virial[2][0];
2795 reduction->
item(REDUCTION_VIRIAL_NORMAL_ZY) += fmsg->
virial[2][1];
2796 reduction->
item(REDUCTION_VIRIAL_NORMAL_ZZ) += fmsg->
virial[2][2];
2805 FILE *inputFile,*outputFile,*chrgFile;
2808 const size_t lineLen = 256;
2809 char *line =
new char[lineLen];
2811 std::string qmCommand, inputFileName, outputFileName, pntChrgFileName;
2818 DebugM(4,
"Running MOPAC on PE " << CkMyPe() << std::endl);
2833 pntChrgSwitching(msg, pcPpme) ;
2842 std::string baseDir(msg->
baseDir);
2843 std::ostringstream itosConv ;
2844 if ( CmiNumPartitions() > 1 ) {
2845 baseDir.append(
"/") ;
2846 itosConv << CmiMyPartition() ;
2847 baseDir += itosConv.str() ;
2851 if (stat(msg->
baseDir, &info) != 0 ) {
2852 CkPrintf(
"Node %d cannot access directory %s\n",
2853 CkMyPe(), baseDir.c_str() );
2854 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
2856 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
2857 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
2858 retVal = mkdir(baseDir.c_str(), S_IRWXU);
2862 baseDir.append(
"/") ;
2864 baseDir += itosConv.str() ;
2866 if (stat(msg->
baseDir, &info) != 0 ) {
2867 CkPrintf(
"Node %d cannot access directory %s\n",
2868 CkMyPe(), baseDir.c_str() );
2869 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
2871 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
2872 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
2873 retVal = mkdir(baseDir.c_str(), S_IRWXU);
2877 Write_PDB(std::string(baseDir)+
"/input.pdb", msg ) ;
2880 inputFileName.clear();
2881 inputFileName.append(baseDir.c_str()) ;
2882 inputFileName.append(
"/qmmm_") ;
2883 inputFileName += itosConv.str() ;
2884 inputFileName.append(
".input") ;
2887 inputFile = fopen(inputFileName.c_str(),
"w");
2888 if ( ! inputFile ) {
2889 iout <<
iERROR <<
"Could not open input file for writing: " 2890 << inputFileName <<
"\n" <<
endi ;
2891 NAMD_err(
"Error writing QM input file.");
2896 qmCommand.append(
"cd ");
2897 qmCommand.append(baseDir);
2898 qmCommand.append(
" ; ");
2900 qmCommand.append(
" ") ;
2901 qmCommand.append(inputFileName) ;
2902 qmCommand.append(
" > /dev/null 2>&1") ;
2906 outputFileName = inputFileName ;
2907 outputFileName.append(
".aux") ;
2911 pntChrgFileName.clear();
2912 pntChrgFileName.append(baseDir.c_str()) ;
2913 pntChrgFileName.append(
"/mol.in") ;
2915 chrgFile = fopen(pntChrgFileName.c_str(),
"w");
2917 iout <<
iERROR <<
"Could not open charge file for writing: " 2918 << pntChrgFileName <<
"\n" <<
endi ;
2919 NAMD_err(
"Error writing point charge file.");
2922 iret = fprintf(chrgFile,
"\n%d %d\n",
2924 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
2929 std::string confLineStr;
2930 while (std::getline(ss, confLineStr) ) {
2931 confLineStr.append(
"\n");
2932 iret = fprintf(inputFile,confLineStr.c_str());
2933 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
2937 iret = fprintf(inputFile,
"\n");
2938 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
2942 <<
" point charges in file " << pntChrgFileName.c_str() <<
"\n");
2946 for (
size_t i=0; i<msg->
numAllAtoms; ++i, ++atmP ) {
2952 iret = fprintf(inputFile,
"%s %f 1 %f 1 %f 1\n",
2954 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
2969 double charge = pcP->
charge;
2975 BigReal rij = sqrt((x-xMM)*(x-xMM) +
2984 phi = phi*constants ;
2986 iret = fprintf(chrgFile,
"%s %f %f %f %f\n",
2988 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
2992 DebugM(4,
"Closing input and charge file\n");
3001 std::string prepProc(msg->
prepProc) ;
3002 prepProc.append(
" ") ;
3003 prepProc.append(inputFileName) ;
3004 iret = system(prepProc.c_str());
3005 if ( iret == -1 ) {
NAMD_err(
"Error running preparation command for QM calculation."); }
3006 if ( iret ) {
NAMD_die(
"Error running preparation command for QM calculation."); }
3010 DebugM(4,
"Running command ->" << qmCommand.c_str() <<
"<-" << std::endl);
3011 iret = system(qmCommand.c_str());
3013 if ( iret == -1 ) {
NAMD_err(
"Error running command for QM forces calculation."); }
3014 if ( iret ) {
NAMD_die(
"Error running command for QM forces calculation."); }
3018 std::string secProc(msg->
secProc) ;
3019 secProc.append(
" ") ;
3020 secProc.append(inputFileName) ;
3024 secProc.append(
" ") ;
3025 secProc += itosConv.str() ;
3027 iret = system(secProc.c_str());
3028 if ( iret == -1 ) {
NAMD_err(
"Error running second command for QM calculation."); }
3029 if ( iret ) {
NAMD_die(
"Error running second command for QM calculation."); }
3041 DebugM(4,
"Reading QM data from file " << outputFileName.c_str() << std::endl);
3042 outputFile = fopen(outputFileName.c_str(),
"r");
3043 if ( ! outputFile ) {
3058 for (
int k=0; k<3; ++k )
3059 for (
int l=0; l<3; ++l )
3060 resMsg->
virial[k][l] = 0;
3066 resForce[i].force = 0;
3067 resForce[i].charge = 0 ;
3068 if (i < msg->numQMAtoms) {
3071 resForce[i].replace = 1 ;
3072 resForce[i].id = atmP->
id;
3078 resForce[i].replace = 0 ;
3079 resForce[i].
id = pcP->
id;
3091 size_t atmIndx = 0, gradCount = 0;
3092 Bool gradFields =
false, chargeFields =
false;
3093 Bool chargesRead =
false, gradsRead =
false;
3094 while ( fgets(line, lineLen, outputFile) != NULL){
3104 if ( strstr(line,
"HEAT_OF_FORMATION") != NULL ) {
3106 char strEnergy[14], *endPtr ;
3109 strncpy(strEnergy, line + 28, 13) ;
3110 strEnergy[13] =
'\0';
3114 resMsg->
energyOrig = strtod(strEnergy, &endPtr);
3115 if ( *endPtr ==
'D' ) {
3117 resMsg->
energyOrig = strtod(strEnergy, &endPtr);
3130 if ( strstr(line,
"ATOM_CHARGES") != NULL ) {
3132 chargeFields =
true;
3138 chargeFields =
false;
3142 chargeFields =
true;
3150 if ( strstr(line,
"GRADIENTS") != NULL ) {
3155 NAMD_die(
"Error reading QM forces file. Wrong number of atom charges");
3161 chargeFields = false ;
3169 if ( strstr(line,
"OVERLAP_MATRIX") != NULL ) {
3174 NAMD_die(
"Error reading QM forces file. Wrong number of gradients");
3187 while ((strIndx < (strlen(line)-9)) && (strlen(line)-1 >=9 ) ) {
3189 strncpy(result, line+strIndx,9) ;
3192 Real localCharge = atof(result);
3195 if (atmIndx < msg->numQMAtoms ) {
3196 atmP[atmIndx].
charge = localCharge;
3197 resForce[atmIndx].charge = localCharge;
3203 atmIndx < msg->numAllAtoms ) {
3206 atmP[atmIndx].
charge = localCharge;
3210 resForce[qmInd].charge += localCharge;
3219 chargeFields =
false;
3231 int numfirstline = sscanf(line,
"%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
3232 &buf[0],&buf[1],&buf[2],&buf[3],&buf[4],&buf[5],
3233 &buf[6],&buf[7],&buf[8],&buf[9]);
3234 gradLength = strlen(line)/numfirstline;
3236 while ((strIndx < (strlen(line)-gradLength)) && (strlen(line)-1 >= gradLength ) ) {
3238 strncpy(result, line+strIndx,gradLength) ;
3239 result[gradLength] =
'\0';
3241 gradient[gradCount] = atof(result);
3242 if (gradCount == 2) {
3244 if (atmIndx < msg->numQMAtoms ) {
3246 resForce[atmIndx].force.x = -1*gradient[0];
3247 resForce[atmIndx].force.y = -1*gradient[1];
3248 resForce[atmIndx].force.z = -1*gradient[2];
3257 atmIndx < msg->numAllAtoms ) {
3266 Real linkDist =
Vector(atmP[atmIndx].position -
3267 atmP[qmInd].position).
length() ;
3269 Force mmForce(0), qmForce(0),
3270 linkForce(gradient[0], gradient[1], gradient[2]);
3273 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
3275 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
3280 qmForce += (linkForce*((1 - linkDist/mmqmDist)*xuv +
3281 (xDelta)*base) )*xuv;
3283 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
3284 (yDelta)*base) )*yuv;
3286 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
3287 (zDelta)*base) )*zuv;
3290 mmForce += (linkForce*((linkDist/mmqmDist)*xuv -
3291 (xDelta)*base) )*xuv;
3293 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
3294 (yDelta)*base) )*yuv;
3296 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
3297 (zDelta)*base) )*zuv;
3299 resForce[qmInd].force += qmForce;
3300 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
3309 strIndx += gradLength;
3336 for (; atmIndx < msg->
numQMAtoms; atmIndx++) {
3339 for (
int qmIter=0; qmIter<globalNumQMAtoms; qmIter++) {
3341 if (qmAtmIndx[qmIter] == atmP[atmIndx].
id) {
3343 atmP[atmIndx].
charge = qmAtmChrg[qmIter];
3344 resForce[atmIndx].charge = qmAtmChrg[qmIter];
3352 for (
size_t j=msg->
numQMAtoms; j<msg->numAllAtoms; ++j ) {
3362 if (! (chargesRead && gradsRead) ) {
3363 NAMD_die(
"Error reading QM forces file. Not all data could be read!");
3384 std::vector<Force> qmElecForce ;
3386 qmElecForce.push_back(
Force(0) );
3398 Force totalForce(0);
3408 BigReal force = pntCharge*qmCharge*constants ;
3419 totalForce += force*rVec.
unit();
3422 qmElecForce[j] += -1*force*rVec.
unit();
3428 if (qmAtomGroup[pcP[i].
id] == 0) {
3431 resForce[pcIndx].force += totalForce;
3445 Force mm1Force = (1-Cq)*totalForce ;
3446 Force mm2Force = Cq*totalForce ;
3448 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
3449 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
3458 if (j < msg->numQMAtoms ) {
3459 resForce[j].force += qmElecForce[j];
3474 atmP[qmInd].position).
length() ;
3476 Force linkForce = qmElecForce[j];
3478 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
3480 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
3485 Force qmForce = (linkForce*((1 - linkDist/mmqmDist)*xuv +
3486 (xDelta)*base) )*xuv;
3488 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
3489 (yDelta)*base) )*yuv;
3491 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
3492 (zDelta)*base) )*zuv;
3495 Force mmForce = (linkForce*((linkDist/mmqmDist)*xuv -
3496 (xDelta)*base) )*xuv;
3498 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
3499 (yDelta)*base) )*yuv;
3501 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
3502 (zDelta)*base) )*zuv;
3504 resForce[qmInd].force += qmForce;
3505 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
3513 DebugM(1,
"Correcting forces and energy for PME.\n");
3516 BigReal TwoBySqrtPi = 1.12837916709551;
3517 pi_ewaldcof = TwoBySqrtPi * ewaldcof;
3524 const BigReal kq_i = p_i_charge * constants;
3526 for (
size_t j=i+1; j < msg->
numQMAtoms; j++) {
3537 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
3540 BigReal recip_energy = (1-tmp_b)/r;
3543 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
3546 BigReal energy = kq_i * p_j_charge * recip_energy ;
3548 Force fixForce = -1*kq_i*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
3559 resForce[i].force -= fixForce ;
3560 resForce[j].force -= -1*fixForce ;
3577 const BigReal kq_i = p_i_charge * constants;
3592 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
3595 BigReal recip_energy = (1-tmp_b)/r;
3598 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
3601 BigReal energy = kq_i * p_j_charge * recip_energy ;
3603 fixForce += -1*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
3614 resForce[pcIndx].force -= kq_i*fixForce ;
3624 for (
int k=0; k<3; ++k )
3625 for (
int l=0; l<3; ++l )
3626 resMsg->
virial[k][l] = -1*resForce[i].force[k]*atmP[i].
position[l];
3633 for (
int k=0; k<3; ++k )
3634 for (
int l=0; l<3; ++l )
3635 resMsg->
virial[k][l] = -1*resForce[pcIndx].force[k]*pcP[i].
position[l];
3641 QMProxy[0].recvQMRes(resMsg);
3653 FILE *inputFile,*outputFile,*chrgFile;
3656 const size_t lineLen = 256;
3657 char *line =
new char[lineLen];
3659 std::string qmCommand, inputFileName, outputFileName, pntChrgFileName, pcGradFilename;
3660 std::string tmpRedirectFileName, pcGradFileName;
3667 DebugM(4,
"Running ORCA on PE " << CkMyPe() << std::endl);
3681 pntChrgSwitching(msg, pcPpme) ;
3690 std::string baseDir(msg->
baseDir);
3691 std::ostringstream itosConv ;
3692 if ( CmiNumPartitions() > 1 ) {
3693 baseDir.append(
"/") ;
3694 itosConv << CmiMyPartition() ;
3695 baseDir += itosConv.str() ;
3699 if (stat(msg->
baseDir, &info) != 0 ) {
3700 CkPrintf(
"Node %d cannot access directory %s\n",
3701 CkMyPe(), baseDir.c_str() );
3702 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
3704 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
3705 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
3706 retVal = mkdir(baseDir.c_str(), S_IRWXU);
3710 baseDir.append(
"/") ;
3712 baseDir += itosConv.str() ;
3714 if (stat(msg->
baseDir, &info) != 0 ) {
3715 CkPrintf(
"Node %d cannot access directory %s\n",
3716 CkMyPe(), baseDir.c_str() );
3717 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
3719 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
3720 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
3721 int retVal = mkdir(baseDir.c_str(), S_IRWXU);
3725 Write_PDB(std::string(baseDir)+
"/input.pdb", msg ) ;
3728 inputFileName.clear();
3729 inputFileName.append(baseDir.c_str()) ;
3730 inputFileName.append(
"/qmmm_") ;
3731 inputFileName += itosConv.str() ;
3732 inputFileName.append(
".input") ;
3735 inputFile = fopen(inputFileName.c_str(),
"w");
3736 if ( ! inputFile ) {
3737 iout <<
iERROR <<
"Could not open input file for writing: " 3738 << inputFileName <<
"\n" <<
endi ;
3739 NAMD_err(
"Error writing QM input file.");
3744 qmCommand.append(
"cd ");
3745 qmCommand.append(baseDir);
3746 qmCommand.append(
" ; ");
3748 qmCommand.append(
" ") ;
3749 qmCommand.append(inputFileName) ;
3753 tmpRedirectFileName = inputFileName ;
3754 tmpRedirectFileName.append(
".TmpOut") ;
3756 qmCommand.append(
" > ") ;
3757 qmCommand.append(tmpRedirectFileName) ;
3761 outputFileName = inputFileName ;
3762 outputFileName.append(
".engrad") ;
3766 pcGradFilename = inputFileName ;
3767 pcGradFilename.append(
".pcgrad") ;
3771 pntChrgFileName = inputFileName ;
3772 pntChrgFileName.append(
".pntchrg") ;
3774 pcGradFileName = inputFileName;
3775 pcGradFileName.append(
".pcgrad");
3777 chrgFile = fopen(pntChrgFileName.c_str(),
"w");
3779 iout <<
iERROR <<
"Could not open charge file for writing: " 3780 << pntChrgFileName <<
"\n" <<
endi ;
3781 NAMD_err(
"Error writing point charge file.");
3784 int numPntChrgs = 0;
3790 iret = fprintf(chrgFile,
"%d\n", numPntChrgs);
3791 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
3796 std::string confLineStr;
3797 while (std::getline(ss, confLineStr) ) {
3798 confLineStr.append(
"\n");
3799 iret = fprintf(inputFile,confLineStr.c_str());
3800 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3804 iret = fprintf(inputFile,
"%%pointcharges \"%s\"\n", pntChrgFileName.c_str());
3805 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3808 iret = fprintf(inputFile,
"\n\n%%coords\n CTyp xyz\n");
3809 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3811 iret = fprintf(inputFile,
" Charge %f\n",msg->
charge);
3812 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3814 iret = fprintf(inputFile,
" Mult %f\n",msg->
multiplicity);
3815 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3817 iret = fprintf(inputFile,
" Units Angs\n coords\n\n");
3818 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3822 " point charges in file " << pntChrgFileName.c_str() <<
"\n");
3826 for (
size_t i=0; i<msg->
numAllAtoms; ++i, ++atmP ) {
3829 double y = atmP->position.y;
3830 double z = atmP->position.z;
3832 iret = fprintf(inputFile,
" %s %f %f %f\n",
3833 atmP->element,x,y,z);
3834 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3838 iret = fprintf(inputFile,
" end\nend\n");
3839 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
3849 double charge = pcP->
charge;
3855 iret = fprintf(chrgFile,
"%f %f %f %f\n",
3857 if ( iret < 0 ) {
NAMD_err(
"Error writing point charge file."); }
3863 DebugM(4,
"Closing input and charge file\n");
3868 std::string prepProc(msg->
prepProc) ;
3869 prepProc.append(
" ") ;
3870 prepProc.append(inputFileName) ;
3871 iret = system(prepProc.c_str());
3872 if ( iret == -1 ) {
NAMD_err(
"Error running preparation command for QM calculation."); }
3873 if ( iret ) {
NAMD_die(
"Error running preparation command for QM calculation."); }
3877 DebugM(4,
"Running command ->" << qmCommand.c_str() <<
"<-" << std::endl);
3878 iret = system(qmCommand.c_str());
3880 if ( iret == -1 ) {
NAMD_err(
"Error running command for QM forces calculation."); }
3881 if ( iret ) {
NAMD_die(
"Error running command for QM forces calculation."); }
3885 std::string secProc(msg->
secProc) ;
3886 secProc.append(
" ") ;
3887 secProc.append(inputFileName) ;
3891 secProc.append(
" ") ;
3892 secProc += itosConv.str() ;
3894 iret = system(secProc.c_str());
3895 if ( iret == -1 ) {
NAMD_err(
"Error running second command for QM calculation."); }
3896 if ( iret ) {
NAMD_die(
"Error running second command for QM calculation."); }
3908 DebugM(4,
"Reading QM data from file " << outputFileName.c_str() << std::endl);
3909 outputFile = fopen(outputFileName.c_str(),
"r");
3910 if ( ! outputFile ) {
3925 for (
int k=0; k<3; ++k )
3926 for (
int l=0; l<3; ++l )
3927 resMsg->
virial[k][l] = 0;
3933 resForce[i].force = 0;
3934 resForce[i].charge = 0 ;
3935 if (i < msg->numQMAtoms) {
3938 resForce[i].replace = 1 ;
3939 resForce[i].id = atmP->id;
3945 resForce[i].replace = 0 ;
3946 resForce[i].id = pcP->
id;
3955 size_t atmIndx = 0, gradCount = 0;
3956 int numAtomsInFile = 0;
3962 for (
int i = 0; i < 3; i++) {
3963 fgets(line, lineLen, outputFile);
3966 iret = fscanf(outputFile,
"%d\n", &numAtomsInFile);
3968 NAMD_die(
"Error reading QM forces file.");
3973 NAMD_die(
"Error reading QM forces file. Number of atoms in QM output\ 3974 does not match the expected.");
3979 for (
int i = 0; i < 3; i++) {
3980 fgets(line, lineLen, outputFile);
3983 iret = fscanf(outputFile,
"%lf\n", &resMsg->
energyOrig);
3985 NAMD_die(
"Error reading QM forces file.");
3997 for (
int i = 0; i < 3; i++) {
3998 fgets(line, lineLen, outputFile) ;
4009 iret = fscanf(outputFile,
"%lf\n", &gradient[gradCount]);
4010 if ( iret != 1 ) {
NAMD_die(
"Error reading QM forces file."); }
4012 if (gradCount == 2){
4017 if (atmIndx < msg->numQMAtoms ) {
4018 resForce[atmIndx].force.x = -1*gradient[0]*1185.82151;
4019 resForce[atmIndx].force.y = -1*gradient[1]*1185.82151;
4020 resForce[atmIndx].force.z = -1*gradient[2]*1185.82151;
4029 atmIndx < msg->numAllAtoms ) {
4032 int qmInd = atmP[atmIndx].bountToIndx ;
4033 int mmInd = atmP[qmInd].bountToIndx ;
4038 Real linkDist =
Vector(atmP[atmIndx].position - atmP[qmInd].position).
length() ;
4040 Force mmForce(0), qmForce(0), linkForce(gradient[0], gradient[1], gradient[2]);
4041 linkForce *= -1*1185.82151;
4043 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
4045 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
4046 Real xDelta = pcP[mmInd].
position.
x - atmP[qmInd].position.x;
4047 Real yDelta = pcP[mmInd].
position.
y - atmP[qmInd].position.y;
4048 Real zDelta = pcP[mmInd].
position.
z - atmP[qmInd].position.z;
4050 qmForce += (linkForce*((1 - linkDist/mmqmDist)*xuv +
4051 (xDelta)*base) )*xuv;
4053 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
4054 (yDelta)*base) )*yuv;
4056 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
4057 (zDelta)*base) )*zuv;
4060 mmForce += (linkForce*((linkDist/mmqmDist)*xuv -
4061 (xDelta)*base) )*xuv;
4063 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
4064 (yDelta)*base) )*yuv;
4066 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
4067 (zDelta)*base) )*zuv;
4069 resForce[qmInd].force += qmForce;
4070 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
4090 for (; atmIndx < msg->
numQMAtoms; atmIndx++) {
4093 for (
int qmIter=0; qmIter<globalNumQMAtoms; qmIter++) {
4095 if (qmAtmIndx[qmIter] == atmP[atmIndx].
id) {
4097 atmP[atmIndx].charge = qmAtmChrg[qmIter];
4098 resForce[atmIndx].charge = qmAtmChrg[qmIter];
4109 outputFile = fopen(tmpRedirectFileName.c_str(),
"r");
4110 if ( ! outputFile ) {
4111 iout <<
iERROR <<
"Could not find Redirect output file:" 4112 << tmpRedirectFileName << std::endl <<
endi;
4116 DebugM(4,
"Opened tmeporary output for charge reading: " << tmpRedirectFileName.c_str() <<
"\n");
4120 while ( fgets(line, lineLen, outputFile) != NULL){
4132 if ( strstr(line,
"MULLIKEN ATOMIC CHARGES") != NULL ) {
4141 if ( strstr(line,
"Sum of atomic charges") != NULL ) {
4146 strncpy(result, line + 31,12) ;
4149 DebugM(4,
"Total charge of QM region calculated by ORCA is: " 4150 << atof(result) << std::endl )
4158 if (lineState == 1) {
4164 if (lineState == 2) {
4166 strncpy(result, line+8,12) ;
4169 Real localCharge = atof(result);
4172 if (atmIndx < msg->numQMAtoms ) {
4173 atmP[atmIndx].charge = localCharge;
4174 resForce[atmIndx].charge = localCharge;
4180 atmIndx < msg->numAllAtoms ) {
4181 int qmInd = atmP[atmIndx].bountToIndx ;
4182 atmP[qmInd].charge += localCharge;
4183 resForce[qmInd].charge += localCharge;
4202 if ( strstr(line,
"CHELPG Charges") != NULL ) {
4211 if ( strstr(line,
"Total charge") != NULL ) {
4216 strncpy(result, line + 14,13) ;
4219 DebugM(4,
"Total charge of QM region calculated by ORCA is: " 4220 << atof(result) << std::endl )
4228 if (lineState == 1) {
4234 if (lineState == 2) {
4236 strncpy(result, line+12,15) ;
4239 Real localCharge = atof(result);
4242 if (atmIndx < msg->numQMAtoms ) {
4243 atmP[atmIndx].charge = localCharge;
4244 resForce[atmIndx].charge = localCharge;
4250 atmIndx < msg->numAllAtoms ) {
4251 int qmInd = atmP[atmIndx].bountToIndx ;
4252 atmP[qmInd].charge += localCharge;
4253 resForce[qmInd].charge += localCharge;
4293 outputFile = fopen(pcGradFileName.c_str(),
"r");
4294 if ( ! outputFile ) {
4295 iout <<
iERROR <<
"Could not find PC gradient output file:" 4296 << pcGradFileName << std::endl <<
endi;
4300 DebugM(4,
"Opened pc output for gradient reading: " << pcGradFileName.c_str() <<
"\n");
4302 int pcgradNumPC = 0, readPC = 0;
4303 iret = fscanf(outputFile,
"%d\n", &pcgradNumPC );
4305 NAMD_die(
"Error reading PC forces file.");
4307 DebugM(4,
"Found in pc gradient output: " << pcgradNumPC <<
" point charge grads.\n");
4315 Force totalForce(0);
4324 fgets(line, lineLen, outputFile);
4326 iret = sscanf(line,
"%lf %lf %lf\n", &totalForce[0], &totalForce[1], &totalForce[2] );
4328 NAMD_die(
"Error reading PC forces file.");
4333 totalForce *= -1185.82151;
4338 if (qmAtomGroup[pcP[i].
id] == 0) {
4341 resForce[pcIndx].force += totalForce;
4348 Force mm1Force(0), mm2Force(0);
4357 mm1Force = (1-Cq)*totalForce ;
4358 mm2Force = Cq*totalForce ;
4360 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
4361 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
4375 DebugM(1,
"Correcting forces and energy for PME.\n");
4378 BigReal TwoBySqrtPi = 1.12837916709551;
4379 pi_ewaldcof = TwoBySqrtPi * ewaldcof;
4383 BigReal p_i_charge = atmP[i].charge ;
4384 Position pos_i = atmP[i].position ;
4386 for (
size_t j=i+1; j < msg->
numQMAtoms; j++) {
4388 BigReal p_j_charge = atmP[j].charge ;
4390 Position pos_j = atmP[j].position ;
4397 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
4400 BigReal recip_energy = (1-tmp_b)/r;
4403 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
4405 const BigReal kq_i = p_i_charge * constants;
4408 BigReal energy = kq_i * p_j_charge * recip_energy ;
4410 Force fixForce = -1*kq_i*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
4420 resForce[i].force -= fixForce ;
4421 resForce[j].force -= -1*fixForce;
4436 const BigReal kq_i = p_i_charge * constants;
4442 BigReal p_j_charge = atmP[j].charge ;
4444 Position pos_j = atmP[j].position ;
4451 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
4454 BigReal recip_energy = (1-tmp_b)/r;
4457 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
4460 BigReal energy = kq_i * p_j_charge * recip_energy ;
4462 fixForce += -1*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
4474 resForce[pcIndx].force -= kq_i*fixForce ;
4479 DebugM(1,
"Determining virial...\n");
4486 for (
int k=0; k<3; ++k )
4487 for (
int l=0; l<3; ++l )
4488 resMsg->
virial[k][l] = -1*resForce[i].force[k]*atmP[i].position[l];
4495 for (
int k=0; k<3; ++k )
4496 for (
int l=0; l<3; ++l )
4497 resMsg->
virial[k][l] = -1*resForce[pcIndx].force[k]*pcP[i].
position[l];
4500 DebugM(1,
"End of QM processing. Sending result message.\n");
4503 QMProxy[0].recvQMRes(resMsg);
4514 FILE *inputFile,*outputFile;
4517 std::string qmCommand, inputFileName, outputFileName;
4522 DebugM(4,
"Running USER DEFINED SOFTWARE on PE " << CkMyPe() << std::endl);
4536 pntChrgSwitching(msg, pcPpme) ;
4545 std::string baseDir(msg->
baseDir);
4546 std::ostringstream itosConv ;
4547 if ( CmiNumPartitions() > 1 ) {
4548 baseDir.append(
"/") ;
4549 itosConv << CmiMyPartition() ;
4550 baseDir += itosConv.str() ;
4554 if (stat(msg->
baseDir, &info) != 0 ) {
4555 CkPrintf(
"Node %d cannot access directory %s\n",
4556 CkMyPe(), baseDir.c_str() );
4557 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
4559 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
4560 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
4561 retVal = mkdir(baseDir.c_str(), S_IRWXU);
4565 baseDir.append(
"/") ;
4567 baseDir += itosConv.str() ;
4569 if (stat(msg->
baseDir, &info) != 0 ) {
4570 CkPrintf(
"Node %d cannot access directory %s\n",
4571 CkMyPe(), baseDir.c_str() );
4572 NAMD_die(
"QM calculation could not be ran. Check your qmBaseDir!");
4574 else if (! (stat(baseDir.c_str(), &info) == 0 && S_ISDIR(info.st_mode)) ) {
4575 DebugM(4,
"Creating directory " << baseDir.c_str() << std::endl);
4576 int retVal = mkdir(baseDir.c_str(), S_IRWXU);
4580 Write_PDB(std::string(baseDir)+
"/input.pdb", msg ) ;
4583 inputFileName.clear();
4584 inputFileName.append(baseDir.c_str()) ;
4585 inputFileName.append(
"/qmmm_") ;
4586 inputFileName += itosConv.str() ;
4587 inputFileName.append(
".input") ;
4590 inputFile = fopen(inputFileName.c_str(),
"w");
4591 if ( ! inputFile ) {
4592 iout <<
iERROR <<
"Could not open input file for writing: " 4593 << inputFileName <<
"\n" <<
endi ;
4594 NAMD_err(
"Error writing QM input file.");
4599 qmCommand.append(
"cd ");
4600 qmCommand.append(baseDir);
4601 qmCommand.append(
" ; ");
4603 qmCommand.append(
" ") ;
4604 qmCommand.append(inputFileName) ;
4608 outputFileName = inputFileName ;
4609 outputFileName.append(
".result") ;
4611 int numPntChrgs = 0;
4617 iret = fprintf(inputFile,
"%d %d\n",msg->
numAllAtoms, numPntChrgs);
4618 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
4622 " point charges." << std::endl);
4626 for (
size_t i=0; i<msg->
numAllAtoms; ++i, ++atmP ) {
4629 double y = atmP->position.y;
4630 double z = atmP->position.z;
4632 iret = fprintf(inputFile,
"%f %f %f %s\n",
4633 x,y,z,atmP->element);
4634 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
4638 int numWritenPCs = 0;
4646 double charge = pcP->
charge;
4652 iret = fprintf(inputFile,
"%f %f %f %f\n",
4654 if ( iret < 0 ) {
NAMD_err(
"Error writing QM input file."); }
4659 DebugM(4,
"Closing input file\n");
4664 std::string prepProc(msg->
prepProc) ;
4665 prepProc.append(
" ") ;
4666 prepProc.append(inputFileName) ;
4667 iret = system(prepProc.c_str());
4668 if ( iret == -1 ) {
NAMD_err(
"Error running preparation command for QM calculation."); }
4669 if ( iret ) {
NAMD_die(
"Error running preparation command for QM calculation."); }
4673 DebugM(4,
"Running command ->" << qmCommand.c_str() <<
"<-" << std::endl);
4674 iret = system(qmCommand.c_str());
4676 if ( iret == -1 ) {
NAMD_err(
"Error running command for QM forces calculation."); }
4677 if ( iret ) {
NAMD_die(
"Error running command for QM forces calculation."); }
4681 std::string secProc(msg->
secProc) ;
4682 secProc.append(
" ") ;
4683 secProc.append(inputFileName) ;
4687 secProc.append(
" ") ;
4688 secProc += itosConv.str() ;
4690 iret = system(secProc.c_str());
4691 if ( iret == -1 ) {
NAMD_err(
"Error running second command for QM calculation."); }
4692 if ( iret ) {
NAMD_die(
"Error running second command for QM calculation."); }
4704 DebugM(4,
"Reading QM data from file " << outputFileName.c_str() << std::endl);
4705 outputFile = fopen(outputFileName.c_str(),
"r");
4706 if ( ! outputFile ) {
4721 for (
int k=0; k<3; ++k )
4722 for (
int l=0; l<3; ++l )
4723 resMsg->
virial[k][l] = 0;
4729 resForce[i].force = 0;
4730 resForce[i].charge = 0 ;
4731 if (i < msg->numQMAtoms) {
4734 resForce[i].replace = 1 ;
4735 resForce[i].id = atmP->id;
4741 resForce[i].replace = 0 ;
4742 resForce[i].id = pcP->
id;
4756 const size_t lineLen = 256;
4757 char *line =
new char[lineLen];
4759 fgets(line, lineLen, outputFile);
4762 iret = sscanf(line,
"%lf %i\n", &resMsg->
energyOrig, &usrPCnum);
4764 NAMD_die(
"Error reading energy from QM results file.");
4769 if (iret == 2 && numWritenPCs != usrPCnum) {
4770 iout <<
iERROR <<
"Number of point charges does not match what was provided!\n" <<
endi ;
4771 NAMD_die(
"Error reading QM results file.");
4775 double localForce[3];
4777 for (atmIndx = 0; atmIndx < msg->
numAllAtoms; atmIndx++) {
4779 iret = fscanf(outputFile,
"%lf %lf %lf %lf\n",
4785 NAMD_die(
"Error reading forces and charge from QM results file.");
4790 if (atmIndx < msg->numQMAtoms ) {
4792 resForce[atmIndx].force.x = localForce[0];
4793 resForce[atmIndx].force.y = localForce[1];
4794 resForce[atmIndx].force.z = localForce[2];
4796 atmP[atmIndx].charge = localCharge;
4797 resForce[atmIndx].charge = localCharge;
4806 atmIndx < msg->numAllAtoms ) {
4810 atmP[atmIndx].charge = localCharge;
4815 int qmInd = atmP[atmIndx].bountToIndx ;
4816 resForce[qmInd].charge += localCharge;
4820 int mmInd = atmP[qmInd].bountToIndx ;
4825 Real linkDist =
Vector(atmP[atmIndx].position -
4826 atmP[qmInd].position).
length() ;
4828 Force mmForce(0), qmForce(0),
4829 linkForce(localForce[0], localForce[1], localForce[2]);
4831 Vector base = (linkDist/(mmqmDist*mmqmDist*mmqmDist))*dir;
4833 Vector xuv(1,0,0), yuv(0,1,0), zuv(0,0,1);
4834 Real xDelta = pcP[mmInd].
position.
x - atmP[qmInd].position.x;
4835 Real yDelta = pcP[mmInd].
position.
y - atmP[qmInd].position.y;
4836 Real zDelta = pcP[mmInd].
position.
z - atmP[qmInd].position.z;
4838 qmForce += (linkForce*((1 - linkDist/mmqmDist)*xuv +
4839 (xDelta)*base) )*xuv;
4841 qmForce += (linkForce*((1 - linkDist/mmqmDist)*yuv +
4842 (yDelta)*base) )*yuv;
4844 qmForce += (linkForce*((1 - linkDist/mmqmDist)*zuv +
4845 (zDelta)*base) )*zuv;
4848 mmForce += (linkForce*((linkDist/mmqmDist)*xuv -
4849 (xDelta)*base) )*xuv;
4851 mmForce += (linkForce*((linkDist/mmqmDist)*yuv -
4852 (yDelta)*base) )*yuv;
4854 mmForce += (linkForce*((linkDist/mmqmDist)*zuv -
4855 (zDelta)*base) )*zuv;
4857 resForce[qmInd].force += qmForce;
4858 resForce[msg->
numQMAtoms + mmInd].force += mmForce;
4873 Force totalForce(0);
4882 iret = fscanf(outputFile,
"%lf %lf %lf\n",
4883 &totalForce[0], &totalForce[1], &totalForce[2]);
4885 NAMD_die(
"Error reading PC forces from QM results file.");
4891 if (qmAtomGroup[pcP[i].
id] == 0) {
4894 resForce[pcIndx].force += totalForce;
4901 Force mm1Force(0), mm2Force(0);
4910 mm1Force = (1-Cq)*totalForce ;
4911 mm2Force = Cq*totalForce ;
4913 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
4914 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
4932 for (; atmIndx < msg->
numQMAtoms; atmIndx++) {
4935 for (
int qmIter=0; qmIter<globalNumQMAtoms; qmIter++) {
4937 if (qmAtmIndx[qmIter] == atmP[atmIndx].
id) {
4939 atmP[atmIndx].charge = qmAtmChrg[qmIter];
4940 resForce[atmIndx].charge = qmAtmChrg[qmIter];
4948 for (
size_t j=msg->
numQMAtoms; j<msg->numAllAtoms; ++j ) {
4958 if (usrPCnum == 0) {
4974 Force totalForce(0);
4982 BigReal qmCharge = atmP[j].charge ;
4984 BigReal force = pntCharge*qmCharge*constants ;
4986 Position rVec = posMM - atmP[j].position ;
4995 totalForce += force*rVec.
unit();
5001 if (qmAtomGroup[pcP[i].
id] == 0) {
5004 resForce[pcIndx].force += totalForce;
5011 Force mm1Force(0), mm2Force(0);
5020 mm1Force = (1-Cq)*totalForce ;
5021 mm2Force = Cq*totalForce ;
5023 resForce[msg->
numQMAtoms + mm1Indx].force += mm1Force;
5024 resForce[msg->
numQMAtoms + mm2Indx].force += mm2Force;
5034 DebugM(1,
"Correcting forces and energy for PME.\n");
5037 BigReal TwoBySqrtPi = 1.12837916709551;
5038 pi_ewaldcof = TwoBySqrtPi * ewaldcof;
5042 BigReal p_i_charge = atmP[i].charge ;
5043 Position pos_i = atmP[i].position ;
5045 for (
size_t j=i+1; j < msg->
numQMAtoms; j++) {
5047 BigReal p_j_charge = atmP[j].charge ;
5049 Position pos_j = atmP[j].position ;
5056 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
5059 BigReal recip_energy = (1-tmp_b)/r;
5062 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
5064 const BigReal kq_i = p_i_charge * constants;
5067 BigReal energy = kq_i * p_j_charge * recip_energy ;
5069 Force fixForce = -1*kq_i*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
5079 resForce[i].force -= fixForce ;
5080 resForce[j].force -= -1*fixForce;
5095 const BigReal kq_i = p_i_charge * constants;
5101 BigReal p_j_charge = atmP[j].charge ;
5103 Position pos_j = atmP[j].position ;
5110 BigReal corr_gradient = pi_ewaldcof*exp(-(tmp_a*tmp_a))*r + tmp_b;
5113 BigReal recip_energy = (1-tmp_b)/r;
5116 BigReal recip_gradient = -(1-corr_gradient)/(r*r);
5119 BigReal energy = kq_i * p_j_charge * recip_energy ;
5121 fixForce += -1*p_j_charge*(recip_gradient/r)*(pos_i - pos_j) ;
5133 resForce[pcIndx].force -= kq_i*fixForce ;
5138 DebugM(1,
"Determining virial...\n");
5145 for (
int k=0; k<3; ++k )
5146 for (
int l=0; l<3; ++l )
5147 resMsg->
virial[k][l] = -1*resForce[i].force[k]*atmP[i].position[l];
5154 for (
int k=0; k<3; ++k )
5155 for (
int l=0; l<3; ++l )
5156 resMsg->
virial[k][l] = -1*resForce[pcIndx].force[k]*pcP[i].
position[l];
5159 DebugM(1,
"End of QM processing. Sending result message.\n");
5162 QMProxy[0].recvQMRes(resMsg);
5182 DebugM(1,
"Initiating point charge switching and processing in rank " 5183 << CkMyPe() <<
"\n" ) ;
5188 Real PCScaleCharge = 0;
5190 PCScaleCharge += pcP[i].
charge;
5192 DebugM(4,
"The initial total Point-Charge charge is " << PCScaleCharge
5193 <<
" before scaling type: " << msg->
switchType <<
"\n" );
5219 Real coef = 1- dist2;
5220 pcP[i].
charge *= coef*coef ;
5231 if (pcP[i].dist > swdist) {
5238 Real swdist2 = swdist*swdist;
5239 Real coef = (dist2 - cutoff2)*(dist2 - cutoff2) ;
5240 coef *= (cutoff2 + 2*dist2 - 3*swdist2) ;
5241 coef /= (cutoff2 - swdist2)*(cutoff2 - swdist2)*(cutoff2 - swdist2);
5251 PCScaleCharge += pcP[i].
charge;
5253 DebugM(4,
"The final total Point-Charge charge is " << PCScaleCharge
5254 <<
" after scaling.\n" );
5258 <<
" point charges were selected for point charge scheme " << msg->
pcScheme <<
"\n" );
5260 Real totalPCCharge = 0, correction = 0;
5266 totalPCCharge += pcP[i].
charge;
5268 DebugM(4,
"The total Point-Charge charge is " << totalPCCharge
5271 if ((fabsf(roundf(totalPCCharge) - totalPCCharge) <= 0.001f) ) {
5272 DebugM(4,
"Charge is already a whole number!\n" );
5275 correction = roundf(totalPCCharge) -totalPCCharge ;
5276 DebugM(4,
"Adding to system the charge: " << correction <<
"\n" );
5283 totalPCCharge += pcP[i].
charge;
5285 DebugM(4,
"The total Point-Charge charge is " << totalPCCharge <<
"\n");
5287 DebugM(4,
"Total QM system charge is: " << msg->
charge <<
"\n" );
5289 correction = -1*(totalPCCharge + msg->
charge);
5290 if ((fabsf(correction) <= 0.001f) ) {
5292 DebugM(4,
"Total QM + PC charge is already zero!\n" );
5295 DebugM(4,
"Adding a charge of " << correction <<
" to the system\n");
5300 if (correction != 0) {
5302 int maxi = sortedDists.
size(), mini = sortedDists.
size()/2;
5303 Real fraction = correction/(maxi - mini);
5305 DebugM(4,
"The charge fraction added to the " << (maxi - mini)
5306 <<
" most distant point charges is " << fraction <<
"\n");
5308 for (
size_t i=mini; i<maxi ; i++) {
5317 totalPCCharge += pcP[i].
charge;
5319 DebugM(4,
"The total Point-Charge charge is " << totalPCCharge
5326 void ComputeQMMgr::lssPrepare() {
5331 DebugM (4,
"Preparing LSS for " << numQMGrps <<
" QM groups.\n" )
5333 for (
int i=0; i<numQMGrps; i++) {
5334 lssTotRes += qmLSSSize[i];
5339 grpIDResNum.
resize(numQMGrps);
5343 lssGrpRefMass.
resize(numQMGrps);
5345 for (
int i=0; i<qmLSSResSize; i++)
5346 lssResMass += qmLSSMass[i];
5348 DebugM(4,
"Total residue mass is " << lssResMass <<
"\n" )
5352 int solvResBeg = 0, refAtmBeg = 0, locIter = 0, solvIndx = 0;
5353 int *lssIndxs, *refAtmsIndxs ;
5354 Mass *lssMasses, *refAtmMasses;
5355 while (locIter < numQMGrps) {
5356 lssIndxs = qmLSSIdxs + solvResBeg;
5358 DebugM (4,
"Loading atom IDs for QM group " << locIter
5359 <<
" with " << qmLSSSize[locIter]
5360 <<
" solvent molecules.\n" )
5367 lssMasses = qmLSSMass + solvResBeg;
5370 for (
int i=0; i<qmLSSSize[locIter]; i++) {
5372 lssPos[solvIndx] = 0;
5374 Debug(
iout <<
"Getting atom IDs from QM solvent molecule " 5375 << solvIndx <<
"\n") ;
5376 for (
int j=0; j<qmLSSResSize; j++) {
5378 int atmID = lssIndxs[i*qmLSSResSize + j];
5379 Mass atmMass = lssMasses[i*qmLSSResSize + j];
5380 Debug(
iout << atmID <<
" (" << atmMass <<
") ") ;
5391 refAtmsIndxs = qmLSSRefIDs + refAtmBeg;
5393 for (
int i=0; i<qmLSSRefSize[locIter]; i++) {
5394 lssGrpRefMass[locIter].
insert(
5395 refLSSData( refAtmsIndxs[i], refAtmMasses[i] )
5398 refAtmBeg += qmLSSRefSize[locIter] ;
5404 for (
int i=0; i<qmLSSSize[locIter]; i++) {
5406 lssPos[solvIndx] = 0;
5408 Debug(
iout <<
"Getting atom IDs from QM solvent molecule " 5409 << solvIndx <<
"\n") ;
5410 for (
int j=0; j<qmLSSResSize; j++) {
5412 int atmID = lssIndxs[i*qmLSSResSize + j];
5426 solvResBeg += qmLSSSize[locIter]*qmLSSResSize ;
5433 void ComputeQMMgr::lssUpdate(
int grpIter,
QMAtmVec& grpQMAtmVec,
5441 DebugM(3,
"LSS UPDATE...\n")
5443 int solvResBeg = 0 ;
5444 for (
int i=0; i<grpIter; i++)
5445 solvResBeg += qmLSSSize[i] ;
5451 DebugM(3,
"Using COM for LSS in group " << grpIter <<
"\n")
5454 for(
int i=0; i<grpQMAtmVec.size(); i++) {
5456 auto it = lssGrpRefMass[grpIter].
find(grpQMAtmVec[i].
id);
5457 if ( it != lssGrpRefMass[grpIter].end() ) {
5458 refCOM += grpQMAtmVec[i].position*it->second ;
5459 totMass += it->second ;
5464 DebugM ( 3,
"Reference COM position: " << refCOM <<
"\n");
5467 for (
int solvIter=solvResBeg; solvIter<solvResBeg+qmLSSSize[grpIter]; solvIter++) {
5468 lssPos[solvIter] = 0 ;
5471 DebugM(3,
"Calculating distance of QM solvent COM from reference COM of group.\n")
5478 for(
int i=0; i<grpQMAtmVec.size(); i++) {
5479 auto it = grpIDResNum[grpIter].
find(grpQMAtmVec[i].
id) ;
5480 if (it != grpIDResNum[grpIter].end()) {
5481 lssPos[it->second.resIndx] += grpQMAtmVec[i].position*it->second.mass ;
5484 auto itRes = resQMDist.find(it->second.resIndx) ;
5485 if (itRes == resQMDist.end() ) {
5486 resQMDist.insert(std::pair<int,lssDistSort >(
5495 resQMDist[it->second.resIndx].idIndx.add(
idIndxStr(grpQMAtmVec[i].
id,i)) ;
5499 DebugM(3,
"QM Solvent molecules " << solvResBeg
5500 <<
" to " << solvResBeg+qmLSSSize[grpIter] <<
"\n")
5503 for (
int solvIter=solvResBeg; solvIter<solvResBeg+qmLSSSize[grpIter]; solvIter++) {
5505 resQMDist[solvIter].dist = dist ;
5506 solvDist.
add(resQMDist[solvIter]);
5510 DebugM(3,
"We loaded the following QM solvent residues and distances:\n")
5511 for (
int i=0; i<solvDist.size(); i++) {
5512 iout << i <<
") type: " << solvDist[i].type
5513 <<
" dist " << solvDist[i].dist
5515 for (
int j=0; j<solvDist[i].idIndx.
size(); j++)
5516 iout << solvDist[i].idIndx[j].ID <<
" " ;
5526 std::map<int,lssDistSort > resPCSize ;
5528 for(
int i=0; i<grpPntChrgVec.size(); i++) {
5531 auto it = molPtr->
get_qmMMSolv().find(grpPntChrgVec[i].
id) ;
5535 auto itRes = resPCSize.find(it->second) ;
5536 if (itRes == resPCSize.end() ) {
5537 resPCSize.insert(std::pair<int,lssDistSort >(
5546 resPCSize[it->second].idIndx.add(
idIndxStr(grpPntChrgVec[i].
id,i)) ;
5553 for (
auto it=resPCSize.begin(); it!=resPCSize.end(); it++) {
5555 if (it->second.idIndx.size() == qmLSSResSize) {
5562 for (
int i=0; i<it->second.idIndx.size(); i++) {
5567 currCOM += grpPntChrgVec[it->second.idIndx[i].indx].position*grpPntChrgVec[it->second.idIndx[i].indx].mass;
5568 totalMass += grpPntChrgVec[it->second.idIndx[i].indx].mass;
5570 currCOM /= totalMass;
5574 it->second.dist = currDist ;
5576 solvDist.
add(it->second) ;
5584 DebugM(3,
"Using minimal distances for LSS in group " << grpIter <<
"\n")
5586 DebugM(3, "QM Solvent molecules " << solvResBeg
5587 << " to " << solvResBeg+qmLSSSize[grpIter] << "\n")
5597 for(
int i=0; i<grpQMAtmVec.size(); i++) {
5599 auto it = grpIDResNum[grpIter].
find(grpQMAtmVec[i].
id) ;
5600 if (it != grpIDResNum[grpIter].end()) {
5603 auto itRes = resQMDist.find(it->second.resIndx) ;
5604 if (itRes == resQMDist.end() ) {
5605 resQMDist.insert(std::pair<int,lssDistSort >(
5614 resQMDist[it->second.resIndx].idIndx.add(
idIndxStr(grpQMAtmVec[i].
id,i)) ;
5624 for (
auto it=resQMDist.begin(); it != resQMDist.end(); it++) {
5628 it->second.dist =
Vector(
5629 grpQMAtmVec[it->second.idIndx[0].indx].position -
5630 grpQMAtmVec[qmRefIndx[0]].position
5633 for (
int i=0; i<it->second.idIndx.size(); i++) {
5635 for(
int j=0; j<qmRefIndx.size(); j++) {
5637 grpQMAtmVec[it->second.idIndx[i].indx].position -
5638 grpQMAtmVec[qmRefIndx[j]].position
5641 if (currDist < it->second.dist)
5642 it->second.dist = currDist;
5648 solvDist.
add(it->second) ;
5653 DebugM(3,
"We loaded the following QM solvent residues and distances:\n")
5654 for (
int i=0; i<solvDist.size(); i++) {
5655 iout << i <<
") type: " << solvDist[i].type
5656 <<
" dist " << solvDist[i].dist
5658 for (
int j=0; j<solvDist[i].idIndx.
size(); j++)
5659 iout << solvDist[i].idIndx[j].ID <<
" " ;
5669 std::map<int,lssDistSort > resPCSize ;
5671 for(
int i=0; i<grpPntChrgVec.size(); i++) {
5674 auto it = molPtr->
get_qmMMSolv().find(grpPntChrgVec[i].
id) ;
5678 auto itRes = resPCSize.find(it->second) ;
5679 if (itRes == resPCSize.end() ) {
5680 resPCSize.insert(std::pair<int,lssDistSort >(
5689 resPCSize[it->second].idIndx.add(
idIndxStr(grpPntChrgVec[i].
id,i)) ;
5696 for (
auto it=resPCSize.begin(); it!=resPCSize.end(); it++) {
5698 if (it->second.idIndx.size() == qmLSSResSize) {
5702 it->second.dist =
Vector(
5703 grpPntChrgVec[it->second.idIndx[0].indx].position -
5704 grpQMAtmVec[qmRefIndx[0]].position
5707 for (
int i=0; i<it->second.idIndx.size(); i++) {
5709 for(
int j=0; j<qmRefIndx.size(); j++) {
5711 grpPntChrgVec[it->second.idIndx[i].indx].position -
5712 grpQMAtmVec[qmRefIndx[j]].position
5715 if (currDist < it->second.dist)
5716 it->second.dist = currDist;
5720 solvDist.
add(it->second) ;
5730 DebugM(3,
"Final selection of solvent residues and distances:\n")
5731 for (
int i=0; i<qmLSSSize[grpIter]; i++) {
5736 typeS =
"Classical";
5737 iout << i <<
") type: " << typeS
5738 <<
" dist " << solvDist[i].dist
5740 for (
int j=0; j<solvDist[i].idIndx.
size(); j++)
5741 iout << solvDist[i].idIndx[j].ID <<
" " ;
5749 DebugM(3,
"Determining residues to be swaped...\n")
5753 for (
int resIter = 0; resIter < qmLSSSize[grpIter] ; resIter++) {
5755 nearMM.add(solvDist[resIter]);
5759 for (
int resIter=qmLSSSize[grpIter]; resIter<solvDist.
size(); resIter++) {
5761 farQM.add(solvDist[resIter]);
5764 if (farQM.size() == nearMM.size())
break;
5767 if (farQM.size() != nearMM.size())
5768 NAMD_die(
"Could not find complementing residues to be swapped in LSS.") ;
5771 DebugM(3,
"Removing the following QM residues:\n")
5772 for (
int i=0; i<farQM.size();i++) {
5777 typeS =
"Classical";
5778 iout << i <<
") type: " << typeS
5779 <<
" dist " << farQM[i].dist
5781 for (
int j=0; j<farQM[i].idIndx.size(); j++)
5782 iout << farQM[i].idIndx[j].ID <<
" " ;
5786 DebugM(3,
"Replacing with the following Classical residues:\n")
5787 for (
int i=0; i<nearMM.size();i++) {
5792 typeS =
"Classical";
5793 iout << i <<
") type: " << typeS
5794 <<
" dist " << nearMM[i].dist
5796 for (
int j=0; j<nearMM[i].idIndx.size(); j++)
5797 iout << nearMM[i].idIndx[j].ID <<
" " ;
5801 DebugM(3,
"Building substitution array...\n")
5804 iout <<
iINFO <<
"LSS is swapping " << farQM.size() <<
" solvent residues in QM group " 5805 << grpIter <<
"\n" <<
endi;
5810 for (
int i=0; i<farQM.size();i++) {
5812 for(
int j=0; j<qmLSSResSize; j++) {
5814 int qIndx= farQM[i].idIndx[j].indx;
5815 int mIndx= nearMM[i].idIndx[j].indx;
5818 grpPntChrgVec[mIndx].
id,
5819 grpPntChrgVec[mIndx].vdwType,
5820 grpPntChrgVec[mIndx].charge ) );
5823 grpQMAtmVec[qIndx].
id,
5824 grpQMAtmVec[qIndx].vdwType,
5825 grpQMAtmVec[qIndx].charge ) );
5831 for(
int i=0; i<subsArray.
size() ;i++) {
5832 DebugM(3, CkMyPe() <<
") Storing LSS atom " << subsArray[i].origID
5833 <<
" Which will become " << subsArray[i].newID
5834 <<
" - " << subsArray[i].newVdWType
5835 <<
" - " << subsArray[i].newCharge <<
"\n" );
5842 void ComputeQMMgr::calcCSMD(
int grpIndx,
int numQMAtoms,
const QMAtomData *atmP,
Force *cSMDForces) {
5846 for (
int i=0; i < cSMDindxLen[grpIndx]; i++ ) {
5853 int cSMDit = cSMDindex[grpIndx][i] ;
5854 AtomID src = -1, trgt = -1;
5857 for (
size_t indx=0; indx < numQMAtoms; ++indx) {
5859 if ( cSMDpairs[cSMDit][0] == atmP[indx].
id )
5862 if ( cSMDpairs[cSMDit][1] == atmP[indx].
id )
5865 if (src != -1 && trgt != -1)
5871 tdist = trgtDir.
length();
5875 if (cSMDInitGuides < cSMDnumInstances) {
5876 cSMDguides[cSMDit] = atmP[src].
position;
5882 if (tdist > cSMDcoffs[cSMDit]) {
5884 cSMDguides[cSMDit] += trgtDir*cSMDVels[cSMDit];
5889 guideDir *= cSMDKs[cSMDit] ;
5890 cSMDforce = guideDir ;
5896 cSMDguides[cSMDit] = atmP[src].
position;
5899 DebugM(4, cSMDit <<
") Center at " << cSMDguides[cSMDit] <<
" for target distance " <<
5900 tdist <<
" and direction " << trgtDir <<
5904 cSMDForces[cSMDit] = cSMDforce;
5906 iout <<
iINFO <<
"Calculated cSMD force vector " << cSMDforce
5907 <<
" (atom " << cSMDpairs[cSMDit][0] <<
" to " << cSMDpairs[cSMDit][1] <<
")\n" <<
endi;
5915 void ComputeQMMgr::Write_PDB(std::string Filename,
const QMGrpCalcMsg *dataMsg)
5917 std::ofstream OutputTmpPDB ;
5922 OutputTmpPDB.open( Filename.c_str(), std::fstream::out );
5924 OutputTmpPDB <<
"REMARK Information used by NAMD to create the QM simulation." << std::endl ;
5925 OutputTmpPDB <<
"REMARK Occupancy: bount to index; Beta: System ID; " << std::endl ;
5939 std::string name(
" x ");
5940 std::string resName (
" uk");
5941 std::string chainName(
"X");
5942 std::string element(
"") ;
5943 if (i < dataMsg->numAllAtoms ) {
5962 OutputTmpPDB <<
"ATOM " ;
5964 OutputTmpPDB.width(5) ;
5965 OutputTmpPDB.right ;
5968 OutputTmpPDB <<
" " ;
5970 OutputTmpPDB.width(4) ;
5971 OutputTmpPDB << name ;
5973 OutputTmpPDB <<
" " ;
5975 OutputTmpPDB.width(4) ;
5976 OutputTmpPDB << resName ;
5978 OutputTmpPDB.width(1) ;
5979 OutputTmpPDB << chainName ;
5981 OutputTmpPDB.width(4) ;
5984 OutputTmpPDB <<
" " ;
5986 OutputTmpPDB <<
" " ;
5988 OutputTmpPDB.width(8) ;
5989 OutputTmpPDB.right ;
5990 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
5991 OutputTmpPDB.precision(3) ;
5994 OutputTmpPDB.width(8) ;
5995 OutputTmpPDB.right ;
5996 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
5997 OutputTmpPDB.precision(3) ;
6000 OutputTmpPDB.width(8) ;
6001 OutputTmpPDB.right ;
6002 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6003 OutputTmpPDB.precision(3) ;
6006 OutputTmpPDB.width(6) ;
6007 OutputTmpPDB.right ;
6008 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6009 OutputTmpPDB.precision(2) ;
6012 OutputTmpPDB.width(6) ;
6013 OutputTmpPDB.right ;
6014 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6015 OutputTmpPDB.precision(2) ;
6016 OutputTmpPDB << dataP[i].
id ;
6018 OutputTmpPDB.width(6) ;
6019 OutputTmpPDB <<
" " ;
6021 OutputTmpPDB.width(4) ;
6023 OutputTmpPDB <<
"QM ";
6025 OutputTmpPDB.width(2) ;
6026 OutputTmpPDB.right ;
6027 OutputTmpPDB << element ;
6029 OutputTmpPDB.width(2) ;
6030 OutputTmpPDB.right ;
6031 OutputTmpPDB << dataP[i].
charge ;
6033 OutputTmpPDB << std::endl;
6037 OutputTmpPDB <<
"END" << std::endl;
6039 OutputTmpPDB.close();
6045 throw "Generic exception!" ;
6050 void ComputeQMMgr::Write_PDB(std::string Filename,
const QMCoordMsg *dataMsg)
6052 std::ofstream OutputTmpPDB ;
6057 OutputTmpPDB.open( Filename.c_str(), std::fstream::out );
6059 OutputTmpPDB <<
"REMARK Information used by NAMD to create the QM simulation." << std::endl ;
6060 OutputTmpPDB <<
"REMARK Occupancy: bount to index; Beta: System ID; " << std::endl ;
6064 for (
int i=0 ; i < dataMsg->
numAtoms; i++ )
6074 std::string name(
" x ");
6075 std::string resName (
" atm");
6076 std::string chainName(
"X");
6077 std::string element(
"") ;
6079 OutputTmpPDB <<
"ATOM " ;
6081 OutputTmpPDB.width(5) ;
6082 OutputTmpPDB.right ;
6085 OutputTmpPDB <<
" " ;
6087 OutputTmpPDB.width(4) ;
6088 OutputTmpPDB << name ;
6090 OutputTmpPDB <<
" " ;
6092 OutputTmpPDB.width(4) ;
6093 OutputTmpPDB << resName ;
6095 OutputTmpPDB.width(1) ;
6096 OutputTmpPDB << chainName ;
6098 OutputTmpPDB.width(4) ;
6101 OutputTmpPDB <<
" " ;
6103 OutputTmpPDB <<
" " ;
6105 OutputTmpPDB.width(8) ;
6106 OutputTmpPDB.right ;
6107 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6108 OutputTmpPDB.precision(3) ;
6111 OutputTmpPDB.width(8) ;
6112 OutputTmpPDB.right ;
6113 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6114 OutputTmpPDB.precision(3) ;
6117 OutputTmpPDB.width(8) ;
6118 OutputTmpPDB.right ;
6119 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6120 OutputTmpPDB.precision(3) ;
6123 OutputTmpPDB.width(6) ;
6124 OutputTmpPDB.right ;
6125 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6126 OutputTmpPDB.precision(2) ;
6127 OutputTmpPDB << dataP[i].
qmGrpID ;
6129 OutputTmpPDB.width(6) ;
6130 OutputTmpPDB.right ;
6131 OutputTmpPDB.setf(std::ios::fixed,std::ios::floatfield) ;
6132 OutputTmpPDB.precision(2) ;
6133 OutputTmpPDB << dataP[i].
id ;
6135 OutputTmpPDB.width(6) ;
6136 OutputTmpPDB <<
" " ;
6138 OutputTmpPDB.width(4) ;
6140 OutputTmpPDB <<
"QM ";
6142 OutputTmpPDB.width(2) ;
6143 OutputTmpPDB.right ;
6144 OutputTmpPDB << element ;
6146 OutputTmpPDB.width(2) ;
6147 OutputTmpPDB.right ;
6148 OutputTmpPDB << dataP[i].
charge ;
6150 OutputTmpPDB << std::endl;
6154 OutputTmpPDB <<
"END" << std::endl;
6156 OutputTmpPDB.close();
6162 throw "Generic exception!" ;
6169 #include "ComputeQMMgr.def.h"
int insert(const Elem &elem, int index)
lssDistSort(const lssDistSort &ref)
BigReal PMEEwaldCoefficient
std::ostream & iINFO(std::ostream &s)
std::map< int, Mass > LSSRefMap
ComputeQMPntChrg(Position posInit, float chrgInit, int idInit, Real qmInit, int hiInit, Real newDist, Mass newM, int newvdwType)
const int * get_qmMMNumTargs()
void NAMD_err(const char *err_msg)
void recvPartQM(QMCoordMsg *)
void setCompute(ComputeQM *c)
ComputeQMAtom(Position posInit, float chrgInit, int idInit, Real qmInit, int hiInit, int newvdwType)
SortedArray< LSSSubsDat > & lssSubs(ComputeQMMgr *mgr)
idIndxStr & operator=(const idIndxStr &ref)
const int * get_qmGrpNumBonds()
bool operator==(const idIndxStr &ref) const
const int * get_qmAtmIndx()
std::pair< Position, BigReal > PosDistPair
static PatchMap * Object()
SimParameters * simParameters
ComputeHomePatchList patchList
const int *const * get_qmMMBondedIndx()
#define QMPCTYPE_CLASSICAL
std::ostream & endi(std::ostream &s)
char qmPrepProc[NAMD_FILENAME_BUFFER_SIZE]
std::ostream & iWARN(std::ostream &s)
SubmitReduction * willSubmit(int setID, int size=-1)
bool operator<(const idIndxStr &ref)
idIndxStr(const idIndxStr &ref)
ResizeArrayIter< T > begin(void) const
dummyData(Position newPos, int newQmInd, int newIndx)
static ReductionMgr * Object(void)
int const * get_cSMDindxLen()
SortedArray< idIndxStr > idIndx
void storeQMRes(QMGrpResMsg *)
void recvPntChrg(QMPntChrgMsg *)
int add(const Elem &elem)
SortedArray< LSSSubsDat > & get_subsArray()
std::map< int, int > & get_qmMMSolv()
const char *const * get_qmDummyElement()
Molecule stores the structural information for the system.
char qmExecPath[NAMD_FILENAME_BUFFER_SIZE]
char outputFilename[NAMD_FILENAME_BUFFER_SIZE]
int open_dcd_write(const char *dcdname)
const int *const * get_qmGrpBonds()
int const *const * get_cSMDpairs()
char qmSecProc[NAMD_FILENAME_BUFFER_SIZE]
lssDistSort(int newType, Real newDist)
static char * QMETITLE(int X)
int index(const Elem &elem)
pntChrgDist(int newIndx, Real newDist)
int insert(const Elem &elem)
int add(const Elem &elem)
lssDistSort & operator=(const lssDistSort &ref)
std::pair< int, Mass > refLSSData
int operator<(const pntChrgDist &v)
bool operator<(const lssDistSort &ref)
ResizeArray< ComputePme * > & getComputes(ComputePmeMgr *mgr)
NAMD_HOST_DEVICE BigReal length(void) const
void NAMD_bug(const char *err_msg)
void recvFullQM(QMCoordMsg *)
int write_dcdstep(int fd, int N, float *X, float *Y, float *Z, double *cell)
const int *const * get_qmMMBond()
bool operator==(const ComputeQMPntChrg &ref)
NAMD_HOST_DEVICE BigReal length2(void) const
int load(const Elem &elem)
idIndxStr(int newID, int newIndx)
std::vector< ComputeQMPntChrg > QMPCVec
bool custom_ComputeQMAtom_Less(const ComputeQMAtom a, const ComputeQMAtom b)
const Real * get_qmAtomGroup() const
BigReal PMEEwaldCoefficient
bool operator<(const ComputeQMPntChrg &ref)
const Real * get_cSMDcoffs()
void NAMD_die(const char *err_msg)
static char * FORMAT(BigReal X)
void calcORCA(QMGrpCalcMsg *)
const int *const * get_qmMMChargeTarget()
int * get_qmCustPCSizes()
int write_dcdheader(int fd, const char *filename, int N, int NFILE, int NPRIV, int NSAVC, int NSTEP, double DELTA, int with_unitcell)
void processFullQM(QMCoordMsg *)
const char *const * get_qmElements()
Bool qmMOPACAddConfigChrg
void calcUSR(QMGrpCalcMsg *)
void saveResults(QMForceMsg *)
void calcMOPAC(QMGrpCalcMsg *)
const Real * get_cSMDKs()
void recvForce(QMForceMsg *)
virtual void initialize()
bool operator!=(const idIndxStr &ref) const
Elem * find(const Elem &elem)
int find(const Elem &e) const
bool operator==(const lssDistSort &ref)
std::map< Real, std::pair< Position, BigReal > > GrpDistMap
std::pair< int, LSSDataStr > atmLSSData
int * get_qmCustomPCIdxs()
const Real * get_cSMDVels()
ComputeQMAtom(const ComputeQMAtom &ref)
int get_qmNumGrps() const
std::ostream & iERROR(std::ostream &s)
StringList * find(const char *name) const
void close_dcd_write(int fd)
LSSDataStr(int newResIndx, Mass newMass)
int const *const * get_cSMDindex()
Mass * get_qmLSSRefMass()
char qmBaseDir[NAMD_FILENAME_BUFFER_SIZE]
NAMD_HOST_DEVICE Vector unit(void) const
ResizeArrayIter< T > end(void) const
ComputeQMPntChrg(const ComputeQMPntChrg &ref)
const BigReal * get_qmDummyBondVal()
QMAtomData(Position posInit, float chrgInit, int idInit, int bountToIndxInit, int newType, char *elementInit, Real newDist)
#define QMLSSCLASSICALRES
std::map< int, LSSDataStr > LSSDataMap
NAMD_HOST_DEVICE Vector delta(const Position &pos1, const Position &pos2) const
const int * get_qmGrpSizes()
std::vector< ComputeQMAtom > QMAtmVec