/[escript]/trunk/ripley/src/Rectangle.cpp
ViewVC logotype

Diff of /trunk/ripley/src/Rectangle.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

branches/ripleygmg_from_3668/ripley/src/Rectangle.cpp revision 3752 by caltinay, Tue Jan 3 08:06:36 2012 UTC trunk/ripley/src/Rectangle.cpp revision 4013 by caltinay, Thu Oct 4 03:13:27 2012 UTC
# Line 1  Line 1 
1    
2  /*******************************************************  /*****************************************************************************
3  *  *
4  * Copyright (c) 2003-2011 by University of Queensland  * Copyright (c) 2003-2012 by University of Queensland
5  * Earth Systems Science Computational Center (ESSCC)  * http://www.uq.edu.au
 * http://www.uq.edu.au/esscc  
6  *  *
7  * Primary Business: Queensland, Australia  * Primary Business: Queensland, Australia
8  * Licensed under the Open Software License version 3.0  * Licensed under the Open Software License version 3.0
9  * http://www.opensource.org/licenses/osl-3.0.php  * http://www.opensource.org/licenses/osl-3.0.php
10  *  *
11  *******************************************************/  * Development until 2012 by Earth Systems Science Computational Center (ESSCC)
12    * Development since 2012 by School of Earth Sciences
13    *
14    *****************************************************************************/
15    
16  #include <ripley/Rectangle.h>  #include <ripley/Rectangle.h>
17  extern "C" {  extern "C" {
18  #include "paso/SystemMatrix.h"  #include <paso/SystemMatrix.h>
19  }  }
20    
21    #ifdef USE_NETCDF
22    #include <netcdfcpp.h>
23    #endif
24    
25  #if USE_SILO  #if USE_SILO
26  #include <silo.h>  #include <silo.h>
27  #ifdef ESYS_MPI  #ifdef ESYS_MPI
# Line 29  using namespace std; Line 35  using namespace std;
35    
36  namespace ripley {  namespace ripley {
37    
38  Rectangle::Rectangle(int n0, int n1, double l0, double l1, int d0, int d1) :  Rectangle::Rectangle(int n0, int n1, double x0, double y0, double x1,
39                         double y1, int d0, int d1) :
40      RipleyDomain(2),      RipleyDomain(2),
41      m_gNE0(n0),      m_x0(x0),
42      m_gNE1(n1),      m_y0(y0),
43      m_l0(l0),      m_l0(x1-x0),
44      m_l1(l1),      m_l1(y1-y0)
     m_NX(d0),  
     m_NY(d1)  
45  {  {
46        // ignore subdivision parameters for serial run
47        if (m_mpiInfo->size == 1) {
48            d0=1;
49            d1=1;
50        }
51    
52        bool warn=false;
53        // if number of subdivisions is non-positive, try to subdivide by the same
54        // ratio as the number of elements
55        if (d0<=0 && d1<=0) {
56            warn=true;
57            d0=max(1, (int)(sqrt(m_mpiInfo->size*(n0+1)/(float)(n1+1))));
58            d1=m_mpiInfo->size/d0;
59            if (d0*d1 != m_mpiInfo->size) {
60                // ratios not the same so subdivide side with more elements only
61                if (n0>n1) {
62                    d0=0;
63                    d1=1;
64                } else {
65                    d0=1;
66                    d1=0;
67                }
68            }
69        }
70        if (d0<=0) {
71            // d1 is preset, determine d0 - throw further down if result is no good
72            d0=m_mpiInfo->size/d1;
73        } else if (d1<=0) {
74            // d0 is preset, determine d1 - throw further down if result is no good
75            d1=m_mpiInfo->size/d0;
76        }
77    
78        m_NX=d0;
79        m_NY=d1;
80    
81      // ensure number of subdivisions is valid and nodes can be distributed      // ensure number of subdivisions is valid and nodes can be distributed
82      // among number of ranks      // among number of ranks
83      if (m_NX*m_NY != m_mpiInfo->size)      if (m_NX*m_NY != m_mpiInfo->size)
84          throw RipleyException("Invalid number of spatial subdivisions");          throw RipleyException("Invalid number of spatial subdivisions");
85    
86      if ((n0+1)%m_NX > 0 || (n1+1)%m_NY > 0)      if (warn) {
87          throw RipleyException("Number of elements+1 must be separable into number of ranks in each dimension");          cout << "Warning: Automatic domain subdivision (d0=" << d0 << ", d1="
88                << d1 << "). This may not be optimal!" << endl;
89        }
90    
91        if ((n0+1)%m_NX > 0) {
92            double Dx=m_l0/n0;
93            n0=(int)round((float)(n0+1)/d0+0.5)*d0-1;
94            m_l0=Dx*n0;
95            cout << "Warning: Adjusted number of elements and length. N0="
96                << n0 << ", l0=" << m_l0 << endl;
97        }
98        if ((n1+1)%m_NY > 0) {
99            double Dy=m_l1/n1;
100            n1=(int)round((float)(n1+1)/d1+0.5)*d1-1;
101            m_l1=Dy*n1;
102            cout << "Warning: Adjusted number of elements and length. N1="
103                << n1 << ", l1=" << m_l1 << endl;
104        }
105    
106        m_gNE0=n0;
107        m_gNE1=n1;
108    
109      if ((m_NX > 1 && (n0+1)/m_NX<2) || (m_NY > 1 && (n1+1)/m_NY<2))      if ((m_NX > 1 && (n0+1)/m_NX<2) || (m_NY > 1 && (n1+1)/m_NY<2))
110          throw RipleyException("Too few elements for the number of ranks");          throw RipleyException("Too few elements for the number of ranks");
111    
112      // local number of elements (including overlap)      // local number of elements (with and without overlap)
113      m_NE0 = (m_NX>1 ? (n0+1)/m_NX : n0);      m_NE0 = m_ownNE0 = (m_NX>1 ? (n0+1)/m_NX : n0);
114      if (m_mpiInfo->rank%m_NX>0 && m_mpiInfo->rank%m_NX<m_NX-1)      if (m_mpiInfo->rank%m_NX>0 && m_mpiInfo->rank%m_NX<m_NX-1)
115          m_NE0++;          m_NE0++;
116      m_NE1 = (m_NY>1 ? (n1+1)/m_NY : n1);      else if (m_NX>1 && m_mpiInfo->rank%m_NX==m_NX-1)
117            m_ownNE0--;
118    
119        m_NE1 = m_ownNE1 = (m_NY>1 ? (n1+1)/m_NY : n1);
120      if (m_mpiInfo->rank/m_NX>0 && m_mpiInfo->rank/m_NX<m_NY-1)      if (m_mpiInfo->rank/m_NX>0 && m_mpiInfo->rank/m_NX<m_NY-1)
121          m_NE1++;          m_NE1++;
122        else if (m_NY>1 && m_mpiInfo->rank/m_NX==m_NY-1)
123            m_ownNE1--;
124    
125      // local number of nodes      // local number of nodes
126      m_N0 = m_NE0+1;      m_N0 = m_NE0+1;
# Line 63  Rectangle::Rectangle(int n0, int n1, dou Line 128  Rectangle::Rectangle(int n0, int n1, dou
128    
129      // bottom-left node is at (offset0,offset1) in global mesh      // bottom-left node is at (offset0,offset1) in global mesh
130      m_offset0 = (n0+1)/m_NX*(m_mpiInfo->rank%m_NX);      m_offset0 = (n0+1)/m_NX*(m_mpiInfo->rank%m_NX);
131      if (m_mpiInfo->rank%m_NX>0)      if (m_offset0 > 0)
132          m_offset0--;          m_offset0--;
133      m_offset1 = (n1+1)/m_NY*(m_mpiInfo->rank/m_NX);      m_offset1 = (n1+1)/m_NY*(m_mpiInfo->rank/m_NX);
134      if (m_mpiInfo->rank/m_NX>0)      if (m_offset1 > 0)
135          m_offset1--;          m_offset1--;
136    
137      populateSampleIds();      populateSampleIds();
138        createPattern();
139  }  }
140    
141  Rectangle::~Rectangle()  Rectangle::~Rectangle()
142  {  {
143        Paso_SystemMatrixPattern_free(m_pattern);
144        Paso_Connector_free(m_connector);
145  }  }
146    
147  string Rectangle::getDescription() const  string Rectangle::getDescription() const
# Line 87  bool Rectangle::operator==(const Abstrac Line 155  bool Rectangle::operator==(const Abstrac
155      if (o) {      if (o) {
156          return (RipleyDomain::operator==(other) &&          return (RipleyDomain::operator==(other) &&
157                  m_gNE0==o->m_gNE0 && m_gNE1==o->m_gNE1                  m_gNE0==o->m_gNE0 && m_gNE1==o->m_gNE1
158                    && m_x0==o->m_x0 && m_y0==o->m_y0
159                  && m_l0==o->m_l0 && m_l1==o->m_l1                  && m_l0==o->m_l0 && m_l1==o->m_l1
160                  && m_NX==o->m_NX && m_NY==o->m_NY);                  && m_NX==o->m_NX && m_NY==o->m_NY);
161      }      }
# Line 94  bool Rectangle::operator==(const Abstrac Line 163  bool Rectangle::operator==(const Abstrac
163      return false;      return false;
164  }  }
165    
166    void Rectangle::readNcGrid(escript::Data& out, string filename, string varname,
167                const vector<int>& first, const vector<int>& numValues) const
168    {
169    #ifdef USE_NETCDF
170        // check destination function space
171        int myN0, myN1;
172        if (out.getFunctionSpace().getTypeCode() == Nodes) {
173            myN0 = m_N0;
174            myN1 = m_N1;
175        } else if (out.getFunctionSpace().getTypeCode() == Elements ||
176                    out.getFunctionSpace().getTypeCode() == ReducedElements) {
177            myN0 = m_NE0;
178            myN1 = m_NE1;
179        } else
180            throw RipleyException("readNcGrid(): invalid function space for output data object");
181    
182        if (first.size() != 2)
183            throw RipleyException("readNcGrid(): argument 'first' must have 2 entries");
184    
185        if (numValues.size() != 2)
186            throw RipleyException("readNcGrid(): argument 'numValues' must have 2 entries");
187    
188        // check file existence and size
189        NcFile f(filename.c_str(), NcFile::ReadOnly);
190        if (!f.is_valid())
191            throw RipleyException("readNcGrid(): cannot open file");
192    
193        NcVar* var = f.get_var(varname.c_str());
194        if (!var)
195            throw RipleyException("readNcGrid(): invalid variable");
196    
197        // TODO: rank>0 data support
198        const int numComp = out.getDataPointSize();
199        if (numComp > 1)
200            throw RipleyException("readNcGrid(): only scalar data supported");
201    
202        const int dims = var->num_dims();
203        const long *edges = var->edges();
204    
205        // is this a slice of the data object (dims!=2)?
206        // note the expected ordering of edges (as in numpy: y,x)
207        if ( (dims==2 && (numValues[1] > edges[0] || numValues[0] > edges[1]))
208                || (dims==1 && numValues[1]>1) ) {
209            throw RipleyException("readNcGrid(): not enough data in file");
210        }
211    
212        // check if this rank contributes anything
213        if (first[0] >= m_offset0+myN0 || first[0]+numValues[0] <= m_offset0 ||
214                first[1] >= m_offset1+myN1 || first[1]+numValues[1] <= m_offset1)
215            return;
216    
217        // now determine how much this rank has to write
218    
219        // first coordinates in data object to write to
220        const int first0 = max(0, first[0]-m_offset0);
221        const int first1 = max(0, first[1]-m_offset1);
222        // indices to first value in file
223        const int idx0 = max(0, m_offset0-first[0]);
224        const int idx1 = max(0, m_offset1-first[1]);
225        // number of values to write
226        const int num0 = min(numValues[0]-idx0, myN0-first0);
227        const int num1 = min(numValues[1]-idx1, myN1-first1);
228    
229        vector<double> values(num0*num1);
230        if (dims==2) {
231            var->set_cur(idx1, idx0);
232            var->get(&values[0], num1, num0);
233        } else {
234            var->set_cur(idx0);
235            var->get(&values[0], num0);
236        }
237    
238        const int dpp = out.getNumDataPointsPerSample();
239        out.requireWrite();
240    
241        for (index_t y=0; y<num1; y++) {
242    #pragma omp parallel for
243            for (index_t x=0; x<num0; x++) {
244                const int dataIndex = (first1+y)*myN0+first0+x;
245                const int srcIndex=y*num0+x;
246                double* dest = out.getSampleDataRW(dataIndex);
247                for (index_t q=0; q<dpp; q++) {
248                    *dest++ = values[srcIndex];
249                }
250            }
251        }
252    #else
253        throw RipleyException("readNcGrid(): not compiled with netCDF support");
254    #endif
255    }
256    
257    void Rectangle::readBinaryGrid(escript::Data& out, string filename,
258                const vector<int>& first, const vector<int>& numValues) const
259    {
260        // check destination function space
261        int myN0, myN1;
262        if (out.getFunctionSpace().getTypeCode() == Nodes) {
263            myN0 = m_N0;
264            myN1 = m_N1;
265        } else if (out.getFunctionSpace().getTypeCode() == Elements ||
266                    out.getFunctionSpace().getTypeCode() == ReducedElements) {
267            myN0 = m_NE0;
268            myN1 = m_NE1;
269        } else
270            throw RipleyException("readBinaryGrid(): invalid function space for output data object");
271    
272        // check file existence and size
273        ifstream f(filename.c_str(), ifstream::binary);
274        if (f.fail()) {
275            throw RipleyException("readBinaryGrid(): cannot open file");
276        }
277        f.seekg(0, ios::end);
278        const int numComp = out.getDataPointSize();
279        const int filesize = f.tellg();
280        const int reqsize = numValues[0]*numValues[1]*numComp*sizeof(float);
281        if (filesize < reqsize) {
282            f.close();
283            throw RipleyException("readBinaryGrid(): not enough data in file");
284        }
285    
286        // check if this rank contributes anything
287        if (first[0] >= m_offset0+myN0 || first[0]+numValues[0] <= m_offset0 ||
288                first[1] >= m_offset1+myN1 || first[1]+numValues[1] <= m_offset1) {
289            f.close();
290            return;
291        }
292    
293        // now determine how much this rank has to write
294    
295        // first coordinates in data object to write to
296        const int first0 = max(0, first[0]-m_offset0);
297        const int first1 = max(0, first[1]-m_offset1);
298        // indices to first value in file
299        const int idx0 = max(0, m_offset0-first[0]);
300        const int idx1 = max(0, m_offset1-first[1]);
301        // number of values to write
302        const int num0 = min(numValues[0]-idx0, myN0-first0);
303        const int num1 = min(numValues[1]-idx1, myN1-first1);
304    
305        out.requireWrite();
306        vector<float> values(num0*numComp);
307        const int dpp = out.getNumDataPointsPerSample();
308    
309        for (index_t y=0; y<num1; y++) {
310            const int fileofs = numComp*(idx0+(idx1+y)*numValues[0]);
311            f.seekg(fileofs*sizeof(float));
312            f.read((char*)&values[0], num0*numComp*sizeof(float));
313            for (index_t x=0; x<num0; x++) {
314                double* dest = out.getSampleDataRW(first0+x+(first1+y)*myN0);
315                for (index_t c=0; c<numComp; c++) {
316                    for (index_t q=0; q<dpp; q++) {
317                        *dest++ = static_cast<double>(values[x*numComp+c]);
318                    }
319                }
320            }
321        }
322    
323        f.close();
324    }
325    
326  void Rectangle::dump(const string& fileName) const  void Rectangle::dump(const string& fileName) const
327  {  {
328  #if USE_SILO  #if USE_SILO
# Line 102  void Rectangle::dump(const string& fileN Line 331  void Rectangle::dump(const string& fileN
331          fn+=".silo";          fn+=".silo";
332      }      }
333    
     const int NUM_SILO_FILES = 1;  
     const char* blockDirFmt = "/block%04d";  
334      int driver=DB_HDF5;          int driver=DB_HDF5;    
     string siloPath;  
335      DBfile* dbfile = NULL;      DBfile* dbfile = NULL;
336        const char* blockDirFmt = "/block%04d";
337    
338  #ifdef ESYS_MPI  #ifdef ESYS_MPI
339      PMPIO_baton_t* baton = NULL;      PMPIO_baton_t* baton = NULL;
340        const int NUM_SILO_FILES = 1;
341  #endif  #endif
342    
343      if (m_mpiInfo->size > 1) {      if (m_mpiInfo->size > 1) {
# Line 125  void Rectangle::dump(const string& fileN Line 353  void Rectangle::dump(const string& fileN
353                          PMPIO_DefaultClose, (void*)&driver);                          PMPIO_DefaultClose, (void*)&driver);
354          }          }
355          if (baton) {          if (baton) {
356              char str[64];              char siloPath[64];
357              snprintf(str, 64, blockDirFmt, PMPIO_RankInGroup(baton, m_mpiInfo->rank));              snprintf(siloPath, 64, blockDirFmt, PMPIO_RankInGroup(baton, m_mpiInfo->rank));
358              siloPath = str;              dbfile = (DBfile*) PMPIO_WaitForBaton(baton, fn.c_str(), siloPath);
             dbfile = (DBfile*) PMPIO_WaitForBaton(baton, fn.c_str(), siloPath.c_str());  
359          }          }
360  #endif  #endif
361      } else {      } else {
# Line 140  void Rectangle::dump(const string& fileN Line 367  void Rectangle::dump(const string& fileN
367              dbfile = DBCreate(fn.c_str(), DB_CLOBBER, DB_LOCAL,              dbfile = DBCreate(fn.c_str(), DB_CLOBBER, DB_LOCAL,
368                      getDescription().c_str(), driver);                      getDescription().c_str(), driver);
369          }          }
370            char siloPath[64];
371            snprintf(siloPath, 64, blockDirFmt, 0);
372            DBMkDir(dbfile, siloPath);
373            DBSetDir(dbfile, siloPath);
374      }      }
375    
376      if (!dbfile)      if (!dbfile)
# Line 232  void Rectangle::dump(const string& fileN Line 463  void Rectangle::dump(const string& fileN
463      }      }
464    
465  #else // USE_SILO  #else // USE_SILO
466      throw RipleyException("dump(): no Silo support");      throw RipleyException("dump: no Silo support");
467  #endif  #endif
468  }  }
469    
# Line 240  const int* Rectangle::borrowSampleRefere Line 471  const int* Rectangle::borrowSampleRefere
471  {  {
472      switch (fsType) {      switch (fsType) {
473          case Nodes:          case Nodes:
474          case ReducedNodes: //FIXME: reduced          case ReducedNodes: // FIXME: reduced
475              return &m_nodeId[0];              return &m_nodeId[0];
476          case DegreesOfFreedom:          case DegreesOfFreedom:
477          case ReducedDegreesOfFreedom: //FIXME: reduced          case ReducedDegreesOfFreedom: // FIXME: reduced
478              return &m_dofId[0];              return &m_dofId[0];
479          case Elements:          case Elements:
480          case ReducedElements:          case ReducedElements:
# Line 256  const int* Rectangle::borrowSampleRefere Line 487  const int* Rectangle::borrowSampleRefere
487      }      }
488    
489      stringstream msg;      stringstream msg;
490      msg << "borrowSampleReferenceIDs() not implemented for function space type "      msg << "borrowSampleReferenceIDs: invalid function space type " << fsType;
         << functionSpaceTypeAsString(fsType);  
491      throw RipleyException(msg.str());      throw RipleyException(msg.str());
492  }  }
493    
494  bool Rectangle::ownSample(int fsCode, index_t id) const  bool Rectangle::ownSample(int fsType, index_t id) const
 {  
 #ifdef ESYS_MPI  
     if (fsCode == Nodes) {  
         const index_t left = (m_offset0==0 ? 0 : 1);  
         const index_t bottom = (m_offset1==0 ? 0 : 1);  
         const index_t right = (m_mpiInfo->rank%m_NX==m_NX-1 ? m_N0 : m_N0-1);  
         const index_t top = (m_mpiInfo->rank/m_NX==m_NY-1 ? m_N1 : m_N1-1);  
         const index_t x=id%m_N0;  
         const index_t y=id/m_N0;  
         return (x>=left && x<right && y>=bottom && y<top);  
     } else {  
         stringstream msg;  
         msg << "ownSample() not implemented for "  
             << functionSpaceTypeAsString(fsCode);  
         throw RipleyException(msg.str());  
     }  
 #else  
     return true;  
 #endif  
 }  
   
 void Rectangle::setToGradient(escript::Data& out, const escript::Data& cIn) const  
