/** \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; }
// Action_ReplicateCell::Init() Action::RetType Action_ReplicateCell::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { // Require imaging. image_.InitImaging( true ); // Set up output traj std::string trajfilename = actionArgs.GetStringKey("out"); parmfilename_ = actionArgs.GetStringKey("parmout"); bool setAll = actionArgs.hasKey("all"); std::string dsname = actionArgs.GetStringKey("name"); if (!dsname.empty()) { coords_ = (DataSet_Coords*)init.DSL().AddSet(DataSet::COORDS, dsname, "RCELL"); if (coords_ == 0) return Action::ERR; } if (trajfilename.empty() && coords_ == 0) { mprinterr("Error: Either 'out <traj filename> or 'name <dsname>' must be specified.\n"); return Action::ERR; } // Get Mask Mask1_.SetMaskString( actionArgs.GetMaskNext() ); // Determine which directions to set if (setAll) { for (int ix = -1; ix < 2; ix++) for (int iy = -1; iy < 2; iy++) for (int iz = -1; iz < 2; iz++) { directionArray_.push_back( ix ); directionArray_.push_back( iy ); directionArray_.push_back( iz ); } } else { std::string dirstring = actionArgs.GetStringKey("dir"); while (!dirstring.empty()) { std::vector<int> ixyz(3, -2); std::vector<int>::iterator iptr = ixyz.begin(); for (std::string::const_iterator c = dirstring.begin(); c != dirstring.end(); ++c) { if (iptr == ixyz.end()) { mprinterr("Error: 'dir' string has too many characters.\n"); return Action::ERR; } int sign = 1; if (*c == '+') ++c; else if (*c == '-') { sign = -1; ++c; } if (isdigit( *c )) *iptr = toDigit( *c ) * sign; else { mprinterr("Error: illegal character '%c' in 'dir' string '%s'; only numbers allowed.\n", *c, dirstring.c_str()); return Action::ERR; } ++iptr; } //mprintf("DEBUG: %s = %i %i %i\n", dirstring.c_str(), ixyz[0], ixyz[1], ixyz[2]); directionArray_.push_back( ixyz[0] ); directionArray_.push_back( ixyz[1] ); directionArray_.push_back( ixyz[2] ); dirstring = actionArgs.GetStringKey("dir"); } } ncopies_ = (int)(directionArray_.size() / 3); if (ncopies_ < 1) { mprinterr("Error: No directions (or 'all') specified.\n"); return Action::ERR; } // Initialize output trajectory with remaining arguments if (!trajfilename.empty()) { outtraj_.SetDebug( debugIn ); if ( outtraj_.InitEnsembleTrajWrite(trajfilename, actionArgs.RemainingArgs(), TrajectoryFile::UNKNOWN_TRAJ, init.DSL().EnsembleNum()) ) return Action::ERR; writeTraj_ = true; # ifdef MPI outtraj_.SetTrajComm( init.TrajComm() ); # endif } else writeTraj_ = false; mprintf(" REPLICATE CELL: Replicating cell in %i directions:\n", ncopies_); mprintf("\t\t X Y Z\n"); for (unsigned int i = 0; i != directionArray_.size(); i += 3) mprintf("\t\t%2i %2i %2i\n", directionArray_[i], directionArray_[i+1], directionArray_[i+2]); mprintf("\tUsing atoms in mask '%s'\n", Mask1_.MaskString()); if (writeTraj_) mprintf("\tWriting to trajectory %s\n", outtraj_.Traj().Filename().full()); if (!parmfilename_.empty()) mprintf("\tWriting topology %s\n", parmfilename_.c_str()); if (coords_ != 0) mprintf("\tSaving coords to data set %s\n", coords_->legend()); return Action::OK; }
// Action_Diffusion::DoAction() Action::RetType Action_Diffusion::DoAction(int frameNum, ActionFrame& frm) { Matrix_3x3 ucell, recip; // Load initial frame if necessary if (initial_.empty()) { initial_ = frm.Frm(); # ifdef MPI if (trajComm_.Size() > 1) { if (trajComm_.Master()) for (int rank = 1; rank < trajComm_.Size(); ++rank) initial_.SendFrame( rank, trajComm_ ); else initial_.RecvFrame( 0, trajComm_ ); } # endif for (AtomMask::const_iterator atom = mask_.begin(); atom != mask_.end(); ++atom) { const double* XYZ = initial_.XYZ(*atom); previous_.push_back( XYZ[0] ); previous_.push_back( XYZ[1] ); previous_.push_back( XYZ[2] ); } } // Diffusion calculation if (image_.ImageType() != NOIMAGE) { boxcenter_ = frm.Frm().BoxCrd().Center(); if (image_.ImageType() == NONORTHO) frm.Frm().BoxCrd().ToRecip(ucell, recip); } // For averaging over selected atoms double average2 = 0.0; double avgx = 0.0; double avgy = 0.0; double avgz = 0.0; unsigned int idx = 0; // Index into previous_ and delta_ for (AtomMask::const_iterator at = mask_.begin(); at != mask_.end(); ++at, idx += 3) { // Get current and initial coords for this atom. const double* XYZ = frm.Frm().XYZ(*at); const double* iXYZ = initial_.XYZ(*at); // Calculate distance from initial position. double delx, dely, delz; if ( image_.ImageType() == ORTHO ) { // Orthorhombic imaging // Calculate distance to previous frames coordinates. delx = XYZ[0] - previous_[idx ]; dely = XYZ[1] - previous_[idx+1]; delz = XYZ[2] - previous_[idx+2]; // If the particle moved more than half the box, assume it was imaged // and adjust the distance of the total movement with respect to the // original frame. if (delx > boxcenter_[0]) delta_[idx ] -= frm.Frm().BoxCrd().BoxX(); else if (delx < -boxcenter_[0]) delta_[idx ] += frm.Frm().BoxCrd().BoxX(); if (dely > boxcenter_[1]) delta_[idx+1] -= frm.Frm().BoxCrd().BoxY(); else if (dely < -boxcenter_[1]) delta_[idx+1] += frm.Frm().BoxCrd().BoxY(); if (delz > boxcenter_[2]) delta_[idx+2] -= frm.Frm().BoxCrd().BoxZ(); else if (delz < -boxcenter_[2]) delta_[idx+2] += frm.Frm().BoxCrd().BoxZ(); // Calculate the distance between this "fixed" coordinate // and the reference (initial) frame. delx = XYZ[0] + delta_[idx ] - iXYZ[0]; dely = XYZ[1] + delta_[idx+1] - iXYZ[1]; delz = XYZ[2] + delta_[idx+2] - iXYZ[2]; } else if ( image_.ImageType() == NONORTHO ) { // Non-orthorhombic imaging // Calculate distance to previous frames coordinates. delx = XYZ[0] - previous_[idx ]; dely = XYZ[1] - previous_[idx+1]; delz = XYZ[2] - previous_[idx+2]; // If the particle moved more than half the box, assume it was imaged // and adjust the distance of the total movement with respect to the // original frame. if (fabs(delx) > boxcenter_[0] || fabs(dely) > boxcenter_[1] || fabs(delz) > boxcenter_[2]) { // Previous position in Cartesian space Vec3 pCart( previous_[idx], previous_[idx+1], previous_[idx+2] ); // Current position in fractional coords Vec3 cFrac = recip * Vec3( XYZ[0], XYZ[1], XYZ[2] ); // Look for imaged distance closer to previous than current position double minDist2 = frm.Frm().BoxCrd().BoxX() * frm.Frm().BoxCrd().BoxY() * frm.Frm().BoxCrd().BoxZ(); Vec3 minCurr(0.0); 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 current position Vec3 ixyz(ix, iy, iz); // Current position shifted and back in Cartesian space Vec3 IMG = ucell.TransposeMult(cFrac + ixyz); // Distance from previous position to imaged current position Vec3 dxyz = IMG - pCart; double dist2 = dxyz.Magnitude2(); if (dist2 < minDist2) { minDist2 = dist2; minCurr = IMG; } } } } } // Update the delta for this atom delta_[idx ] += minCurr[0] - XYZ[0]; // cCart delta_[idx+1] += minCurr[1] - XYZ[1]; delta_[idx+2] += minCurr[2] - XYZ[2]; } // Calculate the distance between this "fixed" coordinate // and the reference (initial) frame. delx = XYZ[0] + delta_[idx ] - iXYZ[0]; dely = XYZ[1] + delta_[idx+1] - iXYZ[1]; delz = XYZ[2] + delta_[idx+2] - iXYZ[2]; } else { // No imaging. Calculate distance from current position to initial position. delx = XYZ[0] - iXYZ[0]; dely = XYZ[1] - iXYZ[1]; delz = XYZ[2] - iXYZ[2]; } // Calc distances for this atom double distx = delx * delx; double disty = dely * dely; double distz = delz * delz; double dist2 = distx + disty + distz; // Accumulate averages avgx += distx; avgy += disty; avgz += distz; average2 += dist2; // Store distances for this atom if (printIndividual_) { float fval = (float)distx; atom_x_[*at]->Add(frameNum, &fval); fval = (float)disty; atom_y_[*at]->Add(frameNum, &fval); fval = (float)distz; atom_z_[*at]->Add(frameNum, &fval); fval = (float)dist2; atom_r_[*at]->Add(frameNum, &fval); dist2 = sqrt(dist2); fval = (float)dist2; atom_a_[*at]->Add(frameNum, &fval); } // Update the previous coordinate set to match the current coordinates previous_[idx ] = XYZ[0]; previous_[idx+1] = XYZ[1]; previous_[idx+2] = XYZ[2]; } // END loop over selected atoms // Calc averages double dNselected = 1.0 / (double)mask_.Nselected(); avgx *= dNselected; avgy *= dNselected; avgz *= dNselected; average2 *= dNselected; // Save averages avg_x_->Add(frameNum, &avgx); avg_y_->Add(frameNum, &avgy); avg_z_->Add(frameNum, &avgz); avg_r_->Add(frameNum, &average2); average2 = sqrt(average2); avg_a_->Add(frameNum, &average2); return Action::OK; }
// Action_ReplicateCell::Init() Action::RetType Action_ReplicateCell::Init(ArgList& actionArgs, TopologyList* PFL, DataSetList* DSL, DataFileList* DFL, int debugIn) { // Require imaging. image_.InitImaging( true ); // Set up output traj trajfilename_ = actionArgs.GetStringKey("out"); parmfilename_ = actionArgs.GetStringKey("parmout"); Topology* tempParm = PFL->GetParm( actionArgs ); bool setAll = actionArgs.hasKey("all"); std::string dsname = actionArgs.GetStringKey("name"); if (!dsname.empty()) { coords_ = (DataSet_Coords*)DSL->AddSet(DataSet::COORDS, dsname, "RCELL"); if (coords_ == 0) return Action::ERR; } if (trajfilename_.empty() && coords_ == 0) { mprinterr("Error: Either 'out <traj filename> or 'name <dsname>' must be specified.\n"); return Action::ERR; } // Get Mask Mask1_.SetMaskString( actionArgs.GetMaskNext() ); // Determine which directions to set if (setAll) { for (int ix = -1; ix < 2; ix++) for (int iy = -1; iy < 2; iy++) for (int iz = -1; iz < 2; iz++) { directionArray_.push_back( ix ); directionArray_.push_back( iy ); directionArray_.push_back( iz ); } } else { std::string dirstring = actionArgs.GetStringKey("dir"); while (!dirstring.empty()) { std::vector<int> ixyz(3, -2); std::vector<int>::iterator iptr = ixyz.begin(); for (std::string::const_iterator c = dirstring.begin(); c != dirstring.end(); ++c) { if (iptr == ixyz.end()) { mprinterr("Error: 'dir' string has too many characters.\n"); return Action::ERR; } int sign = 1; if (*c == '+') ++c; else if (*c == '-') { sign = -1; ++c; } if (*c == '1') *iptr = 1 * sign; else if (*c == '0') *iptr = 0; ++iptr; } mprintf("DEBUG: %s = %i %i %i\n", dirstring.c_str(), ixyz[0], ixyz[1], ixyz[2]); directionArray_.push_back( ixyz[0] ); directionArray_.push_back( ixyz[1] ); directionArray_.push_back( ixyz[2] ); dirstring = actionArgs.GetStringKey("dir"); } } ncopies_ = (int)(directionArray_.size() / 3); if (ncopies_ < 1) { mprinterr("Error: No directions (or 'all') specified.\n"); return Action::ERR; } // Set up output trajectory if (!trajfilename_.empty()) { if (tempParm == 0) { mprinterr("Error: Could not get topology for %s\n", trajfilename_.c_str()); return Action::ERR; } outtraj_.SetDebug( debugIn ); // Initialize output trajectory with remaining arguments trajArgs_ = actionArgs.RemainingArgs(); ensembleNum_ = DSL->EnsembleNum(); } mprintf(" REPLICATE CELL: Replicating cell in %i directions:\n", ncopies_); mprintf("\t\t X Y Z\n"); for (unsigned int i = 0; i != directionArray_.size(); i += 3) mprintf("\t\t%2i %2i %2i\n", directionArray_[i], directionArray_[i+1], directionArray_[i+2]); mprintf("\tUsing atoms in mask '%s'\n", Mask1_.MaskString()); if (!trajfilename_.empty()) mprintf("\tWriting to trajectory %s\n", trajfilename_.c_str()); if (!parmfilename_.empty()) mprintf("\tWriting topology %s\n", parmfilename_.c_str()); if (coords_ != 0) mprintf("\tSaving coords to data set %s\n", coords_->legend()); return Action::OK; }