// Action_DihedralScan::IntervalAngles() void Action_DihedralScan::IntervalAngles(Frame& currentFrame) { Matrix_3x3 rotationMatrix; double theta_in_radians = interval_ * Constants::DEGRAD; // Write original frame if (!outfilename_.empty()) outtraj_.WriteSingle(outframe_++, currentFrame); for (std::vector<DihedralScanType>::iterator dih = BB_dihedrals_.begin(); dih != BB_dihedrals_.end(); dih++) { // Set axis of rotation Vec3 axisOfRotation = currentFrame.SetAxisOfRotation((*dih).atom1, (*dih).atom2); // Calculate rotation matrix for interval rotationMatrix.CalcRotationMatrix(axisOfRotation, theta_in_radians); if (debug_ > 0) { mprintf("\tRotating Dih %s-%s by %.2f deg %i times.\n", CurrentParm_->TruncResAtomName( (*dih).atom1 ).c_str(), CurrentParm_->TruncResAtomName( (*dih).atom2 ).c_str(), interval_, maxVal_); } for (int rot = 0; rot < maxVal_; ++rot) { // Rotate around axis currentFrame.Rotate(rotationMatrix, (*dih).Rmask); // Write output trajectory if (!outfilename_.empty()) outtraj_.WriteSingle(outframe_++, currentFrame); } } }
// ----------------------------------------------------------------------------- void Image::WrapToCell0(std::vector<double>& CoordsIn, Frame const& frmIn, AtomMask const& maskIn, Matrix_3x3 const& ucell, Matrix_3x3 const& recip) { double* uFrac = &CoordsIn[0]; int nUatoms = maskIn.Nselected(); int idx; double* result; const double* XYZ; # ifdef _OPENMP # pragma omp parallel private(idx, result, XYZ) { # pragma omp for # endif for (idx = 0; idx < nUatoms; idx++) { result = uFrac + idx*3; XYZ = frmIn.XYZ( maskIn[idx] ); // Convert to frac coords recip.TimesVec( result, XYZ ); // Wrap to primary unit cell result[0] = result[0] - floor(result[0]); result[1] = result[1] - floor(result[1]); result[2] = result[2] - floor(result[2]); // Convert back to Cartesian ucell.TransposeMult( result, result ); } # ifdef _OPENMP } // END pragma omp parallel # endif }
/** \param a1 First set of XYZ coordinates. * \param a2 Second set of XYZ coordinates. * \param ucell Unit cell vectors. * \param recip Fractional cell vectors. * \return the shortest vector from a1 to a2. */ Vec3 MinImagedVec(Vec3 const& a1, Vec3 const& a2, Matrix_3x3 const& ucell, Matrix_3x3 const& recip) { Vec3 f1 = recip * a1; Vec3 f2 = recip * a2; // mprintf("DEBUG: a1= %g %g %g, f1= %g %g %g\n", a1[0], a1[1], a1[2], f1[0], f1[1], f1[2]); // mprintf("DEBUG: a2= %g %g %g, f2= %g %g %g\n", a2[0], a2[1], a2[2], f2[0], f2[1], f2[2]); for (unsigned int i = 0; i < 3; i++) { f1[i] = f1[i] - floor(f1[i]); f2[i] = f2[i] - floor(f2[i]); } // Self Vec3 c1 = ucell.TransposeMult( f1 ); Vec3 c2 = ucell.TransposeMult( f2 ); Vec3 minVec = c2 - c1; double minDist2 = minVec.Magnitude2(); // Images for (int ix = -1; ix < 2; ix++) { for (int iy = -1; iy < 2; iy++) { for (int iz = -1; iz < 2; iz++) { if (ix != 0 || iy != 0 || iz != 0) { // Ignore a2 self Vec3 ixyz(ix, iy, iz); c2 = ucell.TransposeMult(f2 + ixyz); // a2 image back in Cartesian space Vec3 dxyz = c2 - c1; double dist2 = dxyz.Magnitude2(); if (dist2 < minDist2) { minDist2 = dist2; minVec = dxyz; } } } } } return minVec; }
/** \param Coord Coordinate to image. * \param truncoct If true, image in truncated octahedral shape. * \param origin If true, image w.r.t. coordinate origin. * \param ucell Unit cell matrix. * \param recip Reciprocal coordinates matrix. * \param fcom If truncoct, image translated coordinate w.r.t. this coord. * \return Vector containing image translation. */ Vec3 Image::Nonortho(Vec3 const& Coord, bool truncoct, bool origin, Matrix_3x3 const& ucell, Matrix_3x3 const& recip, Vec3 const& fcom, double min) { int ixyz[3]; Vec3 fc = recip * Coord; if ( origin ) fc += 0.5; Vec3 boxTransOut = ucell.TransposeMult( Vec3(floor(fc[0]), floor(fc[1]), floor(fc[2])) ); boxTransOut.Neg(); // Put into familiar trunc. oct. shape if (truncoct) { Vec3 TransCoord = recip * (Coord + boxTransOut); Vec3 f2 = recip * fcom; if (origin) { TransCoord += 0.5; f2 += 0.5; } DIST2_ImageNonOrthoRecip(TransCoord, f2, min, ixyz, ucell); if (ixyz[0] != 0 || ixyz[1] != 0 || ixyz[2] != 0) { boxTransOut += ucell.TransposeMult( ixyz ); //if (debug > 2) // mprintf( " IMAGING, FAMILIAR OFFSETS ARE %i %i %i\n", // ixyz[0], ixyz[1], ixyz[2]); } } return boxTransOut; }
// Action_Principal::DoAction() Action::RetType Action_Principal::DoAction(int frameNum, ActionFrame& frm) { Matrix_3x3 Inertia; Vec3 Eval; frm.Frm().CalculateInertia( mask_, Inertia ); // NOTE: Diagonalize_Sort_Chirality places sorted eigenvectors in rows. Inertia.Diagonalize_Sort_Chirality( Eval, debug_ ); if (outfile_ != 0) { int fn = frameNum+1; outfile_->Printf("%i EIGENVALUES: %f %f %f\n%i EIGENVECTOR 0: %f %f %f\n%i EIGENVECTOR 1: %f %f %f\n%i EIGENVECTOR 2: %f %f %f\n", fn, Eval[0], Eval[1], Eval[2], fn, Inertia[0], Inertia[1], Inertia[2], fn, Inertia[3], Inertia[4], Inertia[5], fn, Inertia[6], Inertia[7], Inertia[8]); //Eval.Print("PRINCIPAL EIGENVALUES"); //Inertia.Print("PRINCIPAL EIGENVECTORS (Rows)"); } if (vecData_ != 0) { vecData_->AddMat3x3( Inertia ); valData_->AddVxyz( Eval ); } // Rotate - since Evec is already transposed (eigenvectors // are returned in rows) just do plain rotation to affect an // inverse rotation. if (doRotation_) { frm.ModifyFrm().Rotate( Inertia ); return Action::MODIFY_COORDS; } return Action::OK; }
// MomentOfInertia() static void MomentOfInertia(int natom, const double *X_, const double* Mass_, double* pmom) { Matrix_3x3 IVEC; Vec3 eval; // Center of mass double cx = 0.0; double cy = 0.0; double cz = 0.0; double sumMass = 0.0; const double* mass = Mass_; int natom3 = natom * 3; for (int i = 0; i < natom3; i+=3) { sumMass += (*mass); cx += ( X_[i ] * (*mass) ); cy += ( X_[i+1] * (*mass) ); cz += ( X_[i+2] * (*mass) ); ++mass; } cx /= sumMass; cy /= sumMass; cz /= sumMass; // Moment of inertia double xx = 0.0; double yy = 0.0; double zz = 0.0; double xy = 0.0; double xz = 0.0; double yz = 0.0; mass = Mass_; for (int i = 0; i < natom3; i+=3) { double dx = X_[i ] - cx; double dy = X_[i+1] - cy; double dz = X_[i+2] - cz; xx += *mass * ( dy * dy + dz * dz ); yy += *mass * ( dx * dx + dz * dz ); zz += *mass * ( dx * dx + dy * dy ); xy -= *mass * dx * dy; xz -= *mass * dx * dz; yz -= *(mass++) * dy * dz; } IVEC[0] = xx; IVEC[1] = xy; IVEC[2] = xz; IVEC[3] = xy; IVEC[4] = yy; IVEC[5] = yz; IVEC[6] = xz; IVEC[7] = yz; IVEC[8] = zz; // NOTE: Diagonalize sorts evals/evecs in descending order, but // thermo() expects ascending. IVEC.Diagonalize_Sort( eval ); pmom[0] = eval[2]; pmom[1] = eval[1]; pmom[2] = eval[0]; }
/** Set box from unit cell matrix. */ void Box::SetBox(Matrix_3x3 const& ucell) { Vec3 x_axis = ucell.Row1(); Vec3 y_axis = ucell.Row2(); Vec3 z_axis = ucell.Row3(); box_[0] = x_axis.Normalize(); // A box_[1] = y_axis.Normalize(); // B box_[2] = z_axis.Normalize(); // C box_[3] = y_axis.Angle( z_axis ) * Constants::RADDEG; // alpha box_[4] = x_axis.Angle( z_axis ) * Constants::RADDEG; // beta box_[5] = x_axis.Angle( y_axis ) * Constants::RADDEG; // gamma SetBoxType(); }
/** Use box coordinates to calculate unit cell and fractional matrix for use * with imaging routines. Return cell volume. */ double Box::ToRecip(Matrix_3x3& ucell, Matrix_3x3& recip) const { double u12x,u12y,u12z; double u23x,u23y,u23z; double u31x,u31y,u31z; double volume,onevolume; // If box lengths are zero no imaging possible if (box_[0]==0.0 || box_[1]==0.0 || box_[2]==0.0) { ucell.Zero(); recip.Zero(); return -1.0; } ucell[0] = box_[0]; // u(1,1) ucell[1] = 0.0; // u(2,1) ucell[2] = 0.0; // u(3,1) ucell[3] = box_[1]*cos(Constants::DEGRAD*box_[5]); // u(1,2) ucell[4] = box_[1]*sin(Constants::DEGRAD*box_[5]); // u(2,2) ucell[5] = 0.0; // u(3,2) ucell[6] = box_[2]*cos(Constants::DEGRAD*box_[4]); ucell[7] = (box_[1]*box_[2]*cos(Constants::DEGRAD*box_[3]) - ucell[6]*ucell[3]) / ucell[4]; ucell[8] = sqrt(box_[2]*box_[2] - ucell[6]*ucell[6] - ucell[7]*ucell[7]); // Get reciprocal vectors u23x = ucell[4]*ucell[8] - ucell[5]*ucell[7]; u23y = ucell[5]*ucell[6] - ucell[3]*ucell[8]; u23z = ucell[3]*ucell[7] - ucell[4]*ucell[6]; u31x = ucell[7]*ucell[2] - ucell[8]*ucell[1]; u31y = ucell[8]*ucell[0] - ucell[6]*ucell[2]; u31z = ucell[6]*ucell[1] - ucell[7]*ucell[0]; u12x = ucell[1]*ucell[5] - ucell[2]*ucell[4]; u12y = ucell[2]*ucell[3] - ucell[0]*ucell[5]; u12z = ucell[0]*ucell[4] - ucell[1]*ucell[3]; volume=ucell[0]*u23x + ucell[1]*u23y + ucell[2]*u23z; onevolume = 1.0 / volume; recip[0] = u23x*onevolume; recip[1] = u23y*onevolume; recip[2] = u23z*onevolume; recip[3] = u31x*onevolume; recip[4] = u31y*onevolume; recip[5] = u31z*onevolume; recip[6] = u12x*onevolume; recip[7] = u12y*onevolume; recip[8] = u12z*onevolume; return volume; }
void Action_Vector::Principal(Frame const& currentFrame) { Matrix_3x3 Inertia; Vec3 Eval; // Origin is center of atoms in mask_ Vec3 OXYZ = currentFrame.CalculateInertia( mask_, Inertia ); // NOTE: Diagonalize_Sort_Chirality places sorted eigenvectors in rows. Inertia.Diagonalize_Sort_Chirality( Eval, 0 ); // Eval.Print("PRINCIPAL EIGENVALUES"); // Inertia.Print("PRINCIPAL EIGENVECTORS (Rows)"); if ( mode_ == PRINCIPAL_X ) Vec_->AddVxyz( Inertia.Row1(), OXYZ ); // First row = first eigenvector else if ( mode_ == PRINCIPAL_Y ) Vec_->AddVxyz( Inertia.Row2(), OXYZ ); // Second row = second eigenvector else // PRINCIPAL_Z Vec_->AddVxyz( Inertia.Row3(), OXYZ ); // Third row = third eigenvector }
/** Fill the translate vector array with offset values based on this * unit cell. Only need forward direction, so no -Z. */ void PairList::FillTranslateVec(Matrix_3x3 const& ucell) { int iv = 0; for (int i3 = 0; i3 < 2; i3++) for (int i2 = -1; i2 < 2; i2++) for (int i1 = -1; i1 < 2; i1++) translateVec_[iv++] = ucell.TransposeMult( Vec3(i1, i2, i3) ); //for (int i = 0; i < 18; i++) // mprintf("TRANVEC %3i%12.5f%12.5f%12.5f\n", i+1, translateVec_[i][0], // translateVec_[i][1], translateVec_[i][2]); }
/** Calculate direct space energy. This is the slow version that doesn't * use a pair list; for debug purposes only. */ double Ewald::Direct(Matrix_3x3 const& ucell, Topology const& tIn, AtomMask const& mask) { t_direct_.Start(); double cut2 = cutoff_ * cutoff_; double Eelec = 0.0; Varray const& Image = pairList_.ImageCoords(); Varray const& Frac = pairList_.FracCoords(); unsigned int maxidx = Image.size(); for (unsigned int idx1 = 0; idx1 != maxidx; idx1++) { // Set up coord for this atom Vec3 const& crd1 = Image[idx1]; // Set up exclusion list for this atom int atom1 = mask[idx1]; Atom::excluded_iterator excluded_atom = tIn[atom1].excludedbegin(); for (unsigned int idx2 = idx1 + 1; idx2 != maxidx; idx2++) { int atom2 = mask[idx2]; // If atom is excluded, just increment to next excluded atom. if (excluded_atom != tIn[atom1].excludedend() && atom2 == *excluded_atom) { ++excluded_atom; //mprintf("ATOM: Atom %4i to %4i excluded.\n", atom1+1, atom2+1); } else { // Only need to check nearest neighbors. Vec3 const& frac2 = Frac[idx2]; for (Varray::const_iterator ixyz = Cells_.begin(); ixyz != Cells_.end(); ++ixyz) { Vec3 dxyz = ucell.TransposeMult(frac2 + *ixyz) - crd1; double rij2 = dxyz.Magnitude2(); if ( rij2 < cut2 ) { double rij = sqrt( rij2 ); // Coulomb double qiqj = Charge_[idx1] * Charge_[idx2]; t_erfc_.Start(); //double erfc = erfc_func(ew_coeff_ * rij); double erfc = ERFC(ew_coeff_ * rij); t_erfc_.Stop(); double e_elec = qiqj * erfc / rij; Eelec += e_elec; //mprintf("EELEC %4i%4i%12.5f%12.5f%12.5f%3.0f%3.0f%3.0f\n", // mprintf("EELEC %6i%6i%12.5f%12.5f%12.5f\n", atom1, atom2, rij, erfc, e_elec); // TODO can we break here? } //else //mprintf("ATOM: Atom %4i to %4i outside cut, %6.2f > %6.2f %3.0f%3.0f%3.0f\n", //mprintf("ATOM: Atom %4i to %4i outside cut, %6.2f > %6.2f\n", // atom1, atom2,sqrt(rij2),cutoff_); } } } } t_direct_.Stop(); return Eelec; }
// Action_MakeStructure::DoAction() Action::RetType Action_MakeStructure::DoAction(int frameNum, Frame* currentFrame, Frame** frameAddress) { Matrix_3x3 rotationMatrix; for (std::vector<SecStructHolder>::iterator ss = secstruct_.begin(); ss != secstruct_.end(); ++ss) { std::vector<float>::iterator theta = ss->thetas_.begin(); std::vector<AtomMask>::iterator Rmask = ss->Rmasks_.begin(); for (DihedralSearch::mask_it dih = ss->dihSearch_.begin(); dih != ss->dihSearch_.end(); ++dih, ++theta, ++Rmask) { double theta_in_radians = (double)*theta; // Calculate current value of dihedral double torsion = Torsion( currentFrame->XYZ( (*dih).A0() ), currentFrame->XYZ( (*dih).A1() ), currentFrame->XYZ( (*dih).A2() ), currentFrame->XYZ( (*dih).A3() ) ); // Calculate delta needed to get to theta double delta = theta_in_radians - torsion; // Set axis of rotation Vec3 axisOfRotation = currentFrame->SetAxisOfRotation((*dih).A1(), (*dih).A2()); // Calculate rotation matrix for delta rotationMatrix.CalcRotationMatrix(axisOfRotation, delta); if (debug_ > 0) { std::string a0name = CurrentParm_->TruncResAtomName( (*dih).A0() ); std::string a1name = CurrentParm_->TruncResAtomName( (*dih).A1() ); std::string a2name = CurrentParm_->TruncResAtomName( (*dih).A2() ); std::string a3name = CurrentParm_->TruncResAtomName( (*dih).A3() ); mprintf("\tRotating Dih %i:%s (%i-%i-%i-%i) (@%.2f) by %.2f deg to get to %.2f.\n", (*dih).ResNum()+1, (*dih).Name().c_str(), (*dih).A0() + 1, (*dih).A1() + 1, (*dih).A2() + 1, (*dih).A3() + 1, torsion*Constants::RADDEG, delta*Constants::RADDEG, theta_in_radians*Constants::RADDEG); } // Rotate around axis currentFrame->Rotate(rotationMatrix, *Rmask); } } return Action::OK; }
// ----------------------------------------------------------------------------- // Exec_PermuteDihedrals::IntervalAngles() void Exec_PermuteDihedrals::IntervalAngles(Frame const& frameIn, Topology const& topIn, double interval_in_deg) { Matrix_3x3 rotationMatrix; double theta_in_radians = interval_in_deg * Constants::DEGRAD; int maxVal = (int) (360.0 / interval_in_deg); if (maxVal < 0) maxVal = -maxVal; // Write original frame if (outtraj_.IsInitialized()) outtraj_.WriteSingle(outframe_++, frameIn); if (crdout_ != 0) crdout_->AddFrame( frameIn ); Frame currentFrame = frameIn; for (std::vector<PermuteDihedralsType>::const_iterator dih = BB_dihedrals_.begin(); dih != BB_dihedrals_.end(); ++dih) { // Set axis of rotation Vec3 axisOfRotation = currentFrame.SetAxisOfRotation(dih->atom1, dih->atom2); // Calculate rotation matrix for interval rotationMatrix.CalcRotationMatrix(axisOfRotation, theta_in_radians); if (debug_ > 0) { mprintf("\tRotating Dih %s-%s by %.2f deg %i times.\n", topIn.TruncResAtomName( dih->atom1 ).c_str(), topIn.TruncResAtomName( dih->atom2 ).c_str(), interval_in_deg, maxVal); } for (int rot = 0; rot != maxVal; ++rot) { // Rotate around axis currentFrame.Rotate(rotationMatrix, dih->Rmask); // Write output trajectory if (outtraj_.IsInitialized()) outtraj_.WriteSingle(outframe_++, currentFrame); if (crdout_ != 0) crdout_->AddFrame( currentFrame ); } } }
/** \param frameIn Frame to image. * \param origin If true image w.r.t. coordinate origin. * \param fcom If truncoct is true, calc distance w.r.t. this coordinate. * \param ucell Unit cell matrix. * \param recip Reciprocal coordinates matrix. * \param truncoct If true imaging will occur using truncated octahedron shape. * \param center If true image w.r.t. center coords, otherwise use first atom coords. * \param useMass If true use COM, otherwise geometric center. * \param AtomPairs Atom pairs to image. */ void Image::Nonortho(Frame& frameIn, bool origin, Vec3 const& fcom, Vec3 const& offIn, Matrix_3x3 const& ucell, Matrix_3x3 const& recip, bool truncoct, bool center, bool useMass, PairType const& AtomPairs) { Vec3 Coord; Vec3 offset = ucell.TransposeMult( offIn ); double min = -1.0; if (truncoct) min = 100.0 * (frameIn.BoxCrd().BoxX()*frameIn.BoxCrd().BoxX()+ frameIn.BoxCrd().BoxY()*frameIn.BoxCrd().BoxY()+ frameIn.BoxCrd().BoxZ()*frameIn.BoxCrd().BoxZ()); // Loop over atom pairs for (PairType::const_iterator atom = AtomPairs.begin(); atom != AtomPairs.end(); ++atom) { int firstAtom = *atom; ++atom; int lastAtom = *atom; //if (debug>2) // mprintf( " IMAGE processing atoms %i to %i\n", firstAtom+1, lastAtom); // Set up Coord with position to check for imaging based on first atom or // center of mass of atoms first to last. if (center) { if (useMass) Coord = frameIn.VCenterOfMass(firstAtom,lastAtom); else Coord = frameIn.VGeometricCenter(firstAtom,lastAtom); } else Coord = frameIn.XYZ( firstAtom ); // boxTrans will hold calculated translation needed to move atoms back into box Vec3 boxTrans = Nonortho(Coord, truncoct, origin, ucell, recip, fcom, min) + offset; frameIn.Translate(boxTrans, firstAtom, lastAtom); } // END loop over atom pairs }
/** Place selected atoms into grid cells. Convert to fractional coords, wrap * into primary cell, then determine grid cell. */ void PairList::GridUnitCell(Frame const& frmIn, Matrix_3x3 const& ucell, Matrix_3x3 const& recip, AtomMask const& maskIn) { // Clear any existing atoms in cells. for (Carray::iterator cell = cells_.begin(); cell != cells_.end(); ++cell) cell->ClearAtoms(); Frac_.clear(); Frac_.reserve( maskIn.Nselected() ); if (frmIn.BoxCrd().Type() == Box::ORTHO) { // Orthogonal imaging for (AtomMask::const_iterator atom = maskIn.begin(); atom != maskIn.end(); ++atom) { const double* XYZ = frmIn.XYZ(*atom); Vec3 fc( XYZ[0]*recip[0], XYZ[1]*recip[4], XYZ[2]*recip[8] ); Vec3 fcw(fc[0]-floor(fc[0]), fc[1]-floor(fc[1]), fc[2]-floor(fc[2])); Vec3 ccw(fcw[0]*ucell[0], fcw[1]*ucell[4], fcw[2]*ucell[8] ); # ifdef DEBUG_PAIRLIST mprintf("DBG: o %6i fc=%7.3f%7.3f%7.3f fcw=%7.3f%7.3f%7.3f ccw=%7.3f%7.3f%7.3f\n", *atom+1, fc[0], fc[1], fc[2], fcw[0], fcw[1], fcw[2], ccw[0], ccw[1], ccw[2]); # endif GridAtom( atom-maskIn.begin(), fcw, ccw ); } } else { // Non-orthogonal imaging for (AtomMask::const_iterator atom = maskIn.begin(); atom != maskIn.end(); ++atom) { Vec3 fc = recip * Vec3(frmIn.XYZ(*atom)); Vec3 fcw(fc[0]-floor(fc[0]), fc[1]-floor(fc[1]), fc[2]-floor(fc[2])); Vec3 ccw = ucell.TransposeMult( fcw ); # ifdef DEBUG_PAIRLIST mprintf("DBG: n %6i fc=%7.3f%7.3f%7.3f fcw=%7.3f%7.3f%7.3f ccw=%7.3f%7.3f%7.3f\n", *atom+1, fc[0], fc[1], fc[2], fcw[0], fcw[1], fcw[2], ccw[0], ccw[1], ccw[2]); # endif GridAtom( atom-maskIn.begin(), fcw, ccw ); } } }
/** Given the structure of a molecule and its normal mode vibrational * frequencies this routine uses standard statistical mechanical * formulas for an ideal gas (in the canonical ensemble, see, * for example, d. a. mcquarrie, "statistical thermodynamics", * harper & row, new york, 1973, chapters 5, 6, and 8) to compute * the entropy, heat capacity, and internal energy. * The si system of units is used internally. Conversion to units * more familiar to most chemists is made for output. * * \param outfile output file, should already be open. * \param temp temperature * \param patm pressure, in atmospheres */ int DataSet_Modes::Thermo( CpptrajFile& outfile, int ilevel, double temp, double patm) const { // avgcrd_ Contains coordinates in Angstroms // mass_ Contains masses in amu. // nmodes_ Number of eigenvectors (already converted to frequencies) // evalues_ vibrational frequencies, in cm**-1 and in ascending order double rtemp, rtemp1, rtemp2, rtemp3; // ----- Constants ------------------- const double thresh = 900.0; // vibrational frequency threshold const double tokg = 1.660531e-27; // kilograms per amu. const double boltz = 1.380622e-23; // boltzman constant, in joules per kelvin. const double planck = 6.626196e-34; // planck constant, in joule-seconds. // const double avog = 6.022169e+23; // avogadro constant, in mol**(-1). const double jpcal = 4.18674e+00; // joules per calorie. const double tomet = 1.0e-10; // metres per Angstrom. const double hartre = 4.35981e-18; // joules per hartree. const double pstd = 1.01325e+05; // Standard pressure in pascals // compute the gas constant, pi, pi**2, and e. // compute the conversion factors cal per joule and kcal per joule. // const double gas = avog * boltz; // pi = four * datan(one) const double pipi = Constants::PI * Constants::PI; const double e = exp(1.0); const double tocal = 1.0 / jpcal; const double tokcal = tocal / 1000.0; if (!outfile.IsOpen()) { mprinterr("Internal Error: DataSet_Modes::Thermo(): output file is not open.\n"); return 1; } // print the temperature and pressure. outfile.Printf("\n *******************\n"); outfile.Printf( " - Thermochemistry -\n"); outfile.Printf( " *******************\n\n"); outfile.Printf("\n temperature %9.3f kelvin\n pressure %9.5f atm\n",temp,patm); double pressure = pstd * patm; double rt = Constants::GASK_J * temp; // compute and print the molecular mass in amu, then convert to // kilograms. double weight = 0.0; for (Darray::const_iterator m = mass_.begin(); m != mass_.end(); ++m) weight += *m; outfile.Printf(" molecular mass (principal isotopes) %11.5f amu\n", weight); weight *= tokg; //trap non-unit multiplicities. //if (multip != 1) { // outfile.Printf("\n Warning-- assumptions made about the electronic partition function\n"); // outfile.Printf( " are not valid for multiplets!\n\n"); //} // compute contributions due to translation: // etran-- internal energy // ctran-- constant v heat capacity // stran-- entropy double dum1 = boltz * temp; double dum2 = pow(Constants::TWOPI, 1.5); double arg = pow(dum1, 1.5) / planck; arg = (arg / pressure) * (dum1 / planck); arg = arg * dum2 * (weight / planck); arg = arg * sqrt(weight) * exp(2.5); double stran = Constants::GASK_J * log(arg); double etran = 1.5 * rt; double ctran = 1.5 * Constants::GASK_J; // Compute contributions due to electronic motion: // It is assumed that the first electronic excitation energy // is much greater than kt and that the ground state has a // degeneracy of one. Under these conditions the electronic // partition function can be considered to be unity. The // ground electronic state is taken to be the zero of // electronic energy. // for monatomics print and return. if (avgcrd_.size() <= 3){ outfile.Printf("\n internal energy: %10.3f joule/mol %10.3f kcal/mol\n", etran, etran * tokcal); outfile.Printf( " entropy: %10.3f joule/k-mol %10.3f cal/k-mol\n", stran, stran * tocal); outfile.Printf( " heat capacity cv: %10.3f joule/k-mol %10.3f cal/k-mol\n", ctran, ctran * tocal); return 0; } Frame AVG; AVG.SetupFrameXM( avgcrd_, mass_ ); // Allocate workspace memory // vtemp vibrational temperatures, in kelvin. // evibn contribution to e from the vibration n. // cvibn contribution to cv from the vibration n. // svibn contribution to s from the vibration n. double* WorkSpace = new double[ 4 * nmodes_ ]; double* vtemp = WorkSpace; double* evibn = WorkSpace + nmodes_; double* cvibn = WorkSpace + nmodes_*2; double* svibn = WorkSpace + nmodes_*3; // compute contributions due to rotation. // Compute the principal moments of inertia, get the rotational // symmetry number, see if the molecule is linear, and compute // the rotational temperatures. Note the imbedded conversion // of the moments to SI units. Matrix_3x3 Inertia; AVG.CalculateInertia( AtomMask(0, AVG.Natom()), Inertia ); // NOTE: Diagonalize_Sort sorts evals/evecs in descending order, but // thermo() expects ascending. // pmom principal moments of inertia, in amu-bohr**2 and in ascending order. Vec3 pmom; Inertia.Diagonalize_Sort( pmom ); rtemp = pmom[0]; pmom[0] = pmom[2]; pmom[2] = rtemp; outfile.Printf("\n principal moments of inertia (nuclei only) in amu-A**2:\n"); outfile.Printf( " %12.2f%12.2f%12.2f\n", pmom[0], pmom[1], pmom[2]); bool linear = false; // Symmetry number: only for linear molecules. for others symmetry number is unity double sn = 1.0; if (AVG.Natom() <= 2) { linear = true; if (AVG.Mass(0) == AVG.Mass(1)) sn = 2.0; } outfile.Printf("\n rotational symmetry number %3.0f\n", sn); double con = planck / (boltz*8.0*pipi); con = (con / tokg) * (planck / (tomet*tomet)); if (linear) { rtemp = con / pmom[2]; if (rtemp < 0.2) { outfile.Printf("\n Warning-- assumption of classical behavior for rotation\n"); outfile.Printf( " may cause significant error\n"); } outfile.Printf("\n rotational temperature (kelvin) %12.5f\n", rtemp); } else { rtemp1 = con / pmom[0]; rtemp2 = con / pmom[1]; rtemp3 = con / pmom[2]; if (rtemp1 < 0.2) { outfile.Printf("\n Warning-- assumption of classical behavior for rotation\n"); outfile.Printf( " may cause significant error\n"); } outfile.Printf("\n rotational temperatures (kelvin) %12.5f%12.5f%12.5f\n", rtemp1, rtemp2, rtemp3); } // erot-- rotational contribution to internal energy. // crot-- rotational contribution to cv. // srot-- rotational contribution to entropy. double erot, crot, srot; if (linear) { erot = rt; crot = Constants::GASK_J; arg = (temp/rtemp) * (e/sn); srot = Constants::GASK_J * log(arg); } else { erot = 1.5 * rt; crot = 1.5 * Constants::GASK_J; arg = sqrt(Constants::PI*e*e*e) / sn; double dum = (temp/rtemp1) * (temp/rtemp2) * (temp/rtemp3); arg = arg * sqrt(dum); srot = Constants::GASK_J * log(arg); } // compute contributions due to vibration. // compute vibrational temperatures and zero point vibrational // energy. only real frequencies are included in the analysis. // ndof = 3*natoms - 6 - nimag // if (nimag .ne. 0) write(iout,1210) nimag // if (linear) ndof = ndof + 1 int ndof = nmodes_; // (---iff is the first frequency to include in thermo:) int iff; if (ilevel != 0) iff = 0; else if (linear) iff = 5; else iff = 6; con = planck / boltz; double ezpe = 0.0; for (int i = 0; i < ndof; ++i) { vtemp[i] = evalues_[i+iff] * con * 3.0e10; ezpe += evalues_[i+iff] * 3.0e10; } ezpe = 0.5 * planck * ezpe; outfile.Printf("\n zero point vibrational energy %12.1f (joules/mol) \n" " %12.5f (kcal/mol)\n" " %12.7f (hartree/particle)\n", ezpe*Constants::NA, ezpe*tokcal*Constants::NA, ezpe/hartre); // compute the number of vibrations for which more than 5% of an // assembly of molecules would exist in vibrational excited states. // special printing for these modes is done to allow the user to // easily take internal rotations into account. the criterion // corresponds roughly to a low frequency of 1.9(10**13) hz, or // 625 cm**(-1), or a vibrational temperature of 900 k. int lofreq = 0; for (int i = 0; i < ndof; ++i) if (vtemp[i] < thresh) ++lofreq; if (lofreq != 0) { outfile.Printf("\n Warning-- %3i vibrations have low frequencies and may represent hindered \n", lofreq); outfile.Printf( " internal rotations. The contributions printed below assume that these \n"); outfile.Printf( " really are vibrations.\n"); } // compute: // evib-- the vibrational component of the internal energy. // cvib-- the vibrational component of the heat capacity. // svib-- the vibrational component of the entropy. double evib = 0.0; double cvib = 0.0; double svib = 0.0; double scont; for (int i = 0; i < ndof; ++i) { // compute some common factors. double tovt = vtemp[i] / temp; double etovt = exp(tovt); double em1 = etovt - 1.0; // compute contributions due to the i'th vibration. double econt = tovt * (0.5 + 1.0/em1); double ccont = etovt * pow(tovt/em1,2.0); double argd = 1.0 - 1.0/etovt; if (argd > 1.0e-7) scont = tovt/em1 - log(argd); else { scont = 0.0; outfile.Printf(" warning: setting vibrational entropy to zero for mode %i with vtemp = %f\n", i+1, vtemp[i]); } // if (lofreq .ge. i) then evibn[i] = econt * rt; cvibn[i] = ccont * Constants::GASK_J; svibn[i] = scont * Constants::GASK_J; // end if evib += econt; cvib += ccont; svib += scont; } evib *= rt; cvib *= Constants::GASK_J; svib *= Constants::GASK_J; // the units are now: // e-- joules/mol // c-- joules/mol-kelvin // s-- joules/mol-kelvin double etot = etran + erot + evib; double ctot = ctran + crot + cvib; double stot = stran + srot + svib; // print the sum of the hartree-fock energy and the thermal energy. // call tread(501,gen,47,1,47,1,0) // esum = gen(32) + etot/avog/hartre // write(iout,1230) esum // convert to the following and print // e-- kcal/mol // c-- cal/mol-kelvin // s-- cal/mol-kelvin etran = etran * tokcal; ctran = ctran * tocal; stran = stran * tocal; erot = erot * tokcal; crot = crot * tocal; srot = srot * tocal; evib = evib * tokcal; cvib = cvib * tocal; svib = svib * tocal; etot = etran + erot + evib; ctot = ctran + crot + cvib; stot = stran + srot + svib; for (int i = 0; i < ndof; ++i) { evibn[i] *= tokcal; cvibn[i] *= tocal; svibn[i] *= tocal; } outfile.Printf("\n\n freq. E Cv S\n"); outfile.Printf( " cm**-1 kcal/mol cal/mol-kelvin cal/mol-kelvin\n"); outfile.Printf( "--------------------------------------------------------------------------------\n"); outfile.Printf( " Total %11.3f %11.3f %11.3f\n",etot,ctot,stot); outfile.Printf( " translational %11.3f %11.3f %11.3f\n",etran,ctran,stran); outfile.Printf( " rotational %11.3f %11.3f %11.3f\n",erot,crot,srot); outfile.Printf( " vibrational %11.3f %11.3f %11.3f\n",evib,cvib,svib); for (int i = 0; i < iff; ++i) outfile.Printf(" %5i%10.3f\n", i+1, evalues_[i]); for (int i = 0; i < ndof; ++i) { outfile.Printf(" %5i%10.3f %11.3f %11.3f %11.3f\n",i+iff+1, evalues_[i+iff], evibn[i], cvibn[i], svibn[i]); } delete[] WorkSpace; return 0; }
// ----------------------------------------------------------------------------- // Image::UnwrapNonortho() void Image::UnwrapNonortho( Frame& tgtIn, Frame& refIn, PairType const& AtomPairs, Matrix_3x3 const& ucell, Matrix_3x3 const& recip, bool center, bool useMass ) { Vec3 vtgt, vref, boxTrans; // Loop over atom pairs for (PairType::const_iterator atom = AtomPairs.begin(); atom != AtomPairs.end(); ++atom) { int firstAtom = *atom; ++atom; int lastAtom = *atom; if (center) { // Use center of coordinates between first and last atoms. if (useMass) { vtgt = tgtIn.VCenterOfMass(firstAtom, lastAtom); vref = refIn.VCenterOfMass(firstAtom, lastAtom); } else { vtgt = tgtIn.VGeometricCenter(firstAtom, lastAtom); vref = refIn.VGeometricCenter(firstAtom, lastAtom); } } else { // Use position first atom only. vtgt = tgtIn.XYZ( firstAtom ); vref = refIn.XYZ( firstAtom ); } boxTrans.Zero(); // Calculate original distance from the ref (previous) position. Vec3 vd = vtgt - vref; // dx dy dz double minDistanceSquare = vd.Magnitude2(); // Reciprocal coordinates vd = recip * vd ; // recip * dxyz double cx = floor(vd[0]); double cy = floor(vd[1]); double cz = floor(vd[2]); // Loop over all possible translations for (int ix = -1; ix < 2; ++ix) { for (int iy = -1; iy < 2; ++iy) { for (int iz = -1; iz < 2; ++iz) { // Calculate the translation. Vec3 vcc = ucell.TransposeMult( Vec3( cx+(double)ix, cy+(double)iy, cz+(double)iz ) ); // ucell^T * ccxyz // Calc. the potential new coordinate for tgt Vec3 vnew = vtgt - vcc; // Calc. the new distance from the ref (previous) position Vec3 vr = vref - vnew; double distanceSquare = vr.Magnitude2(); // If the orig. distance is greater than the new distance, unwrap. if ( minDistanceSquare > distanceSquare ) { minDistanceSquare = distanceSquare; boxTrans = vcc; } } } } // Translate tgt atoms boxTrans.Neg(); tgtIn.Translate( boxTrans, firstAtom, lastAtom ); // Save new ref positions int i3 = firstAtom * 3; std::copy( tgtIn.xAddress()+i3, tgtIn.xAddress()+(lastAtom*3), refIn.xAddress()+i3 ); } // END loop over atom pairs }
int notmain(void) { int i,j,k; Matrix_3x3 id; Matrix_3x3 invid; Vector vec(1,2,3); Vector res, res2; for(i=0;i<3;i++) for(j=0;j<3;j++) id.set(i,j,(float)((i*4)+j)); for(k=0;k<100;k++) { for(i=0;i<3;i++) //col for(j=0;j<3;j++) //lin { /* if(i<j) id.set(i,j,0.0); else*/ id.set(i,j, (float)( (((i*j*k)%7 + ((k+1)%3) + (i+j))+1) * (((k+i+j)%2)==0 ? -1 : 1) )); }; printf("\n\nTEST #%d\n",k); if(id.is_invertable()) { printf("Det==%g\n",id.det()); res=Vector(1.0,1.0,1.0); res=id.solve(res); printf("solve erg = %g,%g,%g\n",res[0],res[1],res[2]); res2=id*res; printf("solve test = %g,%g,%g\n",res2[0],res2[1],res2[2]); id.dump(" M"); invid=id.invert(); invid.dump("M^-1"); (id*invid).dump("mul"); }; }; id.dump("id"); printf("vec = "); dvec(vec); printf("\n"); res=id*vec; printf("res = "); dvec(res); printf("\n"); return 0; }
// Exec_PermuteDihedrals::RandomizeAngles() void Exec_PermuteDihedrals::RandomizeAngles(Frame& currentFrame, Topology const& topIn) { Matrix_3x3 rotationMatrix; # ifdef DEBUG_PERMUTEDIHEDRALS // DEBUG int debugframenum=0; Trajout_Single DebugTraj; DebugTraj.PrepareTrajWrite("debugtraj.nc",ArgList(),(Topology*)&topIn, CoordinateInfo(), BB_dihedrals_.size()*max_factor_, TrajectoryFile::AMBERNETCDF); DebugTraj.WriteSingle(debugframenum++,currentFrame); # endif int next_resnum; int bestLoop = 0; int number_of_rotations = 0; // Set max number of rotations to try. int max_rotations = (int)BB_dihedrals_.size(); max_rotations *= max_factor_; // Loop over all dihedrals std::vector<PermuteDihedralsType>::const_iterator next_dih = BB_dihedrals_.begin(); next_dih++; for (std::vector<PermuteDihedralsType>::const_iterator dih = BB_dihedrals_.begin(); dih != BB_dihedrals_.end(); ++dih, ++next_dih) { ++number_of_rotations; // Get the residue atom of the next dihedral. Residues up to and // including this residue will be checked for bad clashes if (next_dih != BB_dihedrals_.end()) next_resnum = next_dih->resnum; else next_resnum = dih->resnum - 1; // Set axis of rotation Vec3 axisOfRotation = currentFrame.SetAxisOfRotation(dih->atom1, dih->atom2); // Generate random value to rotate by in radians // Guaranteed to rotate by at least 1 degree. // NOTE: could potentially rotate 360 - prevent? // FIXME: Just use 2PI and rn_gen, get everything in radians double theta_in_degrees = ((int)(RN_.rn_gen()*100000) % 360) + 1; double theta_in_radians = theta_in_degrees * Constants::DEGRAD; // Calculate rotation matrix for random theta rotationMatrix.CalcRotationMatrix(axisOfRotation, theta_in_radians); int loop_count = 0; double clash = 0; double bestClash = 0; if (debug_>0) mprintf("DEBUG: Rotating dihedral %zu res %8i:\n", dih - BB_dihedrals_.begin(), dih->resnum+1); bool rotate_dihedral = true; while (rotate_dihedral) { if (debug_>0) { mprintf("\t%8i %12s %12s, +%.2lf degrees (%i).\n",dih->resnum+1, topIn.AtomMaskName(dih->atom1).c_str(), topIn.AtomMaskName(dih->atom2).c_str(), theta_in_degrees,loop_count); } // Rotate around axis currentFrame.Rotate(rotationMatrix, dih->Rmask); # ifdef DEBUG_PERMUTEDIHEDRALS // DEBUG DebugTraj.WriteSingle(debugframenum++,currentFrame); # endif // If we dont care about sterics exit here if (!check_for_clashes_) break; // Check resulting structure for issues int checkresidue; if (!checkAllResidues_) checkresidue = CheckResidue(currentFrame, topIn, *dih, next_resnum, clash); else checkresidue = CheckResidue(currentFrame, topIn, *dih, topIn.Nres(), clash); if (checkresidue==0) rotate_dihedral = false; else if (checkresidue==-1) { if (dih - BB_dihedrals_.begin() < 2) { mprinterr("Error: Cannot backtrack; initial structure already has clashes.\n"); number_of_rotations = max_rotations + 1; } else { dih--; // 0 dih--; // -1 next_dih = dih; next_dih++; if (debug_>0) mprintf("\tCannot resolve clash with further rotations, trying previous again.\n"); } break; } if (clash > bestClash) {bestClash = clash; bestLoop = loop_count;} //n_problems = CheckResidues( currentFrame, second_atom ); //if (n_problems > -1) { // mprintf("%i\tCheckResidues: %i problems.\n",frameNum,n_problems); // rotate_dihedral = false; //} else if (loop_count==0) { if (loop_count==0 && rotate_dihedral) { if (debug_>0) mprintf("\tTrying dihedral increments of +%i\n",increment_); // Instead of a new random dihedral, try increments theta_in_degrees = (double)increment_; theta_in_radians = theta_in_degrees * Constants::DEGRAD; // Calculate rotation matrix for new theta rotationMatrix.CalcRotationMatrix(axisOfRotation, theta_in_radians); } ++loop_count; if (loop_count == max_increment_) { if (debug_>0) mprintf("%i iterations! Best clash= %.3lf at %i\n",max_increment_, sqrt(bestClash),bestLoop); if (dih - BB_dihedrals_.begin() < backtrack_) { mprinterr("Error: Cannot backtrack; initial structure already has clashes.\n"); number_of_rotations = max_rotations + 1; } else { for (int bt = 0; bt < backtrack_; bt++) dih--; next_dih = dih; next_dih++; if (debug_>0) mprintf("\tCannot resolve clash with further rotations, trying previous %i again.\n", backtrack_ - 1); } break; // Calculate how much to rotate back in order to get to best clash /*int num_back = bestLoop - 359; theta_in_degrees = (double) num_back; theta_in_radians = theta_in_degrees * Constants::DEGRAD; // Calculate rotation matrix for theta calcRotationMatrix(rotationMatrix, axisOfRotation, theta_in_radians); // Rotate back to best clash frm.Frm().RotateAroundAxis(rotationMatrix, theta_in_radians, dih->Rmask); // DEBUG DebugTraj.WriteFrame(debugframenum++,currentParm,*currentFrame); // Sanity check CheckResidue(currentFrame, *dih, second_atom, &clash); rotate_dihedral=false;*/ //DebugTraj.EndTraj(); //return 1; } } // End dihedral rotation loop // Safety valve - number of defined dihedrals times * maxfactor if (number_of_rotations > max_rotations) { mprinterr("Error: # of rotations (%i) exceeds max rotations (%i), exiting.\n", number_of_rotations, max_rotations); //# ifdef DEBUG_PERMUTEDIHEDRALS // DebugTraj.EndTraj(); //# endif // Return gracefully for now break; //return 1; } } // End loop over dihedrals # ifdef DEBUG_PERMUTEDIHEDRALS DebugTraj.EndTraj(); mprintf("\tNumber of rotations %i, expected %u\n",number_of_rotations,BB_dihedrals_.size()); # endif }
// Exec_RotateDihedral::Execute() Exec::RetType Exec_RotateDihedral::Execute(CpptrajState& State, ArgList& argIn) { // Get input COORDS set std::string setname = argIn.GetStringKey("crdset"); if (setname.empty()) { mprinterr("Error: Specify COORDS dataset name with 'crdset'.\n"); return CpptrajState::ERR; } DataSet_Coords* CRD = (DataSet_Coords*)State.DSL().FindCoordsSet( setname ); if (CRD == 0) { mprinterr("Error: Could not find COORDS set '%s'\n", setname.c_str()); return CpptrajState::ERR; } if (CRD->Size() < 1) { mprinterr("Error: COORDS set is empty.\n"); return CpptrajState::ERR; } int frame = argIn.getKeyInt("frame", 0); if (frame < 0 || frame >= (int)CRD->Size()) { mprinterr("Error: Specified frame %i is out of range.\n", frame+1); return CpptrajState::ERR; } mprintf(" ROTATEDIHEDRAL: Using COORDS '%s', frame %i\n", CRD->legend(), frame+1); // Get target frame Frame FRM = CRD->AllocateFrame(); CRD->GetFrame(frame, FRM); // Save as reference Frame refFrame = FRM; // Create output COORDS set if necessary DataSet_Coords* OUT = 0; int outframe = 0; std::string outname = argIn.GetStringKey("name"); if (outname.empty()) { // This will not work for TRAJ data sets if (CRD->Type() == DataSet::TRAJ) { mprinterr("Error: Using TRAJ as input set requires use of 'name' keyword for output.\n"); return CpptrajState::ERR; } OUT = CRD; outframe = frame; } else { // Create new output set with 1 empty frame. OUT = (DataSet_Coords*)State.DSL().AddSet( DataSet::COORDS, outname ); if (OUT == 0) return CpptrajState::ERR; OUT->Allocate( DataSet::SizeArray(1, 1) ); OUT->CoordsSetup( CRD->Top(), CRD->CoordsInfo() ); OUT->AddFrame( CRD->AllocateFrame() ); mprintf("\tOutput to set '%s'\n", OUT->legend()); } // Determine whether we are setting or incrementing. enum ModeType { SET = 0, INCREMENT }; ModeType mode = SET; if (argIn.Contains("value")) mode = SET; else if (argIn.Contains("increment")) mode = INCREMENT; else { mprinterr("Error: Specify 'value <value>' or 'increment <increment>'\n"); return CpptrajState::ERR; } double value = argIn.getKeyDouble(ModeStr[mode], 0.0); switch (mode) { case SET: mprintf("\tDihedral will be set to %g degrees.\n", value); break; case INCREMENT: mprintf("\tDihedral will be incremented by %g degrees.\n", value); break; } // Convert to radians value *= Constants::DEGRAD; // Select dihedral atoms int A1, A2, A3, A4; if (argIn.Contains("type")) { // By type ArgList typeArg = argIn.GetStringKey("type"); if (typeArg.empty()) { mprinterr("Error: No dihedral type specified after 'type'\n"); return CpptrajState::ERR; } DihedralSearch dihSearch; dihSearch.SearchForArgs( typeArg ); if (dihSearch.NoDihedralTokens()) { mprinterr("Error: Specified dihedral type not recognized.\n"); return CpptrajState::ERR; } // Get residue int res = argIn.getKeyInt("res", -1); if (res <= 0) { mprinterr("Error: If 'type' specified 'res' must be specified and > 0.\n"); return CpptrajState::ERR; } // Search for dihedrals. User residue #s start from 1. if (dihSearch.FindDihedrals(CRD->Top(), Range(res-1))) return CpptrajState::ERR; DihedralSearch::mask_it dih = dihSearch.begin(); A1 = dih->A0(); A2 = dih->A1(); A3 = dih->A2(); A4 = dih->A3(); } else { // By masks AtomMask m1( argIn.GetMaskNext() ); AtomMask m2( argIn.GetMaskNext() ); AtomMask m3( argIn.GetMaskNext() ); AtomMask m4( argIn.GetMaskNext() ); if (CRD->Top().SetupIntegerMask( m1 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m2 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m3 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m4 )) return CpptrajState::ERR; if (m1.Nselected() != 1) return MaskError( m1 ); if (m2.Nselected() != 1) return MaskError( m2 ); if (m3.Nselected() != 1) return MaskError( m3 ); if (m4.Nselected() != 1) return MaskError( m4 ); A1 = m1[0]; A2 = m2[0]; A3 = m3[0]; A4 = m4[0]; } mprintf("\tRotating dihedral defined by atoms '%s'-'%s'-'%s'-'%s'\n", CRD->Top().AtomMaskName(A1).c_str(), CRD->Top().AtomMaskName(A2).c_str(), CRD->Top().AtomMaskName(A3).c_str(), CRD->Top().AtomMaskName(A4).c_str()); // Set mask of atoms that will move during dihedral rotation AtomMask Rmask = DihedralSearch::MovingAtoms(CRD->Top(), A2, A3); // Calculate current value of dihedral double torsion = Torsion( FRM.XYZ(A1), FRM.XYZ(A2), FRM.XYZ(A3), FRM.XYZ(A4) ); // Calculate delta needed to get to target value. double delta; switch (mode) { case SET: delta = value - torsion; break; case INCREMENT: delta = value; break; } mprintf("\tOriginal torsion is %g, rotating by %g degrees.\n", torsion*Constants::RADDEG, delta*Constants::RADDEG); // Set axis of rotation Vec3 axisOfRotation = FRM.SetAxisOfRotation( A2, A3 ); // Calculate rotation matrix for delta. Matrix_3x3 rotationMatrix; rotationMatrix.CalcRotationMatrix(axisOfRotation, delta); // Rotate around axis FRM.Rotate(rotationMatrix, Rmask); // RMS-fit the non-moving part of the coords back on original AtomMask refMask = Rmask; refMask.InvertMask(); FRM.Align( refFrame, refMask ); // Update coords OUT->SetCRD( outframe, FRM ); return CpptrajState::OK; }