Skip to content

Commit 19a0bb7

Browse files
drroeDaniel R. Roe
andauthored
Fix segmentation faults when reading in trajectories without forces/velocities after reading in trajectories with forces/velocities (#1188)
* Add tanh * Add hyperbolic sin/cos * Add a test that segfaults * Put into separate functions * Add test for changing velocity information * Check if the current coordinate info (specifically velocity/force info) differs from the coordinate info output trajectories were set up with. If set up for velocities/forces and no velocity/force info in the current frame, set all zeroes in the current frame. * Move to Test_VelFrc * Revert general tests * Add test with forces * Use OutputTrajCommon instead of trajio * Add ensemble test * No need for separate CoordInfo function, already stored in OutputTrajCommon * Add function to check ensembles as well * If initial traj had vel/frc info but this one does not, make sure the velocity/force info is zeroed out. * Add test trajectory files * Protect tests in parallel * Need to modify FrameArray, not FramePtrArray * Enable the ensemble test * Save index/value maps for each ensemble so we can tell if the index value mapping is the same between different trajectories. * Do a better FP comparison * When replica indices do not map to same values as in the previous ensemble force sorting by value * Fix frames in parallel ensemble * Update ensemble test files with good ones from pmemd (with correct replica indices) * Used the wrong restarts * Ensemble test * Protect in parallel * Handle case where outgoing Frame already has forces and/or velocities allocated * Record when ensemble changes * If the input ensemble changes see if the outgoing frame needs to be modified * Code to gather ensemble values in parallel * Hide debug info * Version 7.10.0. Minor version bump for fixing handling remd ensembles with changing vel/frc info. Also added 3 math funcitons. * Add bytemp to ensemble help * Add bytemp option to ensemble help * Need to use NcTest to compare NetCDF files, not DoTest... * More protections in parallel * In serial N_THREADS is not set --------- Co-authored-by: Daniel R. Roe <daniel.roe@nih.gov>
1 parent acba83c commit 19a0bb7

37 files changed

Lines changed: 688 additions & 41 deletions

doc/CpptrajManual.pdf

359 Bytes
Binary file not shown.

doc/DocumentChecksums.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
f6f8cb1a79951d80a9d2656fd9c30f55 CpptrajDevelopmentGuide.lyx
2-
30a19d148a0011fdb02ecc0d2f26e81f cpptraj.lyx
2+
8ba86aca8b37cdcb5b01ef05141e5dce cpptraj.lyx
33
5d9b5b5ed47a3ded57b6464df99b3585 CpptrajManual.lyx

doc/cpptraj.lyx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20551,6 +20551,10 @@ ensemble <file0> {[<start>] [<stop> | last] [offset]} | lastframe
2055120551
bycrdidx |
2055220552
\end_layout
2055320553

20554+
\begin_layout LyX-Code
20555+
bytemp |
20556+
\end_layout
20557+
2055420558
\begin_layout LyX-Code
2055520559
remlog <remlogfile> [nstlim <nstlim> ntwx <ntwx>]}]
2055620560
\begin_inset Separator latexpar
@@ -20628,6 +20632,10 @@ last] Frame to stop reading ensemble at;
2062820632
This is preferred over sorting via 'remlog'.
2062920633
\end_layout
2063020634