495  {  {
496      escript::Data& in = *const_cast<escript::Data*>(&cIn);      if (getMPISize()==1)
497      const dim_t numComp = in.getDataPointSize();          return true;
     const double h0 = m_l0/m_gNE0;  
     const double h1 = m_l1/m_gNE1;  
     const double cx0 = -1./h0;  
     const double cx1 = -.78867513459481288225/h0;  
     const double cx2 = -.5/h0;  
     const double cx3 = -.21132486540518711775/h0;  
     const double cx4 = .21132486540518711775/h0;  
     const double cx5 = .5/h0;  
     const double cx6 = .78867513459481288225/h0;  
     const double cx7 = 1./h0;  
     const double cy0 = -1./h1;  
     const double cy1 = -.78867513459481288225/h1;  
     const double cy2 = -.5/h1;  
     const double cy3 = -.21132486540518711775/h1;  
     const double cy4 = .21132486540518711775/h1;  
     const double cy5 = .5/h1;  
     const double cy6 = .78867513459481288225/h1;  
     const double cy7 = 1./h1;  
   
     if (out.getFunctionSpace().getTypeCode() == Elements) {  
         /*** GENERATOR SNIP_GRAD_ELEMENTS TOP */  
 #pragma omp parallel for  
         for (index_t k1=0; k1 < m_NE1; ++k1) {  
             for (index_t k0=0; k0 < m_NE0; ++k0) {  
                 const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,k1, m_N0));  
                 const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0));  
                 const register double* f_01 = in.getSampleDataRO(INDEX2(k0,k1+1, m_N0));  
                 const register double* f_00 = in.getSampleDataRO(INDEX2(k0,k1, m_N0));  
                 double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));  
                 for (index_t i=0; i < numComp; ++i) {  
                     o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;  
                     o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;  
                     o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;  
                     o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;  
                     o[INDEX3(i,0,2,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;  
                     o[INDEX3(i,1,2,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;  
                     o[INDEX3(i,0,3,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;  
                     o[INDEX3(i,1,3,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;  
                 } /* end of component loop i */  
             } /* end of k0 loop */  
         } /* end of k1 loop */  
         /* GENERATOR SNIP_GRAD_ELEMENTS BOTTOM */  
     } else if (out.getFunctionSpace().getTypeCode() == ReducedElements) {  
         /*** GENERATOR SNIP_GRAD_REDUCED_ELEMENTS TOP */  
 #pragma omp parallel for  
         for (index_t k1=0; k1 < m_NE1; ++k1) {  
             for (index_t k0=0; k0 < m_NE0; ++k0) {  
                 const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,k1, m_N0));  
                 const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0));  
                 const register double* f_01 = in.getSampleDataRO(INDEX2(k0,k1+1, m_N0));  
                 const register double* f_00 = in.getSampleDataRO(INDEX2(k0,k1, m_N0));  
                 double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));  
                 for (index_t i=0; i < numComp; ++i) {  
                     o[INDEX3(i,0,0,numComp,2)] = cx5*(f_10[i] + f_11[i]) + cx2*(f_00[i] + f_01[i]);  
                     o[INDEX3(i,1,0,numComp,2)] = cy2*(f_00[i] + f_10[i]) + cy5*(f_01[i] + f_11[i]);  
                 } /* end of component loop i */  
             } /* end of k0 loop */  
         } /* end of k1 loop */  
         /* GENERATOR SNIP_GRAD_REDUCED_ELEMENTS BOTTOM */  
     } else if (out.getFunctionSpace().getTypeCode() == FaceElements) {  
 #pragma omp parallel  
         {  
             /*** GENERATOR SNIP_GRAD_FACES TOP */  
             if (m_faceOffset[0] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1=0; k1 < m_NE1; ++k1) {  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(1,k1, m_N0));  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(1,k1+1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(0,k1+1, m_N0));  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(0,k1, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[0]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;  
                         o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy0 + f_01[i]*cy7;  
                         o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;  
                         o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy0 + f_01[i]*cy7;  
                     } /* end of component loop i */  
                 } /* end of k1 loop */  
             } /* end of face 0 */  
             if (m_faceOffset[1] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1=0; k1 < m_NE1; ++k1) {  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0));  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(m_N0-2,k1+1, m_N0));  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(m_N0-2,k1, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[1]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;  
                         o[INDEX3(i,1,0,numComp,2)] = f_10[i]*cy0 + f_11[i]*cy7;  
                         o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;  
                         o[INDEX3(i,1,1,numComp,2)] = f_10[i]*cy0 + f_11[i]*cy7;  
                     } /* end of component loop i */  
                 } /* end of k1 loop */  
             } /* end of face 1 */  
             if (m_faceOffset[2] > -1) {  
 #pragma omp for nowait  
                 for (index_t k0=0; k0 < m_NE0; ++k0) {  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(k0,0, m_N0));  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,0, m_N0));  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(k0,1, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[2]+k0);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx0 + f_10[i]*cx7;  
                         o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;  
                         o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx0 + f_10[i]*cx7;  
                         o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;  
                     } /* end of component loop i */  
                 } /* end of k0 loop */  
             } /* end of face 2 */  
             if (m_faceOffset[3] > -1) {  
 #pragma omp for nowait  
                 for (index_t k0=0; k0 < m_NE0; ++k0) {  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0));  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,m_N1-2, m_N0));  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(k0,m_N1-2, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[3]+k0);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = f_01[i]*cx0 + f_11[i]*cx7;  
                         o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;  
                         o[INDEX3(i,0,1,numComp,2)] = f_01[i]*cx0 + f_11[i]*cx7;  
                         o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;  
                     } /* end of component loop i */  
                 } /* end of k0 loop */  
             } /* end of face 3 */  
             /* GENERATOR SNIP_GRAD_FACES BOTTOM */  
         } // end of parallel section  
     } else if (out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {  
 #pragma omp parallel  
         {  
             /*** GENERATOR SNIP_GRAD_REDUCED_FACES TOP */  
             if (m_faceOffset[0] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1=0; k1 < m_NE1; ++k1) {  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(1,k1, m_N0));  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(1,k1+1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(0,k1+1, m_N0));  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(0,k1, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[0]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = cx5*(f_10[i] + f_11[i]) + cx2*(f_00[i] + f_01[i]);  
                         o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy0 + f_01[i]*cy7;  
                     } /* end of component loop i */  
                 } /* end of k1 loop */  
             } /* end of face 0 */  
             if (m_faceOffset[1] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1=0; k1 < m_NE1; ++k1) {  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0));  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(m_N0-2,k1+1, m_N0));  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(m_N0-2,k1, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[1]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = cx5*(f_10[i] + f_11[i]) + cx2*(f_00[i] + f_01[i]);  
                         o[INDEX3(i,1,0,numComp,2)] = f_10[i]*cy0 + f_11[i]*cy7;  
                     } /* end of component loop i */  
                 } /* end of k1 loop */  
             } /* end of face 1 */  
             if (m_faceOffset[2] > -1) {  
 #pragma omp for nowait  
                 for (index_t k0=0; k0 < m_NE0; ++k0) {  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(k0,0, m_N0));  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,0, m_N0));  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(k0,1, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[2]+k0);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx0 + f_10[i]*cx7;  
                         o[INDEX3(i,1,0,numComp,2)] = cy2*(f_00[i] + f_10[i]) + cy5*(f_01[i] + f_11[i]);  
                     } /* end of component loop i */  
                 } /* end of k0 loop */  
             } /* end of face 2 */  
             if (m_faceOffset[3] > -1) {  
 #pragma omp for nowait  
                 for (index_t k0=0; k0 < m_NE0; ++k0) {  
                     const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0));  
                     const register double* f_01 = in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0));  
                     const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,m_N1-2, m_N0));  
                     const register double* f_00 = in.getSampleDataRO(INDEX2(k0,m_N1-2, m_N0));  
                     double* o = out.getSampleDataRW(m_faceOffset[3]+k0);  
                     for (index_t i=0; i < numComp; ++i) {  
                         o[INDEX3(i,0,0,numComp,2)] = f_01[i]*cx0 + f_11[i]*cx7;  
                         o[INDEX3(i,1,0,numComp,2)] = cy5*(f_01[i] + f_11[i]) + cy2*(f_00[i] + f_10[i]);  
                     } /* end of component loop i */  
                 } /* end of k0 loop */  
             } /* end of face 3 */  
             /* GENERATOR SNIP_GRAD_REDUCED_FACES BOTTOM */  
         } // end of parallel section  
     } else {  
         stringstream msg;  
         msg << "setToGradient() not implemented for "  
             << functionSpaceTypeAsString(out.getFunctionSpace().getTypeCode());  
         throw RipleyException(msg.str());  
     }  
 }  
   
 void Rectangle::setToIntegrals(vector<double>& integrals, const escript::Data& arg) const  
 {  
     escript::Data& in = *const_cast<escript::Data*>(&arg);  
     const dim_t numComp = in.getDataPointSize();  
     const double h0 = m_l0/m_gNE0;  
     const double h1 = m_l1/m_gNE1;  
     if (arg.getFunctionSpace().getTypeCode() == Elements) {  
         const double w_0 = h0*h1/4.;  
 #pragma omp parallel  
         {  
             vector<double> int_local(numComp, 0);  
 #pragma omp for nowait  
             for (index_t k1 = 0; k1 < m_NE1; ++k1) {  
                 for (index_t k0 = 0; k0 < m_NE0; ++k0) {  
                     const double* f = in.getSampleDataRO(INDEX2(k0, k1, m_NE0));  
                     for (index_t i=0; i < numComp; ++i) {  
                         const register double f_0 = f[INDEX2(i,0,numComp)];  
                         const register double f_1 = f[INDEX2(i,1,numComp)];  
                         const register double f_2 = f[INDEX2(i,2,numComp)];  
                         const register double f_3 = f[INDEX2(i,3,numComp)];  
                         int_local[i]+=(f_0+f_1+f_2+f_3)*w_0;  
                     }  /* end of component loop i */  
                 } /* end of k0 loop */  
             } /* end of k1 loop */  
   
 #pragma omp critical  
             for (index_t i=0; i<numComp; i++)  
                 integrals[i]+=int_local[i];  
         } // end of parallel section  
     } else if (arg.getFunctionSpace().getTypeCode() == ReducedElements) {  
         const double w_0 = h0*h1;  
 #pragma omp parallel  
         {  
             vector<double> int_local(numComp, 0);  
 #pragma omp for nowait  
             for (index_t k1 = 0; k1 < m_NE1; ++k1) {  
                 for (index_t k0 = 0; k0 < m_NE0; ++k0) {  
                     const double* f = in.getSampleDataRO(INDEX2(k0, k1, m_NE0));  
                     for (index_t i=0; i < numComp; ++i) {  
                         int_local[i]+=f[i]*w_0;  
                     }  /* end of component loop i */  
                 } /* end of k0 loop */  
             } /* end of k1 loop */  
   
 #pragma omp critical  
             for (index_t i=0; i<numComp; i++)  
                 integrals[i]+=int_local[i];  
         } // end of parallel section  
     } else if (arg.getFunctionSpace().getTypeCode() == FaceElements) {  
         const double w_0 = h0/2.;  
         const double w_1 = h1/2.;  
 #pragma omp parallel  
         {  
             vector<double> int_local(numComp, 0);  
             if (m_faceOffset[0] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1 = 0; k1 < m_NE1; ++k1) {  
                     const double* f = in.getSampleDataRO(m_faceOffset[0]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         const register double f_0 = f[INDEX2(i,0,numComp)];  
                         const register double f_1 = f[INDEX2(i,1,numComp)];  
                         int_local[i]+=(f_0+f_1)*w_1;  
                     }  /* end of component loop i */  
                 } /* end of k1 loop */  
             }  
   
             if (m_faceOffset[1] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1 = 0; k1 < m_NE1; ++k1) {  
                     const double* f = in.getSampleDataRO(m_faceOffset[1]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         const register double f_0 = f[INDEX2(i,0,numComp)];  
                         const register double f_1 = f[INDEX2(i,1,numComp)];  
                         int_local[i]+=(f_0+f_1)*w_1;  
                     }  /* end of component loop i */  
                 } /* end of k1 loop */  
             }  
   
             if (m_faceOffset[2] > -1) {  
 #pragma omp for nowait  
                 for (index_t k0 = 0; k0 < m_NE0; ++k0) {  
                     const double* f = in.getSampleDataRO(m_faceOffset[2]+k0);  
                     for (index_t i=0; i < numComp; ++i) {  
                         const register double f_0 = f[INDEX2(i,0,numComp)];  
                         const register double f_1 = f[INDEX2(i,1,numComp)];  
                         int_local[i]+=(f_0+f_1)*w_0;  
                     }  /* end of component loop i */  
                 } /* end of k0 loop */  
             }  
   
             if (m_faceOffset[3] > -1) {  
 #pragma omp for nowait  
                 for (index_t k0 = 0; k0 < m_NE0; ++k0) {  
                     const double* f = in.getSampleDataRO(m_faceOffset[3]+k0);  
                     for (index_t i=0; i < numComp; ++i) {  
                         const register double f_0 = f[INDEX2(i,0,numComp)];  
                         const register double f_1 = f[INDEX2(i,1,numComp)];  
                         int_local[i]+=(f_0+f_1)*w_0;  
                     }  /* end of component loop i */  
                 } /* end of k0 loop */  
             }  
   
 #pragma omp critical  
             for (index_t i=0; i<numComp; i++)  
                 integrals[i]+=int_local[i];  
         } // end of parallel section  
     } else if (arg.getFunctionSpace().getTypeCode() == ReducedFaceElements) {  
 #pragma omp parallel  
         {  
             vector<double> int_local(numComp, 0);  
             if (m_faceOffset[0] > -1) {  
 #pragma omp for nowait  
                 for (index_t k1 = 0; k1 < m_NE1; ++k1) {  
                     const double* f = in.getSampleDataRO(m_faceOffset[0]+k1);  
                     for (index_t i=0; i < numComp; ++i) {  
                         int_local[i]+=f[i]*h1;  
                     }  /* end of component loop i */  
                 } /* end of k1 loop */  
             }  
498    
499              if (m_faceOffset[1] > -1) {      switch (fsType) {
500  #pragma omp for nowait          case Nodes:
501                  for (index_t k1 = 0; k1 < m_NE1; ++k1) {          case ReducedNodes: // FIXME: reduced
502                      const double* f = in.getSampleDataRO(m_faceOffset[1]+k1);              return (m_dofMap[id] < getNumDOF());
503                      for (index_t i=0; i < numComp; ++i) {          case DegreesOfFreedom:
504                          int_local[i]+=f[i]*h1;          case ReducedDegreesOfFreedom:
505                      }  /* end of component loop i */              return true;
506                  } /* end of k1 loop */          case Elements:
507              }          case ReducedElements:
508                // check ownership of element's bottom left node
509              if (m_faceOffset[2] > -1) {              return (m_dofMap[id%m_NE0+m_N0*(id/m_NE0)] < getNumDOF());
510  #pragma omp for nowait          case FaceElements:
511                  for (index_t k0 = 0; k0 < m_NE0; ++k0) {          case ReducedFaceElements:
512                      const double* f = in.getSampleDataRO(m_faceOffset[2]+k0);              {
513                      for (index_t i=0; i < numComp; ++i) {                  // determine which face the sample belongs to before
514                          int_local[i]+=f[i]*h0;                  // checking ownership of corresponding element's first node
515                      }  /* end of component loop i */                  const IndexVector faces = getNumFacesPerBoundary();
516                  } /* end of k0 loop */                  dim_t n=0;
517              }                  for (size_t i=0; i<faces.size(); i++) {
518                        n+=faces[i];
519              if (m_faceOffset[3] > -1) {                      if (id<n) {
520  #pragma omp for nowait                          index_t k;
521                  for (index_t k0 = 0; k0 < m_NE0; ++k0) {                          if (i==1)
522                      const double* f = in.getSampleDataRO(m_faceOffset[3]+k0);                              k=m_N0-2;
523                      for (index_t i=0; i < numComp; ++i) {                          else if (i==3)
524                          int_local[i]+=f[i]*h0;                              k=m_N0*(m_N1-2);
525                      }  /* end of component loop i */                          else
526                  } /* end of k0 loop */                              k=0;
527                            // determine whether to move right or up
528                            const index_t delta=(i/2==0 ? m_N0 : 1);
529                            return (m_dofMap[k+(id-n+faces[i])*delta] < getNumDOF());
530                        }
531                    }
532                    return false;
533              }              }
534            default:
535  #pragma omp critical              break;
             for (index_t i=0; i<numComp; i++)  
                 integrals[i]+=int_local[i];  
         } // end of parallel section  
     } else {  
         stringstream msg;  
         msg << "setToIntegrals() not implemented for "  
             << functionSpaceTypeAsString(arg.getFunctionSpace().getTypeCode());  
         throw RipleyException(msg.str());  
536      }      }
537    
538        stringstream msg;
539        msg << "ownSample: invalid function space type " << fsType;
540        throw RipleyException(msg.str());
541  }  }
542    
543  void Rectangle::setToNormal(escript::Data& out) const  void Rectangle::setToNormal(escript::Data& out) const
544  {  {
545      if (out.getFunctionSpace().getTypeCode() == FaceElements) {      if (out.getFunctionSpace().getTypeCode() == FaceElements) {
546            out.requireWrite();
547  #pragma omp parallel  #pragma omp parallel
548          {          {
549              if (m_faceOffset[0] > -1) {              if (m_faceOffset[0] > -1) {
# Line 702  void Rectangle::setToNormal(escript::Dat Line 595  void Rectangle::setToNormal(escript::Dat
595              }              }
596          } // end of parallel section          } // end of parallel section
597      } else if (out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {      } else if (out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {
598            out.requireWrite();
599  #pragma omp parallel  #pragma omp parallel
600          {          {
601              if (m_faceOffset[0] > -1) {              if (m_faceOffset[0] > -1) {
# Line 743  void Rectangle::setToNormal(escript::Dat Line 637  void Rectangle::setToNormal(escript::Dat
637    
638      } else {      } else {
639          stringstream msg;          stringstream msg;
640          msg << "setToNormal() not implemented for "          msg << "setToNormal: invalid function space type "
641              << functionSpaceTypeAsString(out.getFunctionSpace().getTypeCode());              << out.getFunctionSpace().getTypeCode();
642          throw RipleyException(msg.str());          throw RipleyException(msg.str());
643      }      }
644  }  }
645    
646  Paso_SystemMatrixPattern* Rectangle::getPattern(bool reducedRowOrder,  void Rectangle::setToSize(escript::Data& out) const
                                                 bool reducedColOrder) const  
647  {  {
648      if (reducedRowOrder || reducedColOrder)      if (out.getFunctionSpace().getTypeCode() == Elements
649          throw RipleyException("getPattern() not implemented for reduced order");              || out.getFunctionSpace().getTypeCode() == ReducedElements) {
650            out.requireWrite();
651      // connector          const dim_t numQuad=out.getNumDataPointsPerSample();
652      RankVector neighbour;          const double hSize=getFirstCoordAndSpacing(0).second;
653      IndexVector offsetInShared(1,0);          const double vSize=getFirstCoordAndSpacing(1).second;
654      IndexVector sendShared, recvShared;          const double size=sqrt(hSize*hSize+vSize*vSize);
     const IndexVector faces=getNumFacesPerBoundary();  
     const index_t nDOF0 = (m_gNE0+1)/m_NX;  
     const index_t nDOF1 = (m_gNE1+1)/m_NY;  
     const int numDOF=nDOF0*nDOF1;  
     const index_t left = (m_offset0==0 ? 0 : 1);  
     const index_t bottom = (m_offset1==0 ? 0 : 1);  
     vector<IndexVector> colIndices(numDOF); // for the couple blocks  
     int numShared=0;  
   
     m_dofMap.assign(getNumNodes(), 0);  
655  #pragma omp parallel for  #pragma omp parallel for
656      for (index_t i=bottom; i<m_N1; i++) {          for (index_t k = 0; k < getNumElements(); ++k) {
657          for (index_t j=left; j<m_N0; j++) {              double* o = out.getSampleDataRW(k);
658              m_dofMap[i*m_N0+j]=(i-bottom)*nDOF0+j-left;              fill(o, o+numQuad, size);
659          }          }
660      }      } else if (out.getFunctionSpace().getTypeCode() == FaceElements
661                || out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {
662      // corner node from bottom-left          out.requireWrite();
663      if (faces[0] == 0 && faces[2] == 0) {          const dim_t numQuad=out.getNumDataPointsPerSample();
664          neighbour.push_back(m_mpiInfo->rank-m_NX-1);          const double hSize=getFirstCoordAndSpacing(0).second;
665          offsetInShared.push_back(offsetInShared.back()+1);          const double vSize=getFirstCoordAndSpacing(1).second;
666          sendShared.push_back(0);  #pragma omp parallel
667          recvShared.push_back(numDOF+numShared);          {
668          colIndices[0].push_back(numShared);              if (m_faceOffset[0] > -1) {
669          m_dofMap[0]=numDOF+numShared;  #pragma omp for nowait
670          ++numShared;                  for (index_t k1 = 0; k1 < m_NE1; ++k1) {
671      }                      double* o = out.getSampleDataRW(m_faceOffset[0]+k1);
672      // bottom edge                      fill(o, o+numQuad, vSize);
673      if (faces[2] == 0) {                  }
674          neighbour.push_back(m_mpiInfo->rank-m_NX);              }
         offsetInShared.push_back(offsetInShared.back()+nDOF0);  
         for (dim_t i=0; i<nDOF0; i++, numShared++) {  
             sendShared.push_back(i);  
             recvShared.push_back(numDOF+numShared);  
             if (i>0)  
                 colIndices[i-1].push_back(numShared);  
             colIndices[i].push_back(numShared);  
             if (i<nDOF0-1)  
                 colIndices[i+1].push_back(numShared);  
             m_dofMap[i+left]=numDOF+numShared;  
         }  
     }  
     // corner node from bottom-right  
     if (faces[1] == 0 && faces[2] == 0) {  
         neighbour.push_back(m_mpiInfo->rank-m_NX+1);  
         offsetInShared.push_back(offsetInShared.back()+1);  
         sendShared.push_back(nDOF0-1);  
         recvShared.push_back(numDOF+numShared);  
         colIndices[nDOF0-2].push_back(numShared);  
         colIndices[nDOF0-1].push_back(numShared);  
         m_dofMap[m_N0-1]=numDOF+numShared;  
         ++numShared;  
     }  
     // right edge  
     if (faces[1] == 0) {  
         neighbour.push_back(m_mpiInfo->rank+1);  
         offsetInShared.push_back(offsetInShared.back()+nDOF1);  
         for (dim_t i=0; i<nDOF1; i++, numShared++) {  
             sendShared.push_back((i+1)*(nDOF0)-1);  
             recvShared.push_back(numDOF+numShared);  
             if (i>0)  
                 colIndices[i*(nDOF0)-1].push_back(numShared);  
             colIndices[(i+1)*(nDOF0)-1].push_back(numShared);  
             if (i<nDOF1-1)  
                 colIndices[(i+2)*(nDOF0)-1].push_back(numShared);  
             m_dofMap[(i+bottom+1)*m_N0-1]=numDOF+numShared;  
         }  
     }  
     // corner node from top-right  
     if (faces[1] == 0 && faces[3] == 0) {  
         neighbour.push_back(m_mpiInfo->rank+m_NX+1);  
         offsetInShared.push_back(offsetInShared.back()+1);  
         sendShared.push_back(numDOF-1);  
         recvShared.push_back(numDOF+numShared);  
         colIndices[numDOF-1].push_back(numShared);  
         m_dofMap[m_N0*m_N1-1]=numDOF+numShared;  
         ++numShared;  
     }  
     // top edge  
     if (faces[3] == 0) {  
         neighbour.push_back(m_mpiInfo->rank+m_NX);  
         offsetInShared.push_back(offsetInShared.back()+nDOF0);  
         for (dim_t i=0; i<nDOF0; i++, numShared++) {  
             sendShared.push_back(numDOF-nDOF0+i);  
             recvShared.push_back(numDOF+numShared);  
             if (i>0)  
                 colIndices[numDOF-nDOF0+i-1].push_back(numShared);  
             colIndices[numDOF-nDOF0+i].push_back(numShared);  
             if (i<nDOF0-1)  
                 colIndices[numDOF-nDOF0+i+1].push_back(numShared);  
             m_dofMap[m_N0*(m_N1-1)+i+left]=numDOF+numShared;  
         }  
     }  
     // corner node from top-left  
     if (faces[0] == 0 && faces[3] == 0) {  
         neighbour.push_back(m_mpiInfo->rank+m_NX-1);  
         offsetInShared.push_back(offsetInShared.back()+1);  
         sendShared.push_back(numDOF-nDOF0);  
         recvShared.push_back(numDOF+numShared);  
         colIndices[numDOF-nDOF0].push_back(numShared);  
         m_dofMap[m_N0*(m_N1-1)]=numDOF+numShared;  
         ++numShared;  
     }  
     // left edge  
     if (faces[0] == 0) {  
         neighbour.push_back(m_mpiInfo->rank-1);  
         offsetInShared.push_back(offsetInShared.back()+nDOF1);  
         for (dim_t i=0; i<nDOF1; i++, numShared++) {  
             sendShared.push_back(i*nDOF0);  
             recvShared.push_back(numDOF+numShared);  
             if (i>0)  
                 colIndices[(i-1)*nDOF0].push_back(numShared);  
             colIndices[i*nDOF0].push_back(numShared);  
             if (i<nDOF1-1)  
                 colIndices[(i+1)*nDOF0].push_back(numShared);  
             m_dofMap[(i+bottom)*m_N0]=numDOF+numShared;  
         }  
     }  
   
     /*  
     cout << "--- rcv_shcomp ---" << endl;  
     cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << endl;  
     for (size_t i=0; i<neighbour.size(); i++) {  
         cout << "neighbor[" << i << "]=" << neighbour[i]  
             << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << endl;  
     }  
     for (size_t i=0; i<recvShared.size(); i++) {  
         cout << "shared[" << i << "]=" << recvShared[i] << endl;  
     }  
     cout << "--- snd_shcomp ---" << endl;  
     for (size_t i=0; i<sendShared.size(); i++) {  
         cout << "shared[" << i << "]=" << sendShared[i] << endl;  
     }  
     */  
   
     Paso_SharedComponents *snd_shcomp = Paso_SharedComponents_alloc(  
             numDOF, neighbour.size(), &neighbour[0], &sendShared[0],  
             &offsetInShared[0], 1, 0, m_mpiInfo);  
     Paso_SharedComponents *rcv_shcomp = Paso_SharedComponents_alloc(  
             numDOF, neighbour.size(), &neighbour[0], &recvShared[0],  
             &offsetInShared[0], 1, 0, m_mpiInfo);  
     Paso_Connector* connector = Paso_Connector_alloc(snd_shcomp, rcv_shcomp);  
     Paso_SharedComponents_free(snd_shcomp);  
     Paso_SharedComponents_free(rcv_shcomp);  
   
     // create patterns  
     dim_t M, N;  
     IndexVector ptr(1,0);  
     IndexVector index;  
   
     // main pattern  
     for (index_t i=0; i<numDOF; i++) {  
         // always add the node itself  
         index.push_back(i);  
         const int num=insertNeighbours(index, i);  
         ptr.push_back(ptr.back()+num+1);  
     }  
     M=N=ptr.size()-1;  
     // paso will manage the memory  
     index_t* indexC = MEMALLOC(index.size(),index_t);  
     index_t* ptrC = MEMALLOC(ptr.size(), index_t);  
     copy(index.begin(), index.end(), indexC);  
     copy(ptr.begin(), ptr.end(), ptrC);  
     Paso_Pattern *mainPattern = Paso_Pattern_alloc(MATRIX_FORMAT_DEFAULT,  
             M, N, ptrC, indexC);  
   
     /*  
     cout << "--- main_pattern ---" << endl;  
     cout << "M=" << M << ", N=" << N << endl;  
     for (size_t i=0; i<ptr.size(); i++) {  
         cout << "ptr[" << i << "]=" << ptr[i] << endl;  
     }  
     for (size_t i=0; i<index.size(); i++) {  
         cout << "index[" << i << "]=" << index[i] << endl;  
     }  
     */  
675    
676      // column & row couple patterns              if (m_faceOffset[1] > -1) {
677      ptr.assign(1, 0);  #pragma omp for nowait
678      index.clear();                  for (index_t k1 = 0; k1 < m_NE1; ++k1) {
679                        double* o = out.getSampleDataRW(m_faceOffset[1]+k1);
680      for (index_t i=0; i<numDOF; i++) {                      fill(o, o+numQuad, vSize);
681          index.insert(index.end(), colIndices[i].begin(), colIndices[i].end());                  }
682          ptr.push_back(ptr.back()+colIndices[i].size());              }
     }  
   
     // paso will manage the memory  
     indexC = MEMALLOC(index.size(), index_t);  
     ptrC = MEMALLOC(ptr.size(), index_t);  
     copy(index.begin(), index.end(), indexC);  
     copy(ptr.begin(), ptr.end(), ptrC);  
     M=ptr.size()-1;  
     N=numShared;  
     Paso_Pattern *colCouplePattern=Paso_Pattern_alloc(MATRIX_FORMAT_DEFAULT,  
             M, N, ptrC, indexC);  
683    
684      /*              if (m_faceOffset[2] > -1) {
685      cout << "--- colCouple_pattern ---" << endl;  #pragma omp for nowait
686      cout << "M=" << M << ", N=" << N << endl;                  for (index_t k0 = 0; k0 < m_NE0; ++k0) {
687      for (size_t i=0; i<ptr.size(); i++) {                      double* o = out.getSampleDataRW(m_faceOffset[2]+k0);
688          cout << "ptr[" << i << "]=" << ptr[i] << endl;                      fill(o, o+numQuad, hSize);
689      }                  }
690      for (size_t i=0; i<index.size(); i++) {              }
         cout << "index[" << i << "]=" << index[i] << endl;  
     }  
     */  
691    
692      // now build the row couple pattern              if (m_faceOffset[3] > -1) {
693      IndexVector ptr2(1,0);  #pragma omp for nowait
694      IndexVector index2;                  for (index_t k0 = 0; k0 < m_NE0; ++k0) {
695      for (dim_t id=0; id<N; id++) {                      double* o = out.getSampleDataRW(m_faceOffset[3]+k0);
696          dim_t n=0;                      fill(o, o+numQuad, hSize);
         for (dim_t i=0; i<M; i++) {  
             for (dim_t j=ptr[i]; j<ptr[i+1]; j++) {  
                 if (index[j]==id) {  
                     index2.push_back(i);  
                     n++;  
                     break;  
697                  }                  }
698              }              }
699          }          } // end of parallel section
         ptr2.push_back(ptr2.back()+n);  
     }  
   
     // paso will manage the memory  
     indexC = MEMALLOC(index2.size(), index_t);  
     ptrC = MEMALLOC(ptr2.size(), index_t);  
     copy(index2.begin(), index2.end(), indexC);  
     copy(ptr2.begin(), ptr2.end(), ptrC);  
     Paso_Pattern *rowCouplePattern=Paso_Pattern_alloc(MATRIX_FORMAT_DEFAULT,  
             N, M, ptrC, indexC);  
700    
701      /*      } else {
702      cout << "--- rowCouple_pattern ---" << endl;          stringstream msg;
703      cout << "M=" << N << ", N=" << M << endl;          msg << "setToSize: invalid function space type "
704      for (size_t i=0; i<ptr2.size(); i++) {              << out.getFunctionSpace().getTypeCode();
705          cout << "ptr[" << i << "]=" << ptr2[i] << endl;          throw RipleyException(msg.str());
     }  
     for (size_t i=0; i<index2.size(); i++) {  
         cout << "index[" << i << "]=" << index2[i] << endl;  
706      }      }
707      */  }
   
     // allocate paso distribution  
     Paso_Distribution* distribution = Paso_Distribution_alloc(m_mpiInfo,  
             const_cast<index_t*>(&m_nodeDistribution[0]), 1, 0);  
708    
709      Paso_SystemMatrixPattern* pattern = Paso_SystemMatrixPattern_alloc(  Paso_SystemMatrixPattern* Rectangle::getPattern(bool reducedRowOrder,
710              MATRIX_FORMAT_DEFAULT, distribution, distribution,                                                  bool reducedColOrder) const
711              mainPattern, colCouplePattern, rowCouplePattern,  {
712              connector, connector);      /* FIXME: reduced
713      Paso_Pattern_free(mainPattern);      if (reducedRowOrder || reducedColOrder)
714      Paso_Pattern_free(colCouplePattern);          throw RipleyException("getPattern() not implemented for reduced order");
715      Paso_Pattern_free(rowCouplePattern);      */
716      Paso_Distribution_free(distribution);      return m_pattern;
     return pattern;  
717  }  }
718    
719  void Rectangle::Print_Mesh_Info(const bool full) const  void Rectangle::Print_Mesh_Info(const bool full) const
# Line 1068  IndexVector Rectangle::getNumFacesPerBou Line 767  IndexVector Rectangle::getNumFacesPerBou
767      return ret;      return ret;
768  }  }
769    
770    IndexVector Rectangle::getNumSubdivisionsPerDim() const
771    {
772        IndexVector ret;
773        ret.push_back(m_NX);
774        ret.push_back(m_NY);
775        return ret;
776    }
777    
778  pair<double,double> Rectangle::getFirstCoordAndSpacing(dim_t dim) const  pair<double,double> Rectangle::getFirstCoordAndSpacing(dim_t dim) const
779  {  {
780      if (dim==0) {      if (dim==0) {
781          return pair<double,double>((m_l0*m_offset0)/m_gNE0, m_l0/m_gNE0);          return pair<double,double>(m_x0+(m_l0*m_offset0)/m_gNE0, m_l0/m_gNE0);
782      } else if (dim==1) {      } else if (dim==1) {
783          return pair<double,double>((m_l1*m_offset1)/m_gNE1, m_l1/m_gNE1);          return pair<double,double>(m_y0+(m_l1*m_offset1)/m_gNE1, m_l1/m_gNE1);
784      }      }
785      throw RipleyException("getFirstCoordAndSpacing(): invalid argument");      throw RipleyException("getFirstCoordAndSpacing: invalid argument");
786  }  }
787    
788  //protected  //protected
# Line 1117  void Rectangle::assembleCoordinates(escr Line 824  void Rectangle::assembleCoordinates(escr
824      }      }
825  }  }
826    
827    //protected
828    void Rectangle::assembleGradient(escript::Data& out, escript::Data& in) const
829    {
830        const dim_t numComp = in.getDataPointSize();
831        const double h0 = m_l0/m_gNE0;
832        const double h1 = m_l1/m_gNE1;
833        const double cx0 = -1./h0;
834        const double cx1 = -.78867513459481288225/h0;
835        const double cx2 = -.5/h0;
836        const double cx3 = -.21132486540518711775/h0;
837        const double cx4 = .21132486540518711775/h0;
838        const double cx5 = .5/h0;
839        const double cx6 = .78867513459481288225/h0;
840        const double cx7 = 1./h0;
841        const double cy0 = -1./h1;
842        const double cy1 = -.78867513459481288225/h1;
843        const double cy2 = -.5/h1;
844        const double cy3 = -.21132486540518711775/h1;
845        const double cy4 = .21132486540518711775/h1;
846        const double cy5 = .5/h1;
847        const double cy6 = .78867513459481288225/h1;
848        const double cy7 = 1./h1;
849    
850        if (out.getFunctionSpace().getTypeCode() == Elements) {
851            out.requireWrite();
852    #pragma omp parallel
853            {
854                vector<double> f_00(numComp);
855                vector<double> f_01(numComp);
856                vector<double> f_10(numComp);
857                vector<double> f_11(numComp);
858    #pragma omp for
859                for (index_t k1=0; k1 < m_NE1; ++k1) {
860                    for (index_t k0=0; k0 < m_NE0; ++k0) {
861                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,k1, m_N0)), numComp*sizeof(double));
862                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,k1+1, m_N0)), numComp*sizeof(double));
863                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,k1, m_N0)), numComp*sizeof(double));
864                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0)), numComp*sizeof(double));
865                        double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));
866                        for (index_t i=0; i < numComp; ++i) {
867                            o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;
868                            o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;
869                            o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;
870                            o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;
871                            o[INDEX3(i,0,2,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;
872                            o[INDEX3(i,1,2,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;
873                            o[INDEX3(i,0,3,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;
874                            o[INDEX3(i,1,3,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;
875                        } // end of component loop i
876                    } // end of k0 loop
877                } // end of k1 loop
878            } // end of parallel section
879        } else if (out.getFunctionSpace().getTypeCode() == ReducedElements) {
880            out.requireWrite();
881    #pragma omp parallel
882            {
883                vector<double> f_00(numComp);
884                vector<double> f_01(numComp);
885                vector<double> f_10(numComp);
886                vector<double> f_11(numComp);
887    #pragma omp for
888                for (index_t k1=0; k1 < m_NE1; ++k1) {
889                    for (index_t k0=0; k0 < m_NE0; ++k0) {
890                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,k1, m_N0)), numComp*sizeof(double));
891                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,k1+1, m_N0)), numComp*sizeof(double));
892                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,k1, m_N0)), numComp*sizeof(double));
893                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0)), numComp*sizeof(double));
894                        double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));
895                        for (index_t i=0; i < numComp; ++i) {
896                            o[INDEX3(i,0,0,numComp,2)] = cx5*(f_10[i] + f_11[i]) + cx2*(f_00[i] + f_01[i]);
897                            o[INDEX3(i,1,0,numComp,2)] = cy2*(f_00[i] + f_10[i]) + cy5*(f_01[i] + f_11[i]);
898                        } // end of component loop i
899                    } // end of k0 loop
900                } // end of k1 loop
901            } // end of parallel section
902        } else if (out.getFunctionSpace().getTypeCode() == FaceElements) {
903            out.requireWrite();
904    #pragma omp parallel
905            {
906                vector<double> f_00(numComp);
907                vector<double> f_01(numComp);
908                vector<double> f_10(numComp);
909                vector<double> f_11(numComp);
910                if (m_faceOffset[0] > -1) {
911    #pragma omp for nowait
912                    for (index_t k1=0; k1 < m_NE1; ++k1) {
913                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(0,k1, m_N0)), numComp*sizeof(double));
914                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(0,k1+1, m_N0)), numComp*sizeof(double));
915                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(1,k1, m_N0)), numComp*sizeof(double));
916                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(1,k1+1, m_N0)), numComp*sizeof(double));
917                        double* o = out.getSampleDataRW(m_faceOffset[0]+k1);
918                        for (index_t i=0; i < numComp; ++i) {
919                            o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;
920                            o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy0 + f_01[i]*cy7;
921                            o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;
922                            o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy0 + f_01[i]*cy7;
923                        } // end of component loop i
924                    } // end of k1 loop
925                } // end of face 0
926                if (m_faceOffset[1] > -1) {
927    #pragma omp for nowait
928                    for (index_t k1=0; k1 < m_NE1; ++k1) {
929                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(m_N0-2,k1, m_N0)), numComp*sizeof(double));
930                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(m_N0-2,k1+1, m_N0)), numComp*sizeof(double));
931                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0)), numComp*sizeof(double));
932                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0)), numComp*sizeof(double));
933                        double* o = out.getSampleDataRW(m_faceOffset[1]+k1);
934                        for (index_t i=0; i < numComp; ++i) {
935                            o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx1 + f_01[i]*cx3 + f_10[i]*cx6 + f_11[i]*cx4;
936                            o[INDEX3(i,1,0,numComp,2)] = f_10[i]*cy0 + f_11[i]*cy7;
937                            o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx3 + f_01[i]*cx1 + f_10[i]*cx4 + f_11[i]*cx6;
938                            o[INDEX3(i,1,1,numComp,2)] = f_10[i]*cy0 + f_11[i]*cy7;
939                        } // end of component loop i
940                    } // end of k1 loop
941                } // end of face 1
942                if (m_faceOffset[2] > -1) {
943    #pragma omp for nowait
944                    for (index_t k0=0; k0 < m_NE0; ++k0) {
945                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,0, m_N0)), numComp*sizeof(double));
946                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,1, m_N0)), numComp*sizeof(double));
947                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,0, m_N0)), numComp*sizeof(double));
948                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,1, m_N0)), numComp*sizeof(double));
949                        double* o = out.getSampleDataRW(m_faceOffset[2]+k0);
950                        for (index_t i=0; i < numComp; ++i) {
951                            o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx0 + f_10[i]*cx7;
952                            o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;
953                            o[INDEX3(i,0,1,numComp,2)] = f_00[i]*cx0 + f_10[i]*cx7;
954                            o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;
955                        } // end of component loop i
956                    } // end of k0 loop
957                } // end of face 2
958                if (m_faceOffset[3] > -1) {
959    #pragma omp for nowait
960                    for (index_t k0=0; k0 < m_NE0; ++k0) {
961                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,m_N1-2, m_N0)), numComp*sizeof(double));
962                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0)), numComp*sizeof(double));
963                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,m_N1-2, m_N0)), numComp*sizeof(double));
964                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0)), numComp*sizeof(double));
965                        double* o = out.getSampleDataRW(m_faceOffset[3]+k0);
966                        for (index_t i=0; i < numComp; ++i) {
967                            o[INDEX3(i,0,0,numComp,2)] = f_01[i]*cx0 + f_11[i]*cx7;
968                            o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy1 + f_01[i]*cy6 + f_10[i]*cy3 + f_11[i]*cy4;
969                            o[INDEX3(i,0,1,numComp,2)] = f_01[i]*cx0 + f_11[i]*cx7;
970                            o[INDEX3(i,1,1,numComp,2)] = f_00[i]*cy3 + f_01[i]*cy4 + f_10[i]*cy1 + f_11[i]*cy6;
971                        } // end of component loop i
972                    } // end of k0 loop
973                } // end of face 3
974            } // end of parallel section
975    
976        } else if (out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {
977            out.requireWrite();
978    #pragma omp parallel
979            {
980                vector<double> f_00(numComp);
981                vector<double> f_01(numComp);
982                vector<double> f_10(numComp);
983                vector<double> f_11(numComp);
984                if (m_faceOffset[0] > -1) {
985    #pragma omp for nowait
986                    for (index_t k1=0; k1 < m_NE1; ++k1) {
987                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(0,k1, m_N0)), numComp*sizeof(double));
988                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(0,k1+1, m_N0)), numComp*sizeof(double));
989                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(1,k1, m_N0)), numComp*sizeof(double));
990                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(1,k1+1, m_N0)), numComp*sizeof(double));
991                        double* o = out.getSampleDataRW(m_faceOffset[0]+k1);
992                        for (index_t i=0; i < numComp; ++i) {
993                            o[INDEX3(i,0,0,numComp,2)] = cx5*(f_10[i] + f_11[i]) + cx2*(f_00[i] + f_01[i]);
994                            o[INDEX3(i,1,0,numComp,2)] = f_00[i]*cy0 + f_01[i]*cy7;
995                        } // end of component loop i
996                    } // end of k1 loop
997                } // end of face 0
998                if (m_faceOffset[1] > -1) {
999    #pragma omp for nowait
1000                    for (index_t k1=0; k1 < m_NE1; ++k1) {
1001                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(m_N0-2,k1, m_N0)), numComp*sizeof(double));
1002                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(m_N0-2,k1+1, m_N0)), numComp*sizeof(double));
1003                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0)), numComp*sizeof(double));
1004                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0)), numComp*sizeof(double));
1005                        double* o = out.getSampleDataRW(m_faceOffset[1]+k1);
1006                        for (index_t i=0; i < numComp; ++i) {
1007                            o[INDEX3(i,0,0,numComp,2)] = cx5*(f_10[i] + f_11[i]) + cx2*(f_00[i] + f_01[i]);
1008                            o[INDEX3(i,1,0,numComp,2)] = f_10[i]*cy0 + f_11[i]*cy7;
1009                        } // end of component loop i
1010                    } // end of k1 loop
1011                } // end of face 1
1012                if (m_faceOffset[2] > -1) {
1013    #pragma omp for nowait
1014                    for (index_t k0=0; k0 < m_NE0; ++k0) {
1015                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,0, m_N0)), numComp*sizeof(double));
1016                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,1, m_N0)), numComp*sizeof(double));
1017                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,0, m_N0)), numComp*sizeof(double));
1018                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,1, m_N0)), numComp*sizeof(double));
1019                        double* o = out.getSampleDataRW(m_faceOffset[2]+k0);
1020                        for (index_t i=0; i < numComp; ++i) {
1021                            o[INDEX3(i,0,0,numComp,2)] = f_00[i]*cx0 + f_10[i]*cx7;
1022                            o[INDEX3(i,1,0,numComp,2)] = cy2*(f_00[i] + f_10[i]) + cy5*(f_01[i] + f_11[i]);
1023                        } // end of component loop i
1024                    } // end of k0 loop
1025                } // end of face 2
1026                if (m_faceOffset[3] > -1) {
1027    #pragma omp for nowait
1028                    for (index_t k0=0; k0 < m_NE0; ++k0) {
1029                        memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,m_N1-2, m_N0)), numComp*sizeof(double));
1030                        memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0)), numComp*sizeof(double));
1031                        memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,m_N1-2, m_N0)), numComp*sizeof(double));
1032                        memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0)), numComp*sizeof(double));
1033                        double* o = out.getSampleDataRW(m_faceOffset[3]+k0);
1034                        for (index_t i=0; i < numComp; ++i) {
1035                            o[INDEX3(i,0,0,numComp,2)] = f_01[i]*cx0 + f_11[i]*cx7;
1036                            o[INDEX3(i,1,0,numComp,2)] = cy5*(f_01[i] + f_11[i]) + cy2*(f_00[i] + f_10[i]);
1037                        } // end of component loop i
1038                    } // end of k0 loop
1039                } // end of face 3
1040            } // end of parallel section
1041        }
1042    }
1043    
1044    //protected
1045    void Rectangle::assembleIntegrate(vector<double>& integrals, escript::Data& arg) const
1046    {
1047        const dim_t numComp = arg.getDataPointSize();
1048        const double h0 = m_l0/m_gNE0;
1049        const double h1 = m_l1/m_gNE1;
1050        const index_t left = (m_offset0==0 ? 0 : 1);
1051        const index_t bottom = (m_offset1==0 ? 0 : 1);
1052        const int fs=arg.getFunctionSpace().getTypeCode();
1053        if (fs == Elements && arg.actsExpanded()) {
1054    #pragma omp parallel
1055            {
1056                vector<double> int_local(numComp, 0);
1057                const double w = h0*h1/4.;
1058    #pragma omp for nowait
1059                for (index_t k1 = bottom; k1 < bottom+m_ownNE1; ++k1) {
1060                    for (index_t k0 = left; k0 < left+m_ownNE0; ++k0) {
1061                        const double* f = arg.getSampleDataRO(INDEX2(k0, k1, m_NE0));
1062                        for (index_t i=0; i < numComp; ++i) {
1063                            const double f0 = f[INDEX2(i,0,numComp)];
1064                            const double f1 = f[INDEX2(i,1,numComp)];
1065                            const double f2 = f[INDEX2(i,2,numComp)];
1066                            const double f3 = f[INDEX2(i,3,numComp)];
1067                            int_local[i]+=(f0+f1+f2+f3)*w;
1068                        }  // end of component loop i
1069                    } // end of k0 loop
1070                } // end of k1 loop
1071    #pragma omp critical
1072                for (index_t i=0; i<numComp; i++)
1073                    integrals[i]+=int_local[i];
1074            } // end of parallel section
1075    
1076        } else if (fs==ReducedElements || (fs==Elements && !arg.actsExpanded())) {
1077            const double w = h0*h1;
1078    #pragma omp parallel
1079            {
1080                vector<double> int_local(numComp, 0);
1081    #pragma omp for nowait
1082                for (index_t k1 = bottom; k1 < bottom+m_ownNE1; ++k1) {
1083                    for (index_t k0 = left; k0 < left+m_ownNE0; ++k0) {
1084                        const double* f = arg.getSampleDataRO(INDEX2(k0, k1, m_NE0));
1085                        for (index_t i=0; i < numComp; ++i) {
1086                            int_local[i]+=f[i]*w;
1087                        }
1088                    }
1089                }
1090    #pragma omp critical
1091                for (index_t i=0; i<numComp; i++)
1092                    integrals[i]+=int_local[i];
1093            } // end of parallel section
1094    
1095        } else if (fs == FaceElements && arg.actsExpanded()) {
1096    #pragma omp parallel
1097            {
1098                vector<double> int_local(numComp, 0);
1099                const double w0 = h0/2.;
1100                const double w1 = h1/2.;
1101                if (m_faceOffset[0] > -1) {
1102    #pragma omp for nowait
1103                    for (index_t k1 = bottom; k1 < bottom+m_ownNE1; ++k1) {
1104                        const double* f = arg.getSampleDataRO(m_faceOffset[0]+k1);
1105                        for (index_t i=0; i < numComp; ++i) {
1106                            const double f0 = f[INDEX2(i,0,numComp)];
1107                            const double f1 = f[INDEX2(i,1,numComp)];
1108                            int_local[i]+=(f0+f1)*w1;
1109                        }  // end of component loop i
1110                    } // end of k1 loop
1111                }
1112    
1113                if (m_faceOffset[1] > -1) {
1114    #pragma omp for nowait
1115                    for (index_t k1 = bottom; k1 < bottom+m_ownNE1; ++k1) {
1116                        const double* f = arg.getSampleDataRO(m_faceOffset[1]+k1);
1117                        for (index_t i=0; i < numComp; ++i) {
1118                            const double f0 = f[INDEX2(i,0,numComp)];
1119                            const double f1 = f[INDEX2(i,1,numComp)];
1120                            int_local[i]+=(f0+f1)*w1;
1121                        }  // end of component loop i
1122                    } // end of k1 loop
1123                }
1124    
1125                if (m_faceOffset[2] > -1) {
1126    #pragma omp for nowait
1127                    for (index_t k0 = left; k0 < left+m_ownNE0; ++k0) {
1128                        const double* f = arg.getSampleDataRO(m_faceOffset[2]+k0);
1129                        for (index_t i=0; i < numComp; ++i) {
1130                            const double f0 = f[INDEX2(i,0,numComp)];
1131                            const double f1 = f[INDEX2(i,1,numComp)];
1132                            int_local[i]+=(f0+f1)*w0;
1133                        }  // end of component loop i
1134                    } // end of k0 loop
1135                }
1136    
1137                if (m_faceOffset[3] > -1) {
1138    #pragma omp for nowait
1139                    for (index_t k0 = left; k0 < left+m_ownNE0; ++k0) {
1140                        const double* f = arg.getSampleDataRO(m_faceOffset[3]+k0);
1141                        for (index_t i=0; i < numComp; ++i) {
1142                            const double f0 = f[INDEX2(i,0,numComp)];
1143                            const double f1 = f[INDEX2(i,1,numComp)];
1144                            int_local[i]+=(f0+f1)*w0;
1145                        }  // end of component loop i
1146                    } // end of k0 loop
1147                }
1148    #pragma omp critical
1149                for (index_t i=0; i<numComp; i++)
1150                    integrals[i]+=int_local[i];
1151            } // end of parallel section
1152    
1153        } else if (fs==ReducedFaceElements || (fs==FaceElements && !arg.actsExpanded())) {
1154    #pragma omp parallel
1155            {
1156                vector<double> int_local(numComp, 0);
1157                if (m_faceOffset[0] > -1) {
1158    #pragma omp for nowait
1159                    for (index_t k1 = bottom; k1 < bottom+m_ownNE1; ++k1) {
1160                        const double* f = arg.getSampleDataRO(m_faceOffset[0]+k1);
1161                        for (index_t i=0; i < numComp; ++i) {
1162                            int_local[i]+=f[i]*h1;
1163                        }
1164                    }
1165                }
1166    
1167                if (m_faceOffset[1] > -1) {
1168    #pragma omp for nowait
1169                    for (index_t k1 = bottom; k1 < bottom+m_ownNE1; ++k1) {
1170                        const double* f = arg.getSampleDataRO(m_faceOffset[1]+k1);
1171                        for (index_t i=0; i < numComp; ++i) {
1172                            int_local[i]+=f[i]*h1;
1173                        }
1174                    }
1175                }
1176    
1177                if (m_faceOffset[2] > -1) {
1178    #pragma omp for nowait
1179                    for (index_t k0 = left; k0 < left+m_ownNE0; ++k0) {
1180                        const double* f = arg.getSampleDataRO(m_faceOffset[2]+k0);
1181                        for (index_t i=0; i < numComp; ++i) {
1182                            int_local[i]+=f[i]*h0;
1183                        }
1184                    }
1185                }
1186    
1187                if (m_faceOffset[3] > -1) {
1188    #pragma omp for nowait
1189                    for (index_t k0 = left; k0 < left+m_ownNE0; ++k0) {
1190                        const double* f = arg.getSampleDataRO(m_faceOffset[3]+k0);
1191                        for (index_t i=0; i < numComp; ++i) {
1192                            int_local[i]+=f[i]*h0;
1193                        }
1194                    }
1195                }
1196    
1197    #pragma omp critical
1198                for (index_t i=0; i<numComp; i++)
1199                    integrals[i]+=int_local[i];
1200            } // end of parallel section
1201        } // function space selector
1202    }
1203    
1204    //protected
1205    dim_t Rectangle::insertNeighbourNodes(IndexVector& index, index_t node) const
1206    {
1207        const dim_t nDOF0 = (m_gNE0+1)/m_NX;
1208        const dim_t nDOF1 = (m_gNE1+1)/m_NY;
1209        const int x=node%nDOF0;
1210        const int y=node/nDOF0;
1211        dim_t num=0;
1212        // loop through potential neighbours and add to index if positions are
1213        // within bounds
1214        for (int i1=-1; i1<2; i1++) {
1215            for (int i0=-1; i0<2; i0++) {
1216                // skip node itself
1217                if (i0==0 && i1==0)
1218                    continue;
1219                // location of neighbour node
1220                const int nx=x+i0;
1221                const int ny=y+i1;
1222                if (nx>=0 && ny>=0 && nx<nDOF0 && ny<nDOF1) {
1223                    index.push_back(ny*nDOF0+nx);
1224                    num++;
1225                }
1226            }
1227        }
1228    
1229        return num;
1230    }
1231    
1232    //protected
1233    void Rectangle::nodesToDOF(escript::Data& out, escript::Data& in) const
1234    {
1235        const dim_t numComp = in.getDataPointSize();
1236        out.requireWrite();
1237    
1238        const index_t left = (m_offset0==0 ? 0 : 1);
1239        const index_t bottom = (m_offset1==0 ? 0 : 1);
1240        const dim_t nDOF0 = (m_gNE0+1)/m_NX;
1241        const dim_t nDOF1 = (m_gNE1+1)/m_NY;
1242    #pragma omp parallel for
1243        for (index_t i=0; i<nDOF1; i++) {
1244            for (index_t j=0; j<nDOF0; j++) {
1245                const index_t n=j+left+(i+bottom)*m_N0;
1246                const double* src=in.getSampleDataRO(n);
1247                copy(src, src+numComp, out.getSampleDataRW(j+i*nDOF0));
1248            }
1249        }
1250    }
1251    
1252    //protected
1253    void Rectangle::dofToNodes(escript::Data& out, escript::Data& in) const
1254    {
1255        const dim_t numComp = in.getDataPointSize();
1256        Paso_Coupler* coupler = Paso_Coupler_alloc(m_connector, numComp);
1257        in.requireWrite();
1258        Paso_Coupler_startCollect(coupler, in.getSampleDataRW(0));
1259    
1260        const dim_t numDOF = getNumDOF();
1261        out.requireWrite();
1262        const double* buffer = Paso_Coupler_finishCollect(coupler);
1263    
1264    #pragma omp parallel for
1265        for (index_t i=0; i<getNumNodes(); i++) {
1266            const double* src=(m_dofMap[i]<numDOF ?
1267                    in.getSampleDataRO(m_dofMap[i])
1268                    : &buffer[(m_dofMap[i]-numDOF)*numComp]);
1269            copy(src, src+numComp, out.getSampleDataRW(i));
1270        }
1271        Paso_Coupler_free(coupler);
1272    }
1273    
1274  //private  //private
1275  void Rectangle::populateSampleIds()  void Rectangle::populateSampleIds()
1276  {  {
# Line 1131  void Rectangle::populateSampleIds() Line 1285  void Rectangle::populateSampleIds()
1285      }      }
1286      m_nodeDistribution[m_mpiInfo->size]=getNumDataPointsGlobal();      m_nodeDistribution[m_mpiInfo->size]=getNumDataPointsGlobal();
1287      m_nodeId.resize(getNumNodes());      m_nodeId.resize(getNumNodes());
1288        m_dofId.resize(numDOF);
1289        m_elementId.resize(getNumElements());
1290        m_faceId.resize(getNumFaceElements());
1291    
1292  #pragma omp parallel for  #pragma omp parallel
1293      for (dim_t i1=0; i1<m_N1; i1++) {      {
1294          for (dim_t i0=0; i0<m_N0; i0++) {          // nodes
1295              m_nodeId[i0+i1*m_N0] = (m_offset1+i1)*(m_gNE0+1)+m_offset0+i0;  #pragma omp for nowait
1296            for (dim_t i1=0; i1<m_N1; i1++) {
1297                for (dim_t i0=0; i0<m_N0; i0++) {
1298                    m_nodeId[i0+i1*m_N0] = (m_offset1+i1)*(m_gNE0+1)+m_offset0+i0;
1299                }
1300          }          }
     }  
1301    
1302      m_dofId.resize(numDOF);          // degrees of freedom
1303      const index_t firstId=m_nodeDistribution[m_mpiInfo->rank];  #pragma omp for nowait
1304      for (dim_t i=0; i<numDOF; i++)          for (dim_t k=0; k<numDOF; k++)
1305          m_dofId[i] = firstId+i;              m_dofId[k] = m_nodeDistribution[m_mpiInfo->rank]+k;
1306    
1307            // elements
1308    #pragma omp for nowait
1309            for (dim_t i1=0; i1<m_NE1; i1++) {
1310                for (dim_t i0=0; i0<m_NE0; i0++) {
1311                    m_elementId[i0+i1*m_NE0]=(m_offset1+i1)*m_gNE0+m_offset0+i0;
1312                }
1313            }
1314    
1315            // face elements
1316    #pragma omp for
1317            for (dim_t k=0; k<getNumFaceElements(); k++)
1318                m_faceId[k]=k;
1319        } // end parallel section
1320    
1321      m_nodeTags.assign(getNumNodes(), 0);      m_nodeTags.assign(getNumNodes(), 0);
1322      updateTagsInUse(Nodes);      updateTagsInUse(Nodes);
1323    
     // elements  
     m_elementId.resize(getNumElements());  
 #pragma omp parallel for  
     for (dim_t k=0; k<getNumElements(); k++) {  
         m_elementId[k]=k;  
     }  
