--- trunk/OOPSE/libmdtools/NPTf.cpp 2003/07/14 22:38:13 600 +++ trunk/OOPSE/libmdtools/NPTf.cpp 2003/11/06 22:01:37 855 @@ -1,3 +1,4 @@ +#include #include "Atom.hpp" #include "SRI.hpp" #include "AbstractClasses.hpp" @@ -6,320 +7,301 @@ #include "Thermo.hpp" #include "ReadWrite.hpp" #include "Integrator.hpp" -#include "simError.h" +#include "simError.h" +#ifdef IS_MPI +#include "mpiSimulation.hpp" +#endif // Basic non-isotropic thermostating and barostating via the Melchionna // modification of the Hoover algorithm: // // Melchionna, S., Ciccotti, G., and Holian, B. L., 1993, -// Molec. Phys., 78, 533. +// Molec. Phys., 78, 533. // // and -// +// // Hoover, W. G., 1986, Phys. Rev. A, 34, 2499. -NPTf::NPTf ( SimInfo *theInfo, ForceFields* the_ff): - Integrator( theInfo, the_ff ) +template NPTf::NPTf ( SimInfo *theInfo, ForceFields* the_ff): + T( theInfo, the_ff ) { + GenericData* data; + DoubleArrayData * etaValue; + vector etaArray; + int i,j; + + for(i = 0; i < 3; i++){ + for (j = 0; j < 3; j++){ + + eta[i][j] = 0.0; + oldEta[i][j] = 0.0; + } + } + + + if( theInfo->useInitXSstate ){ + // retrieve eta array from simInfo if it exists + data = info->getProperty(ETAVALUE_ID); + if(data){ + etaValue = dynamic_cast(data); + + if(etaValue){ + etaArray = etaValue->getData(); + + for(i = 0; i < 3; i++){ + for (j = 0; j < 3; j++){ + eta[i][j] = etaArray[3*i+j]; + oldEta[i][j] = eta[i][j]; + } + } + } + } + } + +} + +template NPTf::~NPTf() { + + // empty for now +} + +template void NPTf::resetIntegrator() { + int i, j; - chi = 0.0; - for(i = 0; i < 3; i++) - for (j = 0; j < 3; j++) + for(i = 0; i < 3; i++) + for (j = 0; j < 3; j++) eta[i][j] = 0.0; - have_tau_thermostat = 0; - have_tau_barostat = 0; - have_target_temp = 0; - have_target_pressure = 0; + T::resetIntegrator(); } -void NPTf::moveA() { - - int i, j, k; - DirectionalAtom* dAtom; - double Tb[3], ji[3]; - double A[3][3], I[3][3]; - double angle, mass; - double vel[3], pos[3], frc[3]; +template void NPTf::evolveEtaA() { - double rj[3]; - double instaTemp, instaPress, instaVol; - double tt2, tb2; - double sc[3]; - double eta2ij; - double press[3][3], vScale[3][3], hm[3][3], hmnew[3][3], scaleMat[3][3]; + int i, j; - tt2 = tauThermostat * tauThermostat; - tb2 = tauBarostat * tauBarostat; + for(i = 0; i < 3; i ++){ + for(j = 0; j < 3; j++){ + if( i == j) + eta[i][j] += dt2 * instaVol * + (press[i][j] - targetPressure/p_convert) / (NkBT*tb2); + else + eta[i][j] += dt2 * instaVol * press[i][j] / (NkBT*tb2); + } + } - instaTemp = tStats->getTemperature(); - tStats->getPressureTensor(press); - instaVol = tStats->getVolume(); - - // first evolve chi a half step - - chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2; + for(i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + oldEta[i][j] = eta[i][j]; +} +template void NPTf::evolveEtaB() { + + int i,j; + + for(i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + prevEta[i][j] = eta[i][j]; + + for(i = 0; i < 3; i ++){ + for(j = 0; j < 3; j++){ + if( i == j) { + eta[i][j] = oldEta[i][j] + dt2 * instaVol * + (press[i][j] - targetPressure/p_convert) / (NkBT*tb2); + } else { + eta[i][j] = oldEta[i][j] + dt2 * instaVol * press[i][j] / (NkBT*tb2); + } + } + } +} + +template void NPTf::getVelScaleA(double sc[3], double vel[3]) { + int i,j; + double vScale[3][3]; + for (i = 0; i < 3; i++ ) { for (j = 0; j < 3; j++ ) { - if (i == j) { - - eta[i][j] += dt2 * instaVol * - (press[i][j] - targetPressure/p_convert) / (NkBT*tb2); - - vScale[i][j] = eta[i][j] + chi; - - } else { - - eta[i][j] += dt2 * instaVol * press[i][j] / (NkBT*tb2); + vScale[i][j] = eta[i][j]; - vScale[i][j] = eta[i][j]; - + if (i == j) { + vScale[i][j] += chi; } } } - for( i=0; imatVecMul3( vScale, vel, sc ); +} - atoms[i]->getVel( vel ); - atoms[i]->getPos( pos ); - atoms[i]->getFrc( frc ); +template void NPTf::getVelScaleB(double sc[3], int index ){ + int i,j; + double myVel[3]; + double vScale[3][3]; - mass = atoms[i]->getMass(); - - // velocity half step - - info->matVecMul3( vScale, vel, sc ); - - for (j = 0; j < 3; j++) { - vel[j] += dt2 * ((frc[j] / mass) * eConvert - sc[j]); - rj[j] = pos[j]; + for (i = 0; i < 3; i++ ) { + for (j = 0; j < 3; j++ ) { + vScale[i][j] = eta[i][j]; + + if (i == j) { + vScale[i][j] += chi; + } } + } - atoms[i]->setVel( vel ); + for (j = 0; j < 3; j++) + myVel[j] = oldVel[3*index + j]; - // position whole step + info->matVecMul3( vScale, myVel, sc ); +} - info->wrapVector(rj); +template void NPTf::getPosScale(double pos[3], double COM[3], + int index, double sc[3]){ + int j; + double rj[3]; - info->matVecMul3( eta, rj, sc ); + for(j=0; j<3; j++) + rj[j] = ( oldPos[index*3+j] + pos[j]) / 2.0 - COM[j]; - for (j = 0; j < 3; j++ ) - pos[j] += dt * (vel[j] + sc[j]); - - if( atoms[i]->isDirectional() ){ + info->matVecMul3( eta, rj, sc ); +} - dAtom = (DirectionalAtom *)atoms[i]; - - // get and convert the torque to body frame - - dAtom->getTrq( Tb ); - dAtom->lab2Body( Tb ); - - // get the angular momentum, and propagate a half step +template void NPTf::scaleSimBox( void ){ - dAtom->getJ( ji ); + int i,j,k; + double scaleMat[3][3]; + double eta2ij; + double bigScale, smallScale, offDiagMax; + double hm[3][3], hmnew[3][3]; - for (j=0; j < 3; j++) - ji[j] += dt2 * (Tb[j] * eConvert - ji[j]*chi); - - // use the angular velocities to propagate the rotation matrix a - // full time step - dAtom->getA(A); - dAtom->getI(I); - - // rotate about the x-axis - angle = dt2 * ji[0] / I[0][0]; - this->rotate( 1, 2, angle, ji, A ); - // rotate about the y-axis - angle = dt2 * ji[1] / I[1][1]; - this->rotate( 2, 0, angle, ji, A ); - - // rotate about the z-axis - angle = dt * ji[2] / I[2][2]; - this->rotate( 0, 1, angle, ji, A); - - // rotate about the y-axis - angle = dt2 * ji[1] / I[1][1]; - this->rotate( 2, 0, angle, ji, A ); - - // rotate about the x-axis - angle = dt2 * ji[0] / I[0][0]; - this->rotate( 1, 2, angle, ji, A ); - - dAtom->setJ( ji ); - dAtom->setA( A ); - } - } - // Scale the box after all the positions have been moved: - + // Use a taylor expansion for eta products: Hmat = Hmat . exp(dt * etaMat) // Hmat = Hmat . ( Ident + dt * etaMat + dt^2 * etaMat*etaMat / 2) - - + + bigScale = 1.0; + smallScale = 1.0; + offDiagMax = 0.0; + for(i=0; i<3; i++){ for(j=0; j<3; j++){ - + // Calculate the matrix Product of the eta array (we only need // the ij element right now): - + eta2ij = 0.0; for(k=0; k<3; k++){ eta2ij += eta[i][k] * eta[k][j]; } - + scaleMat[i][j] = 0.0; // identity matrix (see above): if (i == j) scaleMat[i][j] = 1.0; // Taylor expansion for the exponential truncated at second order: scaleMat[i][j] += dt*eta[i][j] + 0.5*dt*dt*eta2ij; - + + if (i != j) + if (fabs(scaleMat[i][j]) > offDiagMax) + offDiagMax = fabs(scaleMat[i][j]); } + + if (scaleMat[i][i] > bigScale) bigScale = scaleMat[i][i]; + if (scaleMat[i][i] < smallScale) smallScale = scaleMat[i][i]; } - - info->getBoxM(hm); - info->matMul3(hm, scaleMat, hmnew); - info->setBoxM(hmnew); - + + if ((bigScale > 1.01) || (smallScale < 0.99)) { + sprintf( painCave.errMsg, + "NPTf error: Attempting a Box scaling of more than 1 percent.\n" + " Check your tauBarostat, as it is probably too small!\n\n" + " scaleMat = [%lf\t%lf\t%lf]\n" + " [%lf\t%lf\t%lf]\n" + " [%lf\t%lf\t%lf]\n", + scaleMat[0][0],scaleMat[0][1],scaleMat[0][2], + scaleMat[1][0],scaleMat[1][1],scaleMat[1][2], + scaleMat[2][0],scaleMat[2][1],scaleMat[2][2]); + painCave.isFatal = 1; + simError(); + } else if (offDiagMax > 0.01) { + sprintf( painCave.errMsg, + "NPTf error: Attempting an off-diagonal Box scaling of more than 1 percent.\n" + " Check your tauBarostat, as it is probably too small!\n\n" + " scaleMat = [%lf\t%lf\t%lf]\n" + " [%lf\t%lf\t%lf]\n" + " [%lf\t%lf\t%lf]\n", + scaleMat[0][0],scaleMat[0][1],scaleMat[0][2], + scaleMat[1][0],scaleMat[1][1],scaleMat[1][2], + scaleMat[2][0],scaleMat[2][1],scaleMat[2][2]); + painCave.isFatal = 1; + simError(); + } else { + info->getBoxM(hm); + info->matMul3(hm, scaleMat, hmnew); + info->setBoxM(hmnew); + } } -void NPTf::moveB( void ){ +template bool NPTf::etaConverged() { + int i; + double diffEta, sumEta; - int i, j; - DirectionalAtom* dAtom; - double Tb[3], ji[3]; - double vel[3], frc[3]; - double mass; + sumEta = 0; + for(i = 0; i < 3; i++) + sumEta += pow(prevEta[i][i] - eta[i][i], 2); - double instaTemp, instaPress, instaVol; - double tt2, tb2; - double sc[3]; - double press[3][3], vScale[3][3]; - - tt2 = tauThermostat * tauThermostat; - tb2 = tauBarostat * tauBarostat; + diffEta = sqrt( sumEta / 3.0 ); - instaTemp = tStats->getTemperature(); - tStats->getPressureTensor(press); - instaVol = tStats->getVolume(); - - // first evolve chi a half step - - chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2; - - for (i = 0; i < 3; i++ ) { - for (j = 0; j < 3; j++ ) { - if (i == j) { + return ( diffEta <= etaTolerance ); +} - eta[i][j] += dt2 * instaVol * - (press[i][j] - targetPressure/p_convert) / (NkBT*tb2); +template double NPTf::getConservedQuantity(void){ - vScale[i][j] = eta[i][j] + chi; - - } else { - - eta[i][j] += dt2 * instaVol * press[i][j] / (NkBT*tb2); + double conservedQuantity; + double totalEnergy; + double thermostat_kinetic; + double thermostat_potential; + double barostat_kinetic; + double barostat_potential; + double trEta; + double a[3][3], b[3][3]; - vScale[i][j] = eta[i][j]; - - } - } - } + totalEnergy = tStats->getTotalE(); - for( i=0; igetVel( vel ); - atoms[i]->getFrc( frc ); + thermostat_potential = fkBT* integralOfChidt / eConvert; - mass = atoms[i]->getMass(); - - // velocity half step - - info->matVecMul3( vScale, vel, sc ); - - for (j = 0; j < 3; j++) { - vel[j] += dt2 * ((frc[j] / mass) * eConvert - sc[j]); - } + info->transposeMat3(eta, a); + info->matMul3(a, eta, b); + trEta = info->matTrace3(b); - atoms[i]->setVel( vel ); - - if( atoms[i]->isDirectional() ){ + barostat_kinetic = NkBT * tb2 * trEta / + (2.0 * eConvert); - dAtom = (DirectionalAtom *)atoms[i]; - - // get and convert the torque to body frame - - dAtom->getTrq( Tb ); - dAtom->lab2Body( Tb ); - - // get the angular momentum, and propagate a half step - - dAtom->getJ( ji ); - - for (j=0; j < 3; j++) - ji[j] += dt2 * (Tb[j] * eConvert - ji[j]*chi); - - dAtom->setJ( ji ); + barostat_potential = (targetPressure * tStats->getVolume() / p_convert) / + eConvert; - } - } -} + conservedQuantity = totalEnergy + thermostat_kinetic + thermostat_potential + + barostat_kinetic + barostat_potential; -int NPTf::readyCheck() { - - // First check to see if we have a target temperature. - // Not having one is fatal. - - if (!have_target_temp) { - sprintf( painCave.errMsg, - "NPTf error: You can't use the NPTf integrator\n" - " without a targetTemp!\n" - ); - painCave.isFatal = 1; - simError(); - return -1; - } + return conservedQuantity; - if (!have_target_pressure) { - sprintf( painCave.errMsg, - "NPTf error: You can't use the NPTf integrator\n" - " without a targetPressure!\n" - ); - painCave.isFatal = 1; - simError(); - return -1; - } - - // We must set tauThermostat. - - if (!have_tau_thermostat) { - sprintf( painCave.errMsg, - "NPTf error: If you use the NPTf\n" - " integrator, you must set tauThermostat.\n"); - painCave.isFatal = 1; - simError(); - return -1; - } +} - // We must set tauBarostat. - - if (!have_tau_barostat) { - sprintf( painCave.errMsg, - "NPTf error: If you use the NPTf\n" - " integrator, you must set tauBarostat.\n"); - painCave.isFatal = 1; - simError(); - return -1; - } +template string NPTf::getAdditionalParameters(void){ + string parameters; + const int BUFFERSIZE = 2000; // size of the read buffer + char buffer[BUFFERSIZE]; - // We need NkBT a lot, so just set it here: + sprintf(buffer,"\t%G\t%G;", chi, integralOfChidt); + parameters += buffer; - NkBT = (double)info->ndf * kB * targetTemp; + for(int i = 0; i < 3; i++){ + sprintf(buffer,"\t%G\t%G\t%G;", eta[i][0], eta[i][1], eta[i][2]); + parameters += buffer; + } - return 1; + return parameters; + }