/[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 1857 by jfenwick, Tue Oct 7 23:58:44 2008 UTC
# Line 1  Line 1 
1  // $Id$  
2  /*  /*******************************************************
3   ************************************************************  *
4   *          Copyright 2006 by ACcESS MNRF                   *  * Copyright (c) 2003-2008 by University of Queensland
5   *                                                          *  * Earth Systems Science Computational Center (ESSCC)
6   *              http://www.access.edu.au                    *  * http://www.uq.edu.au/esscc
7   *       Primary Business: Queensland, Australia            *  *
8   *  Licensed under the Open Software License version 3.0    *  * Primary Business: Queensland, Australia
9   *     http://www.opensource.org/licenses/osl-3.0.php       *  * Licensed under the Open Software License version 3.0
10   *                                                          *  * http://www.opensource.org/licenses/osl-3.0.php
11   ************************************************************  *
12  */  *******************************************************/
13    
14    
15  /** \file Data.h */  /** \file Data.h */
16    
# Line 23  Line 24 
24  #include "BinaryOp.h"  #include "BinaryOp.h"
25  #include "UnaryOp.h"  #include "UnaryOp.h"
26  #include "DataException.h"  #include "DataException.h"
27    #include "DataTypes.h"
28    
29  extern "C" {  extern "C" {
30  #include "DataC.h"  #include "DataC.h"
31  #include "paso/Paso.h"  /* #include "paso/Paso.h" doesn't belong in this file...causes trouble for BruceFactory.cpp */
32  }  }
33    
34    #include "esysmpi.h"
35  #include <string>  #include <string>
36  #include <algorithm>  #include <algorithm>
37    #include <sstream>
38    
39    
40  #include <boost/shared_ptr.hpp>  #include <boost/shared_ptr.hpp>
41  #include <boost/python/object.hpp>  #include <boost/python/object.hpp>
# Line 47  class DataExpanded; Line 52  class DataExpanded;
52    
53  /**  /**
54     \brief     \brief
55     Data creates the appropriate Data object for the given construction     Data represents a collection of datapoints.
    arguments.  
56    
57     Description:     Description:
58     Data is essentially a factory class which creates the appropriate Data     Internally, the datapoints are actually stored by a DataAbstract object.
59     object for the given construction arguments. It retains control over     The specific instance of DataAbstract used may vary over the lifetime
60     the object created for the lifetime of the object.     of the Data object.
61     The type of Data object referred to may change during the lifetime of     Some methods on this class return references (eg getShape()).
62     the Data object.     These references should not be used after an operation which changes the underlying DataAbstract object.
63       Doing so will lead to invalid memory access.
64       This should not affect any methods exposed via boost::python.
65  */  */
66  class Data {  class Data {
67    
# 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 221  class Data { Line 213  class Data {
213    ~Data();    ~Data();
214    
215    /**    /**
216       \brief       \brief Make this object a deep copy of "other".
      Perform a deep copy.  
217    */    */
218    ESCRIPT_DLL_API    ESCRIPT_DLL_API
219    void    void
220    copy(const Data& other);    copy(const Data& other);
221    
222    /**    /**
223         \brief Return a pointer to a deep copy of this object.
224      */
225      ESCRIPT_DLL_API
226      Data*
227      copySelf();
228    
229    
230    
231    
232      /**
233       Member access methods.       Member access methods.
234    */    */
235    
236    /**    /**
237       \brief       \brief
238       Return the values of all data-points as a single python numarray object.       switches on update protection
239    
240    */    */
241    ESCRIPT_DLL_API    ESCRIPT_DLL_API
242    const boost::python::numeric::array    void
243    convertToNumArray();    setProtection();
244    
245    /**    /**
246       \brief       \brief
247       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
248    
249    */    */
250    ESCRIPT_DLL_API    ESCRIPT_DLL_API
251    const boost::python::numeric::array    bool
252    convertToNumArrayFromSampleNo(int sampleNo);    isProtected() const;
253    
254    /**    /**
255       \brief       \brief
256       Return the value of the specified data-point as a single python numarray object.       Return the values of a data point on this process
257    */    */
258    ESCRIPT_DLL_API    ESCRIPT_DLL_API
259    const boost::python::numeric::array    const boost::python::numeric::array
260    convertToNumArrayFromDPNo(int sampleNo,    getValueOfDataPoint(int dataPointNo);
261                              int dataPointNo);  
262      /**
263         \brief
264         sets the values of a data-point from a python object on this process
265      */
266      ESCRIPT_DLL_API
267      void
268      setValueOfDataPointToPyObject(int dataPointNo, const boost::python::object& py_object);
269    
270      /**
271         \brief
272         sets the values of a data-point from a numarray object on this process
273      */
274      ESCRIPT_DLL_API
275      void
276      setValueOfDataPointToArray(int dataPointNo, const boost::python::numeric::array&);
277    
278    /**    /**
279       \brief       \brief
280       Fills the expanded Data object from values of a python numarray object.       sets the values of a data-point on this process
281    */    */
282    ESCRIPT_DLL_API    ESCRIPT_DLL_API
283    void    void
284    fillFromNumArray(const boost::python::numeric::array);    setValueOfDataPoint(int dataPointNo, const double);
285    
286      /**
287         \brief
288         Return the value of the specified data-point across all processors
289      */
290      ESCRIPT_DLL_API
291      const boost::python::numeric::array
292      getValueOfGlobalDataPoint(int procNo, int dataPointNo);
293    
294    /**    /**
295       \brief       \brief
296       Return the tag number associated with the given data-point.       Return the tag number associated with the given data-point.
297    
      The data-point number here corresponds to the data-point number in the  
      numarray returned by convertToNumArray.  
298    */    */
299    ESCRIPT_DLL_API    ESCRIPT_DLL_API
300    int    int
# Line 284  class Data { Line 308  class Data {
308    escriptDataC    escriptDataC
309    getDataC();    getDataC();
310    
311    
312    
313    
314    
315    
316    // REMOVE ME
317    // ESCRIPT_DLL_API
318    // void
319    // CompareDebug(const Data& rd);
320    
321    
322    /**    /**
323       \brief       \brief
324       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 329  class Data {
329    
330    /**    /**
331       \brief       \brief
332       Write the data as a string.       Write the data as a string. For large amounts of data, a summary is printed.
333    */    */
334    ESCRIPT_DLL_API    ESCRIPT_DLL_API
   inline  
335    std::string    std::string
336    toString() const    toString() const;
   {  
     return m_data->toString();  
   }  
337    
338    /**  
339       \brief  //  /**
340    /*     \brief
341       Return the DataArrayView of the point data. This essentially contains       Return the DataArrayView of the point data. This essentially contains
342       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
343       to manipulate the point data.       to manipulate the point data.*/
344    */  //  */
345    ESCRIPT_DLL_API  //   ESCRIPT_DLL_API
346    inline  //   inline
347    const DataArrayView&  //   const DataArrayView&
348    getPointDataView() const  //   getPointDataView() const
349    {  //   {
350       return m_data->getPointDataView();  //      return m_data->getPointDataView();
351    }  //   }
352    
353    /**    /**
354       \brief       \brief
# Line 363  class Data { Line 395  class Data {
395    
396    /**    /**
397       \brief       \brief
398       Return true if this Data is empty.       Return true if this Data holds an instance of DataEmpty. This is _not_ the same as asking if the object
399    contains datapoints.
400    */    */
401    ESCRIPT_DLL_API    ESCRIPT_DLL_API
402    bool    bool
# Line 418  class Data { Line 451  class Data {
451    int    int
452    getDataPointRank() const    getDataPointRank() const
453    {    {
454      return m_data->getPointDataView().getRank();  //    return m_data->getPointDataView().getRank();
455        return m_data->getRank();
456    }    }
457    
458    /**    /**
459       \brief       \brief
460         Return the number of data points
461      */
462      ESCRIPT_DLL_API
463      inline
464      int
465      getNumDataPoints() const
466      {
467        return getNumSamples() * getNumDataPointsPerSample();
468      }
469      /**
470         \brief
471       Return the number of samples.       Return the number of samples.
472    */    */
473    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 445  class Data { Line 490  class Data {
490      return m_data->getNumDPPSample();      return m_data->getNumDPPSample();
491    }    }
492    
493    
494      /**
495        \brief
496        Return the number of values in the shape for this object.
497      */
498      ESCRIPT_DLL_API
499      int
500      getNoValues() const
501      {
502        return m_data->getNoValues();
503      }
504    
505    
506      /**
507         \brief
508         dumps the object into a netCDF file
509      */
510      ESCRIPT_DLL_API
511      void
512      dump(const std::string fileName) const;
513    /**    /**
514       \brief       \brief
515       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 538  class Data {
538      return m_data->getSampleDataByTag(tag);      return m_data->getSampleDataByTag(tag);
539    }    }
540    
541    /**  //  /**
542       \brief  /*     \brief
543       Assign the given value to the data-points referenced by the given       Return a view into the data for the data point specified.
544       reference number.       NOTE: Construction of the DataArrayView is a relatively expensive
545         operation.
546       The value supplied is a python numarray object.  The data from this numarray       \param sampleNo - Input -
547       is unpacked into a DataArray, and this is used to set the corresponding       \param dataPointNo - Input -*/
548       data-points in the underlying Data object.  //  */
549    //   ESCRIPT_DLL_API
550    //   inline
551    //   DataArrayView
552    //   getDataPoint(int sampleNo,
553    //                int dataPointNo)
554    //   {
555    //                 return m_data->getDataPoint(sampleNo,dataPointNo);
556    //   }
557    
      If the underlying Data object cannot be accessed via reference numbers, an  
      exception will be thrown.  
558    
559       \param ref - Input - reference number.    /**
560       \param value - Input - value to assign to data-points associated with       \brief
561                              the given reference number.       Return a view into the data for the data point specified.
562         NOTE: Construction of the DataArrayView is a relatively expensive
563         operation.
564         \param sampleNo - Input -
565         \param dataPointNo - Input -
566    */    */
567    ESCRIPT_DLL_API    ESCRIPT_DLL_API
568    void    DataTypes::ValueType::const_reference
569    setRefValue(int ref,    getDataPoint(int sampleNo, int dataPointNo) const;
               const boost::python::numeric::array& value);  
570    
   /**  
      \brief  
      Return the values associated with the data-points referenced by the given  
      reference number.  
571    
572       The value supplied is a python numarray object. The data from the corresponding    ESCRIPT_DLL_API
573       data-points in this Data object are packed into the given numarray object.    DataTypes::ValueType::reference
574      getDataPoint(int sampleNo, int dataPointNo);
575    
      If the underlying Data object cannot be accessed via reference numbers, an  
      exception will be thrown.  
576    
      \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);  
577    
578    /**    /**
579       \brief       \brief
580       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 -  
581    */    */
582    ESCRIPT_DLL_API    ESCRIPT_DLL_API
583    inline    inline
584    DataArrayView    DataTypes::ValueType::size_type
585    getDataPoint(int sampleNo,    getDataOffset(int sampleNo,
586                 int dataPointNo)                 int dataPointNo)
587    {    {
588      return m_data->getDataPoint(sampleNo,dataPointNo);                  return m_data->getPointOffset(sampleNo,dataPointNo);
589    }    }
590    
591    /**    /**
# Line 536  class Data { Line 593  class Data {
593       Return a reference to the data point shape.       Return a reference to the data point shape.
594    */    */
595    ESCRIPT_DLL_API    ESCRIPT_DLL_API
596    const DataArrayView::ShapeType&    inline
597    getDataPointShape() const;    const DataTypes::ShapeType&
598      getDataPointShape() const
599      {
600        return m_data->getShape();
601      }
602    
603    /**    /**
604       \brief       \brief
# Line 561  class Data { Line 622  class Data {
622       Return the number of doubles stored for this Data.       Return the number of doubles stored for this Data.
623    */    */
624    ESCRIPT_DLL_API    ESCRIPT_DLL_API
625    DataArrayView::ValueType::size_type    DataTypes::ValueType::size_type
626    getLength() const;    getLength() const;
627    
628    
629    
630    /**    /**
631       \brief       \brief
632       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag assocciated with name. Implicitly converts this
633       object to type DataTagged. Throws an exception if this object       object to type DataTagged. Throws an exception if this object
634       cannot be converted to a DataTagged object.       cannot be converted to a DataTagged object or name cannot be mapped onto a tag key.
635         \param tagKey - Input - Integer key.
636         \param value - Input - Value to associate with given key.
637        ==>*
638      */
639      ESCRIPT_DLL_API
640      void
641      setTaggedValueByName(std::string name,
642                           const boost::python::object& value);
643    
644      /**
645         \brief
646         Assign the given value to the tag. Implicitly converts this
647         object to type DataTagged if it is constant.
648    
649       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
650       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
651      ==>*      ==>*
# Line 578  class Data { Line 655  class Data {
655    setTaggedValue(int tagKey,    setTaggedValue(int tagKey,
656                   const boost::python::object& value);                   const boost::python::object& value);
657    
658    
659    //  /**
660    //     \brief
661    //     Assign the given value to the tag. Implicitly converts this
662    //     object to type DataTagged if it is constant.
663    //
664    //     \param tagKey - Input - Integer key.
665    //     \param value - Input - Value to associate with given key.
666    //    ==>*
667    //  */
668    //   ESCRIPT_DLL_API
669    //   void
670    //   setTaggedValueFromCPP(int tagKey,
671    //                         const DataArrayView& value);
672    
673    /**    /**
674       \brief       \brief
675       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag. Implicitly converts this
676       object to type DataTagged. Throws an exception if this object       object to type DataTagged if it is constant.
677       cannot be converted to a DataTagged object.  
678       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
679         \param pointshape - Input - The shape of the value parameter
680       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
681      ==>*       \param dataOffset - Input - Offset of the begining of the point within the value parameter
682    */    */
683    ESCRIPT_DLL_API    ESCRIPT_DLL_API
684    void    void
685    setTaggedValueFromCPP(int tagKey,    setTaggedValueFromCPP(int tagKey,
686                          const DataArrayView& value);              const DataTypes::ShapeType& pointshape,
687                            const DataTypes::ValueType& value,
688                int dataOffset=0);
689    
690    
691    
692    /**    /**
693      \brief      \brief
# Line 607  class Data { Line 704  class Data {
704    
705    /**    /**
706       \brief       \brief
707         set all values to zero
708         *
709      */
710      ESCRIPT_DLL_API
711      void
712      setToZero();
713    
714      /**
715         \brief
716       Interpolates this onto the given functionspace and returns       Interpolates this onto the given functionspace and returns
717       the result as a Data object.       the result as a Data object.
718       *       *
# Line 614  class Data { Line 720  class Data {
720    ESCRIPT_DLL_API    ESCRIPT_DLL_API
721    Data    Data
722    interpolate(const FunctionSpace& functionspace) const;    interpolate(const FunctionSpace& functionspace) const;
   
723    /**    /**
724       \brief       \brief
725       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 745  class Data {
745    
746    /**    /**
747       \brief       \brief
748         Returns 1./ Data object
749         *
750      */
751      ESCRIPT_DLL_API
752      Data
753      oneOver() const;
754      /**
755         \brief
756       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.
757       *       *
758    */    */
# Line 695  class Data { Line 808  class Data {
808    /**    /**
809       \brief       \brief
810       Return the maximum absolute value of this Data object.       Return the maximum absolute value of this Data object.
811         For Data which contain no samples (or tagged Data for which no tags in use have a value)
812         zero is returned.
813       *       *
814    */    */
815    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 703  class Data { Line 818  class Data {
818    
819    /**    /**
820       \brief       \brief
      Return the minimum absolute value of this Data object.  
      *  
   */  
   ESCRIPT_DLL_API  
   double  
   Linf() const;  
   
   /**  
      \brief  
821       Return the maximum value of this Data object.       Return the maximum value of this Data object.
822       *       For Data which contain no samples (or tagged Data for which no tags in use have a value)
823         a large negative value is returned.
824    */    */
825    ESCRIPT_DLL_API    ESCRIPT_DLL_API
826    double    double
# Line 722  class Data { Line 829  class Data {
829    /**    /**
830       \brief       \brief
831       Return the minimum value of this Data object.       Return the minimum value of this Data object.
832         For Data which contain no samples (or tagged Data for which no tags in use have a value)
833         a large positive value is returned.
834       *       *
835    */    */
836    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 762  class Data { Line 871  class Data {
871    */    */
872    ESCRIPT_DLL_API    ESCRIPT_DLL_API
873    const boost::python::tuple    const boost::python::tuple
874    mindp() const;    minGlobalDataPoint() const;
875    
876    ESCRIPT_DLL_API    ESCRIPT_DLL_API
877    void    void
878    calc_mindp(int& SampleNo,    calc_minGlobalDataPoint(int& ProcNo,  int& DataPointNo) const;
              int& DataPointNo) const;  
   
879    /**    /**
880       \brief       \brief
881       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 888  class Data {
888    
889    /**    /**
890       \brief       \brief
891         Return the symmetric part of a matrix which is half the matrix plus its transpose.
892         *
893      */
894      ESCRIPT_DLL_API
895      Data
896      symmetric() const;
897    
898      /**
899         \brief
900         Return the nonsymmetric part of a matrix which is half the matrix minus its transpose.
901         *
902      */
903      ESCRIPT_DLL_API
904      Data
905      nonsymmetric() const;
906    
907      /**
908         \brief
909         Return the trace of a matrix
910         *
911      */
912      ESCRIPT_DLL_API
913      Data
914      trace(int axis_offset) const;
915    
916      /**
917         \brief
918         Transpose each data point of this Data object around the given axis.
919         *
920      */
921      ESCRIPT_DLL_API
922      Data
923      transpose(int axis_offset) const;
924    
925      /**
926         \brief
927       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.
928       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.
929       *       *
# Line 792  class Data { Line 935  class Data {
935    /**    /**
936       \brief       \brief
937       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.
938       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
939       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
940       first non-zero entry is positive.       first non-zero entry is positive.
941       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
942       *       *
# Line 804  class Data { Line 947  class Data {
947    
948    /**    /**
949       \brief       \brief
950       Transpose each data point of this Data object around the given axis.       swaps the components axis0 and axis1
      --* not implemented yet *--  
951       *       *
952    */    */
953    ESCRIPT_DLL_API    ESCRIPT_DLL_API
954    Data    Data
955    transpose(int axis) const;    swapaxes(const int axis0, const int axis1) const;
956    
957    /**    /**
958       \brief       \brief
959       Calculate the trace of each data point of this Data object.       Return the error function erf of each data point of this Data object.
960       *       *
961    */    */
962    ESCRIPT_DLL_API    ESCRIPT_DLL_API
963    Data    Data
964    trace() const;    erf() const;
965    
966    /**    /**
967       \brief       \brief
# Line 998  class Data { Line 1140  class Data {
1140    /**    /**
1141       \brief       \brief
1142       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.
1143        
1144       \param right Input - the power to raise the object to.       \param right Input - the power to raise the object to.
1145       *       *
1146     */     */
# Line 1009  class Data { Line 1151  class Data {
1151    /**    /**
1152       \brief       \brief
1153       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.
1154        
1155       \param left Input - the bases       \param left Input - the bases
1156       *       *
1157     */     */
# Line 1045  class Data { Line 1187  class Data {
1187    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1188    Data& operator+=(const boost::python::object& right);    Data& operator+=(const boost::python::object& right);
1189    
1190      ESCRIPT_DLL_API
1191      Data& operator=(const Data& other);
1192    
1193    /**    /**
1194       \brief       \brief
1195       Overloaded operator -=       Overloaded operator -=
# Line 1137  class Data { Line 1282  class Data {
1282    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1283    inline    inline
1284    void    void
1285    unaryOp(UnaryFunction operation);    unaryOp2(UnaryFunction operation);
1286    
1287    /**    /**
1288       \brief       \brief
# Line 1148  class Data { Line 1293  class Data {
1293    */    */
1294    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1295    Data    Data
1296    getSlice(const DataArrayView::RegionType& region) const;    getSlice(const DataTypes::RegionType& region) const;
1297    
1298    /**    /**
1299       \brief       \brief
# Line 1161  class Data { Line 1306  class Data {
1306    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1307    void    void
1308    setSlice(const Data& value,    setSlice(const Data& value,
1309             const DataArrayView::RegionType& region);             const DataTypes::RegionType& region);
1310    
1311    /**    /**
1312       \brief       \brief
1313       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.  
1314    */    */
1315    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1316    void    void
1317    archiveData(const std::string fileName);          print(void);
1318    
1319    /**    /**
1320       \brief       \brief
1321       Extract the Data object archived in the given file, overwriting       return the MPI rank number of the local data
1322       the current Data object.                   MPI_COMM_WORLD is assumed and the result of MPI_Comm_size()
1323       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.  
1324    */    */
1325    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1326    void          int
1327    extractData(const std::string fileName,          get_MPIRank(void) const;
               const FunctionSpace& fspace);  
1328    
1329      /**
1330         \brief
1331         return the MPI rank number of the local data
1332                     MPI_COMM_WORLD is assumed and the result of MPI_Comm_rank()
1333                     is returned
1334      */
1335      ESCRIPT_DLL_API
1336            int
1337            get_MPISize(void) const;
1338    
1339    /**    /**
1340       \brief       \brief
1341       print the data values to stdout. Used for debugging       return the MPI rank number of the local data
1342                     MPI_COMM_WORLD is assumed and returned.
1343    */    */
1344    void print();    ESCRIPT_DLL_API
1345            MPI_Comm
1346            get_MPIComm(void) const;
1347    
1348      /**
1349         \brief
1350         return the object produced by the factory, which is a DataConstant or DataExpanded
1351        TODO Ownership of this object should be explained in doco.
1352      */
1353      ESCRIPT_DLL_API
1354            DataAbstract*
1355            borrowData(void) const;
1356    
1357    
1358      /**
1359         \brief
1360         Return a pointer to the beginning of the datapoint at the specified offset.
1361         TODO Eventually these should be inlined.
1362         \param i - position(offset) in the underlying datastructure
1363      */
1364      ESCRIPT_DLL_API
1365            DataTypes::ValueType::const_reference
1366            getDataAtOffset(DataTypes::ValueType::size_type i) const;
1367    
1368    
1369      ESCRIPT_DLL_API
1370            DataTypes::ValueType::reference
1371            getDataAtOffset(DataTypes::ValueType::size_type i);
1372    
1373   protected:   protected:
1374    
# Line 1249  class Data { Line 1427  class Data {
1427    
1428    /**    /**
1429       \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  
1430       Convert the data type of the RHS to match this.       Convert the data type of the RHS to match this.
1431       \param right - Input - data type to match.       \param right - Input - data type to match.
1432    */    */
# Line 1278  class Data { Line 1445  class Data {
1445       \brief       \brief
1446       Construct a Data object of the appropriate type.       Construct a Data object of the appropriate type.
1447    */    */
1448    template <class IValueType>  
1449    void    void
1450    initialise(const IValueType& value,    initialise(const DataTypes::ValueType& value,
1451             const DataTypes::ShapeType& shape,
1452               const FunctionSpace& what,               const FunctionSpace& what,
1453               bool expanded);               bool expanded);
1454    
   /**  
      \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.  
   */  
1455    void    void
1456    reshapeDataPoint(const DataArrayView::ShapeType& shape);    initialise(const boost::python::numeric::array& value,
1457                     const FunctionSpace& what,
1458                     bool expanded);
1459    
1460    //    //
1461    // pointer to the actual data object    // flag to protect the data object against any update
1462    boost::shared_ptr<DataAbstract> m_data;    bool m_protected;
1463    
1464    //    //
1465    // pointer to the internal profiling data    // pointer to the actual data object
1466    struct profDataEntry *profData;    boost::shared_ptr<DataAbstract> m_data;
1467    
1468  };  };
1469    
1470  template <class IValueType>  
1471  void  
1472  Data::initialise(const IValueType& value,  /**
1473                   const FunctionSpace& what,     Modify a filename for MPI parallel output to multiple files
1474                   bool expanded)  */
1475  {  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;  
   }  
 }  
1476    
1477  /**  /**
1478     Binary Data object operators.     Binary Data object operators.
1479  */  */
1480    inline double rpow(double x,double y)
1481    {
1482        return pow(y,x);
1483    }
1484    
1485  /**  /**
1486    \brief    \brief
# Line 1422  ESCRIPT_DLL_API Data operator*(const boo Line 1574  ESCRIPT_DLL_API Data operator*(const boo
1574  */  */
1575  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);
1576    
1577    
1578    
1579  /**  /**
1580    \brief    \brief
1581    Output operator    Output operator
# Line 1430  ESCRIPT_DLL_API std::ostream& operator<< Line 1584  ESCRIPT_DLL_API std::ostream& operator<<
1584    
1585  /**  /**
1586    \brief    \brief
1587    Return true if operands are equivalent, else return false.    Compute a tensor product of two Data objects
1588    NB: this operator does very little at this point, and isn't to    \param arg0 - Input - Data object
1589    be relied on. Requires further implementation.    \param arg1 - Input - Data object
1590      \param axis_offset - Input - axis offset
1591      \param transpose - Input - 0: transpose neither, 1: transpose arg0, 2: transpose arg1
1592  */  */
1593  //ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);  ESCRIPT_DLL_API
1594    Data
1595    C_GeneralTensorProduct(Data& arg0,
1596                         Data& arg1,
1597                         int axis_offset=0,
1598                         int transpose=0);
1599    
1600    
1601    
1602    // /**
1603    /*  \brief
1604      Return true if operands are equivalent, else return false.
1605      NB: this operator does very little at this point, and isn't to
1606      be relied on. Requires further implementation.*/
1607    //*/
1608    // ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);
1609    
1610  /**  /**
1611    \brief    \brief
# Line 1449  Data::binaryOp(const Data& right, Line 1620  Data::binaryOp(const Data& right,
1620  {  {
1621     //     //
1622     // 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
1623     if (getPointDataView().getRank()==0 && right.getPointDataView().getRank()!=0) {     if (getDataPointRank()==0 && right.getDataPointRank()!=0) {
1624       reshapeDataPoint(right.getPointDataView().getShape());       throw DataException("Error - attempt to update rank zero object with object with rank bigger than zero.");
1625     }     }
1626     //     //
1627     // initially make the temporary a shallow copy     // initially make the temporary a shallow copy
# Line 1458  Data::binaryOp(const Data& right, Line 1629  Data::binaryOp(const Data& right,
1629     if (getFunctionSpace()!=right.getFunctionSpace()) {     if (getFunctionSpace()!=right.getFunctionSpace()) {
1630       if (right.probeInterpolation(getFunctionSpace())) {       if (right.probeInterpolation(getFunctionSpace())) {
1631         //         //
1632         // an interpolation is required so create a new Data         // an interpolation is required so create a new Data
1633         tempRight=Data(right,this->getFunctionSpace());         tempRight=Data(right,this->getFunctionSpace());
1634       } else if (probeInterpolation(right.getFunctionSpace())) {       } else if (probeInterpolation(right.getFunctionSpace())) {
1635         //         //
# Line 1506  Data::binaryOp(const Data& right, Line 1677  Data::binaryOp(const Data& right,
1677    
1678  /**  /**
1679    \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  
1680    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.
1681    Given operation combines each element of each data point, thus argument    Given operation combines each element of each data point, thus argument
1682    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 1614  Data::algorithm(BinaryFunction operation Line 1699  Data::algorithm(BinaryFunction operation
1699      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());
1700      EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");      EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");
1701      return escript::algorithm(*leftC,operation,initial_value);      return escript::algorithm(*leftC,operation,initial_value);
1702      } else if (isEmpty()) {
1703        throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1704    }    }
1705    return 0;    return 0;
1706  }  }
# Line 1622  Data::algorithm(BinaryFunction operation Line 1709  Data::algorithm(BinaryFunction operation
1709    \brief    \brief
1710    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.
1711    Given operation combines each element within each data point into a scalar,    Given operation combines each element within each data point into a scalar,
1712    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
1713    rank 0 Data object.    rank 0 Data object.
1714    Calls escript::dp_algorithm.    Calls escript::dp_algorithm.
1715  */  */
# Line 1631  inline Line 1718  inline
1718  Data  Data
1719  Data::dp_algorithm(BinaryFunction operation, double initial_value) const  Data::dp_algorithm(BinaryFunction operation, double initial_value) const
1720  {  {
1721    if (isExpanded()) {    if (isEmpty()) {
1722      Data result(0,DataArrayView::ShapeType(),getFunctionSpace(),isExpanded());      throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1723      }
1724      else if (isExpanded()) {
1725        Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1726      DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());      DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());
1727      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());
1728      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");
1729      EsysAssert((resultE!=0), "Programming error - casting result to DataExpanded.");      EsysAssert((resultE!=0), "Programming error - casting result to DataExpanded.");
1730      escript::dp_algorithm(*dataE,*resultE,operation,initial_value);      escript::dp_algorithm(*dataE,*resultE,operation,initial_value);
1731      return result;      return result;
1732    } else if (isTagged()) {    }
1733      else if (isTagged()) {
1734      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());  
1735      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");
1736      EsysAssert((resultT!=0), "Programming error - casting result to DataTagged.");      DataTypes::ValueType defval(1);
1737        defval[0]=0;
1738        DataTagged* resultT=new DataTagged(getFunctionSpace(), DataTypes::scalarShape, defval, dataT);
1739      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);
1740      return result;      return Data(resultT);   // note: the Data object now owns the resultT pointer
1741    } else if (isConstant()) {    }
1742      Data result(0,DataArrayView::ShapeType(),getFunctionSpace(),isExpanded());    else if (isConstant()) {
1743        Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1744      DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());      DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());
1745      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());
1746      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 1752  Data::dp_algorithm(BinaryFunction operat
1752    return falseRetVal;    return falseRetVal;
1753  }  }
1754    
1755    /**
1756      \brief
1757      Compute a tensor operation with two Data objects
1758      \param arg0 - Input - Data object
1759      \param arg1 - Input - Data object
1760      \param operation - Input - Binary op functor
1761    */
1762    template <typename BinaryFunction>
1763    inline
1764    Data
1765    C_TensorBinaryOperation(Data const &arg_0,
1766                            Data const &arg_1,
1767                            BinaryFunction operation)
1768    {
1769      if (arg_0.isEmpty() || arg_1.isEmpty())
1770      {
1771         throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1772      }
1773      // Interpolate if necessary and find an appropriate function space
1774      Data arg_0_Z, arg_1_Z;
1775      if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
1776        if (arg_0.probeInterpolation(arg_1.getFunctionSpace())) {
1777          arg_0_Z = arg_0.interpolate(arg_1.getFunctionSpace());
1778          arg_1_Z = Data(arg_1);
1779        }
1780        else if (arg_1.probeInterpolation(arg_0.getFunctionSpace())) {
1781          arg_1_Z=arg_1.interpolate(arg_0.getFunctionSpace());
1782          arg_0_Z =Data(arg_0);
1783        }
1784        else {
1785          throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible function spaces.");
1786        }
1787      } else {
1788          arg_0_Z = Data(arg_0);
1789          arg_1_Z = Data(arg_1);
1790      }
1791      // Get rank and shape of inputs
1792      int rank0 = arg_0_Z.getDataPointRank();
1793      int rank1 = arg_1_Z.getDataPointRank();
1794      DataTypes::ShapeType shape0 = arg_0_Z.getDataPointShape();
1795      DataTypes::ShapeType shape1 = arg_1_Z.getDataPointShape();
1796      int size0 = arg_0_Z.getDataPointSize();
1797      int size1 = arg_1_Z.getDataPointSize();
1798    
1799      // Declare output Data object
1800      Data res;
1801    
1802      if (shape0 == shape1) {
1803    
1804        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1805          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
1806    /*      double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1807          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1808          double *ptr_2 = &((res.getPointDataView().getData())[0]);*/
1809          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
1810          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
1811          double *ptr_2 = &(res.getDataAtOffset(0));
1812    
1813          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1814        }
1815        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
1816    
1817          // Prepare the DataConstant input
1818          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1819    
1820          // Borrow DataTagged input from Data object
1821          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1822    
1823          // Prepare a DataTagged output 2
1824          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
1825          res.tag();
1826          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1827    
1828          // Prepare offset into DataConstant
1829          int offset_0 = tmp_0->getPointOffset(0,0);
1830          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1831          // Get the views
1832    //       DataArrayView view_1 = tmp_1->getDefaultValue();
1833    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1834    //       // Get the pointers to the actual data
1835    //       double *ptr_1 = &((view_1.getData())[0]);
1836    //       double *ptr_2 = &((view_2.getData())[0]);
1837    
1838          // Get the pointers to the actual data
1839          double *ptr_1 = &(tmp_1->getDefaultValue(0));
1840          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1841    
1842          // Compute a result for the default
1843          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1844          // Compute a result for each tag
1845          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1846          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1847          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1848            tmp_2->addTag(i->first);
1849    /*        DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1850            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1851            double *ptr_1 = &view_1.getData(0);
1852            double *ptr_2 = &view_2.getData(0);*/
1853            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1854            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1855    
1856            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1857          }
1858    
1859        }
1860        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
1861    
1862          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1863          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1864          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1865          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1866    
1867          int sampleNo_1,dataPointNo_1;
1868          int numSamples_1 = arg_1_Z.getNumSamples();
1869          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
1870          int offset_0 = tmp_0->getPointOffset(0,0);
1871          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
1872          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
1873            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
1874              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
1875              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
1876    //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1877    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1878    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1879    
1880              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1881              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
1882              double *ptr_2 = &(res.getDataAtOffset(offset_2));
1883              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1884            }
1885          }
1886    
1887        }
1888        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
1889    
1890          // Borrow DataTagged input from Data object
1891          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1892    
1893          // Prepare the DataConstant input
1894          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
1895    
1896          // Prepare a DataTagged output 2
1897          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
1898          res.tag();
1899          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1900    
1901          // Prepare offset into DataConstant
1902          int offset_1 = tmp_1->getPointOffset(0,0);
1903    //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1904          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
1905          // Get the views
1906    //       DataArrayView view_0 = tmp_0->getDefaultValue();
1907    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1908    //       // Get the pointers to the actual data
1909    //       double *ptr_0 = &((view_0.getData())[0]);
1910    //       double *ptr_2 = &((view_2.getData())[0]);
1911          // Get the pointers to the actual data
1912          double *ptr_0 = &(tmp_0->getDefaultValue(0));
1913          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1914          // Compute a result for the default
1915          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1916          // Compute a result for each tag
1917          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1918          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1919          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1920            tmp_2->addTag(i->first);
1921    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1922    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1923    //         double *ptr_0 = &view_0.getData(0);
1924    //         double *ptr_2 = &view_2.getData(0);
1925            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
1926            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1927            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1928          }
1929    
1930        }
1931        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
1932    
1933          // Borrow DataTagged input from Data object
1934          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1935    
1936          // Borrow DataTagged input from Data object
1937          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1938    
1939          // Prepare a DataTagged output 2
1940          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
1941          res.tag();        // DataTagged output
1942          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1943    
1944    //       // Get the views
1945    //       DataArrayView view_0 = tmp_0->getDefaultValue();
1946    //       DataArrayView view_1 = tmp_1->getDefaultValue();
1947    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1948    //       // Get the pointers to the actual data
1949    //       double *ptr_0 = &((view_0.getData())[0]);
1950    //       double *ptr_1 = &((view_1.getData())[0]);
1951    //       double *ptr_2 = &((view_2.getData())[0]);
1952    
1953          // Get the pointers to the actual data
1954          double *ptr_0 = &(tmp_0->getDefaultValue(0));
1955          double *ptr_1 = &(tmp_1->getDefaultValue(0));
1956          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1957    
1958          // Compute a result for the default
1959          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1960          // Merge the tags
1961          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1962          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1963          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1964          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1965            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
1966          }
1967          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1968            tmp_2->addTag(i->first);
1969          }
1970          // Compute a result for each tag
1971          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
1972          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
1973    
1974    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1975    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1976    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1977    //         double *ptr_0 = &view_0.getData(0);
1978    //         double *ptr_1 = &view_1.getData(0);
1979    //         double *ptr_2 = &view_2.getData(0);
1980    
1981            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
1982            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1983            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1984    
1985            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1986          }
1987    
1988        }
1989        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
1990    
1991          // After finding a common function space above the two inputs have the same numSamples and num DPPS
1992          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
1993          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
1994          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
1995          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
1996    
1997          int sampleNo_0,dataPointNo_0;
1998          int numSamples_0 = arg_0_Z.getNumSamples();
1999          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2000          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2001          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2002            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2003            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2004            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2005              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2006              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2007    
2008    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2009    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2010              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2011              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2012    
2013    
2014              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2015            }
2016          }
2017    
2018        }
2019        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2020    
2021          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2022          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2023          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2024          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2025    
2026          int sampleNo_0,dataPointNo_0;
2027          int numSamples_0 = arg_0_Z.getNumSamples();
2028          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2029          int offset_1 = tmp_1->getPointOffset(0,0);
2030          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2031          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2032            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2033              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2034              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2035    
2036    //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2037    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2038    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2039    
2040              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2041              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2042              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2043    
2044    
2045              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2046            }
2047          }
2048    
2049        }
2050        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2051    
2052          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2053          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2054          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2055          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2056          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2057    
2058          int sampleNo_0,dataPointNo_0;
2059          int numSamples_0 = arg_0_Z.getNumSamples();
2060          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2061          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2062          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2063            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2064            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2065            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2066              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2067              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2068              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2069              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2070              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2071            }
2072          }
2073    
2074        }
2075        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2076    
2077          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2078          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2079          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2080          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2081          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2082    
2083          int sampleNo_0,dataPointNo_0;
2084          int numSamples_0 = arg_0_Z.getNumSamples();
2085          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2086          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2087          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2088            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2089              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2090              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2091              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2092              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2093              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2094              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2095              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2096            }
2097          }
2098    
2099        }
2100        else {
2101          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2102        }
2103    
2104      } else if (0 == rank0) {
2105    
2106        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2107          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output
2108          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2109          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2110          double *ptr_2 = &(res.getDataAtOffset(0));
2111          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2112        }
2113        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2114    
2115          // Prepare the DataConstant input
2116          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2117    
2118          // Borrow DataTagged input from Data object
2119          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2120    
2121          // Prepare a DataTagged output 2
2122          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataTagged output
2123          res.tag();
2124          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2125    
2126          // Prepare offset into DataConstant
2127          int offset_0 = tmp_0->getPointOffset(0,0);
2128          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2129          // Get the views
2130    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2131    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2132    //       // Get the pointers to the actual data
2133    //       double *ptr_1 = &((view_1.getData())[0]);
2134    //       double *ptr_2 = &((view_2.getData())[0]);
2135           double *ptr_1 = &(tmp_1->getDefaultValue(0));
2136           double *ptr_2 = &(tmp_2->getDefaultValue(0));
2137    
2138          // Compute a result for the default
2139          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2140          // Compute a result for each tag
2141          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2142          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2143          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2144            tmp_2->addTag(i->first);
2145    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2146    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2147    //         double *ptr_1 = &view_1.getData(0);
2148    //         double *ptr_2 = &view_2.getData(0);
2149            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2150            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2151            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2152          }
2153    
2154        }
2155        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2156    
2157          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2158          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2159          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2160          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2161    
2162          int sampleNo_1,dataPointNo_1;
2163          int numSamples_1 = arg_1_Z.getNumSamples();
2164          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2165          int offset_0 = tmp_0->getPointOffset(0,0);
2166          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2167          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2168            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2169              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2170              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2171              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2172              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2173              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2174              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2175    
2176            }
2177          }
2178    
2179        }
2180        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2181    
2182          // Borrow DataTagged input from Data object
2183          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2184    
2185          // Prepare the DataConstant input
2186          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2187    
2188          // Prepare a DataTagged output 2
2189          res = Data(0.0, shape1, arg_0_Z.getFunctionSpace());      // DataTagged output
2190          res.tag();
2191          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2192    
2193          // Prepare offset into DataConstant
2194          int offset_1 = tmp_1->getPointOffset(0,0);
2195    //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2196          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2197          // Get the views
2198    /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2199          DataArrayView view_2 = tmp_2->getDefaultValue();
2200          // Get the pointers to the actual data
2201          double *ptr_0 = &((view_0.getData())[0]);
2202          double *ptr_2 = &((view_2.getData())[0]);*/
2203    
2204          // Get the pointers to the actual data
2205          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2206          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2207    
2208    
2209          // Compute a result for the default
2210          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2211          // Compute a result for each tag
2212          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2213          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2214          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2215            tmp_2->addTag(i->first);
2216    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2217            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2218            double *ptr_0 = &view_0.getData(0);
2219            double *ptr_2 = &view_2.getData(0);*/
2220            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2221            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2222    
2223            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2224          }
2225    
2226        }
2227        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2228    
2229          // Borrow DataTagged input from Data object
2230          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2231    
2232          // Borrow DataTagged input from Data object
2233          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2234    
2235          // Prepare a DataTagged output 2
2236          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());
2237          res.tag();        // DataTagged output
2238          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2239    
2240          // Get the views
2241    /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2242          DataArrayView view_1 = tmp_1->getDefaultValue();
2243          DataArrayView view_2 = tmp_2->getDefaultValue();
2244          // Get the pointers to the actual data
2245          double *ptr_0 = &((view_0.getData())[0]);
2246          double *ptr_1 = &((view_1.getData())[0]);
2247          double *ptr_2 = &((view_2.getData())[0]);*/
2248    
2249          // Get the pointers to the actual data
2250          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2251          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2252          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2253    
2254    
2255          // Compute a result for the default
2256          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2257          // Merge the tags
2258          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2259          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2260          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2261          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2262            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2263          }
2264          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2265            tmp_2->addTag(i->first);
2266          }
2267          // Compute a result for each tag
2268          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2269          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2270    
2271    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2272            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2273            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2274            double *ptr_0 = &view_0.getData(0);
2275            double *ptr_1 = &view_1.getData(0);
2276            double *ptr_2 = &view_2.getData(0);*/
2277    
2278            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2279            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2280            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2281    
2282            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2283          }
2284    
2285        }
2286        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2287    
2288          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2289          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2290          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2291          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2292          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2293    
2294          int sampleNo_0,dataPointNo_0;
2295          int numSamples_0 = arg_0_Z.getNumSamples();
2296          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2297          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2298          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2299            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2300            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2301            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2302              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2303              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2304              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2305              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2306              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2307            }
2308          }
2309    
2310        }
2311        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2312    
2313          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2314          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2315          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2316          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2317    
2318          int sampleNo_0,dataPointNo_0;
2319          int numSamples_0 = arg_0_Z.getNumSamples();
2320          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2321          int offset_1 = tmp_1->getPointOffset(0,0);
2322          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2323          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2324            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2325              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2326              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2327              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2328              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2329              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2330              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2331            }
2332          }
2333    
2334    
2335        }
2336        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2337    
2338          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2339          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2340          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2341          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2342          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2343    
2344          int sampleNo_0,dataPointNo_0;
2345          int numSamples_0 = arg_0_Z.getNumSamples();
2346          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2347          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2348          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2349            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2350            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2351            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2352              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2353              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2354              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2355              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2356              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2357            }
2358          }
2359    
2360        }
2361        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2362    
2363          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2364          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2365          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2366          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2367          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2368    
2369          int sampleNo_0,dataPointNo_0;
2370          int numSamples_0 = arg_0_Z.getNumSamples();
2371          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2372          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2373          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2374            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2375              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2376              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2377              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2378              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2379              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2380              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2381              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2382            }
2383          }
2384    
2385        }
2386        else {
2387          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2388        }
2389    
2390      } else if (0 == rank1) {
2391    
2392        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2393          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
2394          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2395          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2396          double *ptr_2 = &(res.getDataAtOffset(0));
2397          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2398        }
2399        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2400    
2401          // Prepare the DataConstant input
2402          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2403    
2404          // Borrow DataTagged input from Data object
2405          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2406    
2407          // Prepare a DataTagged output 2
2408          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
2409          res.tag();
2410          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2411    
2412          // Prepare offset into DataConstant
2413          int offset_0 = tmp_0->getPointOffset(0,0);
2414          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2415          // Get the views
2416    /*      DataArrayView view_1 = tmp_1->getDefaultValue();
2417          DataArrayView view_2 = tmp_2->getDefaultValue();
2418          // Get the pointers to the actual data
2419          double *ptr_1 = &((view_1.getData())[0]);
2420          double *ptr_2 = &((view_2.getData())[0]);*/
2421          //Get the pointers to the actual data
2422          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2423          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2424    
2425          // Compute a result for the default
2426          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2427          // Compute a result for each tag
2428          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2429          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2430          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2431            tmp_2->addTag(i->first);
2432    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2433    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2434    //         double *ptr_1 = &view_1.getData(0);
2435    //         double *ptr_2 = &view_2.getData(0);
2436            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2437            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2438    
2439    
2440            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2441          }
2442    
2443        }
2444        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2445    
2446          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2447          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2448          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2449          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2450    
2451          int sampleNo_1,dataPointNo_1;
2452          int numSamples_1 = arg_1_Z.getNumSamples();
2453          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2454          int offset_0 = tmp_0->getPointOffset(0,0);
2455          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2456          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2457            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2458              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2459              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2460              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2461              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2462              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2463              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2464            }
2465          }
2466    
2467        }
2468        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2469    
2470          // Borrow DataTagged input from Data object
2471          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2472    
2473          // Prepare the DataConstant input
2474          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2475    
2476          // Prepare a DataTagged output 2
2477          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
2478          res.tag();
2479          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2480    
2481          // Prepare offset into DataConstant
2482          int offset_1 = tmp_1->getPointOffset(0,0);
2483          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2484          // Get the views
2485    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2486    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2487    //       // Get the pointers to the actual data
2488    //       double *ptr_0 = &((view_0.getData())[0]);
2489    //       double *ptr_2 = &((view_2.getData())[0]);
2490          // Get the pointers to the actual data
2491          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2492          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2493          // Compute a result for the default
2494          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2495          // Compute a result for each tag
2496          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2497          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2498          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2499            tmp_2->addTag(i->first);
2500    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2501            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2502            double *ptr_0 = &view_0.getData(0);
2503            double *ptr_2 = &view_2.getData(0);*/
2504            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2505            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2506            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2507          }
2508    
2509        }
2510        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2511    
2512          // Borrow DataTagged input from Data object
2513          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2514    
2515          // Borrow DataTagged input from Data object
2516          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2517    
2518          // Prepare a DataTagged output 2
2519          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
2520          res.tag();        // DataTagged output
2521          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2522    
2523          // Get the views
2524    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2525    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2526    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2527    //       // Get the pointers to the actual data
2528    //       double *ptr_0 = &((view_0.getData())[0]);
2529    //       double *ptr_1 = &((view_1.getData())[0]);
2530    //       double *ptr_2 = &((view_2.getData())[0]);
2531    
2532          // Get the pointers to the actual data
2533          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2534          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2535          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2536    
2537          // Compute a result for the default
2538          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2539          // Merge the tags
2540          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2541          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2542          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2543          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2544            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2545          }
2546          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2547            tmp_2->addTag(i->first);
2548          }
2549          // Compute a result for each tag
2550          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2551          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2552    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2553    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2554    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2555    //         double *ptr_0 = &view_0.getData(0);
2556    //         double *ptr_1 = &view_1.getData(0);
2557    //         double *ptr_2 = &view_2.getData(0);
2558    
2559            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2560            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2561            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2562            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2563          }
2564    
2565        }
2566        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2567    
2568          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2569          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2570          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2571          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2572          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2573    
2574          int sampleNo_0,dataPointNo_0;
2575          int numSamples_0 = arg_0_Z.getNumSamples();
2576          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2577          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2578          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2579            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2580            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2581            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2582              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2583              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2584              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2585              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2586              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2587            }
2588          }
2589    
2590        }
2591        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2592    
2593          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2594          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2595          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2596          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2597    
2598          int sampleNo_0,dataPointNo_0;
2599          int numSamples_0 = arg_0_Z.getNumSamples();
2600          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2601          int offset_1 = tmp_1->getPointOffset(0,0);
2602          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2603          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2604            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2605              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2606              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2607              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2608              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2609              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2610              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2611            }
2612          }
2613    
2614    
2615        }
2616        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2617    
2618          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2619          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2620          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2621          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2622          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2623    
2624          int sampleNo_0,dataPointNo_0;
2625          int numSamples_0 = arg_0_Z.getNumSamples();
2626          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2627          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2628          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2629            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2630            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2631            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2632              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2633              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2634              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2635              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2636              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2637            }
2638          }
2639    
2640        }
2641        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2642    
2643          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2644          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2645          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2646          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2647          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2648    
2649          int sampleNo_0,dataPointNo_0;
2650          int numSamples_0 = arg_0_Z.getNumSamples();
2651          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2652          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2653          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2654            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2655              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2656              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2657              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2658              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2659              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2660              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2661              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2662            }
2663          }
2664    
2665        }
2666        else {
2667          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2668        }
2669    
2670      } else {
2671        throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible shapes");
2672      }
2673    
2674      return res;
2675    }
2676    
2677    template <typename UnaryFunction>
2678    Data
2679    C_TensorUnaryOperation(Data const &arg_0,
2680                           UnaryFunction operation)
2681    {
2682      if (arg_0.isEmpty())  // do this before we attempt to interpolate
2683      {
2684         throw DataException("Error - Operations not permitted on instances of DataEmpty.");
2685      }
2686    
2687      // Interpolate if necessary and find an appropriate function space
2688      Data arg_0_Z = Data(arg_0);
2689    
2690      // Get rank and shape of inputs
2691      int rank0 = arg_0_Z.getDataPointRank();
2692      const DataTypes::ShapeType& shape0 = arg_0_Z.getDataPointShape();
2693      int size0 = arg_0_Z.getDataPointSize();
2694    
2695      // Declare output Data object
2696      Data res;
2697    
2698      if (arg_0_Z.isConstant()) {
2699        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output
2700    //     double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2701    //     double *ptr_2 = &((res.getPointDataView().getData())[0]);
2702        double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2703        double *ptr_2 = &(res.getDataAtOffset(0));
2704        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2705      }
2706      else if (arg_0_Z.isTagged()) {
2707    
2708        // Borrow DataTagged input from Data object
2709        DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2710    
2711        // Prepare a DataTagged output 2
2712        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());   // DataTagged output
2713        res.tag();
2714        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2715    
2716    //     // Get the views
2717    //     DataArrayView view_0 = tmp_0->getDefaultValue();
2718    //     DataArrayView view_2 = tmp_2->getDefaultValue();
2719    //     // Get the pointers to the actual data
2720    //     double *ptr_0 = &((view_0.getData())[0]);
2721    //     double *ptr_2 = &((view_2.getData())[0]);
2722        // Get the pointers to the actual data
2723        double *ptr_0 = &(tmp_0->getDefaultValue(0));
2724        double *ptr_2 = &(tmp_2->getDefaultValue(0));
2725        // Compute a result for the default
2726        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2727        // Compute a result for each tag
2728        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2729        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2730        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2731          tmp_2->addTag(i->first);
2732    //       DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2733    //       DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2734    //       double *ptr_0 = &view_0.getData(0);
2735    //       double *ptr_2 = &view_2.getData(0);
2736          double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2737          double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2738          tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2739        }
2740    
2741      }
2742      else if (arg_0_Z.isExpanded()) {
2743    
2744        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace(),true); // DataExpanded output
2745        DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2746        DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2747    
2748        int sampleNo_0,dataPointNo_0;
2749        int numSamples_0 = arg_0_Z.getNumSamples();
2750        int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2751        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2752        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2753          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2754    //         int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2755    //         int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2756    //         double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2757    //         double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2758            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2759            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2760            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2761            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2762            tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2763          }
2764        }
2765      }
2766      else {
2767        throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");
2768      }
2769    
2770      return res;
2771    }
2772    
2773  }  }
2774  #endif  #endif

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

  ViewVC Help
Powered by ViewVC 1.1.26