/[escript]/trunk/escript/src/Data.h
ViewVC logotype

Diff of /trunk/escript/src/Data.h

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

revision 782 by bcumming, Tue Jul 18 00:47:47 2006 UTC revision 1748 by ksteube, Wed Sep 3 06:10:39 2008 UTC
# Line 1  Line 1 
1  // $Id$  
2  /*  /* $Id$ */
3   ************************************************************  
4   *          Copyright 2006 by ACcESS MNRF                   *  /*******************************************************
5   *                                                          *   *
6   *              http://www.access.edu.au                    *   *           Copyright 2003-2007 by ACceSS MNRF
7   *       Primary Business: Queensland, Australia            *   *       Copyright 2007 by University of Queensland
8   *  Licensed under the Open Software License version 3.0    *   *
9   *     http://www.opensource.org/licenses/osl-3.0.php       *   *                http://esscc.uq.edu.au
10   *                                                          *   *        Primary Business: Queensland, Australia
11   ************************************************************   *  Licensed under the Open Software License version 3.0
12  */   *     http://www.opensource.org/licenses/osl-3.0.php
13     *
14     *******************************************************/
15    
16  /** \file Data.h */  /** \file Data.h */
17    
# Line 26  Line 28 
28    
29  extern "C" {  extern "C" {
30  #include "DataC.h"  #include "DataC.h"
31  #include "paso/Paso.h"  /* #include "paso/Paso.h" doesn't belong in this file...causes trouble for BruceFactory.cpp */
32  }  }
33    
34    #include "esysmpi.h"
35  #include <string>  #include <string>
36  #include <algorithm>  #include <algorithm>
37    #include <sstream>
38    
39    
40  #include <boost/shared_ptr.hpp>  #include <boost/shared_ptr.hpp>
41  #include <boost/python/object.hpp>  #include <boost/python/object.hpp>
# Line 47  class DataExpanded; Line 52  class DataExpanded;
52    
53  /**  /**
54     \brief     \brief
55     Data creates the appropriate Data object for the given construction     Data creates the appropriate Data object for the given construction
56     arguments.     arguments.
57    
58     Description:     Description:
59     Data is essentially a factory class which creates the appropriate Data     Data is essentially a factory class which creates the appropriate Data
# Line 66  class Data { Line 71  class Data {
71    typedef double (*UnaryDFunPtr)(double);    typedef double (*UnaryDFunPtr)(double);
72    typedef double (*BinaryDFunPtr)(double,double);    typedef double (*BinaryDFunPtr)(double,double);
73    
74    
75    /**    /**
76       Constructors.       Constructors.
77    */    */
# Line 209  class Data { Line 215  class Data {
215       Constructor which creates a DataConstant of "shape" with constant value.       Constructor which creates a DataConstant of "shape" with constant value.
216    */    */
217    ESCRIPT_DLL_API    ESCRIPT_DLL_API
218    Data(double value,    Data(double value,
219         const boost::python::tuple& shape=boost::python::make_tuple(),         const boost::python::tuple& shape=boost::python::make_tuple(),
220         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
221         bool expanded=false);         bool expanded=false);
222    /**    /**
# Line 234  class Data { Line 240  class Data {
240    
241    /**    /**
242       \brief       \brief
243       Return the values of all data-points as a single python numarray object.       switches on update protection
244    
245    */    */
246    ESCRIPT_DLL_API    ESCRIPT_DLL_API
247    const boost::python::numeric::array    void
248    convertToNumArray();    setProtection();
249    
250    /**    /**
251       \brief       \brief
252       Return the values of all data-points for the given sample as a single python numarray object.       Returns trueif the data object is protected against update
253    
254    */    */
255    ESCRIPT_DLL_API    ESCRIPT_DLL_API
256    const boost::python::numeric::array    bool
257    convertToNumArrayFromSampleNo(int sampleNo);    isProtected() const;
258    
259    /**    /**
260       \brief       \brief
261       Return the value of the specified data-point as a single python numarray object.       Return the values of a data point on this process
262    */    */
263    ESCRIPT_DLL_API    ESCRIPT_DLL_API
264    const boost::python::numeric::array    const boost::python::numeric::array
265    convertToNumArrayFromDPNo(int sampleNo,    getValueOfDataPoint(int dataPointNo);
                             int dataPointNo);  
266    
267    /**    /**
268       \brief       \brief
269       Fills the expanded Data object from values of a python numarray object.       sets the values of a data-point from a python object on this process
270    */    */
271    ESCRIPT_DLL_API    ESCRIPT_DLL_API
272    void    void
273    fillFromNumArray(const boost::python::numeric::array);    setValueOfDataPointToPyObject(int dataPointNo, const boost::python::object& py_object);
274    
275      /**
276         \brief
277         sets the values of a data-point from a numarray object on this process
278      */
279      ESCRIPT_DLL_API
280      void
281      setValueOfDataPointToArray(int dataPointNo, const boost::python::numeric::array&);
282    
283      /**
284         \brief
285         sets the values of a data-point on this process
286      */
287      ESCRIPT_DLL_API
288      void
289      setValueOfDataPoint(int dataPointNo, const double);
290    
291      /**
292         \brief
293         Return the value of the specified data-point across all processors
294      */
295      ESCRIPT_DLL_API
296      const boost::python::numeric::array
297      getValueOfGlobalDataPoint(int procNo, int dataPointNo);
298    
299    /**    /**
300       \brief       \brief
301       Return the tag number associated with the given data-point.       Return the tag number associated with the given data-point.
302    
      The data-point number here corresponds to the data-point number in the  
      numarray returned by convertToNumArray.  
303    */    */
304    ESCRIPT_DLL_API    ESCRIPT_DLL_API
305    int    int
# Line 294  class Data { Line 323  class Data {
323    
324    /**    /**
325       \brief       \brief
326       Write the data as a string.       Write the data as a string. For large amounts of data, a summary is printed.
327    */    */
328    ESCRIPT_DLL_API    ESCRIPT_DLL_API
   inline  
