// Traj_NcEnsemble::setupTrajout() int Traj_NcEnsemble::setupTrajout(FileName const& fname, Topology* trajParm, CoordinateInfo const& cInfoIn, int NframesToWrite, bool append) { int err = 0; # ifdef MPI if (NoPnetcdf()) return 1; # endif readAccess_ = false; if (!append) { CoordinateInfo cInfo = cInfoIn; // TODO: File output modifications SetCoordInfo( cInfo ); # ifdef MPI ensembleStart_ = Parallel::World().Rank(); ensembleEnd_ = Parallel::World().Rank() + 1; # else ensembleStart_ = 0; ensembleEnd_ = cInfo.EnsembleSize();; # endif filename_ = fname; // Set up title if (Title().empty()) SetTitle("Cpptraj Generated trajectory"); # ifdef MPI if (Parallel::World().Master()) { // Only master creates file. # endif // Create NetCDF file. err = NC_create(filename_.Full(), NC_AMBERENSEMBLE, trajParm->Natom(), CoordInfo(), Title(), debug_); // Close Netcdf file. It will be reopened write. FIXME should NC_create leave it closed? NC_close(); # ifdef MPI } Parallel::World().MasterBcast(&err, 1, MPI_INT); # endif if (err != 0) return 1; # ifdef MPI // Synchronize netcdf info on non-master threads Sync(Parallel::World()); // DEBUG: Print info for all ranks DebugVIDs(); # endif // Allocate memory if (Coord_!=0) delete[] Coord_; Coord_ = new float[ Ncatom3() ]; } else { // NOTE: File existence is checked for in Trajout // Call setupTrajin to set input parameters. This will also allocate // memory for coords. if (setupTrajin(fname, trajParm) == TRAJIN_ERR) return 1; if (debug_ > 0) mprintf("\tNetCDF: Appending %s starting at frame %i\n", filename_.base(), Ncframe()); } // Open file # ifdef HAS_PNETCDF err = ncmpi_open(MPI_COMM_WORLD, filename_.full(), NC_WRITE, MPI_INFO_NULL, &ncid_); // TODO: Graceful error handling # else err = NC_openWrite( filename_.Full() ); # endif if ( err != 0 ) { mprinterr("Error: Opening Netcdf file %s for Write.\n", filename_.base()); return 1; } return 0; }
// NetcdfFile::NC_create() int NetcdfFile::NC_create(std::string const& Name, NCTYPE type, int natomIn, CoordinateInfo const& coordInfo, std::string const& title) { if (Name.empty()) return 1; int dimensionID[NC_MAX_VAR_DIMS]; int NDIM; nc_type dataType; if (ncdebug_>1) mprintf("DEBUG: NC_create: %s natom=%i V=%i F=%i box=%i temp=%i time=%i\n", Name.c_str(),natomIn,(int)coordInfo.HasVel(), (int)coordInfo.HasForce(),(int)coordInfo.HasBox(), (int)coordInfo.HasTemp(),(int)coordInfo.HasTime()); if ( checkNCerr( nc_create( Name.c_str(), NC_64BIT_OFFSET, &ncid_) ) ) return 1; ncatom_ = natomIn; ncatom3_ = ncatom_ * 3; // Set number of dimensions based on file type switch (type) { case NC_AMBERENSEMBLE: NDIM = 4; dataType = NC_FLOAT; break; case NC_AMBERTRAJ: NDIM = 3; dataType = NC_FLOAT; break; case NC_AMBERRESTART: NDIM = 2; dataType = NC_DOUBLE; break; default: mprinterr("Error: NC_create (%s): Unrecognized type (%i)\n",Name.c_str(),(int)type); return 1; } if (type == NC_AMBERENSEMBLE) { // Ensemble dimension for ensemble if (coordInfo.EnsembleSize() < 1) { mprinterr("Internal Error: NetcdfFile: ensembleSize < 1\n"); return 1; } if ( checkNCerr(nc_def_dim(ncid_, NCENSEMBLE, coordInfo.EnsembleSize(), &ensembleDID_)) ) { mprinterr("Error: Defining ensemble dimension.\n"); return 1; } dimensionID[1] = ensembleDID_; } ncframe_ = 0; if (type == NC_AMBERTRAJ || type == NC_AMBERENSEMBLE) { // Frame dimension for traj if ( checkNCerr( nc_def_dim( ncid_, NCFRAME, NC_UNLIMITED, &frameDID_)) ) { mprinterr("Error: Defining frame dimension.\n"); return 1; } // Since frame is UNLIMITED, it must be lowest dim. dimensionID[0] = frameDID_; } // Time variable and units if (coordInfo.HasTime()) { if ( checkNCerr( nc_def_var(ncid_, NCTIME, dataType, NDIM-2, dimensionID, &timeVID_)) ) { mprinterr("Error: Defining time variable.\n"); return 1; } if ( checkNCerr( nc_put_att_text(ncid_, timeVID_, "units", 10, "picosecond")) ) { mprinterr("Error: Writing time VID units.\n"); return 1; } } // Spatial dimension and variable if ( checkNCerr( nc_def_dim( ncid_, NCSPATIAL, 3, &spatialDID_)) ) { mprinterr("Error: Defining spatial dimension.\n"); return 1; } dimensionID[0] = spatialDID_; if ( checkNCerr( nc_def_var( ncid_, NCSPATIAL, NC_CHAR, 1, dimensionID, &spatialVID_)) ) { mprinterr("Error: Defining spatial variable.\n"); return 1; } // Atom dimension if ( checkNCerr( nc_def_dim( ncid_, NCATOM, ncatom_, &atomDID_)) ) { mprinterr("Error: Defining atom dimension.\n"); return 1; } // Setup dimensions for Coords/Velocity // NOTE: THIS MUST BE MODIFIED IF NEW TYPES ADDED if (type == NC_AMBERENSEMBLE) { dimensionID[0] = frameDID_; dimensionID[1] = ensembleDID_; dimensionID[2] = atomDID_; dimensionID[3] = spatialDID_; } else if (type == NC_AMBERTRAJ) { dimensionID[0] = frameDID_; dimensionID[1] = atomDID_; dimensionID[2] = spatialDID_; } else { dimensionID[0] = atomDID_; dimensionID[1] = spatialDID_; } // Coord variable if ( checkNCerr( nc_def_var( ncid_, NCCOORDS, dataType, NDIM, dimensionID, &coordVID_)) ) { mprinterr("Error: Defining coordinates variable.\n"); return 1; } if ( checkNCerr( nc_put_att_text( ncid_, coordVID_, "units", 8, "angstrom")) ) { mprinterr("Error: Writing coordinates variable units.\n"); return 1; } // Velocity variable if (coordInfo.HasVel()) { if ( checkNCerr( nc_def_var( ncid_, NCVELO, dataType, NDIM, dimensionID, &velocityVID_)) ) { mprinterr("Error: Defining velocities variable.\n"); return 1; } if ( checkNCerr( nc_put_att_text( ncid_, velocityVID_, "units", 19, "angstrom/picosecond")) ) { mprinterr("Error: Writing velocities variable units.\n"); return 1; } if ( checkNCerr( nc_put_att_double( ncid_, velocityVID_, "scale_factor", NC_DOUBLE, 1, &Constants::AMBERTIME_TO_PS)) ) { mprinterr("Error: Writing velocities scale factor.\n"); return 1; } } // Force variable if (coordInfo.HasForce()) { if ( checkNCerr( nc_def_var( ncid_, NCFRC, dataType, NDIM, dimensionID, &frcVID_)) ) { mprinterr("Error: Defining forces variable\n"); return 1; } if ( checkNCerr( nc_put_att_text( ncid_, frcVID_, "units", 25, "kilocalorie/mole/angstrom")) ) { mprinterr("Error: Writing forces variable units.\n"); return 1; } } // Replica Temperature if (coordInfo.HasTemp()) { // NOTE: Setting dimensionID should be OK for Restart, will not be used. dimensionID[0] = frameDID_; if ( NC_defineTemperature( dimensionID, NDIM-2 ) ) return 1; } // Replica indices int remDimTypeVID = -1; if (coordInfo.HasReplicaDims()) { // Define number of replica dimensions remd_dimension_ = coordInfo.ReplicaDimensions().Ndims(); int remDimDID = -1; if ( checkNCerr(nc_def_dim(ncid_, NCREMD_DIMENSION, remd_dimension_, &remDimDID)) ) { mprinterr("Error: Defining replica indices dimension.\n"); return 1; } dimensionID[0] = remDimDID; // For each dimension, store the type if ( checkNCerr(nc_def_var(ncid_, NCREMD_DIMTYPE, NC_INT, 1, dimensionID, &remDimTypeVID)) ) { mprinterr("Error: Defining replica dimension type variable.\n"); return 1; } // Need to store the indices of replica in each dimension each frame // NOTE: THIS MUST BE MODIFIED IF NEW TYPES ADDED if (type == NC_AMBERENSEMBLE) { dimensionID[0] = frameDID_; dimensionID[1] = ensembleDID_; dimensionID[2] = remDimDID; } else if (type == NC_AMBERTRAJ) { dimensionID[0] = frameDID_; dimensionID[1] = remDimDID; } else { dimensionID[0] = remDimDID; } if (checkNCerr(nc_def_var(ncid_, NCREMD_INDICES, NC_INT, NDIM-1, dimensionID, &indicesVID_))) { mprinterr("Error: Defining replica indices variable ID.\n"); return 1; } // TODO: Determine if groups are really necessary for restarts. If not, // remove from AmberNetcdf.F90. } // Box Info if (coordInfo.HasBox()) { // Cell Spatial if ( checkNCerr( nc_def_dim( ncid_, NCCELL_SPATIAL, 3, &cell_spatialDID_)) ) { mprinterr("Error: Defining cell spatial dimension.\n"); return 1; } dimensionID[0] = cell_spatialDID_; if ( checkNCerr( nc_def_var(ncid_, NCCELL_SPATIAL, NC_CHAR, 1, dimensionID, &cell_spatialVID_))) { mprinterr("Error: Defining cell spatial variable.\n"); return 1; } // Cell angular if ( checkNCerr( nc_def_dim( ncid_, NCLABEL, NCLABELLEN, &labelDID_)) ) { mprinterr("Error: Defining label dimension.\n"); return 1; } if ( checkNCerr( nc_def_dim( ncid_, NCCELL_ANGULAR, 3, &cell_angularDID_)) ) { mprinterr("Error: Defining cell angular dimension.\n"); return 1; } dimensionID[0] = cell_angularDID_; dimensionID[1] = labelDID_; if ( checkNCerr( nc_def_var( ncid_, NCCELL_ANGULAR, NC_CHAR, 2, dimensionID, &cell_angularVID_)) ) { mprinterr("Error: Defining cell angular variable.\n"); return 1; } // Setup dimensions for Box // NOTE: This must be modified if more types added int boxdim; if (type == NC_AMBERENSEMBLE) { dimensionID[0] = frameDID_; dimensionID[1] = ensembleDID_; boxdim = 2; } else if (type == NC_AMBERTRAJ) { dimensionID[0] = frameDID_; boxdim = 1; } else { boxdim = 0; } dimensionID[boxdim] = cell_spatialDID_; if ( checkNCerr( nc_def_var( ncid_, NCCELL_LENGTHS, NC_DOUBLE, NDIM-1, dimensionID, &cellLengthVID_)) ) { mprinterr("Error: Defining cell length variable.\n"); return 1; } if ( checkNCerr( nc_put_att_text( ncid_, cellLengthVID_, "units", 8, "angstrom")) ) { mprinterr("Error: Writing cell length variable units.\n"); return 1; } dimensionID[boxdim] = cell_angularDID_; if ( checkNCerr( nc_def_var( ncid_, NCCELL_ANGLES, NC_DOUBLE, NDIM-1, dimensionID, &cellAngleVID_)) ) { mprinterr("Error: Defining cell angle variable.\n"); return 1; } if ( checkNCerr( nc_put_att_text( ncid_, cellAngleVID_, "units", 6, "degree")) ) { mprinterr("Error: Writing cell angle variable units.\n"); return 1; } } // Attributes if (checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"title",title.size(),title.c_str())) ) { mprinterr("Error: Writing title.\n"); return 1; } if (checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"application",5,"AMBER")) ) { mprinterr("Error: Writing application.\n"); return 1; } if (checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"program",7,"cpptraj")) ) { mprinterr("Error: Writing program.\n"); return 1; } if (checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"programVersion", NETCDF_VERSION_STRLEN, NETCDF_VERSION_STRING)) ) { mprinterr("Error: Writing program version.\n"); return 1; } // TODO: Make conventions a static string bool errOccurred = false; if ( type == NC_AMBERENSEMBLE ) errOccurred = checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"Conventions",13,"AMBERENSEMBLE")); else if ( type == NC_AMBERTRAJ ) errOccurred = checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"Conventions",5,"AMBER")); else errOccurred = checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"Conventions",12,"AMBERRESTART")); if (errOccurred) { mprinterr("Error: Writing conventions.\n"); return 1; } if (checkNCerr(nc_put_att_text(ncid_,NC_GLOBAL,"ConventionVersion",3,"1.0")) ) { mprinterr("Error: Writing conventions version.\n"); return 1; } // Set fill mode if (checkNCerr(nc_set_fill(ncid_, NC_NOFILL, dimensionID))) { mprinterr("Error: NetCDF setting fill value.\n"); return 1; } // End netcdf definitions if (checkNCerr(nc_enddef(ncid_))) { mprinterr("NetCDF error on ending definitions."); return 1; } // Specify spatial dimension labels start_[0] = 0; count_[0] = 3; char xyz[3]; xyz[0] = 'x'; xyz[1] = 'y'; xyz[2] = 'z'; if (checkNCerr(nc_put_vara_text(ncid_, spatialVID_, start_, count_, xyz))) { mprinterr("Error on NetCDF output of spatial VID 'x', 'y' and 'z'"); return 1; } if ( coordInfo.HasBox() ) { xyz[0] = 'a'; xyz[1] = 'b'; xyz[2] = 'c'; if (checkNCerr(nc_put_vara_text(ncid_, cell_spatialVID_, start_, count_, xyz))) { mprinterr("Error on NetCDF output of cell spatial VID 'a', 'b' and 'c'"); return 1; } char abc[15] = { 'a', 'l', 'p', 'h', 'a', 'b', 'e', 't', 'a', ' ', 'g', 'a', 'm', 'm', 'a' }; start_[0] = 0; start_[1] = 0; count_[0] = 3; count_[1] = NCLABELLEN; if (checkNCerr(nc_put_vara_text(ncid_, cell_angularVID_, start_, count_, abc))) { mprinterr("Error on NetCDF output of cell angular VID 'alpha', 'beta ' and 'gamma'"); return 1; } } // Store the type of each replica dimension. if (coordInfo.HasReplicaDims()) { ReplicaDimArray const& remdDim = coordInfo.ReplicaDimensions(); start_[0] = 0; count_[0] = remd_dimension_; int* tempDims = new int[ remd_dimension_ ]; for (int i = 0; i < remd_dimension_; ++i) tempDims[i] = remdDim[i]; if (checkNCerr(nc_put_vara_int(ncid_, remDimTypeVID, start_, count_, tempDims))) { mprinterr("Error: writing replica dimension types.\n"); delete[] tempDims; return 1; } delete[] tempDims; } return 0; }