ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/brains/mpiSimulation.cpp
Revision: 1619
Committed: Wed Oct 20 21:16:01 2004 UTC (19 years, 8 months ago) by chuckv
File size: 13042 byte(s)
Log Message:
Fortran/C++ interface de-obfuscation project appears to be complete!  Woo hoo!

File Contents

# Content
1 #ifdef IS_MPI
2 #include <iostream>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
6 #include <mpi.h>
7
8 #include "brains/mpiSimulation.hpp"
9 #include "utils/simError.h"
10 #include "UseTheForce/DarkSide/simParallel_interface.h"
11 #include "math/randomSPRNG.hpp"
12
13 mpiSimulation* mpiSim;
14
15 mpiSimulation::mpiSimulation(SimInfo* the_entryPlug)
16 {
17 entryPlug = the_entryPlug;
18 parallelData = new mpiSimData;
19
20 MPI_Comm_size(MPI_COMM_WORLD, &(parallelData->nProcessors) );
21 parallelData->myNode = worldRank;
22
23 MolToProcMap = new int[entryPlug->n_mol];
24 MolComponentType = new int[entryPlug->n_mol];
25 AtomToProcMap = new int[entryPlug->n_atoms];
26 GroupToProcMap = new int[entryPlug->ngroup];
27
28 mpiSim = this;
29 }
30
31
32 mpiSimulation::~mpiSimulation(){
33
34 delete[] MolToProcMap;
35 delete[] MolComponentType;
36 delete[] AtomToProcMap;
37 delete[] GroupToProcMap;
38
39 delete parallelData;
40 // perhaps we should let fortran know the party is over.
41
42 }
43
44 void mpiSimulation::divideLabor( ){
45
46 int nComponents;
47 MoleculeStamp** compStamps;
48 randomSPRNG *myRandom;
49 int* componentsNmol;
50 int* AtomsPerProc;
51 int* GroupsPerProc;
52
53 double numerator;
54 double denominator;
55 double precast;
56 double x, y, a;
57 int old_atoms, add_atoms, new_atoms;
58 int old_groups, add_groups, new_groups;
59
60 int nTarget;
61 int molIndex, atomIndex, groupIndex;
62 int done;
63 int i, j, loops, which_proc;
64 int nmol_global, nmol_local;
65 int ngroups_global, ngroups_local;
66 int natoms_global, natoms_local;
67 int ncutoff_groups, nAtomsInGroups;
68 int local_index;
69 int baseSeed = entryPlug->getSeed();
70 CutoffGroupStamp* cg;
71
72 nComponents = entryPlug->nComponents;
73 compStamps = entryPlug->compStamps;
74 componentsNmol = entryPlug->componentsNmol;
75 AtomsPerProc = new int[parallelData->nProcessors];
76 GroupsPerProc = new int[parallelData->nProcessors];
77
78 parallelData->nAtomsGlobal = entryPlug->n_atoms;
79 parallelData->nBondsGlobal = entryPlug->n_bonds;
80 parallelData->nBendsGlobal = entryPlug->n_bends;
81 parallelData->nTorsionsGlobal = entryPlug->n_torsions;
82 parallelData->nSRIGlobal = entryPlug->n_SRI;
83 parallelData->nGroupsGlobal = entryPlug->ngroup;
84 parallelData->nMolGlobal = entryPlug->n_mol;
85
86 if (parallelData->nProcessors > parallelData->nMolGlobal) {
87 sprintf( painCave.errMsg,
88 "nProcessors (%d) > nMol (%d)\n"
89 "\tThe number of processors is larger than\n"
90 "\tthe number of molecules. This will not result in a \n"
91 "\tusable division of atoms for force decomposition.\n"
92 "\tEither try a smaller number of processors, or run the\n"
93 "\tsingle-processor version of OOPSE.\n",
94 parallelData->nProcessors, parallelData->nMolGlobal );
95 painCave.isFatal = 1;
96 simError();
97 }
98
99 myRandom = new randomSPRNG( baseSeed );
100
101
102 a = 3.0 * (double)parallelData->nMolGlobal / (double)parallelData->nAtomsGlobal;
103
104 // Initialize things that we'll send out later:
105 for (i = 0; i < parallelData->nProcessors; i++ ) {
106 AtomsPerProc[i] = 0;
107 GroupsPerProc[i] = 0;
108 }
109 for (i = 0; i < parallelData->nMolGlobal; i++ ) {
110 // default to an error condition:
111 MolToProcMap[i] = -1;
112 MolComponentType[i] = -1;
113 }
114 for (i = 0; i < parallelData->nAtomsGlobal; i++ ) {
115 // default to an error condition:
116 AtomToProcMap[i] = -1;
117 }
118 for (i = 0; i < parallelData->nGroupsGlobal; i++ ) {
119 // default to an error condition:
120 GroupToProcMap[i] = -1;
121 }
122
123 if (parallelData->myNode == 0) {
124 numerator = (double) entryPlug->n_atoms;
125 denominator = (double) parallelData->nProcessors;
126 precast = numerator / denominator;
127 nTarget = (int)( precast + 0.5 );
128
129 // Build the array of molecule component types first
130 molIndex = 0;
131 for (i=0; i < nComponents; i++) {
132 for (j=0; j < componentsNmol[i]; j++) {
133 MolComponentType[molIndex] = i;
134 molIndex++;
135 }
136 }
137
138 atomIndex = 0;
139 groupIndex = 0;
140
141 for (i = 0; i < molIndex; i++ ) {
142
143 done = 0;
144 loops = 0;
145
146 while( !done ){
147 loops++;
148
149 // Pick a processor at random
150
151 which_proc = (int) (myRandom->getRandom() * parallelData->nProcessors);
152
153 // How many atoms does this processor have?
154
155 old_atoms = AtomsPerProc[which_proc];
156 add_atoms = compStamps[MolComponentType[i]]->getNAtoms();
157 new_atoms = old_atoms + add_atoms;
158
159 old_groups = GroupsPerProc[which_proc];
160 ncutoff_groups = compStamps[MolComponentType[i]]->getNCutoffGroups();
161 nAtomsInGroups = 0;
162 for (j = 0; j < ncutoff_groups; j++) {
163 cg = compStamps[MolComponentType[i]]->getCutoffGroup(j);
164 nAtomsInGroups += cg->getNMembers();
165 }
166 add_groups = add_atoms - nAtomsInGroups + ncutoff_groups;
167 new_groups = old_groups + add_groups;
168
169 // If we've been through this loop too many times, we need
170 // to just give up and assign the molecule to this processor
171 // and be done with it.
172
173 if (loops > 100) {
174 sprintf( painCave.errMsg,
175 "I've tried 100 times to assign molecule %d to a "
176 " processor, but can't find a good spot.\n"
177 "I'm assigning it at random to processor %d.\n",
178 i, which_proc);
179 painCave.isFatal = 0;
180 simError();
181
182 MolToProcMap[i] = which_proc;
183 AtomsPerProc[which_proc] += add_atoms;
184 for (j = 0 ; j < add_atoms; j++ ) {
185 AtomToProcMap[atomIndex] = which_proc;
186 atomIndex++;
187 }
188 GroupsPerProc[which_proc] += add_groups;
189 for (j=0; j < add_groups; j++) {
190 GroupToProcMap[groupIndex] = which_proc;
191 groupIndex++;
192 }
193 done = 1;
194 continue;
195 }
196
197 // If we can add this molecule to this processor without sending
198 // it above nTarget, then go ahead and do it:
199
200 if (new_atoms <= nTarget) {
201 MolToProcMap[i] = which_proc;
202 AtomsPerProc[which_proc] += add_atoms;
203 for (j = 0 ; j < add_atoms; j++ ) {
204 AtomToProcMap[atomIndex] = which_proc;
205 atomIndex++;
206 }
207 GroupsPerProc[which_proc] += add_groups;
208 for (j=0; j < add_groups; j++) {
209 GroupToProcMap[groupIndex] = which_proc;
210 groupIndex++;
211 }
212 done = 1;
213 continue;
214 }
215
216
217 // The only situation left is when new_atoms > nTarget. We
218 // want to accept this with some probability that dies off the
219 // farther we are from nTarget
220
221 // roughly: x = new_atoms - nTarget
222 // Pacc(x) = exp(- a * x)
223 // where a = penalty / (average atoms per molecule)
224
225 x = (double) (new_atoms - nTarget);
226 y = myRandom->getRandom();
227
228 if (y < exp(- a * x)) {
229 MolToProcMap[i] = which_proc;
230 AtomsPerProc[which_proc] += add_atoms;
231 for (j = 0 ; j < add_atoms; j++ ) {
232 AtomToProcMap[atomIndex] = which_proc;
233 atomIndex++;
234 }
235 GroupsPerProc[which_proc] += add_groups;
236 for (j=0; j < add_groups; j++) {
237 GroupToProcMap[groupIndex] = which_proc;
238 groupIndex++;
239 }
240 done = 1;
241 continue;
242 } else {
243 continue;
244 }
245
246 }
247 }
248
249
250 // Spray out this nonsense to all other processors:
251
252 //std::cerr << "node 0 mol2proc = \n";
253 //for (i = 0; i < parallelData->nMolGlobal; i++)
254 // std::cerr << i << "\t" << MolToProcMap[i] << "\n";
255
256 MPI_Bcast(MolToProcMap, parallelData->nMolGlobal,
257 MPI_INT, 0, MPI_COMM_WORLD);
258
259 MPI_Bcast(AtomToProcMap, parallelData->nAtomsGlobal,
260 MPI_INT, 0, MPI_COMM_WORLD);
261
262 MPI_Bcast(GroupToProcMap, parallelData->nGroupsGlobal,
263 MPI_INT, 0, MPI_COMM_WORLD);
264
265 MPI_Bcast(MolComponentType, parallelData->nMolGlobal,
266 MPI_INT, 0, MPI_COMM_WORLD);
267
268 MPI_Bcast(AtomsPerProc, parallelData->nProcessors,
269 MPI_INT, 0, MPI_COMM_WORLD);
270
271 MPI_Bcast(GroupsPerProc, parallelData->nProcessors,
272 MPI_INT, 0, MPI_COMM_WORLD);
273 } else {
274
275 // Listen to your marching orders from processor 0:
276
277 MPI_Bcast(MolToProcMap, parallelData->nMolGlobal,
278 MPI_INT, 0, MPI_COMM_WORLD);
279
280 MPI_Bcast(AtomToProcMap, parallelData->nAtomsGlobal,
281 MPI_INT, 0, MPI_COMM_WORLD);
282
283 MPI_Bcast(GroupToProcMap, parallelData->nGroupsGlobal,
284 MPI_INT, 0, MPI_COMM_WORLD);
285
286 MPI_Bcast(MolComponentType, parallelData->nMolGlobal,
287 MPI_INT, 0, MPI_COMM_WORLD);
288
289 MPI_Bcast(AtomsPerProc, parallelData->nProcessors,
290 MPI_INT, 0, MPI_COMM_WORLD);
291
292 MPI_Bcast(GroupsPerProc, parallelData->nProcessors,
293 MPI_INT, 0, MPI_COMM_WORLD);
294
295
296 }
297
298 // Let's all check for sanity:
299
300 nmol_local = 0;
301 for (i = 0 ; i < parallelData->nMolGlobal; i++ ) {
302 if (MolToProcMap[i] == parallelData->myNode) {
303 nmol_local++;
304 }
305 }
306
307 natoms_local = 0;
308 for (i = 0; i < parallelData->nAtomsGlobal; i++) {
309 if (AtomToProcMap[i] == parallelData->myNode) {
310 natoms_local++;
311 }
312 }
313
314 ngroups_local = 0;
315 for (i = 0; i < parallelData->nGroupsGlobal; i++) {
316 if (GroupToProcMap[i] == parallelData->myNode) {
317 ngroups_local++;
318 }
319 }
320
321 MPI_Allreduce(&nmol_local,&nmol_global,1,MPI_INT,MPI_SUM,
322 MPI_COMM_WORLD);
323
324 MPI_Allreduce(&natoms_local,&natoms_global,1,MPI_INT,
325 MPI_SUM, MPI_COMM_WORLD);
326
327 MPI_Allreduce(&ngroups_local,&ngroups_global,1,MPI_INT,
328 MPI_SUM, MPI_COMM_WORLD);
329
330 if( nmol_global != entryPlug->n_mol ){
331 sprintf( painCave.errMsg,
332 "The sum of all nmol_local, %d, did not equal the "
333 "total number of molecules, %d.\n",
334 nmol_global, entryPlug->n_mol );
335 painCave.isFatal = 1;
336 simError();
337 }
338
339 if( natoms_global != entryPlug->n_atoms ){
340 sprintf( painCave.errMsg,
341 "The sum of all natoms_local, %d, did not equal the "
342 "total number of atoms, %d.\n",
343 natoms_global, entryPlug->n_atoms );
344 painCave.isFatal = 1;
345 simError();
346 }
347
348 if( ngroups_global != entryPlug->ngroup ){
349 sprintf( painCave.errMsg,
350 "The sum of all ngroups_local, %d, did not equal the "
351 "total number of cutoffGroups, %d.\n",
352 ngroups_global, entryPlug->ngroup );
353 painCave.isFatal = 1;
354 simError();
355 }
356
357 sprintf( checkPointMsg,
358 "Successfully divided the molecules among the processors.\n" );
359 MPIcheckPoint();
360
361 parallelData->nMolLocal = nmol_local;
362 parallelData->nAtomsLocal = natoms_local;
363 parallelData->nGroupsLocal = ngroups_local;
364
365 globalAtomIndex.resize(parallelData->nAtomsLocal);
366 globalToLocalAtom.resize(parallelData->nAtomsGlobal);
367 local_index = 0;
368 for (i = 0; i < parallelData->nAtomsGlobal; i++) {
369 if (AtomToProcMap[i] == parallelData->myNode) {
370 globalAtomIndex[local_index] = i;
371
372 globalToLocalAtom[i] = local_index;
373 local_index++;
374
375 }
376 else
377 globalToLocalAtom[i] = -1;
378 }
379
380 globalGroupIndex.resize(parallelData->nGroupsLocal);
381 globalToLocalGroup.resize(parallelData->nGroupsGlobal);
382 local_index = 0;
383 for (i = 0; i < parallelData->nGroupsGlobal; i++) {
384 if (GroupToProcMap[i] == parallelData->myNode) {
385 globalGroupIndex[local_index] = i;
386
387 globalToLocalGroup[i] = local_index;
388 local_index++;
389
390 }
391 else
392 globalToLocalGroup[i] = -1;
393 }
394
395 globalMolIndex.resize(parallelData->nMolLocal);
396 globalToLocalMol.resize(parallelData->nMolGlobal);
397 local_index = 0;
398 for (i = 0; i < parallelData->nMolGlobal; i++) {
399 if (MolToProcMap[i] == parallelData->myNode) {
400 globalMolIndex[local_index] = i;
401 globalToLocalMol[i] = local_index;
402 local_index++;
403 }
404 else
405 globalToLocalMol[i] = -1;
406 }
407
408 }
409
410
411 void mpiSimulation::mpiRefresh( void ){
412
413 int isError, i;
414 int *localToGlobalAtomIndex = new int[parallelData->nAtomsLocal];
415 int *localToGlobalGroupIndex = new int[parallelData->nGroupsLocal];
416
417 // Fortran indexing needs to be increased by 1 in order to get the 2
418 // languages to not barf
419
420 for(i = 0; i < parallelData->nAtomsLocal; i++)
421 localToGlobalAtomIndex[i] = globalAtomIndex[i] + 1;
422
423 for(i = 0; i < parallelData->nGroupsLocal; i++)
424 localToGlobalGroupIndex[i] = globalGroupIndex[i] + 1;
425
426 isError = 0;
427
428 setFsimParallel( parallelData,
429 &(parallelData->nAtomsLocal), localToGlobalAtomIndex,
430 &(parallelData->nGroupsLocal), localToGlobalGroupIndex,
431 &isError );
432
433 if( isError ){
434
435 sprintf( painCave.errMsg,
436 "mpiRefresh errror: fortran didn't like something we gave it.\n" );
437 painCave.isFatal = 1;
438 simError();
439 }
440
441 delete[] localToGlobalGroupIndex;
442 delete[] localToGlobalAtomIndex;
443
444
445 sprintf( checkPointMsg,
446 " mpiRefresh successful.\n" );
447 MPIcheckPoint();
448 }
449
450
451 #endif // is_mpi