/[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 757 by woo409, Mon Jun 26 13:12:56 2006 UTC revision 1796 by jfenwick, Wed Sep 17 01:45:46 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 23  Line 25 
25  #include "BinaryOp.h"  #include "BinaryOp.h"
26  #include "UnaryOp.h"  #include "UnaryOp.h"
27  #include "DataException.h"  #include "DataException.h"
28    #include "DataTypes.h"
29    
30  extern "C" {  extern "C" {
31  #include "DataC.h"  #include "DataC.h"
32  #include "paso/Paso.h"  /* #include "paso/Paso.h" doesn't belong in this file...causes trouble for BruceFactory.cpp */
33  }  }
34    
35    #include "esysmpi.h"
36  #include <string>  #include <string>
37  #include <algorithm>  #include <algorithm>
38    #include <sstream>
39    
40    
41  #include <boost/shared_ptr.hpp>  #include <boost/shared_ptr.hpp>
42  #include <boost/python/object.hpp>  #include <boost/python/object.hpp>
# Line 47  class DataExpanded; Line 53  class DataExpanded;
53    
54  /**  /**
55     \brief     \brief
56     Data creates the appropriate Data object for the given construction     Data creates the appropriate Data object for the given construction
57     arguments.     arguments.
58    
59     Description:     Description:
60     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 72  class Data {
72    typedef double (*UnaryDFunPtr)(double);    typedef double (*UnaryDFunPtr)(double);
73    typedef double (*BinaryDFunPtr)(double,double);    typedef double (*BinaryDFunPtr)(double,double);
74    
75    
76    /**    /**
77       Constructors.       Constructors.
78    */    */
# Line 97  class Data { Line 104  class Data {
104         const FunctionSpace& what);         const FunctionSpace& what);
105    
106    /**    /**
107       \brief      \brief Copy Data from an existing vector
108       Constructor which copies data from a DataArrayView.    */
109    
      \param value - Input - Data value for a single point.  
      \param what - Input - A description of what this data represents.  
      \param expanded - Input - Flag, if true fill the entire container with  
                        the value. Otherwise a more efficient storage  
                        mechanism will be used.  
   */  
110    ESCRIPT_DLL_API    ESCRIPT_DLL_API
111    Data(const DataArrayView& value,    Data(const DataTypes::ValueType& value,
112         const FunctionSpace& what=FunctionSpace(),           const DataTypes::ShapeType& shape,
113         bool expanded=false);                   const FunctionSpace& what=FunctionSpace(),
114                     bool expanded=false);
115    
116    /**    /**
117       \brief       \brief
# Line 124  class Data { Line 126  class Data {
126    */    */
127    ESCRIPT_DLL_API    ESCRIPT_DLL_API
128    Data(double value,    Data(double value,
129         const DataArrayView::ShapeType& dataPointShape=DataArrayView::ShapeType(),         const DataTypes::ShapeType& dataPointShape=DataTypes::ShapeType(),
130         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
131         bool expanded=false);         bool expanded=false);
132    
# Line 137  class Data { Line 139  class Data {
139    */    */
140    ESCRIPT_DLL_API    ESCRIPT_DLL_API
141    Data(const Data& inData,    Data(const Data& inData,
142         const DataArrayView::RegionType& region);         const DataTypes::RegionType& region);
   
   /**  
      \brief  
      Constructor which will create Tagged data if expanded is false.  
      No attempt is made to ensure the tag keys match the tag keys  
      within the function space.  
   
      \param tagKeys - Input - List of tag values.  
      \param values - Input - List of values, one for each tag.  
      \param defaultValue - Input - A default value, used if tag doesn't exist.  
      \param what - Input - A description of what this data represents.  
      \param expanded - Input - Flag, if true fill the entire container with  
                        the appropriate values.  
     ==>*  
   */  
   ESCRIPT_DLL_API  
   Data(const DataTagged::TagListType& tagKeys,  
        const DataTagged::ValueListType& values,  
        const DataArrayView& defaultValue,  
        const FunctionSpace& what=FunctionSpace(),  
        bool expanded=false);  
143    
144    /**    /**
145       \brief       \brief
# Line 209  class Data { Line 190  class Data {
190       Constructor which creates a DataConstant of "shape" with constant value.       Constructor which creates a DataConstant of "shape" with constant value.
191    */    */
192    ESCRIPT_DLL_API    ESCRIPT_DLL_API
193    Data(double value,    Data(double value,
194         const boost::python::tuple& shape=boost::python::make_tuple(),         const boost::python::tuple& shape=boost::python::make_tuple(),
195         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
196         bool expanded=false);         bool expanded=false);
197    
198    
199    
200      /**
201        \brief Create a Data using an existing DataAbstract. Warning: The new object assumes ownership of the pointer!
202        Once you have passed the pointer, do not delete it.
203      */
204      ESCRIPT_DLL_API
205      Data(DataAbstract* underlyingdata);
206    
207    
208    /**    /**
209       \brief       \brief
210       Destructor       Destructor
# Line 234  class Data { Line 226  class Data {
226    
227    /**    /**
228       \brief       \brief
229       Return the values of all data-points as a single python numarray object.       switches on update protection
230    
231    */    */
232    ESCRIPT_DLL_API    ESCRIPT_DLL_API
233    const boost::python::numeric::array    void
234    convertToNumArray();    setProtection();
235    
236    /**    /**
237       \brief       \brief
238       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
239    
240    */    */
241    ESCRIPT_DLL_API    ESCRIPT_DLL_API
242    const boost::python::numeric::array    bool
243    convertToNumArrayFromSampleNo(int sampleNo);    isProtected() const;
244    
245    /**    /**
246       \brief       \brief
247       Return the value of the specified data-point as a single python numarray object.       Return the values of a data point on this process
248    */    */
249    ESCRIPT_DLL_API    ESCRIPT_DLL_API
250    const boost::python::numeric::array    const boost::python::numeric::array
251    convertToNumArrayFromDPNo(int sampleNo,    getValueOfDataPoint(int dataPointNo);
                             int dataPointNo);  