329    std::string    std::string
330    toString() const    toString() const;
331    {  
     return m_data->toString();  
   }  
332    
333    /**    /**
334       \brief       \brief
# Line 423  class Data { Line 449  class Data {
449    
450    /**    /**
451       \brief       \brief
452         Return the number of data points
453      */
454      ESCRIPT_DLL_API
455      inline
456      int
457      getNumDataPoints() const
458      {
459        return getNumSamples() * getNumDataPointsPerSample();
460      }
461      /**
462         \brief
463       Return the number of samples.       Return the number of samples.
464    */    */
465    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 444  class Data { Line 481  class Data {
481    {    {
482      return m_data->getNumDPPSample();      return m_data->getNumDPPSample();
483    }    }
484      /**
485         \brief
486         dumps the object into a netCDF file
487      */
488      ESCRIPT_DLL_API
489      void
490      dump(const std::string fileName) const;
491    /**    /**
492       \brief       \brief
493       Return the sample data for the given sample no. This is not the       Return the sample data for the given sample no. This is not the
# Line 475  class Data { Line 518  class Data {
518    
519    /**    /**
520       \brief       \brief
      Assign the given value to the data-points referenced by the given  
      reference number.  
   
      The value supplied is a python numarray object.  The data from this numarray  
      is unpacked into a DataArray, and this is used to set the corresponding  
      data-points in the underlying Data object.  
   
      If the underlying Data object cannot be accessed via reference numbers, an  
      exception will be thrown.  
   
      \param ref - Input - reference number.  
      \param value - Input - value to assign to data-points associated with  
                             the given reference number.  
   */  
   ESCRIPT_DLL_API  
   void  
   setRefValue(int ref,  
               const boost::python::numeric::array& value);  
   
   /**  
      \brief  
      Return the values associated with the data-points referenced by the given  
      reference number.  
   
      The value supplied is a python numarray object. The data from the corresponding  
      data-points in this Data object are packed into the given numarray object.  
   
      If the underlying Data object cannot be accessed via reference numbers, an  
      exception will be thrown.  
   
      \param ref - Input - reference number.  
      \param value - Output - object to receive values from data-points  
                              associated with the given reference number.  
   */  
   ESCRIPT_DLL_API  
   void  
   getRefValue(int ref,  
               boost::python::numeric::array& value);  
   
   /**  
      \brief  
521       Return a view into the data for the data point specified.       Return a view into the data for the data point specified.
522       NOTE: Construction of the DataArrayView is a relatively expensive       NOTE: Construction of the DataArrayView is a relatively expensive
523       operation.       operation.
# Line 528  class Data { Line 530  class Data {
530    getDataPoint(int sampleNo,    getDataPoint(int sampleNo,
531                 int dataPointNo)                 int dataPointNo)
532    {    {
533      return m_data->getDataPoint(sampleNo,dataPointNo);                  return m_data->getDataPoint(sampleNo,dataPointNo);
534    }    }
535    
536    /**    /**
# Line 564  class Data { Line 566  class Data {
566    DataArrayView::ValueType::size_type    DataArrayView::ValueType::size_type
567    getLength() const;    getLength() const;
568    
569    
570    
571    /**    /**
572       \brief       \brief
573       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag assocciated with name. Implicitly converts this
574       object to type DataTagged. Throws an exception if this object       object to type DataTagged. Throws an exception if this object
575       cannot be converted to a DataTagged object.       cannot be converted to a DataTagged object or name cannot be mapped onto a tag key.
576         \param tagKey - Input - Integer key.
577         \param value - Input - Value to associate with given key.
578        ==>*
579      */
580      ESCRIPT_DLL_API
581      void
582      setTaggedValueByName(std::string name,
583                           const boost::python::object& value);
584    
585      /**
586         \brief
587         Assign the given value to the tag. Implicitly converts this
588         object to type DataTagged if it is constant.
589    
590       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
591       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
592      ==>*      ==>*
# Line 581  class Data { Line 599  class Data {
599    /**    /**
600       \brief       \brief
601       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag. Implicitly converts this
602       object to type DataTagged. Throws an exception if this object       object to type DataTagged if it is constant.
603       cannot be converted to a DataTagged object.  
604       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
605       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
606      ==>*      ==>*
# Line 607  class Data { Line 625  class Data {
625    
626    /**    /**
627       \brief       \brief
628         set all values to zero
629         *
630      */
631      ESCRIPT_DLL_API
632      void
633      setToZero();
634    
635      /**
636         \brief
637       Interpolates this onto the given functionspace and returns       Interpolates this onto the given functionspace and returns
638       the result as a Data object.       the result as a Data object.
639       *       *
# Line 614  class Data { Line 641  class Data {
641    ESCRIPT_DLL_API    ESCRIPT_DLL_API
642    Data    Data
643    interpolate(const FunctionSpace& functionspace) const;    interpolate(const FunctionSpace& functionspace) const;
   
644    /**    /**
645       \brief       \brief
646       Calculates the gradient of the data at the data points of functionspace.       Calculates the gradient of the data at the data points of functionspace.
# Line 640  class Data { Line 666  class Data {
666    
667    /**    /**
668       \brief       \brief
669         Returns 1./ Data object
670         *
671      */
672      ESCRIPT_DLL_API
673      Data
674      oneOver() const;
675      /**
676         \brief
677       Return a Data with a 1 for +ive values and a 0 for 0 or -ive values.       Return a Data with a 1 for +ive values and a 0 for 0 or -ive values.
678       *       *
679    */    */
# Line 703  class Data { Line 737  class Data {
737    
738    /**    /**
739       \brief       \brief
      Return the minimum absolute value of this Data object.  
      *  
   */  
   ESCRIPT_DLL_API  
   double  
   Linf() const;  
   
   /**  
      \brief  
740       Return the maximum value of this Data object.       Return the maximum value of this Data object.
741       *       *
742    */    */
# Line 762  class Data { Line 787  class Data {
787    */    */
788    ESCRIPT_DLL_API    ESCRIPT_DLL_API
789    const boost::python::tuple    const boost::python::tuple
790    mindp() const;    minGlobalDataPoint() const;
791    
792    ESCRIPT_DLL_API    ESCRIPT_DLL_API
793    void    void
794  #ifndef PASO_MPI    calc_minGlobalDataPoint(int& ProcNo,  int& DataPointNo) const;
   calc_mindp(int& SampleNo,  
              int& DataPointNo) const;  
 #else  
   calc_mindp(int& ProcNo,  
                         int& SampleNo,    
              int& DataPointNo) const;  
 #endif  
795    /**    /**
796       \brief       \brief
797       Return the sign of each data point of this Data object.       Return the sign of each data point of this Data object.
# Line 809  class Data { Line 827  class Data {
827    */    */
828    ESCRIPT_DLL_API    ESCRIPT_DLL_API
829    Data    Data
830    matrixtrace(int axis_offset) const;    trace(int axis_offset) const;
831    
832    /**    /**
833       \brief       \brief
# Line 833  class Data { Line 851  class Data {
851    /**    /**
852       \brief       \brief
853       Return the eigenvalues and corresponding eigenvcetors of the symmetric part at each data point of this Data object.       Return the eigenvalues and corresponding eigenvcetors of the symmetric part at each data point of this Data object.
854       the eigenvalues are ordered in increasing size where eigenvalues with relative difference less than       the eigenvalues are ordered in increasing size where eigenvalues with relative difference less than
855       tol are treated as equal. The eigenvectors are orthogonal, normalized and the sclaed such that the       tol are treated as equal. The eigenvectors are orthogonal, normalized and the sclaed such that the
856       first non-zero entry is positive.       first non-zero entry is positive.
857       Currently this function is restricted to rank 2, square shape, and dimension 3       Currently this function is restricted to rank 2, square shape, and dimension 3
858       *       *
# Line 845  class Data { Line 863  class Data {
863    
864    /**    /**
865       \brief       \brief
866       Calculate the trace of each data point of this Data object.       swaps the components axis0 and axis1
867         *
868      */
869      ESCRIPT_DLL_API
870      Data
871      swapaxes(const int axis0, const int axis1) const;
872    
873      /**
874         \brief
875         Return the error function erf of each data point of this Data object.
876       *       *
877    */    */
878    ESCRIPT_DLL_API    ESCRIPT_DLL_API
879    Data    Data
880    trace() const;    erf() const;
881    
882    /**    /**
883       \brief       \brief
# Line 1029  class Data { Line 1056  class Data {
1056    /**    /**
1057       \brief       \brief
1058       Return the given power of each data point of this boost python object.       Return the given power of each data point of this boost python object.
1059        
1060       \param right Input - the power to raise the object to.       \param right Input - the power to raise the object to.
1061       *       *
1062     */     */
# Line 1040  class Data { Line 1067  class Data {
1067    /**    /**
1068       \brief       \brief
1069       Return the given power of each data point of this boost python object.       Return the given power of each data point of this boost python object.
1070        
1071       \param left Input - the bases       \param left Input - the bases
1072       *       *
1073     */     */
# Line 1076  class Data { Line 1103  class Data {
1103    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1104    Data& operator+=(const boost::python::object& right);    Data& operator+=(const boost::python::object& right);
1105    
1106      ESCRIPT_DLL_API
1107      Data& operator=(const Data& other);
1108    
1109    /**    /**
1110       \brief       \brief
1111       Overloaded operator -=       Overloaded operator -=
# Line 1168  class Data { Line 1198  class Data {
1198    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1199    inline    inline
1200    void    void
1201    unaryOp(UnaryFunction operation);    unaryOp2(UnaryFunction operation);
1202    
1203    /**    /**
1204       \brief       \brief
# Line 1217  class Data { Line 1247  class Data {
1247                const FunctionSpace& fspace);                const FunctionSpace& fspace);
1248    
1249    
 #ifdef PASO_MPI  
1250    /**    /**
1251       \brief       \brief
1252       print the data values to stdout. Used for debugging       print the data values to stdout. Used for debugging
1253    */    */
1254    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1255    void    void
1256      print(void);          print(void);
1257    
1258    /**    /**
1259       \brief       \brief
1260       return the MPI rank number of the local data       return the MPI rank number of the local data
1261           MPI_COMM_WORLD is assumed and the result of MPI_Comm_size()                   MPI_COMM_WORLD is assumed and the result of MPI_Comm_size()
1262           is returned                   is returned
1263    */    */
1264    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1265      int          int
1266      get_MPIRank(void) const;          get_MPIRank(void) const;
1267    
1268    /**    /**
1269       \brief       \brief
1270       return the MPI rank number of the local data       return the MPI rank number of the local data
1271           MPI_COMM_WORLD is assumed and the result of MPI_Comm_rank()                   MPI_COMM_WORLD is assumed and the result of MPI_Comm_rank()
1272           is returned                   is returned
1273    */    */
1274    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1275      int          int
1276      get_MPISize(void) const;          get_MPISize(void) const;
1277    
1278    /**    /**
1279       \brief       \brief
1280       return the MPI rank number of the local data       return the MPI rank number of the local data
1281           MPI_COMM_WORLD is assumed and returned.                   MPI_COMM_WORLD is assumed and returned.
1282    */    */
1283    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1284      MPI_Comm          MPI_Comm
1285      get_MPIComm(void) const;          get_MPIComm(void) const;
1286  #endif  
1287          /**
1288         \brief
1289         return the object produced by the factory, which is a DataConstant or DataExpanded
1290      */
1291      ESCRIPT_DLL_API
1292            DataAbstract*
1293            borrowData(void) const;
1294    
1295   protected:   protected:
1296    
1297   private:   private:
# Line 1313  class Data { Line 1349  class Data {
1349    
1350    /**    /**
1351       \brief       \brief
      Perform the given binary operation on all of the data's elements.  
      RHS is a boost::python object.  
   */  
   template <class BinaryFunction>  
   inline  
   void  
   binaryOp(const boost::python::object& right,  
            BinaryFunction operation);  
   
   /**  
      \brief  
1352       Convert the data type of the RHS to match this.       Convert the data type of the RHS to match this.
1353       \param right - Input - data type to match.       \param right - Input - data type to match.
1354    */    */
# Line 1348  class Data { Line 1373  class Data {
1373               const FunctionSpace& what,               const FunctionSpace& what,
1374               bool expanded);               bool expanded);
1375    
1376    /**    //
1377       \brief    // flag to protect the data object against any update
1378       Reshape the data point if the data point is currently rank 0.    bool m_protected;
      Will throw an exception if the data points are not rank 0.  
      The original data point value is used for all values of the new  
      data point.  
   */  
   void  
   reshapeDataPoint(const DataArrayView::ShapeType& shape);  