20635+
\begin_layout Description
20636+
[bytemp] If specified the ensemble will be sorted by temperature values instead of replica indices.
20637+
\end_layout
20638+
2063120639
\begin_layout Description
2063220640
[remlog
2063320641
\begin_inset space ~

src/CpptrajState.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,8 @@ int CpptrajState::RunEnsemble() {
682682
EnsembleParm[0].Nframes() );
683683
lastPindex = currentTop->Pindex();
684684
}
685+
// Check output trajectories against current coord info
686+
ensembleOut_.CheckEnsembleOutCoordInfo(currentCoordInfo, FrameEnsemble);
685687
# ifdef TIMER
686688
setup_time.Stop();
687689
# endif
@@ -895,6 +897,8 @@ int CpptrajState::RunParaEnsemble() {
895897
return 1;
896898
// Allocate FrameEnsemble here in case preload is needed.
897899
FrameEnsemble.SetupFrames( NAV.FirstParm()->Atoms(), NAV.EnsCoordInfo() );
900+
// Check output trajectories against current coord info
901+
ensembleOut_.CheckEnsembleOutCoordInfo(NAV.EnsCoordInfo(), FrameEnsemble);
898902
// Figure out if any frames need to be preloaded on ranks
899903
int preload_err = 0;
900904
if (!TrajComm.Master()) {
@@ -931,6 +935,13 @@ int CpptrajState::RunParaEnsemble() {
931935
break;
932936
}
933937
if (!NAV.CurrentEns()->BadEnsemble()) {
938+
// Has the ensemble changed?
939+
if (set != my_start && NAV.EnsembleHasChanged()) {
940+
if (debug_ > 0)
941+
rprintf("DEBUG: Ensemble has changed at set %i\n", set);
942+
// Check output trajectories against current input ensemble
943+
ensembleOut_.CheckEnsembleOutCoordInfo(NAV.CurrentEns()->EnsembleCoordInfo(), FrameEnsemble);
944+
}
934945
// Since Frame can be modified by actions, save original and use currentFrame
935946
ActionFrame currentFrame( SortedFrames[0], set );
936947
if ( currentFrame.Frm().CheckCoordsInvalid() )
@@ -1337,6 +1348,8 @@ int CpptrajState::RunNormal() {
13371348
currentSetup.Nframes() );
13381349
lastPindex = currentSetup.Top().Pindex();
13391350
}
1351+
// Check output trajectories against current coord info
1352+
trajoutList_.CheckTrajoutCoordInfo(currentSetup.CoordInfo(), TrajFrame);
13401353
# ifdef TIMER
13411354
setup_time.Stop();
13421355
# endif

src/DataSet_Coords.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Frame DataSet_Coords::AllocateFrame() const {
1010
void DataSet_Coords::CommonInfo() const {
1111
if (cInfo_.HasBox()) mprintf(" Box Coords,");
1212
if (cInfo_.HasVel()) mprintf(" Velocities,");
13+
if (cInfo_.HasForce()) mprintf(" Forces,");
1314
mprintf(" %i atoms", top_.Natom());
1415
}
1516

src/DataSet_Coords_TRJ.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,18 @@ void DataSet_Coords_TRJ::GetFrame(int idx, Frame& fIn) {
111111
Traj_ = trajinList_[ IDX_.CurrentTrajNum() ];
112112
// NOTE: Currently enforcing all traj have same # atoms, no need to check topology.
113113
// See if frame needs (re-)allocation.
114-
if (previousTraj == 0 || previousTraj->TrajCoordInfo() != Traj_->TrajCoordInfo())
114+
if (previousTraj == 0 || previousTraj->TrajCoordInfo() != Traj_->TrajCoordInfo()) {
115115
readFrame_.SetupFrameV( Traj_->Traj().Parm()->Atoms(), Traj_->TrajCoordInfo() );
116+
// If previously had vel/frc info but now do not, zero it out.
117+
if (CoordsInfo().HasVel() && !Traj_->TrajCoordInfo().HasVel())
118+
readFrame_.AddVelocities(Frame::Darray(readFrame_.size(), 0.0));
119+
if (fIn.HasVelocity() && !Traj_->TrajCoordInfo().HasVel())
120+
fIn.ZeroVelocities();
121+
if (CoordsInfo().HasForce() && !Traj_->TrajCoordInfo().HasForce())
122+
readFrame_.AddForces(Frame::Darray(readFrame_.size(), 0.0));
123+
if (fIn.HasForce() && !Traj_->TrajCoordInfo().HasForce())
124+
fIn.ZeroForces();
125+
}
116126
// Open traj.
117127
if (Traj_->BeginTraj()) {
118128
mprinterr("Error: Could not open trajectory %i '%s'\n", IDX_.CurrentTrajNum(),

src/EnsembleIn.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "EnsembleIn.h"
22
#include "CpptrajStdio.h"
3+
#include "Constants.h" // FNE
34

45
EnsembleIn::EnsembleIn() :
56
targetType_(ReplicaInfo::NONE), badEnsemble_(0), debug_(0)
@@ -35,6 +36,27 @@ int EnsembleIn::GatherIndices(int* iAddress, std::vector<RemdIdxType>& allIndice
3536
return 0;
3637
}
3738

39+
int EnsembleIn::GatherValues(Frame const& frameIn, ReplicaDimArray const& replicaDims,
40+
std::vector<Darray>& allValues,
41+
Parallel::Comm const& commIn)
42+
{
43+
int Ndims = replicaDims.Ndims();
44+
std::vector<double> all_values(allValues.size() * Ndims, 0);
45+
std::vector<double> dtemp(Ndims);
46+
for (int idim = 0; idim != replicaDims.Ndims(); idim++)
47+
dtemp[idim] = frameIn.RemdValue(idim, replicaDims);
48+
if (commIn.AllGather( &dtemp[0], Ndims, MPI_DOUBLE, &all_values[0])) {
49+
rprinterr("Error: Gathering replica values.\n");
50+
return 1;
51+
}
52+
std::vector<double>::const_iterator idx_it = all_values.begin();
53+
for (std::vector<Darray>::iterator it = allValues.begin();
54+
it != allValues.end();
55+
++it, idx_it += Ndims)
56+
it->assign(idx_it, idx_it + Ndims);
57+
return 0;
58+
}
59+
3860
#ifdef TIMER
3961
double EnsembleIn::total_mpi_allgather_ = 0.0;
4062
double EnsembleIn::total_mpi_sendrecv_ = 0.0;
@@ -93,3 +115,92 @@ int EnsembleIn::SetIndicesMap(std::vector<RemdIdxType> const& allIndices) {
93115
}
94116
return 0;
95117
}
118+
119+
int EnsembleIn::SetIdxValMap(std::vector<RemdIdxType> const& allIndices,
120+
std::vector<Darray> const& allValues)
121+
{
122+
if (allIndices.size() != allValues.size()) {
123+
rprinterr("Internal Error: EnsembleIn::SetIdxValMap(): allIndices size %zu != allValues size %zu\n",
124+
allIndices.size(), allValues.size());
125+
return 1;
126+
}
127+
128+
if (debug_ > 0) {
129+
mprintf("DEBUG: index/value map:\n");
130+
for (unsigned int member = 0; member != allIndices.size(); member++) {
131+
mprintf("\t");
132+
for (Frame::RemdIdxType::const_iterator idx = allIndices[member].begin();
133+
idx != allIndices[member].end(); ++idx)
134+
mprintf(" %6i", *idx);
135+
mprintf(" : ");
136+
for (Darray::const_iterator dval = allValues[member].begin();
137+
dval != allValues[member].end(); ++dval)
138+
mprintf(" %8.3f", *dval);
139+
mprintf("\n");
140+
}
141+
}
142+
143+
typedef std::pair<RemdIdxType, Darray> ivPair;
144+
for (unsigned int idx = 0; idx != allIndices.size(); idx++)
145+
RemdIdxValMap_.insert( ivPair(allIndices[idx], allValues[idx]) );
146+
return 0;
147+
}
148+
149+
static inline void indexprint(Frame::RemdIdxType const& IDXin) {
150+
for (Frame::RemdIdxType::const_iterator idx = IDXin.begin();
151+
idx != IDXin.end(); ++idx)
152+
mprintf(" %6i", *idx);
153+
}
154+
155+
static inline void valprint(std::vector<double> const& VALin) {
156+
for (std::vector<double>::const_iterator dval = VALin.begin();
157+
dval != VALin.end(); ++dval)
158+
mprintf(" %8.3f", *dval);
159+
}
160+
161+
/// Floating point not equals.
162+
static inline bool FNE(double v1, double v2) {
163+
double delta = v1 - v2;
164+
if (delta < 0.0) delta = -delta;
165+
return (delta > Constants::SMALL);
166+
}
167+
168+
// Compare Darrays
169+
static inline bool DNE(std::vector<double> const& lhs,
170+
std::vector<double> const& rhs)
171+
{
172+
if (lhs.size() != rhs.size()) return true;
173+
for (unsigned int idx = 0; idx < lhs.size(); idx++)
174+
if (FNE(lhs[idx], rhs[idx])) return true;
175+
return false;
176+
}
177+
178+
int EnsembleIn::CheckIdxValMap(RemdIdxValMapType const& mapIn) const {
179+
if (mapIn.size() != RemdIdxValMap_.size()) {
180+
mprintf("Warning: REMD index/value map size %zu does not match previous map size %zu\n",
181+
RemdIdxValMap_.size(), mapIn.size());
182+
return 1;
183+
}
184+
int match = 0;
185+
for (RemdIdxValMapType::const_iterator it = RemdIdxValMap_.begin();
186+
it != RemdIdxValMap_.end(); ++it)
187+
{
188+
RemdIdxValMapType::const_iterator jt = mapIn.find( it->first );
189+
if (jt == mapIn.end()) {
190+
mprintf("Warning: Index");
191+
indexprint( it->first );
192+
mprintf(" for this ensemble not found in previous ensemble.\n");
193+
match = 1;
194+
} else if (DNE(jt->second, it->second)) {
195+
mprintf("Warning: Index");
196+
indexprint( it->first );
197+
mprintf(" values ");
198+
valprint( it->second );
199+
mprintf(" do not match previous map values ");
200+
valprint( jt->second );
201+
mprintf("\n");
202+
match = 1;
203+
}
204+
}
205+
return match;
206+
}

src/EnsembleIn.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ class FrameArray;
1616
class CoordinateInfo;
1717
/// Read in an array of frames at a time.
1818
class EnsembleIn {
19+
protected:
20+
typedef Frame::RemdIdxType RemdIdxType;
21+
typedef std::vector<double> Darray;
1922
public:
23+
typedef std::map<RemdIdxType, Darray> RemdIdxValMapType;
24+
2025
EnsembleIn();
2126
virtual ~EnsembleIn() {}
2227
virtual int SetupEnsembleRead(FileName const&, ArgList&, Topology*) = 0;
@@ -36,19 +41,28 @@ class EnsembleIn {
3641
InputTrajCommon const& Traj() const { return traj_; }
3742
/// \return true if there was a problem reading the ensemble.
3843
int BadEnsemble() const { return badEnsemble_; }
44+
/// \return 1 if this index/value map does not match the given map
45+
int CheckIdxValMap(RemdIdxValMapType const&) const;
46+
/// \return index/value map
47+
RemdIdxValMapType const& RemdIdxValMap() const { return RemdIdxValMap_; }
48+
/// \return The sorting mode
49+
ReplicaInfo::TargetType TargetMode() const { return targetType_; }
50+
/// Set the debug level
3951
void SetDebug(int d) { debug_ = d; }
4052
/// Write current replica mapping to STDOUT.
4153
void PrintReplicaInfo() const;
4254
protected:
43-
typedef Frame::RemdIdxType RemdIdxType;
4455

4556
int SetTemperatureMap(std::vector<double> const&);
4657
int SetIndicesMap(std::vector<RemdIdxType> const&);
58+
int SetIdxValMap(std::vector<RemdIdxType> const&, std::vector<Darray> const&);
4759
InputTrajCommon& SetTraj() { return traj_; }
4860
/// For converting temperature to replica index
4961
ReplicaInfo::Map<double> TemperatureMap_;
5062
/// For converting indices to replica index
5163
ReplicaInfo::Map<RemdIdxType> IndicesMap_;
64+
65+
RemdIdxValMapType RemdIdxValMap_;
5266
ReplicaInfo::TargetType targetType_; ///< Hold type of REMD frame being searched for.
5367
int badEnsemble_; ///< Set to 1 if problem reading ensemble, 0 otherwise.
5468
int debug_;
@@ -60,6 +74,8 @@ class EnsembleIn {
6074
Parallel::Comm const& EnsembleComm() const { return Parallel::EnsembleComm(); }
6175
static int GatherTemperatures(double*, std::vector<double>&, Parallel::Comm const&);
6276
static int GatherIndices(int*, std::vector<RemdIdxType>&, int, Parallel::Comm const&);
77+
static int GatherValues(Frame const&, ReplicaDimArray const&,
78+
std::vector<Darray>&, Parallel::Comm const&);
6379
# ifdef TIMER
6480
Timer mpi_allgather_timer_;
6581
Timer mpi_sendrecv_timer_;
@@ -68,8 +84,8 @@ class EnsembleIn {
6884
# endif
6985
# endif
7086
private:
71-
static void PrintReplicaTmap(ReplicaInfo::Map<double> const&);
72-
static void PrintReplicaImap(ReplicaInfo::Map<RemdIdxType> const&);
87+
//static void PrintReplicaTmap(ReplicaInfo::Map<double> const&);
88+
//static void PrintReplicaImap(ReplicaInfo::Map<RemdIdxType> const&);
7389

7490
InputTrajCommon traj_;
7591
# ifdef MPI

src/EnsembleIn_Multi.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
2323
double remlog_ntwx = argIn.getKeyDouble("ntwx", 1.0);
2424
bool no_sort = argIn.hasKey("nosort");
2525
bool by_crdidx = argIn.hasKey("bycrdidx");
26+
bool by_temp = argIn.hasKey("bytemp");
2627
if (no_sort && by_crdidx) {
2728
mprinterr("Error: Should only specify either 'nosort' or 'bycrdidx', not both.\n");
2829
return 1;
@@ -35,6 +36,12 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
3536
mprinterr("Error: Should only specify either 'bycrdidx' or 'remlog', not both.\n");
3637
return 1;
3738
}
39+
if (by_temp) {
40+
if (by_crdidx || no_sort) {
41+
mprinterr("Error: 'bycrdidx'/'nosort' should not be specified with 'bytemp'\n");
42+
return 1;
43+
}
44+
}
3845
// CRDIDXARG: Parse out 'crdidx <indices list>' now so it is not processed
3946
// by SetupTrajIO.
4047
ArgList crdidxarg;
@@ -127,8 +134,14 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
127134
}
128135
} else {
129136
// If dimensions are present index by replica indices, otherwise index
130-
// by temperature.
131-
if (cInfo_.ReplicaDimensions().Ndims() > 0)
137+
// by temperature.
138+
if (by_temp) {
139+
targetType_ = ReplicaInfo::TEMP;
140+
if (cInfo_.ReplicaDimensions().Ndims() > 1) {
141+
mprinterr("Error: 'bytemp' not compatible with multiple dimensions.\n");
142+
return 1;
143+
}
144+
} else if (cInfo_.ReplicaDimensions().Ndims() > 0)
132145
targetType_ = ReplicaInfo::INDICES;
133146
else
134147
targetType_ = ReplicaInfo::TEMP;
@@ -147,10 +160,14 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
147160
frameIn.SetupFrameV( Traj().Parm()->Atoms(), cInfo_ );
148161
std::vector<double> allTemps;
149162
std::vector<RemdIdxType> allIndices;
163+
std::vector<Darray> allValues;
150164
if (targetType_ == ReplicaInfo::TEMP)
151165
allTemps.assign(REMDtraj_.size(), -1.0);
152-
else if (targetType_ == ReplicaInfo::INDICES)
166+
else if (targetType_ == ReplicaInfo::INDICES) {
153167
allIndices.resize( REMDtraj_.size() );
168+
if (cInfo_.UseRemdValues())
169+
allValues.resize( REMDtraj_.size(), Darray(cInfo_.ReplicaDimensions().Ndims(), -1.0) );
170+
}
154171
# ifdef MPI
155172
int err = 0;
156173
if (Parallel::TrajComm().Master()) {
@@ -174,6 +191,10 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
174191
if (GatherIndices(frameIn.iAddress(), allIndices, cInfo_.ReplicaDimensions().Ndims(),
175192
EnsembleComm()))
176193
err = 4;
194+
if (cInfo_.UseRemdValues()) {
195+
if (GatherValues(frameIn, cInfo_.ReplicaDimensions(), allValues, EnsembleComm()))
196+
err = 5;
197+
}
177198
}
178199
}
179200
}
@@ -196,6 +217,18 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
196217
Parallel::TrajComm().MasterBcast( &((*it)[0]), it->size(), MPI_INT );
197218
}
198219
}
220+
if (cInfo_.UseRemdValues()) {
221+
for (std::vector<Darray>::iterator it = allValues.begin();
222+
it != allValues.end(); ++it)
223+
{
224+
if (Parallel::TrajComm().Master())
225+
Parallel::TrajComm().MasterBcast( &((*it)[0]), it->size(), MPI_DOUBLE );
226+
else {
227+
it->resize( cInfo_.ReplicaDimensions().Ndims() );
228+
Parallel::TrajComm().MasterBcast( &((*it)[0]), it->size(), MPI_DOUBLE );
229+
}
230+
}
231+
}
199232
}
200233
}
201234
# else /* MPI */
@@ -205,14 +238,24 @@ int EnsembleIn_Multi::SetupEnsembleRead(FileName const& tnameIn, ArgList& argIn,
205238
REMDtraj_[member]->closeTraj();
206239
if (targetType_ == ReplicaInfo::TEMP)
207240
allTemps[member] = frameIn.Temperature();
208-
else if (targetType_ == ReplicaInfo::INDICES)
241+
else if (targetType_ == ReplicaInfo::INDICES) {
209242
allIndices[member] = frameIn.RemdIndices();
243+
if (cInfo_.UseRemdValues()) {
244+
for (int idim = 0; idim != cInfo_.ReplicaDimensions().Ndims(); idim++) {
245+
double dval = frameIn.RemdValue(idim, cInfo_.ReplicaDimensions());
246+
allValues[member][idim] = dval;
247+
}
248+
} // END if UseRemdValues
249+
}
210250
}
211251
# endif /* MPI */
212252
if (targetType_ == ReplicaInfo::TEMP) {
213253
if (SetTemperatureMap(allTemps)) return 1;
214254
} else if (targetType_ == ReplicaInfo::INDICES) {
215255
if (SetIndicesMap(allIndices)) return 1;
256+
if (cInfo_.UseRemdValues()) {
257+
if (SetIdxValMap(allIndices, allValues)) return 1;
258+
}
216259
}
217260
} // Otherwise NONE, no sorting
218261

0 commit comments

Comments
 (0)