252    
253    /**    /**
254       \brief       \brief
255       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
256    */    */
257    ESCRIPT_DLL_API    ESCRIPT_DLL_API
258    void    void
259    fillFromNumArray(const boost::python::numeric::array);    setValueOfDataPointToPyObject(int dataPointNo, const boost::python::object& py_object);
260    
261      /**
262         \brief
263         sets the values of a data-point from a numarray object on this process
264      */
265      ESCRIPT_DLL_API
266      void
267      setValueOfDataPointToArray(int dataPointNo, const boost::python::numeric::array&);
268    
269      /**
270         \brief
271         sets the values of a data-point on this process
272      */
273      ESCRIPT_DLL_API
274      void
275      setValueOfDataPoint(int dataPointNo, const double);
276    
277      /**
278         \brief
279         Return the value of the specified data-point across all processors
280      */
281      ESCRIPT_DLL_API
282      const boost::python::numeric::array
283      getValueOfGlobalDataPoint(int procNo, int dataPointNo);
284    
285    /**    /**
286       \brief       \brief
287       Return the tag number associated with the given data-point.       Return the tag number associated with the given data-point.
288    
      The data-point number here corresponds to the data-point number in the  
      numarray returned by convertToNumArray.  
289    */    */
290    ESCRIPT_DLL_API    ESCRIPT_DLL_API
291    int    int
# Line 284  class Data { Line 299  class Data {
299    escriptDataC    escriptDataC
300    getDataC();    getDataC();
301    
302    
303    
304    
305    
306    
307    // REMOVE ME
308    // ESCRIPT_DLL_API
309    // void
310    // CompareDebug(const Data& rd);
311    
312    
313    /**    /**
314       \brief       \brief
315       Return the C wrapper for the Data object - const version.       Return the C wrapper for the Data object - const version.
# Line 294  class Data { Line 320  class Data {
320    
321    /**    /**
322       \brief       \brief
323       Write the data as a string.       Write the data as a string. For large amounts of data, a summary is printed.
324    */    */
325    ESCRIPT_DLL_API    ESCRIPT_DLL_API
   inline  
326    std::string    std::string
327    toString() const    toString() const;
   {  
     return m_data->toString();  
   }  
328    
329    /**  
330       \brief  //  /**
331    /*     \brief
332       Return the DataArrayView of the point data. This essentially contains       Return the DataArrayView of the point data. This essentially contains
333       the shape information for each data point although it also may be used       the shape information for each data point although it also may be used
334       to manipulate the point data.       to manipulate the point data.*/
335    */  //  */
336    ESCRIPT_DLL_API  //   ESCRIPT_DLL_API
337    inline  //   inline
338    const DataArrayView&  //   const DataArrayView&
339    getPointDataView() const  //   getPointDataView() const
340    {  //   {
341       return m_data->getPointDataView();  //      return m_data->getPointDataView();
342    }  //   }
343    
344    /**    /**
345       \brief       \brief
# Line 418  class Data { Line 441  class Data {
441    int    int
442    getDataPointRank() const    getDataPointRank() const
443    {    {
444      return m_data->getPointDataView().getRank();  //    return m_data->getPointDataView().getRank();
445        return m_data->getRank();
446    }    }
447    
448    /**    /**
449       \brief       \brief
450         Return the number of data points
451      */
452      ESCRIPT_DLL_API
453      inline
454      int
455      getNumDataPoints() const
456      {
457        return getNumSamples() * getNumDataPointsPerSample();
458      }
459      /**
460         \brief
461       Return the number of samples.       Return the number of samples.
462    */    */
463    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 445  class Data { Line 480  class Data {
480      return m_data->getNumDPPSample();      return m_data->getNumDPPSample();
481    }    }
482    
483    
484      /**
485        \brief
486        Return the number of values in the shape for this object.
487      */
488      ESCRIPT_DLL_API
489      int
490      getNoValues() const
491      {
492        return m_data->getNoValues();
493      }
494    
495    
496      /**
497         \brief
498         dumps the object into a netCDF file
499      */
500      ESCRIPT_DLL_API
501      void
502      dump(const std::string fileName) const;
503    /**    /**
504       \brief       \brief
505       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 473  class Data { Line 528  class Data {
528      return m_data->getSampleDataByTag(tag);      return m_data->getSampleDataByTag(tag);
529    }    }
530    
531    /**  //  /**
532       \brief  /*     \brief
533       Assign the given value to the data-points referenced by the given       Return a view into the data for the data point specified.
534       reference number.       NOTE: Construction of the DataArrayView is a relatively expensive
535         operation.
536       The value supplied is a python numarray object.  The data from this numarray       \param sampleNo - Input -
537       is unpacked into a DataArray, and this is used to set the corresponding       \param dataPointNo - Input -*/
538       data-points in the underlying Data object.  //  */
539    //   ESCRIPT_DLL_API
540    //   inline
541    //   DataArrayView
542    //   getDataPoint(int sampleNo,
543    //                int dataPointNo)
544    //   {
545    //                 return m_data->getDataPoint(sampleNo,dataPointNo);
546    //   }
547    
      If the underlying Data object cannot be accessed via reference numbers, an  
      exception will be thrown.  
548    
549       \param ref - Input - reference number.    /**
550       \param value - Input - value to assign to data-points associated with       \brief
551                              the given reference number.       Return a view into the data for the data point specified.
552         NOTE: Construction of the DataArrayView is a relatively expensive
553         operation.
554         \param sampleNo - Input -
555         \param dataPointNo - Input -
556    */    */
557    ESCRIPT_DLL_API    ESCRIPT_DLL_API
558    void    DataTypes::ValueType::const_reference
559    setRefValue(int ref,    getDataPoint(int sampleNo, int dataPointNo) const;
               const boost::python::numeric::array& value);  
