diff --git a/src/Action_Rmsd.cpp b/src/Action_Rmsd.cpp index 78ddc2eafb..2341065412 100644 --- a/src/Action_Rmsd.cpp +++ b/src/Action_Rmsd.cpp @@ -320,6 +320,14 @@ Action::RetType Action_Rmsd::Setup(ActionSetup& setup) { mprintf("Warning: No atoms in mask '%s'.\n", tgtMask_.MaskString()); return Action::SKIP; } + if ( tgtMask_.Nselected() < 3 ) { + mprintf("Warning: Less than 3 atoms selected for RMSD. Cannot fully" + "Warning: populate the coordinate covariance matrix.\n"); + if (debug_ == 0) { + mprintf("Warning: Skipping.\n"); + return Action::SKIP; + } + } // Allocate space for selected atoms in the frame. This will also put the // correct masses in based on the mask. tgtFrame_.SetupFrameFromMask(tgtMask_, setup.Top().Atoms()); diff --git a/src/Cpptraj.cpp b/src/Cpptraj.cpp index 387118094b..7798aab60a 100644 --- a/src/Cpptraj.cpp +++ b/src/Cpptraj.cpp @@ -17,6 +17,9 @@ #ifdef CUDA # include #endif +#ifdef _OPENMP +# include +#endif /// CONSTRUCTOR - initializes all commands Cpptraj::Cpptraj() { @@ -37,17 +40,20 @@ Cpptraj::~Cpptraj() { Command::Free(); } void Cpptraj::Usage() { mprinterr("\n" "Usage: cpptraj [-p ] [-i ] [-y ] [-x ]\n" + " [-ya ] [-xa ] []\n" " [-c ] [-d ] [-w ] [-o ]\n" " [-h | --help] [-V | --version] [--defines] [-debug <#>]\n" " [--interactive] [--log ] [-tl]\n" " [-ms ] [-mr ] [--mask ] [--resmask ]\n" - " cpptraj \n" - "\t-p : Load as a topology file. May be specified more than once.\n" - "\t-i : Read input from . May be specified more than once.\n" - "\t-y : Read from trajectory file ; same as input 'trajin '.\n" - "\t-x : Write trajectory file ; same as input 'trajout '.\n" - "\t-c : Read as reference coordinates; same as input 'reference '.\n" - "\t-d : Read data in from file ('readdata ').\n" + "\t-p : * Load as a topology file.\n" + "\t-i : * Read input from file .\n" + "\t-y : * Read from trajectory file ; same as input 'trajin '.\n" + "\t-x : * Write trajectory file ; same as input 'trajout '.\n" + "\t-ya : * Input trajectory file arguments.\n" + "\t-xa : * Output trajectory file arguments.\n" + "\t : * A topology, input trajectory, or file containing cpptraj input.\n" + "\t-c : * Read as reference coordinates; same as input 'reference '.\n" + "\t-d : * Read data in from file ('readdata ').\n" "\t-w : Write data from as file ('writedata ).\n" "\t-o : Write CPPTRAJ STDOUT output to file .\n" "\t-h | --help : Print command line help and exit.\n" @@ -56,11 +62,13 @@ void Cpptraj::Usage() { "\t-debug <#> : Set global debug level to <#>; same as input 'debug <#>'.\n" "\t--interactive : Force interactive mode.\n" "\t--log : Record commands to (interactive mode only). Default is 'cpptraj.log'.\n" - "\t-tl : Print length of trajectories specified with '-y' to STDOUT.\n" + "\t-tl : Print length of all input trajectories specified on the command line to STDOUT.\n" "\t-ms : Print selected atom numbers to STDOUT.\n" "\t-mr : Print selected residue numbers to STDOUT.\n" "\t--mask : Print detailed atom selection to STDOUT.\n" - "\t--resmask : Print detailed residue selection to STDOUT.\n\n"); + "\t--resmask : Print detailed residue selection to STDOUT.\n" + " * Denotes flag may be specified multiple times.\n" + "\n"); } void Cpptraj::Intro() { @@ -77,7 +85,10 @@ void Cpptraj::Intro() { "\n ___ ___ ___ ___\n | \\/ | \\/ | \\/ | \n _|_/\\_|_/\\_|_/\\_|_\n\n", CPPTRAJ_VERSION_STRING); # ifdef MPI - mprintf("| Running on %i threads\n", Parallel::World().Size()); + mprintf("| Running on %i processes.\n", Parallel::World().Size()); +# endif +# ifdef _OPENMP + mprintf("| %i OpenMP threads available.\n", omp_get_max_threads()); # endif mprintf("| Date/time: %s\n", TimeString().c_str()); std::string available_mem = AvailableMemoryStr(); @@ -251,29 +262,93 @@ int Cpptraj::ProcessMask( Sarray const& topFiles, Sarray const& refFiles, return 0; } -void Cpptraj::AddFiles(Sarray& Files, int argc, char** argv, int& idx) { - Files.push_back( argv[++idx] ); - // Assume all following args without leading '-' are also files. - while (idx+1 != argc && argv[idx+1][0] != '-') - Files.push_back( argv[++idx] ); +/** Add current argument and all following arguments without leading '-' to + * given string array. + */ +void Cpptraj::AddArgs(Sarray& Args, ArgList const& cmdLineArgs, int& idx) +{ + Args.push_back( cmdLineArgs[++idx] ); + while (idx+1 != cmdLineArgs.Nargs() && cmdLineArgs[idx+1][0] != '-') + Args.push_back( cmdLineArgs[++idx] ); +} + +/** \return True if argument at position matches key and is not the final argument. + */ +static inline bool NotFinalArg(ArgList const& cmdLineArgs, const char* key, int pos) +{ + return (cmdLineArgs[pos] == key && pos+1 != cmdLineArgs.Nargs()); +} + +/** \return 0 if unknown, 1 if topology, 2 if trajectory, 3 if input. */ +static inline int AutoDetect(std::string const& arg) +{ + if (File::Exists(arg)) { + // Check if this is a topology file. + ParmFile::ParmFormatType ptype = ParmFile::DetectFormat( arg ); + if (ptype != ParmFile::UNKNOWN_PARM) + return 1; + // Check if this is a trajectory file. + TrajectoryFile::TrajFormatType ttype = TrajectoryFile::DetectFormat( arg ); + if (ttype != TrajectoryFile::UNKNOWN_TRAJ) + return 2; + // Assume input file. + return 3; + } + return 0; +} + +/** Check that number of args are the same as files. If fewer args, + * replicate the last arg until sizes are equal. If more args, remove the + * extra args. If no files, print a warning. + */ +void Cpptraj::ResizeArgs(Sarray const& Files, Sarray& Args, const char* type) +{ + if (Files.empty()) + mprintf("Warning: No %s trajectories but %s trajectory arguments were specified.\n", + type, type); + else { + if (Args.size() < Files.size()) { + mprintf("Warning: Fewer %s trajectory arguments than %s trajectories.\n" + "Warning: Using final specified argument for remaining trajectories: '%s'\n", + type, type, Args.back().c_str()); + Args.resize( Files.size(), Args.back() ); + } else if (Args.size() > Files.size()) { + mprintf("Warning: More %s trajectory arguments specified than %s trajectories.\n", + type, type); + Args.resize( Files.size() ); + } + } + mprintf("\tArguments for %zu %s trajectories:\n", Files.size(), type); + Sarray::const_iterator tf = Files.begin(); + for (Sarray::const_iterator ta = Args.begin(); ta != Args.end(); ++ta, ++tf) + mprintf("\t %s %s\n", tf->c_str(), ta->c_str()); } /** Read command line args. */ Cpptraj::Mode Cpptraj::ProcessCmdLineArgs(int argc, char** argv) { + // First convert argv to one continuous string. commandLine_.clear(); for (int i = 1; i < argc; i++) commandLine_.append( " " + std::string(argv[i]) ); + // Use ArgList to split into arguments. + ArgList cmdLineArgs( commandLine_ ); + // mprintf("DEBUG: CmdLine: %s\n", cmdLineArgs.ArgLine() ); + // Process command line flags from ArgList bool hasInput = false; bool interactive = false; Sarray inputFiles; Sarray topFiles; Sarray trajinFiles; + Sarray trajinArgs; Sarray trajoutFiles; + Sarray trajoutArgs; Sarray refFiles; Sarray dataFiles; std::string dataOut; - for (int i = 1; i < argc; i++) { - std::string arg(argv[i]); + for (int iarg = 0; iarg < cmdLineArgs.Nargs(); iarg++) + { + std::string const& arg = cmdLineArgs[iarg]; + // ----- One-and-done flags ------------------ if ( arg == "--help" || arg == "-h" ) { // --help, -help: Print usage and exit SetWorldSilent(true); @@ -309,76 +384,96 @@ Cpptraj::Mode Cpptraj::ProcessCmdLineArgs(int argc, char** argv) { if (State_.TrajLength( topFiles[0], trajinFiles )) return ERROR; return QUIT; } - if ( arg == "--interactive" ) + // ----- Single flags ------------------------ + if ( arg == "--interactive" ) { interactive = true; - else if ( arg == "--suppress-all-output") { + } else if ( arg == "--suppress-all-output") { mprintf("Info: All further output will be suppressed.\n"); SuppressAllOutput(); - } else if ( arg == "-debug" && i+1 != argc) { + // ----- Flags that precede values ----------- + } else if ( NotFinalArg(cmdLineArgs, "-debug", iarg) ) { // -debug: Set overall debug level - ArgList dbgarg( argv[++i] ); + ArgList dbgarg( cmdLineArgs[++iarg] ); State_.SetListDebug( dbgarg ); - } else if ( arg == "--log" && i+1 != argc) + } else if ( NotFinalArg(cmdLineArgs, "--log", iarg) ) { // --log: Set up log file for interactive mode - logfilename_ = argv[++i]; - else if ( arg == "-p" && i+1 != argc) { + logfilename_ = cmdLineArgs[++iarg]; + } else if ( NotFinalArg(cmdLineArgs, "-p", iarg) ) { // -p: Topology file - AddFiles( topFiles, argc, argv, i ); - } else if ( arg == "-d" && i+1 != argc) { + AddArgs( topFiles, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-d", iarg) ) { // -d: Read data file - AddFiles( dataFiles, argc, argv, i ); - } else if ( arg == "-w" && i+1 != argc) { + AddArgs( dataFiles, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-w", iarg) ) { // -w: Write data file. Only one allowed. For data file conversion. - dataOut.assign( argv[++i] ); - } else if ( arg == "-y" && i+1 != argc) { + dataOut.assign( cmdLineArgs[++iarg] ); + } else if ( NotFinalArg(cmdLineArgs, "-y", iarg) ) { // -y: Trajectory file in. - AddFiles( trajinFiles, argc, argv, i ); - } else if ( arg == "-x" && i+1 != argc) { + AddArgs( trajinFiles, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-ya", iarg) ) { + // -ya: Trajectory file in arguments. + AddArgs( trajinArgs, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-x", iarg) ) { // -x: Trajectory file out - trajoutFiles.push_back( argv[++i] ); - } else if ( arg == "-c" && i+1 != argc) { + trajoutFiles.push_back( cmdLineArgs[++iarg] ); + } else if ( NotFinalArg(cmdLineArgs, "-xa", iarg) ) { + // -xa: Trajectory file out arguments. + AddArgs( trajoutArgs, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-c", iarg) ) { // -c: Reference file - AddFiles( refFiles, argc, argv, i ); - } else if (arg == "-i" && i+1 != argc) { + AddArgs( refFiles, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-i", iarg) ) { // -i: Input file(s) - AddFiles( inputFiles, argc, argv, i ); - } else if (arg == "-o" && i+1 != argc) { + AddArgs( inputFiles, cmdLineArgs, iarg ); + } else if ( NotFinalArg(cmdLineArgs, "-o", iarg) ) { // -o: Output file - FileName ofilename(argv[++i]); + FileName ofilename(cmdLineArgs[++iarg]); if (ofilename.empty()) { mprinterr("Error: Could not set up output file with name '%s'\n", ofilename.full()); return ERROR; } if (OutputToFile(ofilename.full())) return ERROR; - } else if (arg == "-ms" && i+1 != argc) { + } else if ( NotFinalArg(cmdLineArgs, "-ms", iarg) ) { // -ms: Parse mask string, print selected atom #s - if (ProcessMask( topFiles, refFiles, std::string(argv[++i]), false, false )) return ERROR; + if (ProcessMask( topFiles, refFiles, cmdLineArgs[++iarg], false, false )) return ERROR; return QUIT; - } else if (arg == "-mr" && i+1 != argc) { + } else if ( NotFinalArg(cmdLineArgs, "-mr", iarg) ) { // -mr: Parse mask string, print selected res #s - if (ProcessMask( topFiles, refFiles, std::string(argv[++i]), false, true )) return ERROR; + if (ProcessMask( topFiles, refFiles, cmdLineArgs[++iarg], false, true )) return ERROR; return QUIT; - } else if (arg == "--mask" && i+1 != argc) { + } else if ( NotFinalArg(cmdLineArgs, "--mask", iarg) ) { // --mask: Parse mask string, print selected atom details - if (ProcessMask( topFiles, refFiles, std::string(argv[++i]), true, false )) return ERROR; + if (ProcessMask( topFiles, refFiles, cmdLineArgs[++iarg], true, false )) return ERROR; return QUIT; - } else if (arg == "--resmask" && i+1 != argc) { + } else if ( NotFinalArg(cmdLineArgs, "--resmask", iarg) ) { // --resmask: Parse mask string, print selected residue details - if (ProcessMask( topFiles, refFiles, std::string(argv[++i]), true, true )) return ERROR; + if (ProcessMask( topFiles, refFiles, cmdLineArgs[++iarg], true, true )) return ERROR; return QUIT; - } else if ( i == 1 ) { - // For backwards compatibility with PTRAJ; Position 1 = TOP file - topFiles.push_back( argv[i] ); - } else if ( i == 2 ) { - // For backwards compatibility with PTRAJ; Position 2 = INPUT file - inputFiles.push_back( argv[i] ); } else { - // Unrecognized - mprintf(" Unrecognized input on command line: %i: %s\n", i,argv[i]); - Usage(); - return ERROR; + // Check if this is a file. +# ifdef MPI + int ftype; + if (Parallel::World().Master()) + ftype = AutoDetect( arg ); + Parallel::World().MasterBcast(&ftype, 1, MPI_INT); +# else + int ftype = AutoDetect( arg ); +# endif + if (ftype == 1) + topFiles.push_back( arg ); + else if (ftype == 2) + trajinFiles.push_back( arg ); + else if (ftype == 3) { + if (iarg != 1) mprintf("Warning: Assuming '%s' contains cpptraj input.\n", arg.c_str()); + inputFiles.push_back( arg ); + } else { + mprinterr("Error: Unrecognized input on command line: %i: %s\n", + iarg+1, cmdLineArgs[iarg].c_str()); + Usage(); + return ERROR; + } } - } + } // END loop over command line flags Cpptraj::Intro(); // Add all data files specified on command lin. for (Sarray::const_iterator dataFilename = dataFiles.begin(); @@ -419,17 +514,31 @@ Cpptraj::Mode Cpptraj::ProcessCmdLineArgs(int argc, char** argv) { ++refName) if (State_.AddReference( *refName )) return ERROR; // Add all input trajectories specified on command line. - for (Sarray::const_iterator trajinName = trajinFiles.begin(); - trajinName != trajinFiles.end(); - ++trajinName) - if (State_.AddInputTrajectory( *trajinName )) return ERROR; + // If there are fewer input trajectory arguments than input trajectories, + // duplicate the last input trajectory argument. + if (!trajinArgs.empty()) { + ResizeArgs( trajinFiles, trajinArgs, "input" ); + for (unsigned int it = 0; it != trajinFiles.size(); it++) + if (State_.AddInputTrajectory( trajinFiles[it] + " " + trajinArgs[it] )) return ERROR; + } else { + for (Sarray::const_iterator trajinName = trajinFiles.begin(); + trajinName != trajinFiles.end(); + ++trajinName) + if (State_.AddInputTrajectory( *trajinName )) return ERROR; + } // Add all output trajectories specified on command line. if (!trajoutFiles.empty()) { hasInput = true; // This allows direct traj conversion with no other input - for (Sarray::const_iterator trajoutName = trajoutFiles.begin(); - trajoutName != trajoutFiles.end(); - ++trajoutName) - if (State_.AddOutputTrajectory( *trajoutName )) return ERROR; + if (!trajoutArgs.empty()) { + ResizeArgs( trajoutFiles, trajoutArgs, "output" ); + for (unsigned int it = 0; it != trajoutFiles.size(); it++) + if (State_.AddOutputTrajectory( trajoutFiles[it] + " " + trajoutArgs[it] )) return ERROR; + } else { + for (Sarray::const_iterator trajoutName = trajoutFiles.begin(); + trajoutName != trajoutFiles.end(); + ++trajoutName) + if (State_.AddOutputTrajectory( *trajoutName )) return ERROR; + } } // Process all input files specified on command line. if ( !inputFiles.empty() ) { diff --git a/src/Cpptraj.h b/src/Cpptraj.h index 9528bc1f33..00e27f3542 100644 --- a/src/Cpptraj.h +++ b/src/Cpptraj.h @@ -18,8 +18,9 @@ class Cpptraj { static void Usage(); static void Intro(); static void Finalize(); + static inline void AddArgs(Sarray&, ArgList const&, int&); + static inline void ResizeArgs(Sarray const&, Sarray&, const char*); int ProcessMask(Sarray const&, Sarray const&, std::string const&, bool,bool) const; - static inline void AddFiles(Sarray&, int, char**, int&); Mode ProcessCmdLineArgs(int, char**); int Interactive(); diff --git a/src/CpptrajState.cpp b/src/CpptrajState.cpp index b760c88e22..3c16fd3333 100644 --- a/src/CpptrajState.cpp +++ b/src/CpptrajState.cpp @@ -515,7 +515,7 @@ int CpptrajState::RunEnsemble() { // In parallel only two frames needed; one for reading, one for receiving. FramePtrArray SortedFrames( 2 ); FrameArray FrameEnsemble( 2 ); - // Each thread will process one member of the ensemble, so local ensemble + // Each process will handle one member of the ensemble, so local ensemble // size is effectively 1. ensembleSize = 1; # else @@ -533,7 +533,7 @@ int CpptrajState::RunEnsemble() { ActionEnsemble[0] = &actionList_; for (int member = 1; member < ensembleSize; member++) ActionEnsemble[member] = new ActionList(); - // If we are on a single thread, give each member its own copy of the + // If we are on a single process, give each member its own copy of the // current topology address. This way if topology is modified by a member, // e.g. in strip or closest, subsequent members wont be trying to modify // an already-modified topology. @@ -739,19 +739,19 @@ int CpptrajState::RunEnsemble() { } #ifdef MPI // ----------------------------------------------------------------------------- -void CpptrajState::DivideFramesAmongThreads(int& my_start, int& my_stop, int& my_frames, +void CpptrajState::DivideFramesAmongProcesses(int& my_start, int& my_stop, int& my_frames, int maxFrames, Parallel::Comm const& commIn) const { - my_frames = commIn.DivideAmongThreads(my_start, my_stop, maxFrames); - std::vector frames_per_thread( commIn.Size() ); - commIn.GatherMaster(&my_frames, 1, MPI_INT, &frames_per_thread[0]); + my_frames = commIn.DivideAmongProcesses(my_start, my_stop, maxFrames); + std::vector frames_per_process( commIn.Size() ); + commIn.GatherMaster(&my_frames, 1, MPI_INT, &frames_per_process[0]); // Print how many frames each rank will process. if (commIn.Master()) { mprintf("\nPARALLEL INFO:\n"); if (Parallel::EnsembleComm().Size() > 1) - mprintf(" %i threads per ensemble member.\n", commIn.Size()); + mprintf(" %i processes per ensemble member.\n", commIn.Size()); for (int rank = 0; rank != commIn.Size(); rank++) - mprintf(" Thread %i will process %i frames.\n", rank, frames_per_thread[rank]); + mprintf(" Process %i will handle %i frames.\n", rank, frames_per_process[rank]); } commIn.Barrier(); if (debug_ > 0) rprintf("Start %i Stop %i Frames %i\n", my_start+1, my_stop, my_frames); @@ -773,13 +773,13 @@ int CpptrajState::PreloadCheck(int my_start, int my_frames, return 1; } else if (my_frames == n_previous_frames) { rprinterr("Error: Number of preload frames is same as number of processed frames.\n" - "Error: Try reducing the number of threads.\n"); + "Error: Try reducing the number of processes.\n"); return 1; } if (n_previous_frames > (my_frames / 2)) rprintf("Warning: Number of preload frames is greater than half the " "number of processed frames.\n" - "Warning: Try reducing the number of threads.\n"); + "Warning: Try reducing the number of processes.\n"); rprintf("Warning: Preloading %i frames. These frames will NOT have Actions performed on them.\n", n_previous_frames); return 0; @@ -805,19 +805,19 @@ int CpptrajState::RunParaEnsemble() { int err = NAV.AddEnsembles(trajinList_.ensemble_begin(), trajinList_.ensemble_end()); if (Parallel::World().CheckError( err )) return 1; - // Divide frames among threads + // Divide frames among processes int my_start, my_stop, my_frames; - DivideFramesAmongThreads(my_start, my_stop, my_frames, NAV.IDX().MaxFrames(), TrajComm); - // Ensure at least 1 frame per thread, otherwise some ranks could cause hangups. + DivideFramesAmongProcesses(my_start, my_stop, my_frames, NAV.IDX().MaxFrames(), TrajComm); + // Ensure at least 1 frame per process, otherwise some ranks could cause hangups. if (my_frames > 0) err = 0; else { - rprinterr("Error: Thread is processing less than 1 frame. Try reducing # threads.\n"); + rprinterr("Error: Process is handling less than 1 frame. Try reducing # processes.\n"); err = 1; } if (Parallel::World().CheckError( err )) return 1; - // Allocate DataSets in the master DataSetList based on # frames to be read by this thread. + // Allocate DataSets in the master DataSetList based on # frames to be read by this process. DSL_.AllocateSets( my_frames ); // Any DataSets added to the DataSetList during run will need to be synced. DSL_.SetNewSetsNeedSync( true ); @@ -917,9 +917,9 @@ int CpptrajState::RunParaEnsemble() { ensembleOut_.CloseEnsembleOut(); DSL_.SetNewSetsNeedSync( false ); sync_time_.Start(); - // Sync Actions to master thread + // Sync Actions to master process actionList_.SyncActions(); - // Sync data sets to master thread + // Sync data sets to master process if (DSL_.SynchronizeData( TrajComm )) return 1; sync_time_.Stop(); mprintf("\nACTION OUTPUT:\n"); @@ -968,19 +968,19 @@ int CpptrajState::RunParallel() { if (input_traj.AddInputTraj( *traj )) { err = 1; break; } if (TrajComm.CheckError( err )) return 1; - // Divide frames among threads. + // Divide frames among processes. int my_start, my_stop, my_frames; - DivideFramesAmongThreads(my_start, my_stop, my_frames, input_traj.Size(), TrajComm); - // Ensure at least 1 frame per thread, otherwise some ranks could cause hangups. + DivideFramesAmongProcesses(my_start, my_stop, my_frames, input_traj.Size(), TrajComm); + // Ensure at least 1 frame per process, otherwise some ranks could cause hangups. if (my_frames > 0) err = 0; else { - rprinterr("Error: Thread is processing less than 1 frame. Try reducing # threads.\n"); + rprinterr("Error: Process is handling less than 1 frame. Try reducing # processes.\n"); err = 1; } if (TrajComm.CheckError( err )) return 1; - // Allocate DataSets in DataSetList based on # frames read by this thread. + // Allocate DataSets in DataSetList based on # frames read by this process. DSL_.AllocateSets( my_frames ); // Any DataSets added to the DataSetList during run will need to be synced. DSL_.SetNewSetsNeedSync( true ); @@ -1093,9 +1093,9 @@ int CpptrajState::RunParallel() { trajoutList_.CloseTrajout(); DSL_.SetNewSetsNeedSync( false ); sync_time_.Start(); - // Sync Actions to master thread + // Sync Actions to master process actionList_.SyncActions(); - // Sync data sets to master thread + // Sync data sets to master process if (DSL_.SynchronizeData( TrajComm )) return 1; sync_time_.Stop(); post_time_.Start(); @@ -1120,10 +1120,10 @@ int CpptrajState::RunSingleTrajParallel() { // Set up single trajectory for parallel read. Trajin* trajin = *(trajinList_.trajin_begin()); trajin->ParallelBeginTraj( Parallel::World() ); - // Divide frames among threads. + // Divide frames among processes. int total_read_frames = trajin->Traj().Counter().TotalReadFrames(); int my_start, my_stop, my_frames; - std::vector rank_frames = DivideFramesAmongThreads(my_start, my_stop, my_frames, + std::vector rank_frames = DivideFramesAmongProcesses(my_start, my_stop, my_frames, total_read_frames, Parallel::World().Size(), Parallel::World().Rank(), @@ -1135,7 +1135,7 @@ int CpptrajState::RunSingleTrajParallel() { rprintf("Start and stop adjusted for offset: %i to %i\n", traj_start, traj_stop); Parallel::World().Barrier(); - // Allocate DataSets in DataSetList based on # frames read by this thread. + // Allocate DataSets in DataSetList based on # frames read by this process. DSL_.AllocateSets( my_frames ); // ----- SETUP PHASE --------------------------- @@ -1189,11 +1189,11 @@ int CpptrajState::RunSingleTrajParallel() { mprintf("TIME: Avg. throughput= %.4f frames / second.\n", (double)total_read_frames / frames_time.Total()); trajoutList_.CloseTrajout(); - // Sync data sets to master thread + // Sync data sets to master process Timer time_sync; time_sync.Start(); if (DSL_.SynchronizeData( total_read_frames, rank_frames, Parallel::World() )) return 1; - // Sync Actions to master thread + // Sync Actions to master process actionList_.SyncActions(); time_sync.Stop(); time_sync.WriteTiming(1, "Data set/actions sync"); @@ -1368,7 +1368,7 @@ int CpptrajState::RunAnalyses() { # ifdef MPI // Only master performs analyses currently. if (Parallel::TrajComm().Size() > 1) - mprintf("Warning: Analysis does not currently use multiple MPI threads.\n"); + mprintf("Warning: Analysis does not currently use multiple MPI processes.\n"); if (Parallel::TrajComm().Master()) # endif err = analysisList_.DoAnalyses(); diff --git a/src/CpptrajState.h b/src/CpptrajState.h index a738286afe..7d274d2540 100644 --- a/src/CpptrajState.h +++ b/src/CpptrajState.h @@ -83,7 +83,7 @@ class CpptrajState { int RunNormal(); int RunEnsemble(); # ifdef MPI - void DivideFramesAmongThreads(int&, int&, int&, int, Parallel::Comm const&) const; + void DivideFramesAmongProcesses(int&, int&, int&, int, Parallel::Comm const&) const; int PreloadCheck(int, int, int&, int&) const; int RunParallel(); int RunParaEnsemble(); diff --git a/src/Exec_CrdAction.cpp b/src/Exec_CrdAction.cpp index 442733df2c..916ee8e3f5 100644 --- a/src/Exec_CrdAction.cpp +++ b/src/Exec_CrdAction.cpp @@ -110,7 +110,7 @@ Exec::RetType Exec_CrdAction::Execute(CpptrajState& State, ArgList& argIn) { //rprintf("DEBUG: About to create new comm, ID= %i\n", ID); trajComm_ = Parallel::World().Split( ID ); if (ID != MPI_UNDEFINED) { - mprintf("Warning: '%s' command does not yet use multiple MPI threads.\n", argIn.Command()); + mprintf("Warning: '%s' command does not yet use multiple MPI processes.\n", argIn.Command()); ret = ProcessArgs(State, argIn); if (ret != CpptrajState::OK) err = 1; diff --git a/src/Exec_CrdOut.cpp b/src/Exec_CrdOut.cpp index ad705c654c..965ec407c5 100644 --- a/src/Exec_CrdOut.cpp +++ b/src/Exec_CrdOut.cpp @@ -18,7 +18,7 @@ Exec::RetType Exec_CrdOut::Execute(CpptrajState& State, ArgList& argIn) { //rprintf("DEBUG: About to create new comm, ID= %i\n", ID); trajComm_ = Parallel::World().Split( ID ); if (ID != MPI_UNDEFINED) { - mprintf("Warning: '%s' command does not yet use multiple MPI threads.\n", argIn.Command()); + mprintf("Warning: '%s' command does not yet use multiple MPI processes.\n", argIn.Command()); ret = WriteCrd(State, argIn); if (ret != CpptrajState::OK) err = 1; diff --git a/src/Exec_RunAnalysis.cpp b/src/Exec_RunAnalysis.cpp index dfb7f596c1..0ee40a7fc9 100644 --- a/src/Exec_RunAnalysis.cpp +++ b/src/Exec_RunAnalysis.cpp @@ -24,7 +24,7 @@ Exec::RetType Exec_RunAnalysis::Execute(CpptrajState& State, ArgList& argIn) { # ifdef MPI // Only master performs analyses currently. if (Parallel::TrajComm().Size() > 1) - mprintf("Warning: Analysis does not currently use multiple MPI threads.\n"); + mprintf("Warning: Analysis does not currently use multiple MPI processes.\n"); if (Parallel::TrajComm().Master()) # endif err = DoRunAnalysis(State, argIn); diff --git a/src/Parallel.cpp b/src/Parallel.cpp index f1df3cce90..d5e77af9e0 100644 --- a/src/Parallel.cpp +++ b/src/Parallel.cpp @@ -58,10 +58,10 @@ void Parallel::dbgprintf(const char* format, ...) { return; } -/** Open a file named Thread.worldrank for this thread */ +/** Open a file named Process.worldrank for this process */ int Parallel::debug_init() { char outfilename[32]; - sprintf(outfilename, "Thread.%03i", world_.Rank()); + sprintf(outfilename, "Process.%03i", world_.Rank()); mpidebugfile_ = fopen(outfilename, "w"); if (mpidebugfile_ == NULL) { fprintf(stderr,"[%i]\tCould not open debug file:\n", world_.Rank()); @@ -74,7 +74,7 @@ int Parallel::debug_init() { return 0; } -/** Close Thread.worldrank file. */ +/** Close Process.worldrank file. */ int Parallel::debug_end() { if (mpidebugfile_ != 0) fclose(mpidebugfile_); @@ -97,7 +97,7 @@ int Parallel::Init(int argc, char** argv) { //char processor_name[MPI_MAX_PROCESSOR_NAME]; //int namelen; //MPI_Get_processor_name(processor_name, &namelen); - //printf("DEBUG: Thread %i of %i on %s\n", world_.Rank(), world_.Size(), processor_name); + //printf("DEBUG: Process %i of %i on %s\n", world_.Rank(), world_.Size(), processor_name); return 0; } @@ -125,13 +125,13 @@ int Parallel::Abort(int errcode) { /** Trajectory and Ensemble communicators are set up orthogonal to one * another. In row-major notation, Trajectory communicators are set up * across rows, and Ensemble communicators are set up down columns. For - * example, if reading in 2 ensemble members with 3 threads per member + * example, if reading in 2 ensemble members with 3 processes per member * (world size 6), the layout would be: * 0 1 2 (member 0) * 3 4 5 (member 1) - * Threads 0 and 3 would read the first third of the trajectories, etc. + * Processes 0 and 3 would read the first third of the trajectories, etc. */ -int Parallel::SetupComms(int ngroups, bool allowFewerThreadsThanGroups) { +int Parallel::SetupComms(int ngroups, bool allowFewerProcessesThanGroups) { if (ngroups < 1) { // If ngroups < 1 assume we want to reset comm info //fprintf(stdout, "DEBUG: Resetting ensemble/traj comm info.\n"); @@ -152,32 +152,32 @@ int Parallel::SetupComms(int ngroups, bool allowFewerThreadsThanGroups) { return 1; } } else if (world_.Size() < ngroups) { - // Fewer threads than groups. Make sure that # threads is a + // Fewer processes than groups. Make sure that # processes is a // multiple of ngroups. This is required for things like AllGather to work // properly. - if (!allowFewerThreadsThanGroups) { - fprintf(stderr,"Error: Fewer threads than groups currently not allowed.\n"); + if (!allowFewerProcessesThanGroups) { + fprintf(stderr,"Error: Fewer processes than groups currently not allowed.\n"); return 1; } trajComm_.Reset(); ensembleComm_.Reset(); if ( (ngroups % world_.Size()) != 0 ) { - fprintf(stderr,"Error: # of replicas (%i) must be a multiple of # threads (%i)\n", + fprintf(stderr,"Error: # of replicas (%i) must be a multiple of # processes (%i)\n", ngroups, world_.Size()); return 1; } ensemble_size_ = ngroups; - n_ens_members_ = world_.DivideAmongThreads( ensemble_beg_, ensemble_end_, ensemble_size_ ); + n_ens_members_ = world_.DivideAmongProcesses( ensemble_beg_, ensemble_end_, ensemble_size_ ); int ID = world_.Rank(); trajComm_ = world_.Split( ID ); // NOTE: This effectively duplicates World ensembleComm_ = world_.Split( 0 ); world_.Barrier(); } else { - // Threads >= groups. Make sure that ngroups is a multiple of total # threads. + // Processes >= groups. Make sure that ngroups is a multiple of total # processes. if ( (world_.Size() % ngroups) != 0 ) { if ( world_.Master() ) - fprintf(stderr,"Error: # of threads (%i) must be a multiple of # replicas (%i)\n", + fprintf(stderr,"Error: # of processes (%i) must be a multiple of # replicas (%i)\n", world_.Size(), ngroups); return 1; } @@ -233,7 +233,7 @@ int Parallel::SetupComms(int ngroups, bool allowFewerThreadsThanGroups) { /** Can be placed inside the code so debugger can be attached. */ void Parallel::Lock() { - fprintf(stdout,"[%i] Thread is locked. Waiting for debugger.\n", world_.Rank()); + fprintf(stdout,"[%i] Process is locked. Waiting for debugger.\n", world_.Rank()); int PleaseWait = 1; while (PleaseWait == 1) PleaseWait *= 1; @@ -300,20 +300,20 @@ void Parallel::Comm::Reset() { } /** Split given number of elements as evenly as possible among ranks. - * \return Number of elements this thread is responsible for. + * \return Number of elements this process is responsible for. */ -int Parallel::Comm::DivideAmongThreads(int& my_start, int& my_stop, int maxElts) const +int Parallel::Comm::DivideAmongProcesses(int& my_start, int& my_stop, int maxElts) const { - int frames_per_thread = maxElts / size_; + int frames_per_process = maxElts / size_; int remainder = maxElts % size_; - int my_frames = frames_per_thread + (int)(rank_ < remainder); - // Figure out where this thread starts and stops + int my_frames = frames_per_process + (int)(rank_ < remainder); + // Figure out where this process starts and stops my_start = 0; for (int rnk = 0; rnk != rank_; rnk++) if (rnk < remainder) - my_start += (frames_per_thread + 1); + my_start += (frames_per_process + 1); else - my_start += (frames_per_thread); + my_start += (frames_per_process); my_stop = my_start + my_frames; return my_frames; } diff --git a/src/Parallel.h b/src/Parallel.h index a1f02147a4..39157673af 100644 --- a/src/Parallel.h +++ b/src/Parallel.h @@ -51,7 +51,7 @@ class Parallel { static int Abort(int); /// Set up ensemble and trajectory communicators for given ensemble size static int SetupComms(int, bool); - /// Set up communicators - do not allow fewer threads than groups. TODO remove + /// Set up communicators - do not allow fewer processes than groups. TODO remove static int SetupComms(int n) { return SetupComms(n, false); } /// For DEBUG: infinite loop, gives time to attach a debugger. static void Lock(); @@ -61,11 +61,11 @@ class Parallel { static bool EnsembleIsSetup() { return ensemble_size_ > -1; } /// \return total ensemble size. static int Ensemble_Size() { return ensemble_size_; } - /// \return First ensemble member this thread is responsible for. + /// \return First ensemble member this process is responsible for. static int Ensemble_Beg() { return ensemble_beg_; } - /// \return Last+1 ensemble member this thread is responsible for. + /// \return Last+1 ensemble member this process is responsible for. static int Ensemble_End() { return ensemble_end_; } - /// \return Total number of ensemble members this thread is responsible for. + /// \return Total number of ensemble members this process is responsible for. static int N_Ens_Members() { return n_ens_members_; } /// \return Rank in ensemble comm. for given member. static int MemberEnsCommRank(int i) { return memberEnsRank_[i];} @@ -82,9 +82,9 @@ class Parallel { static void printMPIerr(int, const char*, int); static int checkMPIerr(int, const char*, int); static int ensemble_size_; ///< Total number of ensemble members. - static int ensemble_beg_; ///< Starting member for this ensemble thread. - static int ensemble_end_; ///< Ending member for this ensemble thread. - static int n_ens_members_; ///< Number of ensemble members thread is responsible for. + static int ensemble_beg_; ///< Starting member for this ensemble process. + static int ensemble_end_; ///< Ending member for this ensemble process. + static int n_ens_members_; ///< Number of ensemble members process is responsible for. static int* memberEnsRank_; ///< Rank in ensemble comm for each member. # ifdef PARALLEL_DEBUG_VERBOSE static void dbgprintf(const char*, ...); @@ -118,7 +118,7 @@ class Parallel::Comm { Comm Split(int) const; void Reset(); /// my_start, my_stop, maxElts - int DivideAmongThreads(int&, int&, int) const; + int DivideAmongProcesses(int&, int&, int) const; /// RecvBuffer, SendBuffer, Count, DataType, Op int ReduceMaster(void*, void*, int, MPI_Datatype, MPI_Op) const; /// Rank, RecvBuffer, SendBuffer, Count, DataType, Op diff --git a/src/ParmFile.cpp b/src/ParmFile.cpp index dc7d8ef0a0..6e182840fb 100644 --- a/src/ParmFile.cpp +++ b/src/ParmFile.cpp @@ -59,6 +59,14 @@ ParmIO* ParmFile::DetectFormat(FileName const& fname, ParmFormatType& ptype) { return 0; } +// ParmFile::DetectFormat() +ParmFile::ParmFormatType ParmFile::DetectFormat(FileName const& fname) { + ParmFormatType ptype; + ParmIO* pio = DetectFormat(fname, ptype); + delete pio; + return ptype; +} + // ParmFile::ReadTopology() int ParmFile::ReadTopology(Topology& Top, FileName const& fnameIn, ArgList const& argListIn, int debugIn) diff --git a/src/ParmFile.h b/src/ParmFile.h index f54c343c88..ce2dafa717 100644 --- a/src/ParmFile.h +++ b/src/ParmFile.h @@ -25,8 +25,12 @@ class ParmFile { return WriteTopology(t, n, ArgList(), f, d); } FileName const& ParmFilename() { return parmName_; } + /// \return ParmFormatType of given file or UNKNOWN_PARM. + static ParmFormatType DetectFormat(FileName const&); private : - ParmIO* DetectFormat(FileName const&, ParmFormatType&); + /// \return Allocated ParmIO if given file matches known type, 0 otherwise. + static ParmIO* DetectFormat(FileName const&, ParmFormatType&); + FileName parmName_; ///< Topology input/output file name. }; #endif diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index 7e05fe8e43..b4c5d34a49 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -128,3 +128,11 @@ TrajectoryIO* TrajectoryFile::DetectFormat(FileName const& fname, TrajFormatType ttype = UNKNOWN_TRAJ; return 0; } + +// TrajectoryFile::DetectFormat() +TrajectoryFile::TrajFormatType TrajectoryFile::DetectFormat(FileName const& fname) { + TrajFormatType ttype; + TrajectoryIO* tio = DetectFormat(fname, ttype); + delete tio; + return ttype; +} diff --git a/src/TrajectoryFile.h b/src/TrajectoryFile.h index 132d9a2b60..6525ee79f1 100644 --- a/src/TrajectoryFile.h +++ b/src/TrajectoryFile.h @@ -59,5 +59,7 @@ class TrajectoryFile { static TrajectoryIO* AllocTrajIO(TrajFormatType t) { return (TrajectoryIO*)FileTypes::AllocIO(TF_AllocArray, t, true); } + /// \return TrajFormatType of given file or UNKNOWN_TRAJ + static TrajFormatType DetectFormat(FileName const&); }; #endif diff --git a/src/Version.h b/src/Version.h index d950480a41..d85aaf1897 100644 --- a/src/Version.h +++ b/src/Version.h @@ -18,5 +18,5 @@ * Whenever a number that precedes is incremented, all subsequent * numbers should be reset to 0. */ -#define CPPTRAJ_INTERNAL_VERSION "V4.3.11" +#define CPPTRAJ_INTERNAL_VERSION "V4.3.12" #endif diff --git a/test/Makefile b/test/Makefile index 7b5481b4c4..cffaabb1ff 100644 --- a/test/Makefile +++ b/test/Makefile @@ -434,6 +434,9 @@ test.infraredspec: test.cphstats: @-cd Test_Cphstats && ./RunTest.sh $(OPT) +test.cmdline: + @-cd Test_CmdLine && ./RunTest.sh $(OPT) + # Every test target should go here. COMPLETETESTS=test.general \ test.strip \ @@ -573,7 +576,8 @@ COMPLETETESTS=test.general \ test.phipsi \ test.control \ test.infraredspec \ - test.cphstats + test.cphstats \ + test.cmdline test.all: $(MAKE) test.complete summary diff --git a/test/Test_2DRMS/RunTest.sh b/test/Test_2DRMS/RunTest.sh index 9c4ee0b8be..4011f1f4f2 100755 --- a/test/Test_2DRMS/RunTest.sh +++ b/test/Test_2DRMS/RunTest.sh @@ -6,7 +6,7 @@ CleanFiles rms.in rmsd1.dat rmsd2.dat ref.nc rmsd.mass.dat dme.dat trp.dat nofit.dat TESTNAME='2D RMSD tests' -Requires netcdf +Requires netcdf maxthreads 10 TOP="../tz2.parm7" CRD="../tz2.nc" INPUT="rms.in" diff --git a/test/Test_Align/RunTest.sh b/test/Test_Align/RunTest.sh index 8b1942a894..68ce1636b4 100755 --- a/test/Test_Align/RunTest.sh +++ b/test/Test_Align/RunTest.sh @@ -6,7 +6,7 @@ CleanFiles rms.in rmsd.dat rmsd.mass.dat rmsd.reftraj.dat TESTNAME='Align tests' -Requires netcdf +Requires netcdf maxthreads 10 TOP="../tz2.truncoct.parm7" INPUT="rms.in" diff --git a/test/Test_AnalysisRunAvg/RunTest.sh b/test/Test_AnalysisRunAvg/RunTest.sh index b9607b6037..3452d8dac4 100755 --- a/test/Test_AnalysisRunAvg/RunTest.sh +++ b/test/Test_AnalysisRunAvg/RunTest.sh @@ -4,7 +4,7 @@ CleanFiles runavg.in running_avg.dat cumulative_avg.dat distances.dat TESTNAME='Analysis Running Average' -Requires netcdf +Requires netcdf maxthreads 14 INPUT="runavg.in" TOP="../tz2.parm7" cat > $INPUT < cmd.in < cmd.in < cmd.in < prec.in <_X.xmgr, X = {a,r,x,y,z} diff --git a/test/Test_DihCovar/RunTest.sh b/test/Test_DihCovar/RunTest.sh index c2fe123f38..d4d2d9264e 100755 --- a/test/Test_DihCovar/RunTest.sh +++ b/test/Test_DihCovar/RunTest.sh @@ -6,7 +6,7 @@ CleanFiles matrix.in mtest.dat.save mtest.*.dat dihcovar.dat modes.dihcovar.dat dih.project.dat dih.project.agr dihedrals.dat TESTNAME='Dihedral Covariance Matrix Test' -Requires mathlib +Requires mathlib maxthreads 10 INPUT="-i matrix.in" if [ -z "$DO_PARALLEL" ] ; then diff --git a/test/Test_Ensemble_MREMD/RunTest.sh b/test/Test_Ensemble_MREMD/RunTest.sh index e5813f9c8a..7359858965 100755 --- a/test/Test_Ensemble_MREMD/RunTest.sh +++ b/test/Test_Ensemble_MREMD/RunTest.sh @@ -81,18 +81,22 @@ EOF # Test M-REMD process, no sort, running average (tests preload in parallel) RunAvgTest() { - cat > mremd.in < mremd.in < all.RA.dat && DoTest all.RA.dat.save all.RA.dat + RunCpptraj "$UNITNAME" + if [ -z "$DO_PARALLEL" ] ; then + DoTest RA.dat.save RA.dat + else + cat RA.dat.? > all.RA.dat && DoTest all.RA.dat.save all.RA.dat + fi fi } diff --git a/test/Test_Esander/RunTest.sh b/test/Test_Esander/RunTest.sh index 4c577effa7..18efb1232c 100755 --- a/test/Test_Esander/RunTest.sh +++ b/test/Test_Esander/RunTest.sh @@ -10,7 +10,7 @@ INPUT="-i ene.in" TestPME() { UNITNAME='SANDER energy test, PME' - CheckFor pnetcdf + CheckFor pnetcdf maxthreads 10 if [ $? -eq 0 ] ; then cat > ene.in < ene.in < ene.in < fix.in < hbond.in < hbond.in < matrix.in < molsurf.in < para.in < rms.in < rms.in < rms.in < rms.in < rotate.in < temp.in < cpptraj.offset.in < systemVF.in <