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

temp/escript/src/Data.h revision 1387 by trankine, Fri Jan 11 07:45:26 2008 UTC trunk/escript/src/Data.h revision 1857 by jfenwick, Tue Oct 7 23:58:44 2008 UTC
# Line 1  Line 1 
1    
 /* $Id$ */  
   
2  /*******************************************************  /*******************************************************
3   *  *
4   *           Copyright 2003-2007 by ACceSS MNRF  * Copyright (c) 2003-2008 by University of Queensland
5   *       Copyright 2007 by University of Queensland  * Earth Systems Science Computational Center (ESSCC)
6   *  * http://www.uq.edu.au/esscc
7   *                http://esscc.uq.edu.au  *
8   *        Primary Business: Queensland, Australia  * Primary Business: Queensland, Australia
9   *  Licensed under the Open Software License version 3.0  * Licensed under the Open Software License version 3.0
10   *     http://www.opensource.org/licenses/osl-3.0.php  * http://www.opensource.org/licenses/osl-3.0.php
11   *  *
12   *******************************************************/  *******************************************************/
13    
14    
15  /** \file Data.h */  /** \file Data.h */
16    
# Line 25  Line 24 
24  #include "BinaryOp.h"  #include "BinaryOp.h"
25  #include "UnaryOp.h"  #include "UnaryOp.h"
26  #include "DataException.h"  #include "DataException.h"
27    #include "DataTypes.h"
28    
29  extern "C" {  extern "C" {
30  #include "DataC.h"  #include "DataC.h"
# Line 34  extern "C" { Line 34  extern "C" {
34  #include "esysmpi.h"  #include "esysmpi.h"
35  #include <string>  #include <string>
36  #include <algorithm>  #include <algorithm>
37    #include <sstream>
38    
39    
40  #include <boost/shared_ptr.hpp>  #include <boost/shared_ptr.hpp>
41  #include <boost/python/object.hpp>  #include <boost/python/object.hpp>
# Line 50  class DataExpanded; Line 52  class DataExpanded;
52    
53  /**  /**
54     \brief     \brief
55     Data creates the appropriate Data object for the given construction     Data represents a collection of datapoints.
    arguments.  
56    
57     Description:     Description:
58     Data is essentially a factory class which creates the appropriate Data     Internally, the datapoints are actually stored by a DataAbstract object.
59     object for the given construction arguments. It retains control over     The specific instance of DataAbstract used may vary over the lifetime
60     the object created for the lifetime of the object.     of the Data object.
61     The type of Data object referred to may change during the lifetime of     Some methods on this class return references (eg getShape()).
62     the Data object.     These references should not be used after an operation which changes the underlying DataAbstract object.
63       Doing so will lead to invalid memory access.
64       This should not affect any methods exposed via boost::python.
65  */  */
66  class Data {  class Data {
67    
# Line 101  class Data { Line 104  class Data {
104         const FunctionSpace& what);         const FunctionSpace& what);
105    
106    /**    /**
107       \brief      \brief Copy Data from an existing vector
108       Constructor which copies data from a DataArrayView.    */
109    
      \param value - Input - Data value for a single point.  
      \param what - Input - A description of what this data represents.  
      \param expanded - Input - Flag, if true fill the entire container with  
                        the value. Otherwise a more efficient storage  
                        mechanism will be used.  
   */  
110    ESCRIPT_DLL_API    ESCRIPT_DLL_API
111    Data(const DataArrayView& value,    Data(const DataTypes::ValueType& value,
112         const FunctionSpace& what=FunctionSpace(),           const DataTypes::ShapeType& shape,
113         bool expanded=false);                   const FunctionSpace& what=FunctionSpace(),
114                     bool expanded=false);
115    
116    /**    /**
117       \brief       \brief
# Line 128  class Data { Line 126  class Data {
126    */    */
127    ESCRIPT_DLL_API    ESCRIPT_DLL_API
128    Data(double value,    Data(double value,
129         const DataArrayView::ShapeType& dataPointShape=DataArrayView::ShapeType(),         const DataTypes::ShapeType& dataPointShape=DataTypes::ShapeType(),
130         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
131         bool expanded=false);         bool expanded=false);
132    
# Line 141  class Data { Line 139  class Data {
139    */    */
140    ESCRIPT_DLL_API    ESCRIPT_DLL_API
141    Data(const Data& inData,    Data(const Data& inData,
142         const DataArrayView::RegionType& region);         const DataTypes::RegionType& region);
   
   /**  
      \brief  
      Constructor which will create Tagged data if expanded is false.  
      No attempt is made to ensure the tag keys match the tag keys  
      within the function space.  
   
      \param tagKeys - Input - List of tag values.  
      \param values - Input - List of values, one for each tag.  
      \param defaultValue - Input - A default value, used if tag doesn't exist.  
      \param what - Input - A description of what this data represents.  
      \param expanded - Input - Flag, if true fill the entire container with  
                        the appropriate values.  
     ==>*  
   */  
   ESCRIPT_DLL_API  
   Data(const DataTagged::TagListType& tagKeys,  
        const DataTagged::ValueListType& values,  
        const DataArrayView& defaultValue,  
        const FunctionSpace& what=FunctionSpace(),  
        bool expanded=false);  
143    
144    /**    /**
145       \brief       \brief
# Line 217  class Data { Line 194  class Data {
194         const boost::python::tuple& shape=boost::python::make_tuple(),         const boost::python::tuple& shape=boost::python::make_tuple(),
195         const FunctionSpace& what=FunctionSpace(),         const FunctionSpace& what=FunctionSpace(),
196         bool expanded=false);         bool expanded=false);
197    
198    
199    
200      /**
201        \brief Create a Data using an existing DataAbstract. Warning: The new object assumes ownership of the pointer!
202        Once you have passed the pointer, do not delete it.
203      */
204      ESCRIPT_DLL_API
205      Data(DataAbstract* underlyingdata);
206    
207    
208    /**    /**
209       \brief       \brief
210       Destructor       Destructor
# Line 225  class Data { Line 213  class Data {
213    ~Data();    ~Data();
214    
215    /**    /**
216       \brief       \brief Make this object a deep copy of "other".
      Perform a deep copy.  
217    */    */
218    ESCRIPT_DLL_API    ESCRIPT_DLL_API
219    void    void
220    copy(const Data& other);    copy(const Data& other);
221    
222    /**    /**
223         \brief Return a pointer to a deep copy of this object.
224      */
225      ESCRIPT_DLL_API
226      Data*
227      copySelf();
228    
229    
230    
231    
232      /**
233       Member access methods.       Member access methods.
234    */    */
235    
# Line 298  class Data { Line 295  class Data {
295       \brief       \brief
296       Return the tag number associated with the given data-point.       Return the tag number associated with the given data-point.
297    
      The data-point number here corresponds to the data-point number in the  
      numarray returned by convertToNumArray.  
298    */    */
299    ESCRIPT_DLL_API    ESCRIPT_DLL_API
300    int    int
# Line 313  class Data { Line 308  class Data {
308    escriptDataC    escriptDataC
309    getDataC();    getDataC();
310    
311    
312    
313    
314    
315    
316    // REMOVE ME
317    // ESCRIPT_DLL_API
318    // void
319    // CompareDebug(const Data& rd);
320    
321    
322    /**    /**
323       \brief       \brief
324       Return the C wrapper for the Data object - const version.       Return the C wrapper for the Data object - const version.
# Line 323  class Data { Line 329  class Data {
329    
330    /**    /**
331       \brief       \brief
332       Write the data as a string.       Write the data as a string. For large amounts of data, a summary is printed.
333    */    */
334    ESCRIPT_DLL_API    ESCRIPT_DLL_API
   inline  
335    std::string    std::string
336    toString() const    toString() const;
   {  
     return m_data->toString();  
   }  
337    
338    /**  
339       \brief  //  /**
340    /*     \brief
341       Return the DataArrayView of the point data. This essentially contains       Return the DataArrayView of the point data. This essentially contains
342       the shape information for each data point although it also may be used       the shape information for each data point although it also may be used
343       to manipulate the point data.       to manipulate the point data.*/
344    */  //  */
345    ESCRIPT_DLL_API  //   ESCRIPT_DLL_API
346    inline  //   inline
347    const DataArrayView&  //   const DataArrayView&
348    getPointDataView() const  //   getPointDataView() const
349    {  //   {
350       return m_data->getPointDataView();  //      return m_data->getPointDataView();
351    }  //   }
352    
353    /**    /**
354       \brief       \brief
# Line 392  class Data { Line 395  class Data {
395    
396    /**    /**
397       \brief       \brief
398       Return true if this Data is empty.       Return true if this Data holds an instance of DataEmpty. This is _not_ the same as asking if the object
399    contains datapoints.
400    */    */
401    ESCRIPT_DLL_API    ESCRIPT_DLL_API
402    bool    bool
# Line 447  class Data { Line 451  class Data {
451    int    int
452    getDataPointRank() const    getDataPointRank() const
453    {    {
454      return m_data->getPointDataView().getRank();  //    return m_data->getPointDataView().getRank();
455        return m_data->getRank();
456    }    }
457    
458    /**    /**
# Line 484  class Data { Line 489  class Data {
489    {    {
490      return m_data->getNumDPPSample();      return m_data->getNumDPPSample();
491    }    }
492    
493    
494      /**
495        \brief
496        Return the number of values in the shape for this object.
497      */
498      ESCRIPT_DLL_API
499      int
500      getNoValues() const
501      {
502        return m_data->getNoValues();
503      }
504    
505    
506    /**    /**
507       \brief       \brief
508       dumps the object into a netCDF file       dumps the object into a netCDF file
# Line 519  class Data { Line 538  class Data {
538      return m_data->getSampleDataByTag(tag);      return m_data->getSampleDataByTag(tag);
539    }    }
540    
541    //  /**
542    /*     \brief
543         Return a view into the data for the data point specified.
544         NOTE: Construction of the DataArrayView is a relatively expensive
545         operation.
546         \param sampleNo - Input -
547         \param dataPointNo - Input -*/
548    //  */
549    //   ESCRIPT_DLL_API
550    //   inline
551    //   DataArrayView
552    //   getDataPoint(int sampleNo,
553    //                int dataPointNo)
554    //   {
555    //                 return m_data->getDataPoint(sampleNo,dataPointNo);
556    //   }
557    
558    
559    /**    /**
560       \brief       \brief
561       Return a view into the data for the data point specified.       Return a view into the data for the data point specified.
# Line 528  class Data { Line 565  class Data {
565       \param dataPointNo - Input -       \param dataPointNo - Input -
566    */    */
567    ESCRIPT_DLL_API    ESCRIPT_DLL_API
568      DataTypes::ValueType::const_reference
569      getDataPoint(int sampleNo, int dataPointNo) const;
570    
571    
572      ESCRIPT_DLL_API
573      DataTypes::ValueType::reference
574      getDataPoint(int sampleNo, int dataPointNo);
575    
576    
577    
578      /**
579         \brief
580         Return the offset for the given sample and point within the sample
581      */
582      ESCRIPT_DLL_API
583    inline    inline
584    DataArrayView    DataTypes::ValueType::size_type
585    getDataPoint(int sampleNo,    getDataOffset(int sampleNo,
586                 int dataPointNo)                 int dataPointNo)
587    {    {
588                  return m_data->getDataPoint(sampleNo,dataPointNo);                  return m_data->getPointOffset(sampleNo,dataPointNo);
589    }    }
590    
591    /**    /**
# Line 541  class Data { Line 593  class Data {
593       Return a reference to the data point shape.       Return a reference to the data point shape.
594    */    */
595    ESCRIPT_DLL_API    ESCRIPT_DLL_API
596    const DataArrayView::ShapeType&    inline
597    getDataPointShape() const;    const DataTypes::ShapeType&
598      getDataPointShape() const
599      {
600        return m_data->getShape();
601      }
602    
603    /**    /**
604       \brief       \brief
# Line 566  class Data { Line 622  class Data {
622       Return the number of doubles stored for this Data.       Return the number of doubles stored for this Data.
623    */    */
624    ESCRIPT_DLL_API    ESCRIPT_DLL_API
625    DataArrayView::ValueType::size_type    DataTypes::ValueType::size_type
626    getLength() const;    getLength() const;
627    
628    
# Line 599  class Data { Line 655  class Data {
655    setTaggedValue(int tagKey,    setTaggedValue(int tagKey,
656                   const boost::python::object& value);                   const boost::python::object& value);
657    
658    
659    //  /**
660    //     \brief
661    //     Assign the given value to the tag. Implicitly converts this
662    //     object to type DataTagged if it is constant.
663    //
664    //     \param tagKey - Input - Integer key.
665    //     \param value - Input - Value to associate with given key.
666    //    ==>*
667    //  */
668    //   ESCRIPT_DLL_API
669    //   void
670    //   setTaggedValueFromCPP(int tagKey,
671    //                         const DataArrayView& value);
672    
673    /**    /**
674       \brief       \brief
675       Assign the given value to the tag. Implicitly converts this       Assign the given value to the tag. Implicitly converts this
676       object to type DataTagged if it is constant.       object to type DataTagged if it is constant.
677    
678       \param tagKey - Input - Integer key.       \param tagKey - Input - Integer key.
679         \param pointshape - Input - The shape of the value parameter
680       \param value - Input - Value to associate with given key.       \param value - Input - Value to associate with given key.
681      ==>*       \param dataOffset - Input - Offset of the begining of the point within the value parameter
682    */    */
683    ESCRIPT_DLL_API    ESCRIPT_DLL_API
684    void    void
685    setTaggedValueFromCPP(int tagKey,    setTaggedValueFromCPP(int tagKey,
686                          const DataArrayView& value);              const DataTypes::ShapeType& pointshape,
687                            const DataTypes::ValueType& value,
688                int dataOffset=0);
689    
690    
691    
692    /**    /**
693      \brief      \brief
# Line 732  class Data { Line 808  class Data {
808    /**    /**
809       \brief       \brief
810       Return the maximum absolute value of this Data object.       Return the maximum absolute value of this Data object.
811         For Data which contain no samples (or tagged Data for which no tags in use have a value)
812         zero is returned.
813       *       *
814    */    */
815    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 741  class Data { Line 819  class Data {
819    /**    /**
820       \brief       \brief
821       Return the maximum value of this Data object.       Return the maximum value of this Data object.
822       *       For Data which contain no samples (or tagged Data for which no tags in use have a value)
823         a large negative value is returned.
824    */    */
825    ESCRIPT_DLL_API    ESCRIPT_DLL_API
826    double    double
# Line 750  class Data { Line 829  class Data {
829    /**    /**
830       \brief       \brief
831       Return the minimum value of this Data object.       Return the minimum value of this Data object.
832         For Data which contain no samples (or tagged Data for which no tags in use have a value)
833         a large positive value is returned.
834       *       *
835    */    */
836    ESCRIPT_DLL_API    ESCRIPT_DLL_API
# Line 1212  class Data { Line 1293  class Data {
1293    */    */
1294    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1295    Data    Data
1296    getSlice(const DataArrayView::RegionType& region) const;    getSlice(const DataTypes::RegionType& region) const;
1297    
1298    /**    /**
1299       \brief       \brief
# Line 1225  class Data { Line 1306  class Data {
1306    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1307    void    void
1308    setSlice(const Data& value,    setSlice(const Data& value,
1309             const DataArrayView::RegionType& region);             const DataTypes::RegionType& region);
   
   /**  
      \brief  
      Archive the current Data object to the given file.  
      \param fileName - Input - file to archive to.  
   */  
   ESCRIPT_DLL_API  
   void  
   archiveData(const std::string fileName);  
   
   /**  
      \brief  
      Extract the Data object archived in the given file, overwriting  
      the current Data object.  
      Note - the current object must be of type DataEmpty.  
      \param fileName - Input - file to extract from.  
      \param fspace - Input - a suitable FunctionSpace descibing the data.  
   */  
   ESCRIPT_DLL_API  
   void  
   extractData(const std::string fileName,  
               const FunctionSpace& fspace);  
   
1310    
1311    /**    /**
1312       \brief       \brief
# Line 1290  class Data { Line 1348  class Data {
1348    /**    /**
1349       \brief       \brief
1350       return the object produced by the factory, which is a DataConstant or DataExpanded       return the object produced by the factory, which is a DataConstant or DataExpanded
1351        TODO Ownership of this object should be explained in doco.
1352    */    */
1353    ESCRIPT_DLL_API    ESCRIPT_DLL_API
1354          DataAbstract*          DataAbstract*
1355          borrowData(void) const;          borrowData(void) const;
1356    
1357    
1358      /**
1359         \brief
1360         Return a pointer to the beginning of the datapoint at the specified offset.
1361         TODO Eventually these should be inlined.
1362         \param i - position(offset) in the underlying datastructure
1363      */
1364      ESCRIPT_DLL_API
1365            DataTypes::ValueType::const_reference
1366            getDataAtOffset(DataTypes::ValueType::size_type i) const;
1367    
1368    
1369      ESCRIPT_DLL_API
1370            DataTypes::ValueType::reference
1371            getDataAtOffset(DataTypes::ValueType::size_type i);
1372    
1373   protected:   protected:
1374    
1375   private:   private:
# Line 1370  class Data { Line 1445  class Data {
1445       \brief       \brief
1446       Construct a Data object of the appropriate type.       Construct a Data object of the appropriate type.
1447    */    */
1448    template <class IValueType>  
1449    void    void
1450    initialise(const IValueType& value,    initialise(const DataTypes::ValueType& value,
1451             const DataTypes::ShapeType& shape,
1452               const FunctionSpace& what,               const FunctionSpace& what,
1453               bool expanded);               bool expanded);
1454    
1455      void
1456      initialise(const boost::python::numeric::array& value,
1457                     const FunctionSpace& what,
1458                     bool expanded);
1459    
1460    //    //
1461    // flag to protect the data object against any update    // flag to protect the data object against any update
1462    bool m_protected;    bool m_protected;
# Line 1386  class Data { Line 1467  class Data {
1467    
1468  };  };
1469    
1470  template <class IValueType>  
1471  void  
1472  Data::initialise(const IValueType& value,  /**
1473                   const FunctionSpace& what,     Modify a filename for MPI parallel output to multiple files
1474                   bool expanded)  */
1475  {  char *Escript_MPI_appendRankToFileName(const char *, int, int);
   //  
   // Construct a Data object of the appropriate type.  
   // Construct the object first as there seems to be a bug which causes  
   // undefined behaviour if an exception is thrown during construction  
   // within the shared_ptr constructor.  
   if (expanded) {  
     DataAbstract* temp=new DataExpanded(value,what);  
     boost::shared_ptr<DataAbstract> temp_data(temp);  
     m_data=temp_data;  
   } else {  
     DataAbstract* temp=new DataConstant(value,what);  
     boost::shared_ptr<DataAbstract> temp_data(temp);  
     m_data=temp_data;  
   }  
 }  
1476    
1477  /**  /**
1478     Binary Data object operators.     Binary Data object operators.
# Line 1532  C_GeneralTensorProduct(Data& arg0, Line 1598  C_GeneralTensorProduct(Data& arg0,
1598                       int transpose=0);                       int transpose=0);
1599    
1600    
 /**  
   \brief  
   Compute a tensor operation with two Data objects  
   \param arg0 - Input - Data object  
   \param arg1 - Input - Data object  
   \param operation - Input - Binary op functor  
 */  
 template <typename BinaryFunction>  
 ESCRIPT_DLL_API  
 Data  
 C_TensorBinaryOperation(Data const &arg0,  
                         Data const &arg1,  
                         BinaryFunction operation);  
1601    
1602  /**  // /**
1603    \brief  /*  \brief
1604    Return true if operands are equivalent, else return false.    Return true if operands are equivalent, else return false.
1605    NB: this operator does very little at this point, and isn't to    NB: this operator does very little at this point, and isn't to
1606    be relied on. Requires further implementation.    be relied on. Requires further implementation.*/
1607  */  //*/
1608  // ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);  // ESCRIPT_DLL_API bool operator==(const Data& left, const Data& right);
1609    
1610  /**  /**
# Line 1567  Data::binaryOp(const Data& right, Line 1620  Data::binaryOp(const Data& right,
1620  {  {
1621     //     //
1622     // if this has a rank of zero promote it to the rank of the RHS     // if this has a rank of zero promote it to the rank of the RHS
1623     if (getPointDataView().getRank()==0 && right.getPointDataView().getRank()!=0) {     if (getDataPointRank()==0 && right.getDataPointRank()!=0) {
1624       throw DataException("Error - attempt to update rank zero object with object with rank bigger than zero.");       throw DataException("Error - attempt to update rank zero object with object with rank bigger than zero.");
1625     }     }
1626     //     //
# Line 1646  Data::algorithm(BinaryFunction operation Line 1699  Data::algorithm(BinaryFunction operation
1699      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());      DataConstant* leftC=dynamic_cast<DataConstant*>(m_data.get());
1700      EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");      EsysAssert((leftC!=0), "Programming error - casting to DataConstant.");
1701      return escript::algorithm(*leftC,operation,initial_value);      return escript::algorithm(*leftC,operation,initial_value);
1702      } else if (isEmpty()) {
1703        throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1704    }    }
1705    return 0;    return 0;
1706  }  }
# Line 1663  inline Line 1718  inline
1718  Data  Data
1719  Data::dp_algorithm(BinaryFunction operation, double initial_value) const  Data::dp_algorithm(BinaryFunction operation, double initial_value) const
1720  {  {
1721    if (isExpanded()) {    if (isEmpty()) {
1722      Data result(0,DataArrayView::ShapeType(),getFunctionSpace(),isExpanded());      throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1723      }
1724      else if (isExpanded()) {
1725        Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1726      DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());      DataExpanded* dataE=dynamic_cast<DataExpanded*>(m_data.get());
1727      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());      DataExpanded* resultE=dynamic_cast<DataExpanded*>(result.m_data.get());
1728      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");      EsysAssert((dataE!=0), "Programming error - casting data to DataExpanded.");
1729      EsysAssert((resultE!=0), "Programming error - casting result to DataExpanded.");      EsysAssert((resultE!=0), "Programming error - casting result to DataExpanded.");
1730      escript::dp_algorithm(*dataE,*resultE,operation,initial_value);      escript::dp_algorithm(*dataE,*resultE,operation,initial_value);
1731      return result;      return result;
1732    } else if (isTagged()) {    }
1733      else if (isTagged()) {
1734      DataTagged* dataT=dynamic_cast<DataTagged*>(m_data.get());      DataTagged* dataT=dynamic_cast<DataTagged*>(m_data.get());
     DataArrayView::ShapeType viewShape;  
     DataArrayView::ValueType viewData(1);  
     viewData[0]=0;  
     DataArrayView defaultValue(viewData,viewShape);  
     DataTagged::TagListType keys;  
     DataTagged::ValueListType values;  
     DataTagged::DataMapType::const_iterator i;  
     for (i=dataT->getTagLookup().begin();i!=dataT->getTagLookup().end();i++) {  
       keys.push_back(i->first);  
       values.push_back(defaultValue);  
     }  
     Data result(keys,values,defaultValue,getFunctionSpace());  
     DataTagged* resultT=dynamic_cast<DataTagged*>(result.m_data.get());  
1735      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");      EsysAssert((dataT!=0), "Programming error - casting data to DataTagged.");
1736      EsysAssert((resultT!=0), "Programming error - casting result to DataTagged.");      DataTypes::ValueType defval(1);
1737        defval[0]=0;
1738        DataTagged* resultT=new DataTagged(getFunctionSpace(), DataTypes::scalarShape, defval, dataT);
1739      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);      escript::dp_algorithm(*dataT,*resultT,operation,initial_value);
1740      return result;      return Data(resultT);   // note: the Data object now owns the resultT pointer
1741    } else if (isConstant()) {    }
1742      Data result(0,DataArrayView::ShapeType(),getFunctionSpace(),isExpanded());    else if (isConstant()) {
1743        Data result(0,DataTypes::ShapeType(),getFunctionSpace(),isExpanded());
1744      DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());      DataConstant* dataC=dynamic_cast<DataConstant*>(m_data.get());
1745      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());      DataConstant* resultC=dynamic_cast<DataConstant*>(result.m_data.get());
1746      EsysAssert((dataC!=0), "Programming error - casting data to DataConstant.");      EsysAssert((dataC!=0), "Programming error - casting data to DataConstant.");
# Line 1703  Data::dp_algorithm(BinaryFunction operat Line 1752  Data::dp_algorithm(BinaryFunction operat
1752    return falseRetVal;    return falseRetVal;
1753  }  }
1754    
1755    /**
1756      \brief
1757      Compute a tensor operation with two Data objects
1758      \param arg0 - Input - Data object
1759      \param arg1 - Input - Data object
1760      \param operation - Input - Binary op functor
1761    */
1762  template <typename BinaryFunction>  template <typename BinaryFunction>
1763    inline
1764  Data  Data
1765  C_TensorBinaryOperation(Data const &arg_0,  C_TensorBinaryOperation(Data const &arg_0,
1766                          Data const &arg_1,                          Data const &arg_1,
1767                          BinaryFunction operation)                          BinaryFunction operation)
1768  {  {
1769      if (arg_0.isEmpty() || arg_1.isEmpty())
1770      {
1771         throw DataException("Error - Operations not permitted on instances of DataEmpty.");
1772      }
1773    // Interpolate if necessary and find an appropriate function space    // Interpolate if necessary and find an appropriate function space
1774    Data arg_0_Z, arg_1_Z;    Data arg_0_Z, arg_1_Z;
1775    if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {    if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
# Line 1730  C_TensorBinaryOperation(Data const &arg_ Line 1791  C_TensorBinaryOperation(Data const &arg_
1791    // Get rank and shape of inputs    // Get rank and shape of inputs
1792    int rank0 = arg_0_Z.getDataPointRank();    int rank0 = arg_0_Z.getDataPointRank();
1793    int rank1 = arg_1_Z.getDataPointRank();    int rank1 = arg_1_Z.getDataPointRank();
1794    DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();    DataTypes::ShapeType shape0 = arg_0_Z.getDataPointShape();
1795    DataArrayView::ShapeType shape1 = arg_1_Z.getDataPointShape();    DataTypes::ShapeType shape1 = arg_1_Z.getDataPointShape();
1796    int size0 = arg_0_Z.getDataPointSize();    int size0 = arg_0_Z.getDataPointSize();
1797    int size1 = arg_1_Z.getDataPointSize();    int size1 = arg_1_Z.getDataPointSize();
1798    
# Line 1742  C_TensorBinaryOperation(Data const &arg_ Line 1803  C_TensorBinaryOperation(Data const &arg_
1803    
1804      if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {      if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
1805        res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output        res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
1806        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);  /*      double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
1807        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
1808        double *ptr_2 = &((res.getPointDataView().getData())[0]);        double *ptr_2 = &((res.getPointDataView().getData())[0]);*/
1809          double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
1810          double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
1811          double *ptr_2 = &(res.getDataAtOffset(0));
1812    
1813        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1814      }      }
1815      else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {      else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
# Line 1762  C_TensorBinaryOperation(Data const &arg_ Line 1827  C_TensorBinaryOperation(Data const &arg_
1827    
1828        // Prepare offset into DataConstant        // Prepare offset into DataConstant
1829        int offset_0 = tmp_0->getPointOffset(0,0);        int offset_0 = tmp_0->getPointOffset(0,0);
1830        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);        double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1831        // Get the views        // Get the views
1832        DataArrayView view_1 = tmp_1->getDefaultValue();  //       DataArrayView view_1 = tmp_1->getDefaultValue();
1833        DataArrayView view_2 = tmp_2->getDefaultValue();  //       DataArrayView view_2 = tmp_2->getDefaultValue();
1834    //       // Get the pointers to the actual data
1835    //       double *ptr_1 = &((view_1.getData())[0]);
1836    //       double *ptr_2 = &((view_2.getData())[0]);
1837    
1838        // Get the pointers to the actual data        // Get the pointers to the actual data
1839        double *ptr_1 = &((view_1.getData())[0]);        double *ptr_1 = &(tmp_1->getDefaultValue(0));
1840        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &(tmp_2->getDefaultValue(0));
1841    
1842        // Compute a result for the default        // Compute a result for the default
1843        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1844        // Compute a result for each tag        // Compute a result for each tag
1845        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1846        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1847        for (i=lookup_1.begin();i!=lookup_1.end();i++) {        for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1848          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
1849          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);  /*        DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1850          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1851          double *ptr_1 = &view_1.getData(0);          double *ptr_1 = &view_1.getData(0);
1852          double *ptr_2 = &view_2.getData(0);          double *ptr_2 = &view_2.getData(0);*/
1853            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1854            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1855    
1856          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1857        }        }
1858    
# Line 1800  C_TensorBinaryOperation(Data const &arg_ Line 1873  C_TensorBinaryOperation(Data const &arg_
1873          for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {          for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
1874            int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);            int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
1875            int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);            int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
1876            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);  //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
1877            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);  //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1878            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);  //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
1879    
1880              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
1881              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
1882              double *ptr_2 = &(res.getDataAtOffset(offset_2));
1883            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1884          }          }
1885        }        }
# Line 1823  C_TensorBinaryOperation(Data const &arg_ Line 1900  C_TensorBinaryOperation(Data const &arg_
1900    
1901        // Prepare offset into DataConstant        // Prepare offset into DataConstant
1902        int offset_1 = tmp_1->getPointOffset(0,0);        int offset_1 = tmp_1->getPointOffset(0,0);
1903        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);  //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
1904          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
1905        // Get the views        // Get the views
1906        DataArrayView view_0 = tmp_0->getDefaultValue();  //       DataArrayView view_0 = tmp_0->getDefaultValue();
1907        DataArrayView view_2 = tmp_2->getDefaultValue();  //       DataArrayView view_2 = tmp_2->getDefaultValue();
1908    //       // Get the pointers to the actual data
1909    //       double *ptr_0 = &((view_0.getData())[0]);
1910    //       double *ptr_2 = &((view_2.getData())[0]);
1911        // Get the pointers to the actual data        // Get the pointers to the actual data
1912        double *ptr_0 = &((view_0.getData())[0]);        double *ptr_0 = &(tmp_0->getDefaultValue(0));
1913        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &(tmp_2->getDefaultValue(0));
1914        // Compute a result for the default        // Compute a result for the default
1915        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1916        // Compute a result for each tag        // Compute a result for each tag
1917        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1918        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
1919        for (i=lookup_0.begin();i!=lookup_0.end();i++) {        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1920          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
1921          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1922          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);  //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1923          double *ptr_0 = &view_0.getData(0);  //         double *ptr_0 = &view_0.getData(0);
1924          double *ptr_2 = &view_2.getData(0);  //         double *ptr_2 = &view_2.getData(0);
1925            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
1926            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1927          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1928        }        }
1929    
# Line 1858  C_TensorBinaryOperation(Data const &arg_ Line 1941  C_TensorBinaryOperation(Data const &arg_
1941        res.tag();        // DataTagged output        res.tag();        // DataTagged output
1942        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
1943    
1944        // Get the views  //       // Get the views
1945        DataArrayView view_0 = tmp_0->getDefaultValue();  //       DataArrayView view_0 = tmp_0->getDefaultValue();
1946        DataArrayView view_1 = tmp_1->getDefaultValue();  //       DataArrayView view_1 = tmp_1->getDefaultValue();
1947        DataArrayView view_2 = tmp_2->getDefaultValue();  //       DataArrayView view_2 = tmp_2->getDefaultValue();
1948    //       // Get the pointers to the actual data
1949    //       double *ptr_0 = &((view_0.getData())[0]);
1950    //       double *ptr_1 = &((view_1.getData())[0]);
1951    //       double *ptr_2 = &((view_2.getData())[0]);
1952    
1953        // Get the pointers to the actual data        // Get the pointers to the actual data
1954        double *ptr_0 = &((view_0.getData())[0]);        double *ptr_0 = &(tmp_0->getDefaultValue(0));
1955        double *ptr_1 = &((view_1.getData())[0]);        double *ptr_1 = &(tmp_1->getDefaultValue(0));
1956        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &(tmp_2->getDefaultValue(0));
1957    
1958        // Compute a result for the default        // Compute a result for the default
1959        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1960        // Merge the tags        // Merge the tags
# Line 1873  C_TensorBinaryOperation(Data const &arg_ Line 1962  C_TensorBinaryOperation(Data const &arg_
1962        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
1963        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
1964        for (i=lookup_0.begin();i!=lookup_0.end();i++) {        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
1965          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape          tmp_2->addTag(i->first); // use tmp_2 to get correct shape
1966        }        }
1967        for (i=lookup_1.begin();i!=lookup_1.end();i++) {        for (i=lookup_1.begin();i!=lookup_1.end();i++) {
1968          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
1969        }        }
1970        // Compute a result for each tag        // Compute a result for each tag
1971        const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();        const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
1972        for (i=lookup_2.begin();i!=lookup_2.end();i++) {        for (i=lookup_2.begin();i!=lookup_2.end();i++) {
1973          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  
1974          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);  //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
1975          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);  //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
1976          double *ptr_0 = &view_0.getData(0);  //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
1977          double *ptr_1 = &view_1.getData(0);  //         double *ptr_0 = &view_0.getData(0);
1978          double *ptr_2 = &view_2.getData(0);  //         double *ptr_1 = &view_1.getData(0);
1979    //         double *ptr_2 = &view_2.getData(0);
1980    
1981            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
1982            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
1983            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
1984    
1985          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);          tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
1986        }        }
1987    
# Line 1905  C_TensorBinaryOperation(Data const &arg_ Line 2000  C_TensorBinaryOperation(Data const &arg_
2000        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2001        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2002          int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0          int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2003          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2004          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2005            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2006            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2007            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);  
2008            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);  //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2009    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2010              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2011              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2012    
2013    
2014            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2015          }          }
2016        }        }
# Line 1932  C_TensorBinaryOperation(Data const &arg_ Line 2032  C_TensorBinaryOperation(Data const &arg_
2032          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2033            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2034            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2035            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);  
2036            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);  //           double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2037            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);  //           double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2038    //           double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2039    
2040              double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2041              double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2042              double *ptr_2 = &(res.getDataAtOffset(offset_2));
2043    
2044    
2045            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2046          }          }
2047        }        }
# Line 1954  C_TensorBinaryOperation(Data const &arg_ Line 2061  C_TensorBinaryOperation(Data const &arg_
2061        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2062        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2063          int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);          int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2064          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2065          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2066            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2067            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2068            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2069            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2070            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2071          }          }
2072        }        }
# Line 1982  C_TensorBinaryOperation(Data const &arg_ Line 2089  C_TensorBinaryOperation(Data const &arg_
2089            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2090            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2091            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2092            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2093            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2094            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2095            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1, ptr_2, operation);
2096          }          }
2097        }        }
# Line 1998  C_TensorBinaryOperation(Data const &arg_ Line 2105  C_TensorBinaryOperation(Data const &arg_
2105    
2106      if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {      if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2107        res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output        res = Data(0.0, shape1, arg_1_Z.getFunctionSpace());      // DataConstant output
2108        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);        double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2109        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);        double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2110        double *ptr_2 = &((res.getPointDataView().getData())[0]);        double *ptr_2 = &(res.getDataAtOffset(0));
2111        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2112      }      }
2113      else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {      else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
# Line 2018  C_TensorBinaryOperation(Data const &arg_ Line 2125  C_TensorBinaryOperation(Data const &arg_
2125    
2126        // Prepare offset into DataConstant        // Prepare offset into DataConstant
2127        int offset_0 = tmp_0->getPointOffset(0,0);        int offset_0 = tmp_0->getPointOffset(0,0);
2128        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);        double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2129        // Get the views        // Get the views
2130        DataArrayView view_1 = tmp_1->getDefaultValue();  //       DataArrayView view_1 = tmp_1->getDefaultValue();
2131        DataArrayView view_2 = tmp_2->getDefaultValue();  //       DataArrayView view_2 = tmp_2->getDefaultValue();
2132        // Get the pointers to the actual data  //       // Get the pointers to the actual data
2133        double *ptr_1 = &((view_1.getData())[0]);  //       double *ptr_1 = &((view_1.getData())[0]);
2134        double *ptr_2 = &((view_2.getData())[0]);  //       double *ptr_2 = &((view_2.getData())[0]);
2135           double *ptr_1 = &(tmp_1->getDefaultValue(0));
2136           double *ptr_2 = &(tmp_2->getDefaultValue(0));
2137    
2138        // Compute a result for the default        // Compute a result for the default
2139        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2140        // Compute a result for each tag        // Compute a result for each tag
2141        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2142        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2143        for (i=lookup_1.begin();i!=lookup_1.end();i++) {        for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2144          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
2145          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);  //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2146          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);  //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2147          double *ptr_1 = &view_1.getData(0);  //         double *ptr_1 = &view_1.getData(0);
2148          double *ptr_2 = &view_2.getData(0);  //         double *ptr_2 = &view_2.getData(0);
2149            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2150            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2151          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2152        }        }
2153    
# Line 2056  C_TensorBinaryOperation(Data const &arg_ Line 2168  C_TensorBinaryOperation(Data const &arg_
2168          for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {          for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2169            int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);            int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2170            int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);            int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2171            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2172            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2173            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2174            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2175    
2176          }          }
# Line 2080  C_TensorBinaryOperation(Data const &arg_ Line 2192  C_TensorBinaryOperation(Data const &arg_
2192    
2193        // Prepare offset into DataConstant        // Prepare offset into DataConstant
2194        int offset_1 = tmp_1->getPointOffset(0,0);        int offset_1 = tmp_1->getPointOffset(0,0);
2195        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);  //       double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2196          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2197        // Get the views        // Get the views
2198        DataArrayView view_0 = tmp_0->getDefaultValue();  /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2199        DataArrayView view_2 = tmp_2->getDefaultValue();        DataArrayView view_2 = tmp_2->getDefaultValue();
2200        // Get the pointers to the actual data        // Get the pointers to the actual data
2201        double *ptr_0 = &((view_0.getData())[0]);        double *ptr_0 = &((view_0.getData())[0]);
2202        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &((view_2.getData())[0]);*/
2203    
2204          // Get the pointers to the actual data
2205          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2206          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2207    
2208    
2209        // Compute a result for the default        // Compute a result for the default
2210        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2211        // Compute a result for each tag        // Compute a result for each tag
2212        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2213        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2214        for (i=lookup_0.begin();i!=lookup_0.end();i++) {        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2215          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
2216          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2217          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2218          double *ptr_0 = &view_0.getData(0);          double *ptr_0 = &view_0.getData(0);
2219          double *ptr_2 = &view_2.getData(0);          double *ptr_2 = &view_2.getData(0);*/
2220            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2221            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2222    
2223          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2224        }        }
2225    
# Line 2116  C_TensorBinaryOperation(Data const &arg_ Line 2238  C_TensorBinaryOperation(Data const &arg_
2238        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2239    
2240        // Get the views        // Get the views
2241        DataArrayView view_0 = tmp_0->getDefaultValue();  /*      DataArrayView view_0 = tmp_0->getDefaultValue();
2242        DataArrayView view_1 = tmp_1->getDefaultValue();        DataArrayView view_1 = tmp_1->getDefaultValue();
2243        DataArrayView view_2 = tmp_2->getDefaultValue();        DataArrayView view_2 = tmp_2->getDefaultValue();
2244        // Get the pointers to the actual data        // Get the pointers to the actual data
2245        double *ptr_0 = &((view_0.getData())[0]);        double *ptr_0 = &((view_0.getData())[0]);
2246        double *ptr_1 = &((view_1.getData())[0]);        double *ptr_1 = &((view_1.getData())[0]);
2247        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &((view_2.getData())[0]);*/
2248    
2249          // Get the pointers to the actual data
2250          double *ptr_0 = &(tmp_0->getDefaultValue(0));
2251          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2252          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2253    
2254    
2255        // Compute a result for the default        // Compute a result for the default
2256        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);        tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2257        // Merge the tags        // Merge the tags
# Line 2130  C_TensorBinaryOperation(Data const &arg_ Line 2259  C_TensorBinaryOperation(Data const &arg_
2259        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2260        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2261        for (i=lookup_0.begin();i!=lookup_0.end();i++) {        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2262          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape          tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2263        }        }
2264        for (i=lookup_1.begin();i!=lookup_1.end();i++) {        for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2265          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
2266        }        }
2267        // Compute a result for each tag        // Compute a result for each tag
2268        const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();        const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2269        for (i=lookup_2.begin();i!=lookup_2.end();i++) {        for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2270          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  
2271    /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2272          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2273          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2274          double *ptr_0 = &view_0.getData(0);          double *ptr_0 = &view_0.getData(0);
2275          double *ptr_1 = &view_1.getData(0);          double *ptr_1 = &view_1.getData(0);
2276          double *ptr_2 = &view_2.getData(0);          double *ptr_2 = &view_2.getData(0);*/
2277    
2278            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2279            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2280            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2281    
2282          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);          tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2283        }        }
2284    
# Line 2162  C_TensorBinaryOperation(Data const &arg_ Line 2297  C_TensorBinaryOperation(Data const &arg_
2297        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2298        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2299          int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0          int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2300          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2301          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2302            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2303            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2304            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2305            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2306            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2307          }          }
2308        }        }
# Line 2189  C_TensorBinaryOperation(Data const &arg_ Line 2324  C_TensorBinaryOperation(Data const &arg_
2324          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2325            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2326            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2327            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2328            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2329            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2330            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2331          }          }
2332        }        }
# Line 2212  C_TensorBinaryOperation(Data const &arg_ Line 2347  C_TensorBinaryOperation(Data const &arg_
2347        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2348        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2349          int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);          int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2350          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2351          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2352            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2353            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2354            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2355            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2356            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2357          }          }
2358        }        }
# Line 2240  C_TensorBinaryOperation(Data const &arg_ Line 2375  C_TensorBinaryOperation(Data const &arg_
2375            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2376            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2377            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2378            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2379            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2380            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2381            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);            tensor_binary_operation(size1, ptr_0[0], ptr_1, ptr_2, operation);
2382          }          }
2383        }        }
# Line 2256  C_TensorBinaryOperation(Data const &arg_ Line 2391  C_TensorBinaryOperation(Data const &arg_
2391    
2392      if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {      if (arg_0_Z.isConstant()   && arg_1_Z.isConstant()) {
2393        res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output        res = Data(0.0, shape0, arg_1_Z.getFunctionSpace());      // DataConstant output
2394        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);        double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2395        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);        double *ptr_1 = &(arg_1_Z.getDataAtOffset(0));
2396        double *ptr_2 = &((res.getPointDataView().getData())[0]);        double *ptr_2 = &(res.getDataAtOffset(0));
2397        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2398      }      }
2399      else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {      else if (arg_0_Z.isConstant()   && arg_1_Z.isTagged()) {
# Line 2276  C_TensorBinaryOperation(Data const &arg_ Line 2411  C_TensorBinaryOperation(Data const &arg_
2411    
2412        // Prepare offset into DataConstant        // Prepare offset into DataConstant
2413        int offset_0 = tmp_0->getPointOffset(0,0);        int offset_0 = tmp_0->getPointOffset(0,0);
2414        double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);        double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2415        // Get the views        // Get the views
2416        DataArrayView view_1 = tmp_1->getDefaultValue();  /*      DataArrayView view_1 = tmp_1->getDefaultValue();
2417        DataArrayView view_2 = tmp_2->getDefaultValue();        DataArrayView view_2 = tmp_2->getDefaultValue();
2418        // Get the pointers to the actual data        // Get the pointers to the actual data
2419        double *ptr_1 = &((view_1.getData())[0]);        double *ptr_1 = &((view_1.getData())[0]);
2420        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &((view_2.getData())[0]);*/
2421          //Get the pointers to the actual data
2422          double *ptr_1 = &(tmp_1->getDefaultValue(0));
2423          double *ptr_2 = &(tmp_2->getDefaultValue(0));
2424    
2425        // Compute a result for the default        // Compute a result for the default
2426        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2427        // Compute a result for each tag        // Compute a result for each tag
2428        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2429        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2430        for (i=lookup_1.begin();i!=lookup_1.end();i++) {        for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2431          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
2432          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);  //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2433          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);  //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2434          double *ptr_1 = &view_1.getData(0);  //         double *ptr_1 = &view_1.getData(0);
2435          double *ptr_2 = &view_2.getData(0);  //         double *ptr_2 = &view_2.getData(0);
2436            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2437            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2438    
2439    
2440          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2441        }        }
2442    
# Line 2314  C_TensorBinaryOperation(Data const &arg_ Line 2457  C_TensorBinaryOperation(Data const &arg_
2457          for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {          for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2458            int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);            int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2459            int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);            int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2460            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2461            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2462            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2463            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2464          }          }
2465        }        }
# Line 2337  C_TensorBinaryOperation(Data const &arg_ Line 2480  C_TensorBinaryOperation(Data const &arg_
2480    
2481        // Prepare offset into DataConstant        // Prepare offset into DataConstant
2482        int offset_1 = tmp_1->getPointOffset(0,0);        int offset_1 = tmp_1->getPointOffset(0,0);
2483        double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);        double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2484        // Get the views        // Get the views
2485        DataArrayView view_0 = tmp_0->getDefaultValue();  //       DataArrayView view_0 = tmp_0->getDefaultValue();
2486        DataArrayView view_2 = tmp_2->getDefaultValue();  //       DataArrayView view_2 = tmp_2->getDefaultValue();
2487    //       // Get the pointers to the actual data
2488    //       double *ptr_0 = &((view_0.getData())[0]);
2489    //       double *ptr_2 = &((view_2.getData())[0]);
2490        // Get the pointers to the actual data        // Get the pointers to the actual data
2491        double *ptr_0 = &((view_0.getData())[0]);        double *ptr_0 = &(tmp_0->getDefaultValue(0));
2492        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &(tmp_2->getDefaultValue(0));
2493        // Compute a result for the default        // Compute a result for the default
2494        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2495        // Compute a result for each tag        // Compute a result for each tag
2496        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2497        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory        DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2498        for (i=lookup_0.begin();i!=lookup_0.end();i++) {        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2499          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
2500          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  /*        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2501          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2502          double *ptr_0 = &view_0.getData(0);          double *ptr_0 = &view_0.getData(0);
2503          double *ptr_2 = &view_2.getData(0);          double *ptr_2 = &view_2.getData(0);*/
2504            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2505            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2506          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2507        }        }
2508    
# Line 2373  C_TensorBinaryOperation(Data const &arg_ Line 2521  C_TensorBinaryOperation(Data const &arg_
2521        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());        DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2522    
2523        // Get the views        // Get the views
2524        DataArrayView view_0 = tmp_0->getDefaultValue();  //       DataArrayView view_0 = tmp_0->getDefaultValue();
2525        DataArrayView view_1 = tmp_1->getDefaultValue();  //       DataArrayView view_1 = tmp_1->getDefaultValue();
2526        DataArrayView view_2 = tmp_2->getDefaultValue();  //       DataArrayView view_2 = tmp_2->getDefaultValue();
2527    //       // Get the pointers to the actual data
2528    //       double *ptr_0 = &((view_0.getData())[0]);
2529    //       double *ptr_1 = &((view_1.getData())[0]);
2530    //       double *ptr_2 = &((view_2.getData())[0]);
2531    
2532        // Get the pointers to the actual data        // Get the pointers to the actual data
2533        double *ptr_0 = &((view_0.getData())[0]);        double *ptr_0 = &(tmp_0->getDefaultValue(0));
2534        double *ptr_1 = &((view_1.getData())[0]);        double *ptr_1 = &(tmp_1->getDefaultValue(0));
2535        double *ptr_2 = &((view_2.getData())[0]);        double *ptr_2 = &(tmp_2->getDefaultValue(0));
2536    
2537        // Compute a result for the default        // Compute a result for the default
2538        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);        tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2539        // Merge the tags        // Merge the tags
# Line 2387  C_TensorBinaryOperation(Data const &arg_ Line 2541  C_TensorBinaryOperation(Data const &arg_
2541        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();        const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2542        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();        const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2543        for (i=lookup_0.begin();i!=lookup_0.end();i++) {        for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2544          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape          tmp_2->addTag(i->first); // use tmp_2 to get correct shape
2545        }        }
2546        for (i=lookup_1.begin();i!=lookup_1.end();i++) {        for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2547          tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());          tmp_2->addTag(i->first);
2548        }        }
2549        // Compute a result for each tag        // Compute a result for each tag
2550        const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();        const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2551        for (i=lookup_2.begin();i!=lookup_2.end();i++) {        for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2552          DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  //         DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2553          DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);  //         DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2554          DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);  //         DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2555          double *ptr_0 = &view_0.getData(0);  //         double *ptr_0 = &view_0.getData(0);
2556          double *ptr_1 = &view_1.getData(0);  //         double *ptr_1 = &view_1.getData(0);
2557          double *ptr_2 = &view_2.getData(0);  //         double *ptr_2 = &view_2.getData(0);
2558    
2559            double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2560            double *ptr_1 = &(tmp_1->getDataByTag(i->first,0));
2561            double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2562          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);          tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2563        }        }
2564    
# Line 2419  C_TensorBinaryOperation(Data const &arg_ Line 2577  C_TensorBinaryOperation(Data const &arg_
2577        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2578        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2579          int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0          int offset_0 = tmp_0->getPointOffset(sampleNo_0,0); // They're all the same, so just use #0
2580          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2581          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2582            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2583            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2584            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2585            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2586            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2587          }          }
2588        }        }
# Line 2446  C_TensorBinaryOperation(Data const &arg_ Line 2604  C_TensorBinaryOperation(Data const &arg_
2604          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2605            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2606            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2607            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2608            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2609            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2610            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2611          }          }
2612        }        }
# Line 2469  C_TensorBinaryOperation(Data const &arg_ Line 2627  C_TensorBinaryOperation(Data const &arg_
2627        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)        #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2628        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {        for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2629          int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);          int offset_1 = tmp_1->getPointOffset(sampleNo_0,0);
2630          double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);          double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2631          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {          for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2632            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2633            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2634            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2635            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2636            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2637          }          }
2638        }        }
# Line 2497  C_TensorBinaryOperation(Data const &arg_ Line 2655  C_TensorBinaryOperation(Data const &arg_
2655            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2656            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_1 = tmp_1->getPointOffset(sampleNo_0,dataPointNo_0);
2657            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);            int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2658            double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);            double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2659            double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);            double *ptr_1 = &(arg_1_Z.getDataAtOffset(offset_1));
2660            double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);            double *ptr_2 = &(res.getDataAtOffset(offset_2));
2661            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);            tensor_binary_operation(size0, ptr_0, ptr_1[0], ptr_2, operation);
2662          }          }
2663        }        }
# Line 2521  Data Line 2679  Data
2679  C_TensorUnaryOperation(Data const &arg_0,  C_TensorUnaryOperation(Data const &arg_0,
2680                         UnaryFunction operation)                         UnaryFunction operation)
2681  {  {
2682      if (arg_0.isEmpty())  // do this before we attempt to interpolate
2683      {
2684         throw DataException("Error - Operations not permitted on instances of DataEmpty.");
2685      }
2686    
2687    // Interpolate if necessary and find an appropriate function space    // Interpolate if necessary and find an appropriate function space
2688    Data arg_0_Z = Data(arg_0);    Data arg_0_Z = Data(arg_0);
2689    
2690    // Get rank and shape of inputs    // Get rank and shape of inputs
2691    int rank0 = arg_0_Z.getDataPointRank();    int rank0 = arg_0_Z.getDataPointRank();
2692    DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();    const DataTypes::ShapeType& shape0 = arg_0_Z.getDataPointShape();
2693    int size0 = arg_0_Z.getDataPointSize();    int size0 = arg_0_Z.getDataPointSize();
2694    
2695    // Declare output Data object    // Declare output Data object
# Line 2534  C_TensorUnaryOperation(Data const &arg_0 Line 2697  C_TensorUnaryOperation(Data const &arg_0
2697    
2698    if (arg_0_Z.isConstant()) {    if (arg_0_Z.isConstant()) {
2699      res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output      res = Data(0.0, shape0, arg_0_Z.getFunctionSpace());      // DataConstant output
2700      double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);  //     double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2701      double *ptr_2 = &((res.getPointDataView().getData())[0]);  //     double *ptr_2 = &((res.getPointDataView().getData())[0]);
2702        double *ptr_0 = &(arg_0_Z.getDataAtOffset(0));
2703        double *ptr_2 = &(res.getDataAtOffset(0));
2704      tensor_unary_operation(size0, ptr_0, ptr_2, operation);      tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2705    }    }
2706    else if (arg_0_Z.isTagged()) {    else if (arg_0_Z.isTagged()) {
# Line 2548  C_TensorUnaryOperation(Data const &arg_0 Line 2713  C_TensorUnaryOperation(Data const &arg_0
2713      res.tag();      res.tag();
2714      DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());      DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2715    
2716      // Get the views  //     // Get the views
2717      DataArrayView view_0 = tmp_0->getDefaultValue();  //     DataArrayView view_0 = tmp_0->getDefaultValue();
2718      DataArrayView view_2 = tmp_2->getDefaultValue();  //     DataArrayView view_2 = tmp_2->getDefaultValue();
2719    //     // Get the pointers to the actual data
2720    //     double *ptr_0 = &((view_0.getData())[0]);
2721    //     double *ptr_2 = &((view_2.getData())[0]);
2722      // Get the pointers to the actual data      // Get the pointers to the actual data
2723      double *ptr_0 = &((view_0.getData())[0]);      double *ptr_0 = &(tmp_0->getDefaultValue(0));
2724      double *ptr_2 = &((view_2.getData())[0]);      double *ptr_2 = &(tmp_2->getDefaultValue(0));
2725      // Compute a result for the default      // Compute a result for the default
2726      tensor_unary_operation(size0, ptr_0, ptr_2, operation);      tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2727      // Compute a result for each tag      // Compute a result for each tag
2728      const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();      const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2729      DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory      DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2730      for (i=lookup_0.begin();i!=lookup_0.end();i++) {      for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2731        tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());        tmp_2->addTag(i->first);
2732        DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);  //       DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2733        DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);  //       DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2734        double *ptr_0 = &view_0.getData(0);  //       double *ptr_0 = &view_0.getData(0);
2735        double *ptr_2 = &view_2.getData(0);  //       double *ptr_2 = &view_2.getData(0);
2736          double *ptr_0 = &(tmp_0->getDataByTag(i->first,0));
2737          double *ptr_2 = &(tmp_2->getDataByTag(i->first,0));
2738        tensor_unary_operation(size0, ptr_0, ptr_2, operation);        tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2739      }      }
2740    
# Line 2581  C_TensorUnaryOperation(Data const &arg_0 Line 2751  C_TensorUnaryOperation(Data const &arg_0
2751      #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)      #pragma omp parallel for private(sampleNo_0,dataPointNo_0) schedule(static)
2752      for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {      for (sampleNo_0 = 0; sampleNo_0 < numSamples_0; sampleNo_0++) {
2753        for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {        for (dataPointNo_0 = 0; dataPointNo_0 < numDataPointsPerSample_0; dataPointNo_0++) {
2754    //         int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2755    //         int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2756    //         double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2757    //         double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2758          int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);          int offset_0 = tmp_0->getPointOffset(sampleNo_0,dataPointNo_0);
2759          int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);          int offset_2 = tmp_2->getPointOffset(sampleNo_0,dataPointNo_0);
2760          double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);          double *ptr_0 = &(arg_0_Z.getDataAtOffset(offset_0));
2761          double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);          double *ptr_2 = &(res.getDataAtOffset(offset_2));
2762          tensor_unary_operation(size0, ptr_0, ptr_2, operation);          tensor_unary_operation(size0, ptr_0, ptr_2, operation);
2763        }        }
2764      }      }
   
2765    }    }
2766    else {    else {
2767      throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");      throw DataException("Error - C_TensorUnaryOperation: unknown combination of inputs");

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

  ViewVC Help
Powered by ViewVC 1.1.26