/[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 854 by gross, Thu Sep 21 05:29:42 2006 UTC revision 1719 by gross, Thu Aug 21 06:24:29 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  #ifndef PASO_MPI  #include "esysmpi.h"
 #define MPI_Comm long  
 #endif  
   
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 51  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 214  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 239  class Data { Line 240  class Data {
240    
241    /**    /**
242       \brief       \brief
243       switches on update protection       switches on update protection
244    
245    */    */
246    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 254  class Data { Line 255  class Data {
255    ESCRIPT_DLL_API    ESCRIPT_DLL_API
256    bool    bool
257    isProtected() const;    isProtected() const;
258    
259    /**    /**
260       \brief       \brief
261       Return the values of all data-points 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    convertToNumArray();    getValueOfDataPoint(int dataPointNo);
266    
267    /**    /**
268       \brief       \brief
269       Return the values of all data-points for the given sample as a single 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    const boost::python::numeric::array    void
273    convertToNumArrayFromSampleNo(int sampleNo);    setValueOfDataPointToPyObject(int dataPointNo, const boost::python::object& py_object);
274    
275    /**    /**
276       \brief       \brief
277       Return the value of the specified data-point as a single python numarray object.       sets the values of a data-point from a numarray object on this process
278    */    */
 #ifndef PASO_MPI    
279    ESCRIPT_DLL_API    ESCRIPT_DLL_API
280    const boost::python::numeric::array    void
281    convertToNumArrayFromDPNo(int ProcNo,    setValueOfDataPointToArray(int dataPointNo, const boost::python::numeric::array&);
                                                         int sampleNo,  
                             int dataPointNo);  
 #else  
   ESCRIPT_DLL_API  
   const boost::python::numeric::array  
   convertToNumArrayFromDPNo(int procNo,  
                 int sampleNo,  
                 int dataPointNo);  
 #endif  
   
282    
283    /**    /**
284       \brief       \brief
285       Fills the expanded Data object from values of a python numarray object.       sets the values of a data-point on this process
286    */    */
287    ESCRIPT_DLL_API    ESCRIPT_DLL_API
288    void    void
289    fillFromNumArray(const boost::python::numeric::array);    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 326  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 455  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 476  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 507  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 560  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 596  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 613  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 639  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 646  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 743  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 802  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    calc_mindp(int& ProcNo,    calc_minGlobalDataPoint(int& ProcNo,  int& DataPointNo) const;
                         int& SampleNo,    
              int& DataPointNo) const;  
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 868  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 889  class Data { Line 872  class Data {
872    
873    /**    /**
874       \brief       \brief
875         Return the error function erf of each data point of this Data object.
876         *
877      */
878      ESCRIPT_DLL_API
879      Data
880      erf() const;
881    
882      /**
883         \brief
884       Return the sin of each data point of this Data object.       Return the sin of each data point of this Data object.
885       *       *
886    */    */
# Line 1064  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 1075  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 1111  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 1203  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 1254  class Data { Line 1249  class Data {
1249    
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    
1287    /**    /**
1288       \brief       \brief
1289       return the object produced by the factory, which is a DataConstant or DataExpanded       return the object produced by the factory, which is a DataConstant or DataExpanded
1290    */    */
1291    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1292      DataAbstract*          DataAbstract*
1293      borrowData(void) const;          borrowData(void) const;
1294    
1295   protected:   protected:
1296    
# Line 1386  class Data { Line 1381  class Data {
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 1417  Data::initialise(const IValueType& value Line 1408  Data::initialise(const IValueType& value
1408  /**  /**
1409     Binary Data object operators.     Binary Data object operators.
1410  */  */
1411  inline double rpow(double x,double y)  inline double rpow(double x,double y)
1412  {  {
1413      return pow(y,x);      return pow(y,x);
1414  };  }
1415    
1416  /**  /**
1417    \brief    \brief
# Line 1514  ESCRIPT_DLL_API Data operator*(const boo Line 1505  ESCRIPT_DLL_API Data operator*(const boo
1505  */  */
1506  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);
1507    
1508    
1509    
1510  /**  /**
1511    \brief    \brief
1512    Output operator    Output operator
# Line 1535  C_GeneralTensorProduct(Data& arg0, Line 1528  C_GeneralTensorProduct(Data& arg0,
1528                       int axis_offset=0,                       int axis_offset=0,
1529                       int transpose=0);                       int transpose=0);
1530    
1531    
1532    
1533  /**  /**
1534    \brief    \brief
1535    Return true if operands are equivalent, else return false.    Return true if operands are equivalent, else return false.
1536    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
1537    be relied on. Requires further implementation.    be relied on. Requires further implementation.
1538  */  */
1539  //ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);  // ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);
1540    
1541  /**  /**
1542    \brief    \brief
# Line 1565  Data::binaryOp(const Data& right, Line 1560  Data::binaryOp(const Data& right,
1560     if (getFunctionSpace()!=right.getFunctionSpace()) {     if (getFunctionSpace()!=right.getFunctionSpace()) {
1561       if (right.probeInterpolation(getFunctionSpace())) {       if (right.probeInterpolation(getFunctionSpace())) {
1562         //         //
1563         // an interpolation is required so create a new Data         // an interpolation is required so create a new Data
1564         tempRight=Data(right,this->getFunctionSpace());         tempRight=Data(right,this->getFunctionSpace());
1565       } else if (probeInterpolation(right.getFunctionSpace())) {       } else if (probeInterpolation(right.getFunctionSpace())) {
1566         //         //
# Line 1609  Data::binaryOp(const Data& right, Line 1604  Data::binaryOp(const Data& right,
1604       EsysAssert((leftC!=0 && rightC!=0), "Programming error - casting to DataConstant.");       EsysAssert((leftC!=0 && rightC!=0), "Programming error - casting to DataConstant.");
1605       escript::binaryOp(*leftC,*rightC,operation);       escript::binaryOp(*leftC,*rightC,operation);
1606     }     }
    #if defined DOPROF  
    profData->binary++;  
    #endif  
 }  
   
 /**  
   \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);  
   }  
1607  }  }
1608    
1609  /**  /**
# Line 1692  Data::algorithm(BinaryFunction operation Line 1638  Data::algorithm(BinaryFunction operation
1638    \brief    \brief
1639    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.
1640    Given operation combines each element within each data point into a scalar,    Given operation combines each element within each data point into a scalar,
1641    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
1642    rank 0 Data object.    rank 0 Data object.
1643    Calls escript::dp_algorithm.    Calls escript::dp_algorithm.
1644  */  */
# Line 1741  Data::dp_algorithm(BinaryFunction operat Line 1687  Data::dp_algorithm(BinaryFunction operat
1687    return falseRetVal;    return falseRetVal;
1688  }  }
1689    
1690    /**
1691      \brief
1692      Compute a tensor operation with two Data objects
1693      \param arg0 - Input - Data object
1694      \param arg1 - Input - Data object
1695      \param operation - Input - Binary op functor
1696    */
1697    template <typename BinaryFunction>
1698    inline
1699    Data
1700    C_TensorBinaryOperation(Data const &arg_0,
1701                            Data const &arg_1,
1702                            BinaryFunction operation)
1703    {
1704      // Interpolate if necessary and find an appropriate function space
1705      Data arg_0_Z, arg_1_Z;
1706      if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
1707        if (arg_0.probeInterpolation(arg_1.getFunctionSpace())) {
1708          arg_0_Z = arg_0.interpolate(arg_1.getFunctionSpace());
1709          arg_1_Z = Data(arg_1);
1710        }
1711        else if (arg_1.probeInterpolation(arg_0.getFunctionSpace())) {
1712          arg_1_Z=arg_1.interpolate(arg_0.getFunctionSpace());
1713          arg_0_Z =Data(arg_0);
1714        }
1715        else {
1716          throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible function spaces.");
1717        }
1718      } else {
1719          arg_0_Z = Data(arg_0);
1720          arg_1_Z = Data(arg_1);
1721      }
1722      // Get rank and shape of inputs
1723      int rank0 = arg_0_Z.getDataPointRank();
1724      int rank1 = arg_1_Z.getDataPointRank();
1725      DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();
1726      DataArrayView::ShapeType shape1 = arg_1_Z.getDataPointShape();
1727      int size0 = arg_0_Z.getDataPointSize();
1728      int size1 = arg_1_Z.getDataPointSize();
1729    
1730      // Declare output Data object
1731      Data res;
1732    
1733      if (shape0 == shape1) {
1734    
1735        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1736          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
1737          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1738          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1739          double *ptr_2 = &((res.getPointDataView().getData())[0]);
1740          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1741        }
1742        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
1743    
1744          // Prepare the DataConstant input
1745          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1746    
1747          // Borrow DataTagged input from Data object
1748          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1749    
1750          // Prepare a DataTagged output 2
1751          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
1752          res.tag();
1753          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1754    
1755          // Prepare offset into DataConstant
1756          int offset_0 = tmp_0->getPointOffset(0,0);
1757          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1758          // Get the views
1759          DataArrayView view_1 = tmp_1->getDefaultValue();
1760          DataArrayView view_2 = tmp_2->getDefaultValue();
1761          // Get the pointers to the actual data
1762          double *ptr_1 = &((view_1.getData())[0]);
1763          double *ptr_2 = &((view_2.getData())[0]);
1764          // Compute a result for the default
1765          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1766          // Compute a result for each tag
1767          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1768          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1769          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1770            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
1771            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1772            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1773            double *ptr_1 = &view_1.getData(0);
1774            double *ptr_2 = &view_2.getData(0);
1775            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1776          }
1777    
1778        }
1779        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
1780    
1781          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1782          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1783          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1784          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1785    
1786          int sampleNo_1,dataPointNo_1;
1787          int numSamples_1 = arg_1_Z.getNumSamples();
1788          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
1789          int offset_0 = tmp_0->getPointOffset(0,0);
1790          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
1791          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
1792            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
1793              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
1794              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
1795              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1796              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1797              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1798              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1799            }
1800          }
1801    
1802        }
1803        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
1804    
1805          // Borrow DataTagged input from Data object
1806          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1807    
1808          // Prepare the DataConstant input
1809          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
1810    
1811          // Prepare a DataTagged output 2
1812          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
1813          res.tag();
1814          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1815    
1816          // Prepare offset into DataConstant
1817          int offset_1 = tmp_1->getPointOffset(0,0);
1818          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1819          // Get the views
1820          DataArrayView view_0 = tmp_0->getDefaultValue();
1821          DataArrayView view_2 = tmp_2->getDefaultValue();
1822          // Get the pointers to the actual data
1823          double *ptr_0 = &((view_0.getData())[0]);
1824          double *ptr_2 = &((view_2.getData())[0]);
1825          // Compute a result for the default
1826          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1827          // Compute a result for each tag
1828          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1829          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1830          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1831            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
1832            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1833            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1834            double *ptr_0 = &view_0.getData(0);
1835            double *ptr_2 = &view_2.getData(0);
1836            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1837          }
1838    
1839        }
1840        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
1841    
1842          // Borrow DataTagged input from Data object
1843          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1844    
1845          // Borrow DataTagged input from Data object
1846          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1847    
1848          // Prepare a DataTagged output 2
1849          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
1850          res.tag();        // DataTagged output
1851          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1852    
1853          // Get the views
1854          DataArrayView view_0 = tmp_0->getDefaultValue();
1855          DataArrayView view_1 = tmp_1->getDefaultValue();
1856          DataArrayView view_2 = tmp_2->getDefaultValue();
1857          // Get the pointers to the actual data
1858          double *ptr_0 = &((view_0.getData())[0]);
1859          double *ptr_1 = &((view_1.getData())[0]);
1860          double *ptr_2 = &((view_2.getData())[0]);
1861          // Compute a result for the default
1862          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1863          // Merge the tags
1864          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1865          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1866          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1867          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1868            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
1869          }
1870          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1871            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
1872          }
1873          // Compute a result for each tag
1874          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
1875          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
1876            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1877            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1878            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1879            double *ptr_0 = &view_0.getData(0);
1880            double *ptr_1 = &view_1.getData(0);
1881            double *ptr_2 = &view_2.getData(0);
1882            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1883          }
1884    
1885        }
1886        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
1887    
1888          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1889          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1890          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1891          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1892          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1893    
1894          int sampleNo_0,dataPointNo_0;
1895          int numSamples_0 = arg_0_Z.getNumSamples();
1896          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1897          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1898          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1899            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
1900            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1901            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1902              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
1903              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1904              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1905              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1906              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1907            }
1908          }
1909    
1910        }
1911        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
1912    
1913          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1914          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
1915          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
1916          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1917    
1918          int sampleNo_0,dataPointNo_0;
1919          int numSamples_0 = arg_0_Z.getNumSamples();
1920          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1921          int offset_1 = tmp_1->getPointOffset(0,0);
1922          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1923          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1924            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1925              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
1926              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1927              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1928              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1929              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1930              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1931            }
1932          }
1933    
1934        }
1935        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
1936    
1937          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1938          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1939          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
1940          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1941          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1942    
1943          int sampleNo_0,dataPointNo_0;
1944          int numSamples_0 = arg_0_Z.getNumSamples();
1945          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1946          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1947          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1948            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
1949            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1950            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1951              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
1952              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1953              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1954              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1955              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1956            }
1957          }
1958    
1959        }
1960        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
1961    
1962          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1963          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1964          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
1965          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1966          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1967    
1968          int sampleNo_0,dataPointNo_0;
1969          int numSamples_0 = arg_0_Z.getNumSamples();
1970          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1971          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1972          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1973            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1974              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
1975              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
1976              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
1977              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1978              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1979              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1980              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1981            }
1982          }
1983    
1984        }
1985        else {
1986          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
1987        }
1988    
1989      } else if (0 == rank0) {
1990    
1991        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1992          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output
1993          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1994          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1995          double *ptr_2 = &((res.getPointDataView().getData())[0]);
1996          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
1997        }
1998        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
1999    
2000          // Prepare the DataConstant input
2001          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2002    
2003          // Borrow DataTagged input from Data object
2004          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2005    
2006          // Prepare a DataTagged output 2
2007          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataTagged output
2008          res.tag();
2009          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2010    
2011          // Prepare offset into DataConstant
2012          int offset_0 = tmp_0->getPointOffset(0,0);
2013          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2014          // Get the views
2015          DataArrayView view_1 = tmp_1->getDefaultValue();
2016          DataArrayView view_2 = tmp_2->getDefaultValue();
2017          // Get the pointers to the actual data
2018          double *ptr_1 = &((view_1.getData())[0]);
2019          double *ptr_2 = &((view_2.getData())[0]);
2020          // Compute a result for the default
2021          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2022          // Compute a result for each tag
2023          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2024          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2025          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2026            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2027            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2028            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2029            double *ptr_1 = &view_1.getData(0);
2030            double *ptr_2 = &view_2.getData(0);
2031            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2032          }
2033    
2034        }
2035        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2036    
2037          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2038          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2039          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2040          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2041    
2042          int sampleNo_1,dataPointNo_1;
2043          int numSamples_1 = arg_1_Z.getNumSamples();
2044          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2045          int offset_0 = tmp_0->getPointOffset(0,0);
2046          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2047          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2048            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2049              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2050              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2051              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2052              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2053              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2054              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2055    
2056            }
2057          }
2058    
2059        }
2060        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2061    
2062          // Borrow DataTagged input from Data object
2063          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2064    
2065          // Prepare the DataConstant input
2066          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2067    
2068          // Prepare a DataTagged output 2
2069          res = Data(0.0, shape1, arg_0_Z.getFunctionSpace());      // DataTagged output
2070          res.tag();
2071          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2072    
2073          // Prepare offset into DataConstant
2074          int offset_1 = tmp_1->getPointOffset(0,0);
2075          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2076          // Get the views
2077          DataArrayView view_0 = tmp_0->getDefaultValue();
2078          DataArrayView view_2 = tmp_2->getDefaultValue();
2079          // Get the pointers to the actual data
2080          double *ptr_0 = &((view_0.getData())[0]);
2081          double *ptr_2 = &((view_2.getData())[0]);
2082          // Compute a result for the default
2083          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2084          // Compute a result for each tag
2085          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2086          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2087          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2088            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2089            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2090            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2091            double *ptr_0 = &view_0.getData(0);
2092            double *ptr_2 = &view_2.getData(0);
2093            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2094          }
2095    
2096        }
2097        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2098    
2099          // Borrow DataTagged input from Data object
2100          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2101    
2102          // Borrow DataTagged input from Data object
2103          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2104    
2105          // Prepare a DataTagged output 2
2106          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());
2107          res.tag();        // DataTagged output
2108          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2109    
2110          // Get the views
2111          DataArrayView view_0 = tmp_0->getDefaultValue();
2112          DataArrayView view_1 = tmp_1->getDefaultValue();
2113          DataArrayView view_2 = tmp_2->getDefaultValue();
2114          // Get the pointers to the actual data
2115          double *ptr_0 = &((view_0.getData())[0]);
2116          double *ptr_1 = &((view_1.getData())[0]);
2117          double *ptr_2 = &((view_2.getData())[0]);
2118          // Compute a result for the default
2119          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2120          // Merge the tags
2121          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2122          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2123          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2124          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2125            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
2126          }
2127          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2128            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2129          }
2130          // Compute a result for each tag
2131          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2132          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2133            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2134            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2135            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2136            double *ptr_0 = &view_0.getData(0);
2137            double *ptr_1 = &view_1.getData(0);
2138            double *ptr_2 = &view_2.getData(0);
2139            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2140          }
2141    
2142        }
2143        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2144    
2145          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2146          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2147          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2148          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2149          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2150    
2151          int sampleNo_0,dataPointNo_0;
2152          int numSamples_0 = arg_0_Z.getNumSamples();
2153          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2154          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2155          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2156            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2157            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2158            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2159              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2160              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2161              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2162              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2163              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2164            }
2165          }
2166    
2167        }
2168        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2169    
2170          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2171          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2172          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2173          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2174    
2175          int sampleNo_0,dataPointNo_0;
2176          int numSamples_0 = arg_0_Z.getNumSamples();
2177          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2178          int offset_1 = tmp_1->getPointOffset(0,0);
2179          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2180          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2181            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2182              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2183              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2184              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2185              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2186              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2187              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2188            }
2189          }
2190    
2191    
2192        }
2193        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2194    
2195          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2196          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2197          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2198          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2199          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2200    
2201          int sampleNo_0,dataPointNo_0;
2202          int numSamples_0 = arg_0_Z.getNumSamples();
2203          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2204          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2205          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2206            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2207            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2208            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2209              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2210              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2211              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2212              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2213              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2214            }
2215          }
2216    
2217        }
2218        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2219    
2220          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2221          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2222          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2223          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2224          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2225    
2226          int sampleNo_0,dataPointNo_0;
2227          int numSamples_0 = arg_0_Z.getNumSamples();
2228          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2229          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2230          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2231            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2232              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2233              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2234              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2235              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2236              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2237              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2238              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2239            }
2240          }
2241    
2242        }
2243        else {
2244          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2245        }
2246    
2247      } else if (0 == rank1) {
2248    
2249        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2250          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
2251          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2252          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
2253          double *ptr_2 = &((res.getPointDataView().getData())[0]);
2254          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2255        }
2256        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2257    
2258          // Prepare the DataConstant input
2259          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2260    
2261          // Borrow DataTagged input from Data object
2262          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2263    
2264          // Prepare a DataTagged output 2
2265          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
2266          res.tag();
2267          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2268    
2269          // Prepare offset into DataConstant
2270          int offset_0 = tmp_0->getPointOffset(0,0);
2271          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2272          // Get the views
2273          DataArrayView view_1 = tmp_1->getDefaultValue();
2274          DataArrayView view_2 = tmp_2->getDefaultValue();
2275          // Get the pointers to the actual data
2276          double *ptr_1 = &((view_1.getData())[0]);
2277          double *ptr_2 = &((view_2.getData())[0]);
2278          // Compute a result for the default
2279          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2280          // Compute a result for each tag
2281          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2282          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2283          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2284            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2285            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2286            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2287            double *ptr_1 = &view_1.getData(0);
2288            double *ptr_2 = &view_2.getData(0);
2289            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2290          }
2291    
2292        }
2293        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2294    
2295          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2296          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2297          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2298          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2299    
2300          int sampleNo_1,dataPointNo_1;
2301          int numSamples_1 = arg_1_Z.getNumSamples();
2302          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2303          int offset_0 = tmp_0->getPointOffset(0,0);
2304          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2305          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2306            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2307              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2308              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2309              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2310              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2311              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2312              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2313            }
2314          }
2315    
2316        }
2317        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2318    
2319          // Borrow DataTagged input from Data object
2320          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2321    
2322          // Prepare the DataConstant input
2323          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2324    
2325          // Prepare a DataTagged output 2
2326          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
2327          res.tag();
2328          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2329    
2330          // Prepare offset into DataConstant
2331          int offset_1 = tmp_1->getPointOffset(0,0);
2332          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2333          // Get the views
2334          DataArrayView view_0 = tmp_0->getDefaultValue();
2335          DataArrayView view_2 = tmp_2->getDefaultValue();
2336          // Get the pointers to the actual data
2337          double *ptr_0 = &((view_0.getData())[0]);
2338          double *ptr_2 = &((view_2.getData())[0]);
2339          // Compute a result for the default
2340          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2341          // Compute a result for each tag
2342          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2343          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2344          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2345            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2346            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2347            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2348            double *ptr_0 = &view_0.getData(0);
2349            double *ptr_2 = &view_2.getData(0);
2350            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2351          }
2352    
2353        }
2354        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2355    
2356          // Borrow DataTagged input from Data object
2357          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2358    
2359          // Borrow DataTagged input from Data object
2360          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2361    
2362          // Prepare a DataTagged output 2
2363          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
2364          res.tag();        // DataTagged output
2365          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2366    
2367          // Get the views
2368          DataArrayView view_0 = tmp_0->getDefaultValue();
2369          DataArrayView view_1 = tmp_1->getDefaultValue();
2370          DataArrayView view_2 = tmp_2->getDefaultValue();
2371          // Get the pointers to the actual data
2372          double *ptr_0 = &((view_0.getData())[0]);
2373          double *ptr_1 = &((view_1.getData())[0]);
2374          double *ptr_2 = &((view_2.getData())[0]);
2375          // Compute a result for the default
2376          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2377          // Merge the tags
2378          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2379          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2380          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2381          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2382            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
2383          }
2384          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2385            tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2386          }
2387          // Compute a result for each tag
2388          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2389          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2390            DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2391            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2392            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2393            double *ptr_0 = &view_0.getData(0);
2394            double *ptr_1 = &view_1.getData(0);
2395            double *ptr_2 = &view_2.getData(0);
2396            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2397          }
2398    
2399        }
2400        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2401    
2402          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2403          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2404          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2405          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2406          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2407    
2408          int sampleNo_0,dataPointNo_0;
2409          int numSamples_0 = arg_0_Z.getNumSamples();
2410          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2411          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2412          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2413            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2414            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2415            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2416              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2417              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2418              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2419              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2420              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2421            }
2422          }
2423    
2424        }
2425        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2426    
2427          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2428          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2429          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2430          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2431    
2432          int sampleNo_0,dataPointNo_0;
2433          int numSamples_0 = arg_0_Z.getNumSamples();
2434          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2435          int offset_1 = tmp_1->getPointOffset(0,0);
2436          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2437          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2438            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2439              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2440              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2441              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2442              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2443              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2444              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2445            }
2446          }
2447    
2448    
2449        }
2450        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2451    
2452          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2453          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2454          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2455          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2456          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2457    
2458          int sampleNo_0,dataPointNo_0;
2459          int numSamples_0 = arg_0_Z.getNumSamples();
2460          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2461          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2462          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2463            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2464            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2465            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2466              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2467              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2468              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2469              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2470              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2471            }
2472          }
2473    
2474        }
2475        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2476    
2477          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2478          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2479          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2480          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2481          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2482    
2483          int sampleNo_0,dataPointNo_0;
2484          int numSamples_0 = arg_0_Z.getNumSamples();
2485          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2486          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2487          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2488            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2489              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2490              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2491              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2492              double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2493              double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2494              double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2495              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2496            }
2497          }
2498    
2499        }
2500        else {
2501          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2502        }
2503    
2504      } else {
2505        throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible shapes");
2506      }
2507    
2508      return res;
2509    }
2510    
2511    template <typename UnaryFunction>
2512    Data
2513    C_TensorUnaryOperation(Data const &arg_0,
2514                           UnaryFunction operation)
2515    {
2516      // Interpolate if necessary and find an appropriate function space
2517      Data arg_0_Z = Data(arg_0);
2518    
2519      // Get rank and shape of inputs
2520      int rank0 = arg_0_Z.getDataPointRank();
2521      DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();
2522      int size0 = arg_0_Z.getDataPointSize();
2523    
2524      // Declare output Data object
2525      Data res;
2526    
2527      if (arg_0_Z.isConstant()) {
2528        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output
2529        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2530        double *ptr_2 = &((res.getPointDataView().getData())[0]);
2531        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2532      }
2533      else if (arg_0_Z.isTagged()) {
2534    
2535        // Borrow DataTagged input from Data object
2536        DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2537    
2538        // Prepare a DataTagged output 2
2539        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());   // DataTagged output
2540        res.tag();
2541        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2542    
2543        // Get the views
2544        DataArrayView view_0 = tmp_0->getDefaultValue();
2545        DataArrayView view_2 = tmp_2->getDefaultValue();
2546        // Get the pointers to the actual data
2547        double *ptr_0 = &((view_0.getData())[0]);
2548        double *ptr_2 = &((view_2.getData())[0]);
2549        // Compute a result for the default
2550        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2551        // Compute a result for each tag
2552        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2553        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2554        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2555          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2556          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2557          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2558          double *ptr_0 = &view_0.getData(0);
2559          double *ptr_2 = &view_2.getData(0);
2560          tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2561        }
2562    
2563      }
2564      else if (arg_0_Z.isExpanded()) {
2565    
2566        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace(),true); // DataExpanded output
2567        DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2568        DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2569    
2570        int sampleNo_0,dataPointNo_0;
2571        int numSamples_0 = arg_0_Z.getNumSamples();
2572        int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2573        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2574        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2575          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2576            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2577            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2578            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2579            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2580            tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2581          }
2582        }
2583    
2584      }
2585      else {
2586        throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");
2587      }
2588    
2589      return res;
2590    }
2591    
2592  }  }
2593  #endif  #endif

Legend:
Removed from v.854  
changed lines
  Added in v.1719

  ViewVC Help
Powered by ViewVC 1.1.26