1324      m_elementTags.assign(getNumElements(), 0);      m_elementTags.assign(getNumElements(), 0);
1325      updateTagsInUse(Elements);      updateTagsInUse(Elements);
1326    
     // face element id's  
     m_faceId.resize(getNumFaceElements());  
 #pragma omp parallel for  
     for (dim_t k=0; k<getNumFaceElements(); k++) {  
         m_faceId[k]=k;  
     }  
   
1327      // generate face offset vector and set face tags      // generate face offset vector and set face tags
1328      const IndexVector facesPerEdge = getNumFacesPerBoundary();      const IndexVector facesPerEdge = getNumFacesPerBoundary();
1329      const index_t LEFT=1, RIGHT=2, BOTTOM=10, TOP=20;      const index_t LEFT=1, RIGHT=2, BOTTOM=10, TOP=20;
# Line 1185  void Rectangle::populateSampleIds() Line 1346  void Rectangle::populateSampleIds()
1346  }  }
1347    
1348  //private  //private
1349  int Rectangle::insertNeighbours(IndexVector& index, index_t node) const  void Rectangle::createPattern()
1350  {  {
1351      const index_t myN0 = (m_gNE0+1)/m_NX;      const dim_t nDOF0 = (m_gNE0+1)/m_NX;
1352      const index_t myN1 = (m_gNE1+1)/m_NY;      const dim_t nDOF1 = (m_gNE1+1)/m_NY;
1353      const int x=node%myN0;      const index_t left = (m_offset0==0 ? 0 : 1);
1354      const int y=node/myN0;      const index_t bottom = (m_offset1==0 ? 0 : 1);
1355      int num=0;  
1356      if (y>0) {      // populate node->DOF mapping with own degrees of freedom.
1357          if (x>0) {      // The rest is assigned in the loop further down
1358              // bottom-left      m_dofMap.assign(getNumNodes(), 0);
1359              index.push_back(node-myN0-1);  #pragma omp parallel for
1360              num++;      for (index_t i=bottom; i<bottom+nDOF1; i++) {
1361          }          for (index_t j=left; j<left+nDOF0; j++) {
1362          // bottom              m_dofMap[i*m_N0+j]=(i-bottom)*nDOF0+j-left;
1363          index.push_back(node-myN0);          }
         num++;  
         if (x<myN0-1) {  
             // bottom-right  
             index.push_back(node-myN0+1);  
             num++;  
         }  
     }  
     if (x<myN0-1) {  
         // right  
         index.push_back(node+1);  
         num++;  
         if (y<myN1-1) {  
             // top-right  
             index.push_back(node+myN0+1);  
             num++;  
         }  
     }  
     if (y<myN1-1) {  
         // top  
         index.push_back(node+myN0);  
         num++;  
         if (x>0) {  
             // top-left  
             index.push_back(node+myN0-1);  
             num++;  
         }  
     }  
     if (x>0) {  
         // left  
         index.push_back(node-1);  
         num++;  
1364      }      }
1365    
1366      return num;      // build list of shared components and neighbours by looping through
1367        // all potential neighbouring ranks and checking if positions are
1368        // within bounds
1369        const dim_t numDOF=nDOF0*nDOF1;
1370        vector<IndexVector> colIndices(numDOF); // for the couple blocks
1371        RankVector neighbour;
1372        IndexVector offsetInShared(1,0);
1373        IndexVector sendShared, recvShared;
1374        int numShared=0;
1375        const int x=m_mpiInfo->rank%m_NX;
1376        const int y=m_mpiInfo->rank/m_NX;
1377        for (int i1=-1; i1<2; i1++) {
1378            for (int i0=-1; i0<2; i0++) {
1379                // skip this rank
1380                if (i0==0 && i1==0)
1381                    continue;
1382                // location of neighbour rank
1383                const int nx=x+i0;
1384                const int ny=y+i1;
1385                if (nx>=0 && ny>=0 && nx<m_NX && ny<m_NY) {
1386                    neighbour.push_back(ny*m_NX+nx);
1387                    if (i0==0) {
1388                        // sharing top or bottom edge
1389                        const int firstDOF=(i1==-1 ? 0 : numDOF-nDOF0);
1390                        const int firstNode=(i1==-1 ? left : m_N0*(m_N1-1)+left);
1391                        offsetInShared.push_back(offsetInShared.back()+nDOF0);
1392                        for (dim_t i=0; i<nDOF0; i++, numShared++) {
1393                            sendShared.push_back(firstDOF+i);
1394                            recvShared.push_back(numDOF+numShared);
1395                            if (i>0)
1396                                colIndices[firstDOF+i-1].push_back(numShared);
1397                            colIndices[firstDOF+i].push_back(numShared);
1398                            if (i<nDOF0-1)
1399                                colIndices[firstDOF+i+1].push_back(numShared);
1400                            m_dofMap[firstNode+i]=numDOF+numShared;
1401                        }
1402                    } else if (i1==0) {
1403                        // sharing left or right edge
1404                        const int firstDOF=(i0==-1 ? 0 : nDOF0-1);
1405                        const int firstNode=(i0==-1 ? bottom*m_N0 : (bottom+1)*m_N0-1);
1406                        offsetInShared.push_back(offsetInShared.back()+nDOF1);
1407                        for (dim_t i=0; i<nDOF1; i++, numShared++) {
1408                            sendShared.push_back(firstDOF+i*nDOF0);
1409                            recvShared.push_back(numDOF+numShared);
1410                            if (i>0)
1411                                colIndices[firstDOF+(i-1)*nDOF0].push_back(numShared);
1412                            colIndices[firstDOF+i*nDOF0].push_back(numShared);
1413                            if (i<nDOF1-1)
1414                                colIndices[firstDOF+(i+1)*nDOF0].push_back(numShared);
1415                            m_dofMap[firstNode+i*m_N0]=numDOF+numShared;
1416                        }
1417                    } else {
1418                        // sharing a node
1419                        const int dof=(i0+1)/2*(nDOF0-1)+(i1+1)/2*(numDOF-nDOF0);
1420                        const int node=(i0+1)/2*(m_N0-1)+(i1+1)/2*m_N0*(m_N1-1);
1421                        offsetInShared.push_back(offsetInShared.back()+1);
1422                        sendShared.push_back(dof);
1423                        recvShared.push_back(numDOF+numShared);
1424                        colIndices[dof].push_back(numShared);
1425                        m_dofMap[node]=numDOF+numShared;
1426                        ++numShared;
1427                    }
1428                }
1429            }
1430        }
1431    
1432        // create connector
1433        Paso_SharedComponents *snd_shcomp = Paso_SharedComponents_alloc(
1434                numDOF, neighbour.size(), &neighbour[0], &sendShared[0],
1435                &offsetInShared[0], 1, 0, m_mpiInfo);
1436        Paso_SharedComponents *rcv_shcomp = Paso_SharedComponents_alloc(
1437                numDOF, neighbour.size(), &neighbour[0], &recvShared[0],
1438                &offsetInShared[0], 1, 0, m_mpiInfo);
1439        m_connector = Paso_Connector_alloc(snd_shcomp, rcv_shcomp);
1440        Paso_SharedComponents_free(snd_shcomp);
1441        Paso_SharedComponents_free(rcv_shcomp);
1442    
1443        // create main and couple blocks
1444        Paso_Pattern *mainPattern = createMainPattern();
1445        Paso_Pattern *colPattern, *rowPattern;
1446        createCouplePatterns(colIndices, numShared, &colPattern, &rowPattern);
1447    
1448        // allocate paso distribution
1449        Paso_Distribution* distribution = Paso_Distribution_alloc(m_mpiInfo,
1450                const_cast<index_t*>(&m_nodeDistribution[0]), 1, 0);
1451    
1452        // finally create the system matrix
1453        m_pattern = Paso_SystemMatrixPattern_alloc(MATRIX_FORMAT_DEFAULT,
1454                distribution, distribution, mainPattern, colPattern, rowPattern,
1455                m_connector, m_connector);
1456    
1457        Paso_Distribution_free(distribution);
1458    
1459        // useful debug output
1460        /*
1461        cout << "--- rcv_shcomp ---" << endl;
1462        cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << endl;
1463        for (size_t i=0; i<neighbour.size(); i++) {
1464            cout << "neighbor[" << i << "]=" << neighbour[i]
1465                << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << endl;
1466        }
1467        for (size_t i=0; i<recvShared.size(); i++) {
1468            cout << "shared[" << i << "]=" << recvShared[i] << endl;
1469        }
1470        cout << "--- snd_shcomp ---" << endl;
1471        for (size_t i=0; i<sendShared.size(); i++) {
1472            cout << "shared[" << i << "]=" << sendShared[i] << endl;
1473        }
1474        cout << "--- dofMap ---" << endl;
1475        for (size_t i=0; i<m_dofMap.size(); i++) {
1476            cout << "m_dofMap[" << i << "]=" << m_dofMap[i] << endl;
1477        }
1478        cout << "--- colIndices ---" << endl;
1479        for (size_t i=0; i<colIndices.size(); i++) {
1480            cout << "colIndices[" << i << "].size()=" << colIndices[i].size() << endl;
1481        }
1482        */
1483    
1484        /*
1485        cout << "--- main_pattern ---" << endl;
1486        cout << "M=" << mainPattern->numOutput << ", N=" << mainPattern->numInput << endl;
1487        for (size_t i=0; i<mainPattern->numOutput+1; i++) {
1488            cout << "ptr[" << i << "]=" << mainPattern->ptr[i] << endl;
1489        }
1490        for (size_t i=0; i<mainPattern->ptr[mainPattern->numOutput]; i++) {
1491            cout << "index[" << i << "]=" << mainPattern->index[i] << endl;
1492        }
1493        */
1494    
1495        /*
1496        cout << "--- colCouple_pattern ---" << endl;
1497        cout << "M=" << colPattern->numOutput << ", N=" << colPattern->numInput << endl;
1498        for (size_t i=0; i<colPattern->numOutput+1; i++) {
1499            cout << "ptr[" << i << "]=" << colPattern->ptr[i] << endl;
1500        }
1501        for (size_t i=0; i<colPattern->ptr[colPattern->numOutput]; i++) {
1502            cout << "index[" << i << "]=" << colPattern->index[i] << endl;
1503        }
1504        */
1505    
1506        /*
1507        cout << "--- rowCouple_pattern ---" << endl;
1508        cout << "M=" << rowPattern->numOutput << ", N=" << rowPattern->numInput << endl;
1509        for (size_t i=0; i<rowPattern->numOutput+1; i++) {
1510            cout << "ptr[" << i << "]=" << rowPattern->ptr[i] << endl;
1511        }
1512        for (size_t i=0; i<rowPattern->ptr[rowPattern->numOutput]; i++) {
1513            cout << "index[" << i << "]=" << rowPattern->index[i] << endl;
1514        }
1515        */
1516    
1517        Paso_Pattern_free(mainPattern);
1518        Paso_Pattern_free(colPattern);
1519        Paso_Pattern_free(rowPattern);
1520    }
1521    
1522    //private
1523    void Rectangle::addToMatrixAndRHS(Paso_SystemMatrix* S, escript::Data& F,
1524             const vector<double>& EM_S, const vector<double>& EM_F, bool addS,
1525             bool addF, index_t firstNode, dim_t nEq, dim_t nComp) const
1526    {
1527        IndexVector rowIndex;
1528        rowIndex.push_back(m_dofMap[firstNode]);
1529        rowIndex.push_back(m_dofMap[firstNode+1]);
1530        rowIndex.push_back(m_dofMap[firstNode+m_N0]);
1531        rowIndex.push_back(m_dofMap[firstNode+m_N0+1]);
1532        if (addF) {
1533            double *F_p=F.getSampleDataRW(0);
1534            for (index_t i=0; i<rowIndex.size(); i++) {
1535                if (rowIndex[i]<getNumDOF()) {
1536                    for (index_t eq=0; eq<nEq; eq++) {
1537                        F_p[INDEX2(eq, rowIndex[i], nEq)]+=EM_F[INDEX2(eq,i,nEq)];
1538                    }
1539                }
1540            }
1541        }
1542        if (addS) {
1543            addToSystemMatrix(S, rowIndex, nEq, rowIndex, nComp, EM_S);
1544        }
1545  }  }
1546    
1547  //protected  //protected
# Line 1242  void Rectangle::interpolateNodesOnElemen Line 1550  void Rectangle::interpolateNodesOnElemen
1550  {  {
1551      const dim_t numComp = in.getDataPointSize();      const dim_t numComp = in.getDataPointSize();
1552      if (reduced) {      if (reduced) {
1553          /*** GENERATOR SNIP_INTERPOLATE_REDUCED_ELEMENTS TOP */          out.requireWrite();
1554          const double c0 = .25;          const double c0 = 0.25;
1555  #pragma omp parallel for  #pragma omp parallel
1556          for (index_t k1=0; k1 < m_NE1; ++k1) {          {
1557              for (index_t k0=0; k0 < m_NE0; ++k0) {              vector<double> f_00(numComp);
1558                  const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0));              vector<double> f_01(numComp);
1559                  const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,k1, m_N0));              vector<double> f_10(numComp);
1560                  const register double* f_00 = in.getSampleDataRO(INDEX2(k0,k1, m_N0));              vector<double> f_11(numComp);
1561                  const register double* f_01 = in.getSampleDataRO(INDEX2(k0,k1+1, m_N0));  #pragma omp for
1562                  double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));              for (index_t k1=0; k1 < m_NE1; ++k1) {
1563                  for (index_t i=0; i < numComp; ++i) {                  for (index_t k0=0; k0 < m_NE0; ++k0) {
1564                      o[INDEX2(i,numComp,0)] = c0*(f_00[i] + f_01[i] + f_10[i] + f_11[i]);                      memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,k1, m_N0)), numComp*sizeof(double));
1565                  } /* end of component loop i */                      memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,k1+1, m_N0)), numComp*sizeof(double));
1566              } /* end of k0 loop */                      memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,k1, m_N0)), numComp*sizeof(double));
1567          } /* end of k1 loop */                      memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0)), numComp*sizeof(double));
1568          /* GENERATOR SNIP_INTERPOLATE_REDUCED_ELEMENTS BOTTOM */                      double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));
1569                        for (index_t i=0; i < numComp; ++i) {
1570                            o[INDEX2(i,numComp,0)] = c0*(f_00[i] + f_01[i] + f_10[i] + f_11[i]);
1571                        } /* end of component loop i */
1572                    } /* end of k0 loop */
1573                } /* end of k1 loop */
1574            } /* end of parallel section */
1575      } else {      } else {
1576          /*** GENERATOR SNIP_INTERPOLATE_ELEMENTS TOP */          out.requireWrite();
1577          const double c0 = .16666666666666666667;          const double c0 = 0.16666666666666666667;
1578          const double c1 = .044658198738520451079;          const double c1 = 0.044658198738520451079;
1579          const double c2 = .62200846792814621559;          const double c2 = 0.62200846792814621559;
1580  #pragma omp parallel for  #pragma omp parallel
1581          for (index_t k1=0; k1 < m_NE1; ++k1) {          {
1582              for (index_t k0=0; k0 < m_NE0; ++k0) {              vector<double> f_00(numComp);
1583                  const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,k1, m_N0));              vector<double> f_01(numComp);
1584                  const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0));              vector<double> f_10(numComp);
1585                  const register double* f_01 = in.getSampleDataRO(INDEX2(k0,k1+1, m_N0));              vector<double> f_11(numComp);
1586                  const register double* f_00 = in.getSampleDataRO(INDEX2(k0,k1, m_N0));  #pragma omp for
1587                  double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));              for (index_t k1=0; k1 < m_NE1; ++k1) {
1588                  for (index_t i=0; i < numComp; ++i) {                  for (index_t k0=0; k0 < m_NE0; ++k0) {
1589                      o[INDEX2(i,numComp,0)] = f_00[i]*c2 + f_11[i]*c1 + c0*(f_01[i] + f_10[i]);                      memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,k1, m_N0)), numComp*sizeof(double));
1590                      o[INDEX2(i,numComp,1)] = f_01[i]*c1 + f_10[i]*c2 + c0*(f_00[i] + f_11[i]);                      memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,k1+1, m_N0)), numComp*sizeof(double));
1591                      o[INDEX2(i,numComp,2)] = f_01[i]*c2 + f_10[i]*c1 + c0*(f_00[i] + f_11[i]);                      memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,k1, m_N0)), numComp*sizeof(double));
1592                      o[INDEX2(i,numComp,3)] = f_00[i]*c1 + f_11[i]*c2 + c0*(f_01[i] + f_10[i]);                      memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,k1+1, m_N0)), numComp*sizeof(double));
1593                  } /* end of component loop i */                      double* o = out.getSampleDataRW(INDEX2(k0,k1,m_NE0));
1594              } /* end of k0 loop */                      for (index_t i=0; i < numComp; ++i) {
1595          } /* end of k1 loop */                          o[INDEX2(i,numComp,0)] = c0*(f_01[i] + f_10[i]) + c1*f_11[i] + c2*f_00[i];
1596          /* GENERATOR SNIP_INTERPOLATE_ELEMENTS BOTTOM */                          o[INDEX2(i,numComp,1)] = c0*(f_00[i] + f_11[i]) + c1*f_01[i] + c2*f_10[i];
1597                            o[INDEX2(i,numComp,2)] = c0*(f_00[i] + f_11[i]) + c1*f_10[i] + c2*f_01[i];
1598                            o[INDEX2(i,numComp,3)] = c0*(f_01[i] + f_10[i]) + c1*f_00[i] + c2*f_11[i];
1599                        } /* end of component loop i */
1600                    } /* end of k0 loop */
1601                } /* end of k1 loop */
1602            } /* end of parallel section */
1603      }      }
1604  }  }
1605    
# Line 1289  void Rectangle::interpolateNodesOnFaces( Line 1609  void Rectangle::interpolateNodesOnFaces(
1609  {  {
1610      const dim_t numComp = in.getDataPointSize();      const dim_t numComp = in.getDataPointSize();
1611      if (reduced) {      if (reduced) {
1612          const double c0 = .5;          out.requireWrite();
1613            const double c0 = 0.5;
1614  #pragma omp parallel  #pragma omp parallel
1615          {          {
1616              /*** GENERATOR SNIP_INTERPOLATE_REDUCED_FACES TOP */              vector<double> f_00(numComp);
1617                vector<double> f_01(numComp);
1618                vector<double> f_10(numComp);
1619                vector<double> f_11(numComp);
1620              if (m_faceOffset[0] > -1) {              if (m_faceOffset[0] > -1) {
1621  #pragma omp for nowait  #pragma omp for nowait
1622                  for (index_t k1=0; k1 < m_NE1; ++k1) {                  for (index_t k1=0; k1 < m_NE1; ++k1) {
1623                      const register double* f_00 = in.getSampleDataRO(INDEX2(0,k1, m_N0));                      memcpy(&f_00[0], in.getSampleDataRO(INDEX2(0,k1, m_N0)), numComp*sizeof(double));
1624                      const register double* f_01 = in.getSampleDataRO(INDEX2(0,k1+1, m_N0));                      memcpy(&f_01[0], in.getSampleDataRO(INDEX2(0,k1+1, m_N0)), numComp*sizeof(double));
1625                      double* o = out.getSampleDataRW(m_faceOffset[0]+k1);                      double* o = out.getSampleDataRW(m_faceOffset[0]+k1);
1626                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1627                          o[INDEX2(i,numComp,0)] = c0*(f_00[i] + f_01[i]);                          o[INDEX2(i,numComp,0)] = c0*(f_00[i] + f_01[i]);
# Line 1307  void Rectangle::interpolateNodesOnFaces( Line 1631  void Rectangle::interpolateNodesOnFaces(
1631              if (m_faceOffset[1] > -1) {              if (m_faceOffset[1] > -1) {
1632  #pragma omp for nowait  #pragma omp for nowait
1633                  for (index_t k1=0; k1 < m_NE1; ++k1) {                  for (index_t k1=0; k1 < m_NE1; ++k1) {
1634                      const register double* f_10 = in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0));                      memcpy(&f_10[0], in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0)), numComp*sizeof(double));
1635                      const register double* f_11 = in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0));                      memcpy(&f_11[0], in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0)), numComp*sizeof(double));
1636                      double* o = out.getSampleDataRW(m_faceOffset[1]+k1);                      double* o = out.getSampleDataRW(m_faceOffset[1]+k1);
1637                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1638                          o[INDEX2(i,numComp,0)] = c0*(f_10[i] + f_11[i]);                          o[INDEX2(i,numComp,0)] = c0*(f_10[i] + f_11[i]);
# Line 1318  void Rectangle::interpolateNodesOnFaces( Line 1642  void Rectangle::interpolateNodesOnFaces(
1642              if (m_faceOffset[2] > -1) {              if (m_faceOffset[2] > -1) {
1643  #pragma omp for nowait  #pragma omp for nowait
1644                  for (index_t k0=0; k0 < m_NE0; ++k0) {                  for (index_t k0=0; k0 < m_NE0; ++k0) {
1645                      const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,0, m_N0));                      memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,0, m_N0)), numComp*sizeof(double));
1646                      const register double* f_00 = in.getSampleDataRO(INDEX2(k0,0, m_N0));                      memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,0, m_N0)), numComp*sizeof(double));
1647                      double* o = out.getSampleDataRW(m_faceOffset[2]+k0);                      double* o = out.getSampleDataRW(m_faceOffset[2]+k0);
1648                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1649                          o[INDEX2(i,numComp,0)] = c0*(f_00[i] + f_10[i]);                          o[INDEX2(i,numComp,0)] = c0*(f_00[i] + f_10[i]);
# Line 1329  void Rectangle::interpolateNodesOnFaces( Line 1653  void Rectangle::interpolateNodesOnFaces(
1653              if (m_faceOffset[3] > -1) {              if (m_faceOffset[3] > -1) {
1654  #pragma omp for nowait  #pragma omp for nowait
1655                  for (index_t k0=0; k0 < m_NE0; ++k0) {                  for (index_t k0=0; k0 < m_NE0; ++k0) {
1656                      const register double* f_01 = in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0));                      memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0)), numComp*sizeof(double));
1657                      const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0));                      memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0)), numComp*sizeof(double));
1658                      double* o = out.getSampleDataRW(m_faceOffset[3]+k0);                      double* o = out.getSampleDataRW(m_faceOffset[3]+k0);
1659                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1660                          o[INDEX2(i,numComp,0)] = c0*(f_01[i] + f_11[i]);                          o[INDEX2(i,numComp,0)] = c0*(f_01[i] + f_11[i]);
1661                      } /* end of component loop i */                      } /* end of component loop i */
1662                  } /* end of k0 loop */                  } /* end of k0 loop */
1663              } /* end of face 3 */              } /* end of face 3 */
1664              /* GENERATOR SNIP_INTERPOLATE_REDUCED_FACES BOTTOM */          } /* end of parallel section */
         } // end of parallel section  
