src/Index/SIndexAssign.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 
00026 // include files
00027 #include "Index/SIndexAssign.h"
00028 #include "Index/SIndex.h"
00029 #include "Field/BrickIterator.h"
00030 #include "Field/Field.h"
00031 #include "Field/IndexedField.h"
00032 #include "Field/Assign.h"
00033 #include "Utility/IpplInfo.h"
00034 #include "Profile/Profiler.h"
00035 
00036 
00038 // a simple class to apply the assign function to one point of the
00039 // assignment domain.
00040 template<unsigned int Dim, class OP>
00041 class SIndexAssignTraits { };
00042 
00043 
00045 // a specialization of the simple class to apply the regular assign
00046 // function to one point of the assignment domain.
00047 
00048 template<unsigned int Dim>
00049 class SIndexAssignTraits<Dim, OpAssign> {
00050 public:
00051   // initially, the sparse index container must be cleared out
00052   static void initialize(SIndex<Dim>& s) { s.clear(); }
00053 
00054   // S = exp means we cleared out all the points previously, so we know
00055   // we do not need to worry about repeated points
00056   static void apply(SIndex<Dim>& SI,
00057                     typename SIndex<Dim>::iterator_iv& LSI,
00058                     const SOffset<Dim>& SO,
00059                     bool result) {
00060     TAU_TYPE_STRING(taustr, "void (" + CT(SI) + ", " + CT(LSI) + ", " + CT(SO) 
00061       + ", bool)" );
00062     TAU_PROFILE("SIndexAssignTraits::apply()", taustr, 
00063       TAU_SPARSE | TAU_ASSIGN);
00064     if (result) {
00065       // we can just add the index to the LSIndex's list here, for the
00066       // following reasons:
00067       // 1. We did a 'clear' before the expression started (when
00068       //    initialize was called), so all the LSIndex objects in this
00069       //    SIndex are separate, empty items, not references to other
00070       //    SIndex lists.
00071       // 2. We know this point is unique, since we did a clear and then
00072       //    looped over completely different points in the expression
00073       //    evaluation.
00074       // 3. We are sure this point belongs to this LSIndex, since we
00075       //    iterate over the vnodes of the SIndex.
00076       (*LSI)->addIndex(SO);
00077     }
00078   }
00079 };
00080 
00081 
00083 // a specialization of the simple class to apply the bitwise AND assign
00084 // function to one point of the assignment domain.
00085 
00086 template<unsigned int Dim>
00087 class SIndexAssignTraits<Dim, OpBitwiseAndAssign> {
00088 public:
00089   // since we do an intersection, we must keep the existing data
00090   static void initialize(SIndex<Dim>&) { }
00091 
00092   // S &= expr means 'intersection' ... only keep the point if result is
00093   // true, remove the point if result is false
00094   static void apply(SIndex<Dim>& SI,
00095                     typename SIndex<Dim>::iterator_iv& LSI,
00096                     const SOffset<Dim>& SO,
00097                     bool result) {
00098     TAU_TYPE_STRING(taustr, "void (" + CT(SI) + ", " + CT(LSI) + ", " + CT(SO)
00099       + ", bool)" );
00100     TAU_PROFILE("SIndexAssignTraits::apply()", taustr, 
00101       TAU_SPARSE | TAU_ASSIGN);
00102     if (!result && (*LSI)->hasIndex(SO)) {
00103       // we must call removeIndex in SIndex (and not in LSIndex) here
00104       // because we might need to make a copy of the LSIndex data
00105       // first (copy-on-write).  This will be slower than doing some
00106       // form of direct assignment.
00107       SI.removeIndex(LSI, SO);
00108     }
00109   }
00110 };
00111 
00112 
00114 // a specialization of the simple class to apply the bitwise OR assign
00115 // function to one point of the assignment domain.
00116 
00117 template<unsigned int Dim>
00118 class SIndexAssignTraits<Dim, OpBitwiseOrAssign> {
00119 public:
00120   // since we do a union, we must keep the existing data
00121   static void initialize(SIndex<Dim>&) { }
00122 
00123   // S |= expr means 'union' ... we add points as normal, but we did not
00124   // clear out the points that were there previously
00125   static void apply(SIndex<Dim>& SI,
00126                     typename SIndex<Dim>::iterator_iv& LSI,
00127                     const SOffset<Dim>& SO,
00128                     bool result) {
00129     TAU_TYPE_STRING(taustr, "void (" + CT(SI) + ", " + CT(LSI) + ", " + CT(SO)
00130       + ", bool)" );
00131     TAU_PROFILE("SIndexAssignTraits::apply()", taustr, 
00132       TAU_SPARSE | TAU_ASSIGN);
00133     if (result && ! (*LSI)->hasIndex(SO)) {
00134       // we must call addIndex in SIndex (and not in LSIndex) here
00135       // because we need to check if this point SO is already in the
00136       // list of points.  This will be slower than doing some form
00137       // of direct assignment.
00138       SI.addIndex(LSI, SO);
00139     }
00140   }
00141 };
00142 
00143 
00145 // a simple class to do different dimension-specific loops in an
00146 // SIndex expression.
00147 template<class OP, unsigned int Dim>
00148 class SIndexExpLoop {
00149 public:
00150   // the general loop; this is done for 4D or higher dimensions
00151   template<class RHS>
00152   static void evaluate(SIndex<Dim>& si, typename SIndex<Dim>::iterator_iv& lsi,
00153                        NDIndex<Dim>& dom, RHS& Rhs) {
00154     TAU_TYPE_STRING(taustr, "void (" + CT(si) + ", " + CT(lsi) + ", " 
00155       + CT(dom) + ", " + CT(Rhs) + " )" );
00156     TAU_PROFILE("SIndexExpLoop::evaluate()", taustr, TAU_SPARSE);
00157     int n0 = dom[0].length();
00158     int n1 = dom[1].length();
00159     int n2 = dom[2].length();
00160     if (n0 > 0 && n1 > 0 && n2 > 0) {
00161         BrickCounter<Dim> count(dom);   // ada: changed from cdom to dom, cdom does not make sense!
00162         ERRORMSG("changed from cdom to dom, cdom does not make sense! (SindexAssign.cpp)" << endl);
00163         
00164         unsigned d;
00165       SOffset<Dim> so;
00166       for (d=3; d < Dim; ++d)
00167         so[d] = dom[d].first();
00168       do {
00169         Index::iterator x2 = dom[2].begin();
00170         for (int i2=0; i2<n2; ++i2, ++x2) {
00171           so[2] = *x2;
00172           Index::iterator x1 = dom[1].begin();
00173           for (int i1=0; i1<n1; ++i1, ++x1) {
00174             so[1] = *x1;
00175             Index::iterator x0 = dom[0].begin();
00176             for (int i0=0; i0<n0; ++i0, ++x0) {
00177               so[0] = *x0;
00178               bool result = (for_each(Rhs, EvalFunctor_3(i0,i1,i2)) != false);
00179               SIndexAssignTraits<3U,OP>::apply(si, lsi, so, result);
00180             }
00181           }
00182         }
00183 
00184         for (d=3; d<Dim; ++d) {
00185           count.step(d);
00186           so[d] += dom[d].stride();
00187           for_each(Rhs,StepFunctor(d),PETE_NullCombiner());
00188           if ( ! count.done(d) )
00189             break;
00190           count.rewind(d);
00191           so[d] = dom[d].first();
00192           for_each(Rhs,RewindFunctor(d),PETE_NullCombiner());
00193         }
00194 
00195       } while (d<Dim);
00196     }
00197   }
00198 };
00199 
00200 
00202 //a specialization of SIndexAssignLoop for a 1D loop evaluation NOTE:
00203 //dom must be within the local domain of the given LSIndex
00204 template<class OP>
00205 class SIndexExpLoop<OP,1U> {
00206 public:
00207   template<class RHS>
00208   static void evaluate(SIndex<1U>& si, SIndex<1U>::iterator_iv& lsi,
00209                        NDIndex<1U>& dom, RHS& Rhs) {
00210     TAU_TYPE_STRING(taustr, "void (" + CT(si) + ", " + CT(lsi) + ", " + CT(dom)
00211       + ", " + CT(Rhs) + " )" );
00212     TAU_PROFILE("SIndexExpLoop::evaluate()", taustr, TAU_SPARSE );
00213     int n0 = dom[0].length();
00214     if (n0 > 0) {
00215       Index::iterator x0 = dom[0].begin();
00216       for (int i0 = 0; i0 < n0; ++i0, ++x0) {
00217         bool result = (for_each(Rhs, EvalFunctor_1(i0)) != false);
00218         SIndexAssignTraits<1U,OP>::apply(si, lsi, SOffset<1>(*x0), result);
00219       }
00220     }
00221   }
00222 };
00223 
00224 
00226 // a specialization of SIndexAssignLoop for a 2D loop evaluation
00227 // NOTE: dom must be within the local domain of the given LSIndex
00228 template<class OP>
00229 class SIndexExpLoop<OP,2U> {
00230 public:
00231   template<class RHS>
00232   static void evaluate(SIndex<2U>& si, SIndex<2U>::iterator_iv& lsi,
00233                        NDIndex<2U>& dom, RHS& Rhs) {
00234     TAU_TYPE_STRING(taustr, "void (" + CT(si) + ", " + CT(lsi) + ", " + CT(dom)
00235       + ", " + CT(Rhs) + " )" );
00236     TAU_PROFILE("SIndexExpLoop::evaluate()", taustr, TAU_SPARSE );
00237     int n0 = dom[0].length();
00238     int n1 = dom[1].length();
00239     if (n0 > 0 && n1 > 0) {
00240       Index::iterator x1 = dom[1].begin();
00241       for (int i1 = 0; i1 < n1; ++i1, ++x1) {
00242         Index::iterator x0 = dom[0].begin();
00243         for (int i0 = 0; i0 < n0; ++i0, ++x0) {
00244           bool result = (for_each(Rhs, EvalFunctor_2(i0,i1)) != false);
00245           SIndexAssignTraits<2U,OP>::apply(si, lsi, SOffset<2>(*x0, *x1),
00246                                            result);
00247         }
00248       }
00249     }
00250   }
00251 };
00252 
00253 
00255 // a specialization of SIndexAssignLoop for a 3D loop evaluation
00256 // NOTE: dom must be within the local domain of the given LSIndex
00257 template<class OP>
00258 class SIndexExpLoop<OP,3U> {
00259 public:
00260   template<class RHS>
00261   static void evaluate(SIndex<3U>& si, SIndex<3U>::iterator_iv& lsi,
00262                        NDIndex<3U>& dom, RHS& Rhs) {
00263     TAU_TYPE_STRING(taustr, "void (" + CT(si) + ", " + CT(lsi) + ", " + CT(dom)
00264       + ", " + CT(Rhs) + " )" );
00265     TAU_PROFILE("SIndexExpLoop::evaluate()", taustr, TAU_SPARSE );
00266     int n0 = dom[0].length();
00267     int n1 = dom[1].length();
00268     int n2 = dom[2].length();
00269     if (n0 > 0 && n1 > 0 && n2 > 0) {
00270       Index::iterator x2 = dom[2].begin();
00271       for (int i2 = 0; i2 < n2; ++i2, ++x2) {
00272         Index::iterator x1 = dom[1].begin();
00273         for (int i1 = 0; i1 < n1; ++i1, ++x1) {
00274           Index::iterator x0 = dom[0].begin();
00275           for (int i0 = 0; i0 < n0; ++i0, ++x0) {
00276             bool result = (for_each(Rhs, EvalFunctor_3(i0,i1,i2)) != false);
00277             SIndexAssignTraits<3U,OP>::apply(si, lsi,
00278                                              SOffset<3>(*x0, *x1, *x2),
00279                                              result);
00280           }
00281         }
00282       }
00283     }
00284   }
00285 };
00286 
00287 
00289 // The 'assign' function for SIndex objects must handle two situations,
00290 // one where the RHS is a simple, full-field expression, and one where
00291 // the RHS is a complex, indexed expression.  The 'AssignActions'
00292 // struct is specialized on the 'SiExprTag<bool>' class to perform
00293 // different setup and cleaup operations for the RHS objects based on
00294 // whether the expression is simple (bool=false) or indexed (bool=true).
00295 
00296 template<unsigned Dim, class T>
00297 struct AssignActions { };
00298 
00299 template<unsigned Dim>
00300 struct AssignActions<Dim, SIExprTag<true> > {
00301   template<class RHS>
00302   static void fillgc(RHS &bb, const NDIndex<Dim> &domain) {
00303     // ask each field on the RHS to fill its guard cells, if necessary
00304     //tjw3/3/99    for_each(bb, FillGCIfNecessary(domain), PETE_NullCombiner());
00305     for_each(bb, FillGCIfNecessary(FGCINTag<Dim,double>()), PETE_NullCombiner());
00306   }
00307 
00308   template<class RHS>
00309   static bool plugbase(RHS &bb, const NDIndex<Dim> &domain) {
00310     // ask each RHS field to set itself up to iterate over the given locdomain.
00311     // if any cannot, this will return false.
00312     return for_each(bb, PlugBase<Dim>(domain), PETE_AndCombiner());
00313   }
00314 
00315   template<class RHS>
00316   static void nextLField(RHS &) {
00317     // in this case, there is nothing to do, since PlugBase always ends
00318     // up setting which LField to use
00319   }
00320 };
00321 
00322 template<unsigned Dim>
00323 struct AssignActions<Dim, SIExprTag<false> > {
00324   template<class RHS>
00325   static void fillgc(RHS &bb, const NDIndex<Dim> &) {
00326     // ask each field on the RHS to fill its guard cells, if necessary
00327     // here, it cannot be a stencil, so not necessary
00328     //tjw 3/3/99, add:
00329     for_each(bb, FillGCIfNecessary(FGCINTag<Dim,double>()), PETE_NullCombiner());
00330     //tjw 3/3/99, add.
00331   }
00332 
00333   template<class RHS>
00334   static bool plugbase(RHS &bb, const NDIndex<Dim> &) {
00335     // tell each RHS field to reset to the beginning of it's current LField
00336     for_each(bb, BeginLField(), PETE_NullCombiner());
00337     return true;
00338   }
00339 
00340   template<class RHS>
00341   static void nextLField(RHS &bb) {
00342     // tell each RHS field to move on to the next LField
00343     for_each(bb, NextLField(), PETE_NullCombiner());
00344   }
00345 };
00346 
00347 
00349 // assign values to an SIndex: evaluate the RHS at all the points in
00350 // the given domain, find where it evaluates to true, and store the
00351 // value of that index point.
00352 template<unsigned Dim, class RHS, class Op, bool IsExpr>
00353 void assign(SIndex<Dim>& a, RHS b, Op, const NDIndex<Dim> &domain,
00354             SIExprTag<IsExpr> isexpr) {
00355   TAU_PROFILE_STMT(Op oper);
00356   TAU_TYPE_STRING(taustr, "void (" + CT(a) + ", " + CT(b) + CT(oper) + " )"); 
00357   TAU_PROFILE("assign()", taustr, TAU_SPARSE | TAU_ASSIGN);
00358 
00359   // Inform dbgmsg("SIndex assign", INFORM_ALL_NODES);
00360   // dbgmsg << "Computing on total domain = " << domain << endl;
00361 
00362   // unwrap the PETE expression object to get what we're computing with
00363   typename RHS::Wrapped& bb = b.PETE_unwrap();
00364 
00365   // initialize the SIndex for this operation
00366   SIndexAssignTraits<Dim,Op>::initialize(a);
00367 
00368   // Fill GC's, if necessary
00369   AssignActions<Dim,SIExprTag<IsExpr> >::fillgc(bb, domain);
00370 
00371   // iterate through all the local vnodes in the FieldLayout used
00372   // by the SIndex, and look at the points in these domains
00373   typename SIndex<Dim>::iterator_iv la   = a.begin_iv();
00374   typename SIndex<Dim>::iterator_iv aend = a.end_iv();
00375   for ( ; la != aend; ++la ) {
00376     // check if we have any points in this LField to process
00377     NDIndex<Dim> locdomain = domain.intersect((*la)->getDomain());
00378     //dbgmsg << "Doing LField " << (*la)->getDomain() << " with intersection ";
00379     //dbgmsg << locdomain << endl;
00380 
00381     // only proceed if we have any intersecting points
00382     if (!locdomain.empty()) {
00383       // First look and see if the arrays are sufficiently aligned to do
00384       // this in one shot.  We do this by trying to do a plugBase and
00385       // seeing if it worked.
00386       if (AssignActions<Dim,SIExprTag<IsExpr> >::plugbase(bb, locdomain)) {
00387 
00388         // check if the RHS is compressed and we can do a compressed assign
00389         if (OperatorTraits<Op>::IsAssign && locdomain == (*la)->getDomain() &&
00390             for_each(bb, IsCompressed(), PETE_AndCombiner())) {
00391           // why yes we can ... tell the SIndex to store the results for
00392           // the entire vnode in one shot
00393           bool result = (for_each(bb, EvalFunctor_0()) != false);
00394           (*la)->Compress(result);
00395 
00396           //NDIndex<Dim>& dom = (NDIndex<Dim>&) ((*la)->getDomain());
00397           //dbgmsg << "compressed in dom = " << dom << ", result = " << result;
00398           //dbgmsg << endl;
00399         } else { 
00400           // perform actions to find necessary points in the current Vnode
00401           // of the SIndex, by looping over the domain and seeing where
00402           // the RHS == true
00403           SIndexExpLoop<Op,Dim>::evaluate(a, la, locdomain, bb);
00404 
00405           //NDIndex<Dim>& dom = (NDIndex<Dim>&) ((*la)->getDomain());
00406           //dbgmsg << "uncompressed in dom = " << dom << endl;
00407         }
00408       } else {
00409         ERRORMSG("All Fields in an expression must be aligned.  ");
00410         ERRORMSG("(Do you have enough guard cells?)" << endl);
00411         ERRORMSG("This error occurred while evaluating an SIndex expression ");
00412         ERRORMSG("for an LField with domain " << (*la)->getDomain() << endl);
00413         Ippl::abort();
00414       }
00415       //    } else {
00416       //      dbgmsg << " ... intersection is empty." << endl;
00417     }
00418 
00419     // move the RHS Field's on to the next LField, if necessary
00420     AssignActions<Dim,SIExprTag<IsExpr> >::nextLField(bb);
00421   }
00422 
00423   // at the end, tell the SIndex we used this domain, so that should be
00424   // its new bounding box
00425   a.setDomain(domain);
00426 }
00427 
00428 
00429 /***************************************************************************
00430  * $RCSfile: SIndexAssign.cpp,v $   $Author: adelmann $
00431  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:27 $
00432  * IPPL_VERSION_ID: $Id: SIndexAssign.cpp,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $ 
00433  ***************************************************************************/

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