src/Field/Assign.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 versions of assign() that work with expressions
00029 // on the RHS.  They do not handle general communications, and require
00030 // sufficient guard cells to cover any stencil-like access.
00031 //
00033 
00034 // include files
00035 #include "Field/Assign.h"
00036 #include "Field/AssignDefs.h"
00037 #include "Field/BareField.h"
00038 #include "Field/BrickExpression.h"
00039 #include "Field/IndexedBareField.h"
00040 #include "Field/LField.h"
00041 #include "Message/Communicate.h"
00042 #include "Message/Message.h"
00043 #include "Utility/PAssert.h"
00044 #include "Utility/IpplInfo.h"
00045 #include "Utility/IpplStats.h"
00046 #include "Profile/Profiler.h"
00047 #include "PETE/IpplExpressions.h"
00048 
00049 #ifdef IPPL_STDSTL
00050 #include <map>
00051 #include <vector>
00052 #include <functional>
00053 #include <utility>
00054 using namespace std;
00055 #else
00056 #include <map.h>
00057 #include <vector.h>
00058 #include <function.h>
00059 #include <multimap.h>
00060 #endif
00061 
00062 #ifdef IPPL_USE_STANDARD_HEADERS
00063 #include <iostream>
00064 #include <typeinfo>
00065 using namespace std;
00066 #else
00067 #include <iostream.h>
00068 #include <typeinfo.h>
00069 #endif
00070 
00071 
00073 //
00074 // TryCompressLhs.
00075 //
00076 // Encodes the logic for whether to compress or uncompress the
00077 // left hand side given information about the expression.
00078 //
00080 
00081 template<class T, unsigned Dim, class A, class Op>
00082 bool
00083 TryCompressLHS(LField<T,Dim>& lf, A& rhs, Op op, const NDIndex<Dim>& domain)
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(taustr, "bool (" + CT(lf) + ", " + CT(rhs) + ", " +
00089                   CT(Op) + ", " + CT(domain) + " )" );
00090   TAU_PROFILE("TryCompressLHS()", taustr, TAU_ASSIGN | TAU_FIELD);
00091 
00092   // just skip this if we can
00093   if (IpplInfo::noFieldCompression)
00094     return(false);
00095 
00096   // debugging output macros.  these are only enabled if DEBUG_ASSIGN is
00097   // defined.
00098   ASSIGNMSG(Inform msg("TryCompressLHS", INFORM_ALL_NODES));
00099   ASSIGNMSG(msg << "Checking for compressibility of LField with domain = ");
00100   ASSIGNMSG(msg << lf.getOwned() << " over assignment domain = " << domain);
00101   ASSIGNMSG(msg << endl);
00102 
00103   // If the right hand side is compressed and we are looking at
00104   // the whole domain for the lhs, we have a chance of
00105   // being able to compress the left hand side.
00106   // Then if it is simple assign or if the lhs is already compressed
00107   // we can do a compressed assign.
00108   bool c1 = for_each(rhs,IsCompressed(),PETE_AndCombiner());
00109   bool c2 = domain.containsAllPoints(lf.getOwned());
00110   bool c3 = OperatorTraits<Op>::IsAssign;
00111   bool c4 = lf.IsCompressed();
00112   bool compress = c1 && c2 && ( c3 || c4 );
00113 
00114   ASSIGNMSG(msg << "  RHS IsCompressed() = " << c1 << endl);
00115   ASSIGNMSG(msg << "  LHS IsCompressed() = " << c4 << endl);
00116   ASSIGNMSG(msg << "domain.contains(lhs) = " << c2 << endl);
00117   ASSIGNMSG(msg << "            IsAssign = " << c3 << endl);
00118   ASSIGNMSG(msg << "              result = " << compress << endl);
00119 
00120   // If we decide it can be compressed, do it, otherwise undo it.
00121   if (compress)
00122     {
00123       // We can compress this, so compress it down using first element
00124       // as the compression value.
00125       ASSIGNMSG(msg << "Yes we CAN compress, so do so now ... ");
00126       lf.Compress();
00127       ASSIGNMSG(msg << "now, compressed value = " << *lf.begin() << endl);
00128       return true;
00129     }
00130 
00131   // We can't compress the LHS.  Check if both sides are compressed already
00132   // and have the same value, and we're doing assignment (that is, check
00133   // if we're trying to assign the same value to a portion of an already
00134   // compressed region).  Note that if this is true, we know that the op
00135   // is for assignment.
00136   if (c1 && c3 && c4)
00137     {
00138       T tmpval;
00139       PETE_apply(op, tmpval, for_each(rhs, EvalFunctor_0()));
00140       if (*lf.begin() == tmpval)
00141         {
00142           // Both sides are compressed, and we're doing assignment, but the
00143           // domains don't fully intersect.  We can still deal with this as
00144           // a compressed entity if the LHS compressed value equals the RHS
00145           // compressed value.
00146           ASSIGNMSG(msg << "LHS and RHS are compressed, doing assign, and ");
00147           ASSIGNMSG(msg << *lf.begin() << " == " <<tmpval<<", so result = 1");
00148           ASSIGNMSG(msg << endl);
00149           return true;
00150         }
00151     }
00152 
00153   // OK we need to uncompress the LHS, but we might not need to keep the data.
00154   // If we are doing assignment, or are not going to use all of the
00155   // LHS domain, we will need to copy the compressed value into the
00156   // uncompressed storage.  Otherwise, we know we'll just reset all the
00157   // values during the upcoming assignment, so it is a waste to do it
00158   // now.  If the arguments is true, then copy in the compressed value,
00159   // if it is false then allocate storage but do not do anything more
00160   // now to initialize it.
00161   ASSIGNMSG(msg << "No we cannot compress, so make sure we're ");
00162   ASSIGNMSG(msg << "uncompressed. Fill domain? " << !(c3&&c2) << endl);
00163   lf.Uncompress( !(c3 && c2) );
00164   return false;
00165 }
00166 
00167 
00169 //
00170 // A class with an interface like BrickIterator
00171 // that applies the parens operator to some expression of type Expr.
00172 // It passes most operations to the 'Child' item, but retrieves values
00173 // by applying operator() to the Child or the Child's returned values.
00174 // This is used by the version of assign that lets you assign values
00175 // to just one component of a Field on the LHS.
00176 //
00178 
00179 template<class Expr>
00180 class ParensIterator : public Expr
00181 {
00182 public:
00183   typedef typename Expr::PETE_Return_t PETE_Return_t;
00184 
00185   ParensIterator( const Expr& e ) : Expr(e) {}
00186   PETE_Return_t& operator*() const
00187   {
00188     return (*Expr::Child)(Expr::Value.Arg);
00189   }
00190   PETE_Return_t& offset(int i) const
00191   {
00192     return Expr::Child.offset(i)(Expr::Value.Arg);
00193   }
00194   PETE_Return_t& offset(int i, int j) const
00195   {
00196     return Expr::Child.offset(i,j)(Expr::Value.Arg);
00197   }
00198   PETE_Return_t& offset(int i, int j, int k) const
00199   {
00200     return Expr::Child.offset(i,j,k)(Expr::Value.Arg);
00201   }
00202 
00203   PETE_Return_t& operator*() 
00204   {
00205     return (*Expr::Child)(Expr::Value.Arg);
00206   }
00207   PETE_Return_t& offset(int i) 
00208   {
00209     return Expr::Child.offset(i)(Expr::Value.Arg);
00210   }
00211   PETE_Return_t& offset(int i, int j) 
00212   {
00213     return Expr::Child.offset(i,j)(Expr::Value.Arg);
00214   }
00215   PETE_Return_t& offset(int i, int j, int k) 
00216   {
00217     return Expr::Child.offset(i,j,k)(Expr::Value.Arg);
00218   }
00219   PETE_Return_t& unit_offset(int i) 
00220   {
00221     return Expr::Child.unit_offset(i)(Expr::Value.Arg);
00222   }
00223   PETE_Return_t& unit_offset(int i, int j) 
00224   {
00225     return Expr::Child.unit_offset(i,j)(Expr::Value.Arg);
00226   }
00227   PETE_Return_t& unit_offset(int i, int j, int k) 
00228   {
00229     return Expr::Child.unit_offset(i,j,k)(Expr::Value.Arg);
00230   }
00231 
00232   void step(unsigned d)
00233   {
00234     Expr::Child.step(d);
00235   }
00236   void rewind(unsigned d)
00237   {
00238     Expr::Child.rewind(d);
00239   }
00240   int size(unsigned d) const
00241   {
00242     return Expr::Child.size(d);
00243   }
00244   int done(unsigned d) const
00245   {
00246     return Expr::Child.done(d);
00247   }
00248   int Stride(int d) const
00249   {
00250     return Expr::Child.Stride(d);
00251   }
00252 };
00253 
00254 
00256 //
00257 // IndexedBareField = expression assignment.
00258 //
00259 // This is the specialization with ExprTag<true>, meaning the RHS
00260 // is an expression, not just a simple IndexedBareField.  This version
00261 // only works if the LHS and RHS terms all agree in their parallel
00262 // layout within guard-cell tolerances.  If they do not, it is
00263 // an error and IPPL will report it and die.
00264 // Since this is for IndexedBareField, extra checks are done to
00265 // make sure you only process the relevant domain, and that you keep
00266 // track of how you are indexing the values (using plugbase).
00267 //
00269 
00270 template<class T1, unsigned Dim, class RHS, class OP>
00271 void
00272 assign(const IndexedBareField<T1,Dim,Dim> &aa, RHS b, OP op, ExprTag<true>, 
00273        bool fillGC)
00274 {
00275   IndexedBareField<T1,Dim,Dim> &a = 
00276     const_cast<IndexedBareField<T1,Dim,Dim>&>(aa);
00277 
00278   // profiling macros
00279   // here, 'Op' is not used to form the type string, so the timings here
00280   // will be the sum of all different operators 'Op' used in the code.
00281   TAU_TYPE_STRING(p1, "void (" + CT(a) + ", " + CT(b) + ", " + CT(op) 
00282     + ", ExprTag<true> )" );
00283   TAU_PROFILE("assign()", p1.data(), TAU_ASSIGN | TAU_FIELD);
00284   TAU_PROFILE_TIMER(looptimer, " assign[IndexedBareField]-vnodeloop",
00285                     p1.data(), TAU_ASSIGN);
00286   TAU_PROFILE_TIMER(filltimer, " assign[IndexedBareField]-guardfill",
00287                     p1.data(), TAU_ASSIGN);
00288 
00289   // debugging output macros.  these are only enabled if DEBUG_ASSIGN is
00290   // defined.
00291   ASSIGNMSG(Inform msg("assign IBF(t)", INFORM_ALL_NODES));
00292   ASSIGNMSG(msg << "Computing assignment to IBF[" << aa.getDomain());
00293   ASSIGNMSG(msg << "] ..." << endl);
00294 
00295   // First check to see if any of the terms on the rhs
00296   // are the field on the lhs.  If so we'll have to make temporaries.
00297   int lhs_id = a.getBareField().get_Id();
00298   typename RHS::Wrapped& bb = b.PETE_unwrap();
00299   bool both_sides = for_each(bb,SameFieldID(lhs_id),PETE_OrCombiner());
00300 
00301   // Fill guard cells if necessary
00302   ASSIGNMSG(msg << "Checking whether to fill GC's on RHS ..." << endl);
00303   for_each(bb, FillGCIfNecessary(a.getBareField()), PETE_NullCombiner());
00304 
00305   // Begin and end iterators for the local fields in the left hand side.
00306   typename BareField<T1,Dim>::iterator_if la = a.getBareField().begin_if();
00307   typename BareField<T1,Dim>::iterator_if aend = a.getBareField().end_if();
00308 
00309   // Set the dirty flag indicating this field should have guard cells
00310   // filled next time if we are doing deferred GC fills, since
00311   // we will be modifying at least one LField of this BareField.
00312   // We need to set this here so that our compression checks on each
00313   // LField take the dirty flag setting into account.
00314   a.getBareField().setDirtyFlag();
00315 
00316   // Loop over all the local fields of the left hand side.
00317   TAU_PROFILE_START(looptimer);
00318   int lfcount=0;
00319   bool needFinalCompressCheck = false;
00320   while (la != aend)
00321     {
00322       // The pointer to the current lhs local field.
00323       LField<T1,Dim> *lf = (*la).second.get();
00324 
00325       // If it is on the rhs somewhere, make a copy of it.
00326       if ( both_sides ) {
00327         lf = new LField<T1,Dim>( *lf );
00328         ASSIGNMSG(msg << "For lf " << lfcount << ": making lfield copy.");
00329         ASSIGNMSG(msg << endl);
00330       }
00331 
00332       // Find the local domain.
00333       // Intersect with the indexes used to see how much we will actually use.
00334       NDIndex<Dim> local_domain = a.getDomain().intersect( lf->getOwned() );
00335 
00336       // If there is something there...
00337       if ( ! local_domain.empty() )
00338         {
00339           // Some typedefs to make the lines shorter...
00340           // types for the left hand side, right hand side and
00341           // the whole expression.
00342           typedef typename LField<T1,Dim>::iterator LHS;
00343           typedef BrickExpression<Dim,LHS,typename RHS::Wrapped,OP> ExprT;
00344 
00345           // First look and see if the arrays are sufficiently aligned
00346           // to do this in one shot.
00347           // We do this by trying to do a plugBase and seeing if it worked.
00348 
00349           ASSIGNMSG(msg << "For lf " << lfcount << ": plugbase on ");
00350           ASSIGNMSG(msg << local_domain << endl);
00351           if ( for_each(bb,PlugBase<Dim>( local_domain ), PETE_AndCombiner()) )
00352             {
00353               ASSIGNMSG(msg << "For lf " << lfcount << " with owned domain ");
00354               ASSIGNMSG(msg << lf->getOwned() << " assigned intersection ");
00355               ASSIGNMSG(msg << local_domain << " : ");
00356 
00357               if (a.getBareField().compressible() &&
00358                   TryCompressLHS(*lf,bb,op,local_domain) ) {
00359                 // Compressed assign.
00360                 ASSIGNMSG(msg << "compressed assign, changing ");
00361                 ASSIGNMSG(msg << *(lf->begin()));
00362 
00363                 // Just apply the operator to the single compressed value
00364                 // on the LHS.  If we're here, we know the RHS is compressed
00365                 // so we can just evaluate it at its first position.
00366                 PETE_apply(op, *(lf->begin()), for_each(bb,EvalFunctor_0()));
00367                 ASSIGNMSG(msg << " to " << *(lf->begin()) << endl);
00368               } else {
00369                 // Loop assign.
00370                 ASSIGNMSG(msg << "loop assign." << endl);
00371 
00372                 // Create the expression object.
00373                 ExprT expr(lf->begin(local_domain), bb);
00374                 expr.apply();
00375 
00376                 // Try to compress this LField since we did an uncompressed
00377                 // assignment, if the user has requested this kind of
00378                 // check right after computation on the LField.  If this
00379                 // is not selected, then we'll need to do some end-of-loop
00380                 // compression checks.
00381                 if (IpplInfo::extraCompressChecks) {
00382                   ASSIGNMSG(msg << "For lf " << lfcount);
00383                   ASSIGNMSG(msg << ": doing extra post-compute ");
00384                   ASSIGNMSG(msg << "compression check ..." << endl);
00385                   lf->TryCompress(a.getBareField().isDirty());
00386                 } else {
00387                   needFinalCompressCheck = true;
00388                 }
00389               }
00390             }
00391           else
00392             {
00393               ERRORMSG("All Fields in an expression must be aligned.  ");
00394               ERRORMSG("(Do you have enough guard cells?)" << endl);
00395               ERRORMSG("This error occurred while evaluating an expression ");
00396               ERRORMSG("for an LField with domain " << lf->getOwned() << endl);
00397               Ippl::abort();
00398             }
00399         }
00400 
00401       // If we had to make a copy of the current LField,
00402       // swap the pointers and delete the old memory.
00403       if ( both_sides )
00404         {
00405           ASSIGNMSG(msg << "For lf " << lfcount << ": swapping lfield data.");
00406           ASSIGNMSG(msg << endl);
00407           ASSIGNMSG(msg << "For lf " << lfcount << ": at beg, lfield=" << *lf);
00408           ASSIGNMSG(msg << endl);
00409           (*la).second->swapData( *lf );
00410           delete lf;
00411           ASSIGNMSG(msg << "For lf " << lfcount << ": at end, lfield=");
00412           ASSIGNMSG(msg << *((*la).second) << endl);
00413         }
00414 
00415       ++la;
00416       ++lfcount;
00417     }
00418   TAU_PROFILE_STOP(looptimer);
00419 
00420   // If we are not deferring guard cell fills, and we need to do this
00421   // now, fill the guard cells.  This will also apply any boundary
00422   // conditions after the guards have been updated.
00423   if (fillGC) {
00424     ASSIGNMSG(msg << "Filling GC's at end if necessary ..." << endl);
00425     TAU_PROFILE_START(filltimer);
00426     a.getBareField().fillGuardCellsIfNotDirty();
00427     TAU_PROFILE_STOP(filltimer);
00428   }
00429 
00430   // Try to compress the result.
00431   if (fillGC && needFinalCompressCheck) {
00432     ASSIGNMSG(msg << "Trying to compress BareField at end ..." << endl);
00433     a.getBareField().Compress(); // tjw added fillGC 12/16/1997
00434   }
00435 
00436   //INCIPPLSTAT(incExpressions);
00437   //INCIPPLSTAT(incIBFEqualsExpression);
00438 }
00439 
00440 
00442 //
00443 // ParensExpression = expression assignment.
00444 //
00445 // A version of assign() that handles assignment to just a component of
00446 // a Field that has been selected via operator().  This version
00447 // only works if the LHS and RHS terms all agree in their parallel
00448 // layout within guard-cell tolerances.  If they do not, it is
00449 // an error and IPPL will report it and die.  The item having operator()
00450 // applied can be a BareField or an IndexedBareField.
00451 //
00453 
00454 template<class A, class RHS, class OP, class Tag, class TP>
00455 void
00456 assign(PETE_TUTree<OpParens<TP>,A> lhs, RHS wrhs, OP op, Tag,
00457        bool fillGC)
00458 {
00459   // profiling macros
00460   // here, 'Op' is not used to form the type string, so the timings here
00461   // will be the sum of all different operators 'Op' used in the code.
00462   TAU_PROFILE_STMT(Tag tauTag);
00463   TAU_TYPE_STRING(p1, "void (" + CT(lhs) + ", " + CT(wrhs) + ", " + CT(op)
00464                   + ", " + CT(tauTag) + " )" );
00465   TAU_PROFILE("assign()", p1.data(), TAU_ASSIGN | TAU_FIELD);
00466   TAU_PROFILE_TIMER(looptimer, " assign[TUTree]-vnodeloop", p1.data(),
00467                     TAU_ASSIGN);
00468   TAU_PROFILE_TIMER(filltimer, " assign[TUTree]-guardfill", p1.data(),
00469                     TAU_ASSIGN);
00470 
00471   // debugging output macros.  these are only enabled if DEBUG_ASSIGN is
00472   // defined.
00473   ASSIGNMSG(Inform msg("assign Parens", INFORM_ALL_NODES));
00474   ASSIGNMSG(msg << "Computing assignment to IBF[" << lhs.Child.getDomain());
00475   ASSIGNMSG(msg << "](" << lhs.Value.Arg << ") ..." << endl);
00476 
00477   enum { Dim = A::Dim_u };
00478   typedef typename A::return_type T1;
00479 
00480   typedef typename Expressionize<RHS>::type::Wrapped RHS_Wrapped;
00481   typename Expressionize<RHS>::type expr = Expressionize<RHS>::apply(wrhs);
00482   RHS_Wrapped & rhs = expr.PETE_unwrap();
00483   
00484   // Get a reference to the BareField on the left hand side, and the
00485   // total domain we are modifying.
00486   BareField<T1,Dim>& bare = lhs.Child.getBareField();
00487   const NDIndex<Dim> &total_domain = lhs.Child.getDomain();
00488 
00489   // First check to see if any of the terms on the rhs
00490   // are the field on the lhs.  If so we'll have to make temporaries.
00491   bool both_sides = for_each(rhs,SameFieldID(bare.get_Id()),PETE_OrCombiner());
00492 
00493   // Fill guard cells if necessary
00494   ASSIGNMSG(msg << "Checking whether to fill GC's on RHS ..." << endl);
00495   for_each(rhs, FillGCIfNecessary(bare), PETE_NullCombiner());
00496 
00497   // Begin and end iterators for the local fields in the left hand side.
00498   typename BareField<T1,Dim>::iterator_if la = bare.begin_if();
00499   typename BareField<T1,Dim>::iterator_if aend = bare.end_if();
00500 
00501   // Set the dirty flag indicating this field should have guard cells
00502   // filled next time if we are doing deferred GC fills.
00503   // We need to set this here so that our compression checks on each
00504   // LField take the dirty flag setting into account.
00505   bare.setDirtyFlag();
00506 
00507   // Loop over all the local fields of the left hand side.
00508   TAU_PROFILE_START(looptimer);
00509   bool needFinalCompressCheck = false;
00510   while (la != aend)
00511     {
00512       // The pointer to the current lhs local field, and the owned domain.
00513       LField<T1,Dim> *lf = (*la).second.get();
00514       const NDIndex<Dim> &lo = lf->getOwned();
00515 
00516       // Find the local domain.
00517       // Intersect with the indexes used to see how much we will actually use.
00518       NDIndex<Dim> local_domain = total_domain.intersect(lo);
00519 
00520       // If there is something there...
00521       if (!local_domain.empty())
00522         {
00523           // Some typedefs to make the lines shorter...
00524           // types for the left hand side, right hand side and
00525           // the whole expression.
00526           typedef typename LField<T1,Dim>::iterator LA;
00527           typedef PETE_TUTree<OpParens<TP>,LA> LHS;
00528           typedef BrickExpression<Dim,ParensIterator<LHS>,RHS_Wrapped,OP> 
00529             ExprT;
00530 
00531           // First look and see if the arrays are sufficiently aligned
00532           // to do this in one shot.
00533           // We do this by trying to do a plugBase and seeing if it worked.
00534           ASSIGNMSG(msg << "For lf " << lo << ": plugbase on ");
00535           ASSIGNMSG(msg << local_domain << endl);
00536           if (for_each(rhs, PlugBase<Dim>(local_domain), PETE_AndCombiner()))
00537             {
00538               // Check and see if the lhs is already compressed, and if so,
00539               // if the RHS is compressed as well.  If so, then we can
00540               // just do a compressed assign to modify the Nth element
00541               // of the compressed value.
00542               bool c1 = for_each(rhs, IsCompressed(), PETE_AndCombiner());
00543               bool c2 = local_domain.containsAllPoints(lo);
00544               bool c3 = lf->IsCompressed();
00545               if (bare.compressible() && c1 && c2 && c3) {
00546                 // We can do a compressed assign, and we know the LHS is
00547                 // already compressed.  So we can just assign to the first
00548                 // value, which will modify the selected element of that
00549                 // value.
00550                 ASSIGNMSG(msg << "Compressed assign on ");
00551                 ASSIGNMSG(msg << local_domain << ", changing "<< *lf->begin());
00552                 const ParensIterator<LHS> ilhs = LHS(lhs.Value, lf->begin());
00553                 PETE_apply(op, *ilhs, for_each(rhs, EvalFunctor_0()));
00554                 ASSIGNMSG(msg << " to " << *lf->begin() << endl);
00555 
00556               } else {
00557                 ASSIGNMSG(msg << "Loop assign on " << local_domain << endl);
00558 
00559                 // We must uncompress, and since we will only be writing
00560                 // to a portion of each element, we must definitely fill
00561                 // the domain with the compressed value if it is currently
00562                 // compressed.
00563                 lf->Uncompress();
00564 
00565                 // Build an object that will carry out the expression.
00566                 const ParensIterator<LHS> ilhs =
00567                   LHS(lhs.Value, lf->begin(local_domain));
00568                 ExprT expr(ilhs, rhs, op);
00569                 expr.apply();
00570 
00571                 // Try to compress this LField right after we've modified it,
00572                 // if the user wants us to do this now.
00573                 if (IpplInfo::extraCompressChecks) {
00574                   ASSIGNMSG(msg << "Doing extra post-compute ");
00575                   ASSIGNMSG(msg << "compression check ..." << endl);
00576                   lf->TryCompress(bare.isDirty());
00577                 } else {
00578                   needFinalCompressCheck = true;
00579                 }
00580               }
00581             }
00582           else
00583             {
00584               ERRORMSG("All Fields in an expression must be aligned.  ");
00585               ERRORMSG("(Do you have enough guard cells?)" << endl);
00586               ERRORMSG("This error occurred while evaluating an expression ");
00587               ERRORMSG("for an LField with domain ");
00588               ERRORMSG((*la).second->getOwned() << endl);
00589               Ippl::abort();
00590             }
00591         }
00592       ++la;
00593     }
00594   TAU_PROFILE_STOP(looptimer);
00595 
00596   // Fill the guard cells on the left hand side, if we are deferring
00597   // this operation until the next time it is needed.
00598   ASSIGNMSG(msg << "Filling GC's at end if necessary ..." << endl);
00599   if (fillGC) {
00600     TAU_PROFILE_START(filltimer);
00601     bare.fillGuardCellsIfNotDirty();
00602     TAU_PROFILE_STOP(filltimer);
00603   }
00604 
00605   // Compress the LHS.
00606   if (fillGC && needFinalCompressCheck) {
00607     ASSIGNMSG(msg << "Trying to compress BareField at end ..." << endl);
00608     bare.Compress();
00609   }
00610 
00611   //INCIPPLSTAT(incExpressions);
00612   //INCIPPLSTAT(incParensEqualsExpression);
00613 }
00614 
00615 
00617 //
00618 // BareField = expression assignment.
00619 //
00620 // This is the specialization with ExprTag<true>, meaning the RHS
00621 // is an expression, not just a simple BareField.  This version
00622 // only works if the LHS and RHS terms all agree in their parallel
00623 // layout within guard-cell tolerances.  If they do not, it is
00624 // an error and IPPL will report it and die.
00625 // Since this is for BareField, the entire domain of the LHS is
00626 // used to index the RHS.  The RHS terms cannot be IndexedBareFields,
00627 // they must be BareFields as well (or other simpler items).
00628 //
00630 
00631 template<class T1, unsigned Dim, class RHS, class OP>
00632 void
00633 assign(const BareField<T1,Dim>& ca, RHS b, OP op, ExprTag<true>)
00634 {
00635   // profiling macros
00636   // here, 'Op' is not used to form the type string, so the timings here
00637   // will be the sum of all different operators 'Op' used in the code.
00638   TAU_TYPE_STRING(p1, "void (" + CT(ca) + ", " + CT(b) + ", " +
00639                   CT(op) + ", ExprTag<true> )" );
00640   TAU_PROFILE("assign()", p1.data(), TAU_ASSIGN | TAU_FIELD);
00641   TAU_PROFILE_TIMER(looptimer, " assign[BareField]-vnodeloop", p1.data(),
00642                     TAU_ASSIGN);
00643   TAU_PROFILE_TIMER(filltimer, " assign[BareField]-guardfill", p1.data(),
00644                     TAU_ASSIGN);
00645 
00646   // debugging output macros.  these are only enabled if DEBUG_ASSIGN is
00647   // defined.
00648   ASSIGNMSG(Inform msg("assign BF(t)", INFORM_ALL_NODES));
00649   ASSIGNMSG(msg << "Computing assignment to BF[" << ca.getDomain());
00650   ASSIGNMSG(msg << "] ..." << endl);
00651 
00652   // cast away const here for lhs ... unfortunate but necessary.
00653   // Also get the item wrapped within the PETE expression.
00654   BareField<T1,Dim>& a = const_cast<BareField<T1,Dim>&>(ca);
00655   typename RHS::Wrapped& bb = b.PETE_unwrap();
00656 
00657   // Create iterators over the LHS's LFields.
00658   typedef typename LField<T1,Dim>::iterator It;
00659   typedef BrickExpression<Dim,It,typename RHS::Wrapped,OP> ExprT;
00660   typename BareField<T1,Dim>::iterator_if la = a.begin_if();
00661   typename BareField<T1,Dim>::iterator_if aend = a.end_if();
00662 
00663   // Set the dirty flag indicating this field should have guard cells
00664   // filled next time if we are doing deferred GC fills.
00665   // We need to set this here so that our compression checks on each
00666   // LField take the dirty flag setting into account.
00667   a.setDirtyFlag();
00668 
00669   // Loop over the LHS LFields, and assign from RHS LFields
00670   TAU_PROFILE_START(looptimer);
00671   int lfcount = 0;
00672   bool needFinalCompressCheck = false;
00673   while (la != aend)
00674   {
00675     // Get the current LHS and set up the RHS to point to the beginning
00676     // of its current LField.  This second step is done in lieu of doing
00677     // a "plugbase", since it is faster and we know we're dealing with
00678     // a whole BareField here, not an indexed BareField.
00679     LField<T1,Dim>& lf = *(*la).second;
00680     for_each(bb, BeginLField(), PETE_NullCombiner());
00681 
00682     ASSIGNMSG(msg << "For lf " << lfcount << " with domain ");
00683     ASSIGNMSG(msg << lf.getOwned() << " : ");
00684 
00685     // Check to see if we can compress here.  If so, we can avoid a lot
00686     // of work.
00687     if (a.compressible() && TryCompressLHS(lf, bb, op, a.getDomain())) {
00688       ASSIGNMSG(msg << "compressed assign, changing " << *lf.begin());
00689       PETE_apply(op,*lf.begin(),for_each(bb,EvalFunctor_0()));
00690       ASSIGNMSG(msg << " to " << *lf.begin() << endl);
00691     } else {
00692       ASSIGNMSG(msg << "loop assign." << endl);
00693 
00694       // Create the expression object.
00695       ExprT expr(lf.begin(),bb,op);
00696       expr.apply();
00697 
00698       // Try to compress this LField since we did an uncompressed
00699       // assignment, if the user has requested this kind of
00700       // check right after computation on the LField.  If this kind
00701       // of request has not been made, then we'll need to do a compression
00702       // check at the end.
00703       if (IpplInfo::extraCompressChecks) {
00704         ASSIGNMSG(msg << "For lf " << lfcount);
00705         ASSIGNMSG(msg << ": doing extra post-compute ");
00706         ASSIGNMSG(msg << "compression check ..." << endl);
00707         lf.TryCompress(a.isDirty());
00708       } else {
00709         needFinalCompressCheck = true;
00710       }
00711     }
00712 
00713     ++la;
00714     for_each(bb,NextLField(),PETE_NullCombiner());
00715     ++lfcount;
00716   }
00717   TAU_PROFILE_STOP(looptimer);
00718 
00719   // Fill the guard cells on the left hand side, if we are deferring
00720   // this operation until the next time it is needed.
00721   ASSIGNMSG(msg << "Filling GC's at end if necessary ..." << endl);
00722   TAU_PROFILE_START(filltimer);
00723   a.fillGuardCellsIfNotDirty();
00724   TAU_PROFILE_STOP(filltimer);
00725 
00726   // Compress the LHS, if necessary
00727   if (needFinalCompressCheck) {
00728     ASSIGNMSG(msg << "Trying to compress BareField at end ..." << endl);
00729     a.Compress();
00730   }
00731 
00732   // Compress the LHS.
00733   //INCIPPLSTAT(incExpressions);
00734   //INCIPPLSTAT(incBFEqualsExpression);
00735 }
00736 
00737 
00738 /***************************************************************************
00739  * $RCSfile: Assign.cpp,v $   $Author: adelmann $
00740  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:26 $
00741  * IPPL_VERSION_ID: $Id: Assign.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $ 
00742  ***************************************************************************/

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