1665      } else {      } else {
1666            out.requireWrite();
1667          const double c0 = 0.21132486540518711775;          const double c0 = 0.21132486540518711775;
1668          const double c1 = 0.78867513459481288225;          const double c1 = 0.78867513459481288225;
1669  #pragma omp parallel  #pragma omp parallel
1670          {          {
1671              /*** GENERATOR SNIP_INTERPOLATE_FACES TOP */              vector<double> f_00(numComp);
1672                vector<double> f_01(numComp);
1673                vector<double> f_10(numComp);
1674                vector<double> f_11(numComp);
1675              if (m_faceOffset[0] > -1) {              if (m_faceOffset[0] > -1) {
1676  #pragma omp for nowait  #pragma omp for nowait
1677                  for (index_t k1=0; k1 < m_NE1; ++k1) {                  for (index_t k1=0; k1 < m_NE1; ++k1) {
1678                      const register double* f_01 = in.getSampleDataRO(INDEX2(0,k1+1, m_N0));                      memcpy(&f_00[0], in.getSampleDataRO(INDEX2(0,k1, m_N0)), numComp*sizeof(double));
1679                      const register double* f_00 = in.getSampleDataRO(INDEX2(0,k1, m_N0));                      memcpy(&f_01[0], in.getSampleDataRO(INDEX2(0,k1+1, m_N0)), numComp*sizeof(double));
1680                      double* o = out.getSampleDataRW(m_faceOffset[0]+k1);                      double* o = out.getSampleDataRW(m_faceOffset[0]+k1);
1681                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1682                          o[INDEX2(i,numComp,0)] = f_00[i]*c1 + f_01[i]*c0;                          o[INDEX2(i,numComp,0)] = c0*f_01[i] + c1*f_00[i];
1683                          o[INDEX2(i,numComp,1)] = f_00[i]*c0 + f_01[i]*c1;                          o[INDEX2(i,numComp,1)] = c0*f_00[i] + c1*f_01[i];
1684                      } /* end of component loop i */                      } /* end of component loop i */
1685                  } /* end of k1 loop */                  } /* end of k1 loop */
1686              } /* end of face 0 */              } /* end of face 0 */
1687              if (m_faceOffset[1] > -1) {              if (m_faceOffset[1] > -1) {
1688  #pragma omp for nowait  #pragma omp for nowait
1689                  for (index_t k1=0; k1 < m_NE1; ++k1) {                  for (index_t k1=0; k1 < m_NE1; ++k1) {
1690                      const register double* f_10 = in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0));                      memcpy(&f_10[0], in.getSampleDataRO(INDEX2(m_N0-1,k1, m_N0)), numComp*sizeof(double));
1691                      const register double* f_11 = in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0));                      memcpy(&f_11[0], in.getSampleDataRO(INDEX2(m_N0-1,k1+1, m_N0)), numComp*sizeof(double));
1692                      double* o = out.getSampleDataRW(m_faceOffset[1]+k1);                      double* o = out.getSampleDataRW(m_faceOffset[1]+k1);
1693                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1694                          o[INDEX2(i,numComp,0)] = f_10[i]*c1 + f_11[i]*c0;                          o[INDEX2(i,numComp,0)] = c1*f_10[i] + c0*f_11[i];
1695                          o[INDEX2(i,numComp,1)] = f_10[i]*c0 + f_11[i]*c1;                          o[INDEX2(i,numComp,1)] = c1*f_11[i] + c0*f_10[i];
1696                      } /* end of component loop i */                      } /* end of component loop i */
1697                  } /* end of k1 loop */                  } /* end of k1 loop */
1698              } /* end of face 1 */              } /* end of face 1 */
1699              if (m_faceOffset[2] > -1) {              if (m_faceOffset[2] > -1) {
1700  #pragma omp for nowait  #pragma omp for nowait
1701                  for (index_t k0=0; k0 < m_NE0; ++k0) {                  for (index_t k0=0; k0 < m_NE0; ++k0) {
1702                      const register double* f_10 = in.getSampleDataRO(INDEX2(k0+1,0, m_N0));                      memcpy(&f_00[0], in.getSampleDataRO(INDEX2(k0,0, m_N0)), numComp*sizeof(double));
1703                      const register double* f_00 = in.getSampleDataRO(INDEX2(k0,0, m_N0));                      memcpy(&f_10[0], in.getSampleDataRO(INDEX2(k0+1,0, m_N0)), numComp*sizeof(double));
1704                      double* o = out.getSampleDataRW(m_faceOffset[2]+k0);                      double* o = out.getSampleDataRW(m_faceOffset[2]+k0);
1705                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1706                          o[INDEX2(i,numComp,0)] = f_00[i]*c1 + f_10[i]*c0;                          o[INDEX2(i,numComp,0)] = c0*f_10[i] + c1*f_00[i];
1707                          o[INDEX2(i,numComp,1)] = f_00[i]*c0 + f_10[i]*c1;                          o[INDEX2(i,numComp,1)] = c0*f_00[i] + c1*f_10[i];
1708                      } /* end of component loop i */                      } /* end of component loop i */
1709                  } /* end of k0 loop */                  } /* end of k0 loop */
1710              } /* end of face 2 */              } /* end of face 2 */
1711              if (m_faceOffset[3] > -1) {              if (m_faceOffset[3] > -1) {
1712  #pragma omp for nowait  #pragma omp for nowait
1713                  for (index_t k0=0; k0 < m_NE0; ++k0) {                  for (index_t k0=0; k0 < m_NE0; ++k0) {
1714                      const register double* f_11 = in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0));                      memcpy(&f_01[0], in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0)), numComp*sizeof(double));
1715                      const register double* f_01 = in.getSampleDataRO(INDEX2(k0,m_N1-1, m_N0));                      memcpy(&f_11[0], in.getSampleDataRO(INDEX2(k0+1,m_N1-1, m_N0)), numComp*sizeof(double));
1716                      double* o = out.getSampleDataRW(m_faceOffset[3]+k0);                      double* o = out.getSampleDataRW(m_faceOffset[3]+k0);
1717                      for (index_t i=0; i < numComp; ++i) {                      for (index_t i=0; i < numComp; ++i) {
1718                          o[INDEX2(i,numComp,0)] = f_01[i]*c1 + f_11[i]*c0;                          o[INDEX2(i,numComp,0)] = c0*f_11[i] + c1*f_01[i];
1719                          o[INDEX2(i,numComp,1)] = f_01[i]*c0 + f_11[i]*c1;                          o[INDEX2(i,numComp,1)] = c0*f_01[i] + c1*f_11[i];
1720                      } /* end of component loop i */                      } /* end of component loop i */
1721                  } /* end of k0 loop */                  } /* end of k0 loop */
1722              } /* end of face 3 */              } /* end of face 3 */
1723              /* GENERATOR SNIP_INTERPOLATE_FACES BOTTOM */          } /* end of parallel section */
         } // end of parallel section  
     }  
 }  
   
 //protected  
 void Rectangle::nodesToDOF(escript::Data& out, escript::Data& in) const  
 {  
     const dim_t numComp = in.getDataPointSize();  
     out.requireWrite();  
   
     const index_t left = (m_offset0==0 ? 0 : 1);  
     const index_t bottom = (m_offset1==0 ? 0 : 1);  
     const index_t right = (m_mpiInfo->rank%m_NX==m_NX-1 ? m_N0 : m_N0-1);  
     const index_t top = (m_mpiInfo->rank/m_NX==m_NY-1 ? m_N1 : m_N1-1);  
     index_t n=0;  
     for (index_t i=bottom; i<top; i++) {  
         for (index_t j=left; j<right; j++, n++) {  
             const double* src=in.getSampleDataRO(j+i*m_N0);  
             copy(src, src+numComp, out.getSampleDataRW(n));  
         }  
1724      }      }
1725  }  }
1726    
# Line 1421  void Rectangle::nodesToDOF(escript::Data Line 1728  void Rectangle::nodesToDOF(escript::Data
1728  void Rectangle::assemblePDESingle(Paso_SystemMatrix* mat,  void Rectangle::assemblePDESingle(Paso_SystemMatrix* mat,
1729          escript::Data& rhs, const escript::Data& A, const escript::Data& B,          escript::Data& rhs, const escript::Data& A, const escript::Data& B,
1730          const escript::Data& C, const escript::Data& D,          const escript::Data& C, const escript::Data& D,
1731          const escript::Data& X, const escript::Data& Y,          const escript::Data& X, const escript::Data& Y) const
         const escript::Data& d, const escript::Data& y) const  
