31 #define MIN_DEBUG_LEVEL 3 39 #ifndef CODE_REDUNDANT 40 #define CODE_REDUNDANT 0 61 const char* newSegName,
Real newQMID) {
66 atmIDs.push_back(newBegAtm) ;
74 std::vector<std::string>
split(
const std::string &text, std::string delimiter) {
76 std::vector<std::string> tokens;
77 std::size_t start = 0, end = 0;
79 while ((end = text.find(delimiter, start)) != std::string::npos) {
81 std::string temp = text.substr(start, end - start);
83 if (! temp.empty()) tokens.push_back(temp);
85 start = end + delimiter.length();
89 std::string temp = text.substr(start);
90 if (! temp.empty()) tokens.push_back(temp);
112 #ifdef MEM_OPT_VERSION 113 NAMD_die(
"QMMM interface is not supported in memory optimized builds.");
122 iout <<
iINFO <<
"Using the following PDB file for QM parameters: " <<
123 pdbFileName <<
"\n" <<
endi;
125 pdbP =
new PDB(pdbFileName);
127 iout <<
"pdbFile name not defined!\n\n" <<
endi ;
131 NAMD_die(
"Number of atoms in QM parameter PDB file doesn't match coordinate PDB");
134 qmElementArray =
new char*[
numAtoms] ;
141 std::set<Real> atmGrpSet;
143 std::vector<Real> grpChrgVec;
146 std::vector<BigReal> qmBondValVec;
148 std::vector<Real> qmGroupIDsVec;
151 std::map<Real,int> qmGrpIDMap ;
153 std::vector<int> qmAtmIndxVec, qmGrpSizeVec;
156 std::vector<std::string> strVec;
158 qmNoPC = simParams->
qmNoPC;
170 qmLSSTotalNumAtms = 0;
172 std::map<Real,std::vector<int> > lssGrpRefIDs;
174 int totalNumRefAtms = 0;
175 int lssClassicResIndx = 0 ;
176 int lssCurrClassResID = -1 ;
177 char lssCurrClassResSegID[5];
179 DebugM(4,
"LSS is ON! Processing QM solvent.\n") ;
181 if (resLookup == NULL)
182 NAMD_die(
"We need residue data to conduct LSS.");
187 for ( ; current; current = current->
next ) {
189 strVec =
split( std::string(current->
data) ,
" ");
191 if (strVec.size() != 3 ) {
192 iout <<
iERROR <<
"Format error in QM LSS size: " 195 NAMD_die(
"Error processing QM information.");
198 std::stringstream storConv ;
200 storConv << strVec[0] ;
203 if (storConv.fail()) {
204 iout <<
iERROR <<
"Error parsing QMLSSRef selection: " 207 NAMD_die(
"Error processing QM information.");
210 std::string segName = strVec[1].substr(0,4);
213 storConv << strVec[2];
216 if (storConv.fail()) {
217 iout <<
iERROR <<
"Error parsing QMLSSRef selection: " 220 NAMD_die(
"Error processing QM information.");
223 auto it = lssRefUsrSel.find(grpID) ;
224 if (it == lssRefUsrSel.end())
227 lssRefUsrSel[grpID].push_back(
refSelStr(segName, resID));
230 for (
auto it=lssRefUsrSel.begin(); it!=lssRefUsrSel.end(); it++) {
231 iout <<
iINFO <<
"LSS user selection for COM composition of group " 232 << it->first <<
":\n" <<
endi ;
233 for (
int i=0; i<it->second.size();i++) {
234 iout <<
iINFO <<
"Segment " << it->second[i].segid
235 <<
" ; residue " << it->second[i].resid <<
"\n" <<
endi ;
247 for (
int atmInd = 0 ; atmInd <
numAtoms; atmInd++) {
255 if ( strcmp(simParams->
qmColumn,
"beta") == 0 ){
266 qmBondValVec.push_back(bondVal);
270 if ( strcmp(simParams->
qmColumn,
"beta") == 0 ){
280 qmAtomGroup[atmInd] = atmGrp;
284 qmElementArray[atmInd] =
new char[3];
285 strncpy(qmElementArray[atmInd],pdbP->
atom(atmInd)->
element(),3);
292 if ( fixedAtomFlags[atmInd] == 1 ) {
293 iout <<
iERROR <<
"QM atom cannot be fixed in space!\n" 295 NAMD_die(
"Error processing QM information.");
302 if (simParams->
qmVDW) {
304 std::string qmType(qmElementArray[atmInd]) ;
307 std::remove_if(qmType.begin(), qmType.end(), isspace ),
310 qmType = std::string(
"q") + qmType;
327 qmAtmIndxVec.push_back(atmInd);
329 auto retVal = atmGrpSet.insert(atmGrp);
336 qmGrpIDMap.insert(std::pair<BigReal,int>(atmGrp, qmNumGrps));
339 qmGroupIDsVec.push_back(atmGrp);
347 qmGrpSizeVec.push_back(1);
351 grpChrgVec.push_back( atoms[atmInd].charge );
356 qmGrpSizeVec[ qmGrpIDMap[atmGrp] ]++ ;
359 grpChrgVec[ qmGrpIDMap[atmGrp] ] += atoms[atmInd].
charge;
373 resLookup->
lookup(segName,resID,&i, &end);
382 resP->
atmIDs.push_back(atmInd) ;
401 auto itNewGrp = lssGrpRefIDs.find(atmGrp) ;
402 if (itNewGrp == lssGrpRefIDs.end()) {
403 lssGrpRefIDs.insert(std::pair<
Real, std::vector<int> >(
404 atmGrp, std::vector<int>() ) );
414 for(
int i=0; i<lssRefUsrSel[atmGrp].size(); i++) {
415 if (lssRefUsrSel[atmGrp][i].resid == resID &&
416 strncmp(lssRefUsrSel[atmGrp][i].segid.c_str(),
419 lssGrpRefIDs[atmGrp].push_back(atmInd);
429 lssGrpRefIDs[atmGrp].push_back(atmInd);
440 else if (atmGrp == 0) {
451 if (lssCurrClassResID < 0) {
452 lssCurrClassResID = resID ;
453 strncpy(lssCurrClassResSegID, segName,5);
454 lssClassicResIndx = 0;
456 else if (lssCurrClassResID != resID ||
457 strcmp(lssCurrClassResSegID, segName) != 0 ) {
458 lssCurrClassResID = resID ;
459 strncpy(lssCurrClassResSegID, segName,5);
463 qmClassicSolv.insert(std::pair<int,int>(atmInd,lssClassicResIndx));
468 else if(atmGrp < 0) {
469 iout <<
iERROR <<
"QM group ID cannot be less than zero!\n" <<
endi;
470 NAMD_die(
"Error processing QM information.");
476 if (lssGrpRes.
size() == 0)
477 NAMD_die(
"LSS was activated but there are no QM solvent molecules!\n");
479 for (
auto it=lssRefUsrSel.begin(); it!=lssRefUsrSel.end(); it++) {
480 auto itTarget = qmGrpIDMap.find(it->first);
481 if (itTarget == qmGrpIDMap.end()) {
482 iout <<
iERROR <<
"QM group ID for LSS could not be found in input!" 483 <<
" QM group ID: " << it->first <<
"\n" <<
endi;
484 NAMD_die(
"Error processing QM information.");
488 DebugM(3,
"We found " << lssClassicResIndx <<
" classical solvent molecules totalling " 489 << qmClassicSolv.size() <<
" atoms.\n" );
493 qmNumQMAtoms = qmAtmIndxVec.size();
495 if (qmNumQMAtoms == 0)
496 NAMD_die(
"No QM atoms were found in this QM simulation!") ;
498 iout <<
iINFO <<
"Number of QM atoms (excluding Dummy atoms): " <<
499 qmNumQMAtoms <<
"\n" <<
endi;
501 qmAtmChrg =
new Real[qmNumQMAtoms] ;
502 qmAtmIndx =
new int[qmNumQMAtoms] ;
503 for (
int i=0; i<qmNumQMAtoms; i++) {
507 qmAtmIndx[i] = qmAtmIndxVec[i] ;
513 std::map<int, std::vector<std::pair<int,int> > > qmGrpIDBonds ;
523 for (
int bndIt = 0; bndIt <
numBonds; bndIt++) {
525 bond curr = bonds[bndIt] ;
527 bool storeBond = false ;
534 if ((qmAtomGroup[curr.
atom1] == 0 || qmAtomGroup[curr.
atom2] == 0) &&
535 (qmAtomGroup[curr.
atom1] != qmAtomGroup[curr.
atom2]))
547 if (qmBondValVec[curr.
atom1] != 0 &&
548 qmBondValVec[curr.
atom2] != 0 ) {
553 if (qmAtomGroup[curr.
atom1] != 0 &&
554 qmAtomGroup[curr.
atom2] != 0) {
556 <<
" and " << curr.
atom2 <<
557 " are assigned as QM atoms.\n" <<
endi;
562 if (qmAtomGroup[curr.
atom1] == 0 &&
563 qmAtomGroup[curr.
atom2] == 0) {
565 <<
" and " << curr.
atom2 <<
566 " are assigned as MM atoms.\n" <<
endi;
575 std::pair<int,int> newPair(0,0);
578 if (qmAtomGroup[curr.
atom1] != 0) {
579 newPair = std::pair<int,int>(curr.
atom2, curr.
atom1) ;
580 currGrpID = qmAtomGroup[curr.
atom1];
582 newPair = std::pair<int,int>(curr.
atom1, curr.
atom2) ;
583 currGrpID = qmAtomGroup[curr.
atom2];
586 int grpIndx = qmGrpIDMap[currGrpID] ;
589 auto retIter = qmGrpIDBonds.find(grpIndx) ;
592 if (retIter == qmGrpIDBonds.end()) {
593 qmGrpIDBonds.insert(std::pair<
BigReal,std::vector<std::pair<int,int> > >(
594 grpIndx, std::vector<std::pair<int,int> >() ) );
597 qmGrpIDBonds[grpIndx].push_back( newPair );
607 if (bondCounter == 0)
608 iout <<
iWARN <<
"We found " << bondCounter <<
" QM-MM bonds.\n" <<
endi ;
610 iout <<
iINFO <<
"We found " << bondCounter <<
" QM-MM bonds.\n" <<
endi ;
615 qmNumBonds = bondCounter ;
617 qmMMBond =
new int*[qmNumBonds];
619 qmDummyBondVal =
new BigReal[qmNumBonds];
621 qmMMChargeTarget =
new int*[qmNumBonds] ;
622 qmMMNumTargs =
new int[qmNumBonds] ;
624 qmDummyElement =
new char*[qmNumBonds] ;
627 qmNumGrps = atmGrpSet.size();
629 qmGrpSizes =
new int[qmNumGrps];
631 qmGrpID =
new Real[qmNumGrps];
633 qmGrpChrg =
new Real[qmNumGrps];
635 qmGrpMult =
new Real[qmNumGrps] ;
637 qmGrpNumBonds =
new int[qmNumGrps];
639 qmGrpBonds =
new int*[qmNumGrps];
640 qmMMBondedIndx =
new int*[qmNumGrps];
649 for (
int grpIter = 0; grpIter < qmNumGrps; grpIter++) {
650 qmGrpMult[grpIter] = 0;
655 for ( ; current; current = current->
next ) {
657 auto strVec =
split( std::string(current->
data) ,
" ");
659 if (strVec.size() != 2 ) {
660 iout <<
iERROR <<
"Format error in QM Multiplicity string: " 663 NAMD_die(
"Error processing QM information.");
666 std::stringstream storConv ;
668 storConv << strVec[0] ;
671 if (storConv.fail()) {
672 iout <<
iERROR <<
"Error parsing QMMult selection: " 675 NAMD_die(
"Error processing QM information.");
679 storConv << strVec[1];
681 storConv >> multiplicity;
682 if (storConv.fail()) {
683 iout <<
iERROR <<
"Error parsing QMMult selection: " 686 NAMD_die(
"Error processing QM information.");
689 auto it = qmGrpIDMap.find(grpID);
691 if (it == qmGrpIDMap.end()) {
692 iout <<
iERROR <<
"Error parsing QMMult selection. Could not find QM group ID: " 695 NAMD_die(
"Error processing QM information.");
698 iout <<
iINFO <<
"Applying user defined multiplicity " 699 << multiplicity <<
" to QM group ID " << grpID <<
"\n" <<
endi;
700 qmGrpMult[it->second] = multiplicity;
707 NAMD_die(
"ORCA neds multiplicity values for all QM regions.");
715 for (
size_t grpIndx = 0; grpIndx < qmGrpSizeVec.size(); grpIndx++) {
717 bool nonInteger =
true;
718 if ((fabsf(roundf(grpChrgVec[grpIndx]) - grpChrgVec[grpIndx]) <= 0.001f) ) {
719 grpChrgVec[grpIndx] = roundf(grpChrgVec[grpIndx]) ;
723 iout <<
iINFO << grpIndx + 1 <<
") Group ID: " << qmGroupIDsVec[grpIndx]
724 <<
" ; Group size: " << qmGrpSizeVec[grpIndx] <<
" atoms" 725 <<
" ; Total PSF charge: " << grpChrgVec[grpIndx] <<
"\n" <<
endi ;
727 if (nonInteger && simParams->
PMEOn)
728 NAMD_die(
"QM atoms do not add up to a whole charge, which is needed for PME.") ;
732 current = cfgList->
find(
"QMCharge");
733 for ( ; current; current = current->
next ) {
735 auto strVec =
split( std::string(current->
data) ,
" ");
737 if (strVec.size() != 2 ) {
738 iout <<
iERROR <<
"Format error in QM Charge string: " 741 NAMD_die(
"Error processing QM information.");
744 std::stringstream storConv ;
746 storConv << strVec[0] ;
749 if (storConv.fail()) {
750 iout <<
iERROR <<
"Error parsing QMCharge selection: " 753 NAMD_die(
"Error processing QM information.");
757 storConv << strVec[1];
760 if (storConv.fail()) {
761 iout <<
iERROR <<
"Error parsing QMCharge selection: " 764 NAMD_die(
"Error processing QM information.");
767 auto it = qmGrpIDMap.find(grpID);
769 if (it == qmGrpIDMap.end()) {
770 iout <<
iERROR <<
"Error parsing QMCharge selection. Could not find QM group ID: " 773 NAMD_die(
"Error processing QM information.");
776 iout <<
iINFO <<
"Found user defined charge " 777 << charge <<
" for QM group ID " << grpID <<
". Will ignore PSF charge.\n" <<
endi;
778 grpChrgVec[it->second] = charge;
790 std::string::size_type chrgLoc = std::string::npos ;
793 std::string configLine(cfgList->
find(
"QMConfigLine")->
data) ;
794 chrgLoc = configLine.find(
"CHARGE") ;
796 if ( chrgLoc != std::string::npos ) {
797 iout <<
iINFO <<
"Found user defined charge in command line. This \ 798 will be used for all QM regions and will take precedence over all other charge \ 799 definitions.\n" <<
endi;
801 else if ( chrgLoc == std::string::npos && (simParams->
qmChrgFromPSF || chrgCount == qmNumGrps) ) {
812 iout <<
iERROR <<
"Could not find charge for all QM groups. For MOPAC, \ 813 charges can be defined through QMConfigLine, QMCharge or QMChargeFromPSF keywords.\n" <<
endi;
814 NAMD_die(
"Error processing QM information.");
820 if ((chrgCount != qmNumGrps ) && !simParams->
qmChrgFromPSF) {
824 iout <<
iERROR <<
"Could not find charge for all QM groups. For ORCA, \ 825 charges can be defined through QMCharge or QMChargeFromPSF keywords.\n" <<
endi;
826 NAMD_die(
"Error processing QM information.");
832 if (qmNumBonds > 0 && qmNoPC) {
833 qmMeNumBonds = qmNumBonds;
834 qmMeMMindx =
new int[qmMeNumBonds] ;
835 qmMeQMGrp =
new Real[qmMeNumBonds] ;
849 for (
int grpIter = 0; grpIter < qmNumGrps; grpIter++) {
851 qmGrpID[grpIter] = qmGroupIDsVec[grpIter] ;
853 qmGrpSizes[grpIter] = qmGrpSizeVec[grpIter] ;
855 qmGrpChrg[grpIter] = grpChrgVec[grpIter];
859 int currNumbBonds = qmGrpIDBonds[grpIter].size() ;
862 qmGrpNumBonds[grpIter] = currNumbBonds;
864 if (currNumbBonds > 0) {
866 qmGrpBonds[grpIter] =
new int[currNumbBonds];
867 qmMMBondedIndx[grpIter] =
new int[currNumbBonds];
869 for (
int bndIter = 0; bndIter<currNumbBonds; bndIter++) {
872 qmMMBond[bondCounter] =
new int[2] ;
873 qmMMBond[bondCounter][0] = qmGrpIDBonds[grpIter][bndIter].first ;
874 qmMMBond[bondCounter][1] = qmGrpIDBonds[grpIter][bndIter].second ;
877 qmGrpBonds[grpIter][bndIter] = bondCounter;
880 qmMMBondedIndx[grpIter][bndIter] = qmGrpIDBonds[grpIter][bndIter].first ;
883 qmDummyElement[bondCounter] =
new char[3];
884 strcpy(qmDummyElement[bondCounter],
"H\0");
890 if (qmBondValVec[qmMMBond[bondCounter][0]] !=
891 qmBondValVec[qmMMBond[bondCounter][1]]
893 iout <<
iERROR <<
"qmBondDist is ON but the values in the bond column are different for atom " 894 << qmMMBond[bondCounter][0] <<
" and " << qmMMBond[bondCounter][1]
896 NAMD_die(
"Error in QM-MM bond processing.");
899 bondVal = qmBondValVec[qmMMBond[bondCounter][0]] ;
903 if (strcmp(qmElementArray[qmMMBond[bondCounter][1]],
"C") == 0 ) {
906 else if (strcmp(qmElementArray[qmMMBond[bondCounter][1]],
"O") == 0 ) {
909 else if (strcmp(qmElementArray[qmMMBond[bondCounter][1]],
"N") == 0 ) {
913 iout <<
iERROR <<
"qmBondDist is OFF but the QM atom has no default distance value. Atom " 914 << qmMMBond[bondCounter][1] <<
", with element: " 915 << qmElementArray[qmMMBond[bondCounter][1]]
917 NAMD_die(
"Error in QM-MM bond processing.");
922 iout <<
iINFO <<
"MM-QM pair: " << qmMMBond[bondCounter][0] <<
":" 923 << qmMMBond[bondCounter][1]
924 <<
" -> Value (distance or ratio): " << bondVal
925 <<
" (QM Group " << grpIter <<
" ID " << qmGrpID[grpIter] <<
")" 928 qmDummyBondVal[bondCounter] = bondVal;
932 if (qmMeNumBonds > 0) {
933 qmMeMMindx[bondCounter] = qmMMBond[bondCounter][0];
934 qmMeQMGrp[bondCounter] = qmGrpID[grpIter];
949 current = cfgList->
find(
"QMLinkElement");
951 int numParsedLinkElem = 0;
952 for ( ; current != NULL; current = current->
next ) {
954 DebugM(3,
"Parsing link atom element: " << current->
data <<
"\n" );
956 strVec =
split( std::string(current->
data) ,
" ");
960 if (strVec.size() != 3 && qmNumBonds > 1) {
961 iout <<
iERROR <<
"Format error in QM link atom element selection: " 964 NAMD_die(
"Error processing QM information.");
968 if (strVec.size() != 1 && strVec.size() != 3 && qmNumBonds == 1) {
969 iout <<
iERROR <<
"Format error in QM link atom element selection: " 972 NAMD_die(
"Error processing QM information.");
975 std::stringstream storConv ;
976 int bondAtom1, bondAtom2;
977 std::string linkElement ;
979 if (strVec.size() == 1) {
980 linkElement = strVec[0].substr(0,2);
982 else if (strVec.size() == 3) {
984 storConv << strVec[0] ;
985 storConv >> bondAtom1;
986 if (storConv.fail()) {
987 iout <<
iERROR <<
"Error parsing link atom element selection: " 990 NAMD_die(
"Error processing QM information.");
994 storConv << strVec[1];
995 storConv >> bondAtom2;
996 if (storConv.fail()) {
997 iout <<
iERROR <<
"Error parsing link atom element selection: " 1000 NAMD_die(
"Error processing QM information.");
1003 linkElement = strVec[2].substr(0,2);
1006 numParsedLinkElem++;
1008 if (numParsedLinkElem>qmNumBonds) {
1009 iout <<
iERROR <<
"More link atom elements were set than there" 1010 " are QM-MM bonds.\n" <<
endi;
1011 NAMD_die(
"Error processing QM information.");
1016 if (strVec.size() == 1) {
1019 else if (strVec.size() == 3) {
1021 Bool foundBond =
false;
1023 for (bondIter=0; bondIter<qmNumBonds; bondIter++) {
1025 if ( (qmMMBond[bondIter][0] == bondAtom1 &&
1026 qmMMBond[bondIter][1] == bondAtom2 ) ||
1027 (qmMMBond[bondIter][0] == bondAtom2 &&
1028 qmMMBond[bondIter][1] == bondAtom1 ) ) {
1036 iout <<
iERROR <<
"Error parsing link atom element selection: " 1039 iout <<
iERROR <<
"Atom pair was not found to be a QM-MM bond.\n" 1041 NAMD_die(
"Error processing QM information.");
1045 strcpy(qmDummyElement[bondIter],linkElement.c_str());
1046 qmDummyElement[bondIter][2] =
'\0';
1048 iout <<
iINFO <<
"Applying user defined link atom element " 1049 << qmDummyElement[bondIter] <<
" to QM-MM bond " 1050 << bondIter <<
": " << qmMMBond[bondIter][0]
1051 <<
" - " << qmMMBond[bondIter][1]
1061 int32 **bondsWithAtomLocal = NULL ;
1062 int32 *byAtomSizeLocal = NULL;
1064 if (qmNumBonds > 0) {
1073 byAtomSizeLocal[i] = 0;
1077 byAtomSizeLocal[bonds[i].
atom1]++;
1078 byAtomSizeLocal[bonds[i].atom2]++;
1082 bondsWithAtomLocal[i] = tmpArenaLocal->
getNewArray(byAtomSizeLocal[i]+1);
1083 bondsWithAtomLocal[i][byAtomSizeLocal[i]] = -1;
1084 byAtomSizeLocal[i] = 0;
1088 int a1 = bonds[i].
atom1;
1089 int a2 = bonds[i].
atom2;
1090 bondsWithAtomLocal[a1][byAtomSizeLocal[a1]++] = i;
1091 bondsWithAtomLocal[a2][byAtomSizeLocal[a2]++] = i;
1098 for (
int qmBndIt = 0; qmBndIt < qmNumBonds; qmBndIt++) {
1102 std::vector<int> chrgTrgt ;
1104 int MM1 = qmMMBond[qmBndIt][0], MM2, MM2BondIndx, MM3, MM3BondIndx;
1113 for (
int i=0; i<byAtomSizeLocal[MM1]; i++) {
1114 MM2BondIndx = bondsWithAtomLocal[MM1][i] ;
1118 if (bonds[MM2BondIndx].atom1 == MM1)
1119 MM2 = bonds[MM2BondIndx].
atom2;
1121 MM2 = bonds[MM2BondIndx].
atom1;
1125 if (qmAtomGroup[MM2] > 0)
1128 chrgTrgt.push_back(MM2);
1136 for (
int i=0; i<byAtomSizeLocal[MM1]; i++) {
1137 MM2BondIndx = bondsWithAtomLocal[MM1][i] ;
1141 if (bonds[MM2BondIndx].atom1 == MM1)
1142 MM2 = bonds[MM2BondIndx].
atom2;
1144 MM2 = bonds[MM2BondIndx].
atom1;
1148 if (qmAtomGroup[MM2] > 0)
1151 for (
int i=0; i<byAtomSizeLocal[MM2]; i++) {
1152 MM3BondIndx = bondsWithAtomLocal[MM2][i] ;
1156 if (bonds[MM3BondIndx].atom1 == MM2)
1157 MM3 = bonds[MM3BondIndx].
atom2;
1159 MM3 = bonds[MM3BondIndx].
atom1;
1164 if (qmAtomGroup[MM3] > 0 || MM3 == MM1)
1167 chrgTrgt.push_back(MM3);
1177 for (
int i=0; i<byAtomSizeLocal[MM1]; i++) {
1178 MM2BondIndx = bondsWithAtomLocal[MM1][i] ;
1182 if (bonds[MM2BondIndx].atom1 == MM1)
1183 MM2 = bonds[MM2BondIndx].
atom2;
1185 MM2 = bonds[MM2BondIndx].
atom1;
1189 if (qmAtomGroup[MM2] > 0)
1192 chrgTrgt.push_back(MM2);
1200 chrgTrgt.push_back(MM1);
1205 qmMMChargeTarget[qmBndIt] =
new int[chrgTrgt.size()] ;
1206 qmMMNumTargs[qmBndIt] = chrgTrgt.size();
1208 DebugM(3,
"MM-QM bond " << qmBndIt <<
"; MM atom " 1209 << qmMMBond[qmBndIt][0] <<
" conections: \n" );
1211 for (
size_t i=0; i < chrgTrgt.size(); i++) {
1212 qmMMChargeTarget[qmBndIt][i] = chrgTrgt[i];
1213 DebugM(3,
"MM Bonded to: " << chrgTrgt[i] <<
"\n" );
1219 if (bondsWithAtomLocal != NULL)
1220 delete [] bondsWithAtomLocal; bondsWithAtomLocal = 0;
1221 if (byAtomSizeLocal != NULL)
1222 delete [] byAtomSizeLocal; byAtomSizeLocal = 0;
1223 if (tmpArenaLocal != NULL)
1224 delete tmpArenaLocal; tmpArenaLocal = 0;
1233 std::map<Real,int> grpLSSSize ;
1234 std::map<Real,int>::iterator itGrpSize;
1236 qmLSSTotalNumAtms = 0;
1237 qmLSSResidueSize = 0;
1248 std::map<Real, int> grpNumLSSRes;
1249 std::map<Real, int>::iterator itGrpNumRes;
1251 for(
auto it = lssGrpRes.
begin(); it != lssGrpRes.
end();it++ ) {
1253 if (it->atmIDs.size() != it->size) {
1254 iout <<
iERROR <<
"The number of atoms loaded for residue " 1255 << it->resID <<
" does not match the expected for this residue type.\n" 1257 NAMD_die(
"Error parsing data for LSS.");
1260 qmLSSTotalNumAtms += it->size;
1263 if (resSize < 0) resSize = it->size ;
1264 if (resSize > 0 and resSize != it->size) {
1265 iout <<
iERROR <<
"The number of atoms loaded for residue " 1266 << it->resID <<
" does not match previously loaded residues.\n" 1268 NAMD_die(
"Error parsing data for LSS.");
1280 itGrpSize = grpLSSSize.find(it->qmGrpID) ;
1281 if (itGrpSize != grpLSSSize.end())
1282 itGrpSize->second += it->size;
1284 grpLSSSize.insert(std::pair<Real,int>(it->qmGrpID, it->size));
1287 itGrpNumRes = grpNumLSSRes.find(it->qmGrpID) ;
1288 if (itGrpNumRes != grpNumLSSRes.end())
1289 itGrpNumRes->second += 1;
1291 grpNumLSSRes.insert(std::pair<Real,int>(it->qmGrpID, 1));
1294 qmLSSResidueSize = lssGrpRes.
begin()->
size ;
1296 qmLSSSize =
new int[qmNumGrps];
1298 qmLSSIdxs =
new int[qmLSSTotalNumAtms];
1306 qmLSSRefSize =
new int[qmNumGrps];
1308 qmLSSMass =
new Mass[qmLSSTotalNumAtms];
1310 qmLSSRefIDs =
new int[totalNumRefAtms];
1311 qmLSSRefMass =
new Mass[totalNumRefAtms];
1314 for (
int grpIndx=0; grpIndx<qmNumGrps; grpIndx++) {
1316 itGrpSize = grpNumLSSRes.find(qmGrpID[grpIndx]) ;
1318 if (itGrpSize != grpNumLSSRes.end())
1319 qmLSSSize[grpIndx] = itGrpSize->second;
1321 qmLSSSize[grpIndx] = 0;
1323 for(
auto it = lssGrpRes.
begin(); it != lssGrpRes.
end();it++ ) {
1325 if (it->qmGrpID == qmGrpID[grpIndx]) {
1326 for (
int i=0; i<it->atmIDs.size(); i++) {
1327 qmLSSIdxs[lssAtmIndx] = it->atmIDs[i];
1328 qmLSSMass[lssAtmIndx] = atoms[it->atmIDs[i]].
mass;
1334 DebugM(4,
"QM group " << qmGrpID[grpIndx]
1335 <<
" has " << qmLSSSize[grpIndx] <<
" solvent molecules, " 1336 <<
"totalling " << grpLSSSize[qmGrpID[grpIndx]]
1337 <<
" atoms (check " << lssAtmIndx <<
").\n" );
1339 qmLSSRefSize[grpIndx] = lssGrpRefIDs[qmGrpID[grpIndx]].size();
1340 for(
int i=0; i < qmLSSRefSize[grpIndx]; i++) {
1341 qmLSSRefIDs[lssRefIndx] = lssGrpRefIDs[qmGrpID[grpIndx]][i];
1342 qmLSSRefMass[lssRefIndx] = atoms[qmLSSRefIDs[lssRefIndx]].
mass;
1346 DebugM(4,
"QM group " << qmGrpID[grpIndx]
1347 <<
" has " << qmLSSRefSize[grpIndx] <<
" non-solvent atoms for LSS.\n" );
1354 for (
int grpIndx=0; grpIndx<qmNumGrps; grpIndx++) {
1356 itGrpSize = grpNumLSSRes.find(qmGrpID[grpIndx]) ;
1358 if (itGrpSize != grpNumLSSRes.end())
1359 qmLSSSize[grpIndx] = itGrpSize->second;
1361 qmLSSSize[grpIndx] = 0;
1363 for(
auto it = lssGrpRes.
begin(); it != lssGrpRes.
end();it++ ) {
1365 if (it->qmGrpID == qmGrpID[grpIndx]) {
1366 for (
int i=0; i<it->atmIDs.size(); i++) {
1367 qmLSSIdxs[lssAtmIndx] = it->atmIDs[i];
1373 DebugM(4,
"QM group " << qmGrpID[grpIndx]
1374 <<
" has " << qmLSSSize[grpIndx] <<
" solvent molecules, " 1375 <<
"totalling " << grpLSSSize[qmGrpID[grpIndx]]
1376 <<
" atoms (check " << lssAtmIndx <<
").\n" );
1395 current = cfgList->
find(
"QMCustomPCFile");
1398 std::map<Real,std::vector<int> > qmPCVecMap ;
1400 int numParsedPBDs = 0;
1401 for ( ; current != NULL; current = current->
next ) {
1404 customPCPDB =
new PDB(current->
data);
1407 NAMD_die(
"Number of atoms in QM Custom PC PDB file doesn't match coordinate PDB");
1409 std::vector< int > currPCSel ;
1411 int currGrpSize = 0 ;
1413 for (
int atmInd = 0 ; atmInd <
numAtoms; atmInd++) {
1418 if ( beta != 0 && occ != 0)
1419 NAMD_die(
"An atom cannot be marked as QM and poitn charge simultaneously!");
1423 currPCSel.push_back(atmInd) ;
1428 NAMD_die(
"QM Group selection is different in reference PDB and Custom-PC PDB!");
1430 if (currQMID == 0) {
1436 if (currQMID != beta)
1437 NAMD_die(
"Found two different QM group IDs in this file!");
1445 if (currGrpSize != qmGrpSizeVec[ qmGrpIDMap[currQMID] ])
1446 NAMD_die(
"Reference PDB and Custom-PC PDB have different QM group sizes!") ;
1448 qmPCVecMap.insert(std::pair<
Real,std::vector<int> >(
1449 currQMID, currPCSel ));
1457 if (numParsedPBDs != qmNumGrps && simParams->
qmCustomPCSel) {
1458 iout <<
iWARN <<
"The number of files provided for custom point " 1459 "charges is not equal to the number of QM groups!\n" <<
endi;
1464 qmCustPCSizes =
new int[qmNumGrps];
1465 for (
int i=0; i<qmNumGrps; i++)
1466 qmCustPCSizes[i] = 0;
1472 for (
auto it = qmPCVecMap.begin(); it != qmPCVecMap.end(); it++) {
1473 qmTotCustPCs += (*it).second.size();
1474 int qmIndx = qmGrpIDMap[(*it).first];
1475 qmCustPCSizes[qmIndx] = (*it).second.size();
1478 qmCustomPCIdxs =
new int[qmTotCustPCs];
1483 for (
int grpIndx=0; grpIndx<qmNumGrps; grpIndx++) {
1485 Real currQMID = qmGrpID[grpIndx];
1487 iout <<
iINFO <<
"Loading " << qmPCVecMap[currQMID].size()
1488 <<
" custom point charges to QM Group " << grpIndx
1489 <<
" (ID: " << currQMID <<
")\n" <<
endi;
1491 for (
int pcIndx=0; pcIndx<qmPCVecMap[currQMID].size(); pcIndx++) {
1492 qmCustomPCIdxs[auxIter] = qmPCVecMap[currQMID][pcIndx] ;
1499 qmcSMD = simParams->
qmCSMD;
1501 read_qm_csdm_file(qmGrpIDMap);
1513 for (
int i=0; i<qmNumQMAtoms; i++) {
1514 qmAtmChrg[i] = atoms[qmAtmIndx[i]].
charge;
1515 atoms[qmAtmIndx[i]].
charge = 0;
1526 int a1,a2;
float k, ref;
1528 for ( ; file; file = file->
next ) {
1529 FILE *f = fopen(file->
data,
"r");
1543 if (ret_code!=0)
break;
1546 sscanf(buffer,
"%s",type);
1549 if ( ! strncasecmp(type,
"bond",4) ) {
1550 if ( sscanf(buffer,
"%s %d %d %f %f %s",
1551 type, &a1, &a2, &k, &ref, err_msg) != 5 ) badline = 1;
1556 if( qmAtomGroup[a1] > 0 && qmAtomGroup[a2]) {
1560 qmExtraBonds.add(tmp);
1564 }
else if ( ! strncasecmp(type,
"#",1) ) {
1575 #endif // MEM_OPT_VERSION 1581 #ifdef MEM_OPT_VERSION 1582 NAMD_die(
"QMMM interface is not supported in memory optimized builds.");
1585 DebugM(3,
"Cleaning QM bonds, angles, dihedrals, impropers and crossterms.\n")
1590 int nonQMBondCount = 0;
1592 for (
int i = 0; i <
numBonds; i++) {
1594 int part1 = qmAtomGroup[bonds[i].
atom1];
1595 int part2 = qmAtomGroup[bonds[i].atom2];
1596 if (part1 > 0 && part2 > 0 ) {
1603 for (
int ebi=0; ebi < qmExtraBonds.size() ; ebi++) {
1605 if( (qmExtraBonds[ebi].atom1 == bonds[i].atom1 ||
1606 qmExtraBonds[ebi].atom1 == bonds[i].atom2) &&
1607 (qmExtraBonds[ebi].atom2 == bonds[i].atom1 ||
1608 qmExtraBonds[ebi].atom2 == bonds[i].atom2) ) {
1610 nonQMBonds[nonQMBondCount++] = bonds[i];
1621 if ((part1 > 0 || part2 > 0) && qmNumBonds == 0) {
1622 iout <<
iERROR <<
" Atoms " << bonds[i].atom1
1623 <<
" and " << bonds[i].atom2 <<
" form a QM-MM bond!\n" <<
endi ;
1624 NAMD_die(
"No QM-MM bonds were defined by the user, but one was found.");
1626 nonQMBonds[nonQMBondCount++] = bonds[i];
1632 for (
int i = 0; i < nonQMBondCount; i++) {
1633 bonds[i]=nonQMBonds[i];
1635 delete [] nonQMBonds;
1641 int nonQMAngleCount = 0;
1642 qmDroppedAngles = 0;
1644 int part1 = qmAtomGroup[angles[i].
atom1];
1645 int part2 = qmAtomGroup[angles[i].atom2];
1646 int part3 = qmAtomGroup[angles[i].atom3];
1647 if (part1 > 0 && part2 > 0 && part3 > 0) {
1652 nonQMAngles[nonQMAngleCount++] = angles[i];
1658 for (
int i = 0; i < nonQMAngleCount; i++) {
1659 angles[i]=nonQMAngles[i];
1661 delete [] nonQMAngles;
1667 int nonQMDihedralCount = 0;
1668 qmDroppedDihedrals = 0;
1670 int part1 = qmAtomGroup[dihedrals[i].
atom1];
1671 int part2 = qmAtomGroup[dihedrals[i].atom2];
1672 int part3 = qmAtomGroup[dihedrals[i].atom3];
1673 int part4 = qmAtomGroup[dihedrals[i].atom4];
1674 if (part1 > 0 && part2 > 0 && part3 > 0 && part4 > 0) {
1676 qmDroppedDihedrals++;
1679 nonQMDihedrals[nonQMDihedralCount++] = dihedrals[i];
1683 delete [] dihedrals;
1686 dihedrals[i]=nonQMDihedrals[i];
1688 delete [] nonQMDihedrals;
1693 int nonQMImproperCount = 0;
1694 qmDroppedImpropers = 0;
1696 int part1 = qmAtomGroup[impropers[i].
atom1];
1697 int part2 = qmAtomGroup[impropers[i].atom2];
1698 int part3 = qmAtomGroup[impropers[i].atom3];
1699 int part4 = qmAtomGroup[impropers[i].atom4];
1700 if (part1 > 0 && part2 > 0 && part3 > 0 && part4 > 0) {
1702 qmDroppedImpropers++;
1705 nonQMImpropers[nonQMImproperCount++] = impropers[i];
1709 delete [] impropers;
1712 impropers[i]=nonQMImpropers[i];
1714 delete [] nonQMImpropers;
1719 int nonQMCrosstermCount = 0;
1720 qmDroppedCrossterms = 0 ;
1722 int part1 = qmAtomGroup[crossterms[i].
atom1];
1723 int part2 = qmAtomGroup[crossterms[i].atom2];
1724 int part3 = qmAtomGroup[crossterms[i].atom3];
1725 int part4 = qmAtomGroup[crossterms[i].atom4];
1726 int part5 = qmAtomGroup[crossterms[i].atom5];
1727 int part6 = qmAtomGroup[crossterms[i].atom6];
1728 int part7 = qmAtomGroup[crossterms[i].atom7];
1729 int part8 = qmAtomGroup[crossterms[i].atom8];
1730 if (part1 > 0 && part2 > 0 && part3 > 0 && part4 > 0 &&
1731 part5 > 0 && part6 > 0 && part7 > 0 && part8 > 0) {
1733 qmDroppedCrossterms++;
1736 nonQMCrossterms[nonQMCrosstermCount++] = crossterms[i];
1740 delete [] crossterms;
1743 crossterms[i] = nonQMCrossterms[i] ;
1745 delete [] nonQMCrossterms ;
1748 iout <<
iINFO <<
"The QM region will remove " << qmDroppedBonds <<
" bonds, " <<
1749 qmDroppedAngles <<
" angles, " << qmDroppedDihedrals <<
" dihedrals, " 1750 << qmDroppedImpropers <<
" impropers and " << qmDroppedCrossterms
1751 <<
" crossterms.\n" <<
endi ;
1759 void Molecule::read_qm_csdm_file(std::map<Real,int> &qmGrpIDMap) {
1761 std::ifstream cSMDInputFile ;
1762 std::string Line(
"") ;
1764 iout <<
iINFO <<
"Reading QM cSMD configuration file: " <<
1767 cSMDInputFile.open( simParams->
qmCSMDFile ) ;
1769 if (! cSMDInputFile.good())
1771 NAMD_die(
"Configuration file for QM cSMD could not be read!") ;
1777 cSMDindexV.
resize(qmNumGrps);
1787 while( ! cSMDInputFile.eof() )
1789 getline(cSMDInputFile, Line) ;
1791 if ( ! Line.length() )
1794 if (Line.substr(0,1) == std::string(
"#") )
1797 auto strVec =
split( Line,
" ");
1799 if (strVec.size() != 5 ) {
1800 iout <<
iERROR <<
"Format error in QM cSDM configuration file: " 1801 << Line <<
"\n" <<
endi;
1802 NAMD_die(
"Error processing QM information.");
1805 std::stringstream storConv ;
1813 for (
int i=0; i < 5; i++ ) {
1815 storConv << strVec[i] ;
1816 storConv >> convData;
1817 if (storConv.fail()) {
1818 iout <<
iERROR <<
"Error parsing QM cSMD configuration file: " 1819 << convData <<
"\n" <<
endi;
1820 NAMD_die(
"Error processing QM information.");
1825 cSMDpairsV[cSMDnumInst].first = convData ;
1828 cSMDpairsV[cSMDnumInst].second = convData ;
1831 cSMDKsV[cSMDnumInst] = convData ;
1834 cSMDVelsV[cSMDnumInst] = convData ;
1837 cSMDcoffsV[cSMDnumInst] = convData ;
1843 if (cSMDpairsV[cSMDnumInst].first == cSMDpairsV[cSMDnumInst].second) {
1844 iout <<
iERROR <<
"Conditional SMD atoms must be different! We got " <<
1845 cSMDpairsV[cSMDnumInst].first <<
" and " << cSMDpairsV[cSMDnumInst].second <<
"\n" <<
endi;
1846 NAMD_die(
"Error processing QM information.") ;
1850 if (qmAtomGroup[cSMDpairsV[cSMDnumInst].first] == 0 ||
1851 qmAtomGroup[cSMDpairsV[cSMDnumInst].second] == 0) {
1852 iout <<
iERROR <<
"Atoms " << cSMDpairsV[cSMDnumInst].first <<
" and " <<
1853 cSMDpairsV[cSMDnumInst].second <<
" MUST be assigned as QM atoms.\n" <<
endi;
1854 NAMD_die(
"Error processing QM information.") ;
1858 if (qmAtomGroup[cSMDpairsV[cSMDnumInst].first] !=
1859 qmAtomGroup[cSMDpairsV[cSMDnumInst].second] ) {
1860 iout <<
iERROR <<
"Atoms in cSMD MUST be assigned to the same QM group.\n" <<
endi;
1861 NAMD_die(
"Error processing QM information.") ;
1864 int grpIndx = qmGrpIDMap[qmAtomGroup[cSMDpairsV[cSMDnumInst].first]] ;
1866 iout <<
iINFO <<
"Adding cSMD data: (" << cSMDnumInst <<
") " <<
1867 cSMDpairsV[cSMDnumInst].first <<
"," << cSMDpairsV[cSMDnumInst].second <<
"," <<
1868 cSMDKsV[cSMDnumInst] <<
"," << cSMDVelsV[cSMDnumInst] <<
"," << cSMDcoffsV[cSMDnumInst] <<
1869 " to QM Group " << grpIndx <<
"\n" <<
endi ;
1871 cSMDindexV[grpIndx].
add(cSMDnumInst);
1876 cSMDindex =
new int*[qmNumGrps];
1877 cSMDindxLen =
new int[qmNumGrps];
1879 for (
int i=0; i<qmNumGrps; i++) {
1880 cSMDindex[i] =
new int[cSMDindexV[i].
size()];
1881 cSMDindxLen[i] = cSMDindexV[i].size();
1883 for (
int j=0; j<cSMDindxLen[i]; j++)
1884 cSMDindex[i][j] = cSMDindexV[i][j] ;
1887 cSMDpairs =
new int*[cSMDnumInst];
1888 for (
int i=0; i<cSMDnumInst; i++)
1889 cSMDpairs[i] =
new int[2];
1890 cSMDKs =
new Real[cSMDnumInst];
1891 cSMDVels =
new Real[cSMDnumInst];
1892 cSMDcoffs =
new Real[cSMDnumInst];
1894 for (
int i=0; i<cSMDnumInst; i++) {
1895 cSMDpairs[i][0] = cSMDpairsV[i].first;
1896 cSMDpairs[i][1] = cSMDpairsV[i].second;
1898 cSMDKs[i] = cSMDKsV[i];
1899 cSMDVels[i] = cSMDVelsV[i];
1900 cSMDcoffs[i] = cSMDcoffsV[i];
std::ostream & iINFO(std::ostream &s)
Type * getNewArray(int n)
std::map< Real, refSelStrVec > refSelStrMap
int NAMD_read_line(FILE *fd, char *buf, int bufsize)
void assign_vdw_index(const char *, Atom *)
std::vector< int > atmIDs
int get_residue_size(const char *segid, int resid) const
BigReal temperaturefactor(void)
int lookup(const char *segid, int resid, int *begin, int *end) const
std::ostream & endi(std::ostream &s)
char qmCSMDFile[NAMD_FILENAME_BUFFER_SIZE]
std::ostream & iWARN(std::ostream &s)
refSelStr(std::string newSegID, int newResid)
int add(const Elem &elem)
const char * residuename(void)
int insert(const Elem &elem)
std::pair< int, int > cSMDPair
PDBAtom * atom(int place)
int NAMD_blank_string(char *str)
std::pair< Real, refSelStrVec > refSelStrPair
void prepare_qm(const char *pdbFileName, Parameters *params, ConfigList *cfgList)
void NAMD_die(const char *err_msg)
bool operator<(const qmSolvData &ref)
std::vector< std::string > split(const std::string &text, std::string delimiter)
Bool qmMOPACAddConfigChrg
std::vector< refSelStr > refSelStrVec
Elem * find(const Elem &elem)
bool operator==(const qmSolvData &ref)
std::ostream & iERROR(std::ostream &s)
qmSolvData(int newResID, int newBegAtm, int newSize, const char *newSegName, Real newQMID)
StringList * find(const char *name) const
const char * element(void)
const char * segmentname(void)
qmSolvData(int newResID, int newBegAtm, int newSize)