00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef PARTICLE_SPATIAL_LAYOUT_H
00012 #define PARTICLE_SPATIAL_LAYOUT_H
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "Particle/ParticleLayout.h"
00029 #include "Particle/ParticleBase.h"
00030 #include "Region/RegionLayout.h"
00031 #include "Message/Message.h"
00032 #include "FieldLayout/FieldLayoutUser.h"
00033 #include <stddef.h>
00034
00035 #ifdef IPPL_STDSTL
00036 #include <vector>
00037 using std::vector;
00038 #else
00039 #include <vector.h>
00040 #endif // IPPL_STDSTL
00041
00042 #ifdef IPPL_USE_STANDARD_HEADERS
00043 #include <iostream>
00044 using namespace std;
00045 #else
00046 #include <iostream.h>
00047 #endif
00048
00049
00050
00051 class UserList;
00052 template <class T> class ParticleAttrib;
00053 template <unsigned Dim, class T> class UniformCartesian;
00054 template <class T, unsigned Dim, class Mesh> class ParticleSpatialLayout;
00055 template <class T, unsigned Dim, class Mesh>
00056 ostream& operator<<(ostream&, const ParticleSpatialLayout<T,Dim,Mesh>&);
00057
00058
00059
00060
00061
00062
00063
00064 template < class T, unsigned Dim, class Mesh=UniformCartesian<Dim,T> >
00065 class ParticleSpatialLayout : public ParticleLayout<T, Dim>,
00066 public FieldLayoutUser
00067 {
00068
00069 public:
00070
00071 typedef int pair_t;
00072 typedef pair_t* pair_iterator;
00073 typedef typename ParticleLayout<T, Dim>::SingleParticlePos_t
00074 SingleParticlePos_t;
00075 typedef typename ParticleLayout<T, Dim>::Index_t Index_t;
00076
00077
00078 typedef ParticleAttrib<SingleParticlePos_t> ParticlePos_t;
00079 typedef ParticleAttrib<Index_t> ParticleIndex_t;
00080
00081 public:
00082
00083
00084 ParticleSpatialLayout(FieldLayout<Dim>&);
00085
00086
00087 ParticleSpatialLayout(FieldLayout<Dim>&, Mesh&);
00088
00089
00090 ParticleSpatialLayout(const RegionLayout<T,Dim,Mesh>&);
00091
00092
00093
00094
00095 ParticleSpatialLayout();
00096
00097
00098 ~ParticleSpatialLayout();
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 FieldLayout<Dim>& getFieldLayout() { return RLayout.getFieldLayout(); }
00114
00115
00116 RegionLayout<T,Dim,Mesh>& getLayout() { return RLayout; }
00117 const RegionLayout<T,Dim,Mesh>& getLayout() const { return RLayout; }
00118
00119
00120 int getNodeCount(unsigned i) const {
00121 PAssert(i < Ippl::getNodes());
00122 return NodeCount[i];
00123 }
00124
00125
00126 bool getEmptyNode(unsigned i) const {
00127 PAssert(i < Ippl::getNodes());
00128 return EmptyNode[i];
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 void update(ParticleBase< ParticleSpatialLayout<T,Dim,Mesh> >& p,
00140 const ParticleAttrib<char>* canSwap=0);
00141
00142
00143
00144
00145
00146
00147 void printDebug(Inform&);
00148
00149
00150
00151
00152
00153
00154 virtual void Repartition(UserList *);
00155
00156
00157 virtual void notifyUserOfDelete(UserList *);
00158
00159 protected:
00160
00161 RegionLayout<T,Dim,Mesh> RLayout;
00162
00163
00164 size_t *NodeCount;
00165
00166
00167 bool* EmptyNode;
00168
00169
00170
00171 bool* SwapNodeList[Dim];
00172 Message** SwapMsgList;
00173 unsigned NeighborNodes[Dim];
00174 vector<size_t>* PutList;
00175
00176
00177 void setup();
00178
00179
00180
00181
00182 void rebuild_neighbor_data();
00183
00184
00185
00186
00187
00189
00190
00191
00192
00193 template < class PB >
00194 void rebuild_layout(size_t haveLocal, PB& PData) {
00195 TAU_TYPE_STRING(taustr, "void (unsigned, " + CT(PData) + " )");
00196 TAU_PROFILE("ParticleSpatialLayout::rebuild_layout()",taustr,TAU_PARTICLE);
00197
00198 size_t i;
00199 unsigned d;
00200
00201 SingleParticlePos_t minpos = 0;
00202 SingleParticlePos_t maxpos = 0;
00203 int tag = Ippl::Comm->next_tag(P_SPATIAL_RANGE_TAG, P_LAYOUT_CYCLE);
00204 int btag = Ippl::Comm->next_tag(P_SPATIAL_RANGE_TAG, P_LAYOUT_CYCLE);
00205
00206
00207 if (haveLocal > 0) {
00208 minpos = PData.R[0];
00209 maxpos = PData.R[0];
00210 for (i=1; i < haveLocal; ++i) {
00211 for (d=0; d < Dim; ++d) {
00212 if (PData.R[i][d] < minpos[d])
00213 minpos[d] = PData.R[i][d];
00214 if (PData.R[i][d] > maxpos[d])
00215 maxpos[d] = PData.R[i][d];
00216 }
00217 }
00218 }
00219
00220
00221 if (Ippl::myNode() != 0) {
00222 Message *msg = new Message;
00223 msg->put(haveLocal);
00224 if (haveLocal > 0) {
00225 minpos.putMessage(*msg);
00226 maxpos.putMessage(*msg);
00227 }
00228 Ippl::Comm->send(msg, 0, tag);
00229
00230
00231
00232
00233 int node = 0;
00234 msg = Ippl::Comm->receive_block(node, btag);
00235 minpos.getMessage(*msg);
00236 maxpos.getMessage(*msg);
00237 delete msg;
00238
00239 }
00240 else {
00241 SingleParticlePos_t tmpminpos;
00242 SingleParticlePos_t tmpmaxpos;
00243 size_t tmphaveLocal;
00244 unsigned unreceived = Ippl::getNodes() - 1;
00245
00246
00247 while (unreceived > 0) {
00248 int node = COMM_ANY_NODE;
00249 Message *msg = Ippl::Comm->receive_block(node, tag);
00250 msg->get(tmphaveLocal);
00251 if (tmphaveLocal > 0) {
00252 tmpminpos.getMessage(*msg);
00253 tmpmaxpos.getMessage(*msg);
00254 for (i=0; i < Dim; ++i) {
00255 if (tmpminpos[i] < minpos[i])
00256 minpos[i] = tmpminpos[i];
00257 if (tmpmaxpos[i] > maxpos[i])
00258 maxpos[i] = tmpmaxpos[i];
00259 }
00260 }
00261 delete msg;
00262 unreceived--;
00263 }
00264
00265
00266
00267 SingleParticlePos_t extrapos = (maxpos - minpos) * ((T)0.125);
00268 maxpos += extrapos;
00269 minpos -= extrapos;
00270 for (i=0; i < Dim; ++i) {
00271 if (minpos[i] >= 0.0)
00272 minpos[i] = (int)(minpos[i]);
00273 else
00274 minpos[i] = (int)(minpos[i] - 1);
00275 maxpos[i] = (int)(maxpos[i] + 1);
00276 }
00277
00278
00279 if (Ippl::getNodes() > 1) {
00280 Message *bmsg = new Message;
00281 minpos.putMessage(*bmsg);
00282 maxpos.putMessage(*bmsg);
00283 Ippl::Comm->broadcast_others(bmsg, btag);
00284 }
00285 }
00286
00287
00288
00289 NDIndex<Dim> range;
00290 for (i=0; i < Dim; ++i)
00291 range[i] = Index((int)(minpos[i]), (int)(maxpos[i]));
00292 int vn = -1;
00293 if (RLayout.initialized())
00294 vn = RLayout.size_iv() + RLayout.size_rdv();
00295
00296
00297
00298
00299
00300 RLayout.changeDomain(range, vn);
00301 }
00302
00303
00304
00305
00306
00308
00309
00310 template < class PB >
00311 size_t swap_particles(size_t LocalNum, PB& PData) {
00312
00313 TAU_TYPE_STRING(taustr, "unsigned (unsigned, " + CT(PData) + " )");
00314 TAU_PROFILE("ParticleSpatialLayout::swap_particles()", taustr,
00315 TAU_PARTICLE);
00316
00317 Inform msg("ParticleSpatialLayout ERROR ", INFORM_ALL_NODES);
00318
00319 unsigned d, i, j;
00320 size_t ip;
00321 unsigned N = Ippl::getNodes();
00322 unsigned myN = Ippl::myNode();
00323
00324
00325 typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
00326
00327
00328 typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV, remoteEnd = RLayout.end_rdv();
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 NDRegion<T,Dim> pLoc;
00372
00373
00374 int etag = Ippl::Comm->next_tag(P_SPATIAL_RETURN_TAG,P_LAYOUT_CYCLE);
00375
00376 if (!getEmptyNode(myN)) {
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 for (d = 1; d < Dim; ++d) {
00395 T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
00396 T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
00397 T mid = first + 0.5 * (last - first);
00398 pLoc[d] = PRegion<T>(mid, mid);
00399 }
00400
00401 for (d = 0; d < Dim; ++d) {
00402
00403
00404 int tag = Ippl::Comm->next_tag(P_SPATIAL_TRANSFER_TAG,P_LAYOUT_CYCLE);
00405
00406
00407 if (NeighborNodes[d] > 0) {
00408
00409 for (i = 0; i < N; i++)
00410 if (SwapNodeList[d][i])
00411 SwapMsgList[i] = new Message;
00412
00413
00414
00415 for (ip=0; ip<LocalNum; ++ip) {
00416
00417
00418 for (j = 0; j <= d; j++)
00419 pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
00420
00421
00422 bool foundit = false;
00423
00424 while (!foundit) {
00425 for (localV = RLayout.begin_iv();
00426 localV != localEnd && !foundit; ++localV) {
00427 foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
00428 }
00429
00430
00431 if (!foundit) {
00432
00433 typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
00434 RLayout.touch_range_rdv(pLoc);
00435
00436
00437 if (touchingVN.first == touchingVN.second) {
00438
00439 ERRORMSG("Local particle " << ip << " with ID=");
00440 ERRORMSG(PData.ID[ip] << " at ");
00441 ERRORMSG(PData.R[ip] << " is outside of global domain ");
00442 ERRORMSG(RLayout.getDomain() << endl);
00443 ERRORMSG("This occurred when searching for point " << pLoc);
00444 ERRORMSG(" in RegionLayout = " << RLayout << endl);
00445 Ippl::abort();
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 }
00466 else {
00467
00468 unsigned node = (*(touchingVN.first)).second->getNode();
00469 PAssert(SwapNodeList[d][node]);
00470 PutList[node].push_back(ip);
00471
00472
00473 PData.destroy(1, ip);
00474
00475
00476 foundit = true;
00477 }
00478 }
00479 }
00480 }
00481
00482
00483 for (i = 0; i < N; i++) {
00484 if (SwapNodeList[d][i]) {
00485
00486 PData.putMessage( *(SwapMsgList[i]), PutList[i] );
00487
00488
00489 PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
00490
00491
00492
00493
00494
00495
00496 int node = i;
00497 Ippl::Comm->send(SwapMsgList[i], node, tag);
00498
00499
00500 PutList[i].erase(PutList[i].begin(), PutList[i].end());
00501 }
00502 }
00503
00504 LocalNum -= PData.getDestroyNum();
00505 ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
00506 PData.performDestroy();
00507
00508
00509 unsigned sendnum = NeighborNodes[d];
00510 while (sendnum-- > 0) {
00511 int node = Communicate::COMM_ANY_NODE;
00512 Message *recmsg = Ippl::Comm->receive_block(node, tag);
00513 size_t recvd;
00514 while ((recvd = PData.getMessage(*recmsg)) > 0)
00515 LocalNum += recvd;
00516 delete recmsg;
00517 }
00518 }
00519
00520 if (d == 0) {
00521
00522 for (i = 0; i < N; ++i) {
00523 if (getEmptyNode(i)) {
00524 int node = i;
00525 Message *recmsg = Ippl::Comm->receive_block(node, etag);
00526 size_t recvd;
00527 while ((recvd = PData.getMessage(*recmsg)) > 0)
00528 LocalNum += recvd;
00529 delete recmsg;
00530 }
00531 }
00532 }
00533
00534 }
00535
00536 }
00537 else {
00538 msg << "case getEmptyNode(myN) " << endl;
00539
00540 for (i = 0; i < N; i++)
00541 if (SwapNodeList[0][i])
00542 SwapMsgList[i] = new Message;
00543
00544
00545
00546 for (ip=0; ip<LocalNum; ++ip) {
00547
00548 for (j = 0; j < Dim; j++)
00549 pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
00550
00551
00552 typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
00553 RLayout.touch_range_rdv(pLoc);
00554
00555
00556 if (touchingVN.first == touchingVN.second) {
00557 ERRORMSG("Local particle " << ip << " with ID=");
00558 ERRORMSG(PData.ID[ip] << " at ");
00559 ERRORMSG(PData.R[ip] << " is outside of global domain ");
00560 ERRORMSG(RLayout.getDomain() << endl);
00561 ERRORMSG("This occurred when searching for point " << pLoc);
00562 ERRORMSG(" in RegionLayout = " << RLayout << endl);
00563 Ippl::abort();
00564 }
00565 else {
00566
00567 unsigned node = (*(touchingVN.first)).second->getNode();
00568 PAssert(SwapNodeList[0][node]);
00569 PutList[node].push_back(ip);
00570
00571
00572 PData.destroy(1, ip);
00573 }
00574 }
00575
00576
00577 for (i = 0; i < N; i++) {
00578 if (SwapNodeList[0][i]) {
00579
00580 PData.putMessage( *(SwapMsgList[i]), PutList[i] );
00581
00582
00583 PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
00584
00585
00586 int node = i;
00587 Ippl::Comm->send(SwapMsgList[i], node, etag);
00588
00589
00590 PutList[i].erase(PutList[i].begin(), PutList[i].end());
00591 }
00592 }
00593
00594 LocalNum -= PData.getDestroyNum();
00595 ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
00596 PData.performDestroy();
00597
00598 }
00599
00600
00601 return LocalNum;
00602 }
00603
00604
00605
00606
00608
00609
00610 template < class PB >
00611 size_t swap_particles(size_t LocalNum, PB& PData,
00612 const ParticleAttrib<char>& canSwap) {
00613
00614 TAU_TYPE_STRING(taustr, "unsigned (unsigned, " + CT(PData) + ", const ParticleAttrib<char>&)");
00615 TAU_PROFILE("ParticleSpatialLayout::swap_particles()", taustr,
00616 TAU_PARTICLE);
00617
00618 unsigned d, i, j;
00619 size_t ip;
00620 unsigned N = Ippl::getNodes();
00621 unsigned myN = Ippl::myNode();
00622
00623
00624 typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
00625
00626
00627 typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV, remoteEnd = RLayout.end_rdv();
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670 NDRegion<T,Dim> pLoc;
00671
00672
00673 int etag = Ippl::Comm->next_tag(P_SPATIAL_RETURN_TAG,P_LAYOUT_CYCLE);
00674
00675 if (!getEmptyNode(myN)) {
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 for (d = 1; d < Dim; ++d) {
00694 T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
00695 T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
00696 T mid = first + 0.5 * (last - first);
00697 pLoc[d] = PRegion<T>(mid, mid);
00698 }
00699
00700 for (d = 0; d < Dim; ++d) {
00701
00702
00703 int tag = Ippl::Comm->next_tag(P_SPATIAL_TRANSFER_TAG,P_LAYOUT_CYCLE);
00704
00705
00706 if (NeighborNodes[d] > 0) {
00707
00708 for (i = 0; i < N; i++)
00709 if (SwapNodeList[d][i])
00710 SwapMsgList[i] = new Message;
00711
00712
00713
00714 for (ip=0; ip<LocalNum; ++ip) {
00715 if (!bool(canSwap[ip])) continue;
00716
00717
00718 for (j = 0; j <= d; j++)
00719 pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
00720
00721
00722 bool foundit = false;
00723
00724 while (!foundit) {
00725 for (localV = RLayout.begin_iv();
00726 localV != localEnd && !foundit; ++localV) {
00727 foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
00728 }
00729
00730
00731 if (!foundit) {
00732
00733 typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
00734 RLayout.touch_range_rdv(pLoc);
00735
00736
00737 if (touchingVN.first == touchingVN.second) {
00738
00739 ERRORMSG("Local particle " << ip << " with ID=");
00740 ERRORMSG(PData.ID[ip] << " at ");
00741 ERRORMSG(PData.R[ip] << " is outside of global domain ");
00742 ERRORMSG(RLayout.getDomain() << endl);
00743 ERRORMSG("This occurred when searching for point " << pLoc);
00744 ERRORMSG(" in RegionLayout = " << RLayout << endl);
00745 Ippl::abort();
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765 }
00766 else {
00767
00768 unsigned node = (*(touchingVN.first)).second->getNode();
00769 PAssert(SwapNodeList[d][node]);
00770 PutList[node].push_back(ip);
00771
00772
00773 PData.destroy(1, ip);
00774
00775
00776 foundit = true;
00777 }
00778 }
00779 }
00780 }
00781
00782
00783 for (i = 0; i < N; i++) {
00784 if (SwapNodeList[d][i]) {
00785
00786 PData.putMessage( *(SwapMsgList[i]), PutList[i] );
00787
00788
00789 PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
00790
00791
00792
00793
00794
00795
00796 int node = i;
00797 Ippl::Comm->send(SwapMsgList[i], node, tag);
00798
00799
00800 PutList[i].erase(PutList[i].begin(), PutList[i].end());
00801 }
00802 }
00803
00804 LocalNum -= PData.getDestroyNum();
00805 ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
00806 PData.performDestroy();
00807
00808
00809 unsigned sendnum = NeighborNodes[d];
00810 while (sendnum-- > 0) {
00811 int node = Communicate::COMM_ANY_NODE;
00812 Message *recmsg = Ippl::Comm->receive_block(node, tag);
00813 size_t recvd;
00814 while ((recvd = PData.getMessage(*recmsg)) > 0)
00815 LocalNum += recvd;
00816 delete recmsg;
00817 }
00818 }
00819
00820 if (d == 0) {
00821
00822 for (i = 0; i < N; ++i) {
00823 if (getEmptyNode(i)) {
00824 int node = i;
00825 Message *recmsg = Ippl::Comm->receive_block(node, etag);
00826 size_t recvd;
00827 while ((recvd = PData.getMessage(*recmsg)) > 0)
00828 LocalNum += recvd;
00829 delete recmsg;
00830 }
00831 }
00832 }
00833
00834 }
00835
00836 }
00837 else {
00838
00839 for (i = 0; i < N; i++)
00840 if (SwapNodeList[0][i])
00841 SwapMsgList[i] = new Message;
00842
00843
00844
00845 for (ip=0; ip<LocalNum; ++ip) {
00846 if (!bool(canSwap[ip])) continue;
00847
00848 for (j = 0; j < Dim; j++)
00849 pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
00850
00851
00852 typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
00853 RLayout.touch_range_rdv(pLoc);
00854
00855
00856 if (touchingVN.first == touchingVN.second) {
00857 ERRORMSG("Local particle " << ip << " with ID=");
00858 ERRORMSG(PData.ID[ip] << " at ");
00859 ERRORMSG(PData.R[ip] << " is outside of global domain ");
00860 ERRORMSG(RLayout.getDomain() << endl);
00861 ERRORMSG("This occurred when searching for point " << pLoc);
00862 ERRORMSG(" in RegionLayout = " << RLayout << endl);
00863 Ippl::abort();
00864 }
00865 else {
00866
00867 unsigned node = (*(touchingVN.first)).second->getNode();
00868 PAssert(SwapNodeList[0][node]);
00869 PutList[node].push_back(ip);
00870
00871
00872 PData.destroy(1, ip);
00873 }
00874 }
00875
00876
00877 for (i = 0; i < N; i++) {
00878 if (SwapNodeList[0][i]) {
00879
00880 PData.putMessage( *(SwapMsgList[i]), PutList[i] );
00881
00882
00883 PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
00884
00885
00886 int node = i;
00887 Ippl::Comm->send(SwapMsgList[i], node, etag);
00888
00889
00890 PutList[i].erase(PutList[i].begin(), PutList[i].end());
00891 }
00892 }
00893
00894 LocalNum -= PData.getDestroyNum();
00895 ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
00896 PData.performDestroy();
00897
00898 }
00899
00900
00901 return LocalNum;
00902 }
00903 };
00904
00905 #include "Particle/ParticleSpatialLayout.cpp"
00906
00907 #endif // PARTICLE_SPATIAL_LAYOUT_H
00908
00909
00910
00911
00912
00913