560    
   /**  
      \brief  
      Return the values associated with the data-points referenced by the given  
      reference number.  
561    
562       The value supplied is a python numarray object. The data from the corresponding    ESCRIPT_DLL_API
563       data-points in this Data object are packed into the given numarray object.    DataTypes::ValueType::reference
564      getDataPoint(int sampleNo, int dataPointNo);
565    
      If the underlying Data object cannot be accessed via reference numbers, an  
      exception will be thrown.  
566    
      \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);  
567    
568    /**    /**
569       \brief       \brief
570       Return a view into the data for the data point specified.       Return the offset for the given sample and point within the sample
      NOTE: Construction of the DataArrayView is a relatively expensive  
      operation.  
      \param sampleNo - Input -  
      \param dataPointNo - Input -  
571    */    */
572    ESCRIPT_DLL_API    ESCRIPT_DLL_API
573    inline    inline
574    DataArrayView    DataTypes::ValueType::size_type
575    getDataPoint(int sampleNo,    getDataOffset(int sampleNo,
576                 int dataPointNo)                 int dataPointNo)
577    {    {
578      return m_data->getDataPoint(sampleNo,dataPointNo);                  return m_data->getPointOffset(sampleNo,dataPointNo);
579    }    }
580    
581    /**    /**
# Line 536  class Data { Line 583  class Data {
583       Return a reference to the data point shape.       Return a reference to the data point shape.
584    */    */
585    ESCRIPT_DLL_API    ESCRIPT_DLL_API
586    const DataArrayView::ShapeType&    inline
587    getDataPointShape() const;    const DataTypes::ShapeType&
588      getDataPointShape() const
589      {
590        return m_data->getShape();
591      }
592    
593    /**    /**
594       \brief       \brief
# Line 561  class Data { Line 612  class Data {
612       Return the number of doubles stored for this Data.       Return the number of doubles stored for this Data.
613    */    */
614    ESCRIPT_DLL_API    ESCRIPT_DLL_API
615    DataArrayView::ValueType::size_type    DataTypes::ValueType::size_type
616    getLength() const;    getLength() const;
617    
618    
619    
620    /**    /**
621       \brief       \brief
622       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag assocciated with name. Implicitly converts this
623       object to type DataTagged. Throws an exception if this object       object to type DataTagged. Throws an exception if this object
624       cannot be converted to a DataTagged object.       cannot be converted to a DataTagged object or name cannot be mapped onto a tag key.
625         \param tagKey - Input - Integer key.
626         \param value - Input - Value to associate with given key.
627        ==>*
628      */
629      ESCRIPT_DLL_API
630      void
631      setTaggedValueByName(std::string name,
632                           const boost::python::object& value);
633    
634      /**
635         \brief
636         Assign the given value to the tag. Implicitly converts this
637         object to type DataTagged if it is constant.
638    
639       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
640       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
641      ==>*      ==>*
# Line 578  class Data { Line 645  class Data {
645    setTaggedValue(int tagKey,    setTaggedValue(int tagKey,
646                   const boost::python::object& value);                   const boost::python::object& value);
647    
648    
649    //  /**
650    //     \brief
651    //     Assign the given value to the tag. Implicitly converts this
652    //     object to type DataTagged if it is constant.
653    //
654    //     \param tagKey - Input - Integer key.
655    //     \param value - Input - Value to associate with given key.
656    //    ==>*
657    //  */
658    //   ESCRIPT_DLL_API
659    //   void
660    //   setTaggedValueFromCPP(int tagKey,
661    //                         const DataArrayView& value);
662    
663    /**    /**
664       \brief       \brief
665       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag. Implicitly converts this
666       object to type DataTagged. Throws an exception if this object       object to type DataTagged if it is constant.
667       cannot be converted to a DataTagged object.  
668       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
669         \param pointshape - Input - The shape of the value parameter
670       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
671      ==>*       \param dataOffset - Input - Offset of the begining of the point within the value parameter
672    */    */
673    ESCRIPT_DLL_API    ESCRIPT_DLL_API
674    void    void
675    setTaggedValueFromCPP(int tagKey,    setTaggedValueFromCPP(int tagKey,
676                          const DataArrayView& value);              const DataTypes::ShapeType& pointshape,
677                            const DataTypes::ValueType& value,
678                int dataOffset=0);
679    
680    
681    
682    /**    /**
683      \brief      \brief
# Line 607  class Data { Line 694  class Data {
694    
695    /**    /**
696       \brief       \brief
697         set all values to zero
698         *
699      */
700      ESCRIPT_DLL_API
701      void
702      setToZero();
703    
704      /**
705         \brief
706       Interpolates this onto the given functionspace and returns       Interpolates this onto the given functionspace and returns
707       the result as a Data object.       the result as a Data object.
708       *       *
# Line 614  class Data { Line 710  class Data {
710    ESCRIPT_DLL_API    ESCRIPT_DLL_API
711    Data    Data
712    interpolate(const FunctionSpace& functionspace) const;    interpolate(const FunctionSpace& functionspace) const;
   
713    /**    /**
714       \brief       \brief
715       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 735  class Data {
735    
736    /**    /**
737       \brief       \brief
738         Returns 1./ Data object
739         *
740      */
741      ESCRIPT_DLL_API
742      Data
743      oneOver() const;
744      /**
745         \brief
746       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.
747       *       *
748    */    */
# Line 703  class Data { Line 806  class Data {
806    
807    /**    /**
808       \brief       \brief
      Return the minimum absolute value of this Data object.  
      *  
   */  
   ESCRIPT_DLL_API  
   double  
   Linf() const;  
   
   /**  
      \brief  
809       Return the maximum value of this Data object.       Return the maximum value of this Data object.
810       *       *
811    */    */
# Line 762  class Data { Line 856  class Data {
856    */    */
857    ESCRIPT_DLL_API    ESCRIPT_DLL_API
858    const boost::python::tuple    const boost::python::tuple
859    mindp() const;    minGlobalDataPoint() const;
860    
861    ESCRIPT_DLL_API    ESCRIPT_DLL_API
862    void    void
863    calc_mindp(int& SampleNo,    calc_minGlobalDataPoint(int& ProcNo,  int& DataPointNo) const;
              int& DataPointNo) const;  
   
864    /**    /**
865       \brief       \brief
866       Return the sign of each data point of this Data object.       Return the sign of each data point of this Data object.
# Line 781  class Data { Line 873  class Data {
873    
874    /**    /**
875       \brief       \brief
876         Return the symmetric part of a matrix which is half the matrix plus its transpose.
877         *
878      */
879      ESCRIPT_DLL_API
880      Data
881      symmetric() const;
882    
883      /**
884         \brief
885         Return the nonsymmetric part of a matrix which is half the matrix minus its transpose.
886         *
887      */
888      ESCRIPT_DLL_API
889      Data
890      nonsymmetric() const;
891    
892      /**
893         \brief
894         Return the trace of a matrix
895         *
896      */
897      ESCRIPT_DLL_API
898      Data
899      trace(int axis_offset) const;
900    
901      /**
902         \brief
903         Transpose each data point of this Data object around the given axis.
904         *
905      */
906      ESCRIPT_DLL_API
907      Data
908      transpose(int axis_offset) const;
909    
910      /**
911         \brief
912       Return the eigenvalues of the symmetric part at each data point of this Data object in increasing values.       Return the eigenvalues of the symmetric part at each data point of this Data object in increasing values.
913       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.
914       *       *
# Line 792  class Data { Line 920  class Data {
920    /**    /**
921       \brief       \brief
922       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.
923       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
924       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
925       first non-zero entry is positive.       first non-zero entry is positive.
926       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
927       *       *
# Line 804  class Data { Line 932  class Data {
932    
933    /**    /**
934       \brief       \brief
935       Transpose each data point of this Data object around the given axis.       swaps the components axis0 and axis1
      --* not implemented yet *--  
936       *       *
937    */    */
938    ESCRIPT_DLL_API    ESCRIPT_DLL_API
939    Data    Data
940    transpose(int axis) const;    swapaxes(const int axis0, const int axis1) const;
941    
942    /**    /**
943       \brief       \brief
944       Calculate the trace of each data point of this Data object.       Return the error function erf of each data point of this Data object.
945       *       *
946    */    */
947    ESCRIPT_DLL_API    ESCRIPT_DLL_API
948    Data    Data
949    trace() const;    erf() const;
950    
951    /**    /**
952       \brief       \brief
# Line 998  class Data { Line 1125  class Data {
1125    /**    /**
1126       \brief       \brief
1127       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.
1128        
1129       \param right Input - the power to raise the object to.       \param right Input - the power to raise the object to.
1130       *       *
1131     */     */
# Line 1009  class Data { Line 1136  class Data {
1136    /**    /**
1137       \brief       \brief
1138       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.
1139        
1140       \param left Input - the bases       \param left Input - the bases
1141       *       *
1142     */     */
# Line 1045  class Data { Line 1172  class Data {
1172    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1173    Data& operator+=(const boost::python::object& right);    Data& operator+=(const boost::python::object& right);
1174    
1175      ESCRIPT_DLL_API
1176      Data& operator=(const Data& other);
1177    
1178    /**    /**
1179       \brief       \brief
1180       Overloaded operator -=       Overloaded operator -=
# Line 1137  class Data { Line 1267  class Data {
1267    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1268    inline    inline
1269    void    void
1270    unaryOp(UnaryFunction operation);    unaryOp2(UnaryFunction operation);
1271    
1272    /**    /**
1273       \brief       \brief
# Line 1148  class Data { Line 1278  class Data {
1278    */    */
1279    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1280    Data    Data
1281    getSlice(const DataArrayView::RegionType& region) const;    getSlice(const DataTypes::RegionType& region) const;
1282    
1283    /**    /**
1284       \brief       \brief
# Line 1161  class Data { Line 1291  class Data {
1291    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1292    void    void
1293    setSlice(const Data& value,    setSlice(const Data& value,
1294             const DataArrayView::RegionType& region);             const DataTypes::RegionType& region);
1295    
1296    /**    /**
1297       \brief       \brief
1298       Archive the current Data object to the given file.       print the data values to stdout. Used for debugging
      \param fileName - Input - file to archive to.  
1299    */    */
1300    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1301    void    void
1302    archiveData(const std::string fileName);          print(void);
1303    
1304    /**    /**
1305       \brief       \brief
1306       Extract the Data object archived in the given file, overwriting       return the MPI rank number of the local data
1307       the current Data object.                   MPI_COMM_WORLD is assumed and the result of MPI_Comm_size()
1308       Note - the current object must be of type DataEmpty.                   is returned
      \param fileName - Input - file to extract from.  
      \param fspace - Input - a suitable FunctionSpace descibing the data.  
1309    */    */
1310    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1311    void          int
1312    extractData(const std::string fileName,          get_MPIRank(void) const;
               const FunctionSpace& fspace);  
