# | Line 28 | Line 28 | DumpWriter::DumpWriter( SimInfo* the_entry_plug ){ | |
---|---|---|
28 | if(worldRank == 0 ){ | |
29 | #endif // is_mpi | |
30 | ||
31 | – | |
31 | dumpFile.open(entry_plug->sampleName, ios::out | ios::trunc ); | |
32 | ||
33 | if( !dumpFile ){ | |
# | Line 40 | Line 39 | DumpWriter::DumpWriter( SimInfo* the_entry_plug ){ | |
39 | simError(); | |
40 | } | |
41 | ||
43 | – | //outFile.setf( ios::scientific ); |
44 | – | |
42 | #ifdef IS_MPI | |
43 | } | |
44 | ||
# | Line 94 | Line 91 | void DumpWriter::sortByGlobalIndex(){ | |
91 | ||
92 | indexArray.clear(); | |
93 | ||
94 | < | for(int i = 0; i < mpiSim->getMyNlocal();i++) |
94 | > | for(int i = 0; i < mpiSim->getMyNlocal();i++) |
95 | indexArray.push_back(make_pair(i, atoms[i]->getGlobalIndex())); | |
96 | ||
97 | sort(indexArray.begin(), indexArray.end(), indexSortingCriterion); | |
98 | } | |
99 | + | |
100 | #endif | |
101 | ||
102 | void DumpWriter::writeDump(double currentTime){ | |
105 | – | |
106 | – | // write to eor file |
107 | – | writeFinal(currentTime); |
103 | ||
104 | < | //write to dump file |
105 | < | writeFrame(dumpFile, currentTime); |
104 | > | ofstream finalOut; |
105 | > | vector<ofstream*> fileStreams; |
106 | > | |
107 | > | #ifdef IS_MPI |
108 | > | if(worldRank == 0 ){ |
109 | > | #endif |
110 | > | finalOut.open( entry_plug->finalName, ios::out | ios::trunc ); |
111 | > | if( !finalOut ){ |
112 | > | sprintf( painCave.errMsg, |
113 | > | "Could not open \"%s\" for final dump output.\n", |
114 | > | entry_plug->finalName ); |
115 | > | painCave.isFatal = 1; |
116 | > | simError(); |
117 | > | } |
118 | > | #ifdef IS_MPI |
119 | > | } |
120 | > | #endif // is_mpi |
121 | > | |
122 | > | fileStreams.push_back(&finalOut); |
123 | > | fileStreams.push_back(&dumpFile); |
124 | > | |
125 | > | writeFrame(fileStreams, currentTime); |
126 | > | |
127 | > | #ifdef IS_MPI |
128 | > | finalOut.close(); |
129 | > | #endif |
130 | ||
131 | } | |
132 | ||
133 | void DumpWriter::writeFinal(double currentTime){ | |
134 | ||
135 | < | ofstream finalOut; |
136 | < | |
137 | < | //Open eor file |
135 | > | ofstream finalOut; |
136 | > | vector<ofstream*> fileStreams; |
137 | > | |
138 | #ifdef IS_MPI | |
139 | if(worldRank == 0 ){ | |
140 | #endif // is_mpi | |
141 | ||
142 | finalOut.open( entry_plug->finalName, ios::out | ios::trunc ); | |
143 | + | |
144 | if( !finalOut ){ | |
145 | sprintf( painCave.errMsg, | |
146 | "Could not open \"%s\" for final dump output.\n", | |
# | Line 128 | Line 148 | void DumpWriter::writeFinal(double currentTime){ | |
148 | painCave.isFatal = 1; | |
149 | simError(); | |
150 | } | |
151 | < | |
151 | > | |
152 | #ifdef IS_MPI | |
153 | } | |
134 | – | #endif |
135 | – | |
136 | – | //write to eor file |
137 | – | writeFrame(finalOut, currentTime); |
138 | – | |
139 | – | //close eor file |
140 | – | #ifdef IS_MPI |
141 | – | if(worldRank == 0 ){ |
142 | – | finalOut.close(); |
143 | – | } |
154 | #endif // is_mpi | |
155 | + | |
156 | + | fileStreams.push_back(&finalOut); |
157 | + | writeFrame(fileStreams, currentTime); |
158 | ||
159 | + | #ifdef IS_MPI |
160 | + | finalOut.close(); |
161 | + | #endif |
162 | + | |
163 | } | |
164 | ||
165 | < | void DumpWriter::writeFrame( ofstream& outFile, double currentTime ){ |
165 | > | void DumpWriter::writeFrame( vector<ofstream*>& outFile, double currentTime ){ |
166 | ||
167 | const int BUFFERSIZE = 2000; | |
168 | const int MINIBUFFERSIZE = 100; | |
169 | ||
170 | < | char tempBuffer[BUFFERSIZE]; |
170 | > | char tempBuffer[BUFFERSIZE]; |
171 | char writeLine[BUFFERSIZE]; | |
172 | ||
173 | < | int i; |
173 | > | int i, k; |
174 | ||
175 | #ifdef IS_MPI | |
176 | ||
177 | + | /********************************************************************* |
178 | + | * Documentation? You want DOCUMENTATION? |
179 | + | * |
180 | + | * Why all the potatoes below? |
181 | + | * |
182 | + | * To make a long story short, the original version of DumpWriter |
183 | + | * worked in the most inefficient way possible. Node 0 would |
184 | + | * poke each of the node for an individual atom's formatted data |
185 | + | * as node 0 worked its way down the global index. This was particularly |
186 | + | * inefficient since the method blocked all processors at every atom |
187 | + | * (and did it twice!). |
188 | + | * |
189 | + | * An intermediate version of DumpWriter could be described from Node |
190 | + | * zero's perspective as follows: |
191 | + | * |
192 | + | * 1) Have 100 of your friends stand in a circle. |
193 | + | * 2) When you say go, have all of them start tossing potatoes at |
194 | + | * you (one at a time). |
195 | + | * 3) Catch the potatoes. |
196 | + | * |
197 | + | * It was an improvement, but MPI has buffers and caches that could |
198 | + | * best be described in this analogy as "potato nets", so there's no |
199 | + | * need to block the processors atom-by-atom. |
200 | + | * |
201 | + | * This new and improved DumpWriter works in an even more efficient |
202 | + | * way: |
203 | + | * |
204 | + | * 1) Have 100 of your friend stand in a circle. |
205 | + | * 2) When you say go, have them start tossing 5-pound bags of |
206 | + | * potatoes at you. |
207 | + | * 3) Once you've caught a friend's bag of potatoes, |
208 | + | * toss them a spud to let them know they can toss another bag. |
209 | + | * |
210 | + | * How's THAT for documentation? |
211 | + | * |
212 | + | *********************************************************************/ |
213 | + | |
214 | int *potatoes; | |
215 | int myPotato; | |
216 | ||
# | Line 178 | Line 232 | void DumpWriter::writeFrame( ofstream& outFile, double | |
232 | double pos[3], vel[3]; | |
233 | ||
234 | #ifndef IS_MPI | |
235 | + | |
236 | + | for(k = 0; k < outFile.size(); k++){ |
237 | + | *outFile[k] << nAtoms << "\n"; |
238 | ||
239 | < | outFile << nAtoms << "\n"; |
239 | > | *outFile[k] << currentTime << ";\t" |
240 | > | << entry_plug->Hmat[0][0] << "\t" |
241 | > | << entry_plug->Hmat[1][0] << "\t" |
242 | > | << entry_plug->Hmat[2][0] << ";\t" |
243 | > | |
244 | > | << entry_plug->Hmat[0][1] << "\t" |
245 | > | << entry_plug->Hmat[1][1] << "\t" |
246 | > | << entry_plug->Hmat[2][1] << ";\t" |
247 | ||
248 | < | outFile << currentTime << ";\t" |
249 | < | << entry_plug->Hmat[0][0] << "\t" |
250 | < | << entry_plug->Hmat[1][0] << "\t" |
187 | < | << entry_plug->Hmat[2][0] << ";\t" |
188 | < | |
189 | < | << entry_plug->Hmat[0][1] << "\t" |
190 | < | << entry_plug->Hmat[1][1] << "\t" |
191 | < | << entry_plug->Hmat[2][1] << ";\t" |
248 | > | << entry_plug->Hmat[0][2] << "\t" |
249 | > | << entry_plug->Hmat[1][2] << "\t" |
250 | > | << entry_plug->Hmat[2][2] << ";"; |
251 | ||
252 | < | << entry_plug->Hmat[0][2] << "\t" |
253 | < | << entry_plug->Hmat[1][2] << "\t" |
254 | < | << entry_plug->Hmat[2][2] << ";"; |
255 | < | //write out additional parameters, such as chi and eta |
197 | < | outFile << entry_plug->the_integrator->getAdditionalParameters(); |
198 | < | outFile << endl; |
199 | < | |
252 | > | //write out additional parameters, such as chi and eta |
253 | > | *outFile[k] << entry_plug->the_integrator->getAdditionalParameters() << endl; |
254 | > | } |
255 | > | |
256 | for( i=0; i<nAtoms; i++ ){ | |
257 | ||
258 | atoms[i]->getPos(pos); | |
# | Line 232 | Line 288 | void DumpWriter::writeFrame( ofstream& outFile, double | |
288 | else | |
289 | strcat( writeLine, "0.0\t0.0\t0.0\t0.0\t0.0\t0.0\t0.0\n" ); | |
290 | ||
291 | < | outFile << writeLine; |
291 | > | for(k = 0; k < outFile.size(); k++) |
292 | > | *outFile[k] << writeLine; |
293 | } | |
294 | ||
295 | #else // is_mpi | |
# | Line 261 | Line 318 | void DumpWriter::writeFrame( ofstream& outFile, double | |
318 | nProc = mpiSim->getNumberProcessors(); | |
319 | potatoes = new int[nProc]; | |
320 | ||
321 | + | //write out the comment lines |
322 | for (i = 0; i < nProc; i++) | |
323 | potatoes[i] = 0; | |
324 | ||
325 | < | outFile << mpiSim->getTotAtoms() << "\n"; |
325 | > | for(k = 0; k < outFile.size(); k++){ |
326 | > | *outFile[k] << mpiSim->getTotAtoms() << "\n"; |
327 | ||
328 | < | outFile << currentTime << ";\t" |
329 | < | << entry_plug->Hmat[0][0] << "\t" |
330 | < | << entry_plug->Hmat[1][0] << "\t" |
331 | < | << entry_plug->Hmat[2][0] << ";\t" |
328 | > | *outFile[k] << currentTime << ";\t" |
329 | > | << entry_plug->Hmat[0][0] << "\t" |
330 | > | << entry_plug->Hmat[1][0] << "\t" |
331 | > | << entry_plug->Hmat[2][0] << ";\t" |
332 | ||
333 | < | << entry_plug->Hmat[0][1] << "\t" |
334 | < | << entry_plug->Hmat[1][1] << "\t" |
335 | < | << entry_plug->Hmat[2][1] << ";\t" |
333 | > | << entry_plug->Hmat[0][1] << "\t" |
334 | > | << entry_plug->Hmat[1][1] << "\t" |
335 | > | << entry_plug->Hmat[2][1] << ";\t" |
336 | ||
337 | < | << entry_plug->Hmat[0][2] << "\t" |
338 | < | << entry_plug->Hmat[1][2] << "\t" |
339 | < | << entry_plug->Hmat[2][2] << ";"; |
337 | > | << entry_plug->Hmat[0][2] << "\t" |
338 | > | << entry_plug->Hmat[1][2] << "\t" |
339 | > | << entry_plug->Hmat[2][2] << ";"; |
340 | > | |
341 | > | *outFile[k] << entry_plug->the_integrator->getAdditionalParameters() << endl; |
342 | > | } |
343 | ||
282 | – | outFile << entry_plug->the_integrator->getAdditionalParameters(); |
283 | – | outFile << endl; |
284 | – | outFile.flush(); |
285 | – | |
344 | currentIndex = 0; | |
345 | + | |
346 | for (i = 0 ; i < mpiSim->getTotAtoms(); i++ ) { | |
347 | ||
348 | // Get the Node number which has this atom; | |
# | Line 328 | Line 387 | void DumpWriter::writeFrame( ofstream& outFile, double | |
387 | ||
388 | } else { | |
389 | ||
390 | < | haveError = 0; |
390 | > | haveError = 0; |
391 | which_atom = i; | |
392 | ||
393 | < | local_index = indexArray[currentIndex].first; |
335 | < | |
336 | < | if (which_atom == indexArray[currentIndex].second) { |
393 | > | local_index = indexArray[currentIndex].first; |
394 | ||
395 | < | atomTypeString = atoms[local_index]->getType(); |
396 | < | |
395 | > | if (which_atom == indexArray[currentIndex].second) { |
396 | > | |
397 | > | atomTypeString = atoms[local_index]->getType(); |
398 | > | |
399 | atoms[local_index]->getPos(pos); | |
400 | atoms[local_index]->getVel(vel); | |
401 | < | |
401 | > | |
402 | atomData6[0] = pos[0]; | |
403 | atomData6[1] = pos[1]; | |
404 | atomData6[2] = pos[2]; | |
# | Line 372 | Line 431 | void DumpWriter::writeFrame( ofstream& outFile, double | |
431 | ||
432 | } else { | |
433 | sprintf(painCave.errMsg, | |
434 | < | "Atom %d not found on processor %d\n", |
435 | < | i, worldRank ); |
434 | > | "Atom %d not found on processor %d, currentIndex = %d, local_index = %d\n", |
435 | > | which_atom, worldRank, currentIndex, local_index ); |
436 | haveError= 1; | |
437 | simError(); | |
438 | } | |
439 | ||
440 | < | if(haveError) DieDieDie(); |
440 | > | if(haveError) DieDieDie(); |
441 | ||
442 | < | currentIndex ++; |
442 | > | currentIndex++; |
443 | } | |
444 | // If we've survived to here, format the line: | |
445 | ||
446 | if (!isDirectional) { | |
447 | ||
448 | < | sprintf( writeLine, |
448 | > | sprintf( writeLine, |
449 | "%s\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t", | |
450 | atomTypeString, | |
451 | atomData6[0], | |
# | Line 395 | Line 454 | void DumpWriter::writeFrame( ofstream& outFile, double | |
454 | atomData6[3], | |
455 | atomData6[4], | |
456 | atomData6[5]); | |
457 | < | |
457 | > | |
458 | strcat( writeLine, "0.0\t0.0\t0.0\t0.0\t0.0\t0.0\t0.0\n" ); | |
459 | ||
460 | } else { | |
# | Line 419 | Line 478 | void DumpWriter::writeFrame( ofstream& outFile, double | |
478 | ||
479 | } | |
480 | ||
481 | < | outFile << writeLine; |
481 | > | for(k = 0; k < outFile.size(); k++) |
482 | > | *outFile[k] << writeLine; |
483 | } | |
484 | ||
485 | < | |
486 | < | outFile.flush(); |
485 | > | for(k = 0; k < outFile.size(); k++) |
486 | > | outFile[k]->flush(); |
487 | > | |
488 | sprintf( checkPointMsg, | |
489 | "Sucessfully took a dump.\n"); | |
490 | + | |
491 | MPIcheckPoint(); | |
492 | + | |
493 | delete[] potatoes; | |
494 | + | |
495 | } else { | |
496 | ||
497 | // worldRank != 0, so I'm a remote node. | |
# | Line 444 | Line 508 | void DumpWriter::writeFrame( ofstream& outFile, double | |
508 | if (AtomToProcMap[i] == worldRank) { | |
509 | ||
510 | if (myPotato + 3 >= MAXTAG) { | |
511 | < | |
511 | > | |
512 | // The potato was going to exceed the maximum value, | |
513 | // so wrap this processor potato back to 0 (and block until | |
514 | // node 0 says we can go: | |
515 | < | |
515 | > | |
516 | MPI_Recv(&myPotato, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &istatus); | |
517 | ||
518 | } | |
519 | which_atom = i; | |
520 | < | local_index = indexArray[currentIndex].first; |
520 | > | |
521 | > | local_index = indexArray[currentIndex].first; |
522 | ||
523 | < | if (which_atom == indexArray[currentIndex].second) { |
523 | > | if (which_atom == indexArray[currentIndex].second) { |
524 | ||
525 | atomTypeString = atoms[local_index]->getType(); | |
526 | < | |
526 | > | |
527 | atoms[local_index]->getPos(pos); | |
528 | atoms[local_index]->getVel(vel); | |
529 | < | |
529 | > | |
530 | atomData6[0] = pos[0]; | |
531 | atomData6[1] = pos[1]; | |
532 | atomData6[2] = pos[2]; | |
# | Line 486 | Line 551 | void DumpWriter::writeFrame( ofstream& outFile, double | |
551 | atomData13[7] = q[1]; | |
552 | atomData13[8] = q[2]; | |
553 | atomData13[9] = q[3]; | |
554 | < | |
554 | > | |
555 | atomData13[10] = dAtom->getJx(); | |
556 | atomData13[11] = dAtom->getJy(); | |
557 | atomData13[12] = dAtom->getJz(); | |
# | Line 494 | Line 559 | void DumpWriter::writeFrame( ofstream& outFile, double | |
559 | ||
560 | } else { | |
561 | sprintf(painCave.errMsg, | |
562 | < | "Atom %d not found on processor %d\n", |
563 | < | i, worldRank ); |
562 | > | "Atom %d not found on processor %d, currentIndex = %d, local_index = %d\n", |
563 | > | which_atom, worldRank, currentIndex, local_index ); |
564 | haveError= 1; | |
565 | simError(); | |
566 | } | |
567 | < | |
567 | > | |
568 | strncpy(MPIatomTypeString, atomTypeString, MINIBUFFERSIZE); | |
569 | ||
570 | // null terminate the string before sending (just in case): | |
571 | MPIatomTypeString[MINIBUFFERSIZE-1] = '\0'; | |
572 | ||
573 | MPI_Send(MPIatomTypeString, MINIBUFFERSIZE, MPI_CHAR, 0, | |
574 | < | myPotato, MPI_COMM_WORLD); |
574 | > | myPotato, MPI_COMM_WORLD); |
575 | ||
576 | myPotato++; | |
577 | ||
578 | MPI_Send(&isDirectional, 1, MPI_INT, 0, | |
579 | < | myPotato, MPI_COMM_WORLD); |
579 | > | myPotato, MPI_COMM_WORLD); |
580 | ||
581 | myPotato++; | |
582 |
– | Removed lines |
+ | Added lines |
< | Changed lines |
> | Changed lines |