1379    
1380    //    //
1381    // pointer to the actual data object    // pointer to the actual data object
1382    boost::shared_ptr<DataAbstract> m_data;    boost::shared_ptr<DataAbstract> m_data;
1383    
   //  
   // pointer to the internal profiling data  
   struct profDataEntry *profData;  
   
1384  };  };
1385    
1386  template <class IValueType>  template <class IValueType>
# Line 1391  Data::initialise(const IValueType& value Line 1406  Data::initialise(const IValueType& value
1406  }  }
1407    
1408  /**  /**
1409       Modify a filename for MPI parallel output to multiple files
1410    */
1411    char *Escript_MPI_appendRankToFileName(const char *, int, int);
1412    
1413    /**
1414     Binary Data object operators.     Binary Data object operators.
1415  */  */
1416    inline double rpow(double x,double y)
1417    {
1418        return pow(y,x);
1419    }
1420    
1421  /**  /**
1422    \brief    \brief
# Line 1486  ESCRIPT_DLL_API Data operator*(const boo Line 1510  ESCRIPT_DLL_API Data operator*(const boo
1510  */  */
1511  ESCRIPT_DLL_API Data operator/(const boost::python::object& left, const Data& right);  ESCRIPT_DLL_API Data operator/(const boost::python::object& left, const Data& right);
1512    
1513    
1514    
1515  /**  /**
1516    \brief    \brief
1517    Output operator    Output operator
# Line 1494  ESCRIPT_DLL_API std::ostream& operator<< Line 1520  ESCRIPT_DLL_API std::ostream& operator<<
1520    
1521  /**  /**
1522    \brief    \brief
1523      Compute a tensor product of two Data objects
1524      \param arg0 - Input - Data object
1525      \param arg1 - Input - Data object
1526      \param axis_offset - Input - axis offset
1527      \param transpose - Input - 0: transpose neither, 1: transpose arg0, 2: transpose arg1
1528    */
1529    ESCRIPT_DLL_API
1530    Data
1531    C_GeneralTensorProduct(Data& arg0,
1532                         Data& arg1,
1533                         int axis_offset=0,
1534                         int transpose=0);
1535    
1536    
1537    
1538    /**
1539      \brief
1540    Return true if operands are equivalent, else return false.    Return true if operands are equivalent, else return false.
1541    NB: this operator does very little at this point, and isn't to    NB: this operator does very little at this point, and isn't to
1542    be relied on. Requires further implementation.    be relied on. Requires further implementation.
1543  */  */
1544  //ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);  // ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);
1545    
1546  /**  /**
1547    \brief    \brief
# Line 1514  Data::binaryOp(const Data& right, Line 1557  Data::binaryOp(const Data& right,
1557     //     //
1558     // if this has a rank of zero promote it to the rank of the RHS     // if this has a rank of zero promote it to the rank of the RHS
1559     if (getPointDataView().getRank()==0 && right.getPointDataView().getRank()!=0) {     if (getPointDataView().getRank()==0 && right.getPointDataView().getRank()!=0) {
1560       reshapeDataPoint(right.getPointDataView().getShape());       throw DataException("Error - attempt to update rank zero object with object with rank bigger than zero.");
1561     }     }
1562     //     //
1563     // initially make the temporary a shallow copy     // initially make the temporary a shallow copy
# Line 1522  Data::binaryOp(const Data& right, Line 1565  Data::binaryOp(const Data& right,
1565     if (getFunctionSpace()!=right.getFunctionSpace()) {     if (getFunctionSpace()!=right.getFunctionSpace()) {
1566       if (right.probeInterpolation(getFunctionSpace())) {       if (right.probeInterpolation(getFunctionSpace())) {
1567         //         //
1568         // an interpolation is required so create a new Data         // an interpolation is required so create a new Data
1569         tempRight=Data(right,this->getFunctionSpace());         tempRight=Data(right,this->getFunctionSpace());
1570       } else if (probeInterpolation(right.getFunctionSpace())) {       } else if (probeInterpolation(right.getFunctionSpace())) {
1571         //         //
# Line 1570  Data::binaryOp(const Data& right, Line 1613  Data::binaryOp(const Data& right,
1613    
1614  /**  /**
1615    \brief    \brief
   Perform the given binary operation with this and right as operands.  
   Right is a boost::python object.  
 */  
 template <class BinaryFunction>  
 inline  
 void  
 Data::binaryOp(const boost::python::object& right,  
                BinaryFunction operation)  
 {  
    DataArray temp(right);  
    //  
    // if this has a rank of zero promote it to the rank of the RHS.  
    if (getPointDataView().getRank()==0 && temp.getView().getRank()!=0) {  
       reshapeDataPoint(temp.getView().getShape());  
    }  
    //  
    // Always allow scalar values for the RHS but check other shapes  
    if (temp.getView().getRank()!=0) {  
      if (!getPointDataView().checkShape(temp.getView().getShape())) {  
        throw DataException(getPointDataView().createShapeErrorMessage(  
                   "Error - RHS shape doesn't match LHS shape.",temp.getView().getShape()));  
      }  
    }  
    if (isExpanded()) {  
      DataExpanded* leftC=dynamic_cast<DataExpanded*>(m_data.get());  
      EsysAssert((leftC!=0),"Programming error - casting to DataExpanded.");  
      escript::binaryOp(*leftC,temp.getView(),operation);  
    } else if (isTagged()) {  
      DataTagged* leftC=dynamic_cast<DataTagged*>(m_data.get());  
      EsysAssert((leftC!=0), "Programming error - casting to DataTagged.");  
      escript::binaryOp(*leftC,temp.getView(),operation);  
    } else if (isConstant()) {  
      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());  
      EsysAssert((leftC!=0),"Programming error - casting to DataConstant.");  
      escript::binaryOp(*leftC,temp.getView(),operation);  
    }  
 }  
   
 /**  
   \brief  
   Perform the given unary operation on other and return the result.  
   Given operation is performed on each element of each data point, thus  
   argument object is a rank n Data object, and returned object is a rank n  
   Data object.  
   Calls Data::unaryOp.  
 */  
 template <class UnaryFunction>  
 inline  
 Data  
 unaryOp(const Data& other,  
         UnaryFunction operation)  
 {  
   Data result;  
   result.copy(other);  
   result.unaryOp(operation);  
   return result;  
 }  
   
 /**  
   \brief  
   Perform the given unary operation on this.  
   Given operation is performed on each element of each data point.  
   Calls escript::unaryOp.  
 */  
 template <class UnaryFunction>  
 inline  
 void  
 Data::unaryOp(UnaryFunction operation)  
 {  
   if (isExpanded()) {  
     DataExpanded* leftC=dynamic_cast<DataExpanded*>(m_data.get());  
     EsysAssert((leftC!=0), "Programming error - casting to DataExpanded.");  
     escript::unaryOp(*leftC,operation);  
   } else if (isTagged()) {  
     DataTagged* leftC=dynamic_cast<DataTagged*>(m_data.get());  
     EsysAssert((leftC!=0), "Programming error - casting to DataTagged.");  
     escript::unaryOp(*leftC,operation);  
   } else if (isConstant()) {  
     DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());  
     EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");  
     escript::unaryOp(*leftC,operation);  
   }  
 }  
   
 /**  
   \brief  
1616    Perform the given Data object reduction algorithm on this and return the result.    Perform the given Data object reduction algorithm on this and return the result.
1617    Given operation combines each element of each data point, thus argument    Given operation combines each element of each data point, thus argument
1618    object (*this) is a rank n Data object, and returned object is a scalar.    object (*this) is a rank n Data object, and returned object is a scalar.
# Line 1686  Data::algorithm(BinaryFunction operation Line 1643  Data::algorithm(BinaryFunction operation
1643    \brief    \brief
1644    Perform the given data point reduction algorithm on data and return the result.    Perform the given data point reduction algorithm on data and return the result.
1645    Given operation combines each element within each data point into a scalar,    Given operation combines each element within each data point into a scalar,
1646    thus argument object is a rank n Data object, and returned object is a    thus argument object is a rank n Data object, and returned object is a
1647    rank 0 Data object.    rank 0 Data object.
1648    Calls escript::dp_algorithm.    Calls escript::dp_algorithm.
1649  */  */
# Line 1735  Data::dp_algorithm(BinaryFunction operat Line 1692  Data::dp_algorithm(BinaryFunction operat
1692    return falseRetVal;    return falseRetVal;
1693  }  }
1694    
1695    /**
1696      \brief
1697      Compute a tensor operation with two Data objects
1698      \param arg0 - Input - Data object
1699      \param arg1 - Input - Data object
1700      \param operation - Input - Binary op functor
1701    */
1702    template <typename BinaryFunction>
1703    inline
1704    Data
1705    C_TensorBinaryOperation(Data const &arg_0,
1706                            Data const &arg_1,
1707                            BinaryFunction operation)
1708    {
1709      // Interpolate if necessary and find an appropriate function space
1710      Data arg_0_Z, arg_1_Z;
1711      if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
1712        if (arg_0.probeInterpolation(arg_1.getFunctionSpace())) {
1713          arg_0_Z = arg_0.interpolate(arg_1.getFunctionSpace());
1714          arg_1_Z = Data(arg_1);
1715        }
1716        else if (arg_1.probeInterpolation(arg_0.getFunctionSpace())) {
1717          arg_1_Z=arg_1.interpolate(arg_0.getFunctionSpace());
1718          arg_0_Z =Data(arg_0);
1719        }
1720        else {
1721          throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible function spaces.");
1722        }
1723      } else {
1724          arg_0_Z = Data(arg_0);
1725          arg_1_Z = Data(arg_1);
1726      }
1727      // Get rank and shape of inputs
1728      int rank0 = arg_0_Z.getDataPointRank();
1729      int rank1 = arg_1_Z.getDataPointRank();
1730      DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();
1731      DataArrayView::ShapeType shape1 = arg_1_Z.getDataPointShape();
1732      int size0 = arg_0_Z.getDataPointSize();
1733      int size1 = arg_1_Z.getDataPointSize();
1734    
1735      // Declare output Data object
1736      Data res;
1737    
1738      if (shape0 == shape1) {
1739    
1740        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1741          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
1742          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1743          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1744          double *ptr_2 = &((res.getPointDataView().getData())[0]);
1745          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1746        }
1747        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
1748    
1749          // Prepare the DataConstant input
1750          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1751    
1752          // Borrow DataTagged input from Data object
1753          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1754    
1755          // Prepare a DataTagged output 2
1756          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
1757          res.tag();
1758          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1759    
1760          // Prepare offset into DataConstant
1761          int offset_0 = tmp_0->getPointOffset(0,0);
1762          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1763          // Get the views
1764          DataArrayView view_1 = tmp_1->getDefaultValue();
1765          DataArrayView view_2 = tmp_2->getDefaultValue();
1766          // Get the pointers to the actual data
1767          double *ptr_1 = &((view_1.getData())[0]);
1768          double *ptr_2 = &((view_2.getData())[0]);
1769          // Compute a result for the default
1770          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1771          // Compute a result for each tag
1772          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1773          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1774          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1775            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
1776            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1777            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1778            double *ptr_1 = &view_1.getData(0);
1779            double *ptr_2 = &view_2.getData(0);
1780            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1781          }
1782    
1783        }
1784        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
1785    
1786          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1787          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1788          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1789          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1790    
1791          int sampleNo_1,dataPointNo_1;
1792          int numSamples_1 = arg_1_Z.getNumSamples();
1793          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
1794          int offset_0 = tmp_0->getPointOffset(0,0);
1795          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
1796          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
1797            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
1798              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
1799              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
1800              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1801              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1802              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1803              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1804            }
1805          }
1806    
1807        }
1808        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
1809    
1810          // Borrow DataTagged input from Data object
1811          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1812    
1813          // Prepare the DataConstant input
1814          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
1815    
1816          // Prepare a DataTagged output 2
1817          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
1818          res.tag();
1819          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1820    
1821          // Prepare offset into DataConstant
1822          int offset_1 = tmp_1->getPointOffset(0,0);
1823          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1824          // Get the views
1825          DataArrayView view_0 = tmp_0->getDefaultValue();
1826          DataArrayView view_2 = tmp_2->getDefaultValue();
1827          // Get the pointers to the actual data
1828          double *ptr_0 = &((view_0.getData())[0]);
1829          double *ptr_2 = &((view_2.getData())[0]);
1830          // Compute a result for the default
1831          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1832          // Compute a result for each tag
1833          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1834          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1835          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1836            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
1837            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1838            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1839            double *ptr_0 = &view_0.getData(0);
1840            double *ptr_2 = &view_2.getData(0);
1841            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1842          }
1843    
1844        }
1845        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
1846    
1847          // Borrow DataTagged input from Data object
1848          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1849    
1850          // Borrow DataTagged input from Data object
1851          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1852    
1853          // Prepare a DataTagged output 2
1854          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
1855          res.tag();        // DataTagged output
1856          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1857    
1858          // Get the views
1859          DataArrayView view_0 = tmp_0->getDefaultValue();
1860          DataArrayView view_1 = tmp_1->getDefaultValue();
1861          DataArrayView view_2 = tmp_2->getDefaultValue();
1862          // Get the pointers to the actual data
1863          double *ptr_0 = &((view_0.getData())[0]);
1864          double *ptr_1 = &((view_1.getData())[0]);
1865          double *ptr_2 = &((view_2.getData())[0]);
1866          // Compute a result for the default
1867          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1868          // Merge the tags
1869          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1870          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1871          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1872          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1873            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
1874          }
1875          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1876            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
1877          }
1878          // Compute a result for each tag
1879          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
1880          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
1881            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1882            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1883            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1884            double *ptr_0 = &view_0.getData(0);
1885            double *ptr_1 = &view_1.getData(0);
1886            double *ptr_2 = &view_2.getData(0);
1887            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1888          }
1889    
1890        }
1891        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
1892    
1893          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1894          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1895          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1896          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1897          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1898    
1899          int sampleNo_0,dataPointNo_0;
1900          int numSamples_0 = arg_0_Z.getNumSamples();
1901          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1902          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1903          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1904            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
1905            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1906            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1907              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
1908              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1909              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1910              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1911              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1912            }
1913          }
1914    
1915        }
1916        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
1917    
1918          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1919          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
1920          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
1921          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1922    
1923          int sampleNo_0,dataPointNo_0;
1924          int numSamples_0 = arg_0_Z.getNumSamples();
1925          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1926          int offset_1 = tmp_1->getPointOffset(0,0);
1927          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1928          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1929            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1930              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
1931              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1932              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1933              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1934              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1935              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1936            }
1937          }
1938    
1939        }
1940        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
1941    
1942          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1943          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1944          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
1945          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1946          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1947    
1948          int sampleNo_0,dataPointNo_0;
1949          int numSamples_0 = arg_0_Z.getNumSamples();
1950          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1951          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1952          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1953            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
1954            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1955            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1956              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
1957              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1958              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1959              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1960              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1961            }
1962          }
1963    
1964        }
1965        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
1966    
1967          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1968          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1969          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
1970          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1971          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1972    
1973          int sampleNo_0,dataPointNo_0;
1974          int numSamples_0 = arg_0_Z.getNumSamples();
1975          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1976          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1977          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1978            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1979              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
1980              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
1981              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1982              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1983              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1984              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1985              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1986            }
1987          }
1988    
1989        }
1990        else {
1991          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
1992        }
1993    
1994      } else if (0 == rank0) {
1995    
1996        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1997          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output
1998          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1999          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
2000          double *ptr_2 = &((res.getPointDataView().getData())[0]);
2001          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2002        }
2003        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2004    
2005          // Prepare the DataConstant input
2006          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2007    
2008          // Borrow DataTagged input from Data object
2009          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2010    
2011          // Prepare a DataTagged output 2
2012          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataTagged output
2013          res.tag();
2014          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2015    
2016          // Prepare offset into DataConstant
2017          int offset_0 = tmp_0->getPointOffset(0,0);
2018          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2019          // Get the views
2020          DataArrayView view_1 = tmp_1->getDefaultValue();
2021          DataArrayView view_2 = tmp_2->getDefaultValue();
2022          // Get the pointers to the actual data
2023          double *ptr_1 = &((view_1.getData())[0]);
2024          double *ptr_2 = &((view_2.getData())[0]);
2025          // Compute a result for the default
2026          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2027          // Compute a result for each tag
2028          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2029          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2030          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2031            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2032            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2033            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2034            double *ptr_1 = &view_1.getData(0);
2035            double *ptr_2 = &view_2.getData(0);
2036            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2037          }
2038    
2039        }
2040        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2041    
2042          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2043          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2044          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2045          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2046    
2047          int sampleNo_1,dataPointNo_1;
2048          int numSamples_1 = arg_1_Z.getNumSamples();
2049          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2050          int offset_0 = tmp_0->getPointOffset(0,0);
2051          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2052          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2053            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2054              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2055              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2056              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2057              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2058              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2059              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2060    
2061            }
2062          }
2063    
2064        }
2065        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2066    
2067          // Borrow DataTagged input from Data object
2068          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2069    
2070          // Prepare the DataConstant input
2071          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2072    
2073          // Prepare a DataTagged output 2
2074          res = Data(0.0, shape1, arg_0_Z.getFunctionSpace());      // DataTagged output
2075          res.tag();
2076          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2077    
2078          // Prepare offset into DataConstant
2079          int offset_1 = tmp_1->getPointOffset(0,0);
2080          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2081          // Get the views
2082          DataArrayView view_0 = tmp_0->getDefaultValue();
2083          DataArrayView view_2 = tmp_2->getDefaultValue();
2084          // Get the pointers to the actual data
2085          double *ptr_0 = &((view_0.getData())[0]);
2086          double *ptr_2 = &((view_2.getData())[0]);
2087          // Compute a result for the default
2088          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2089          // Compute a result for each tag
2090          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2091          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2092          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2093            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2094            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2095            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2096            double *ptr_0 = &view_0.getData(0);
2097            double *ptr_2 = &view_2.getData(0);
2098            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2099          }
2100    
2101        }
2102        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2103    
2104          // Borrow DataTagged input from Data object
2105          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2106    
2107          // Borrow DataTagged input from Data object
2108          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2109    
2110          // Prepare a DataTagged output 2
2111          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());
2112          res.tag();        // DataTagged output
2113          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2114    
2115          // Get the views
2116          DataArrayView view_0 = tmp_0->getDefaultValue();
2117          DataArrayView view_1 = tmp_1->getDefaultValue();
2118          DataArrayView view_2 = tmp_2->getDefaultValue();
2119          // Get the pointers to the actual data
2120          double *ptr_0 = &((view_0.getData())[0]);
2121          double *ptr_1 = &((view_1.getData())[0]);
2122          double *ptr_2 = &((view_2.getData())[0]);
2123          // Compute a result for the default
2124          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2125          // Merge the tags
2126          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2127          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2128          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2129          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2130            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
2131          }
2132          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2133            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2134          }
2135          // Compute a result for each tag
2136          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2137          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2138            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2139            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2140            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2141            double *ptr_0 = &view_0.getData(0);
2142            double *ptr_1 = &view_1.getData(0);
2143            double *ptr_2 = &view_2.getData(0);
2144            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2145          }
2146    
2147        }
2148        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2149    
2150          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2151          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2152          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2153          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2154          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2155    
2156          int sampleNo_0,dataPointNo_0;
2157          int numSamples_0 = arg_0_Z.getNumSamples();
2158          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2159          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2160          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2161            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2162            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2163            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2164              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2165              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2166              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2167              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2168              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2169            }
2170          }
2171    
2172        }
2173        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2174    
2175          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2176          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2177          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2178          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2179    
2180          int sampleNo_0,dataPointNo_0;
2181          int numSamples_0 = arg_0_Z.getNumSamples();
2182          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2183          int offset_1 = tmp_1->getPointOffset(0,0);
2184          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2185          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2186            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2187              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2188              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2189              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2190              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2191              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2192              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2193            }
2194          }
2195    
2196    
2197        }
2198        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2199    
2200          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2201          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2202          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2203          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2204          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2205    
2206          int sampleNo_0,dataPointNo_0;
2207          int numSamples_0 = arg_0_Z.getNumSamples();
2208          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2209          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2210          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2211            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2212            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2213            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2214              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2215              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2216              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2217              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2218              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2219            }
2220          }
2221    
2222        }
2223        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2224    
2225          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2226          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2227          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2228          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2229          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2230    
2231          int sampleNo_0,dataPointNo_0;
2232          int numSamples_0 = arg_0_Z.getNumSamples();
2233          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2234          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2235          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2236            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2237              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2238              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2239              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2240              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2241              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2242              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2243              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2244            }
2245          }
2246    
2247        }
2248        else {
2249          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2250        }
2251    
2252      } else if (0 == rank1) {
2253    
2254        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2255          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
2256          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2257          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
2258          double *ptr_2 = &((res.getPointDataView().getData())[0]);
2259          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2260        }
2261        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2262    
2263          // Prepare the DataConstant input
2264          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2265    
2266          // Borrow DataTagged input from Data object
2267          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2268    
2269          // Prepare a DataTagged output 2
2270          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
2271          res.tag();
2272          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2273    
2274          // Prepare offset into DataConstant
2275          int offset_0 = tmp_0->getPointOffset(0,0);
2276          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2277          // Get the views
2278          DataArrayView view_1 = tmp_1->getDefaultValue();
2279          DataArrayView view_2 = tmp_2->getDefaultValue();
2280          // Get the pointers to the actual data
2281          double *ptr_1 = &((view_1.getData())[0]);
2282          double *ptr_2 = &((view_2.getData())[0]);
2283          // Compute a result for the default
2284          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2285          // Compute a result for each tag
2286          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2287          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2288          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2289            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2290            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2291            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2292            double *ptr_1 = &view_1.getData(0);
2293            double *ptr_2 = &view_2.getData(0);
2294            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2295          }
2296    
2297        }
2298        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2299    
2300          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2301          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2302          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2303          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2304    
2305          int sampleNo_1,dataPointNo_1;
2306          int numSamples_1 = arg_1_Z.getNumSamples();
2307          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2308          int offset_0 = tmp_0->getPointOffset(0,0);
2309          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2310          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2311            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2312              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2313              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2314              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2315              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2316              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2317              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2318            }
2319          }
2320    
2321        }
2322        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2323    
2324          // Borrow DataTagged input from Data object
2325          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2326    
2327          // Prepare the DataConstant input
2328          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2329    
2330          // Prepare a DataTagged output 2
2331          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
2332          res.tag();
2333          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2334    
2335          // Prepare offset into DataConstant
2336          int offset_1 = tmp_1->getPointOffset(0,0);
2337          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2338          // Get the views
2339          DataArrayView view_0 = tmp_0->getDefaultValue();
2340          DataArrayView view_2 = tmp_2->getDefaultValue();
2341          // Get the pointers to the actual data
2342          double *ptr_0 = &((view_0.getData())[0]);
2343          double *ptr_2 = &((view_2.getData())[0]);
2344          // Compute a result for the default
2345          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2346          // Compute a result for each tag
2347          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2348          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2349          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2350            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2351            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2352            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2353            double *ptr_0 = &view_0.getData(0);
2354            double *ptr_2 = &view_2.getData(0);
2355            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2356          }
2357    
2358        }
2359        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2360    
2361          // Borrow DataTagged input from Data object
2362          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2363    
2364          // Borrow DataTagged input from Data object
2365          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2366    
2367          // Prepare a DataTagged output 2
2368          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
2369          res.tag();        // DataTagged output
2370          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2371    
2372          // Get the views
2373          DataArrayView view_0 = tmp_0->getDefaultValue();
2374          DataArrayView view_1 = tmp_1->getDefaultValue();
2375          DataArrayView view_2 = tmp_2->getDefaultValue();
2376          // Get the pointers to the actual data
2377          double *ptr_0 = &((view_0.getData())[0]);
2378          double *ptr_1 = &((view_1.getData())[0]);
2379          double *ptr_2 = &((view_2.getData())[0]);
2380          // Compute a result for the default
2381          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2382          // Merge the tags
2383          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2384          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2385          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2386          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2387            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
2388          }
2389          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2390            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2391          }
2392          // Compute a result for each tag
2393          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2394          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2395            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2396            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2397            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2398            double *ptr_0 = &view_0.getData(0);
2399            double *ptr_1 = &view_1.getData(0);
2400            double *ptr_2 = &view_2.getData(0);
2401            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2402          }
2403    
2404        }
2405        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2406    
2407          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2408          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2409          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2410          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2411          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2412    
2413          int sampleNo_0,dataPointNo_0;
2414          int numSamples_0 = arg_0_Z.getNumSamples();
2415          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2416          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2417          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2418            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2419            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2420            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2421              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2422              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2423              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2424              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2425              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2426            }
2427          }
2428    
2429        }
2430        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2431    
2432          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2433          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2434          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2435          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2436    
2437          int sampleNo_0,dataPointNo_0;
2438          int numSamples_0 = arg_0_Z.getNumSamples();
2439          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2440          int offset_1 = tmp_1->getPointOffset(0,0);
2441          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2442          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2443            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2444              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2445              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2446              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2447              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2448              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2449              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2450            }
2451          }
2452    
2453    
2454        }
2455        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2456    
2457          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2458          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2459          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2460          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2461          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2462    
2463          int sampleNo_0,dataPointNo_0;
2464          int numSamples_0 = arg_0_Z.getNumSamples();
2465          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2466          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2467          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2468            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2469            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2470            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2471              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2472              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2473              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2474              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2475              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2476            }
2477          }
2478    
2479        }
2480        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2481    
2482          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2483          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2484          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2485          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2486          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2487    
2488          int sampleNo_0,dataPointNo_0;
2489          int numSamples_0 = arg_0_Z.getNumSamples();
2490          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2491          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2492          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2493            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2494              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2495              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2496              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2497              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2498              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2499              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2500              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2501            }
2502          }
2503    
2504        }
2505        else {
2506          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2507        }
2508    
2509      } else {
2510        throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible shapes");
2511      }
2512    
2513      return res;
2514    }
2515    
2516    template <typename UnaryFunction>
2517    Data
2518    C_TensorUnaryOperation(Data const &arg_0,
2519                           UnaryFunction operation)
2520    {
2521      // Interpolate if necessary and find an appropriate function space
2522      Data arg_0_Z = Data(arg_0);
2523    
2524      // Get rank and shape of inputs
2525      int rank0 = arg_0_Z.getDataPointRank();
2526      DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();
2527      int size0 = arg_0_Z.getDataPointSize();
2528    
2529      // Declare output Data object
2530      Data res;
2531    
2532      if (arg_0_Z.isConstant()) {
2533        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output
2534        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2535        double *ptr_2 = &((res.getPointDataView().getData())[0]);
2536        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2537      }
2538      else if (arg_0_Z.isTagged()) {
2539    
2540        // Borrow DataTagged input from Data object
2541        DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2542    
2543        // Prepare a DataTagged output 2
2544        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());   // DataTagged output
2545        res.tag();
2546        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2547    
2548        // Get the views
2549        DataArrayView view_0 = tmp_0->getDefaultValue();
2550        DataArrayView view_2 = tmp_2->getDefaultValue();
2551        // Get the pointers to the actual data
2552        double *ptr_0 = &((view_0.getData())[0]);
2553        double *ptr_2 = &((view_2.getData())[0]);
2554        // Compute a result for the default
2555        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2556        // Compute a result for each tag
2557        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2558        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2559        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2560          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2561          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2562          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2563          double *ptr_0 = &view_0.getData(0);
2564          double *ptr_2 = &view_2.getData(0);
2565          tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2566        }
2567    
2568      }
2569      else if (arg_0_Z.isExpanded()) {
2570    
2571        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace(),true); // DataExpanded output
2572        DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2573        DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2574    
2575        int sampleNo_0,dataPointNo_0;
2576        int numSamples_0 = arg_0_Z.getNumSamples();
2577        int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2578        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2579        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2580          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2581            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2582            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2583            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2584            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2585            tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2586          }
2587        }
2588    
2589      }
2590      else {
2591        throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");
2592      }
2593    
2594      return res;
2595    }
2596    
2597  }  }
2598  #endif  #endif

Legend:
Removed from v.782  
changed lines
  Added in v.1748

  ViewVC Help
Powered by ViewVC 1.1.26