1313    
1314      /**
1315         \brief
1316         return the MPI rank number of the local data
1317                     MPI_COMM_WORLD is assumed and the result of MPI_Comm_rank()
1318                     is returned
1319      */
1320      ESCRIPT_DLL_API
1321            int
1322            get_MPISize(void) const;
1323    
1324    /**    /**
1325       \brief       \brief
1326       print the data values to stdout. Used for debugging       return the MPI rank number of the local data
1327                     MPI_COMM_WORLD is assumed and returned.
1328    */    */
1329    void print();    ESCRIPT_DLL_API
1330            MPI_Comm
1331            get_MPIComm(void) const;
1332    
1333      /**
1334         \brief
1335         return the object produced by the factory, which is a DataConstant or DataExpanded
1336        TODO Ownership of this object should be explained in doco.
1337      */
1338      ESCRIPT_DLL_API
1339            DataAbstract*
1340            borrowData(void) const;
1341    
1342    
1343      /**
1344         \brief
1345         Return a pointer to the beginning of the datapoint at the specified offset.
1346         TODO Eventually these should be inlined.
1347         \param i - position(offset) in the underlying datastructure
1348      */
1349      ESCRIPT_DLL_API
1350            DataTypes::ValueType::const_reference
1351            getDataAtOffset(DataTypes::ValueType::size_type i) const;
1352    
1353    
1354      ESCRIPT_DLL_API
1355            DataTypes::ValueType::reference
1356            getDataAtOffset(DataTypes::ValueType::size_type i);
1357    
1358   protected:   protected:
1359    
# Line 1249  class Data { Line 1412  class Data {
1412    
1413    /**    /**
1414       \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  
1415       Convert the data type of the RHS to match this.       Convert the data type of the RHS to match this.
1416       \param right - Input - data type to match.       \param right - Input - data type to match.
1417    */    */
# Line 1278  class Data { Line 1430  class Data {
1430       \brief       \brief
1431       Construct a Data object of the appropriate type.       Construct a Data object of the appropriate type.
1432    */    */
1433    template <class IValueType>  
1434    void    void
1435    initialise(const IValueType& value,    initialise(const DataTypes::ValueType& value,
1436             const DataTypes::ShapeType& shape,
1437               const FunctionSpace& what,               const FunctionSpace& what,
1438               bool expanded);               bool expanded);
1439    
   /**  
      \brief  
      Reshape the data point if the data point is currently rank 0.  
      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.  
   */  
