src/Field/AssignGeneralBF.cpp

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  * This program was prepared by PSI. 
00007  * All rights in the program are reserved by PSI.
00008  * Neither PSI nor the author(s)
00009  * makes any warranty, express or implied, or assumes any liability or
00010  * responsibility for the use of this software
00011  *
00012  * Visit http://www.acl.lanl.gov/POOMS for more details
00013  *
00014  ***************************************************************************/
00015 
00016 // -*- C++ -*-
00017 /***************************************************************************
00018  *
00019  * The IPPL Framework
00020  * 
00021  *
00022  * Visit http://people.web.psi.ch/adelmann/ for more details
00023  *
00024  ***************************************************************************/
00025 
00027 //
00028 // This file contains the version of assign() that work with 
00029 // general BareField = BareField expressions.  It will perform
00030 // general communication to exchange data if the LHS and RHS layouts
00031 // do not match.
00032 //
00034 
00035 // include files
00036 #include "Field/Assign.h"
00037 #include "Field/AssignDefs.h"
00038 #include "Field/BareField.h"
00039 #include "Field/BrickExpression.h"
00040 #include "Field/IndexedBareField.h"
00041 #include "Field/LField.h"
00042 #include "Message/Communicate.h"
00043 #include "Message/Message.h"
00044 #include "Utility/PAssert.h"
00045 #include "Utility/IpplInfo.h"
00046 #include "Utility/IpplStats.h"
00047 #include "Profile/Profiler.h"
00048 #include "PETE/IpplExpressions.h"
00049 
00050 #ifdef IPPL_STDSTL
00051 #include <map>
00052 #include <vector>
00053 #include <functional>
00054 #include <utility>
00055 using namespace std;
00056 #else
00057 #include <map.h>
00058 #include <vector.h>
00059 #include <function.h>
00060 #include <multimap.h>
00061 #endif
00062 
00063 #ifdef IPPL_USE_STANDARD_HEADERS
00064 #include <iostream>
00065 #include <typeinfo>
00066 using namespace std;
00067 #else
00068 #include <iostream.h>
00069 #include <typeinfo.h>
00070 #endif
00071 
00072 
00074 //
00075 // Assign one BareField to another.
00076 // Unlike the above, this works even if the two BareFields are 
00077 // on different layouts.
00078 //
00080 
00081 template<class T1, unsigned Dim, class RHS, class Op>
00082 void
00083 assign(const BareField<T1,Dim>& clhs, RHS rhsp, Op op, ExprTag<false>)
00084 {
00085   // profiling macros
00086   // here, 'Op' is not used to form the type string, so the timings here
00087   // will be the sum of all different operators 'Op' used in the code.
00088   TAU_TYPE_STRING(p1, "void (" + CT(clhs) + ", " + CT(rhsp) + ", " + CT(op) 
00089     + ", ExprTag<false> )" );
00090   TAU_PROFILE("assign()", p1.data(), TAU_ASSIGN | TAU_FIELD);
00091   TAU_PROFILE_TIMER(sendtimer,   " assign[BareField]-send", p1.data(),
00092                     TAU_ASSIGN);
00093   TAU_PROFILE_TIMER(findtimer,   " assign[BareField]-findreceive", p1.data(),
00094                     TAU_ASSIGN);
00095   TAU_PROFILE_TIMER(localstimer, " assign[BareField]-locals", p1.data(),
00096                     TAU_ASSIGN);
00097   TAU_PROFILE_TIMER(rectimer,    " assign[BareField]-receive", p1.data(),
00098                     TAU_ASSIGN);
00099   TAU_PROFILE_TIMER(filltimer,   " assign[BareField]-fill", p1.data(),
00100                     TAU_ASSIGN);
00101 
00102   // debugging output macros.  these are only enabled if DEBUG_ASSIGN is
00103   // defined.
00104   ASSIGNMSG(Inform msg("NEW assign BF(f)", INFORM_ALL_NODES));
00105   ASSIGNMSG(msg << "Computing general assignment to BF[" << clhs.getDomain());
00106   ASSIGNMSG(msg << "] ..." << endl);
00107 
00108   // cast away const here for lhs ... unfortunate but necessary.
00109   // also, retrieve the BareField from the rhs iterator.  We know we can
00110   // do this since this is the ExprTag<false> specialization, only called if
00111   // the rhs is also a BareField.
00112   BareField<T1,Dim>& lhs = (BareField<T1,Dim>&) clhs ;
00113   typedef typename RHS::PETE_Return_t T2;
00114   const BareField<T2,Dim>& rhs( rhsp.GetBareField() );
00115 
00116   // Build iterators within local fields on the left and right hand side.
00117   typedef typename LField<T1,Dim>::iterator LFI;
00118   typedef typename LField<T2,Dim>::iterator RFI;
00119   T1 lhs_compressed_data;
00120   T2 rhs_compressed_data;
00121   LFI lhs_i(lhs_compressed_data);
00122   RFI rhs_i(rhs_compressed_data);
00123 
00124   // Build an iterator for the local fields on the left and right hand side.
00125   typename BareField<T1,Dim>::iterator_if lf_i, lf_e = lhs.end_if();
00126   typename BareField<T2,Dim>::const_iterator_if rf_i, rf_e = rhs.end_if();
00127 
00128   // Get message tag
00129   int tag = Ippl::Comm->next_tag( F_GEN_ASSIGN_TAG , F_TAG_CYCLE );
00130   int remaining = 0;  // counter for messages to receive
00131 
00132   // Build a map of the messages we expect to receive.
00133   typedef multimap< NDIndex<Dim> , LField<T1,Dim>* , less<NDIndex<Dim> > >
00134     ac_recv_type;
00135   ac_recv_type recv_ac;
00136 
00137   // ----------------------------------------
00138   // First the send loop.
00139   // Loop over all the local nodes of the right hand side and
00140   // send data to the remote ones they overlap on the left hand side.
00141   int nprocs = Ippl::getNodes();
00142   ASSIGNMSG(msg << "Processing send-loop for " << nprocs << " nodes." << endl);
00143   if (nprocs > 1) {
00144 
00145     // set up messages to be sent
00146     TAU_PROFILE_START(sendtimer);
00147     Message** mess = new Message*[nprocs];
00148     bool* recvmsg = new bool[nprocs]; // receive msg from this node?
00149     int iproc;
00150     for (iproc=0; iproc<nprocs; ++iproc) {
00151       mess[iproc] = 0;
00152       recvmsg[iproc] = false;
00153     }
00154     TAU_PROFILE_STOP(sendtimer);
00155 
00156     // now loop over LFields of lhs, building receive list
00157     TAU_PROFILE_START(findtimer);
00158     for (lf_i = lhs.begin_if(); lf_i != lf_e; ++lf_i) {
00159       // Cache some information about this LField.
00160       LField<T1,Dim> &lf = *((*lf_i).second);
00161       const NDIndex<Dim> &la = lf.getAllocated();
00162 
00163       // Find the remote ones that have owned cells that touch this.
00164       typename FieldLayout<Dim>::touch_range_dv
00165         range( rhs.getLayout().touch_range_rdv(la) );
00166       typename FieldLayout<Dim>::touch_iterator_dv rv_i;
00167       for (rv_i = range.first; rv_i != range.second; ++rv_i) {
00168         // Save the intersection and the LField it is for.
00169         // It is a multimap so we can't use operator[].
00170         NDIndex<Dim> sub = la.intersect((*rv_i).first);
00171         typedef typename ac_recv_type::value_type value_type;
00172         recv_ac.insert( value_type(sub,&lf) );
00173 
00174         // Note who will be sending this data
00175         int rnode = (*rv_i).second->getNode();
00176         recvmsg[rnode] = true;
00177       }
00178     }
00179     TAU_PROFILE_STOP(findtimer);
00180 
00181     // now loop over LFields of rhs, packing overlaps into proper messages
00182     TAU_PROFILE_START(sendtimer);
00183     for (rf_i = rhs.begin_if(); rf_i != rf_e; ++rf_i) {
00184       // Cache some information about this local array.
00185       LField<T2,Dim> &rf = *((*rf_i).second);
00186       const NDIndex<Dim>& ro = rf.getOwned();
00187 
00188       // Loop over the local ones that have allocated cells that this
00189       // remote one touches.
00190       typename FieldLayout<Dim>::touch_range_dv
00191         range( lhs.getLayout().touch_range_rdv(ro,lhs.getGuardCellSizes()) );
00192       typename FieldLayout<Dim>::touch_iterator_dv remote_i;
00193       for (remote_i = range.first; remote_i != range.second; ++remote_i) {
00194         // Find the intersection.
00195         NDIndex<Dim> intersection = ro.intersect( (*remote_i).first );
00196 
00197         // Find out who owns this domain
00198         int rnode = (*remote_i).second->getNode();
00199 
00200         // Construct an iterator for use in sending out the data
00201         rhs_i = rf.begin(intersection, rhs_compressed_data);
00202         rhs_i.TryCompress();
00203 
00204         // Put intersection domain and field data into message
00205         if (mess[rnode] == 0)
00206           mess[rnode] = new Message;
00207         intersection.putMessage(*mess[rnode]);
00208         rhs_i.putMessage(*mess[rnode]);
00209       }
00210     }
00211     TAU_PROFILE_STOP(sendtimer);
00212 
00213     // tally number of messages to receive
00214     TAU_PROFILE_START(findtimer);
00215     for (iproc=0; iproc<nprocs; ++iproc)
00216       if (recvmsg[iproc]) ++remaining;
00217     delete [] recvmsg;
00218     TAU_PROFILE_STOP(findtimer);
00219 
00220     // send the messages
00221     TAU_PROFILE_START(sendtimer);
00222     for (iproc=0; iproc<nprocs; ++iproc) {
00223       if (mess[iproc] != 0)
00224         Ippl::Comm->send(mess[iproc],iproc,tag);
00225     }
00226     delete [] mess;
00227     TAU_PROFILE_STOP(sendtimer);
00228   }
00229 
00230   // ----------------------------------------
00231   // Handle the local fills.
00232   // Loop over all the local Fields of the lhs and all the local
00233   // fields in the rhs.
00234   // This is an N*N operation, but the expectation is that there won't
00235   // be TOO many Vnodes on a given processor.
00236   ASSIGNMSG(msg << "Doing local fills for " << lhs.size_if());
00237   ASSIGNMSG(msg << " local lhs blocks and ");
00238   ASSIGNMSG(msg << rhs.size_if() << " local rhs blocks." << endl);
00239   TAU_PROFILE_START(localstimer);
00240   for (lf_i = lhs.begin_if(); lf_i != lf_e; ++lf_i) {
00241     // Cache some information about this LField.
00242     LField<T1,Dim> &lf = *(*lf_i).second;
00243     const NDIndex<Dim> &lo = lf.getOwned();
00244     const NDIndex<Dim> &la = lf.getAllocated();
00245 
00246     ASSIGNMSG(msg << "----------------" << endl);
00247     ASSIGNMSG(msg << "Assigning to local LField with owned = " << lo);
00248     ASSIGNMSG(msg << ", allocated = " << la << endl);
00249 
00250     // Loop over the ones it touches on the rhs.
00251     for (rf_i = rhs.begin_if(); rf_i != rf_e; ++rf_i) {
00252       // Cache some info about this LField.
00253       LField<T2,Dim> &rf = *(*rf_i).second;
00254       const NDIndex<Dim> &ro = rf.getOwned();
00255       const NDIndex<Dim> &ra = rf.getAllocated();
00256 
00257       // If the remote has info we want, then get it.
00258       if (la.touches(ro)) {
00259         ASSIGNMSG(msg << "Computing assignment of portion of rhs " << ro);
00260         ASSIGNMSG(msg << " to lhs " << la << endl);
00261 
00262         // Can we compress the left?
00263         // End point "contains" works here since ro has unit stride.
00264         bool c1 = rf.IsCompressed();
00265         bool c2 = lf.IsCompressed();
00266         bool c3 = ro.contains(lo);
00267         ASSIGNMSG(msg << "Checking for possible compressed-assign:");
00268         ASSIGNMSG(msg << "\n  rf.IsCompressed = " << c1);
00269         ASSIGNMSG(msg << "\n  lf.IsCompressed = " << c2);
00270         ASSIGNMSG(msg << "\n  ro.contains(lo) = " << c3);
00271         ASSIGNMSG(msg << endl);
00272 
00273         // If these are compressed we might not have to do any work.
00274         if (c1 && c2 && c3) {
00275           ASSIGNMSG(msg << "LHS, RHS both compressed, and rhs contains lhs, ");
00276           ASSIGNMSG(msg << "compress." << endl);
00277           PETE_apply(op,*lf.begin(),*rf.begin());
00278           ASSIGNMSG(msg << "Now " << *lf.begin() << " == " << *rf.begin());
00279           ASSIGNMSG(msg << endl);
00280         } else {
00281           // Find the intersection.
00282           NDIndex<Dim> intersection = la.intersect(ro);
00283           ASSIGNMSG(msg << "Intersection is " << intersection << endl);
00284 
00285           // Build an iterator for the rhs.
00286           RFI rhs_i = rf.begin(intersection);
00287 
00288           // Could we compress that rhs iterator, and if so,
00289           // Are we assigning the whole LField on the left?
00290           // If both of these are true, we can compress the whole thing.
00291           // Otherwise, we have to uncompress the LHS and do a full assign.
00292           if (rhs_i.CanCompress(*rf.begin(intersection)) &&
00293               lhs.compressible() && intersection.containsAllPoints(la) &&
00294               OperatorTraits<Op>::IsAssign) {
00295 
00296             // Compress the whole LField to the value on the right:
00297             ASSIGNMSG(msg << "LHS BF is compressible, rhs_i compressed, ");
00298             ASSIGNMSG(msg << "intersection contains ");
00299             ASSIGNMSG(msg << la << ", assignment ==> compress assign.");
00300             ASSIGNMSG(msg << endl);
00301             lf.Compress((T1)(*rf.begin(intersection)));
00302             ASSIGNMSG(msg << "Now " << *lf.begin() << " == ");
00303             ASSIGNMSG(msg << *rf.begin(intersection) << endl);
00304 
00305           } else {
00306             // Assigning only part of LField on the left.
00307             // Must uncompress lhs, if not already uncompressed
00308             // If the argument is true, we are not assigning to the whole
00309             // allocated domain, and thus must fill in the uncompressed
00310             // storage with the compressed value.  If it is false, then
00311             // we're assigning to the whole allocated domain, so we don't
00312             // have to fill (it would just all get overwritten in the
00313             // BrickExpression::apply).
00314             ASSIGNMSG(msg << "Cannot do compressed assign, so do loop."<<endl);
00315             ASSIGNMSG(msg << "First uncompress LHS LF ..." << endl);
00316             lf.Uncompress(!intersection.containsAllPoints(la));
00317 
00318             // Get the iterator for it.
00319             ASSIGNMSG(msg << "Get iterator for LHS ..." << endl);
00320             LFI lhs_i = lf.begin(intersection);
00321 
00322             // And do the assignment.
00323             ASSIGNMSG(msg << "And do expression evaluation." << endl);
00324             BrickExpression<Dim,LFI,RFI,Op>(lhs_i,rhs_i,op).apply();
00325           }
00326         }
00327       }
00328     }
00329   }
00330   TAU_PROFILE_STOP(localstimer);
00331 
00332   // ----------------------------------------
00333   // Receive all the messages.
00334   ASSIGNMSG(msg << "Processing receive-loop for " << nprocs<<" nodes."<<endl);
00335   if (nprocs > 1) {
00336     TAU_PROFILE_START(rectimer);
00337     while (remaining>0) {
00338       // Receive the next message.
00339       int any_node = COMM_ANY_NODE;
00340       Message *rmess = Ippl::Comm->receive_block(any_node,tag);
00341       PAssert(rmess != 0);
00342       --remaining;
00343 
00344       // Determine the number of domains being sent
00345       int ndoms = rmess->size() / (Dim+3);
00346       for (int idom=0; idom<ndoms; ++idom) {
00347         // extract the next domain from the message
00348         NDIndex<Dim> intersection;
00349         intersection.getMessage(*rmess);
00350 
00351         // Extract the rhs iterator from it.
00352         T2 rhs_compressed_data;
00353         RFI rhs_i(rhs_compressed_data);
00354         rhs_i.getMessage(*rmess);
00355 
00356         // Find the LField it is destined for.
00357         typename ac_recv_type::iterator hit = recv_ac.find( intersection );
00358         PAssert( hit != recv_ac.end() );
00359 
00360         // Build the lhs brick iterator.
00361         LField<T1,Dim> &lf = *(*hit).second;
00362         const NDIndex<Dim> &lo = lf.getOwned();
00363 
00364         // Check and see if we really have to do this.
00365         if ( !(rhs_i.IsCompressed() && lf.IsCompressed() &&
00366              (*rhs_i == *lf.begin())) )
00367         {
00368           // Yep. gotta do it.
00369           // Only fill in the data if you have to.
00370           bool c2 = intersection.containsAllPoints(lo);
00371           bool c3 = OperatorTraits<Op>::IsAssign;
00372           lf.Uncompress( !(c2&&c3) );
00373           LFI lhs_i = lf.begin(intersection);
00374 
00375           // Do the assignment.
00376           BrickExpression<Dim,LFI,RFI,Op>(lhs_i,rhs_i,op).apply();
00377         }
00378 
00379         // Take that entry out of the receive list.
00380         recv_ac.erase( hit );
00381       }
00382       delete rmess;
00383     }
00384     TAU_PROFILE_STOP(rectimer);
00385   }
00386 
00387   // Update the guard cells.
00388   ASSIGNMSG(msg << "Filling GC's at end if necessary ..." << endl);
00389   TAU_PROFILE_START(filltimer);
00390   lhs.setDirtyFlag();
00391   lhs.fillGuardCellsIfNotDirty();
00392   TAU_PROFILE_STOP(filltimer);
00393 
00394   // Compress the LHS.
00395   ASSIGNMSG(msg << "Trying to compress BareField at end ..." << endl);
00396   lhs.Compress();
00397 
00398   //INCIPPLSTAT(incExpressions);
00399   //INCIPPLSTAT(incBFEqualsBF);
00400 }
00401 
00402 /***************************************************************************
00403  * $RCSfile: AssignGeneralBF.cpp,v $   $Author: adelmann $
00404  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:26 $
00405  * IPPL_VERSION_ID: $Id: AssignGeneralBF.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $ 
00406  ***************************************************************************/

Generated on Mon Jan 16 13:23:43 2006 for IPPL by  doxygen 1.4.6