/[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

trunk/esys2/escript/src/Data/Data.h revision 97 by jgs, Tue Dec 14 05:39:33 2004 UTC trunk/escript/src/Data.h revision 2005 by jfenwick, Mon Nov 10 01:21:39 2008 UTC
# Line 1  Line 1 
 // $Id$  
 /*=============================================================================  
1    
2   ******************************************************************************  /*******************************************************
3   *                                                                            *  *
4   *       COPYRIGHT ACcESS 2004 -  All Rights Reserved                         *  * Copyright (c) 2003-2008 by University of Queensland
5   *                                                                            *  * Earth Systems Science Computational Center (ESSCC)
6   * This software is the property of ACcESS.  No part of this code             *  * http://www.uq.edu.au/esscc
7   * may be copied in any form or by any means without the expressed written    *  *
8   * consent of ACcESS.  Copying, use or modification of this software          *  * Primary Business: Queensland, Australia
9   * by any unauthorised person is illegal unless that                          *  * Licensed under the Open Software License version 3.0
10   * person has a software license agreement with ACcESS.                       *  * http://www.opensource.org/licenses/osl-3.0.php
11   *                                                                            *  *
12   ******************************************************************************  *******************************************************/
13    
14  ******************************************************************************/  
15    /** \file Data.h */
16    
17  #ifndef DATA_H  #ifndef DATA_H
18  #define DATA_H  #define DATA_H
19    #include "system_dep.h"
20    
21  #include "escript/Data/DataAbstract.h"  #include "DataAbstract.h"
22  #include "escript/Data/DataTagged.h"  #include "DataAlgorithm.h"
23  #include "escript/Data/FunctionSpace.h"  #include "FunctionSpace.h"
24  #include "escript/Data/BinaryOp.h"  #include "BinaryOp.h"
25  #include "escript/Data/UnaryOp.h"  #include "UnaryOp.h"
26    #include "DataException.h"
27    #include "DataTypes.h"
28    
29  extern "C" {  extern "C" {
30  #include "escript/Data/DataC.h"  #include "DataC.h"
31    /* #include "paso/Paso.h" doesn't belong in this file...causes trouble for BruceFactory.cpp */
32  }  }
33    
34  #include <iostream>  #include "esysmpi.h"
35  #include <string>  #include <string>
 #include <memory>  
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>
 #include <boost/python/list.hpp>  
42  #include <boost/python/tuple.hpp>  #include <boost/python/tuple.hpp>
43  #include <boost/python/numeric.hpp>  #include <boost/python/numeric.hpp>
44    
 /**  
    \brief  
    Data is essentially a factory class which creates the appropriate Data  
    object for the given construction arguments. It retains control over  
    the object created for the lifetime of the object.  
    The type of Data object referred to may change during the lifetime of  
    the Data object.  
   
    Description:  
    Data is essentially a factory class which creates the appropriate Data  
    object for the given construction arguments. It retains control over  
    the object created for the lifetime of the object.  
    The type of Data object referred to may change during the lifetime of  
    the Data object.  
 */  
   
45  namespace escript {  namespace escript {
46    
47  //  //
48  // Forward declaration for various implimentations of Data.  // Forward declaration for various implementations of Data.
 class DataEmpty;  
49  class DataConstant;  class DataConstant;
50  class DataTagged;  class DataTagged;
51  class DataExpanded;  class DataExpanded;
52    
53    /**
54       \brief
55       Data represents a collection of datapoints.
56    
57       Description:
58       Internally, the datapoints are actually stored by a DataAbstract object.
59       The specific instance of DataAbstract used may vary over the lifetime
60       of the Data object.
61       Some methods on this class return references (eg getShape()).
62       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    
68    public:    public:
69    
70      // These typedefs allow function names to be cast to pointers
71      // to functions of the appropriate type when calling unaryOp etc.
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 80  class Data { Line 82  class Data {
82       Default constructor.       Default constructor.
83       Creates a DataEmpty object.       Creates a DataEmpty object.
84    */    */
85      ESCRIPT_DLL_API
86    Data();    Data();
87    
88    /**    /**
# Line 87  class Data { Line 90  class Data {
90       Copy constructor.       Copy constructor.
91       WARNING: Only performs a shallow copy.       WARNING: Only performs a shallow copy.
92    */    */
93      ESCRIPT_DLL_API
94    Data(const Data& inData);    Data(const Data& inData);
95    
96    /**    /**
# Line 95  class Data { Line 99  class Data {
99       function space of inData the inData are tried to be interpolated to what,       function space of inData the inData are tried to be interpolated to what,
100       otherwise a shallow copy of inData is returned.       otherwise a shallow copy of inData is returned.
101    */    */
102      ESCRIPT_DLL_API
103    Data(const Data& inData,    Data(const Data& inData,
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    
110       \param value - Input - Data value for a single point.    ESCRIPT_DLL_API
111       \param what - Input - A description of what this data represents.    Data(const DataTypes::ValueType& value,
112       \param expanded - Input - Flag, if true fill the entire container with           const DataTypes::ShapeType& shape,
113                         the value. Otherwise a more efficient storage                   const FunctionSpace& what=FunctionSpace(),
114                         mechanism will be used.                   bool expanded=false);
   */  
   Data(const DataArrayView& value,  
        const FunctionSpace& what=FunctionSpace(),  
        bool expanded=false);  
115    
116    /**    /**
117       \brief       \brief
# Line 123  class Data { Line 124  class Data {
124                         the given value. Otherwise a more efficient storage                         the given value. Otherwise a more efficient storage
125                         mechanism will be used.                         mechanism will be used.
126    */    */
127      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 135  class Data { Line 137  class Data {
137       \param inData - Input - Input Data object.       \param inData - Input - Input Data object.
138       \param region - Input - Region to copy.       \param region - Input - Region to copy.
139    */    */
140      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.  
   */  
   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 167  class Data { Line 151  class Data {
151                         the value. Otherwise a more efficient storage                         the value. Otherwise a more efficient storage
152                         mechanism will be used.                         mechanism will be used.
153    */    */
154      ESCRIPT_DLL_API
155    Data(const boost::python::numeric::array& value,    Data(const boost::python::numeric::array& value,
156         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
157         bool expanded=false);         bool expanded=false);
# Line 182  class Data { Line 167  class Data {
167                         the value. Otherwise a more efficient storage                         the value. Otherwise a more efficient storage
168                         mechanism will be used.                         mechanism will be used.
169    */    */
170      ESCRIPT_DLL_API
171    Data(const boost::python::object& value,    Data(const boost::python::object& value,
172         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
173         bool expanded=false);         bool expanded=false);
# Line 195  class Data { Line 181  class Data {
181       \param value - Input - Input data.       \param value - Input - Input data.
182       \param other - Input - contains all other parameters.       \param other - Input - contains all other parameters.
183    */    */
184      ESCRIPT_DLL_API
185    Data(const boost::python::object& value,    Data(const boost::python::object& value,
186         const Data& other);         const Data& other);
187    
# Line 202  class Data { Line 189  class Data {
189       \brief       \brief
190       Constructor which creates a DataConstant of "shape" with constant value.       Constructor which creates a DataConstant of "shape" with constant value.
191    */    */
192    Data(double value,    ESCRIPT_DLL_API
193         const boost::python::tuple& shape=boost::python::make_tuple(),    Data(double value,
194           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      explicit Data(DataAbstract* underlyingdata);
206    
207      /**
208        \brief Create a Data based on the supplied DataAbstract
209      */
210      ESCRIPT_DLL_API
211      explicit Data(DataAbstract_ptr underlyingdata);
212    
213    /**    /**
214       \brief       \brief
215       Perform a deep copy.       Destructor
216    */    */
217      ESCRIPT_DLL_API
218      ~Data();
219    
220      /**
221         \brief Make this object a deep copy of "other".
222      */
223      ESCRIPT_DLL_API
224    void    void
225    copy(const Data& other);    copy(const Data& other);
226    
227    /**    /**
228         \brief Return a pointer to a deep copy of this object.
229      */
230      ESCRIPT_DLL_API
231      Data*
232      copySelf();
233    
234    
235      /**
236         \brief produce a delayed evaluation version of this Data.
237      */
238      ESCRIPT_DLL_API
239      Data
240      delay();
241    
242      /**
243         \brief convert the current data into lazy data.
244      */
245      ESCRIPT_DLL_API
246      void
247      delaySelf();
248    
249    
250      /**
251       Member access methods.       Member access methods.
252    */    */
253    
254    /**    /**
255       \brief       \brief
256         switches on update protection
257    
258      */
259      ESCRIPT_DLL_API
260      void
261      setProtection();
262    
263      /**
264         \brief
265         Returns trueif the data object is protected against update
266    
267      */
268      ESCRIPT_DLL_API
269      bool
270      isProtected() const;
271    
272      /**
273         \brief
274         Return the values of a data point on this process
275      */
276      ESCRIPT_DLL_API
277      const boost::python::numeric::array
278      getValueOfDataPoint(int dataPointNo);
279    
280      /**
281         \brief
282         sets the values of a data-point from a python object on this process
283      */
284      ESCRIPT_DLL_API
285      void
286      setValueOfDataPointToPyObject(int dataPointNo, const boost::python::object& py_object);
287    
288      /**
289         \brief
290         sets the values of a data-point from a numarray object on this process
291      */
292      ESCRIPT_DLL_API
293      void
294      setValueOfDataPointToArray(int dataPointNo, const boost::python::numeric::array&);
295    
296      /**
297         \brief
298         sets the values of a data-point on this process
299      */
300      ESCRIPT_DLL_API
301      void
302      setValueOfDataPoint(int dataPointNo, const double);
303    
304      /**
305         \brief
306         Return the value of the specified data-point across all processors
307      */
308      ESCRIPT_DLL_API
309      const boost::python::numeric::array
310      getValueOfGlobalDataPoint(int procNo, int dataPointNo);
311    
312      /**
313         \brief
314         Return the tag number associated with the given data-point.
315    
316      */
317      ESCRIPT_DLL_API
318      int
319      getTagNumber(int dpno);
320    
321      /**
322         \brief
323       Return the C wrapper for the Data object.       Return the C wrapper for the Data object.
324    */    */
325      ESCRIPT_DLL_API
326    escriptDataC    escriptDataC
327    getDataC();    getDataC();
328    
329    
330    
331    
332    
333    
334    // REMOVE ME
335    // ESCRIPT_DLL_API
336    // void
337    // CompareDebug(const Data& rd);
338    
339    
340    /**    /**
341       \brief       \brief
342       Return the C wrapper for the Data object - const version.       Return the C wrapper for the Data object - const version.
343    */    */
344      ESCRIPT_DLL_API
345    escriptDataC    escriptDataC
346    getDataC() const;    getDataC() const;
347    
348    /**    /**
349       \brief       \brief
350       Write the data as a string.       Write the data as a string. For large amounts of data, a summary is printed.
351    */    */
352    inline    ESCRIPT_DLL_API
353    std::string    std::string
354    toString() const    toString() const;
   {  
     return m_data->toString();  
   }  
   
   /**  
      \brief  
      Return the DataArrayView of the point data. This essentially contains  
      the shape information for each data point although it also may be used  
      to manipulate the point data.  
   */  
   inline  
   const DataArrayView&  
   getPointDataView() const  
   {  
      return m_data->getPointDataView();  
   }  
355    
356    /**    /**
357       \brief       \brief
358       Whatever the current Data type make this into a DataExpanded.       Whatever the current Data type make this into a DataExpanded.
359    */    */
360      ESCRIPT_DLL_API
361    void    void
362    expand();    expand();
363    
# Line 269  class Data { Line 367  class Data {
367       Constant data to be converted to tagged. An attempt to convert       Constant data to be converted to tagged. An attempt to convert
368       Expanded data to tagged will throw an exception.       Expanded data to tagged will throw an exception.
369    */    */
370      ESCRIPT_DLL_API
371    void    void
372    tag();    tag();
373    
374    /**    /**
375        \brief If this data is lazy, then convert it to ready data.
376        What type of ready data depends on the expression. For example, Constant+Tagged==Tagged.
377      */
378      ESCRIPT_DLL_API
379      void
380      resolve();
381    
382    
383      /**
384       \brief       \brief
385       Return true if this Data is expanded.       Return true if this Data is expanded.
386    */    */
387      ESCRIPT_DLL_API
388    bool    bool
389    isExpanded() const;    isExpanded() const;
390    
# Line 283  class Data { Line 392  class Data {
392       \brief       \brief
393       Return true if this Data is tagged.       Return true if this Data is tagged.
394    */    */
395      ESCRIPT_DLL_API
396    bool    bool
397    isTagged() const;    isTagged() const;
398    
# Line 290  class Data { Line 400  class Data {
400       \brief       \brief
401       Return true if this Data is constant.       Return true if this Data is constant.
402    */    */
403      ESCRIPT_DLL_API
404    bool    bool
405    isConstant() const;    isConstant() const;
406    
407    /**    /**
408         \brief Return true if this Data is lazy.
409      */
410      ESCRIPT_DLL_API
411      bool
412      isLazy() const;
413    
414      /**
415         \brief Return true if this data is ready.
416      */
417      ESCRIPT_DLL_API
418      bool
419      isReady() const;
420    
421      /**
422       \brief       \brief
423       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
424    contains datapoints.
425    */    */
426      ESCRIPT_DLL_API
427    bool    bool
428    isEmpty() const;    isEmpty() const;
429    
# Line 304  class Data { Line 431  class Data {
431       \brief       \brief
432       Return the function space.       Return the function space.
433    */    */
434      ESCRIPT_DLL_API
435    inline    inline
436    const FunctionSpace&    const FunctionSpace&
437    getFunctionSpace() const    getFunctionSpace() const
# Line 315  class Data { Line 443  class Data {
443       \brief       \brief
444       Return a copy of the function space.       Return a copy of the function space.
445    */    */
446      ESCRIPT_DLL_API
447    const FunctionSpace    const FunctionSpace
448    getCopyOfFunctionSpace() const;    getCopyOfFunctionSpace() const;
449    
# Line 322  class Data { Line 451  class Data {
451       \brief       \brief
452       Return the domain.       Return the domain.
453    */    */
454      ESCRIPT_DLL_API
455    inline    inline
456    const AbstractDomain&  //   const AbstractDomain&
457      const_Domain_ptr
458    getDomain() const    getDomain() const
459    {    {
460       return getFunctionSpace().getDomain();       return getFunctionSpace().getDomain();
461    }    }
462    
463    
464      /**
465         \brief
466         Return the domain.
467         TODO: For internal use only.   This should be removed.
468      */
469      ESCRIPT_DLL_API
470      inline
471    //   const AbstractDomain&
472      Domain_ptr
473      getDomainPython() const
474      {
475         return getFunctionSpace().getDomainPython();
476      }
477    
478    /**    /**
479       \brief       \brief
480       Return a copy of the domain.       Return a copy of the domain.
481    */    */
482      ESCRIPT_DLL_API
483    const AbstractDomain    const AbstractDomain
484    getCopyOfDomain() const;    getCopyOfDomain() const;
485    
# Line 340  class Data { Line 487  class Data {
487       \brief       \brief
488       Return the rank of the point data.       Return the rank of the point data.
489    */    */
490      ESCRIPT_DLL_API
491    inline    inline
492    int    unsigned int
493    getDataPointRank() const    getDataPointRank() const
494    {    {
495      return m_data->getPointDataView().getRank();      return m_data->getRank();
496    }    }
497    
498    /**    /**
499       \brief       \brief
500         Return the number of data points
501      */
502      ESCRIPT_DLL_API
503      inline
504      int
505      getNumDataPoints() const
506      {
507        return getNumSamples() * getNumDataPointsPerSample();
508      }
509      /**
510         \brief
511       Return the number of samples.       Return the number of samples.
512    */    */
513      ESCRIPT_DLL_API
514    inline    inline
515    int    int
516    getNumSamples() const    getNumSamples() const
# Line 362  class Data { Line 522  class Data {
522       \brief       \brief
523       Return the number of data points per sample.       Return the number of data points per sample.
524    */    */
525      ESCRIPT_DLL_API
526    inline    inline
527    int    int
528    getNumDataPointsPerSample() const    getNumDataPointsPerSample() const
# Line 369  class Data { Line 530  class Data {
530      return m_data->getNumDPPSample();      return m_data->getNumDPPSample();
531    }    }
532    
533    
534      /**
535        \brief
536        Return the number of values in the shape for this object.
537      */
538      ESCRIPT_DLL_API
539      int
540      getNoValues() const
541      {
542        return m_data->getNoValues();
543      }
544    
545    
546      /**
547         \brief
548         dumps the object into a netCDF file
549      */
550      ESCRIPT_DLL_API
551      void
552      dump(const std::string fileName) const;
553    
554    /**    /**
555       \brief       \brief
556       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
557       preferred interface but is provided for use by C code.       preferred interface but is provided for use by C code.
558       \param sampleNo - Input - the given sample no.       \param sampleNo - Input - the given sample no.
559    */    */
560      ESCRIPT_DLL_API
561    inline    inline
562    DataAbstract::ValueType::value_type*    DataAbstract::ValueType::value_type*
563    getSampleData(DataAbstract::ValueType::size_type sampleNo)    getSampleData(DataAbstract::ValueType::size_type sampleNo);
   {  
     return m_data->getSampleData(sampleNo);  
   }  
564    
565    /**    /**
566       \brief       \brief
# Line 388  class Data { Line 568  class Data {
568       access data that isn't tagged an exception will be thrown.       access data that isn't tagged an exception will be thrown.
569       \param tag - Input - the tag key.       \param tag - Input - the tag key.
570    */    */
571      ESCRIPT_DLL_API
572    inline    inline
573    DataAbstract::ValueType::value_type*    DataAbstract::ValueType::value_type*
574    getSampleDataByTag(int tag)    getSampleDataByTag(int tag)
# Line 403  class Data { Line 584  class Data {
584       \param sampleNo - Input -       \param sampleNo - Input -
585       \param dataPointNo - Input -       \param dataPointNo - Input -
586    */    */
587      ESCRIPT_DLL_API
588      DataTypes::ValueType::const_reference
589      getDataPoint(int sampleNo, int dataPointNo) const;
590    
591    
592      ESCRIPT_DLL_API
593      DataTypes::ValueType::reference
594      getDataPoint(int sampleNo, int dataPointNo);
595    
596    
597    
598      /**
599         \brief
600         Return the offset for the given sample and point within the sample
601      */
602      ESCRIPT_DLL_API
603    inline    inline
604    DataArrayView    DataTypes::ValueType::size_type
605    getDataPoint(int sampleNo,    getDataOffset(int sampleNo,
606                 int dataPointNo)                 int dataPointNo)
607    {    {
608      return m_data->getDataPoint(sampleNo,dataPointNo);        return m_data->getPointOffset(sampleNo,dataPointNo);
609    }    }
610    
611    /**    /**
612       \brief       \brief
613       Return a reference to the data point shape.       Return a reference to the data point shape.
614    */    */
615    const DataArrayView::ShapeType&    ESCRIPT_DLL_API
616    getDataPointShape() const;    inline
617      const DataTypes::ShapeType&
618      getDataPointShape() const
619      {
620        return m_data->getShape();
621      }
622    
623    /**    /**
624       \brief       \brief
625       Return the data point shape as a tuple of integers.       Return the data point shape as a tuple of integers.
626    */    */
627    boost::python::tuple    ESCRIPT_DLL_API
628      const boost::python::tuple
629    getShapeTuple() const;    getShapeTuple() const;
630    
631    /**    /**
# Line 430  class Data { Line 633  class Data {
633       Return the size of the data point. It is the product of the       Return the size of the data point. It is the product of the
634       data point shape dimensions.       data point shape dimensions.
635    */    */
636      ESCRIPT_DLL_API
637    int    int
638    getDataPointSize() const;    getDataPointSize() const;
639    
# Line 437  class Data { Line 641  class Data {
641       \brief       \brief
642       Return the number of doubles stored for this Data.       Return the number of doubles stored for this Data.
643    */    */
644    DataArrayView::ValueType::size_type    ESCRIPT_DLL_API
645      DataTypes::ValueType::size_type
646    getLength() const;    getLength() const;
647    
648    
649    
650    /**    /**
651       \brief       \brief
652       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag assocciated with name. Implicitly converts this
653       object to type DataTagged. Throws an exception if this object       object to type DataTagged. Throws an exception if this object
654       cannot be converted to a DataTagged object.       cannot be converted to a DataTagged object or name cannot be mapped onto a tag key.
655       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
656       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
657        ==>*
658    */    */
659      ESCRIPT_DLL_API
660    void    void
661    setTaggedValue(int tagKey,    setTaggedValueByName(std::string name,
662                   const boost::python::object& value);                         const boost::python::object& value);
663    
664    /**    /**
665       \brief       \brief
666       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag. Implicitly converts this
667       object to type DataTagged. Throws an exception if this object       object to type DataTagged if it is constant.
668       cannot be converted to a DataTagged object.  
669       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
670       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
671       Note: removed for now - this version not needed, and breaks escript.cpp      ==>*
672    */    */
673    /*    ESCRIPT_DLL_API
674    void    void
675    setTaggedValue(int tagKey,    setTaggedValue(int tagKey,
676                   const DataArrayView& value);                   const boost::python::object& value);
677    
678      /**
679         \brief
680         Assign the given value to the tag. Implicitly converts this
681         object to type DataTagged if it is constant.
682    
683         \param tagKey - Input - Integer key.
684         \param pointshape - Input - The shape of the value parameter
685         \param value - Input - Value to associate with given key.
686         \param dataOffset - Input - Offset of the begining of the point within the value parameter
687    */    */
688      ESCRIPT_DLL_API
689      void
690      setTaggedValueFromCPP(int tagKey,
691                const DataTypes::ShapeType& pointshape,
692                            const DataTypes::ValueType& value,
693                int dataOffset=0);
694    
695    
696    
697    /**    /**
698      \brief      \brief
699      Copy other Data object into this Data object where mask is positive.      Copy other Data object into this Data object where mask is positive.
700    */    */
701      ESCRIPT_DLL_API
702    void    void
703    copyWithMask(const Data& other,    copyWithMask(const Data& other,
704                 const Data& mask);                 const Data& mask);
# Line 481  class Data { Line 709  class Data {
709    
710    /**    /**
711       \brief       \brief
712         set all values to zero
713         *
714      */
715      ESCRIPT_DLL_API
716      void
717      setToZero();
718    
719      /**
720         \brief
721       Interpolates this onto the given functionspace and returns       Interpolates this onto the given functionspace and returns
722       the result as a Data object.       the result as a Data object.
723         *
724    */    */
725      ESCRIPT_DLL_API
726    Data    Data
727    interpolate(const FunctionSpace& functionspace) const;    interpolate(const FunctionSpace& functionspace) const;
   
728    /**    /**
729       \brief       \brief
730       Calculates the gradient of the data at the data points of functionspace.       Calculates the gradient of the data at the data points of functionspace.
731       If functionspace is not present the function space of Function(getDomain()) is used.       If functionspace is not present the function space of Function(getDomain()) is used.
732         *
733    */    */
734      ESCRIPT_DLL_API
735    Data    Data
736    gradOn(const FunctionSpace& functionspace) const;    gradOn(const FunctionSpace& functionspace) const;
737    
738      ESCRIPT_DLL_API
739    Data    Data
740    grad() const;    grad() const;
741    
742    /**    /**
743       \brief       \brief
744       Calculate the integral over the function space domain.       Calculate the integral over the function space domain.
745         *
746    */    */
747      ESCRIPT_DLL_API
748      boost::python::numeric::array
749      integrate_const() const;
750    
751      ESCRIPT_DLL_API
752    boost::python::numeric::array    boost::python::numeric::array
753    integrate() const;    integrate();
754    
755    /**    /**
756       \brief       \brief
757         Returns 1./ Data object
758         *
759      */
760      ESCRIPT_DLL_API
761      Data
762      oneOver() const;
763      /**
764         \brief
765       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.
766         *
767    */    */
768      ESCRIPT_DLL_API
769    Data    Data
770    wherePositive() const;    wherePositive() const;
771    
772    /**    /**
773       \brief       \brief
774       Return a Data with a 1 for -ive values and a 0 for +ive or 0 values.       Return a Data with a 1 for -ive values and a 0 for +ive or 0 values.
775         *
776    */    */
777      ESCRIPT_DLL_API
778    Data    Data
779    whereNegative() const;    whereNegative() const;
780    
781    /**    /**
782       \brief       \brief
783       Return a Data with a 1 for +ive or 0 values and a 0 for -ive values.       Return a Data with a 1 for +ive or 0 values and a 0 for -ive values.
784         *
785    */    */
786      ESCRIPT_DLL_API
787    Data    Data
788    whereNonNegative() const;    whereNonNegative() const;
789    
790    /**    /**
791       \brief       \brief
792       Return a Data with a 1 for -ive or 0 values and a 0 for +ive values.       Return a Data with a 1 for -ive or 0 values and a 0 for +ive values.
793         *
794    */    */
795      ESCRIPT_DLL_API
796    Data    Data
797    whereNonPositive() const;    whereNonPositive() const;
798    
799    /**    /**
800       \brief       \brief
801       Return a Data with a 1 for 0 values and a 0 for +ive or -ive values.       Return a Data with a 1 for 0 values and a 0 for +ive or -ive values.
802         *
803    */    */
804      ESCRIPT_DLL_API
805    Data    Data
806    whereZero() const;    whereZero(double tol=0.0) const;
807    
808    /**    /**
809       \brief       \brief
810       Return a Data with a 0 for 0 values and a 1 for +ive or -ive values.       Return a Data with a 0 for 0 values and a 1 for +ive or -ive values.
811         *
812    */    */
813      ESCRIPT_DLL_API
814    Data    Data
815    whereNonZero() const;    whereNonZero(double tol=0.0) const;
816    
817      /**
818         \brief
819         Return the maximum absolute value of this Data object.
820    
821         The method is not const because lazy data needs to be expanded before Lsup can be computed.
822         The _const form can be used when the Data object is const, however this will only work for
823         Data which is not Lazy.
824    
825         For Data which contain no samples (or tagged Data for which no tags in use have a value)
826         zero is returned.
827      */
828      ESCRIPT_DLL_API
829      double
830      Lsup();
831    
832      ESCRIPT_DLL_API
833      double
834      Lsup_const() const;
835    
836    
837      /**
838         \brief
839         Return the maximum value of this Data object.
840    
841         The method is not const because lazy data needs to be expanded before sup can be computed.
842         The _const form can be used when the Data object is const, however this will only work for
843         Data which is not Lazy.
844    
845         For Data which contain no samples (or tagged Data for which no tags in use have a value)
846         a large negative value is returned.
847      */
848      ESCRIPT_DLL_API
849      double
850      sup();
851    
852      ESCRIPT_DLL_API
853      double
854      sup_const() const;
855    
856    
857      /**
858         \brief
859         Return the minimum value of this Data object.
860    
861         The method is not const because lazy data needs to be expanded before inf can be computed.
862         The _const form can be used when the Data object is const, however this will only work for
863         Data which is not Lazy.
864    
865         For Data which contain no samples (or tagged Data for which no tags in use have a value)
866         a large positive value is returned.
867      */
868      ESCRIPT_DLL_API
869      double
870      inf();
871    
872      ESCRIPT_DLL_API
873      double
874      inf_const() const;
875    
876    
877    
878      /**
879         \brief
880         Return the absolute value of each data point of this Data object.
881         *
882      */
883      ESCRIPT_DLL_API
884      Data
885      abs() const;
886    
887      /**
888         \brief
889         Return the maximum value of each data point of this Data object.
890         *
891      */
892      ESCRIPT_DLL_API
893      Data
894      maxval() const;
895    
896      /**
897         \brief
898         Return the minimum value of each data point of this Data object.
899         *
900      */
901      ESCRIPT_DLL_API
902      Data
903      minval() const;
904    
905      /**
906         \brief
907         Return the (sample number, data-point number) of the data point with
908         the minimum value in this Data object.
909      */
910      ESCRIPT_DLL_API
911      const boost::python::tuple
912      minGlobalDataPoint() const;
913    
914      ESCRIPT_DLL_API
915      void
916      calc_minGlobalDataPoint(int& ProcNo,  int& DataPointNo) const;
917      /**
918         \brief
919         Return the sign of each data point of this Data object.
920         -1 for negative values, zero for zero values, 1 for positive values.
921         *
922      */
923      ESCRIPT_DLL_API
924      Data
925      sign() const;
926    
927      /**
928         \brief
929         Return the symmetric part of a matrix which is half the matrix plus its transpose.
930         *
931      */
932      ESCRIPT_DLL_API
933      Data
934      symmetric() const;
935    
936      /**
937         \brief
938         Return the nonsymmetric part of a matrix which is half the matrix minus its transpose.
939         *
940      */
941      ESCRIPT_DLL_API
942      Data
943      nonsymmetric() const;
944    
945      /**
946         \brief
947         Return the trace of a matrix
948         *
949      */
950      ESCRIPT_DLL_API
951      Data
952      trace(int axis_offset) const;
953    
954      /**
955         \brief
956         Transpose each data point of this Data object around the given axis.
957         *
958      */
959      ESCRIPT_DLL_API
960      Data
961      transpose(int axis_offset) const;
962    
963      /**
964         \brief
965         Return the eigenvalues of the symmetric part at each data point of this Data object in increasing values.
966         Currently this function is restricted to rank 2, square shape, and dimension 3.
967         *
968      */
969      ESCRIPT_DLL_API
970      Data
971      eigenvalues() const;
972    
973      /**
974         \brief
975         Return the eigenvalues and corresponding eigenvcetors of the symmetric part at each data point of this Data object.
976         the eigenvalues are ordered in increasing size where eigenvalues with relative difference less than
977         tol are treated as equal. The eigenvectors are orthogonal, normalized and the sclaed such that the
978         first non-zero entry is positive.
979         Currently this function is restricted to rank 2, square shape, and dimension 3
980         *
981      */
982      ESCRIPT_DLL_API
983      const boost::python::tuple
984      eigenvalues_and_eigenvectors(const double tol=1.e-12) const;
985    
986      /**
987         \brief
988         swaps the components axis0 and axis1
989         *
990      */
991      ESCRIPT_DLL_API
992      Data
993      swapaxes(const int axis0, const int axis1) const;
994    
995      /**
996         \brief
997         Return the error function erf of each data point of this Data object.
998         *
999      */
1000      ESCRIPT_DLL_API
1001      Data
1002      erf() const;
1003    
1004    /**    /**
1005       \brief       \brief
1006       Return the sin of each data point of this Data object.       Return the sin of each data point of this Data object.
1007         *
1008    */    */
1009      ESCRIPT_DLL_API
1010    Data    Data
1011    sin() const;    sin() const;
1012    
1013    /**    /**
1014       \brief       \brief
1015       Return the cos of each data point of this Data object.       Return the cos of each data point of this Data object.
1016         *
1017    */    */
1018      ESCRIPT_DLL_API
1019    Data    Data
1020    cos() const;    cos() const;
1021    
1022    /**    /**
1023       \brief       \brief
1024       Return the tan of each data point of this Data object.       Return the tan of each data point of this Data object.
1025         *
1026    */    */
1027      ESCRIPT_DLL_API
1028    Data    Data
1029    tan() const;    tan() const;
1030    
1031    /**    /**
1032       \brief       \brief
1033       Return the log to base 10 of each data point of this Data object.       Return the asin of each data point of this Data object.
1034         *
1035    */    */
1036      ESCRIPT_DLL_API
1037    Data    Data
1038    log() const;    asin() const;
1039    
1040    /**    /**
1041       \brief       \brief
1042       Return the natural log of each data point of this Data object.       Return the acos of each data point of this Data object.
1043         *
1044    */    */
1045      ESCRIPT_DLL_API
1046    Data    Data
1047    ln() const;    acos() const;
1048    
1049    /**    /**
1050       \brief       \brief
1051       Return the maximum absolute value of this Data object.       Return the atan of each data point of this Data object.
1052         *
1053    */    */
1054    double    ESCRIPT_DLL_API
1055    Lsup() const;    Data
1056      atan() const;
1057    
1058    /**    /**
1059       \brief       \brief
1060       Return the maximum value of this Data object.       Return the sinh of each data point of this Data object.
1061         *
1062    */    */
1063    double    ESCRIPT_DLL_API
1064    sup() const;    Data
1065      sinh() const;
1066    
1067    /**    /**
1068       \brief       \brief
1069       Return the minimum value of this Data object.       Return the cosh of each data point of this Data object.
1070         *
1071    */    */
1072    double    ESCRIPT_DLL_API
1073    inf() const;    Data
1074      cosh() const;
1075    
1076    /**    /**
1077       \brief       \brief
1078       Return the absolute value of each data point of this Data object.       Return the tanh of each data point of this Data object.
1079         *
1080    */    */
1081      ESCRIPT_DLL_API
1082    Data    Data
1083    abs() const;    tanh() const;
1084    
1085    /**    /**
1086       \brief       \brief
1087       Return the maximum value of each data point of this Data object.       Return the asinh of each data point of this Data object.
1088         *
1089    */    */
1090      ESCRIPT_DLL_API
1091    Data    Data
1092    maxval() const;    asinh() const;
1093    
1094    /**    /**
1095       \brief       \brief
1096       Return the minimum value of each data point of this Data object.       Return the acosh of each data point of this Data object.
1097         *
1098    */    */
1099      ESCRIPT_DLL_API
1100    Data    Data
1101    minval() const;    acosh() const;
1102    
1103    /**    /**
1104       \brief       \brief
1105       Return the length of each data point of this Data object.       Return the atanh of each data point of this Data object.
1106       sqrt(sum(A[i,j,k,l]^2))       *
1107    */    */
1108      ESCRIPT_DLL_API
1109    Data    Data
1110    length() const;    atanh() const;
1111    
1112    /**    /**
1113       \brief       \brief
1114       Return the sign of each data point of this Data object.       Return the log to base 10 of each data point of this Data object.
1115       -1 for negative values, zero for zero values, 1 for positive values.       *
1116    */    */
1117      ESCRIPT_DLL_API
1118    Data    Data
1119    sign() const;    log10() const;
1120    
1121    /**    /**
1122      \transpose       \brief
1123      Transpose each data point of this Data object around the given axis.       Return the natural log of each data point of this Data object.
1124         *
1125    */    */
1126      ESCRIPT_DLL_API
1127    Data    Data
1128    transpose(int axis) const;    log() const;
1129    
1130    /**    /**
1131      \trace       \brief
1132      Calculate the trace of each data point of this Data object.       Return the exponential function of each data point of this Data object.
1133      sum(A[i,i,i,i])       *
1134    */    */
1135      ESCRIPT_DLL_API
1136    Data    Data
1137    trace() const;    exp() const;
1138    
1139    /**    /**
1140      \exp       \brief
1141      Return the exponential function of each data point of this Data object.       Return the square root of each data point of this Data object.
1142         *
1143    */    */
1144      ESCRIPT_DLL_API
1145    Data    Data
1146    exp() const;    sqrt() const;
1147    
1148    /**    /**
1149      \sqrt       \brief
1150      Return the square root of each data point of this Data object.       Return the negation of each data point of this Data object.
1151         *
1152    */    */
1153      ESCRIPT_DLL_API
1154    Data    Data
1155    sqrt() const;    neg() const;
1156    
1157      /**
1158         \brief
1159         Return the identity of each data point of this Data object.
1160         Simply returns this object unmodified.
1161         *
1162      */
1163      ESCRIPT_DLL_API
1164      Data
1165      pos() const;
1166    
1167    /**    /**
1168       \brief       \brief
1169       Return the given power of each data point of this Data object.       Return the given power of each data point of this Data object.
1170    
1171         \param right Input - the power to raise the object to.
1172         *
1173    */    */
1174      ESCRIPT_DLL_API
1175    Data    Data
1176    powD(const Data& right) const;    powD(const Data& right) const;
1177    
1178      /**
1179         \brief
1180         Return the given power of each data point of this boost python object.
1181    
1182         \param right Input - the power to raise the object to.
1183         *
1184       */
1185      ESCRIPT_DLL_API
1186    Data    Data
1187    powO(const boost::python::object& right) const;    powO(const boost::python::object& right) const;
1188    
1189    /**    /**
1190      \brief       \brief
1191      Return the negation of each data point of this Data object.       Return the given power of each data point of this boost python object.
1192    */  
1193         \param left Input - the bases
1194         *
1195       */
1196    
1197      ESCRIPT_DLL_API
1198    Data    Data
1199    neg() const;    rpowO(const boost::python::object& left) const;
1200    
1201    /**    /**
1202      \brief       \brief
1203      Return the identity of each data point of this Data object.       writes the object to a file in the DX file format
     Simply returns this object unmodified.  
1204    */    */
1205    Data    ESCRIPT_DLL_API
1206    pos() const;    void
1207      saveDX(std::string fileName) const;
1208    
1209      /**
1210         \brief
1211         writes the object to a file in the VTK file format
1212      */
1213      ESCRIPT_DLL_API
1214      void
1215      saveVTK(std::string fileName) const;
1216    
1217    /**    /**
1218       \brief       \brief
1219       Overloaded operator +=       Overloaded operator +=
1220       \param right - Input - The right hand side.       \param right - Input - The right hand side.
1221         *
1222    */    */
1223      ESCRIPT_DLL_API
1224    Data& operator+=(const Data& right);    Data& operator+=(const Data& right);
1225      ESCRIPT_DLL_API
1226    Data& operator+=(const boost::python::object& right);    Data& operator+=(const boost::python::object& right);
1227    
1228      ESCRIPT_DLL_API
1229      Data& operator=(const Data& other);
1230    
1231    /**    /**
1232       \brief       \brief
1233       Overloaded operator -=       Overloaded operator -=
1234       \param right - Input - The right hand side.       \param right - Input - The right hand side.
1235         *
1236    */    */
1237      ESCRIPT_DLL_API
1238    Data& operator-=(const Data& right);    Data& operator-=(const Data& right);
1239      ESCRIPT_DLL_API
1240    Data& operator-=(const boost::python::object& right);    Data& operator-=(const boost::python::object& right);
1241    
1242   /**   /**
1243       \brief       \brief
1244       Overloaded operator *=       Overloaded operator *=
1245       \param right - Input - The right hand side.       \param right - Input - The right hand side.
1246         *
1247    */    */
1248      ESCRIPT_DLL_API
1249    Data& operator*=(const Data& right);    Data& operator*=(const Data& right);
1250      ESCRIPT_DLL_API
1251    Data& operator*=(const boost::python::object& right);    Data& operator*=(const boost::python::object& right);
1252    
1253   /**   /**
1254       \brief       \brief
1255       Overloaded operator /=       Overloaded operator /=
1256       \param right - Input - The right hand side.       \param right - Input - The right hand side.
1257         *
1258    */    */
1259      ESCRIPT_DLL_API
1260    Data& operator/=(const Data& right);    Data& operator/=(const Data& right);
1261      ESCRIPT_DLL_API
1262    Data& operator/=(const boost::python::object& right);    Data& operator/=(const boost::python::object& right);
1263    
1264    /**    /**
1265       \brief       \brief
1266       Returns true if this can be interpolated to functionspace.       Returns true if this can be interpolated to functionspace.
1267    */    */
1268      ESCRIPT_DLL_API
1269    bool    bool
1270    probeInterpolation(const FunctionSpace& functionspace) const;    probeInterpolation(const FunctionSpace& functionspace) const;
1271    
# Line 748  class Data { Line 1284  class Data {
1284       \param key - Input - python slice tuple specifying       \param key - Input - python slice tuple specifying
1285       slice to return.       slice to return.
1286    */    */
1287      ESCRIPT_DLL_API
1288    Data    Data
1289    getItem(const boost::python::object& key) const;    getItem(const boost::python::object& key) const;
1290    
# Line 755  class Data { Line 1292  class Data {
1292       \brief       \brief
1293       Copies slice from value into this Data object.       Copies slice from value into this Data object.
1294    
      \description  
1295       Implements the [] set operator in python.       Implements the [] set operator in python.
1296       Calls setSlice.       Calls setSlice.
1297    
# Line 763  class Data { Line 1299  class Data {
1299       slice to copy from value.       slice to copy from value.
1300       \param value - Input - Data object to copy from.       \param value - Input - Data object to copy from.
1301    */    */
1302      ESCRIPT_DLL_API
1303    void    void
1304    setItemD(const boost::python::object& key,    setItemD(const boost::python::object& key,
1305             const Data& value);             const Data& value);
1306    
1307      ESCRIPT_DLL_API
1308    void    void
1309    setItemO(const boost::python::object& key,    setItemO(const boost::python::object& key,
1310             const boost::python::object& value);             const boost::python::object& value);
# Line 779  class Data { Line 1317  class Data {
1317       this Data object.       this Data object.
1318    */    */
1319    template <class UnaryFunction>    template <class UnaryFunction>
1320      ESCRIPT_DLL_API
1321    inline    inline
1322    void    void
1323    unaryOp(UnaryFunction operation);    unaryOp2(UnaryFunction operation);
1324    
1325    /**    /**
1326       \brief       \brief
1327       Return a Data object containing the specified slice of       Return a Data object containing the specified slice of
1328       this Data object.       this Data object.
1329       \param region - Input - Region to copy.       \param region - Input - Region to copy.
1330         *
1331    */    */
1332      ESCRIPT_DLL_API
1333    Data    Data
1334    getSlice(const DataArrayView::RegionType& region) const;    getSlice(const DataTypes::RegionType& region) const;
1335    
1336    /**    /**
1337       \brief       \brief
# Line 798  class Data { Line 1339  class Data {
1339       Data object.       Data object.
1340       \param value - Input - Data to copy from.       \param value - Input - Data to copy from.
1341       \param region - Input - Region to copy.       \param region - Input - Region to copy.
1342         *
1343    */    */
1344      ESCRIPT_DLL_API
1345    void    void
1346    setSlice(const Data& value,    setSlice(const Data& value,
1347             const DataArrayView::RegionType& region);             const DataTypes::RegionType& region);
1348    
1349      /**
1350         \brief
1351         print the data values to stdout. Used for debugging
1352      */
1353      ESCRIPT_DLL_API
1354      void
1355            print(void);
1356    
1357      /**
1358         \brief
1359         return the MPI rank number of the local data
1360                     MPI_COMM_WORLD is assumed and the result of MPI_Comm_size()
1361                     is returned
1362      */
1363      ESCRIPT_DLL_API
1364            int
1365            get_MPIRank(void) const;
1366    
1367      /**
1368         \brief
1369         return the MPI rank number of the local data
1370                     MPI_COMM_WORLD is assumed and the result of MPI_Comm_rank()
1371                     is returned
1372      */
1373      ESCRIPT_DLL_API
1374            int
1375            get_MPISize(void) const;
1376    
1377      /**
1378         \brief
1379         return the MPI rank number of the local data
1380                     MPI_COMM_WORLD is assumed and returned.
1381      */
1382      ESCRIPT_DLL_API
1383            MPI_Comm
1384            get_MPIComm(void) const;
1385    
1386      /**
1387         \brief
1388         return the object produced by the factory, which is a DataConstant or DataExpanded
1389        TODO Ownership of this object should be explained in doco.
1390      */
1391      ESCRIPT_DLL_API
1392            DataAbstract*
1393            borrowData(void) const;
1394    
1395      ESCRIPT_DLL_API
1396            DataAbstract_ptr
1397            borrowDataPtr(void) const;
1398    
1399      ESCRIPT_DLL_API
1400            DataReady_ptr
1401            borrowReadyPtr(void) const;
1402    
1403    
1404    
1405      /**
1406         \brief
1407         Return a pointer to the beginning of the datapoint at the specified offset.
1408         TODO Eventually these should be inlined.
1409         \param i - position(offset) in the underlying datastructure
1410      */
1411      ESCRIPT_DLL_API
1412            DataTypes::ValueType::const_reference
1413            getDataAtOffset(DataTypes::ValueType::size_type i) const;
1414    
1415    
1416      ESCRIPT_DLL_API
1417            DataTypes::ValueType::reference
1418            getDataAtOffset(DataTypes::ValueType::size_type i);
1419    
1420   protected:   protected:
1421    
1422   private:   private:
1423    
1424      double
1425      LsupWorker() const;
1426    
1427      double
1428      supWorker() const;
1429    
1430      double
1431      infWorker() const;
1432    
1433      boost::python::numeric::array
1434      integrateWorker() const;
1435    
1436    /**    /**
1437       \brief       \brief
1438       Check *this and the right operand are compatible. Throws       Check *this and the right operand are compatible. Throws
# Line 823  class Data { Line 1449  class Data {
1449    /**    /**
1450       \brief       \brief
1451       Perform the specified reduction algorithm on every element of every data point in       Perform the specified reduction algorithm on every element of every data point in
1452       this Data object and return the single double value result.       this Data object according to the given function and return the single value result.
1453    */    */
1454    template <class UnaryFunction>    template <class BinaryFunction>
1455    inline    inline
1456    double    double
1457    algorithm(UnaryFunction operation) const;    algorithm(BinaryFunction operation,
1458                double initial_value) const;
1459    
1460    /**    /**
1461       \brief       \brief
1462       Perform the given binary operation on all of the data's elements.       Reduce each data-point in this Data object using the given operation. Return a Data
1463       The underlying type of the right hand side (right) determines the final       object with the same number of data-points, but with each data-point containing only
1464       type of *this after the operation. For example if the right hand side       one value - the result of the reduction operation on the corresponding data-point in
1465       is expanded *this will be expanded if necessary.       this Data object
      RHS is a Data object.  
1466    */    */
1467    template <class BinaryFunction>    template <class BinaryFunction>
1468    inline    inline
1469    void    Data
1470    binaryOp(const Data& right,    dp_algorithm(BinaryFunction operation,
1471             BinaryFunction operation);                 double initial_value) const;
1472    
1473    /**    /**
1474       \brief       \brief
1475       Perform the given binary operation on all of the data's elements.       Perform the given binary operation on all of the data's elements.
1476       RHS is a boost::python object.       The underlying type of the right hand side (right) determines the final
1477         type of *this after the operation. For example if the right hand side
1478         is expanded *this will be expanded if necessary.
1479         RHS is a Data object.
1480    */    */
1481    template <class BinaryFunction>    template <class BinaryFunction>
1482    inline    inline
1483    void    void
1484    binaryOp(const boost::python::object& right,    binaryOp(const Data& right,
1485             BinaryFunction operation);             BinaryFunction operation);
1486    
1487    /**    /**
# Line 875  class Data { Line 1504  class Data {
1504       \brief       \brief
1505       Construct a Data object of the appropriate type.       Construct a Data object of the appropriate type.
1506    */    */
1507    template <class IValueType>  
1508    void    void
1509    initialise(const IValueType& value,    initialise(const DataTypes::ValueType& value,
1510             const DataTypes::ShapeType& shape,
1511               const FunctionSpace& what,               const FunctionSpace& what,
1512               bool expanded);               bool expanded);
1513    
   /**  
      \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.  
   */  
1514    void    void
1515    reshapeDataPoint(const DataArrayView::ShapeType& shape);    initialise(const boost::python::numeric::array& value,
1516                     const FunctionSpace& what,
1517                     bool expanded);
1518    
1519      //
1520      // flag to protect the data object against any update
1521      bool m_protected;
1522    
1523    //    //
1524    // pointer to the actual data object    // pointer to the actual data object
1525    boost::shared_ptr<DataAbstract> m_data;  //   boost::shared_ptr<DataAbstract> m_data;
1526      DataAbstract_ptr m_data;
1527    
1528    // If possible please use getReadyPtr instead
1529      const DataReady*
1530      getReady() const;
1531    
1532      DataReady*
1533      getReady();
1534    
1535      DataReady_ptr
1536      getReadyPtr();
1537    
1538      const_DataReady_ptr
1539      getReadyPtr() const;
1540    
1541    
1542  };  };
1543    
1544  template <class IValueType>  }   // end namespace escript
1545  void  
1546  Data::initialise(const IValueType& value,  
1547                   const FunctionSpace& what,  // No, this is not supposed to be at the top of the file
1548                   bool expanded)  // DataAbstact needs to be declared first, then DataReady needs to be fully declared
1549    // so that I can dynamic cast between them below.
1550    #include "DataReady.h"
1551    
1552    namespace escript
1553  {  {
1554    //  
1555    // Construct a Data object of the appropriate type.  inline
1556    // Construct the object first as there seems to be a bug which causes  const DataReady*
1557    // undefined behaviour if an exception is thrown during construction  Data::getReady() const
1558    // within the shared_ptr constructor.  {
1559    if (expanded) {     const DataReady* dr=dynamic_cast<const DataReady*>(m_data.get());
1560      DataAbstract* temp=new DataExpanded(value,what);     EsysAssert((dr!=0), "Error - casting to DataReady.");
1561      boost::shared_ptr<DataAbstract> temp_data(temp);     return dr;
1562      m_data=temp_data;  }
1563    } else {  
1564      DataAbstract* temp=new DataConstant(value,what);  inline
1565      boost::shared_ptr<DataAbstract> temp_data(temp);  DataReady*
1566      m_data=temp_data;  Data::getReady()
1567    }  {
1568       DataReady* dr=dynamic_cast<DataReady*>(m_data.get());
1569       EsysAssert((dr!=0), "Error - casting to DataReady.");
1570       return dr;
1571    }
1572    
1573    inline
1574    DataReady_ptr
1575    Data::getReadyPtr()
1576    {
1577       DataReady_ptr dr=boost::dynamic_pointer_cast<DataReady>(m_data);
1578       EsysAssert((dr.get()!=0), "Error - casting to DataReady.");
1579       return dr;
1580  }  }
1581    
1582    
1583    inline
1584    const_DataReady_ptr
1585    Data::getReadyPtr() const
1586    {
1587       const_DataReady_ptr dr=boost::dynamic_pointer_cast<const DataReady>(m_data);
1588       EsysAssert((dr.get()!=0), "Error - casting to DataReady.");
1589       return dr;
1590    }
1591    
1592    inline
1593    DataAbstract::ValueType::value_type*
1594    Data::getSampleData(DataAbstract::ValueType::size_type sampleNo)
1595    {
1596       if (isLazy())
1597       {
1598        resolve();
1599       }
1600       return getReady()->getSampleData(sampleNo);
1601    }
1602    
1603    
1604    /**
1605       Modify a filename for MPI parallel output to multiple files
1606    */
1607    char *Escript_MPI_appendRankToFileName(const char *, int, int);
1608    
1609  /**  /**
1610     Binary Data object operators.     Binary Data object operators.
1611  */  */
1612    inline double rpow(double x,double y)
1613    {
1614        return pow(y,x);
1615    }
1616    
1617  /**  /**
1618    \brief    \brief
1619    Operator+    Operator+
1620    Takes two Data objects.    Takes two Data objects.
1621  */  */
1622  Data operator+(const Data& left, const Data& right);  ESCRIPT_DLL_API Data operator+(const Data& left, const Data& right);
1623    
1624  /**  /**
1625    \brief    \brief
1626    Operator-    Operator-
1627    Takes two Data objects.    Takes two Data objects.
1628  */  */
1629  Data operator-(const Data& left, const Data& right);  ESCRIPT_DLL_API Data operator-(const Data& left, const Data& right);
1630    
1631  /**  /**
1632    \brief    \brief
1633    Operator*    Operator*
1634    Takes two Data objects.    Takes two Data objects.
1635  */  */
1636  Data operator*(const Data& left, const Data& right);  ESCRIPT_DLL_API Data operator*(const Data& left, const Data& right);
1637    
1638  /**  /**
1639    \brief    \brief
1640    Operator/    Operator/
1641    Takes two Data objects.    Takes two Data objects.
1642  */  */
1643  Data operator/(const Data& left, const Data& right);  ESCRIPT_DLL_API Data operator/(const Data& left, const Data& right);
1644    
1645  /**  /**
1646    \brief    \brief
# Line 957  Data operator/(const Data& left, const D Line 1648  Data operator/(const Data& left, const D
1648    Takes LHS Data object and RHS python::object.    Takes LHS Data object and RHS python::object.
1649    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1650  */  */
1651  Data operator+(const Data& left, const boost::python::object& right);  ESCRIPT_DLL_API Data operator+(const Data& left, const boost::python::object& right);
1652    
1653  /**  /**
1654    \brief    \brief
# Line 965  Data operator+(const Data& left, const b Line 1656  Data operator+(const Data& left, const b
1656    Takes LHS Data object and RHS python::object.    Takes LHS Data object and RHS python::object.
1657    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1658  */  */
1659  Data operator-(const Data& left, const boost::python::object& right);  ESCRIPT_DLL_API Data operator-(const Data& left, const boost::python::object& right);
1660    
1661  /**  /**
1662    \brief    \brief
# Line 973  Data operator-(const Data& left, const b Line 1664  Data operator-(const Data& left, const b
1664    Takes LHS Data object and RHS python::object.    Takes LHS Data object and RHS python::object.
1665    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1666  */  */
1667  Data operator*(const Data& left, const boost::python::object& right);  ESCRIPT_DLL_API Data operator*(const Data& left, const boost::python::object& right);
1668    
1669  /**  /**
1670    \brief    \brief
# Line 981  Data operator*(const Data& left, const b Line 1672  Data operator*(const Data& left, const b
1672    Takes LHS Data object and RHS python::object.    Takes LHS Data object and RHS python::object.
1673    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1674  */  */
1675  Data operator/(const Data& left, const boost::python::object& right);  ESCRIPT_DLL_API Data operator/(const Data& left, const boost::python::object& right);
1676    
1677  /**  /**
1678    \brief    \brief
# Line 989  Data operator/(const Data& left, const b Line 1680  Data operator/(const Data& left, const b
1680    Takes LHS python::object and RHS Data object.    Takes LHS python::object and RHS Data object.
1681    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1682  */  */
1683  Data operator+(const boost::python::object& left, const Data& right);  ESCRIPT_DLL_API Data operator+(const boost::python::object& left, const Data& right);
1684    
1685  /**  /**
1686    \brief    \brief
# Line 997  Data operator+(const boost::python::obje Line 1688  Data operator+(const boost::python::obje
1688    Takes LHS python::object and RHS Data object.    Takes LHS python::object and RHS Data object.
1689    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1690  */  */
1691  Data operator-(const boost::python::object& left, const Data& right);  ESCRIPT_DLL_API Data operator-(const boost::python::object& left, const Data& right);
1692    
1693  /**  /**
1694    \brief    \brief
# Line 1005  Data operator-(const boost::python::obje Line 1696  Data operator-(const boost::python::obje
1696    Takes LHS python::object and RHS Data object.    Takes LHS python::object and RHS Data object.
1697    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1698  */  */
1699  Data operator*(const boost::python::object& left, const Data& right);  ESCRIPT_DLL_API Data operator*(const boost::python::object& left, const Data& right);
1700    
1701  /**  /**
1702    \brief    \brief
# Line 1013  Data operator*(const boost::python::obje Line 1704  Data operator*(const boost::python::obje
1704    Takes LHS python::object and RHS Data object.    Takes LHS python::object and RHS Data object.
1705    python::object must be convertable to Data type.    python::object must be convertable to Data type.
1706  */  */
1707  Data operator/(const boost::python::object& left, const Data& right);  ESCRIPT_DLL_API Data operator/(const boost::python::object& left, const Data& right);
1708    
1709    
1710    
1711  /**  /**
1712    \brief    \brief
1713    Output operator    Output operator
1714  */  */
1715  std::ostream& operator<<(std::ostream& o, const Data& data);  ESCRIPT_DLL_API std::ostream& operator<<(std::ostream& o, const Data& data);
1716    
1717  /**  /**
1718    \brief    \brief
1719    Return true if operands are equivalent, else return false.    Compute a tensor product of two Data objects
1720    NB: this operator does very little at this point, and isn't to    \param arg0 - Input - Data object
1721    be relied on. Requires further implementation.    \param arg1 - Input - Data object
1722      \param axis_offset - Input - axis offset
1723      \param transpose - Input - 0: transpose neither, 1: transpose arg0, 2: transpose arg1
1724  */  */
1725  //bool operator==(const Data& left, const Data& right);  ESCRIPT_DLL_API
1726    Data
1727    C_GeneralTensorProduct(Data& arg0,
1728                         Data& arg1,
1729                         int axis_offset=0,
1730                         int transpose=0);
1731    
1732  /**  /**
1733    \brief    \brief
# Line 1042  Data::binaryOp(const Data& right, Line 1742  Data::binaryOp(const Data& right,
1742  {  {
1743     //     //
1744     // 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
1745     if (getPointDataView().getRank()==0 && right.getPointDataView().getRank()!=0) {     if (getDataPointRank()==0 && right.getDataPointRank()!=0) {
1746       reshapeDataPoint(right.getPointDataView().getShape());       throw DataException("Error - attempt to update rank zero object with object with rank bigger than zero.");
1747       }
1748    
1749       if (isLazy() || right.isLazy())
1750       {
1751         throw DataException("Programmer error - attempt to call binaryOp with Lazy Data.");
1752     }     }
1753     //     //
1754     // initially make the temporary a shallow copy     // initially make the temporary a shallow copy
1755     Data tempRight(right);     Data tempRight(right);
1756    
1757     if (getFunctionSpace()!=right.getFunctionSpace()) {     if (getFunctionSpace()!=right.getFunctionSpace()) {
1758       if (right.probeInterpolation(getFunctionSpace())) {       if (right.probeInterpolation(getFunctionSpace())) {
1759         //         //
1760         // an interpolation is required so create a new Data         // an interpolation is required so create a new Data
1761         tempRight=Data(right,this->getFunctionSpace());         tempRight=Data(right,this->getFunctionSpace());
1762       } else if (probeInterpolation(right.getFunctionSpace())) {       } else if (probeInterpolation(right.getFunctionSpace())) {
1763         //         //
# Line 1073  Data::binaryOp(const Data& right, Line 1779  Data::binaryOp(const Data& right,
1779       // of any data type       // of any data type
1780       DataExpanded* leftC=dynamic_cast<DataExpanded*>(m_data.get());       DataExpanded* leftC=dynamic_cast<DataExpanded*>(m_data.get());
1781       EsysAssert((leftC!=0), "Programming error - casting to DataExpanded.");       EsysAssert((leftC!=0), "Programming error - casting to DataExpanded.");
1782       escript::binaryOp(*leftC,*(tempRight.m_data.get()),operation);       escript::binaryOp(*leftC,*(tempRight.getReady()),operation);
1783     } else if (isTagged()) {     } else if (isTagged()) {
1784       //       //
1785       // Tagged data is operated on serially, the right hand side can be       // Tagged data is operated on serially, the right hand side can be
# Line 1099  Data::binaryOp(const Data& right, Line 1805  Data::binaryOp(const Data& right,
1805    
1806  /**  /**
1807    \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  
1808    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.
1809    Given operation combines each element of each data point, thus argument    Given operation combines each element of each data point, thus argument
1810    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.
1811    Calls escript::algorithm.    Calls escript::algorithm.
1812  */  */
1813  template <class UnaryFunction>  template <class BinaryFunction>
1814  inline  inline
1815  double  double
1816  Data::algorithm(UnaryFunction operation) const  Data::algorithm(BinaryFunction operation, double initial_value) const
1817  {  {
1818    if (isExpanded()) {    if (isExpanded()) {
1819      DataExpanded* leftC=dynamic_cast<DataExpanded*>(m_data.get());      DataExpanded* leftC=dynamic_cast<DataExpanded*>(m_data.get());
1820      EsysAssert((leftC!=0), "Programming error - casting to DataExpanded.");      EsysAssert((leftC!=0), "Programming error - casting to DataExpanded.");
1821      return escript::algorithm(*leftC,operation);      return escript::algorithm(*leftC,operation,initial_value);
1822    } else if (isTagged()) {    } else if (isTagged()) {
1823      DataTagged* leftC=dynamic_cast<DataTagged*>(m_data.get());      DataTagged* leftC=dynamic_cast<DataTagged*>(m_data.get());
1824      EsysAssert((leftC!=0), "Programming error - casting to DataTagged.");      EsysAssert((leftC!=0), "Programming error - casting to DataTagged.");
1825      return escript::algorithm(*leftC,operation);      return escript::algorithm(*leftC,operation,initial_value);
1826    } else if (isConstant()) {    } else if (isConstant()) {
1827      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());
1828      EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");      EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");
1829      return escript::algorithm(*leftC,operation);      return escript::algorithm(*leftC,operation,initial_value);
1830      } else if (isEmpty()) {
1831        throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1832      } else if (isLazy()) {
1833        throw DataException("Error - Operations not permitted on instances of DataLazy.");
1834      } else {
1835        throw DataException("Error - Data encapsulates an unknown type.");
1836    }    }
   return 0;  
1837  }  }
1838    
1839  /**  /**
1840    \brief    \brief
1841    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.
1842    Given operation combines each element within each data point into a scalar,    Given operation combines each element within each data point into a scalar,
1843    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
1844    rank 0 Data object.    rank 0 Data object.
1845    Calls escript::dp_algorithm.    Calls escript::dp_algorithm.
1846  */  */
1847  template <class UnaryFunction>  template <class BinaryFunction>
1848  inline  inline
1849  Data  Data
1850  dp_algorithm(const Data& data,  Data::dp_algorithm(BinaryFunction operation, double initial_value) const
              UnaryFunction operation)  
1851  {  {
1852    Data result(0,DataArrayView::ShapeType(),data.getFunctionSpace(),data.isExpanded());    if (isEmpty()) {
1853    if (data.isExpanded()) {      throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1854      DataExpanded* dataE=dynamic_cast<DataExpanded*>(data.m_data.get());    }
1855      else if (isExpanded()) {
1856        Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1857        DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());
1858      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());
1859      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");
1860      EsysAssert((resultE!=0), "Programming error - casting result to DataExpanded.");      EsysAssert((resultE!=0), "Programming error - casting result to DataExpanded.");
1861      escript::dp_algorithm(*dataE,*resultE,operation);      escript::dp_algorithm(*dataE,*resultE,operation,initial_value);
1862    } else if (data.isTagged()) {      return result;
1863      DataTagged* dataT=dynamic_cast<DataTagged*>(data.m_data.get());    }
1864      DataTagged* resultT=dynamic_cast<DataTagged*>(result.m_data.get());    else if (isTagged()) {
1865        DataTagged* dataT=dynamic_cast<DataTagged*>(m_data.get());
1866      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");
1867      EsysAssert((resultT!=0), "Programming error - casting result to DataTagged.");      DataTypes::ValueType defval(1);
1868      escript::dp_algorithm(*dataT,*resultT,operation);      defval[0]=0;
1869    } else if (data.isConstant()) {      DataTagged* resultT=new DataTagged(getFunctionSpace(), DataTypes::scalarShape, defval, dataT);
1870      DataConstant* dataC=dynamic_cast<DataConstant*>(data.m_data.get());      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);
1871        return Data(resultT);   // note: the Data object now owns the resultT pointer
1872      }
1873      else if (isConstant()) {
1874        Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1875        DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());
1876      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());
1877      EsysAssert((dataC!=0), "Programming error - casting data to DataConstant.");      EsysAssert((dataC!=0), "Programming error - casting data to DataConstant.");
1878      EsysAssert((resultC!=0), "Programming error - casting result to DataConstant.");      EsysAssert((resultC!=0), "Programming error - casting result to DataConstant.");
1879      escript::dp_algorithm(*dataC,*resultC,operation);      escript::dp_algorithm(*dataC,*resultC,operation,initial_value);
1880        return result;
1881      } else if (isLazy()) {
1882        throw DataException("Error - Operations not permitted on instances of DataLazy.");
1883      } else {
1884        throw DataException("Error - Data encapsulates an unknown type.");
1885      }
1886    }
1887    
1888    /**
1889      \brief
1890      Compute a tensor operation with two Data objects
1891      \param arg0 - Input - Data object
1892      \param arg1 - Input - Data object
1893      \param operation - Input - Binary op functor
1894    */
1895    template <typename BinaryFunction>
1896    inline
1897    Data
1898    C_TensorBinaryOperation(Data const &arg_0,
1899                            Data const &arg_1,
1900                            BinaryFunction operation)
1901    {
1902      if (arg_0.isEmpty() || arg_1.isEmpty())
1903      {
1904         throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1905    }    }
1906    return result;    if (arg_0.isLazy() || arg_1.isLazy())
1907      {
1908         throw DataException("Error - Operations not permitted on lazy data.");
1909      }
1910      // Interpolate if necessary and find an appropriate function space
1911      Data arg_0_Z, arg_1_Z;
1912      if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
1913        if (arg_0.probeInterpolation(arg_1.getFunctionSpace())) {
1914          arg_0_Z = arg_0.interpolate(arg_1.getFunctionSpace());
1915          arg_1_Z = Data(arg_1);
1916        }
1917        else if (arg_1.probeInterpolation(arg_0.getFunctionSpace())) {
1918          arg_1_Z=arg_1.interpolate(arg_0.getFunctionSpace());
1919          arg_0_Z =Data(arg_0);
1920        }
1921        else {
1922          throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible function spaces.");
1923        }
1924      } else {
1925          arg_0_Z = Data(arg_0);
1926          arg_1_Z = Data(arg_1);
1927      }
1928      // Get rank and shape of inputs
1929      int rank0 = arg_0_Z.getDataPointRank();
1930      int rank1 = arg_1_Z.getDataPointRank();
1931      DataTypes::ShapeType shape0 = arg_0_Z.getDataPointShape();
1932      DataTypes::ShapeType shape1 = arg_1_Z.getDataPointShape();
1933      int size0 = arg_0_Z.getDataPointSize();
1934      int size1 = arg_1_Z.getDataPointSize();
1935    
1936      // Declare output Data object
1937      Data res;
1938    
1939      if (shape0 == shape1) {
1940    
1941        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1942          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
1943    /*      double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1944          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1945          double *ptr_2 = &((res.getPointDataView().getData())[0]);*/
1946          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
1947          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
1948          double *ptr_2 = &(res.getDataAtOffset(0));
1949    
1950          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1951        }
1952        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
1953    
1954          // Prepare the DataConstant input
1955          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
1956    
1957          // Borrow DataTagged input from Data object
1958          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
1959    
1960          // Prepare a DataTagged output 2
1961          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
1962          res.tag();
1963          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1964    
1965          // Prepare offset into DataConstant
1966          int offset_0 = tmp_0->getPointOffset(0,0);
1967          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1968          // Get the views
1969    //       DataArrayView view_1 = tmp_1->getDefaultValue();
1970    //       DataArrayView view_2 = tmp_2->getDefaultValue();
1971    //       // Get the pointers to the actual data
1972    //       double *ptr_1 = &((view_1.getData())[0]);
1973    //       double *ptr_2 = &((view_2.getData())[0]);
1974    
1975          // Get the pointers to the actual data
1976          double *ptr_1 = &(tmp_1->getDefaultValue(0));
1977          double *ptr_2 = &(tmp_2->getDefaultValue(0));
1978    
1979          // Compute a result for the default
1980          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1981          // Compute a result for each tag
1982          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1983          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1984          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1985            tmp_2->addTag(i->first);
1986    /*        DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1987            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1988            double *ptr_1 = &view_1.getData(0);
1989            double *ptr_2 = &view_2.getData(0);*/
1990            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1991            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1992    
1993            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1994          }
1995    
1996        }
1997        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
1998    
1999          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2000          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2001          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2002          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2003    
2004          int sampleNo_1,dataPointNo_1;
2005          int numSamples_1 = arg_1_Z.getNumSamples();
2006          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2007          int offset_0 = tmp_0->getPointOffset(0,0);
2008          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2009          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2010            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2011              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2012              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2013    //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2014    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2015    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2016    
2017              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2018              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2019              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2020              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2021            }
2022          }
2023    
2024        }
2025        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2026    
2027          // Borrow DataTagged input from Data object
2028          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2029    
2030          // Prepare the DataConstant input
2031          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2032    
2033          // Prepare a DataTagged output 2
2034          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
2035          res.tag();
2036          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2037    
2038          // Prepare offset into DataConstant
2039          int offset_1 = tmp_1->getPointOffset(0,0);
2040    //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2041          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2042          // Get the views
2043    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2044    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2045    //       // Get the pointers to the actual data
2046    //       double *ptr_0 = &((view_0.getData())[0]);
2047    //       double *ptr_2 = &((view_2.getData())[0]);
2048          // Get the pointers to the actual data
2049          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2050          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2051          // Compute a result for the default
2052          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2053          // Compute a result for each tag
2054          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2055          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2056          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2057            tmp_2->addTag(i->first);
2058    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2059    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2060    //         double *ptr_0 = &view_0.getData(0);
2061    //         double *ptr_2 = &view_2.getData(0);
2062            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2063            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2064            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2065          }
2066    
2067        }
2068        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2069    
2070          // Borrow DataTagged input from Data object
2071          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2072    
2073          // Borrow DataTagged input from Data object
2074          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2075    
2076          // Prepare a DataTagged output 2
2077          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
2078          res.tag();        // DataTagged output
2079          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2080    
2081    //       // Get the views
2082    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2083    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2084    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2085    //       // Get the pointers to the actual data
2086    //       double *ptr_0 = &((view_0.getData())[0]);
2087    //       double *ptr_1 = &((view_1.getData())[0]);
2088    //       double *ptr_2 = &((view_2.getData())[0]);
2089    
2090          // Get the pointers to the actual data
2091          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2092          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2093          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2094    
2095          // Compute a result for the default
2096          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2097          // Merge the tags
2098          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2099          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2100          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2101          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2102            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2103          }
2104          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2105            tmp_2->addTag(i->first);
2106          }
2107          // Compute a result for each tag
2108          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2109          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2110    
2111    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2112    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2113    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2114    //         double *ptr_0 = &view_0.getData(0);
2115    //         double *ptr_1 = &view_1.getData(0);
2116    //         double *ptr_2 = &view_2.getData(0);
2117    
2118            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2119            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2120            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2121    
2122            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2123          }
2124    
2125        }
2126        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2127    
2128          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2129          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2130          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2131          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2132          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2133    
2134          int sampleNo_0,dataPointNo_0;
2135          int numSamples_0 = arg_0_Z.getNumSamples();
2136          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2137          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2138          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2139            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2140            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2141            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2142              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2143              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2144    
2145    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2146    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2147              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2148              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2149    
2150    
2151              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2152            }
2153          }
2154    
2155        }
2156        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2157    
2158          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2159          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2160          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2161          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2162    
2163          int sampleNo_0,dataPointNo_0;
2164          int numSamples_0 = arg_0_Z.getNumSamples();
2165          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2166          int offset_1 = tmp_1->getPointOffset(0,0);
2167          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2168          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2169            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2170              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2171              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2172    
2173    //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2174    //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2175    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2176    
2177              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2178              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2179              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2180    
2181    
2182              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2183            }
2184          }
2185    
2186        }
2187        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2188    
2189          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2190          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2191          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2192          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2193          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2194    
2195          int sampleNo_0,dataPointNo_0;
2196          int numSamples_0 = arg_0_Z.getNumSamples();
2197          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2198          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2199          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2200            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2201            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2202            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2203              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2204              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2205              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2206              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2207              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2208            }
2209          }
2210    
2211        }
2212        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2213    
2214          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2215          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2216          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2217          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2218          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2219    
2220          int sampleNo_0,dataPointNo_0;
2221          int numSamples_0 = arg_0_Z.getNumSamples();
2222          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2223          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2224          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2225            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2226              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2227              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2228              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2229              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2230              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2231              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2232              tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2233            }
2234          }
2235    
2236        }
2237        else {
2238          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2239        }
2240    
2241      } else if (0 == rank0) {
2242    
2243        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2244          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output
2245          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2246          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2247          double *ptr_2 = &(res.getDataAtOffset(0));
2248          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2249        }
2250        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2251    
2252          // Prepare the DataConstant input
2253          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2254    
2255          // Borrow DataTagged input from Data object
2256          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2257    
2258          // Prepare a DataTagged output 2
2259          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataTagged output
2260          res.tag();
2261          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2262    
2263          // Prepare offset into DataConstant
2264          int offset_0 = tmp_0->getPointOffset(0,0);
2265          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2266          // Get the views
2267    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2268    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2269    //       // Get the pointers to the actual data
2270    //       double *ptr_1 = &((view_1.getData())[0]);
2271    //       double *ptr_2 = &((view_2.getData())[0]);
2272           double *ptr_1 = &(tmp_1->getDefaultValue(0));
2273           double *ptr_2 = &(tmp_2->getDefaultValue(0));
2274    
2275          // Compute a result for the default
2276          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2277          // Compute a result for each tag
2278          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2279          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2280          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2281            tmp_2->addTag(i->first);
2282    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2283    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2284    //         double *ptr_1 = &view_1.getData(0);
2285    //         double *ptr_2 = &view_2.getData(0);
2286            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2287            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2288            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2289          }
2290    
2291        }
2292        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2293    
2294          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2295          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2296          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2297          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2298    
2299          int sampleNo_1,dataPointNo_1;
2300          int numSamples_1 = arg_1_Z.getNumSamples();
2301          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2302          int offset_0 = tmp_0->getPointOffset(0,0);
2303          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2304          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2305            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2306              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2307              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2308              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2309              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2310              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2311              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2312    
2313            }
2314          }
2315    
2316        }
2317        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2318    
2319          // Borrow DataTagged input from Data object
2320          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2321    
2322          // Prepare the DataConstant input
2323          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2324    
2325          // Prepare a DataTagged output 2
2326          res = Data(0.0, shape1, arg_0_Z.getFunctionSpace());      // DataTagged output
2327          res.tag();
2328          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2329    
2330          // Prepare offset into DataConstant
2331          int offset_1 = tmp_1->getPointOffset(0,0);
2332    //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2333          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2334          // Get the views
2335    /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2336          DataArrayView view_2 = tmp_2->getDefaultValue();
2337          // Get the pointers to the actual data
2338          double *ptr_0 = &((view_0.getData())[0]);
2339          double *ptr_2 = &((view_2.getData())[0]);*/
2340    
2341          // Get the pointers to the actual data
2342          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2343          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2344    
2345    
2346          // Compute a result for the default
2347          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2348          // Compute a result for each tag
2349          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2350          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2351          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2352            tmp_2->addTag(i->first);
2353    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2354            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2355            double *ptr_0 = &view_0.getData(0);
2356            double *ptr_2 = &view_2.getData(0);*/
2357            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2358            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2359    
2360            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2361          }
2362    
2363        }
2364        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2365    
2366          // Borrow DataTagged input from Data object
2367          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2368    
2369          // Borrow DataTagged input from Data object
2370          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2371    
2372          // Prepare a DataTagged output 2
2373          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());
2374          res.tag();        // DataTagged output
2375          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2376    
2377          // Get the views
2378    /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2379          DataArrayView view_1 = tmp_1->getDefaultValue();
2380          DataArrayView view_2 = tmp_2->getDefaultValue();
2381          // Get the pointers to the actual data
2382          double *ptr_0 = &((view_0.getData())[0]);
2383          double *ptr_1 = &((view_1.getData())[0]);
2384          double *ptr_2 = &((view_2.getData())[0]);*/
2385    
2386          // Get the pointers to the actual data
2387          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2388          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2389          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2390    
2391    
2392          // Compute a result for the default
2393          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2394          // Merge the tags
2395          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2396          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2397          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2398          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2399            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2400          }
2401          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2402            tmp_2->addTag(i->first);
2403          }
2404          // Compute a result for each tag
2405          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2406          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2407    
2408    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2409            DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2410            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2411            double *ptr_0 = &view_0.getData(0);
2412            double *ptr_1 = &view_1.getData(0);
2413            double *ptr_2 = &view_2.getData(0);*/
2414    
2415            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2416            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2417            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2418    
2419            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2420          }
2421    
2422        }
2423        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2424    
2425          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2426          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2427          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2428          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2429          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2430    
2431          int sampleNo_0,dataPointNo_0;
2432          int numSamples_0 = arg_0_Z.getNumSamples();
2433          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2434          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2435          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2436            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2437            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2438            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2439              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2440              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2441              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2442              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2443              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2444            }
2445          }
2446    
2447        }
2448        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2449    
2450          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2451          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2452          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2453          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2454    
2455          int sampleNo_0,dataPointNo_0;
2456          int numSamples_0 = arg_0_Z.getNumSamples();
2457          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2458          int offset_1 = tmp_1->getPointOffset(0,0);
2459          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2460          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2461            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2462              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2463              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2464              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2465              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2466              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2467              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2468            }
2469          }
2470    
2471    
2472        }
2473        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2474    
2475          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2476          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2477          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2478          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2479          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2480    
2481          int sampleNo_0,dataPointNo_0;
2482          int numSamples_0 = arg_0_Z.getNumSamples();
2483          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2484          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2485          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2486            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2487            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2488            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2489              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2490              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2491              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2492              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2493              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2494            }
2495          }
2496    
2497        }
2498        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2499    
2500          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2501          res = Data(0.0, shape1, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2502          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2503          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2504          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2505    
2506          int sampleNo_0,dataPointNo_0;
2507          int numSamples_0 = arg_0_Z.getNumSamples();
2508          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2509          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2510          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2511            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2512              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2513              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2514              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2515              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2516              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2517              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2518              tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2519            }
2520          }
2521    
2522        }
2523        else {
2524          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2525        }
2526    
2527      } else if (0 == rank1) {
2528    
2529        if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2530          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
2531          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2532          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2533          double *ptr_2 = &(res.getDataAtOffset(0));
2534          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2535        }
2536        else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
2537    
2538          // Prepare the DataConstant input
2539          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2540    
2541          // Borrow DataTagged input from Data object
2542          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2543    
2544          // Prepare a DataTagged output 2
2545          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataTagged output
2546          res.tag();
2547          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2548    
2549          // Prepare offset into DataConstant
2550          int offset_0 = tmp_0->getPointOffset(0,0);
2551          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2552          // Get the views
2553    /*      DataArrayView view_1 = tmp_1->getDefaultValue();
2554          DataArrayView view_2 = tmp_2->getDefaultValue();
2555          // Get the pointers to the actual data
2556          double *ptr_1 = &((view_1.getData())[0]);
2557          double *ptr_2 = &((view_2.getData())[0]);*/
2558          //Get the pointers to the actual data
2559          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2560          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2561    
2562          // Compute a result for the default
2563          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2564          // Compute a result for each tag
2565          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2566          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2567          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2568            tmp_2->addTag(i->first);
2569    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2570    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2571    //         double *ptr_1 = &view_1.getData(0);
2572    //         double *ptr_2 = &view_2.getData(0);
2573            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2574            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2575    
2576    
2577            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2578          }
2579    
2580        }
2581        else if (arg_0_Z.isConstant()   && arg_1_Z.isExpanded()) {
2582    
2583          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2584          DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2585          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2586          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2587    
2588          int sampleNo_1,dataPointNo_1;
2589          int numSamples_1 = arg_1_Z.getNumSamples();
2590          int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2591          int offset_0 = tmp_0->getPointOffset(0,0);
2592          #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2593          for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2594            for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2595              int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2596              int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2597              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2598              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2599              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2600              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2601            }
2602          }
2603    
2604        }
2605        else if (arg_0_Z.isTagged()     && arg_1_Z.isConstant()) {
2606    
2607          // Borrow DataTagged input from Data object
2608          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2609    
2610          // Prepare the DataConstant input
2611          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2612    
2613          // Prepare a DataTagged output 2
2614          res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataTagged output
2615          res.tag();
2616          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2617    
2618          // Prepare offset into DataConstant
2619          int offset_1 = tmp_1->getPointOffset(0,0);
2620          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2621          // Get the views
2622    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2623    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2624    //       // Get the pointers to the actual data
2625    //       double *ptr_0 = &((view_0.getData())[0]);
2626    //       double *ptr_2 = &((view_2.getData())[0]);
2627          // Get the pointers to the actual data
2628          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2629          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2630          // Compute a result for the default
2631          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2632          // Compute a result for each tag
2633          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2634          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2635          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2636            tmp_2->addTag(i->first);
2637    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2638            DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2639            double *ptr_0 = &view_0.getData(0);
2640            double *ptr_2 = &view_2.getData(0);*/
2641            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2642            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2643            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2644          }
2645    
2646        }
2647        else if (arg_0_Z.isTagged()     && arg_1_Z.isTagged()) {
2648    
2649          // Borrow DataTagged input from Data object
2650          DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2651    
2652          // Borrow DataTagged input from Data object
2653          DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2654    
2655          // Prepare a DataTagged output 2
2656          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());
2657          res.tag();        // DataTagged output
2658          DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2659    
2660          // Get the views
2661    //       DataArrayView view_0 = tmp_0->getDefaultValue();
2662    //       DataArrayView view_1 = tmp_1->getDefaultValue();
2663    //       DataArrayView view_2 = tmp_2->getDefaultValue();
2664    //       // Get the pointers to the actual data
2665    //       double *ptr_0 = &((view_0.getData())[0]);
2666    //       double *ptr_1 = &((view_1.getData())[0]);
2667    //       double *ptr_2 = &((view_2.getData())[0]);
2668    
2669          // Get the pointers to the actual data
2670          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2671          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2672          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2673    
2674          // Compute a result for the default
2675          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2676          // Merge the tags
2677          DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2678          const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2679          const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2680          for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2681            tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2682          }
2683          for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2684            tmp_2->addTag(i->first);
2685          }
2686          // Compute a result for each tag
2687          const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2688          for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2689    //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2690    //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2691    //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2692    //         double *ptr_0 = &view_0.getData(0);
2693    //         double *ptr_1 = &view_1.getData(0);
2694    //         double *ptr_2 = &view_2.getData(0);
2695    
2696            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2697            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2698            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2699            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2700          }
2701    
2702        }
2703        else if (arg_0_Z.isTagged()     && arg_1_Z.isExpanded()) {
2704    
2705          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2706          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2707          DataTagged*   tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2708          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2709          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2710    
2711          int sampleNo_0,dataPointNo_0;
2712          int numSamples_0 = arg_0_Z.getNumSamples();
2713          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2714          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2715          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2716            int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2717            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2718            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2719              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2720              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2721              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2722              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2723              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2724            }
2725          }
2726    
2727        }
2728        else if (arg_0_Z.isExpanded()   && arg_1_Z.isConstant()) {
2729    
2730          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2731          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2732          DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2733          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2734    
2735          int sampleNo_0,dataPointNo_0;
2736          int numSamples_0 = arg_0_Z.getNumSamples();
2737          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2738          int offset_1 = tmp_1->getPointOffset(0,0);
2739          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2740          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2741            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2742              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2743              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2744              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2745              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2746              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2747              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2748            }
2749          }
2750    
2751    
2752        }
2753        else if (arg_0_Z.isExpanded()   && arg_1_Z.isTagged()) {
2754    
2755          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2756          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2757          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2758          DataTagged*   tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2759          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2760    
2761          int sampleNo_0,dataPointNo_0;
2762          int numSamples_0 = arg_0_Z.getNumSamples();
2763          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2764          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2765          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2766            int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2767            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2768            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2769              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2770              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2771              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2772              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2773              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2774            }
2775          }
2776    
2777        }
2778        else if (arg_0_Z.isExpanded()   && arg_1_Z.isExpanded()) {
2779    
2780          // After finding a common function space above the two inputs have the same numSamples and num DPPS
2781          res = Data(0.0, shape0, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2782          DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2783          DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2784          DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2785    
2786          int sampleNo_0,dataPointNo_0;
2787          int numSamples_0 = arg_0_Z.getNumSamples();
2788          int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2789          #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2790          for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2791            for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2792              int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2793              int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2794              int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2795              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2796              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2797              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2798              tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2799            }
2800          }
2801    
2802        }
2803        else {
2804          throw DataException("Error - C_TensorBinaryOperation: unknown combination of inputs");
2805        }
2806    
2807      } else {
2808        throw DataException("Error - C_TensorBinaryOperation: arguments have incompatible shapes");
2809      }
2810    
2811      return res;
2812    }
2813    
2814    template <typename UnaryFunction>
2815    Data
2816    C_TensorUnaryOperation(Data const &arg_0,
2817                           UnaryFunction operation)
2818    {
2819      if (arg_0.isEmpty())  // do this before we attempt to interpolate
2820      {
2821         throw DataException("Error - Operations not permitted on instances of DataEmpty.");
2822      }
2823      if (arg_0.isLazy())
2824      {
2825         throw DataException("Error - Operations not permitted on lazy data.");
2826      }
2827      // Interpolate if necessary and find an appropriate function space
2828      Data arg_0_Z = Data(arg_0);
2829    
2830      // Get rank and shape of inputs
2831    //  int rank0 = arg_0_Z.getDataPointRank();
2832      const DataTypes::ShapeType& shape0 = arg_0_Z.getDataPointShape();
2833      int size0 = arg_0_Z.getDataPointSize();
2834    
2835      // Declare output Data object
2836      Data res;
2837    
2838      if (arg_0_Z.isConstant()) {
2839        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output
2840    //     double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2841    //     double *ptr_2 = &((res.getPointDataView().getData())[0]);
2842        double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2843        double *ptr_2 = &(res.getDataAtOffset(0));
2844        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2845      }
2846      else if (arg_0_Z.isTagged()) {
2847    
2848        // Borrow DataTagged input from Data object
2849        DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2850    
2851        // Prepare a DataTagged output 2
2852        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());   // DataTagged output
2853        res.tag();
2854        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2855    
2856    //     // Get the views
2857    //     DataArrayView view_0 = tmp_0->getDefaultValue();
2858    //     DataArrayView view_2 = tmp_2->getDefaultValue();
2859    //     // Get the pointers to the actual data
2860    //     double *ptr_0 = &((view_0.getData())[0]);
2861    //     double *ptr_2 = &((view_2.getData())[0]);
2862        // Get the pointers to the actual data
2863        double *ptr_0 = &(tmp_0->getDefaultValue(0));
2864        double *ptr_2 = &(tmp_2->getDefaultValue(0));
2865        // Compute a result for the default
2866        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2867        // Compute a result for each tag
2868        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2869        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2870        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2871          tmp_2->addTag(i->first);
2872    //       DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2873    //       DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2874    //       double *ptr_0 = &view_0.getData(0);
2875    //       double *ptr_2 = &view_2.getData(0);
2876          double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2877          double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2878          tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2879        }
2880    
2881      }
2882      else if (arg_0_Z.isExpanded()) {
2883    
2884        res = Data(0.0, shape0, arg_0_Z.getFunctionSpace(),true); // DataExpanded output
2885        DataExpanded* tmp_0=dynamic_cast<DataExpanded*>(arg_0_Z.borrowData());
2886        DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2887    
2888        int sampleNo_0,dataPointNo_0;
2889        int numSamples_0 = arg_0_Z.getNumSamples();
2890        int numDataPointsPerSample_0 = arg_0_Z.getNumDataPointsPerSample();
2891        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2892        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2893          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2894    //         int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2895    //         int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2896    //         double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2897    //         double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2898            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2899            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2900            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2901            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2902            tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2903          }
2904        }
2905      }
2906      else {
2907        throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");
2908      }
2909    
2910      return res;
2911  }  }
2912    
2913  }  }

Legend:
Removed from v.97  
changed lines
  Added in v.2005

  ViewVC Help
Powered by ViewVC 1.1.26