1440    void    void
1441    reshapeDataPoint(const DataArrayView::ShapeType& shape);    initialise(const boost::python::numeric::array& value,
1442                     const FunctionSpace& what,
1443                     bool expanded);
1444    
1445    //    //
1446    // pointer to the actual data object    // flag to protect the data object against any update
1447    boost::shared_ptr<DataAbstract> m_data;    bool m_protected;
1448    
1449    //    //
1450    // pointer to the internal profiling data    // pointer to the actual data object
1451    struct profDataEntry *profData;    boost::shared_ptr<DataAbstract> m_data;
1452    
1453  };  };
1454    
1455  template <class IValueType>  
1456  void  
1457  Data::initialise(const IValueType& value,  /**
1458                   const FunctionSpace& what,     Modify a filename for MPI parallel output to multiple files
1459                   bool expanded)  */
1460  {  char *Escript_MPI_appendRankToFileName(const char *, int, int);
   //  
   // Construct a Data object of the appropriate type.  
   // Construct the object first as there seems to be a bug which causes  
   // undefined behaviour if an exception is thrown during construction  
   // within the shared_ptr constructor.  
   if (expanded) {  
     DataAbstract* temp=new DataExpanded(value,what);  
     boost::shared_ptr<DataAbstract> temp_data(temp);  
     m_data=temp_data;  
   } else {  
     DataAbstract* temp=new DataConstant(value,what);  
     boost::shared_ptr<DataAbstract> temp_data(temp);  
     m_data=temp_data;  
   }  
 }  
1461    
1462  /**  /**
1463     Binary Data object operators.     Binary Data object operators.
1464  */  */
1465    inline double rpow(double x,double y)
1466    {
1467        return pow(y,x);
1468    }
1469    
1470  /**  /**
1471    \brief    \brief
# Line 1422  ESCRIPT_DLL_API Data operator*(const boo Line 1559  ESCRIPT_DLL_API Data operator*(const boo
1559  */  */
1560  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);
1561    
1562    
1563    
1564  /**  /**
1565    \brief    \brief
1566    Output operator    Output operator
# Line 1430  ESCRIPT_DLL_API std::ostream& operator<< Line 1569  ESCRIPT_DLL_API std::ostream& operator<<
1569    
1570  /**  /**
1571    \brief    \brief
1572    Return true if operands are equivalent, else return false.    Compute a tensor product of two Data objects
1573    NB: this operator does very little at this point, and isn't to    \param arg0 - Input - Data object
1574    be relied on. Requires further implementation.    \param arg1 - Input - Data object
1575      \param axis_offset - Input - axis offset
1576      \param transpose - Input - 0: transpose neither, 1: transpose arg0, 2: transpose arg1
1577  */  */
1578  //ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);  ESCRIPT_DLL_API
1579    Data
1580    C_GeneralTensorProduct(Data& arg0,
1581                         Data& arg1,
1582                         int axis_offset=0,
1583                         int transpose=0);
1584    
1585    
1586    
1587    // /**
1588    /*  \brief
1589      Return true if operands are equivalent, else return false.
1590      NB: this operator does very little at this point, and isn't to
1591      be relied on. Requires further implementation.*/
1592    //*/
1593    // ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);
1594    
1595  /**  /**
1596    \brief    \brief
# Line 1449  Data::binaryOp(const Data& right, Line 1605  Data::binaryOp(const Data& right,
1605  {  {
1606     //     //
1607     // 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
1608     if (getPointDataView().getRank()==0 && right.getPointDataView().getRank()!=0) {     if (getDataPointRank()==0 && right.getDataPointRank()!=0) {
1609       reshapeDataPoint(right.getPointDataView().getShape());       throw DataException("Error - attempt to update rank zero object with object with rank bigger than zero.");
1610     }     }
1611     //     //
1612     // initially make the temporary a shallow copy     // initially make the temporary a shallow copy
# Line 1458  Data::binaryOp(const Data& right, Line 1614  Data::binaryOp(const Data& right,
1614     if (getFunctionSpace()!=right.getFunctionSpace()) {     if (getFunctionSpace()!=right.getFunctionSpace()) {
1615       if (right.probeInterpolation(getFunctionSpace())) {       if (right.probeInterpolation(getFunctionSpace())) {
1616         //         //
1617         // an interpolation is required so create a new Data         // an interpolation is required so create a new Data
1618         tempRight=Data(right,this->getFunctionSpace());         tempRight=Data(right,this->getFunctionSpace());
1619       } else if (probeInterpolation(right.getFunctionSpace())) {       } else if (probeInterpolation(right.getFunctionSpace())) {
1620         //         //
# Line 1506  Data::binaryOp(const Data& right, Line 1662  Data::binaryOp(const Data& right,
1662    
1663  /**  /**
1664    \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  
1665    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.
1666    Given operation combines each element of each data point, thus argument    Given operation combines each element of each data point, thus argument
1667    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 1622  Data::algorithm(BinaryFunction operation Line 1692  Data::algorithm(BinaryFunction operation
1692    \brief    \brief
1693    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.
1694    Given operation combines each element within each data point into a scalar,    Given operation combines each element within each data point into a scalar,
1695    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
1696    rank 0 Data object.    rank 0 Data object.
1697    Calls escript::dp_algorithm.    Calls escript::dp_algorithm.
1698  */  */
# Line 1632  Data Line 1702  Data
1702  Data::dp_algorithm(BinaryFunction operation, double initial_value) const  Data::dp_algorithm(BinaryFunction operation, double initial_value) const
1703  {  {
1704    if (isExpanded()) {    if (isExpanded()) {
1705      Data result(0,DataArrayView::ShapeType(),getFunctionSpace(),isExpanded());      Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1706      DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());      DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());
1707      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());
1708      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");
# Line 1641  Data::dp_algorithm(BinaryFunction operat Line 1711  Data::dp_algorithm(BinaryFunction operat
1711      return result;      return result;
1712    } else if (isTagged()) {    } else if (isTagged()) {
1713      DataTagged* dataT=dynamic_cast<DataTagged*>(m_data.get());      DataTagged* dataT=dynamic_cast<DataTagged*>(m_data.get());
     DataArrayView::ShapeType viewShape;  
     DataArrayView::ValueType viewData(1);  
     viewData[0]=0;  
     DataArrayView defaultValue(viewData,viewShape);  
     DataTagged::TagListType keys;  
     DataTagged::ValueListType values;  
     DataTagged::DataMapType::const_iterator i;  
     for (i=dataT->getTagLookup().begin();i!=dataT->getTagLookup().end();i++) {  
       keys.push_back(i->first);  
       values.push_back(defaultValue);  
     }  
     Data result(keys,values,defaultValue,getFunctionSpace());  
     DataTagged* resultT=dynamic_cast<DataTagged*>(result.m_data.get());  
1714      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");
1715      EsysAssert((resultT!=0), "Programming error - casting result to DataTagged.");  
1716    //     DataTypes::ShapeType viewShape;
1717    //     DataTypes::ValueType viewData(1);
1718    //     viewData[0]=0;
1719    //     DataArrayView defaultValue(viewData,viewShape);
1720    //     DataTagged::TagListType keys;
1721    //     DataTagged::ValueListType values;
1722    //     DataTagged::DataMapType::const_iterator i;
1723    //     for (i=dataT->getTagLookup().begin();i!=dataT->getTagLookup().end();i++) {
1724    //       keys.push_back(i->first);
1725    //       values.push_back(defaultValue);
1726    //     }
1727    //     Data result(keys,values,defaultValue,getFunctionSpace());
1728    //     DataTagged* resultT=dynamic_cast<DataTagged*>(result.m_data.get());
1729    //     EsysAssert((resultT!=0), "Programming error - casting result to DataTagged.");
1730    
1731    
1732    
1733    
1734        DataTypes::ValueType defval(1);
1735        defval[0]=0;
1736        DataTagged* resultT=new DataTagged(getFunctionSpace(), DataTypes::scalarShape, defval, dataT);
1737      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);
1738      return result;      return Data(resultT);   // note: the Data object now owns the resultT pointer
1739    
1740    } else if (isConstant()) {    } else if (isConstant()) {
1741      Data result(0,DataArrayView::ShapeType(),getFunctionSpace(),isExpanded());      Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1742      DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());      DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());
1743      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());
1744      EsysAssert((dataC!=0), "Programming error - casting data to DataConstant.");      EsysAssert((dataC!=0), "Programming error - casting data to DataConstant.");
# Line 1671  Data::dp_algorithm(BinaryFunction operat Line 1750  Data::dp_algorithm(BinaryFunction operat
1750    return falseRetVal;    return falseRetVal;
1751  }  }
1752    
1753    /**
1754      \brief
1755      Compute a tensor operation with two Data objects
1756      \param arg0 - Input - Data object
1757      \param arg1 - Input - Data object
1758      \param operation - Input - Binary op functor
1759    */
1760    template <typename BinaryFunction>
1761    inline
1762    Data
1763    C_TensorBinaryOperation(Data const &arg_0,
1764                            Data const &arg_1,
1765                            BinaryFunction operation)
1766    {
1767      // Interpolate if necessary and find an appropriate function space
1768      Data arg_0_Z, arg_1_Z;
1769      if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
1770        if (arg_0.probeInterpolation(arg_1.getFunctionSpace())) {
1771          arg_0_Z = arg_0.interpolate(arg_1.getFunctionSpace());
1772          arg_1_Z = Data(arg_1);
1773        }
1774        else if (arg_1.probeInterpolation(arg_0.getFunctionSpace())) {
1775          arg_1_Z=arg_1.interpolate(arg_0.getFunctionSpace());
1776          arg_0_Z =Data(arg_0);
1777        }
1778        else {
1779          throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible function spaces.");
1780        }
1781      } else {
1782          arg_0_Z = Data(arg_0);
1783          arg_1_Z = Data(arg_1);
1784      }
1785      // Get rank and shape of inputs
1786      int rank0 = arg_0_Z.getDataPointRank();
1787      int rank1 = arg_1_Z.getDataPointRank();
1788      DataTypes::ShapeType shape0 = arg_0_Z.getDataPointShape();
1789      DataTypes::ShapeType shape1 = arg_1_Z.getDataPointShape();
1790      int size0 = arg_0_Z.getDataPointSize();
1791      int size1 = arg_1_Z.getDataPointSize();
1792    
1793      // Declare output Data object
1794      Data res;
1795    
1796      if (shape0 == shape1) {
1797    
1798        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1799          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
1800    /*      double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1801          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1802          double *ptr_2 = &((res.getPointDataView().getData())[0]);*/
1803          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
1804          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
1805          double *ptr_2 = &(res.getDataAtOffset(0));
1806    
1807          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1808        }
1809        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
1810    
1811          // Prepare the DataConstant input
1812          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1813    
1814          // Borrow DataTagged input from Data object
1815          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1816    
1817          // Prepare a DataTagged output 2
1818          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
1819          res.tag();
1820          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1821    
1822          // Prepare offset into DataConstant
1823          int offset_0 = tmp_0->getPointOffset(0,0);
1824          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1825          // Get the views
1826    //       DataArrayView view_1 = tmp_1->getDefaultValue();
1827    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1828    //       // Get the pointers to the actual data
1829    //       double *ptr_1 = &((view_1.getData())[0]);
1830    //       double *ptr_2 = &((view_2.getData())[0]);
1831    
1832          // Get the pointers to the actual data
1833          double *ptr_1 = &(tmp_1->getDefaultValue(0));
1834          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1835    
1836          // Compute a result for the default
1837          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1838          // Compute a result for each tag
1839          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1840          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1841          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1842            tmp_2->addTag(i->first);
1843    /*        DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1844            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1845            double *ptr_1 = &view_1.getData(0);
1846            double *ptr_2 = &view_2.getData(0);*/
1847            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1848            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1849    
1850            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1851          }
1852    
1853        }
1854        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
1855    
1856          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1857          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1858          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1859          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1860    
1861          int sampleNo_1,dataPointNo_1;
1862          int numSamples_1 = arg_1_Z.getNumSamples();
1863          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
1864          int offset_0 = tmp_0->getPointOffset(0,0);
1865          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
1866          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
1867            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
1868              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
1869              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
1870    //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1871    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1872    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1873    
1874              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1875              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
1876              double *ptr_2 = &(res.getDataAtOffset(offset_2));
1877              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1878            }
1879          }
1880    
1881        }
1882        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
1883    
1884          // Borrow DataTagged input from Data object
1885          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1886    
1887          // Prepare the DataConstant input
1888          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
1889    
1890          // Prepare a DataTagged output 2
1891          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
1892          res.tag();
1893          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1894    
1895          // Prepare offset into DataConstant
1896          int offset_1 = tmp_1->getPointOffset(0,0);
1897    //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1898          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
1899          // Get the views
1900    //       DataArrayView view_0 = tmp_0->getDefaultValue();
1901    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1902    //       // Get the pointers to the actual data
1903    //       double *ptr_0 = &((view_0.getData())[0]);
1904    //       double *ptr_2 = &((view_2.getData())[0]);
1905          // Get the pointers to the actual data
1906          double *ptr_0 = &(tmp_0->getDefaultValue(0));
1907          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1908          // Compute a result for the default
1909          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1910          // Compute a result for each tag
1911          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1912          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1913          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1914            tmp_2->addTag(i->first);
1915    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1916    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1917    //         double *ptr_0 = &view_0.getData(0);
1918    //         double *ptr_2 = &view_2.getData(0);
1919            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
1920            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1921            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1922          }
1923    
1924        }
1925        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
1926    
1927          // Borrow DataTagged input from Data object
1928          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1929    
1930          // Borrow DataTagged input from Data object
1931          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1932    
1933          // Prepare a DataTagged output 2
1934          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
1935          res.tag();        // DataTagged output
1936          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1937    
1938    //       // Get the views
1939    //       DataArrayView view_0 = tmp_0->getDefaultValue();
1940    //       DataArrayView view_1 = tmp_1->getDefaultValue();
1941    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1942    //       // Get the pointers to the actual data
1943    //       double *ptr_0 = &((view_0.getData())[0]);
1944    //       double *ptr_1 = &((view_1.getData())[0]);
1945    //       double *ptr_2 = &((view_2.getData())[0]);
1946    
1947          // Get the pointers to the actual data
1948          double *ptr_0 = &(tmp_0->getDefaultValue(0));
1949          double *ptr_1 = &(tmp_1->getDefaultValue(0));
1950          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1951    
1952          // Compute a result for the default
1953          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1954          // Merge the tags
1955          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1956          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1957          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1958          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1959            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
1960          }
1961          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1962            tmp_2->addTag(i->first);
1963          }
1964          // Compute a result for each tag
1965          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
1966          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
1967    
1968    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1969    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1970    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1971    //         double *ptr_0 = &view_0.getData(0);
1972    //         double *ptr_1 = &view_1.getData(0);
1973    //         double *ptr_2 = &view_2.getData(0);
1974    
1975            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
1976            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1977            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1978    
1979            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1980          }
1981    
1982        }
1983        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
1984    
1985          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1986          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1987          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1988          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1989          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1990    
1991          int sampleNo_0,dataPointNo_0;
1992          int numSamples_0 = arg_0_Z.getNumSamples();
1993          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
1994          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
1995          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
1996            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
1997            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1998            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
1999              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2000              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2001    
2002    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2003    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2004              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2005              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2006    
2007    
2008              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2009            }
2010          }
2011    
2012        }
2013        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2014    
2015          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2016          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2017          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2018          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2019    
2020          int sampleNo_0,dataPointNo_0;
2021          int numSamples_0 = arg_0_Z.getNumSamples();
2022          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2023          int offset_1 = tmp_1->getPointOffset(0,0);
2024          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2025          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2026            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2027              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2028              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2029    
2030    //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2031    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2032    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2033    
2034              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2035              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2036              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2037    
2038    
2039              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2040            }
2041          }
2042    
2043        }
2044        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2045    
2046          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2047          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2048          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2049          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2050          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2051    
2052          int sampleNo_0,dataPointNo_0;
2053          int numSamples_0 = arg_0_Z.getNumSamples();
2054          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2055          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2056          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2057            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2058            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2059            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2060              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2061              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2062              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2063              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2064              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2065            }
2066          }
2067    
2068        }
2069        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2070    
2071          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2072          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2073          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2074          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2075          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2076    
2077          int sampleNo_0,dataPointNo_0;
2078          int numSamples_0 = arg_0_Z.getNumSamples();
2079          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2080          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2081          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2082            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2083              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2084              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2085              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2086              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2087              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2088              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2089              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2090            }
2091          }
2092    
2093        }
2094        else {
2095          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2096        }
2097    
2098      } else if (0 == rank0) {
2099    
2100        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2101          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output
2102          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2103          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2104          double *ptr_2 = &(res.getDataAtOffset(0));
2105          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2106        }
2107        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2108    
2109          // Prepare the DataConstant input
2110          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2111    
2112          // Borrow DataTagged input from Data object
2113          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2114    
2115          // Prepare a DataTagged output 2
2116          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataTagged output
2117          res.tag();
2118          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2119    
2120          // Prepare offset into DataConstant
2121          int offset_0 = tmp_0->getPointOffset(0,0);
2122          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2123          // Get the views
2124    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2125    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2126    //       // Get the pointers to the actual data
2127    //       double *ptr_1 = &((view_1.getData())[0]);
2128    //       double *ptr_2 = &((view_2.getData())[0]);
2129           double *ptr_1 = &(tmp_1->getDefaultValue(0));
2130           double *ptr_2 = &(tmp_2->getDefaultValue(0));
2131    
2132          // Compute a result for the default
2133          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2134          // Compute a result for each tag
2135          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2136          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2137          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2138            tmp_2->addTag(i->first);
2139    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2140    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2141    //         double *ptr_1 = &view_1.getData(0);
2142    //         double *ptr_2 = &view_2.getData(0);
2143            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2144            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2145            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2146          }
2147    
2148        }
2149        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2150    
2151          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2152          DataConstant* tmp_0=dynamic_cast<DataConstant*>(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_1,dataPointNo_1;
2157          int numSamples_1 = arg_1_Z.getNumSamples();
2158          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2159          int offset_0 = tmp_0->getPointOffset(0,0);
2160          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2161          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2162            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2163              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2164              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2165              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2166              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2167              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2168              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2169    
2170            }
2171          }
2172    
2173        }
2174        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2175    
2176          // Borrow DataTagged input from Data object
2177          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2178    
2179          // Prepare the DataConstant input
2180          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2181    
2182          // Prepare a DataTagged output 2
2183          res = Data(0.0, shape1, arg_0_Z.getFunctionSpace());      // DataTagged output
2184          res.tag();
2185          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2186    
2187          // Prepare offset into DataConstant
2188          int offset_1 = tmp_1->getPointOffset(0,0);
2189    //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2190          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2191          // Get the views
2192    /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2193          DataArrayView view_2 = tmp_2->getDefaultValue();
2194          // Get the pointers to the actual data
2195          double *ptr_0 = &((view_0.getData())[0]);
2196          double *ptr_2 = &((view_2.getData())[0]);*/
2197    
2198          // Get the pointers to the actual data
2199          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2200          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2201    
2202    
2203          // Compute a result for the default
2204          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2205          // Compute a result for each tag
2206          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2207          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2208          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2209            tmp_2->addTag(i->first);
2210    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2211            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2212            double *ptr_0 = &view_0.getData(0);
2213            double *ptr_2 = &view_2.getData(0);*/
2214            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2215            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2216    
2217            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2218          }
2219    
2220        }
2221        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2222    
2223          // Borrow DataTagged input from Data object
2224          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2225    
2226          // Borrow DataTagged input from Data object
2227          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2228    
2229          // Prepare a DataTagged output 2
2230          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());
2231          res.tag();        // DataTagged output
2232          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2233    
2234          // Get the views
2235    /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2236          DataArrayView view_1 = tmp_1->getDefaultValue();
2237          DataArrayView view_2 = tmp_2->getDefaultValue();
2238          // Get the pointers to the actual data
2239          double *ptr_0 = &((view_0.getData())[0]);
2240          double *ptr_1 = &((view_1.getData())[0]);
2241          double *ptr_2 = &((view_2.getData())[0]);*/
2242    
2243          // Get the pointers to the actual data
2244          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2245          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2246          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2247    
2248    
2249          // Compute a result for the default
2250          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2251          // Merge the tags
2252          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2253          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2254          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2255          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2256            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2257          }
2258          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2259            tmp_2->addTag(i->first);
2260          }
2261          // Compute a result for each tag
2262          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2263          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2264    
2265    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2266            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2267            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2268            double *ptr_0 = &view_0.getData(0);
2269            double *ptr_1 = &view_1.getData(0);
2270            double *ptr_2 = &view_2.getData(0);*/
2271    
2272            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2273            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2274            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2275    
2276            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2277          }
2278    
2279        }
2280        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2281    
2282          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2283          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2284          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2285          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2286          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2287    
2288          int sampleNo_0,dataPointNo_0;
2289          int numSamples_0 = arg_0_Z.getNumSamples();
2290          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2291          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2292          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2293            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2294            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2295            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2296              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2297              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2298              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2299              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2300              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2301            }
2302          }
2303    
2304        }
2305        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2306    
2307          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2308          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2309          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2310          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2311    
2312          int sampleNo_0,dataPointNo_0;
2313          int numSamples_0 = arg_0_Z.getNumSamples();
2314          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2315          int offset_1 = tmp_1->getPointOffset(0,0);
2316          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2317          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2318            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2319              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2320              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2321              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2322              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2323              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2324              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2325            }
2326          }
2327    
2328    
2329        }
2330        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2331    
2332          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2333          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2334          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2335          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2336          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2337    
2338          int sampleNo_0,dataPointNo_0;
2339          int numSamples_0 = arg_0_Z.getNumSamples();
2340          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2341          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2342          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2343            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2344            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2345            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2346              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2347              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2348              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2349              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2350              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2351            }
2352          }
2353    
2354        }
2355        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2356    
2357          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2358          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2359          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2360          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2361          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2362    
2363          int sampleNo_0,dataPointNo_0;
2364          int numSamples_0 = arg_0_Z.getNumSamples();
2365          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2366          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2367          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2368            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2369              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2370              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2371              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2372              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2373              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2374              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2375              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2376            }
2377          }
2378    
2379        }
2380        else {
2381          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2382        }
2383    
2384      } else if (0 == rank1) {
2385    
2386        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2387          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
2388          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2389          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2390          double *ptr_2 = &(res.getDataAtOffset(0));
2391          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2392        }
2393        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2394    
2395          // Prepare the DataConstant input
2396          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2397    
2398          // Borrow DataTagged input from Data object
2399          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2400    
2401          // Prepare a DataTagged output 2
2402          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
2403          res.tag();
2404          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2405    
2406          // Prepare offset into DataConstant
2407          int offset_0 = tmp_0->getPointOffset(0,0);
2408          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2409          // Get the views
2410    /*      DataArrayView view_1 = tmp_1->getDefaultValue();
2411          DataArrayView view_2 = tmp_2->getDefaultValue();
2412          // Get the pointers to the actual data
2413          double *ptr_1 = &((view_1.getData())[0]);
2414          double *ptr_2 = &((view_2.getData())[0]);*/
2415          //Get the pointers to the actual data
2416          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2417          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2418    
2419          // Compute a result for the default
2420          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2421          // Compute a result for each tag
2422          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2423          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2424          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2425            tmp_2->addTag(i->first);
2426    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2427    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2428    //         double *ptr_1 = &view_1.getData(0);
2429    //         double *ptr_2 = &view_2.getData(0);
2430            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2431            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2432    
2433    
2434            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2435          }
2436    
2437        }
2438        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2439    
2440          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2441          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2442          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2443          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2444    
2445          int sampleNo_1,dataPointNo_1;
2446          int numSamples_1 = arg_1_Z.getNumSamples();
2447          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2448          int offset_0 = tmp_0->getPointOffset(0,0);
2449          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2450          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2451            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2452              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2453              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2454              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2455              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2456              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2457              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2458            }
2459          }
2460    
2461        }
2462        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2463    
2464          // Borrow DataTagged input from Data object
2465          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2466    
2467          // Prepare the DataConstant input
2468          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2469    
2470          // Prepare a DataTagged output 2
2471          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
2472          res.tag();
2473          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2474    
2475          // Prepare offset into DataConstant
2476          int offset_1 = tmp_1->getPointOffset(0,0);
2477          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2478          // Get the views
2479    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2480    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2481    //       // Get the pointers to the actual data
2482    //       double *ptr_0 = &((view_0.getData())[0]);
2483    //       double *ptr_2 = &((view_2.getData())[0]);
2484          // Get the pointers to the actual data
2485          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2486          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2487          // Compute a result for the default
2488          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2489          // Compute a result for each tag
2490          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2491          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2492          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2493            tmp_2->addTag(i->first);
2494    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2495            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2496            double *ptr_0 = &view_0.getData(0);
2497            double *ptr_2 = &view_2.getData(0);*/
2498            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2499            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2500            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2501          }
2502    
2503        }
2504        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2505    
2506          // Borrow DataTagged input from Data object
2507          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2508    
2509          // Borrow DataTagged input from Data object
2510          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2511    
2512          // Prepare a DataTagged output 2
2513          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
2514          res.tag();        // DataTagged output
2515          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2516    
2517          // Get the views
2518    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2519    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2520    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2521    //       // Get the pointers to the actual data
2522    //       double *ptr_0 = &((view_0.getData())[0]);
2523    //       double *ptr_1 = &((view_1.getData())[0]);
2524    //       double *ptr_2 = &((view_2.getData())[0]);
2525    
2526          // Get the pointers to the actual data
2527          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2528          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2529          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2530    
2531          // Compute a result for the default
2532          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2533          // Merge the tags
2534          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2535          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2536          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2537          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2538            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2539          }
2540          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2541            tmp_2->addTag(i->first);
2542          }
2543          // Compute a result for each tag
2544          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2545          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2546    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2547    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2548    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2549    //         double *ptr_0 = &view_0.getData(0);
2550    //         double *ptr_1 = &view_1.getData(0);
2551    //         double *ptr_2 = &view_2.getData(0);
2552    
2553            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2554            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2555            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2556            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2557          }
2558    
2559        }
2560        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2561    
2562          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2563          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2564          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2565          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2566          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2567    
2568          int sampleNo_0,dataPointNo_0;
2569          int numSamples_0 = arg_0_Z.getNumSamples();
2570          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2571          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2572          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2573            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2574            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2575            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2576              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2577              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2578              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2579              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2580              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2581            }
2582          }
2583    
2584        }
2585        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2586    
2587          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2588          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2589          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2590          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2591    
2592          int sampleNo_0,dataPointNo_0;
2593          int numSamples_0 = arg_0_Z.getNumSamples();
2594          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2595          int offset_1 = tmp_1->getPointOffset(0,0);
2596          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2597          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2598            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2599              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2600              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2601              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2602              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2603              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2604              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2605            }
2606          }
2607    
2608    
2609        }
2610        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2611    
2612          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2613          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2614          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2615          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2616          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2617    
2618          int sampleNo_0,dataPointNo_0;
2619          int numSamples_0 = arg_0_Z.getNumSamples();
2620          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2621          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2622          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2623            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2624            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2625            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2626              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2627              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2628              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2629              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2630              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2631            }
2632          }
2633    
2634        }
2635        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2636    
2637          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2638          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2639          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2640          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2641          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2642    
2643          int sampleNo_0,dataPointNo_0;
2644          int numSamples_0 = arg_0_Z.getNumSamples();
2645          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2646          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2647          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2648            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2649              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2650              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2651              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2652              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2653              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2654              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2655              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2656            }
2657          }
2658    
2659        }
2660        else {
2661          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2662        }
2663    
2664      } else {
2665        throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible shapes");
2666      }
2667    
2668      return res;
2669    }
2670    
2671    template <typename UnaryFunction>
2672    Data
2673    C_TensorUnaryOperation(Data const &arg_0,
2674                           UnaryFunction operation)
2675    {
2676      // Interpolate if necessary and find an appropriate function space
2677      Data arg_0_Z = Data(arg_0);
2678    
2679      // Get rank and shape of inputs
2680      int rank0 = arg_0_Z.getDataPointRank();
2681      const DataTypes::ShapeType& shape0 = arg_0_Z.getDataPointShape();
2682      int size0 = arg_0_Z.getDataPointSize();
2683    
2684      // Declare output Data object
2685      Data res;
2686    
2687      if (arg_0_Z.isConstant()) {
2688        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output
2689    //     double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2690    //     double *ptr_2 = &((res.getPointDataView().getData())[0]);
2691        double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2692        double *ptr_2 = &(res.getDataAtOffset(0));
2693        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2694      }
2695      else if (arg_0_Z.isTagged()) {
2696    
2697        // Borrow DataTagged input from Data object
2698        DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2699    
2700        // Prepare a DataTagged output 2
2701        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());   // DataTagged output
2702        res.tag();
2703        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2704    
2705    //     // Get the views
2706    //     DataArrayView view_0 = tmp_0->getDefaultValue();
2707    //     DataArrayView view_2 = tmp_2->getDefaultValue();
2708    //     // Get the pointers to the actual data
2709    //     double *ptr_0 = &((view_0.getData())[0]);
2710    //     double *ptr_2 = &((view_2.getData())[0]);
2711        // Get the pointers to the actual data
2712        double *ptr_0 = &(tmp_0->getDefaultValue(0));
2713        double *ptr_2 = &(tmp_2->getDefaultValue(0));
2714        // Compute a result for the default
2715        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2716        // Compute a result for each tag
2717        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2718        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2719        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2720          tmp_2->addTag(i->first);
2721    //       DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2722    //       DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2723    //       double *ptr_0 = &view_0.getData(0);
2724    //       double *ptr_2 = &view_2.getData(0);
2725          double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2726          double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2727          tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2728        }
2729    
2730      }
2731      else if (arg_0_Z.isExpanded()) {
2732    
2733        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace(),true); // DataExpanded output
2734        DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2735        DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2736    
2737        int sampleNo_0,dataPointNo_0;
2738        int numSamples_0 = arg_0_Z.getNumSamples();
2739        int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2740        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2741        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2742          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2743    //         int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2744    //         int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2745    //         double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2746    //         double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2747            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2748            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2749            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2750            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2751            tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2752          }
2753        }
2754    
2755      }
2756      else {
2757        throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");
2758      }
2759    
2760      return res;
2761    }
2762    
2763  }  }
2764  #endif  #endif

Legend:
Removed from v.757  
changed lines
  Added in v.1796

  ViewVC Help
Powered by ViewVC 1.1.26