1732  {  {
1733      const double h0 = m_l0/m_gNE0;      const double h0 = m_l0/m_gNE0;
1734      const double h1 = m_l1/m_gNE1;      const double h1 = m_l1/m_gNE1;
     /* GENERATOR SNIP_PDE_SINGLE_PRE TOP */  
1735      const double w0 = -0.1555021169820365539*h1/h0;      const double w0 = -0.1555021169820365539*h1/h0;
1736      const double w1 = 0.041666666666666666667;      const double w1 = 0.041666666666666666667;
1737        const double w2 = -0.15550211698203655390;
1738        const double w3 = 0.041666666666666666667*h0/h1;
1739        const double w4 = 0.15550211698203655390;
1740        const double w5 = -0.041666666666666666667;
1741        const double w6 = -0.01116454968463011277*h1/h0;
1742        const double w7 = 0.011164549684630112770;
1743        const double w8 = -0.011164549684630112770;
1744        const double w9 = -0.041666666666666666667*h1/h0;
1745      const double w10 = -0.041666666666666666667*h0/h1;      const double w10 = -0.041666666666666666667*h0/h1;
1746      const double w11 = 0.1555021169820365539*h1/h0;      const double w11 = 0.1555021169820365539*h1/h0;
1747      const double w12 = 0.1555021169820365539*h0/h1;      const double w12 = 0.1555021169820365539*h0/h1;
# Line 1438  void Rectangle::assemblePDESingle(Paso_S Line 1751  void Rectangle::assemblePDESingle(Paso_S
1751      const double w16 = -0.01116454968463011277*h0/h1;      const double w16 = -0.01116454968463011277*h0/h1;
1752      const double w17 = -0.1555021169820365539*h0/h1;      const double w17 = -0.1555021169820365539*h0/h1;
1753      const double w18 = -0.33333333333333333333*h1/h0;      const double w18 = -0.33333333333333333333*h1/h0;
1754      const double w19 = 0.25000000000000000000;      const double w19 = 0.25;
1755      const double w2 = -0.15550211698203655390;      const double w20 = -0.25;
     const double w20 = -0.25000000000000000000;  
1756      const double w21 = 0.16666666666666666667*h0/h1;      const double w21 = 0.16666666666666666667*h0/h1;
1757      const double w22 = -0.16666666666666666667*h1/h0;      const double w22 = -0.16666666666666666667*h1/h0;
1758      const double w23 = -0.16666666666666666667*h0/h1;      const double w23 = -0.16666666666666666667*h0/h1;
# Line 1450  void Rectangle::assemblePDESingle(Paso_S Line 1762  void Rectangle::assemblePDESingle(Paso_S
1762      const double w27 = -0.33333333333333333333*h0/h1;      const double w27 = -0.33333333333333333333*h0/h1;
1763      const double w28 = -0.032861463941450536761*h1;      const double w28 = -0.032861463941450536761*h1;
1764      const double w29 = -0.032861463941450536761*h0;      const double w29 = -0.032861463941450536761*h0;
     const double w3 = 0.041666666666666666667*h0/h1;  
1765      const double w30 = -0.12264065304058601714*h1;      const double w30 = -0.12264065304058601714*h1;
1766      const double w31 = -0.0023593469594139828636*h1;      const double w31 = -0.0023593469594139828636*h1;
1767      const double w32 = -0.008805202725216129906*h0;      const double w32 = -0.008805202725216129906*h0;
# Line 1461  void Rectangle::assemblePDESingle(Paso_S Line 1772  void Rectangle::assemblePDESingle(Paso_S
1772      const double w37 = 0.0023593469594139828636*h1;      const double w37 = 0.0023593469594139828636*h1;
1773      const double w38 = 0.12264065304058601714*h1;      const double w38 = 0.12264065304058601714*h1;
1774      const double w39 = 0.032861463941450536761*h0;      const double w39 = 0.032861463941450536761*h0;
     const double w4 = 0.15550211698203655390;  
1775      const double w40 = -0.12264065304058601714*h0;      const double w40 = -0.12264065304058601714*h0;
1776      const double w41 = -0.0023593469594139828636*h0;      const double w41 = -0.0023593469594139828636*h0;
1777      const double w42 = 0.0023593469594139828636*h0;      const double w42 = 0.0023593469594139828636*h0;
# Line 1472  void Rectangle::assemblePDESingle(Paso_S Line 1782  void Rectangle::assemblePDESingle(Paso_S
1782      const double w47 = 0.16666666666666666667*h1;      const double w47 = 0.16666666666666666667*h1;
1783      const double w48 = 0.083333333333333333333*h0;      const double w48 = 0.083333333333333333333*h0;
1784      const double w49 = -0.16666666666666666667*h0;      const double w49 = -0.16666666666666666667*h0;
     const double w5 = -0.041666666666666666667;  
1785      const double w50 = 0.16666666666666666667*h0;      const double w50 = 0.16666666666666666667*h0;
1786      const double w51 = -0.083333333333333333333*h1;      const double w51 = -0.083333333333333333333*h1;
1787      const double w52 = 0.025917019497006092316*h0*h1;      const double w52 = 0.025917019497006092316*h0*h1;
# Line 1483  void Rectangle::assemblePDESingle(Paso_S Line 1792  void Rectangle::assemblePDESingle(Paso_S
1792      const double w57 = 0.055555555555555555556*h0*h1;      const double w57 = 0.055555555555555555556*h0*h1;
1793      const double w58 = 0.027777777777777777778*h0*h1;      const double w58 = 0.027777777777777777778*h0*h1;
1794      const double w59 = 0.11111111111111111111*h0*h1;      const double w59 = 0.11111111111111111111*h0*h1;
     const double w6 = -0.01116454968463011277*h1/h0;  
1795      const double w60 = -0.19716878364870322056*h1;      const double w60 = -0.19716878364870322056*h1;
1796      const double w61 = -0.19716878364870322056*h0;      const double w61 = -0.19716878364870322056*h0;
1797      const double w62 = -0.052831216351296779436*h0;      const double w62 = -0.052831216351296779436*h0;
# Line 1494  void Rectangle::assemblePDESingle(Paso_S Line 1802  void Rectangle::assemblePDESingle(Paso_S
1802      const double w67 = 0.052831216351296779436*h0;      const double w67 = 0.052831216351296779436*h0;
1803      const double w68 = -0.5*h1;      const double w68 = -0.5*h1;
1804      const double w69 = -0.5*h0;      const double w69 = -0.5*h0;
     const double w7 = 0.011164549684630112770;  
1805      const double w70 = 0.5*h1;      const double w70 = 0.5*h1;
1806      const double w71 = 0.5*h0;      const double w71 = 0.5*h0;
1807      const double w72 = 0.1555021169820365539*h0*h1;      const double w72 = 0.1555021169820365539*h0*h1;
1808      const double w73 = 0.041666666666666666667*h0*h1;      const double w73 = 0.041666666666666666667*h0*h1;
1809      const double w74 = 0.01116454968463011277*h0*h1;      const double w74 = 0.01116454968463011277*h0*h1;
1810      const double w75 = 0.25*h0*h1;      const double w75 = 0.25*h0*h1;
     const double w8 = -0.011164549684630112770;  
     const double w9 = -0.041666666666666666667*h1/h0;  
     /* GENERATOR SNIP_PDE_SINGLE_PRE BOTTOM */  
1811    
1812      rhs.requireWrite();      rhs.requireWrite();
1813  #pragma omp parallel  #pragma omp parallel
1814      {      {
1815          for (index_t k1_0=0; k1_0<2; k1_0++) { // coloring          for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
1816  #pragma omp for  #pragma omp for
1817              for (index_t k1=k1_0; k1<m_NE1; k1+=2) {              for (index_t k1=k1_0; k1<m_NE1; k1+=2) {
1818                  for (index_t k0=0; k0<m_NE0; ++k0)  {                  for (index_t k0=0; k0<m_NE0; ++k0)  {
# Line 1517  void Rectangle::assemblePDESingle(Paso_S Line 1821  void Rectangle::assemblePDESingle(Paso_S
1821                      vector<double> EM_S(4*4, 0);                      vector<double> EM_S(4*4, 0);
1822                      vector<double> EM_F(4, 0);                      vector<double> EM_F(4, 0);
1823                      const index_t e = k0 + m_NE0*k1;                      const index_t e = k0 + m_NE0*k1;
                     /* GENERATOR SNIP_PDE_SINGLE TOP */  
1824                      ///////////////                      ///////////////
1825                      // process A //                      // process A //
1826                      ///////////////                      ///////////////
# Line 1525  void Rectangle::assemblePDESingle(Paso_S Line 1828  void Rectangle::assemblePDESingle(Paso_S
1828                          add_EM_S=true;                          add_EM_S=true;
1829                          const double* A_p=const_cast<escript::Data*>(&A)->getSampleDataRO(e);                          const double* A_p=const_cast<escript::Data*>(&A)->getSampleDataRO(e);
1830                          if (A.actsExpanded()) {                          if (A.actsExpanded()) {
1831                              const register double A_00_0 = A_p[INDEX3(0,0,0,2,2)];                              const double A_00_0 = A_p[INDEX3(0,0,0,2,2)];
1832                              const register double A_01_0 = A_p[INDEX3(0,1,0,2,2)];                              const double A_10_0 = A_p[INDEX3(1,0,0,2,2)];
1833                              const register double A_10_0 = A_p[INDEX3(1,0,0,2,2)];                              const double A_01_0 = A_p[INDEX3(0,1,0,2,2)];
1834                              const register double A_11_0 = A_p[INDEX3(1,1,0,2,2)];                              const double A_11_0 = A_p[INDEX3(1,1,0,2,2)];
1835                              const register double A_00_1 = A_p[INDEX3(0,0,1,2,2)];                              const double A_00_1 = A_p[INDEX3(0,0,1,2,2)];
1836                              const register double A_01_1 = A_p[INDEX3(0,1,1,2,2)];                              const double A_10_1 = A_p[INDEX3(1,0,1,2,2)];
1837                              const register double A_10_1 = A_p[INDEX3(1,0,1,2,2)];                              const double A_01_1 = A_p[INDEX3(0,1,1,2,2)];
1838                              const register double A_11_1 = A_p[INDEX3(1,1,1,2,2)];                              const double A_11_1 = A_p[INDEX3(1,1,1,2,2)];
1839                              const register double A_00_2 = A_p[INDEX3(0,0,2,2,2)];                              const double A_00_2 = A_p[INDEX3(0,0,2,2,2)];
1840                              const register double A_01_2 = A_p[INDEX3(0,1,2,2,2)];                              const double A_10_2 = A_p[INDEX3(1,0,2,2,2)];
1841                              const register double A_10_2 = A_p[INDEX3(1,0,2,2,2)];                              const double A_01_2 = A_p[INDEX3(0,1,2,2,2)];
1842                              const register double A_11_2 = A_p[INDEX3(1,1,2,2,2)];                              const double A_11_2 = A_p[INDEX3(1,1,2,2,2)];
1843                              const register double A_00_3 = A_p[INDEX3(0,0,3,2,2)];                              const double A_00_3 = A_p[INDEX3(0,0,3,2,2)];
1844                              const register double A_01_3 = A_p[INDEX3(0,1,3,2,2)];                              const double A_10_3 = A_p[INDEX3(1,0,3,2,2)];
1845                              const register double A_10_3 = A_p[INDEX3(1,0,3,2,2)];                              const double A_01_3 = A_p[INDEX3(0,1,3,2,2)];
1846                              const register double A_11_3 = A_p[INDEX3(1,1,3,2,2)];                              const double A_11_3 = A_p[INDEX3(1,1,3,2,2)];
1847                              const register double tmp4_0 = A_10_1 + A_10_2;                              const double tmp0_0 = A_01_0 + A_01_3;
1848                              const register double tmp12_0 = A_11_0 + A_11_2;                              const double tmp1_0 = A_00_0 + A_00_1;
1849                              const register double tmp2_0 = A_11_0 + A_11_1 + A_11_2 + A_11_3;                              const double tmp2_0 = A_11_0 + A_11_1 + A_11_2 + A_11_3;
1850                              const register double tmp10_0 = A_01_3 + A_10_3;                              const double tmp3_0 = A_00_2 + A_00_3;
1851                              const register double tmp14_0 = A_01_0 + A_01_3 + A_10_0 + A_10_3;                              const double tmp4_0 = A_10_1 + A_10_2;
1852                              const register double tmp0_0 = A_01_0 + A_01_3;                              const double tmp5_0 = A_00_0 + A_00_1 + A_00_2 + A_00_3;
1853                              const register double tmp13_0 = A_01_2 + A_10_1;                              const double tmp6_0 = A_01_3 + A_10_0;
1854                              const register double tmp3_0 = A_00_2 + A_00_3;                              const double tmp7_0 = A_01_0 + A_10_3;
1855                              const register double tmp11_0 = A_11_1 + A_11_3;                              const double tmp8_0 = A_01_1 + A_01_2 + A_10_1 + A_10_2;
1856                              const register double tmp18_0 = A_01_1 + A_10_1;                              const double tmp9_0 = A_01_0 + A_10_0;
1857                              const register double tmp1_0 = A_00_0 + A_00_1;                              const double tmp12_0 = A_11_0 + A_11_2;
1858                              const register double tmp15_0 = A_01_1 + A_10_2;                              const double tmp10_0 = A_01_3 + A_10_3;
1859                              const register double tmp5_0 = A_00_0 + A_00_1 + A_00_2 + A_00_3;                              const double tmp14_0 = A_01_0 + A_01_3 + A_10_0 + A_10_3;
1860                              const register double tmp16_0 = A_10_0 + A_10_3;                              const double tmp13_0 = A_01_2 + A_10_1;
1861                              const register double tmp6_0 = A_01_3 + A_10_0;                              const double tmp11_0 = A_11_1 + A_11_3;
1862                              const register double tmp17_0 = A_01_1 + A_01_2;                              const double tmp18_0 = A_01_1 + A_10_1;
1863                              const register double tmp9_0 = A_01_0 + A_10_0;                              const double tmp15_0 = A_01_1 + A_10_2;
1864                              const register double tmp7_0 = A_01_0 + A_10_3;                              const double tmp16_0 = A_10_0 + A_10_3;
1865                              const register double tmp8_0 = A_01_1 + A_01_2 + A_10_1 + A_10_2;                              const double tmp17_0 = A_01_1 + A_01_2;
1866                              const register double tmp19_0 = A_01_2 + A_10_2;                              const double tmp19_0 = A_01_2 + A_10_2;
1867                              const register double tmp14_1 = A_10_0*w8;                              const double tmp0_1 = A_10_3*w8;
1868                              const register double tmp23_1 = tmp3_0*w14;                              const double tmp1_1 = tmp0_0*w1;
1869                              const register double tmp35_1 = A_01_0*w8;                              const double tmp2_1 = A_01_1*w4;
1870                              const register double tmp54_1 = tmp13_0*w8;                              const double tmp3_1 = tmp1_0*w0;
1871                              const register double tmp20_1 = tmp9_0*w4;                              const double tmp4_1 = A_01_2*w7;
1872                              const register double tmp25_1 = tmp12_0*w12;                              const double tmp5_1 = tmp2_0*w3;
1873                              const register double tmp2_1 = A_01_1*w4;                              const double tmp6_1 = tmp3_0*w6;
1874                              const register double tmp44_1 = tmp7_0*w7;                              const double tmp7_1 = A_10_0*w2;
1875                              const register double tmp26_1 = tmp10_0*w4;                              const double tmp8_1 = tmp4_0*w5;
1876                              const register double tmp52_1 = tmp18_0*w8;                              const double tmp9_1 = tmp2_0*w10;
1877                              const register double tmp48_1 = A_10_1*w7;                              const double tmp14_1 = A_10_0*w8;
1878                              const register double tmp46_1 = A_01_3*w8;                              const double tmp23_1 = tmp3_0*w14;
1879                              const register double tmp50_1 = A_01_0*w2;                              const double tmp35_1 = A_01_0*w8;
1880                              const register double tmp8_1 = tmp4_0*w5;                              const double tmp54_1 = tmp13_0*w8;
1881                              const register double tmp56_1 = tmp19_0*w8;                              const double tmp20_1 = tmp9_0*w4;
1882                              const register double tmp9_1 = tmp2_0*w10;                              const double tmp25_1 = tmp12_0*w12;
1883                              const register double tmp19_1 = A_10_3*w2;                              const double tmp44_1 = tmp7_0*w7;
1884                              const register double tmp47_1 = A_10_2*w4;                              const double tmp26_1 = tmp10_0*w4;
1885                              const register double tmp16_1 = tmp3_0*w0;                              const double tmp52_1 = tmp18_0*w8;
1886                              const register double tmp18_1 = tmp1_0*w6;                              const double tmp48_1 = A_10_1*w7;
1887                              const register double tmp31_1 = tmp11_0*w12;                              const double tmp46_1 = A_01_3*w8;
1888                              const register double tmp55_1 = tmp15_0*w2;                              const double tmp50_1 = A_01_0*w2;
1889                              const register double tmp39_1 = A_10_2*w7;                              const double tmp56_1 = tmp19_0*w8;
1890                              const register double tmp11_1 = tmp6_0*w7;                              const double tmp19_1 = A_10_3*w2;
1891                              const register double tmp40_1 = tmp11_0*w17;                              const double tmp47_1 = A_10_2*w4;
1892                              const register double tmp34_1 = tmp15_0*w8;                              const double tmp16_1 = tmp3_0*w0;
1893                              const register double tmp33_1 = tmp14_0*w5;                              const double tmp18_1 = tmp1_0*w6;
1894                              const register double tmp24_1 = tmp11_0*w13;                              const double tmp31_1 = tmp11_0*w12;
1895                              const register double tmp3_1 = tmp1_0*w0;                              const double tmp55_1 = tmp15_0*w2;
1896                              const register double tmp5_1 = tmp2_0*w3;                              const double tmp39_1 = A_10_2*w7;
1897                              const register double tmp43_1 = tmp17_0*w5;                              const double tmp11_1 = tmp6_0*w7;
1898                              const register double tmp15_1 = A_01_2*w4;                              const double tmp40_1 = tmp11_0*w17;
1899                              const register double tmp53_1 = tmp19_0*w2;                              const double tmp34_1 = tmp15_0*w8;
1900                              const register double tmp27_1 = tmp3_0*w11;                              const double tmp33_1 = tmp14_0*w5;
1901                              const register double tmp32_1 = tmp13_0*w2;                              const double tmp24_1 = tmp11_0*w13;
1902                              const register double tmp10_1 = tmp5_0*w9;                              const double tmp43_1 = tmp17_0*w5;
1903                              const register double tmp37_1 = A_10_1*w4;                              const double tmp15_1 = A_01_2*w4;
1904                              const register double tmp38_1 = tmp5_0*w15;                              const double tmp53_1 = tmp19_0*w2;
1905                              const register double tmp17_1 = A_01_1*w7;                              const double tmp27_1 = tmp3_0*w11;
1906                              const register double tmp12_1 = tmp7_0*w4;                              const double tmp32_1 = tmp13_0*w2;
1907                              const register double tmp22_1 = tmp10_0*w7;                              const double tmp10_1 = tmp5_0*w9;
1908                              const register double tmp57_1 = tmp18_0*w2;                              const double tmp37_1 = A_10_1*w4;
1909                              const register double tmp28_1 = tmp9_0*w7;                              const double tmp38_1 = tmp5_0*w15;
1910                              const register double tmp29_1 = tmp1_0*w14;                              const double tmp17_1 = A_01_1*w7;
1911                              const register double tmp51_1 = tmp11_0*w16;                              const double tmp12_1 = tmp7_0*w4;
1912                              const register double tmp42_1 = tmp12_0*w16;                              const double tmp22_1 = tmp10_0*w7;
1913                              const register double tmp49_1 = tmp12_0*w17;                              const double tmp57_1 = tmp18_0*w2;
1914                              const register double tmp21_1 = tmp1_0*w11;                              const double tmp28_1 = tmp9_0*w7;
1915                              const register double tmp1_1 = tmp0_0*w1;                              const double tmp29_1 = tmp1_0*w14;
1916                              const register double tmp45_1 = tmp6_0*w4;                              const double tmp51_1 = tmp11_0*w16;
1917                              const register double tmp7_1 = A_10_0*w2;                              const double tmp42_1 = tmp12_0*w16;
1918                              const register double tmp6_1 = tmp3_0*w6;                              const double tmp49_1 = tmp12_0*w17;
1919                              const register double tmp13_1 = tmp8_0*w1;                              const double tmp21_1 = tmp1_0*w11;
1920                              const register double tmp36_1 = tmp16_0*w1;                              const double tmp45_1 = tmp6_0*w4;
1921                              const register double tmp41_1 = A_01_3*w2;                              const double tmp13_1 = tmp8_0*w1;
1922                              const register double tmp30_1 = tmp12_0*w13;                              const double tmp36_1 = tmp16_0*w1;
1923                              const register double tmp4_1 = A_01_2*w7;                              const double tmp41_1 = A_01_3*w2;
1924                              const register double tmp0_1 = A_10_3*w8;                              const double tmp30_1 = tmp12_0*w13;
                             EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1 + tmp4_1 + tmp5_1 + tmp6_1 + tmp7_1 + tmp8_1;  
                             EM_S[INDEX2(1,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1 + tmp9_1;  
                             EM_S[INDEX2(3,2,4)]+=tmp14_1 + tmp15_1 + tmp16_1 + tmp17_1 + tmp18_1 + tmp19_1 + tmp1_1 + tmp5_1 + tmp8_1;  
1925                              EM_S[INDEX2(0,0,4)]+=tmp13_1 + tmp20_1 + tmp21_1 + tmp22_1 + tmp23_1 + tmp24_1 + tmp25_1;                              EM_S[INDEX2(0,0,4)]+=tmp13_1 + tmp20_1 + tmp21_1 + tmp22_1 + tmp23_1 + tmp24_1 + tmp25_1;
1926                              EM_S[INDEX2(3,3,4)]+=tmp13_1 + tmp26_1 + tmp27_1 + tmp28_1 + tmp29_1 + tmp30_1 + tmp31_1;                              EM_S[INDEX2(1,0,4)]+=tmp36_1 + tmp37_1 + tmp39_1 + tmp3_1 + tmp43_1 + tmp46_1 + tmp50_1 + tmp5_1 + tmp6_1;
1927                                EM_S[INDEX2(2,0,4)]+=tmp0_1 + tmp15_1 + tmp17_1 + tmp1_1 + tmp38_1 + tmp49_1 + tmp51_1 + tmp7_1 + tmp8_1;
1928                              EM_S[INDEX2(3,0,4)]+=tmp10_1 + tmp32_1 + tmp33_1 + tmp34_1 + tmp9_1;                              EM_S[INDEX2(3,0,4)]+=tmp10_1 + tmp32_1 + tmp33_1 + tmp34_1 + tmp9_1;
1929                              EM_S[INDEX2(3,1,4)]+=tmp35_1 + tmp36_1 + tmp37_1 + tmp38_1 + tmp39_1 + tmp40_1 + tmp41_1 + tmp42_1 + tmp43_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1 + tmp4_1 + tmp5_1 + tmp6_1 + tmp7_1 + tmp8_1;
1930                                EM_S[INDEX2(1,1,4)]+=tmp21_1 + tmp23_1 + tmp30_1 + tmp31_1 + tmp33_1 + tmp56_1 + tmp57_1;
1931                              EM_S[INDEX2(2,1,4)]+=tmp10_1 + tmp13_1 + tmp44_1 + tmp45_1 + tmp9_1;                              EM_S[INDEX2(2,1,4)]+=tmp10_1 + tmp13_1 + tmp44_1 + tmp45_1 + tmp9_1;
1932                                EM_S[INDEX2(3,1,4)]+=tmp35_1 + tmp36_1 + tmp37_1 + tmp38_1 + tmp39_1 + tmp40_1 + tmp41_1 + tmp42_1 + tmp43_1;
1933                              EM_S[INDEX2(0,2,4)]+=tmp36_1 + tmp38_1 + tmp43_1 + tmp46_1 + tmp47_1 + tmp48_1 + tmp49_1 + tmp50_1 + tmp51_1;                              EM_S[INDEX2(0,2,4)]+=tmp36_1 + tmp38_1 + tmp43_1 + tmp46_1 + tmp47_1 + tmp48_1 + tmp49_1 + tmp50_1 + tmp51_1;
1934                              EM_S[INDEX2(2,0,4)]+=tmp0_1 + tmp15_1 + tmp17_1 + tmp1_1 + tmp38_1 + tmp49_1 + tmp51_1 + tmp7_1 + tmp8_1;                              EM_S[INDEX2(1,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1 + tmp9_1;
                             EM_S[INDEX2(1,3,4)]+=tmp14_1 + tmp19_1 + tmp1_1 + tmp2_1 + tmp38_1 + tmp40_1 + tmp42_1 + tmp4_1 + tmp8_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp16_1 + tmp18_1 + tmp35_1 + tmp36_1 + tmp41_1 + tmp43_1 + tmp47_1 + tmp48_1 + tmp5_1;  
1935                              EM_S[INDEX2(2,2,4)]+=tmp24_1 + tmp25_1 + tmp27_1 + tmp29_1 + tmp33_1 + tmp52_1 + tmp53_1;                              EM_S[INDEX2(2,2,4)]+=tmp24_1 + tmp25_1 + tmp27_1 + tmp29_1 + tmp33_1 + tmp52_1 + tmp53_1;
1936                              EM_S[INDEX2(1,0,4)]+=tmp36_1 + tmp37_1 + tmp39_1 + tmp3_1 + tmp43_1 + tmp46_1 + tmp50_1 + tmp5_1 + tmp6_1;                              EM_S[INDEX2(3,2,4)]+=tmp14_1 + tmp15_1 + tmp16_1 + tmp17_1 + tmp18_1 + tmp19_1 + tmp1_1 + tmp5_1 + tmp8_1;
1937                              EM_S[INDEX2(0,3,4)]+=tmp10_1 + tmp33_1 + tmp54_1 + tmp55_1 + tmp9_1;                              EM_S[INDEX2(0,3,4)]+=tmp10_1 + tmp33_1 + tmp54_1 + tmp55_1 + tmp9_1;
1938                              EM_S[INDEX2(1,1,4)]+=tmp21_1 + tmp23_1 + tmp30_1 + tmp31_1 + tmp33_1 + tmp56_1 + tmp57_1;                              EM_S[INDEX2(1,3,4)]+=tmp14_1 + tmp19_1 + tmp1_1 + tmp2_1 + tmp38_1 + tmp40_1 + tmp42_1 + tmp4_1 + tmp8_1;
1939                          } else { /* constant data */                              EM_S[INDEX2(2,3,4)]+=tmp16_1 + tmp18_1 + tmp35_1 + tmp36_1 + tmp41_1 + tmp43_1 + tmp47_1 + tmp48_1 + tmp5_1;
1940                              const register double A_00 = A_p[INDEX2(0,0,2)];                              EM_S[INDEX2(3,3,4)]+=tmp13_1 + tmp26_1 + tmp27_1 + tmp28_1 + tmp29_1 + tmp30_1 + tmp31_1;
1941                              const register double A_01 = A_p[INDEX2(0,1,2)];                          } else { // constant data
1942                              const register double A_10 = A_p[INDEX2(1,0,2)];                              const double A_00 = A_p[INDEX2(0,0,2)];
1943                              const register double A_11 = A_p[INDEX2(1,1,2)];                              const double A_10 = A_p[INDEX2(1,0,2)];
1944                              const register double tmp0_0 = A_01 + A_10;                              const double A_01 = A_p[INDEX2(0,1,2)];
1945                              const register double tmp0_1 = A_00*w18;                              const double A_11 = A_p[INDEX2(1,1,2)];
1946                              const register double tmp10_1 = A_01*w20;                              const double tmp0_0 = A_01 + A_10;
1947                              const register double tmp12_1 = A_00*w26;                              const double tmp0_1 = A_00*w18;
1948                              const register double tmp4_1 = A_00*w22;                              const double tmp1_1 = A_01*w19;
1949                              const register double tmp8_1 = A_00*w24;                              const double tmp2_1 = A_10*w20;
1950                              const register double tmp13_1 = A_10*w19;                              const double tmp3_1 = A_11*w21;
1951                              const register double tmp9_1 = tmp0_0*w20;                              const double tmp4_1 = A_00*w22;
1952                              const register double tmp3_1 = A_11*w21;                              const double tmp5_1 = tmp0_0*w19;
1953                              const register double tmp11_1 = A_11*w27;                              const double tmp6_1 = A_11*w23;
1954                              const register double tmp1_1 = A_01*w19;                              const double tmp7_1 = A_11*w25;
1955                              const register double tmp6_1 = A_11*w23;                              const double tmp8_1 = A_00*w24;
1956                              const register double tmp7_1 = A_11*w25;                              const double tmp9_1 = tmp0_0*w20;
1957                              const register double tmp2_1 = A_10*w20;                              const double tmp10_1 = A_01*w20;
1958                              const register double tmp5_1 = tmp0_0*w19;                              const double tmp11_1 = A_11*w27;
1959                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;                              const double tmp12_1 = A_00*w26;
1960                              EM_S[INDEX2(1,2,4)]+=tmp4_1 + tmp5_1 + tmp6_1;                              const double tmp13_1 = A_10*w19;
                             EM_S[INDEX2(3,2,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;  
1961                              EM_S[INDEX2(0,0,4)]+=tmp5_1 + tmp7_1 + tmp8_1;                              EM_S[INDEX2(0,0,4)]+=tmp5_1 + tmp7_1 + tmp8_1;
1962                              EM_S[INDEX2(3,3,4)]+=tmp5_1 + tmp7_1 + tmp8_1;                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp10_1 + tmp13_1 + tmp3_1;
1963                                EM_S[INDEX2(2,0,4)]+=tmp11_1 + tmp12_1 + tmp1_1 + tmp2_1;
1964                              EM_S[INDEX2(3,0,4)]+=tmp4_1 + tmp6_1 + tmp9_1;                              EM_S[INDEX2(3,0,4)]+=tmp4_1 + tmp6_1 + tmp9_1;
1965                              EM_S[INDEX2(3,1,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;
1966                                EM_S[INDEX2(1,1,4)]+=tmp7_1 + tmp8_1 + tmp9_1;
1967                              EM_S[INDEX2(2,1,4)]+=tmp4_1 + tmp5_1 + tmp6_1;                              EM_S[INDEX2(2,1,4)]+=tmp4_1 + tmp5_1 + tmp6_1;
1968                                EM_S[INDEX2(3,1,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1;
1969                              EM_S[INDEX2(0,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1;                              EM_S[INDEX2(0,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1;
1970                              EM_S[INDEX2(2,0,4)]+=tmp11_1 + tmp12_1 + tmp1_1 + tmp2_1;                              EM_S[INDEX2(1,2,4)]+=tmp4_1 + tmp5_1 + tmp6_1;
                             EM_S[INDEX2(1,3,4)]+=tmp11_1 + tmp12_1 + tmp1_1 + tmp2_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp10_1 + tmp13_1 + tmp3_1;  
1971                              EM_S[INDEX2(2,2,4)]+=tmp7_1 + tmp8_1 + tmp9_1;                              EM_S[INDEX2(2,2,4)]+=tmp7_1 + tmp8_1 + tmp9_1;
1972                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp10_1 + tmp13_1 + tmp3_1;                              EM_S[INDEX2(3,2,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;
1973                              EM_S[INDEX2(0,3,4)]+=tmp4_1 + tmp6_1 + tmp9_1;                              EM_S[INDEX2(0,3,4)]+=tmp4_1 + tmp6_1 + tmp9_1;
1974                              EM_S[INDEX2(1,1,4)]+=tmp7_1 + tmp8_1 + tmp9_1;                              EM_S[INDEX2(1,3,4)]+=tmp11_1 + tmp12_1 + tmp1_1 + tmp2_1;
1975                                EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp10_1 + tmp13_1 + tmp3_1;
1976                                EM_S[INDEX2(3,3,4)]+=tmp5_1 + tmp7_1 + tmp8_1;
1977                          }                          }
1978                      }                      }
1979                      ///////////////                      ///////////////
# Line 1680  void Rectangle::assemblePDESingle(Paso_S Line 1983  void Rectangle::assemblePDESingle(Paso_S
1983                          add_EM_S=true;                          add_EM_S=true;
1984                          const double* B_p=const_cast<escript::Data*>(&B)->getSampleDataRO(e);                          const double* B_p=const_cast<escript::Data*>(&B)->getSampleDataRO(e);
1985                          if (B.actsExpanded()) {                          if (B.actsExpanded()) {
1986                              const register double B_0_0 = B_p[INDEX2(0,0,2)];                              const double B_0_0 = B_p[INDEX2(0,0,2)];
1987                              const register double B_1_0 = B_p[INDEX2(1,0,2)];                              const double B_1_0 = B_p[INDEX2(1,0,2)];
1988                              const register double B_0_1 = B_p[INDEX2(0,1,2)];                              const double B_0_1 = B_p[INDEX2(0,1,2)];
1989                              const register double B_1_1 = B_p[INDEX2(1,1,2)];                              const double B_1_1 = B_p[INDEX2(1,1,2)];
1990                              const register double B_0_2 = B_p[INDEX2(0,2,2)];                              const double B_0_2 = B_p[INDEX2(0,2,2)];
1991                              const register double B_1_2 = B_p[INDEX2(1,2,2)];                              const double B_1_2 = B_p[INDEX2(1,2,2)];
1992                              const register double B_0_3 = B_p[INDEX2(0,3,2)];                              const double B_0_3 = B_p[INDEX2(0,3,2)];
1993                              const register double B_1_3 = B_p[INDEX2(1,3,2)];                              const double B_1_3 = B_p[INDEX2(1,3,2)];
1994                              const register double tmp3_0 = B_0_0 + B_0_2;                              const double tmp0_0 = B_1_0 + B_1_1;
1995                              const register double tmp1_0 = B_1_2 + B_1_3;                              const double tmp1_0 = B_1_2 + B_1_3;
1996                              const register double tmp2_0 = B_0_1 + B_0_3;                              const double tmp2_0 = B_0_1 + B_0_3;
1997                              const register double tmp0_0 = B_1_0 + B_1_1;                              const double tmp3_0 = B_0_0 + B_0_2;
1998                              const register double tmp63_1 = B_1_1*w42;                              const double tmp63_1 = B_1_1*w42;
1999                              const register double tmp79_1 = B_1_1*w40;                              const double tmp79_1 = B_1_1*w40;
2000                              const register double tmp37_1 = tmp3_0*w35;                              const double tmp37_1 = tmp3_0*w35;
2001                              const register double tmp8_1 = tmp0_0*w32;                              const double tmp8_1 = tmp0_0*w32;
2002                              const register double tmp71_1 = B_0_1*w34;                              const double tmp71_1 = B_0_1*w34;
2003                              const register double tmp19_1 = B_0_3*w31;                              const double tmp19_1 = B_0_3*w31;
2004                              const register double tmp15_1 = B_0_3*w34;                              const double tmp15_1 = B_0_3*w34;
2005                              const register double tmp9_1 = tmp3_0*w34;                              const double tmp9_1 = tmp3_0*w34;
2006                              const register double tmp35_1 = B_1_0*w36;                              const double tmp35_1 = B_1_0*w36;
2007                              const register double tmp66_1 = B_0_3*w28;                              const double tmp66_1 = B_0_3*w28;
2008                              const register double tmp28_1 = B_1_0*w42;                              const double tmp28_1 = B_1_0*w42;
2009                              const register double tmp22_1 = B_1_0*w40;                              const double tmp22_1 = B_1_0*w40;
2010                              const register double tmp16_1 = B_1_2*w29;                              const double tmp16_1 = B_1_2*w29;
2011                              const register double tmp6_1 = tmp2_0*w35;                              const double tmp6_1 = tmp2_0*w35;
2012                              const register double tmp55_1 = B_1_3*w40;                              const double tmp55_1 = B_1_3*w40;
2013                              const register double tmp50_1 = B_1_3*w42;                              const double tmp50_1 = B_1_3*w42;
2014                              const register double tmp7_1 = tmp1_0*w29;                              const double tmp7_1 = tmp1_0*w29;
2015                              const register double tmp1_1 = tmp1_0*w32;                              const double tmp1_1 = tmp1_0*w32;
2016                              const register double tmp57_1 = B_0_3*w30;                              const double tmp57_1 = B_0_3*w30;
2017                              const register double tmp18_1 = B_1_1*w32;                              const double tmp18_1 = B_1_1*w32;
2018                              const register double tmp53_1 = B_1_0*w41;                              const double tmp53_1 = B_1_0*w41;
2019                              const register double tmp61_1 = B_1_3*w36;                              const double tmp61_1 = B_1_3*w36;
2020                              const register double tmp27_1 = B_0_3*w38;                              const double tmp27_1 = B_0_3*w38;
2021                              const register double tmp64_1 = B_0_2*w30;                              const double tmp64_1 = B_0_2*w30;
2022                              const register double tmp76_1 = B_0_1*w38;                              const double tmp76_1 = B_0_1*w38;
2023                              const register double tmp39_1 = tmp2_0*w34;                              const double tmp39_1 = tmp2_0*w34;
2024                              const register double tmp62_1 = B_0_1*w31;                              const double tmp62_1 = B_0_1*w31;
2025                              const register double tmp56_1 = B_0_0*w31;                              const double tmp56_1 = B_0_0*w31;
2026                              const register double tmp49_1 = B_1_1*w36;                              const double tmp49_1 = B_1_1*w36;
2027                              const register double tmp2_1 = B_0_2*w31;                              const double tmp2_1 = B_0_2*w31;
2028                              const register double tmp23_1 = B_0_2*w33;                              const double tmp23_1 = B_0_2*w33;
2029                              const register double tmp38_1 = B_1_1*w43;                              const double tmp38_1 = B_1_1*w43;
2030                              const register double tmp74_1 = B_1_2*w41;                              const double tmp74_1 = B_1_2*w41;
2031                              const register double tmp43_1 = B_1_1*w41;                              const double tmp43_1 = B_1_1*w41;
2032                              const register double tmp58_1 = B_0_2*w28;                              const double tmp58_1 = B_0_2*w28;
2033                              const register double tmp67_1 = B_0_0*w33;                              const double tmp67_1 = B_0_0*w33;
2034                              const register double tmp33_1 = tmp0_0*w39;                              const double tmp33_1 = tmp0_0*w39;
2035                              const register double tmp4_1 = B_0_0*w28;                              const double tmp4_1 = B_0_0*w28;
2036                              const register double tmp20_1 = B_0_0*w30;                              const double tmp20_1 = B_0_0*w30;
2037                              const register double tmp13_1 = B_0_2*w38;                              const double tmp13_1 = B_0_2*w38;
2038                              const register double tmp65_1 = B_1_2*w43;                              const double tmp65_1 = B_1_2*w43;
2039                              const register double tmp0_1 = tmp0_0*w29;                              const double tmp0_1 = tmp0_0*w29;
2040                              const register double tmp41_1 = tmp3_0*w33;                              const double tmp41_1 = tmp3_0*w33;
2041                              const register double tmp73_1 = B_0_2*w37;                              const double tmp73_1 = B_0_2*w37;
2042                              const register double tmp69_1 = B_0_0*w38;                              const double tmp69_1 = B_0_0*w38;
2043                              const register double tmp48_1 = B_1_2*w39;                              const double tmp48_1 = B_1_2*w39;
2044                              const register double tmp59_1 = B_0_1*w33;                              const double tmp59_1 = B_0_1*w33;
2045                              const register double tmp17_1 = B_1_3*w41;                              const double tmp17_1 = B_1_3*w41;
2046                              const register double tmp5_1 = B_0_3*w33;                              const double tmp5_1 = B_0_3*w33;
2047                              const register double tmp3_1 = B_0_1*w30;                              const double tmp3_1 = B_0_1*w30;
2048                              const register double tmp21_1 = B_0_1*w28;                              const double tmp21_1 = B_0_1*w28;
2049                              const register double tmp42_1 = B_1_0*w29;                              const double tmp42_1 = B_1_0*w29;
2050                              const register double tmp54_1 = B_1_2*w32;                              const double tmp54_1 = B_1_2*w32;
2051                              const register double tmp60_1 = B_1_0*w39;                              const double tmp60_1 = B_1_0*w39;
2052                              const register double tmp32_1 = tmp1_0*w36;                              const double tmp32_1 = tmp1_0*w36;
2053                              const register double tmp10_1 = B_0_1*w37;                              const double tmp10_1 = B_0_1*w37;
2054                              const register double tmp14_1 = B_0_0*w35;                              const double tmp14_1 = B_0_0*w35;
2055                              const register double tmp29_1 = B_0_1*w35;                              const double tmp29_1 = B_0_1*w35;
2056                              const register double tmp26_1 = B_1_2*w36;                              const double tmp26_1 = B_1_2*w36;
2057                              const register double tmp30_1 = B_1_3*w43;                              const double tmp30_1 = B_1_3*w43;
2058                              const register double tmp70_1 = B_0_2*w35;                              const double tmp70_1 = B_0_2*w35;
2059                              const register double tmp34_1 = B_1_3*w39;                              const double tmp34_1 = B_1_3*w39;
2060                              const register double tmp51_1 = B_1_0*w43;                              const double tmp51_1 = B_1_0*w43;
2061                              const register double tmp31_1 = B_0_2*w34;                              const double tmp31_1 = B_0_2*w34;
2062                              const register double tmp45_1 = tmp3_0*w28;                              const double tmp45_1 = tmp3_0*w28;
2063                              const register double tmp11_1 = tmp1_0*w39;                              const double tmp11_1 = tmp1_0*w39;
2064                              const register double tmp52_1 = B_1_1*w29;                              const double tmp52_1 = B_1_1*w29;
2065                              const register double tmp44_1 = B_1_3*w32;                              const double tmp44_1 = B_1_3*w32;
2066                              const register double tmp25_1 = B_1_1*w39;                              const double tmp25_1 = B_1_1*w39;
2067                              const register double tmp47_1 = tmp2_0*w33;                              const double tmp47_1 = tmp2_0*w33;
2068                              const register double tmp72_1 = B_1_3*w29;                              const double tmp72_1 = B_1_3*w29;
2069                              const register double tmp40_1 = tmp2_0*w28;                              const double tmp40_1 = tmp2_0*w28;
2070                              const register double tmp46_1 = B_1_2*w40;                              const double tmp46_1 = B_1_2*w40;
2071                              const register double tmp36_1 = B_1_2*w42;                              const double tmp36_1 = B_1_2*w42;
2072                              const register double tmp24_1 = B_0_0*w37;                              const double tmp24_1 = B_0_0*w37;
2073                              const register double tmp77_1 = B_0_3*w35;                              const double tmp77_1 = B_0_3*w35;
2074                              const register double tmp68_1 = B_0_3*w37;                              const double tmp68_1 = B_0_3*w37;
2075                              const register double tmp78_1 = B_0_0*w34;                              const double tmp78_1 = B_0_0*w34;
2076                              const register double tmp12_1 = tmp0_0*w36;                              const double tmp12_1 = tmp0_0*w36;
2077                              const register double tmp75_1 = B_1_0*w32;                              const double tmp75_1 = B_1_0*w32;
                             EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1 + tmp4_1 + tmp5_1;  
                             EM_S[INDEX2(1,2,4)]+=tmp6_1 + tmp7_1 + tmp8_1 + tmp9_1;  
                             EM_S[INDEX2(3,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1 + tmp14_1 + tmp15_1;  
2078                              EM_S[INDEX2(0,0,4)]+=tmp16_1 + tmp17_1 + tmp18_1 + tmp19_1 + tmp20_1 + tmp21_1 + tmp22_1 + tmp23_1;                              EM_S[INDEX2(0,0,4)]+=tmp16_1 + tmp17_1 + tmp18_1 + tmp19_1 + tmp20_1 + tmp21_1 + tmp22_1 + tmp23_1;
2079                              EM_S[INDEX2(3,3,4)]+=tmp24_1 + tmp25_1 + tmp26_1 + tmp27_1 + tmp28_1 + tmp29_1 + tmp30_1 + tmp31_1;                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp1_1 + tmp68_1 + tmp69_1 + tmp70_1 + tmp71_1;
2080                                EM_S[INDEX2(2,0,4)]+=tmp45_1 + tmp47_1 + tmp48_1 + tmp49_1 + tmp50_1 + tmp51_1;
2081                              EM_S[INDEX2(3,0,4)]+=tmp32_1 + tmp33_1 + tmp6_1 + tmp9_1;                              EM_S[INDEX2(3,0,4)]+=tmp32_1 + tmp33_1 + tmp6_1 + tmp9_1;
2082                              EM_S[INDEX2(3,1,4)]+=tmp34_1 + tmp35_1 + tmp36_1 + tmp37_1 + tmp38_1 + tmp39_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1 + tmp4_1 + tmp5_1;
2083                                EM_S[INDEX2(1,1,4)]+=tmp72_1 + tmp73_1 + tmp74_1 + tmp75_1 + tmp76_1 + tmp77_1 + tmp78_1 + tmp79_1;
2084                              EM_S[INDEX2(2,1,4)]+=tmp32_1 + tmp33_1 + tmp40_1 + tmp41_1;                              EM_S[INDEX2(2,1,4)]+=tmp32_1 + tmp33_1 + tmp40_1 + tmp41_1;
2085                                EM_S[INDEX2(3,1,4)]+=tmp34_1 + tmp35_1 + tmp36_1 + tmp37_1 + tmp38_1 + tmp39_1;
2086                              EM_S[INDEX2(0,2,4)]+=tmp42_1 + tmp43_1 + tmp44_1 + tmp45_1 + tmp46_1 + tmp47_1;                              EM_S[INDEX2(0,2,4)]+=tmp42_1 + tmp43_1 + tmp44_1 + tmp45_1 + tmp46_1 + tmp47_1;
2087                              EM_S[INDEX2(2,0,4)]+=tmp45_1 + tmp47_1 + tmp48_1 + tmp49_1 + tmp50_1 + tmp51_1;                              EM_S[INDEX2(1,2,4)]+=tmp6_1 + tmp7_1 + tmp8_1 + tmp9_1;
                             EM_S[INDEX2(1,3,4)]+=tmp37_1 + tmp39_1 + tmp52_1 + tmp53_1 + tmp54_1 + tmp55_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp11_1 + tmp12_1 + tmp56_1 + tmp57_1 + tmp58_1 + tmp59_1;  
2088                              EM_S[INDEX2(2,2,4)]+=tmp60_1 + tmp61_1 + tmp62_1 + tmp63_1 + tmp64_1 + tmp65_1 + tmp66_1 + tmp67_1;                              EM_S[INDEX2(2,2,4)]+=tmp60_1 + tmp61_1 + tmp62_1 + tmp63_1 + tmp64_1 + tmp65_1 + tmp66_1 + tmp67_1;
2089                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp1_1 + tmp68_1 + tmp69_1 + tmp70_1 + tmp71_1;                              EM_S[INDEX2(3,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1 + tmp14_1 + tmp15_1;
2090                              EM_S[INDEX2(0,3,4)]+=tmp40_1 + tmp41_1 + tmp7_1 + tmp8_1;                              EM_S[INDEX2(0,3,4)]+=tmp40_1 + tmp41_1 + tmp7_1 + tmp8_1;
2091                              EM_S[INDEX2(1,1,4)]+=tmp72_1 + tmp73_1 + tmp74_1 + tmp75_1 + tmp76_1 + tmp77_1 + tmp78_1 + tmp79_1;                              EM_S[INDEX2(1,3,4)]+=tmp37_1 + tmp39_1 + tmp52_1 + tmp53_1 + tmp54_1 + tmp55_1;
2092                          } else { /* constant data */                              EM_S[INDEX2(2,3,4)]+=tmp11_1 + tmp12_1 + tmp56_1 + tmp57_1 + tmp58_1 + tmp59_1;
2093                              const register double B_0 = B_p[0];                              EM_S[INDEX2(3,3,4)]+=tmp24_1 + tmp25_1 + tmp26_1 + tmp27_1 + tmp28_1 + tmp29_1 + tmp30_1 + tmp31_1;
2094                              const register double B_1 = B_p[1];                          } else { // constant data
2095                              const register double tmp6_1 = B_1*w50;                              const double B_0 = B_p[0];
2096                              const register double tmp1_1 = B_1*w45;                              const double B_1 = B_p[1];
2097                              const register double tmp5_1 = B_1*w49;                              const double tmp0_1 = B_0*w44;
2098                              const register double tmp4_1 = B_1*w48;                              const double tmp1_1 = B_1*w45;
2099                              const register double tmp0_1 = B_0*w44;                              const double tmp2_1 = B_0*w46;
2100                              const register double tmp2_1 = B_0*w46;                              const double tmp3_1 = B_0*w47;
2101                              const register double tmp7_1 = B_0*w51;                              const double tmp4_1 = B_1*w48;
2102                              const register double tmp3_1 = B_0*w47;                              const double tmp5_1 = B_1*w49;
2103                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;                              const double tmp6_1 = B_1*w50;
2104                              EM_S[INDEX2(1,2,4)]+=tmp1_1 + tmp2_1;                              const double tmp7_1 = B_0*w51;
                             EM_S[INDEX2(3,2,4)]+=tmp3_1 + tmp4_1;  
2105                              EM_S[INDEX2(0,0,4)]+=tmp0_1 + tmp5_1;                              EM_S[INDEX2(0,0,4)]+=tmp0_1 + tmp5_1;
2106                              EM_S[INDEX2(3,3,4)]+=tmp3_1 + tmp6_1;                              EM_S[INDEX2(1,0,4)]+=tmp1_1 + tmp3_1;
2107                                EM_S[INDEX2(2,0,4)]+=tmp6_1 + tmp7_1;
2108                              EM_S[INDEX2(3,0,4)]+=tmp2_1 + tmp4_1;                              EM_S[INDEX2(3,0,4)]+=tmp2_1 + tmp4_1;
2109                              EM_S[INDEX2(3,1,4)]+=tmp2_1 + tmp6_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;
2110                                EM_S[INDEX2(1,1,4)]+=tmp3_1 + tmp5_1;
2111                              EM_S[INDEX2(2,1,4)]+=tmp4_1 + tmp7_1;                              EM_S[INDEX2(2,1,4)]+=tmp4_1 + tmp7_1;
2112                                EM_S[INDEX2(3,1,4)]+=tmp2_1 + tmp6_1;
2113                              EM_S[INDEX2(0,2,4)]+=tmp5_1 + tmp7_1;                              EM_S[INDEX2(0,2,4)]+=tmp5_1 + tmp7_1;
2114                              EM_S[INDEX2(2,0,4)]+=tmp6_1 + tmp7_1;                              EM_S[INDEX2(1,2,4)]+=tmp1_1 + tmp2_1;
                             EM_S[INDEX2(1,3,4)]+=tmp2_1 + tmp5_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp4_1;  
2115                              EM_S[INDEX2(2,2,4)]+=tmp0_1 + tmp6_1;                              EM_S[INDEX2(2,2,4)]+=tmp0_1 + tmp6_1;
2116                              EM_S[INDEX2(1,0,4)]+=tmp1_1 + tmp3_1;                              EM_S[INDEX2(3,2,4)]+=tmp3_1 + tmp4_1;
2117                              EM_S[INDEX2(0,3,4)]+=tmp1_1 + tmp7_1;                              EM_S[INDEX2(0,3,4)]+=tmp1_1 + tmp7_1;
2118                              EM_S[INDEX2(1,1,4)]+=tmp3_1 + tmp5_1;                              EM_S[INDEX2(1,3,4)]+=tmp2_1 + tmp5_1;
2119                                EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp4_1;
2120                                EM_S[INDEX2(3,3,4)]+=tmp3_1 + tmp6_1;
2121                          }                          }
2122                      }                      }
2123                      ///////////////                      ///////////////
# Line 1824  void Rectangle::assemblePDESingle(Paso_S Line 2127  void Rectangle::assemblePDESingle(Paso_S
2127                          add_EM_S=true;                          add_EM_S=true;
2128                          const double* C_p=const_cast<escript::Data*>(&C)->getSampleDataRO(e);                          const double* C_p=const_cast<escript::Data*>(&C)->getSampleDataRO(e);
2129                          if (C.actsExpanded()) {                          if (C.actsExpanded()) {
2130                              const register double C_0_0 = C_p[INDEX2(0,0,2)];                              const double C_0_0 = C_p[INDEX2(0,0,2)];
2131                              const register double C_1_0 = C_p[INDEX2(1,0,2)];                              const double C_1_0 = C_p[INDEX2(1,0,2)];
2132                              const register double C_0_1 = C_p[INDEX2(0,1,2)];                              const double C_0_1 = C_p[INDEX2(0,1,2)];
2133                              const register double C_1_1 = C_p[INDEX2(1,1,2)];                              const double C_1_1 = C_p[INDEX2(1,1,2)];
2134                              const register double C_0_2 = C_p[INDEX2(0,2,2)];                              const double C_0_2 = C_p[INDEX2(0,2,2)];
2135                              const register double C_1_2 = C_p[INDEX2(1,2,2)];                              const double C_1_2 = C_p[INDEX2(1,2,2)];
2136                              const register double C_0_3 = C_p[INDEX2(0,3,2)];                              const double C_0_3 = C_p[INDEX2(0,3,2)];
2137                              const register double C_1_3 = C_p[INDEX2(1,3,2)];                              const double C_1_3 = C_p[INDEX2(1,3,2)];
2138                              const register double tmp2_0 = C_0_1 + C_0_3;                              const double tmp0_0 = C_1_0 + C_1_1;
2139                              const register double tmp1_0 = C_1_2 + C_1_3;                              const double tmp1_0 = C_1_2 + C_1_3;
2140                              const register double tmp3_0 = C_0_0 + C_0_2;                              const double tmp2_0 = C_0_1 + C_0_3;
2141                              const register double tmp0_0 = C_1_0 + C_1_1;                              const double tmp3_0 = C_0_0 + C_0_2;
2142                              const register double tmp64_1 = C_0_2*w30;                              const double tmp64_1 = C_0_2*w30;
2143                              const register double tmp14_1 = C_0_2*w28;                              const double tmp14_1 = C_0_2*w28;
2144                              const register double tmp19_1 = C_0_3*w31;                              const double tmp19_1 = C_0_3*w31;
2145                              const register double tmp22_1 = C_1_0*w40;                              const double tmp22_1 = C_1_0*w40;
2146                              const register double tmp37_1 = tmp3_0*w35;                              const double tmp37_1 = tmp3_0*w35;
2147                              const register double tmp29_1 = C_0_1*w35;                              const double tmp29_1 = C_0_1*w35;
2148                              const register double tmp73_1 = C_0_2*w37;                              const double tmp73_1 = C_0_2*w37;
2149                              const register double tmp74_1 = C_1_2*w41;                              const double tmp74_1 = C_1_2*w41;
2150                              const register double tmp52_1 = C_1_3*w39;                              const double tmp52_1 = C_1_3*w39;
2151                              const register double tmp25_1 = C_1_1*w39;                              const double tmp25_1 = C_1_1*w39;
2152                              const register double tmp62_1 = C_0_1*w31;                              const double tmp62_1 = C_0_1*w31;
2153                              const register double tmp79_1 = C_1_1*w40;                              const double tmp79_1 = C_1_1*w40;
2154                              const register double tmp43_1 = C_1_1*w36;                              const double tmp43_1 = C_1_1*w36;
2155                              const register double tmp27_1 = C_0_3*w38;                              const double tmp27_1 = C_0_3*w38;
2156                              const register double tmp28_1 = C_1_0*w42;                              const double tmp28_1 = C_1_0*w42;
2157                              const register double tmp63_1 = C_1_1*w42;                              const double tmp63_1 = C_1_1*w42;
2158                              const register double tmp59_1 = C_0_3*w34;                              const double tmp59_1 = C_0_3*w34;
2159                              const register double tmp72_1 = C_1_3*w29;                              const double tmp72_1 = C_1_3*w29;
2160                              const register double tmp40_1 = tmp2_0*w35;                              const double tmp40_1 = tmp2_0*w35;
2161                              const register double tmp13_1 = C_0_3*w30;                              const double tmp13_1 = C_0_3*w30;
2162                              const register double tmp51_1 = C_1_2*w40;                              const double tmp51_1 = C_1_2*w40;
2163                              const register double tmp54_1 = C_1_2*w42;                              const double tmp54_1 = C_1_2*w42;
2164                              const register double tmp12_1 = C_0_0*w31;                              const double tmp12_1 = C_0_0*w31;
2165                              const register double tmp2_1 = tmp1_0*w32;                              const double tmp2_1 = tmp1_0*w32;
2166                              const register double tmp68_1 = C_0_2*w31;                              const double tmp68_1 = C_0_2*w31;
2167                              const register double tmp75_1 = C_1_0*w32;                              const double tmp75_1 = C_1_0*w32;
2168                              const register double tmp49_1 = C_1_1*w41;                              const double tmp49_1 = C_1_1*w41;
2169                              const register double tmp4_1 = C_0_2*w35;                              const double tmp4_1 = C_0_2*w35;
2170                              const register double tmp66_1 = C_0_3*w28;                              const double tmp66_1 = C_0_3*w28;
2171                              const register double tmp56_1 = C_0_1*w37;                              const double tmp56_1 = C_0_1*w37;
2172                              const register double tmp5_1 = C_0_1*w34;                              const double tmp5_1 = C_0_1*w34;
2173                              const register double tmp38_1 = tmp2_0*w34;                              const double tmp38_1 = tmp2_0*w34;
2174                              const register double tmp76_1 = C_0_1*w38;                              const double tmp76_1 = C_0_1*w38;
2175                              const register double tmp21_1 = C_0_1*w28;                              const double tmp21_1 = C_0_1*w28;
2176                              const register double tmp69_1 = C_0_1*w30;                              const double tmp69_1 = C_0_1*w30;
2177                              const register double tmp53_1 = C_1_0*w36;                              const double tmp53_1 = C_1_0*w36;
2178                              const register double tmp42_1 = C_1_2*w39;                              const double tmp42_1 = C_1_2*w39;
2179                              const register double tmp32_1 = tmp1_0*w29;                              const double tmp32_1 = tmp1_0*w29;
2180                              const register double tmp45_1 = C_1_0*w43;                              const double tmp45_1 = C_1_0*w43;
2181                              const register double tmp33_1 = tmp0_0*w32;                              const double tmp33_1 = tmp0_0*w32;
2182                              const register double tmp35_1 = C_1_0*w41;                              const double tmp35_1 = C_1_0*w41;
2183                              const register double tmp26_1 = C_1_2*w36;                              const double tmp26_1 = C_1_2*w36;
2184                              const register double tmp67_1 = C_0_0*w33;                              const double tmp67_1 = C_0_0*w33;
2185                              const register double tmp31_1 = C_0_2*w34;                              const double tmp31_1 = C_0_2*w34;
2186                              const register double tmp20_1 = C_0_0*w30;                              const double tmp20_1 = C_0_0*w30;
2187                              const register double tmp70_1 = C_0_0*w28;                              const double tmp70_1 = C_0_0*w28;
2188                              const register double tmp8_1 = tmp0_0*w39;                              const double tmp8_1 = tmp0_0*w39;
2189                              const register double tmp30_1 = C_1_3*w43;                              const double tmp30_1 = C_1_3*w43;
2190                              const register double tmp0_1 = tmp0_0*w29;                              const double tmp0_1 = tmp0_0*w29;
2191                              const register double tmp17_1 = C_1_3*w41;                              const double tmp17_1 = C_1_3*w41;
2192                              const register double tmp58_1 = C_0_0*w35;                              const double tmp58_1 = C_0_0*w35;
2193                              const register double tmp9_1 = tmp3_0*w33;                              const double tmp9_1 = tmp3_0*w33;
2194                              const register double tmp61_1 = C_1_3*w36;                              const double tmp61_1 = C_1_3*w36;
2195                              const register double tmp41_1 = tmp3_0*w34;                              const double tmp41_1 = tmp3_0*w34;
2196                              const register double tmp50_1 = C_1_3*w32;                              const double tmp50_1 = C_1_3*w32;
2197                              const register double tmp18_1 = C_1_1*w32;                              const double tmp18_1 = C_1_1*w32;
2198                              const register double tmp6_1 = tmp1_0*w36;                              const double tmp6_1 = tmp1_0*w36;
2199                              const register double tmp3_1 = C_0_0*w38;                              const double tmp3_1 = C_0_0*w38;
2200                              const register double tmp34_1 = C_1_1*w29;                              const double tmp34_1 = C_1_1*w29;
2201                              const register double tmp77_1 = C_0_3*w35;                              const double tmp77_1 = C_0_3*w35;
2202                              const register double tmp65_1 = C_1_2*w43;                              const double tmp65_1 = C_1_2*w43;
2203                              const register double tmp71_1 = C_0_3*w33;                              const double tmp71_1 = C_0_3*w33;
2204                              const register double tmp55_1 = C_1_1*w43;                              const double tmp55_1 = C_1_1*w43;
2205                              const register double tmp46_1 = tmp3_0*w28;                              const double tmp46_1 = tmp3_0*w28;
2206                              const register double tmp24_1 = C_0_0*w37;                              const double tmp24_1 = C_0_0*w37;
2207                              const register double tmp10_1 = tmp1_0*w39;                              const double tmp10_1 = tmp1_0*w39;
2208                              const register double tmp48_1 = C_1_0*w29;                              const double tmp48_1 = C_1_0*w29;
2209                              const register double tmp15_1 = C_0_1*w33;                              const double tmp15_1 = C_0_1*w33;
2210                              const register double tmp36_1 = C_1_2*w32;                              const double tmp36_1 = C_1_2*w32;
2211                              const register double tmp60_1 = C_1_0*w39;                              const double tmp60_1 = C_1_0*w39;
2212                              const register double tmp47_1 = tmp2_0*w33;                              const double tmp47_1 = tmp2_0*w33;
2213                              const register double tmp16_1 = C_1_2*w29;                              const double tmp16_1 = C_1_2*w29;
2214                              const register double tmp1_1 = C_0_3*w37;                              const double tmp1_1 = C_0_3*w37;
2215                              const register double tmp7_1 = tmp2_0*w28;                              const double tmp7_1 = tmp2_0*w28;
2216                              const register double tmp39_1 = C_1_3*w40;                              const double tmp39_1 = C_1_3*w40;
2217                              const register double tmp44_1 = C_1_3*w42;                              const double tmp44_1 = C_1_3*w42;
2218                              const register double tmp57_1 = C_0_2*w38;                              const double tmp57_1 = C_0_2*w38;
2219                              const register double tmp78_1 = C_0_0*w34;                              const double tmp78_1 = C_0_0*w34;
2220                              const register double tmp11_1 = tmp0_0*w36;                              const double tmp11_1 = tmp0_0*w36;
2221                              const register double tmp23_1 = C_0_2*w33;                              const double tmp23_1 = C_0_2*w33;
                             EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1 + tmp4_1 + tmp5_1;  
                             EM_S[INDEX2(1,2,4)]+=tmp6_1 + tmp7_1 + tmp8_1 + tmp9_1;  
                             EM_S[INDEX2(3,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1 + tmp14_1 + tmp15_1;  
2222                              EM_S[INDEX2(0,0,4)]+=tmp16_1 + tmp17_1 + tmp18_1 + tmp19_1 + tmp20_1 + tmp21_1 + tmp22_1 + tmp23_1;                              EM_S[INDEX2(0,0,4)]+=tmp16_1 + tmp17_1 + tmp18_1 + tmp19_1 + tmp20_1 + tmp21_1 + tmp22_1 + tmp23_1;
2223                              EM_S[INDEX2(3,3,4)]+=tmp24_1 + tmp25_1 + tmp26_1 + tmp27_1 + tmp28_1 + tmp29_1 + tmp30_1 + tmp31_1;                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp2_1 + tmp68_1 + tmp69_1 + tmp70_1 + tmp71_1;
2224                                EM_S[INDEX2(2,0,4)]+=tmp46_1 + tmp47_1 + tmp48_1 + tmp49_1 + tmp50_1 + tmp51_1;
2225                              EM_S[INDEX2(3,0,4)]+=tmp32_1 + tmp33_1 + tmp7_1 + tmp9_1;                              EM_S[INDEX2(3,0,4)]+=tmp32_1 + tmp33_1 + tmp7_1 + tmp9_1;
2226                              EM_S[INDEX2(3,1,4)]+=tmp34_1 + tmp35_1 + tmp36_1 + tmp37_1 + tmp38_1 + tmp39_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1 + tmp4_1 + tmp5_1;
2227                                EM_S[INDEX2(1,1,4)]+=tmp72_1 + tmp73_1 + tmp74_1 + tmp75_1 + tmp76_1 + tmp77_1 + tmp78_1 + tmp79_1;
2228                              EM_S[INDEX2(2,1,4)]+=tmp32_1 + tmp33_1 + tmp40_1 + tmp41_1;                              EM_S[INDEX2(2,1,4)]+=tmp32_1 + tmp33_1 + tmp40_1 + tmp41_1;
2229                                EM_S[INDEX2(3,1,4)]+=tmp34_1 + tmp35_1 + tmp36_1 + tmp37_1 + tmp38_1 + tmp39_1;
2230                              EM_S[INDEX2(0,2,4)]+=tmp42_1 + tmp43_1 + tmp44_1 + tmp45_1 + tmp46_1 + tmp47_1;                              EM_S[INDEX2(0,2,4)]+=tmp42_1 + tmp43_1 + tmp44_1 + tmp45_1 + tmp46_1 + tmp47_1;
2231                              EM_S[INDEX2(2,0,4)]+=tmp46_1 + tmp47_1 + tmp48_1 + tmp49_1 + tmp50_1 + tmp51_1;                              EM_S[INDEX2(1,2,4)]+=tmp6_1 + tmp7_1 + tmp8_1 + tmp9_1;
                             EM_S[INDEX2(1,3,4)]+=tmp37_1 + tmp38_1 + tmp52_1 + tmp53_1 + tmp54_1 + tmp55_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp10_1 + tmp11_1 + tmp56_1 + tmp57_1 + tmp58_1 + tmp59_1;  
2232                              EM_S[INDEX2(2,2,4)]+=tmp60_1 + tmp61_1 + tmp62_1 + tmp63_1 + tmp64_1 + tmp65_1 + tmp66_1 + tmp67_1;                              EM_S[INDEX2(2,2,4)]+=tmp60_1 + tmp61_1 + tmp62_1 + tmp63_1 + tmp64_1 + tmp65_1 + tmp66_1 + tmp67_1;
2233                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp2_1 + tmp68_1 + tmp69_1 + tmp70_1 + tmp71_1;                              EM_S[INDEX2(3,2,4)]+=tmp10_1 + tmp11_1 + tmp12_1 + tmp13_1 + tmp14_1 + tmp15_1;
2234                              EM_S[INDEX2(0,3,4)]+=tmp40_1 + tmp41_1 + tmp6_1 + tmp8_1;                              EM_S[INDEX2(0,3,4)]+=tmp40_1 + tmp41_1 + tmp6_1 + tmp8_1;
2235                              EM_S[INDEX2(1,1,4)]+=tmp72_1 + tmp73_1 + tmp74_1 + tmp75_1 + tmp76_1 + tmp77_1 + tmp78_1 + tmp79_1;                              EM_S[INDEX2(1,3,4)]+=tmp37_1 + tmp38_1 + tmp52_1 + tmp53_1 + tmp54_1 + tmp55_1;
2236                          } else { /* constant data */                              EM_S[INDEX2(2,3,4)]+=tmp10_1 + tmp11_1 + tmp56_1 + tmp57_1 + tmp58_1 + tmp59_1;
2237                              const register double C_0 = C_p[0];                              EM_S[INDEX2(3,3,4)]+=tmp24_1 + tmp25_1 + tmp26_1 + tmp27_1 + tmp28_1 + tmp29_1 + tmp30_1 + tmp31_1;
2238                              const register double C_1 = C_p[1];                          } else { // constant data
2239                              const register double tmp1_1 = C_1*w45;                              const double C_0 = C_p[0];
2240                              const register double tmp3_1 = C_0*w51;                              const double C_1 = C_p[1];
2241                              const register double tmp4_1 = C_0*w44;                              const double tmp0_1 = C_0*w47;
2242                              const register double tmp7_1 = C_0*w46;                              const double tmp1_1 = C_1*w45;
2243                              const register double tmp5_1 = C_1*w49;                              const double tmp2_1 = C_1*w48;
2244                              const register double tmp2_1 = C_1*w48;                              const double tmp3_1 = C_0*w51;
2245                              const register double tmp0_1 = C_0*w47;                              const double tmp4_1 = C_0*w44;
2246                              const register double tmp6_1 = C_1*w50;                              const double tmp5_1 = C_1*w49;
2247                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;                              const double tmp6_1 = C_1*w50;
2248                              EM_S[INDEX2(1,2,4)]+=tmp2_1 + tmp3_1;                              const double tmp7_1 = C_0*w46;
                             EM_S[INDEX2(3,2,4)]+=tmp2_1 + tmp4_1;  
2249                              EM_S[INDEX2(0,0,4)]+=tmp4_1 + tmp5_1;                              EM_S[INDEX2(0,0,4)]+=tmp4_1 + tmp5_1;
2250                              EM_S[INDEX2(3,3,4)]+=tmp0_1 + tmp6_1;                              EM_S[INDEX2(1,0,4)]+=tmp1_1 + tmp4_1;
2251                                EM_S[INDEX2(2,0,4)]+=tmp3_1 + tmp5_1;
2252                              EM_S[INDEX2(3,0,4)]+=tmp1_1 + tmp3_1;                              EM_S[INDEX2(3,0,4)]+=tmp1_1 + tmp3_1;
2253                              EM_S[INDEX2(3,1,4)]+=tmp5_1 + tmp7_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;
2254                                EM_S[INDEX2(1,1,4)]+=tmp0_1 + tmp5_1;
2255                              EM_S[INDEX2(2,1,4)]+=tmp1_1 + tmp7_1;                              EM_S[INDEX2(2,1,4)]+=tmp1_1 + tmp7_1;
2256                                EM_S[INDEX2(3,1,4)]+=tmp5_1 + tmp7_1;
2257                              EM_S[INDEX2(0,2,4)]+=tmp3_1 + tmp6_1;                              EM_S[INDEX2(0,2,4)]+=tmp3_1 + tmp6_1;
2258                              EM_S[INDEX2(2,0,4)]+=tmp3_1 + tmp5_1;                              EM_S[INDEX2(1,2,4)]+=tmp2_1 + tmp3_1;
                             EM_S[INDEX2(1,3,4)]+=tmp6_1 + tmp7_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp2_1;  
2259                              EM_S[INDEX2(2,2,4)]+=tmp4_1 + tmp6_1;                              EM_S[INDEX2(2,2,4)]+=tmp4_1 + tmp6_1;
2260                              EM_S[INDEX2(1,0,4)]+=tmp1_1 + tmp4_1;                              EM_S[INDEX2(3,2,4)]+=tmp2_1 + tmp4_1;
2261                              EM_S[INDEX2(0,3,4)]+=tmp2_1 + tmp7_1;                              EM_S[INDEX2(0,3,4)]+=tmp2_1 + tmp7_1;
2262                              EM_S[INDEX2(1,1,4)]+=tmp0_1 + tmp5_1;                              EM_S[INDEX2(1,3,4)]+=tmp6_1 + tmp7_1;
2263                                EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp2_1;
2264                                EM_S[INDEX2(3,3,4)]+=tmp0_1 + tmp6_1;
2265                          }                          }
2266                      }                      }
2267                      ///////////////                      ///////////////
# Line 1968  void Rectangle::assemblePDESingle(Paso_S Line 2271  void Rectangle::assemblePDESingle(Paso_S
2271                          add_EM_S=true;                          add_EM_S=true;
2272                          const double* D_p=const_cast<escript::Data*>(&D)->getSampleDataRO(e);                          const double* D_p=const_cast<escript::Data*>(&D)->getSampleDataRO(e);
2273                          if (D.actsExpanded()) {                          if (D.actsExpanded()) {
2274                              const register double D_0 = D_p[0];                              const double D_0 = D_p[0];
2275                              const register double D_1 = D_p[1];                              const double D_1 = D_p[1];
2276                              const register double D_2 = D_p[2];                              const double D_2 = D_p[2];
2277                              const register double D_3 = D_p[3];                              const double D_3 = D_p[3];
2278                              const register double tmp4_0 = D_1 + D_3;                              const double tmp0_0 = D_0 + D_1;
2279                              const register double tmp2_0 = D_0 + D_1 + D_2 + D_3;                              const double tmp1_0 = D_2 + D_3;
2280                              const register double tmp5_0 = D_0 + D_2;                              const double tmp2_0 = D_0 + D_1 + D_2 + D_3;
2281                              const register double tmp0_0 = D_0 + D_1;                              const double tmp3_0 = D_1 + D_2;
2282                              const register double tmp6_0 = D_0 + D_3;                              const double tmp4_0 = D_1 + D_3;
2283                              const register double tmp1_0 = D_2 + D_3;                              const double tmp5_0 = D_0 + D_2;
2284                              const register double tmp3_0 = D_1 + D_2;                              const double tmp6_0 = D_0 + D_3;
2285                              const register double tmp16_1 = D_1*w56;                              const double tmp0_1 = tmp0_0*w52;
2286                              const register double tmp14_1 = tmp6_0*w54;                              const double tmp1_1 = tmp1_0*w53;
2287                              const register double tmp8_1 = D_3*w55;                              const double tmp2_1 = tmp2_0*w54;
2288                              const register double tmp2_1 = tmp2_0*w54;                              const double tmp3_1 = tmp1_0*w52;
2289                              const register double tmp12_1 = tmp5_0*w52;                              const double tmp4_1 = tmp0_0*w53;
2290                              const register double tmp4_1 = tmp0_0*w53;                              const double tmp5_1 = tmp3_0*w54;
2291                              const register double tmp3_1 = tmp1_0*w52;                              const double tmp6_1 = D_0*w55;
2292                              const register double tmp13_1 = tmp4_0*w53;                              const double tmp7_1 = D_3*w56;
2293                              const register double tmp10_1 = tmp4_0*w52;                              const double tmp8_1 = D_3*w55;
2294                              const register double tmp1_1 = tmp1_0*w53;                              const double tmp9_1 = D_0*w56;
2295                              const register double tmp7_1 = D_3*w56;                              const double tmp10_1 = tmp4_0*w52;
2296                              const register double tmp0_1 = tmp0_0*w52;                              const double tmp11_1 = tmp5_0*w53;
2297                              const register double tmp11_1 = tmp5_0*w53;                              const double tmp12_1 = tmp5_0*w52;
2298                              const register double tmp9_1 = D_0*w56;                              const double tmp13_1 = tmp4_0*w53;
2299                              const register double tmp5_1 = tmp3_0*w54;                              const double tmp14_1 = tmp6_0*w54;
2300                              const register double tmp18_1 = D_2*w56;                              const double tmp15_1 = D_2*w55;
2301                              const register double tmp17_1 = D_1*w55;                              const double tmp16_1 = D_1*w56;
2302                              const register double tmp6_1 = D_0*w55;                              const double tmp17_1 = D_1*w55;
2303                              const register double tmp15_1 = D_2*w55;                              const double tmp18_1 = D_2*w56;
                             EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;  
                             EM_S[INDEX2(1,2,4)]+=tmp2_1;  
                             EM_S[INDEX2(3,2,4)]+=tmp3_1 + tmp4_1;  
2304                              EM_S[INDEX2(0,0,4)]+=tmp5_1 + tmp6_1 + tmp7_1;                              EM_S[INDEX2(0,0,4)]+=tmp5_1 + tmp6_1 + tmp7_1;
2305                              EM_S[INDEX2(3,3,4)]+=tmp5_1 + tmp8_1 + tmp9_1;                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp1_1;
2306                                EM_S[INDEX2(2,0,4)]+=tmp12_1 + tmp13_1;
2307                              EM_S[INDEX2(3,0,4)]+=tmp2_1;                              EM_S[INDEX2(3,0,4)]+=tmp2_1;
2308                              EM_S[INDEX2(3,1,4)]+=tmp10_1 + tmp11_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;
2309                                EM_S[INDEX2(1,1,4)]+=tmp14_1 + tmp17_1 + tmp18_1;
2310                              EM_S[INDEX2(2,1,4)]+=tmp2_1;                              EM_S[INDEX2(2,1,4)]+=tmp2_1;
2311                                EM_S[INDEX2(3,1,4)]+=tmp10_1 + tmp11_1;
2312                              EM_S[INDEX2(0,2,4)]+=tmp12_1 + tmp13_1;                              EM_S[INDEX2(0,2,4)]+=tmp12_1 + tmp13_1;
2313                              EM_S[INDEX2(2,0,4)]+=tmp12_1 + tmp13_1;                              EM_S[INDEX2(1,2,4)]+=tmp2_1;
                             EM_S[INDEX2(1,3,4)]+=tmp10_1 + tmp11_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp3_1 + tmp4_1;  
2314                              EM_S[INDEX2(2,2,4)]+=tmp14_1 + tmp15_1 + tmp16_1;                              EM_S[INDEX2(2,2,4)]+=tmp14_1 + tmp15_1 + tmp16_1;
2315                              EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp1_1;                              EM_S[INDEX2(3,2,4)]+=tmp3_1 + tmp4_1;
2316                              EM_S[INDEX2(0,3,4)]+=tmp2_1;                              EM_S[INDEX2(0,3,4)]+=tmp2_1;
2317                              EM_S[INDEX2(1,1,4)]+=tmp14_1 + tmp17_1 + tmp18_1;                              EM_S[INDEX2(1,3,4)]+=tmp10_1 + tmp11_1;
2318                          } else { /* constant data */                              EM_S[INDEX2(2,3,4)]+=tmp3_1 + tmp4_1;
2319                              const register double D_0 = D_p[0];                              EM_S[INDEX2(3,3,4)]+=tmp5_1 + tmp8_1 + tmp9_1;
2320                              const register double tmp2_1 = D_0*w59;                          } else { // constant data
2321                              const register double tmp1_1 = D_0*w58;                              const double tmp0_1 = D_p[0]*w57;
2322                              const register double tmp0_1 = D_0*w57;                              const double tmp1_1 = D_p[0]*w58;
2323                              EM_S[INDEX2(0,1,4)]+=tmp0_1;                              const double tmp2_1 = D_p[0]*w59;
                             EM_S[INDEX2(1,2,4)]+=tmp1_1;  
                             EM_S[INDEX2(3,2,4)]+=tmp0_1;  
2324                              EM_S[INDEX2(0,0,4)]+=tmp2_1;                              EM_S[INDEX2(0,0,4)]+=tmp2_1;
2325                              EM_S[INDEX2(3,3,4)]+=tmp2_1;                              EM_S[INDEX2(1,0,4)]+=tmp0_1;
2326                                EM_S[INDEX2(2,0,4)]+=tmp0_1;
2327                              EM_S[INDEX2(3,0,4)]+=tmp1_1;                              EM_S[INDEX2(3,0,4)]+=tmp1_1;
2328                              EM_S[INDEX2(3,1,4)]+=tmp0_1;                              EM_S[INDEX2(0,1,4)]+=tmp0_1;
2329                                EM_S[INDEX2(1,1,4)]+=tmp2_1;
2330                              EM_S[INDEX2(2,1,4)]+=tmp1_1;                              EM_S[INDEX2(2,1,4)]+=tmp1_1;
2331                                EM_S[INDEX2(3,1,4)]+=tmp0_1;
2332                              EM_S[INDEX2(0,2,4)]+=tmp0_1;                              EM_S[INDEX2(0,2,4)]+=tmp0_1;
2333                              EM_S[INDEX2(2,0,4)]+=tmp0_1;                              EM_S[INDEX2(1,2,4)]+=tmp1_1;
                             EM_S[INDEX2(1,3,4)]+=tmp0_1;  
                             EM_S[INDEX2(2,3,4)]+=tmp0_1;  
2334                              EM_S[INDEX2(2,2,4)]+=tmp2_1;                              EM_S[INDEX2(2,2,4)]+=tmp2_1;
2335                              EM_S[INDEX2(1,0,4)]+=tmp0_1;                              EM_S[INDEX2(3,2,4)]+=tmp0_1;
2336                              EM_S[INDEX2(0,3,4)]+=tmp1_1;                              EM_S[INDEX2(0,3,4)]+=tmp1_1;
2337                              EM_S[INDEX2(1,1,4)]+=tmp2_1;                              EM_S[INDEX2(1,3,4)]+=tmp0_1;
2338                                EM_S[INDEX2(2,3,4)]+=tmp0_1;
2339                                EM_S[INDEX2(3,3,4)]+=tmp2_1;
2340                          }                          }
2341                      }                      }
2342                      ///////////////                      ///////////////
# Line 2044  void Rectangle::assemblePDESingle(Paso_S Line 2346  void Rectangle::assemblePDESingle(Paso_S
2346                          add_EM_F=true;                          add_EM_F=true;
2347                          const double* X_p=const_cast<escript::Data*>(&X)->getSampleDataRO(e);                          const double* X_p=const_cast<escript::Data*>(&X)->getSampleDataRO(e);
2348                          if (X.actsExpanded()) {                          if (X.actsExpanded()) {
2349                              const register double X_0_0 = X_p[INDEX2(0,0,2)];                              const double X_0_0 = X_p[INDEX2(0,0,2)];
2350                              const register double X_1_0 = X_p[INDEX2(1,0,2)];                              const double X_1_0 = X_p[INDEX2(1,0,2)];
2351                              const register double X_0_1 = X_p[INDEX2(0,1,2)];                              const double X_0_1 = X_p[INDEX2(0,1,2)];
2352                              const register double X_1_1 = X_p[INDEX2(1,1,2)];                              const double X_1_1 = X_p[INDEX2(1,1,2)];
2353                              const register double X_0_2 = X_p[INDEX2(0,2,2)];                              const double X_0_2 = X_p[INDEX2(0,2,2)];
2354                              const register double X_1_2 = X_p[INDEX2(1,2,2)];                              const double X_1_2 = X_p[INDEX2(1,2,2)];
2355                              const register double X_0_3 = X_p[INDEX2(0,3,2)];                              const double X_0_3 = X_p[INDEX2(0,3,2)];
2356                              const register double X_1_3 = X_p[INDEX2(1,3,2)];                              const double X_1_3 = X_p[INDEX2(1,3,2)];
2357                              const register double tmp1_0 = X_1_1 + X_1_3;                              const double tmp0_0 = X_0_2 + X_0_3;
2358                              const register double tmp3_0 = X_0_0 + X_0_1;                              const double tmp1_0 = X_1_1 + X_1_3;
2359                              const register double tmp2_0 = X_1_0 + X_1_2;                              const double tmp2_0 = X_1_0 + X_1_2;
2360                              const register double tmp0_0 = X_0_2 + X_0_3;                              const double tmp3_0 = X_0_0 + X_0_1;
2361                              const register double tmp8_1 = tmp2_0*w66;                              const double tmp0_1 = tmp0_0*w63;
2362                              const register double tmp5_1 = tmp3_0*w64;                              const double tmp1_1 = tmp1_0*w62;
2363                              const register double tmp14_1 = tmp0_0*w64;                              const double tmp2_1 = tmp2_0*w61;
2364                              const register double tmp3_1 = tmp3_0*w60;                              const double tmp3_1 = tmp3_0*w60;
2365                              const register double tmp9_1 = tmp3_0*w63;                              const double tmp4_1 = tmp0_0*w65;
2366                              const register double tmp13_1 = tmp3_0*w65;                              const double tmp5_1 = tmp3_0*w64;
2367                              const register double tmp12_1 = tmp1_0*w66;                              const double tmp6_1 = tmp2_0*w62;
2368                              const register double tmp10_1 = tmp0_0*w60;                              const double tmp7_1 = tmp1_0*w61;
2369                              const register double tmp2_1 = tmp2_0*w61;                              const double tmp8_1 = tmp2_0*w66;
2370                              const register double tmp6_1 = tmp2_0*w62;                              const double tmp9_1 = tmp3_0*w63;
2371                              const register double tmp4_1 = tmp0_0*w65;                              const double tmp10_1 = tmp0_0*w60;
2372                              const register double tmp11_1 = tmp1_0*w67;                              const double tmp11_1 = tmp1_0*w67;
2373                              const register double tmp1_1 = tmp1_0*w62;                              const double tmp12_1 = tmp1_0*w66;
2374                              const register double tmp7_1 = tmp1_0*w61;                              const double tmp13_1 = tmp3_0*w65;
2375                              const register double tmp0_1 = tmp0_0*w63;                              const double tmp14_1 = tmp0_0*w64;
2376                              const register double tmp15_1 = tmp2_0*w67;                              const double tmp15_1 = tmp2_0*w67;
2377                              EM_F[0]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;                              EM_F[0]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;
2378                              EM_F[1]+=tmp4_1 + tmp5_1 + tmp6_1 + tmp7_1;                              EM_F[1]+=tmp4_1 + tmp5_1 + tmp6_1 + tmp7_1;
2379                              EM_F[2]+=tmp10_1 + tmp11_1 + tmp8_1 + tmp9_1;                              EM_F[2]+=tmp10_1 + tmp11_1 + tmp8_1 + tmp9_1;
2380                              EM_F[3]+=tmp12_1 + tmp13_1 + tmp14_1 + tmp15_1;                              EM_F[3]+=tmp12_1 + tmp13_1 + tmp14_1 + tmp15_1;
2381                          } else { /* constant data */                          } else { // constant data
2382                              const register double X_0 = X_p[0];                              const double tmp0_1 = X_p[1]*w69;
2383                              const register double X_1 = X_p[1];                              const double tmp1_1 = X_p[0]*w68;
2384                              const register double tmp3_1 = X_1*w71;                              const double tmp2_1 = X_p[0]*w70;
2385                              const register double tmp2_1 = X_0*w70;                              const double tmp3_1 = X_p[1]*w71;
                             const register double tmp1_1 = X_0*w68;  
                             const register double tmp0_1 = X_1*w69;  
2386                              EM_F[0]+=tmp0_1 + tmp1_1;                              EM_F[0]+=tmp0_1 + tmp1_1;
2387                              EM_F[1]+=tmp0_1 + tmp2_1;                              EM_F[1]+=tmp0_1 + tmp2_1;
2388                              EM_F[2]+=tmp1_1 + tmp3_1;                              EM_F[2]+=tmp1_1 + tmp3_1;
# Line 2096  void Rectangle::assemblePDESingle(Paso_S Line 2396  void Rectangle::assemblePDESingle(Paso_S
2396                          add_EM_F=true;                          add_EM_F=true;
2397                          const double* Y_p=const_cast<escript::Data*>(&Y)->getSampleDataRO(e);                          const double* Y_p=const_cast<escript::Data*>(&Y)->getSampleDataRO(e);
2398                          if (Y.actsExpanded()) {                          if (Y.actsExpanded()) {
2399                              const register double Y_0 = Y_p[0];                              const double Y_0 = Y_p[0];
2400                              const register double Y_1 = Y_p[1];                              const double Y_1 = Y_p[1];
2401                              const register double Y_2 = Y_p[2];                              const double Y_2 = Y_p[2];
2402                              const register double Y_3 = Y_p[3];                              const double Y_3 = Y_p[3];
2403                              const register double tmp0_0 = Y_1 + Y_2;                              const double tmp0_0 = Y_1 + Y_2;
2404                              const register double tmp1_0 = Y_0 + Y_3;                              const double tmp1_0 = Y_0 + Y_3;
2405                              const register double tmp9_1 = Y_0*w74;                              const double tmp0_1 = Y_0*w72;
2406                              const register double tmp4_1 = tmp1_0*w73;                              const double tmp1_1 = tmp0_0*w73;
2407                              const register double tmp5_1 = Y_2*w74;                              const double tmp2_1 = Y_3*w74;
2408                              const register double tmp7_1 = Y_1*w74;                              const double tmp3_1 = Y_1*w72;
2409                              const register double tmp6_1 = Y_2*w72;                              const double tmp4_1 = tmp1_0*w73;
2410                              const register double tmp2_1 = Y_3*w74;                              const double tmp5_1 = Y_2*w74;
2411                              const register double tmp8_1 = Y_3*w72;                              const double tmp6_1 = Y_2*w72;
2412                              const register double tmp3_1 = Y_1*w72;                              const double tmp7_1 = Y_1*w74;
2413                              const register double tmp0_1 = Y_0*w72;                              const double tmp8_1 = Y_3*w72;
2414                              const register double tmp1_1 = tmp0_0*w73;                              const double tmp9_1 = Y_0*w74;
2415                              EM_F[0]+=tmp0_1 + tmp1_1 + tmp2_1;                              EM_F[0]+=tmp0_1 + tmp1_1 + tmp2_1;
2416                              EM_F[1]+=tmp3_1 + tmp4_1 + tmp5_1;                              EM_F[1]+=tmp3_1 + tmp4_1 + tmp5_1;
2417                              EM_F[2]+=tmp4_1 + tmp6_1 + tmp7_1;                              EM_F[2]+=tmp4_1 + tmp6_1 + tmp7_1;
2418                              EM_F[3]+=tmp1_1 + tmp8_1 + tmp9_1;                              EM_F[3]+=tmp1_1 + tmp8_1 + tmp9_1;
2419                          } else { /* constant data */                          } else { // constant data
2420                              const register double Y_0 = Y_p[0];                              const double tmp0_1 = Y_p[0]*w75;
                             const register double tmp0_1 = Y_0*w75;  
2421                              EM_F[0]+=tmp0_1;                              EM_F[0]+=tmp0_1;
2422                              EM_F[1]+=tmp0_1;                              EM_F[1]+=tmp0_1;
2423                              EM_F[2]+=tmp0_1;                              EM_F[2]+=tmp0_1;
2424                              EM_F[3]+=tmp0_1;                              EM_F[3]+=tmp0_1;
2425                          }                          }
2426                      }                      }
                     /* GENERATOR SNIP_PDE_SINGLE BOTTOM */  
2427    
2428                      // add to matrix (if add_EM_S) and RHS (if add_EM_F)                      // add to matrix (if add_EM_S) and RHS (if add_EM_F)
2429                      const index_t firstNode=m_N0*k1+k0;                      const index_t firstNode=m_N0*k1+k0;
2430                      IndexVector rowIndex;                      addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S, add_EM_F, firstNode);
2431                      rowIndex.push_back(m_dofMap[firstNode]);                  } // end k0 loop
2432                      rowIndex.push_back(m_dofMap[firstNode+1]);              } // end k1 loop
2433                      rowIndex.push_back(m_dofMap[firstNode+m_N0]);          } // end of colouring
2434                      rowIndex.push_back(m_dofMap[firstNode+m_N0+1]);      } // end of parallel region
2435                      if (add_EM_F) {  }
2436                          //cout << "-- AddtoRHS -- " << endl;  
2437                          double *F_p=rhs.getSampleDataRW(0);  //protected
2438                          for (index_t i=0; i<4; i++) {  void Rectangle::assemblePDESingleReduced(Paso_SystemMatrix* mat,
2439                              if (rowIndex[i]<getNumDOF()) {          escript::Data& rhs, const escript::Data& A, const escript::Data& B,
2440                                  F_p[rowIndex[i]]+=EM_F[i];          const escript::Data& C, const escript::Data& D,
2441                                  //cout << "F[" << rowIndex[i] << "]=" << F_p[rowIndex[i]] << endl;          const escript::Data& X, const escript::Data& Y) const
2442    {
2443        const double h0 = m_l0/m_gNE0;
2444        const double h1 = m_l1/m_gNE1;
2445        const double w0 = -.25*h1/h0;
2446        const double w1 = .25;
2447        const double w2 = -.25;
2448        const double w3 = .25*h0/h1;
2449        const double w4 = -.25*h0/h1;
2450        const double w5 = .25*h1/h0;
2451        const double w6 = -.125*h1;
2452        const double w7 = -.125*h0;
2453        const double w8 = .125*h1;
2454        const double w9 = .125*h0;
2455        const double w10 = .0625*h0*h1;
2456        const double w11 = -.5*h1;
2457        const double w12 = -.5*h0;
2458        const double w13 = .5*h1;
2459        const double w14 = .5*h0;
2460        const double w15 = .25*h0*h1;
2461    
2462        rhs.requireWrite();
2463    #pragma omp parallel
2464        {
2465            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
2466    #pragma omp for
2467                for (index_t k1=k1_0; k1<m_NE1; k1+=2) {
2468                    for (index_t k0=0; k0<m_NE0; ++k0)  {
2469                        bool add_EM_S=false;
2470                        bool add_EM_F=false;
2471                        vector<double> EM_S(4*4, 0);
2472                        vector<double> EM_F(4, 0);
2473                        const index_t e = k0 + m_NE0*k1;
2474                        ///////////////
2475                        // process A //
2476                        ///////////////
2477                        if (!A.isEmpty()) {
2478                            add_EM_S=true;
2479                            const double* A_p=const_cast<escript::Data*>(&A)->getSampleDataRO(e);
2480                            const double A_00 = A_p[INDEX2(0,0,2)];
2481                            const double A_10 = A_p[INDEX2(1,0,2)];
2482                            const double A_01 = A_p[INDEX2(0,1,2)];
2483                            const double A_11 = A_p[INDEX2(1,1,2)];
2484                            const double tmp0_0 = A_01 + A_10;
2485                            const double tmp0_1 = A_11*w3;
2486                            const double tmp1_1 = A_00*w0;
2487                            const double tmp2_1 = A_01*w1;
2488                            const double tmp3_1 = A_10*w2;
2489                            const double tmp4_1 = tmp0_0*w1;
2490                            const double tmp5_1 = A_11*w4;
2491                            const double tmp6_1 = A_00*w5;
2492                            const double tmp7_1 = tmp0_0*w2;
2493                            const double tmp8_1 = A_10*w1;
2494                            const double tmp9_1 = A_01*w2;
2495                            EM_S[INDEX2(0,0,4)]+=tmp0_1 + tmp4_1 + tmp6_1;
2496                            EM_S[INDEX2(1,0,4)]+=tmp0_1 + tmp1_1 + tmp8_1 + tmp9_1;
2497                            EM_S[INDEX2(2,0,4)]+=tmp2_1 + tmp3_1 + tmp5_1 + tmp6_1;
2498                            EM_S[INDEX2(3,0,4)]+=tmp1_1 + tmp5_1 + tmp7_1;
2499                            EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;
2500                            EM_S[INDEX2(1,1,4)]+=tmp0_1 + tmp6_1 + tmp7_1;
2501                            EM_S[INDEX2(2,1,4)]+=tmp1_1 + tmp4_1 + tmp5_1;
2502                            EM_S[INDEX2(3,1,4)]+=tmp5_1 + tmp6_1 + tmp8_1 + tmp9_1;
2503                            EM_S[INDEX2(0,2,4)]+=tmp5_1 + tmp6_1 + tmp8_1 + tmp9_1;
2504                            EM_S[INDEX2(1,2,4)]+=tmp1_1 + tmp4_1 + tmp5_1;
2505                            EM_S[INDEX2(2,2,4)]+=tmp0_1 + tmp6_1 + tmp7_1;
2506                            EM_S[INDEX2(3,2,4)]+=tmp0_1 + tmp1_1 + tmp2_1 + tmp3_1;
2507                            EM_S[INDEX2(0,3,4)]+=tmp1_1 + tmp5_1 + tmp7_1;
2508                            EM_S[INDEX2(1,3,4)]+=tmp2_1 + tmp3_1 + tmp5_1 + tmp6_1;
2509                            EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp1_1 + tmp8_1 + tmp9_1;
2510                            EM_S[INDEX2(3,3,4)]+=tmp0_1 + tmp4_1 + tmp6_1;
2511                        }
2512                        ///////////////
2513                        // process B //
2514                        ///////////////
2515                        if (!B.isEmpty()) {
2516                            add_EM_S=true;
2517                            const double* B_p=const_cast<escript::Data*>(&B)->getSampleDataRO(e);
2518                            const double tmp2_1 = B_p[0]*w8;
2519                            const double tmp0_1 = B_p[0]*w6;
2520                            const double tmp3_1 = B_p[1]*w9;
2521                            const double tmp1_1 = B_p[1]*w7;
2522                            EM_S[INDEX2(0,0,4)]+=tmp0_1 + tmp1_1;
2523                            EM_S[INDEX2(1,0,4)]+=tmp1_1 + tmp2_1;
2524                            EM_S[INDEX2(2,0,4)]+=tmp0_1 + tmp3_1;
2525                            EM_S[INDEX2(3,0,4)]+=tmp2_1 + tmp3_1;
2526                            EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;
2527                            EM_S[INDEX2(1,1,4)]+=tmp1_1 + tmp2_1;
2528                            EM_S[INDEX2(2,1,4)]+=tmp0_1 + tmp3_1;
2529                            EM_S[INDEX2(3,1,4)]+=tmp2_1 + tmp3_1;
2530                            EM_S[INDEX2(0,2,4)]+=tmp0_1 + tmp1_1;
2531                            EM_S[INDEX2(1,2,4)]+=tmp1_1 + tmp2_1;
2532                            EM_S[INDEX2(2,2,4)]+=tmp0_1 + tmp3_1;
2533                            EM_S[INDEX2(3,2,4)]+=tmp2_1 + tmp3_1;
2534                            EM_S[INDEX2(0,3,4)]+=tmp0_1 + tmp1_1;
2535                            EM_S[INDEX2(1,3,4)]+=tmp1_1 + tmp2_1;
2536                            EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp3_1;
2537                            EM_S[INDEX2(3,3,4)]+=tmp2_1 + tmp3_1;
2538                        }
2539                        ///////////////
2540                        // process C //
2541                        ///////////////
2542                        if (!C.isEmpty()) {
2543                            add_EM_S=true;
2544                            const double* C_p=const_cast<escript::Data*>(&C)->getSampleDataRO(e);
2545                            const double tmp1_1 = C_p[1]*w7;
2546                            const double tmp0_1 = C_p[0]*w8;
2547                            const double tmp3_1 = C_p[0]*w6;
2548                            const double tmp2_1 = C_p[1]*w9;
2549                            EM_S[INDEX2(0,0,4)]+=tmp1_1 + tmp3_1;
2550                            EM_S[INDEX2(1,0,4)]+=tmp1_1 + tmp3_1;
2551                            EM_S[INDEX2(2,0,4)]+=tmp1_1 + tmp3_1;
2552                            EM_S[INDEX2(3,0,4)]+=tmp1_1 + tmp3_1;
2553                            EM_S[INDEX2(0,1,4)]+=tmp0_1 + tmp1_1;
2554                            EM_S[INDEX2(1,1,4)]+=tmp0_1 + tmp1_1;
2555                            EM_S[INDEX2(2,1,4)]+=tmp0_1 + tmp1_1;
2556                            EM_S[INDEX2(3,1,4)]+=tmp0_1 + tmp1_1;
2557                            EM_S[INDEX2(0,2,4)]+=tmp2_1 + tmp3_1;
2558                            EM_S[INDEX2(1,2,4)]+=tmp2_1 + tmp3_1;
2559                            EM_S[INDEX2(2,2,4)]+=tmp2_1 + tmp3_1;
2560                            EM_S[INDEX2(3,2,4)]+=tmp2_1 + tmp3_1;
2561                            EM_S[INDEX2(0,3,4)]+=tmp0_1 + tmp2_1;
2562                            EM_S[INDEX2(1,3,4)]+=tmp0_1 + tmp2_1;
2563                            EM_S[INDEX2(2,3,4)]+=tmp0_1 + tmp2_1;
2564                            EM_S[INDEX2(3,3,4)]+=tmp0_1 + tmp2_1;
2565                        }
2566                        ///////////////
2567                        // process D //
2568                        ///////////////
2569                        if (!D.isEmpty()) {
2570                            add_EM_S=true;
2571                            const double* D_p=const_cast<escript::Data*>(&D)->getSampleDataRO(e);
2572                            const double tmp0_1 = D_p[0]*w10;
2573                            EM_S[INDEX2(0,0,4)]+=tmp0_1;
2574                            EM_S[INDEX2(1,0,4)]+=tmp0_1;
2575                            EM_S[INDEX2(2,0,4)]+=tmp0_1;
2576                            EM_S[INDEX2(3,0,4)]+=tmp0_1;
2577                            EM_S[INDEX2(0,1,4)]+=tmp0_1;
2578                            EM_S[INDEX2(1,1,4)]+=tmp0_1;
2579                            EM_S[INDEX2(2,1,4)]+=tmp0_1;
2580                            EM_S[INDEX2(3,1,4)]+=tmp0_1;
2581                            EM_S[INDEX2(0,2,4)]+=tmp0_1;
2582                            EM_S[INDEX2(1,2,4)]+=tmp0_1;
2583                            EM_S[INDEX2(2,2,4)]+=tmp0_1;
2584                            EM_S[INDEX2(3,2,4)]+=tmp0_1;
2585                            EM_S[INDEX2(0,3,4)]+=tmp0_1;
2586                            EM_S[INDEX2(1,3,4)]+=tmp0_1;
2587                            EM_S[INDEX2(2,3,4)]+=tmp0_1;
2588                            EM_S[INDEX2(3,3,4)]+=tmp0_1;
2589                        }
2590                        ///////////////
2591                        // process X //
2592                        ///////////////
2593                        if (!X.isEmpty()) {
2594                            add_EM_F=true;
2595                            const double* X_p=const_cast<escript::Data*>(&X)->getSampleDataRO(e);
2596                            const double tmp0_1 = X_p[0]*w11;
2597                            const double tmp2_1 = X_p[0]*w13;
2598                            const double tmp1_1 = X_p[1]*w12;
2599                            const double tmp3_1 = X_p[1]*w14;
2600                            EM_F[0]+=tmp0_1 + tmp1_1;
2601                            EM_F[1]+=tmp1_1 + tmp2_1;
2602                            EM_F[2]+=tmp0_1 + tmp3_1;
2603                            EM_F[3]+=tmp2_1 + tmp3_1;
2604                        }
2605                        ///////////////
2606                        // process Y //
2607                        ///////////////
2608                        if (!Y.isEmpty()) {
2609                            add_EM_F=true;
2610                            const double* Y_p=const_cast<escript::Data*>(&Y)->getSampleDataRO(e);
2611                            const double tmp0_1 = Y_p[0]*w15;
2612                            EM_F[0]+=tmp0_1;
2613                            EM_F[1]+=tmp0_1;
2614                            EM_F[2]+=tmp0_1;
2615                            EM_F[3]+=tmp0_1;
2616                        }
2617    
2618                        // add to matrix (if add_EM_S) and RHS (if add_EM_F)
2619                        const index_t firstNode=m_N0*k1+k0;
2620                        addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S, add_EM_F, firstNode);
2621                    } // end k0 loop
2622                } // end k1 loop
2623            } // end of colouring
2624        } // end of parallel region
2625    }
2626    
2627    //protected
2628    void Rectangle::assemblePDESystem(Paso_SystemMatrix* mat,
2629            escript::Data& rhs, const escript::Data& A, const escript::Data& B,
2630            const escript::Data& C, const escript::Data& D,
2631            const escript::Data& X, const escript::Data& Y) const
2632    {
2633        const double h0 = m_l0/m_gNE0;
2634        const double h1 = m_l1/m_gNE1;
2635        dim_t numEq, numComp;
2636        if (!mat)
2637            numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
2638        else {
2639            numEq=mat->logical_row_block_size;
2640            numComp=mat->logical_col_block_size;
2641        }
2642    
2643        const double w0 = -0.1555021169820365539*h1/h0;
2644        const double w1 = 0.041666666666666666667;
2645        const double w2 = -0.15550211698203655390;
2646        const double w3 = 0.041666666666666666667*h0/h1;
2647        const double w4 = 0.15550211698203655390;
2648        const double w5 = -0.041666666666666666667;
2649        const double w6 = -0.01116454968463011277*h1/h0;
2650        const double w7 = 0.011164549684630112770;
2651        const double w8 = -0.011164549684630112770;
2652        const double w9 = -0.041666666666666666667*h1/h0;
2653        const double w10 = -0.041666666666666666667*h0/h1;
2654        const double w11 = 0.1555021169820365539*h1/h0;
2655        const double w12 = 0.1555021169820365539*h0/h1;
2656        const double w13 = 0.01116454968463011277*h0/h1;
2657        const double w14 = 0.01116454968463011277*h1/h0;
2658        const double w15 = 0.041666666666666666667*h1/h0;
2659        const double w16 = -0.01116454968463011277*h0/h1;
2660        const double w17 = -0.1555021169820365539*h0/h1;
2661        const double w18 = -0.33333333333333333333*h1/h0;
2662        const double w19 = 0.25000000000000000000;
2663        const double w20 = -0.25000000000000000000;
2664