/[escript]/trunk/escript/src/Data.cpp
ViewVC logotype

Annotation of /trunk/escript/src/Data.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1092 - (hide annotations)
Fri Apr 13 03:39:49 2007 UTC (15 years, 11 months ago) by gross
File size: 74839 byte(s)
the useless profilinf for data.cpp removed (doDebug=yes should work again)
and a small bug in the gmsh reader fixed.

1 jgs 94 // $Id$
2 jgs 480
3 elspeth 615 /*
4     ************************************************************
5     * Copyright 2006 by ACcESS MNRF *
6     * *
7     * http://www.access.edu.au *
8     * Primary Business: Queensland, Australia *
9     * Licensed under the Open Software License version 3.0 *
10     * http://www.opensource.org/licenses/osl-3.0.php *
11     * *
12     ************************************************************
13     */
14 jgs 474 #include "Data.h"
15 jgs 94
16 jgs 480 #include "DataExpanded.h"
17     #include "DataConstant.h"
18     #include "DataTagged.h"
19     #include "DataEmpty.h"
20     #include "DataArray.h"
21     #include "DataArrayView.h"
22     #include "DataProf.h"
23     #include "FunctionSpaceFactory.h"
24     #include "AbstractContinuousDomain.h"
25     #include "UnaryFuncs.h"
26    
27 jgs 119 #include <fstream>
28 jgs 94 #include <algorithm>
29     #include <vector>
30     #include <functional>
31    
32 jgs 153 #include <boost/python/dict.hpp>
33 jgs 94 #include <boost/python/extract.hpp>
34     #include <boost/python/long.hpp>
35    
36     using namespace std;
37     using namespace boost::python;
38     using namespace boost;
39     using namespace escript;
40    
41     Data::Data()
42     {
43     //
44     // Default data is type DataEmpty
45     DataAbstract* temp=new DataEmpty();
46 jgs 102 shared_ptr<DataAbstract> temp_data(temp);
47     m_data=temp_data;
48 gross 783 m_protected=false;
49 jgs 94 }
50    
51     Data::Data(double value,
52     const tuple& shape,
53     const FunctionSpace& what,
54     bool expanded)
55     {
56     DataArrayView::ShapeType dataPointShape;
57     for (int i = 0; i < shape.attr("__len__")(); ++i) {
58     dataPointShape.push_back(extract<const int>(shape[i]));
59     }
60     DataArray temp(dataPointShape,value);
61     initialise(temp.getView(),what,expanded);
62 gross 783 m_protected=false;
63 jgs 94 }
64    
65     Data::Data(double value,
66     const DataArrayView::ShapeType& dataPointShape,
67     const FunctionSpace& what,
68     bool expanded)
69     {
70     DataArray temp(dataPointShape,value);
71     pair<int,int> dataShape=what.getDataShape();
72     initialise(temp.getView(),what,expanded);
73 gross 783 m_protected=false;
74 jgs 94 }
75    
76 jgs 102 Data::Data(const Data& inData)
77 jgs 94 {
78 jgs 102 m_data=inData.m_data;
79 gross 783 m_protected=inData.isProtected();
80 jgs 94 }
81    
82     Data::Data(const Data& inData,
83     const DataArrayView::RegionType& region)
84     {
85     //
86 jgs 102 // Create Data which is a slice of another Data
87     DataAbstract* tmp = inData.m_data->getSlice(region);
88     shared_ptr<DataAbstract> temp_data(tmp);
89     m_data=temp_data;
90 gross 783 m_protected=false;
91 jgs 94 }
92    
93     Data::Data(const Data& inData,
94     const FunctionSpace& functionspace)
95     {
96     if (inData.getFunctionSpace()==functionspace) {
97     m_data=inData.m_data;
98     } else {
99     Data tmp(0,inData.getPointDataView().getShape(),functionspace,true);
100 jgs 123 // Note: Must use a reference or pointer to a derived object
101 jgs 94 // in order to get polymorphic behaviour. Shouldn't really
102     // be able to create an instance of AbstractDomain but that was done
103 jgs 123 // as a boost:python work around which may no longer be required.
104 jgs 94 const AbstractDomain& inDataDomain=inData.getDomain();
105     if (inDataDomain==functionspace.getDomain()) {
106     inDataDomain.interpolateOnDomain(tmp,inData);
107     } else {
108     inDataDomain.interpolateACross(tmp,inData);
109     }
110     m_data=tmp.m_data;
111     }
112 gross 783 m_protected=false;
113 jgs 94 }
114    
115     Data::Data(const DataTagged::TagListType& tagKeys,
116     const DataTagged::ValueListType & values,
117     const DataArrayView& defaultValue,
118     const FunctionSpace& what,
119     bool expanded)
120     {
121     DataAbstract* temp=new DataTagged(tagKeys,values,defaultValue,what);
122 jgs 102 shared_ptr<DataAbstract> temp_data(temp);
123     m_data=temp_data;
124 gross 783 m_protected=false;
125 jgs 94 if (expanded) {
126     expand();
127     }
128     }
129    
130     Data::Data(const numeric::array& value,
131     const FunctionSpace& what,
132     bool expanded)
133     {
134     initialise(value,what,expanded);
135 gross 783 m_protected=false;
136 jgs 94 }
137    
138     Data::Data(const DataArrayView& value,
139     const FunctionSpace& what,
140     bool expanded)
141     {
142     initialise(value,what,expanded);
143 gross 783 m_protected=false;
144 jgs 94 }
145    
146     Data::Data(const object& value,
147     const FunctionSpace& what,
148     bool expanded)
149     {
150     numeric::array asNumArray(value);
151     initialise(asNumArray,what,expanded);
152 gross 783 m_protected=false;
153 jgs 94 }
154    
155     Data::Data(const object& value,
156     const Data& other)
157     {
158     //
159     // Create DataConstant using the given value and all other parameters
160     // copied from other. If value is a rank 0 object this Data
161     // will assume the point data shape of other.
162     DataArray temp(value);
163     if (temp.getView().getRank()==0) {
164     //
165     // Create a DataArray with the scalar value for all elements
166     DataArray temp2(other.getPointDataView().getShape(),temp.getView()());
167     initialise(temp2.getView(),other.getFunctionSpace(),false);
168     } else {
169     //
170     // Create a DataConstant with the same sample shape as other
171     initialise(temp.getView(),other.getFunctionSpace(),false);
172     }
173 gross 783 m_protected=false;
174 jgs 94 }
175    
176 jgs 151 Data::~Data()
177     {
178    
179     }
180    
181 jgs 94 escriptDataC
182     Data::getDataC()
183     {
184     escriptDataC temp;
185     temp.m_dataPtr=(void*)this;
186     return temp;
187     }
188    
189     escriptDataC
190     Data::getDataC() const
191     {
192     escriptDataC temp;
193     temp.m_dataPtr=(void*)this;
194     return temp;
195     }
196    
197 jgs 121 const boost::python::tuple
198 jgs 94 Data::getShapeTuple() const
199     {
200     const DataArrayView::ShapeType& shape=getDataPointShape();
201     switch(getDataPointRank()) {
202     case 0:
203     return make_tuple();
204     case 1:
205     return make_tuple(long_(shape[0]));
206     case 2:
207     return make_tuple(long_(shape[0]),long_(shape[1]));
208     case 3:
209     return make_tuple(long_(shape[0]),long_(shape[1]),long_(shape[2]));
210     case 4:
211     return make_tuple(long_(shape[0]),long_(shape[1]),long_(shape[2]),long_(shape[3]));
212     default:
213     throw DataException("Error - illegal Data rank.");
214     }
215     }
216    
217     void
218     Data::copy(const Data& other)
219     {
220     //
221     // Perform a deep copy
222     {
223     DataExpanded* temp=dynamic_cast<DataExpanded*>(other.m_data.get());
224     if (temp!=0) {
225     //
226     // Construct a DataExpanded copy
227     DataAbstract* newData=new DataExpanded(*temp);
228 jgs 102 shared_ptr<DataAbstract> temp_data(newData);
229     m_data=temp_data;
230 jgs 94 return;
231     }
232     }
233     {
234     DataTagged* temp=dynamic_cast<DataTagged*>(other.m_data.get());
235     if (temp!=0) {
236     //
237 jgs 102 // Construct a DataTagged copy
238 jgs 94 DataAbstract* newData=new DataTagged(*temp);
239 jgs 102 shared_ptr<DataAbstract> temp_data(newData);
240     m_data=temp_data;
241 jgs 94 return;
242     }
243     }
244     {
245     DataConstant* temp=dynamic_cast<DataConstant*>(other.m_data.get());
246     if (temp!=0) {
247     //
248     // Construct a DataConstant copy
249     DataAbstract* newData=new DataConstant(*temp);
250 jgs 102 shared_ptr<DataAbstract> temp_data(newData);
251     m_data=temp_data;
252 jgs 94 return;
253     }
254     }
255 jgs 102 {
256     DataEmpty* temp=dynamic_cast<DataEmpty*>(other.m_data.get());
257     if (temp!=0) {
258     //
259     // Construct a DataEmpty copy
260     DataAbstract* newData=new DataEmpty();
261     shared_ptr<DataAbstract> temp_data(newData);
262     m_data=temp_data;
263     return;
264     }
265     }
266 jgs 94 throw DataException("Error - Copy not implemented for this Data type.");
267     }
268    
269     void
270     Data::copyWithMask(const Data& other,
271     const Data& mask)
272     {
273     Data mask1;
274     Data mask2;
275    
276     mask1 = mask.wherePositive();
277     mask2.copy(mask1);
278    
279     mask1 *= other;
280     mask2 *= *this;
281     mask2 = *this - mask2;
282    
283     *this = mask1 + mask2;
284     }
285    
286     bool
287     Data::isExpanded() const
288     {
289     DataExpanded* temp=dynamic_cast<DataExpanded*>(m_data.get());
290     return (temp!=0);
291     }
292    
293     bool
294     Data::isTagged() const
295     {
296     DataTagged* temp=dynamic_cast<DataTagged*>(m_data.get());
297     return (temp!=0);
298     }
299    
300     bool
301     Data::isEmpty() const
302     {
303     DataEmpty* temp=dynamic_cast<DataEmpty*>(m_data.get());
304     return (temp!=0);
305     }
306    
307     bool
308     Data::isConstant() const
309     {
310     DataConstant* temp=dynamic_cast<DataConstant*>(m_data.get());
311     return (temp!=0);
312     }
313    
314     void
315 gross 783 Data::setProtection()
316     {
317     m_protected=true;
318     }
319    
320     bool
321     Data::isProtected() const
322     {
323     return m_protected;
324     }
325    
326    
327    
328     void
329 jgs 94 Data::expand()
330     {
331     if (isConstant()) {
332     DataConstant* tempDataConst=dynamic_cast<DataConstant*>(m_data.get());
333     DataAbstract* temp=new DataExpanded(*tempDataConst);
334 jgs 102 shared_ptr<DataAbstract> temp_data(temp);
335     m_data=temp_data;
336 jgs 94 } else if (isTagged()) {
337     DataTagged* tempDataTag=dynamic_cast<DataTagged*>(m_data.get());
338     DataAbstract* temp=new DataExpanded(*tempDataTag);
339 jgs 102 shared_ptr<DataAbstract> temp_data(temp);
340     m_data=temp_data;
341 jgs 94 } else if (isExpanded()) {
342     //
343     // do nothing
344     } else if (isEmpty()) {
345     throw DataException("Error - Expansion of DataEmpty not possible.");
346     } else {
347     throw DataException("Error - Expansion not implemented for this Data type.");
348     }
349     }
350    
351     void
352     Data::tag()
353     {
354     if (isConstant()) {
355     DataConstant* tempDataConst=dynamic_cast<DataConstant*>(m_data.get());
356     DataAbstract* temp=new DataTagged(*tempDataConst);
357 jgs 102 shared_ptr<DataAbstract> temp_data(temp);
358     m_data=temp_data;
359 jgs 94 } else if (isTagged()) {
360     // do nothing
361     } else if (isExpanded()) {
362     throw DataException("Error - Creating tag data from DataExpanded not possible.");
363     } else if (isEmpty()) {
364     throw DataException("Error - Creating tag data from DataEmpty not possible.");
365     } else {
366     throw DataException("Error - Tagging not implemented for this Data type.");
367     }
368     }
369    
370 gross 854 Data
371     Data::oneOver() const
372 jgs 102 {
373 gross 854 return escript::unaryOp(*this,bind1st(divides<double>(),1.));
374 jgs 102 }
375    
376 jgs 94 Data
377 gross 698 Data::wherePositive() const
378 jgs 94 {
379 gross 698 return escript::unaryOp(*this,bind2nd(greater<double>(),0.0));
380 jgs 94 }
381    
382     Data
383 gross 698 Data::whereNegative() const
384 jgs 102 {
385 gross 698 return escript::unaryOp(*this,bind2nd(less<double>(),0.0));
386 jgs 102 }
387    
388     Data
389 gross 698 Data::whereNonNegative() const
390 jgs 94 {
391 gross 698 return escript::unaryOp(*this,bind2nd(greater_equal<double>(),0.0));
392 jgs 94 }
393    
394     Data
395 gross 698 Data::whereNonPositive() const
396 jgs 94 {
397 gross 698 return escript::unaryOp(*this,bind2nd(less_equal<double>(),0.0));
398 jgs 94 }
399    
400     Data
401 jgs 571 Data::whereZero(double tol) const
402 jgs 94 {
403 jgs 571 Data dataAbs=abs();
404     return escript::unaryOp(dataAbs,bind2nd(less_equal<double>(),tol));
405 jgs 94 }
406    
407     Data
408 jgs 571 Data::whereNonZero(double tol) const
409 jgs 102 {
410 jgs 571 Data dataAbs=abs();
411     return escript::unaryOp(dataAbs,bind2nd(greater<double>(),tol));
412 jgs 102 }
413    
414     Data
415 jgs 94 Data::interpolate(const FunctionSpace& functionspace) const
416     {
417     return Data(*this,functionspace);
418     }
419    
420     bool
421     Data::probeInterpolation(const FunctionSpace& functionspace) const
422     {
423     if (getFunctionSpace()==functionspace) {
424     return true;
425     } else {
426     const AbstractDomain& domain=getDomain();
427     if (domain==functionspace.getDomain()) {
428     return domain.probeInterpolationOnDomain(getFunctionSpace().getTypeCode(),functionspace.getTypeCode());
429     } else {
430     return domain.probeInterpolationACross(getFunctionSpace().getTypeCode(),functionspace.getDomain(),functionspace.getTypeCode());
431     }
432     }
433     }
434    
435     Data
436     Data::gradOn(const FunctionSpace& functionspace) const
437     {
438     if (functionspace.getDomain()!=getDomain())
439     throw DataException("Error - gradient cannot be calculated on different domains.");
440     DataArrayView::ShapeType grad_shape=getPointDataView().getShape();
441     grad_shape.push_back(functionspace.getDim());
442     Data out(0.0,grad_shape,functionspace,true);
443     getDomain().setToGradient(out,*this);
444     return out;
445     }
446    
447     Data
448     Data::grad() const
449     {
450     return gradOn(escript::function(getDomain()));
451     }
452    
453     int
454     Data::getDataPointSize() const
455     {
456     return getPointDataView().noValues();
457     }
458    
459     DataArrayView::ValueType::size_type
460     Data::getLength() const
461     {
462     return m_data->getLength();
463     }
464    
465     const DataArrayView::ShapeType&
466     Data::getDataPointShape() const
467     {
468     return getPointDataView().getShape();
469     }
470    
471 gross 921
472    
473     const
474 jgs 121 boost::python::numeric::array
475 gross 921 Data:: getValueOfDataPoint(int dataPointNo)
476 jgs 121 {
477 gross 921 size_t length=0;
478     int i, j, k, l;
479 jgs 121 //
480     // determine the rank and shape of each data point
481     int dataPointRank = getDataPointRank();
482     DataArrayView::ShapeType dataPointShape = getDataPointShape();
483    
484     //
485     // create the numeric array to be returned
486     boost::python::numeric::array numArray(0.0);
487    
488     //
489 gross 921 // the shape of the returned numeric array will be the same
490     // as that of the data point
491     int arrayRank = dataPointRank;
492     DataArrayView::ShapeType arrayShape = dataPointShape;
493 jgs 121
494     //
495     // resize the numeric array to the shape just calculated
496 gross 921 if (arrayRank==0) {
497     numArray.resize(1);
498     }
499 jgs 121 if (arrayRank==1) {
500     numArray.resize(arrayShape[0]);
501     }
502     if (arrayRank==2) {
503     numArray.resize(arrayShape[0],arrayShape[1]);
504     }
505     if (arrayRank==3) {
506     numArray.resize(arrayShape[0],arrayShape[1],arrayShape[2]);
507     }
508     if (arrayRank==4) {
509     numArray.resize(arrayShape[0],arrayShape[1],arrayShape[2],arrayShape[3]);
510     }
511    
512 gross 921 if (getNumDataPointsPerSample()>0) {
513     int sampleNo = dataPointNo/getNumDataPointsPerSample();
514     int dataPointNoInSample = dataPointNo - sampleNo * getNumDataPointsPerSample();
515     //
516     // Check a valid sample number has been supplied
517 trankine 924 if ((sampleNo >= getNumSamples()) || (sampleNo < 0 )) {
518 gross 921 throw DataException("Error - Data::convertToNumArray: invalid sampleNo.");
519     }
520    
521     //
522     // Check a valid data point number has been supplied
523 trankine 924 if ((dataPointNoInSample >= getNumDataPointsPerSample()) || (dataPointNoInSample < 0)) {
524 gross 921 throw DataException("Error - Data::convertToNumArray: invalid dataPointNoInSample.");
525     }
526     // TODO: global error handling
527     // create a view of the data if it is stored locally
528     DataArrayView dataPointView = getDataPoint(sampleNo, dataPointNoInSample);
529    
530     switch( dataPointRank ){
531     case 0 :
532     numArray[0] = dataPointView();
533     break;
534     case 1 :
535     for( i=0; i<dataPointShape[0]; i++ )
536     numArray[i]=dataPointView(i);
537     break;
538     case 2 :
539     for( i=0; i<dataPointShape[0]; i++ )
540     for( j=0; j<dataPointShape[1]; j++)
541     numArray[make_tuple(i,j)]=dataPointView(i,j);
542     break;
543     case 3 :
544     for( i=0; i<dataPointShape[0]; i++ )
545     for( j=0; j<dataPointShape[1]; j++ )
546     for( k=0; k<dataPointShape[2]; k++)
547     numArray[make_tuple(i,j,k)]=dataPointView(i,j,k);
548     break;
549     case 4 :
550     for( i=0; i<dataPointShape[0]; i++ )
551     for( j=0; j<dataPointShape[1]; j++ )
552     for( k=0; k<dataPointShape[2]; k++ )
553     for( l=0; l<dataPointShape[3]; l++)
554     numArray[make_tuple(i,j,k,l)]=dataPointView(i,j,k,l);
555     break;
556     }
557 jgs 117 }
558     //
559 gross 921 // return the array
560 jgs 117 return numArray;
561 gross 921
562 jgs 117 }
563 gross 921 void
564 gross 1034 Data::setValueOfDataPointToPyObject(int dataPointNo, const boost::python::object& py_object)
565 jgs 121 {
566 gross 1034 // this will throw if the value cannot be represented
567     boost::python::numeric::array num_array(py_object);
568     setValueOfDataPointToArray(dataPointNo,num_array);
569    
570    
571     }
572    
573     void
574     Data::setValueOfDataPointToArray(int dataPointNo, const boost::python::numeric::array& num_array)
575     {
576 gross 921 if (isProtected()) {
577     throw DataException("Error - attempt to update protected Data object.");
578     }
579     //
580     // check rank
581     if (num_array.getrank()<getDataPointRank())
582     throw DataException("Rank of numarray does not match Data object rank");
583 bcumming 790
584 jgs 121 //
585 gross 921 // check shape of num_array
586     for (int i=0; i<getDataPointRank(); i++) {
587     if (extract<int>(num_array.getshape()[i])!=getDataPointShape()[i])
588     throw DataException("Shape of numarray does not match Data object rank");
589 jgs 121 }
590     //
591 gross 921 // make sure data is expanded:
592     if (!isExpanded()) {
593     expand();
594 jgs 121 }
595 gross 921 if (getNumDataPointsPerSample()>0) {
596     int sampleNo = dataPointNo/getNumDataPointsPerSample();
597     int dataPointNoInSample = dataPointNo - sampleNo * getNumDataPointsPerSample();
598     m_data->copyToDataPoint(sampleNo, dataPointNoInSample,num_array);
599     } else {
600     m_data->copyToDataPoint(-1, 0,num_array);
601     }
602     }
603 jgs 121
604 gross 922 void
605     Data::setValueOfDataPoint(int dataPointNo, const double value)
606     {
607     if (isProtected()) {
608     throw DataException("Error - attempt to update protected Data object.");
609     }
610     //
611     // make sure data is expanded:
612     if (!isExpanded()) {
613     expand();
614     }
615     if (getNumDataPointsPerSample()>0) {
616     int sampleNo = dataPointNo/getNumDataPointsPerSample();
617     int dataPointNoInSample = dataPointNo - sampleNo * getNumDataPointsPerSample();
618     m_data->copyToDataPoint(sampleNo, dataPointNoInSample,value);
619     } else {
620     m_data->copyToDataPoint(-1, 0,value);
621     }
622     }
623    
624 gross 921 const
625     boost::python::numeric::array
626     Data::getValueOfGlobalDataPoint(int procNo, int dataPointNo)
627     {
628     size_t length=0;
629     int i, j, k, l, pos;
630 jgs 121 //
631     // determine the rank and shape of each data point
632     int dataPointRank = getDataPointRank();
633     DataArrayView::ShapeType dataPointShape = getDataPointShape();
634    
635     //
636     // create the numeric array to be returned
637     boost::python::numeric::array numArray(0.0);
638    
639     //
640     // the shape of the returned numeric array will be the same
641     // as that of the data point
642     int arrayRank = dataPointRank;
643     DataArrayView::ShapeType arrayShape = dataPointShape;
644    
645     //
646     // resize the numeric array to the shape just calculated
647     if (arrayRank==0) {
648     numArray.resize(1);
649     }
650     if (arrayRank==1) {
651     numArray.resize(arrayShape[0]);
652     }
653     if (arrayRank==2) {
654     numArray.resize(arrayShape[0],arrayShape[1]);
655     }
656     if (arrayRank==3) {
657     numArray.resize(arrayShape[0],arrayShape[1],arrayShape[2]);
658     }
659     if (arrayRank==4) {
660     numArray.resize(arrayShape[0],arrayShape[1],arrayShape[2],arrayShape[3]);
661     }
662    
663 gross 921 // added for the MPI communication
664     length=1;
665     for( i=0; i<arrayRank; i++ ) length *= arrayShape[i];
666     double *tmpData = new double[length];
667 bcumming 790
668 jgs 121 //
669     // load the values for the data point into the numeric array.
670 bcumming 790
671     // updated for the MPI case
672     if( get_MPIRank()==procNo ){
673 gross 921 if (getNumDataPointsPerSample()>0) {
674     int sampleNo = dataPointNo/getNumDataPointsPerSample();
675     int dataPointNoInSample = dataPointNo - sampleNo * getNumDataPointsPerSample();
676     //
677     // Check a valid sample number has been supplied
678 trankine 924 if ((sampleNo >= getNumSamples()) || (sampleNo < 0 )) {
679 gross 921 throw DataException("Error - Data::convertToNumArray: invalid sampleNo.");
680     }
681    
682     //
683     // Check a valid data point number has been supplied
684 trankine 924 if ((dataPointNoInSample >= getNumDataPointsPerSample()) || (dataPointNoInSample < 0)) {
685 gross 921 throw DataException("Error - Data::convertToNumArray: invalid dataPointNoInSample.");
686     }
687     // TODO: global error handling
688 bcumming 790 // create a view of the data if it is stored locally
689 gross 921 DataArrayView dataPointView = getDataPoint(sampleNo, dataPointNoInSample);
690 bcumming 790
691     // pack the data from the view into tmpData for MPI communication
692     pos=0;
693     switch( dataPointRank ){
694     case 0 :
695     tmpData[0] = dataPointView();
696     break;
697     case 1 :
698     for( i=0; i<dataPointShape[0]; i++ )
699     tmpData[i]=dataPointView(i);
700     break;
701     case 2 :
702     for( i=0; i<dataPointShape[0]; i++ )
703     for( j=0; j<dataPointShape[1]; j++, pos++ )
704     tmpData[pos]=dataPointView(i,j);
705     break;
706     case 3 :
707     for( i=0; i<dataPointShape[0]; i++ )
708     for( j=0; j<dataPointShape[1]; j++ )
709     for( k=0; k<dataPointShape[2]; k++, pos++ )
710     tmpData[pos]=dataPointView(i,j,k);
711     break;
712     case 4 :
713     for( i=0; i<dataPointShape[0]; i++ )
714     for( j=0; j<dataPointShape[1]; j++ )
715     for( k=0; k<dataPointShape[2]; k++ )
716     for( l=0; l<dataPointShape[3]; l++, pos++ )
717     tmpData[pos]=dataPointView(i,j,k,l);
718     break;
719     }
720 gross 921 }
721 bcumming 790 }
722 gross 921 #ifdef PASO_MPI
723     // broadcast the data to all other processes
724     MPI_Bcast( tmpData, length, MPI_DOUBLE, procNo, get_MPIComm() );
725     #endif
726 bcumming 790
727     // unpack the data
728     switch( dataPointRank ){
729     case 0 :
730 gross 921 numArray[0]=tmpData[0];
731 bcumming 790 break;
732     case 1 :
733     for( i=0; i<dataPointShape[0]; i++ )
734     numArray[i]=tmpData[i];
735     break;
736     case 2 :
737     for( i=0; i<dataPointShape[0]; i++ )
738     for( j=0; j<dataPointShape[1]; j++ )
739 gross 921 numArray[make_tuple(i,j)]=tmpData[i+j*dataPointShape[0]];
740 bcumming 790 break;
741     case 3 :
742     for( i=0; i<dataPointShape[0]; i++ )
743     for( j=0; j<dataPointShape[1]; j++ )
744     for( k=0; k<dataPointShape[2]; k++ )
745 gross 921 numArray[make_tuple(i,j,k)]=tmpData[i+dataPointShape[0]*(j*+k*dataPointShape[1])];
746 bcumming 790 break;
747     case 4 :
748     for( i=0; i<dataPointShape[0]; i++ )
749     for( j=0; j<dataPointShape[1]; j++ )
750     for( k=0; k<dataPointShape[2]; k++ )
751     for( l=0; l<dataPointShape[3]; l++ )
752 gross 921 numArray[make_tuple(i,j,k,l)]=tmpData[i+dataPointShape[0]*(j*+dataPointShape[1]*(k+l*dataPointShape[2]))];
753 bcumming 790 break;
754     }
755    
756     delete [] tmpData;
757 jgs 121 //
758     // return the loaded array
759     return numArray;
760     }
761    
762 gross 921
763    
764 jgs 121 boost::python::numeric::array
765 jgs 94 Data::integrate() const
766     {
767     int index;
768     int rank = getDataPointRank();
769     DataArrayView::ShapeType shape = getDataPointShape();
770    
771 jgs 123
772 jgs 94 //
773     // calculate the integral values
774     vector<double> integrals(getDataPointSize());
775     AbstractContinuousDomain::asAbstractContinuousDomain(getDomain()).setToIntegrals(integrals,*this);
776    
777     //
778     // create the numeric array to be returned
779     // and load the array with the integral values
780     boost::python::numeric::array bp_array(1.0);
781     if (rank==0) {
782 jgs 108 bp_array.resize(1);
783 jgs 94 index = 0;
784     bp_array[0] = integrals[index];
785     }
786     if (rank==1) {
787     bp_array.resize(shape[0]);
788     for (int i=0; i<shape[0]; i++) {
789     index = i;
790     bp_array[i] = integrals[index];
791     }
792     }
793     if (rank==2) {
794 gross 436 bp_array.resize(shape[0],shape[1]);
795     for (int i=0; i<shape[0]; i++) {
796     for (int j=0; j<shape[1]; j++) {
797     index = i + shape[0] * j;
798     bp_array[make_tuple(i,j)] = integrals[index];
799     }
800     }
801 jgs 94 }
802     if (rank==3) {
803     bp_array.resize(shape[0],shape[1],shape[2]);
804     for (int i=0; i<shape[0]; i++) {
805     for (int j=0; j<shape[1]; j++) {
806     for (int k=0; k<shape[2]; k++) {
807     index = i + shape[0] * ( j + shape[1] * k );
808 gross 436 bp_array[make_tuple(i,j,k)] = integrals[index];
809 jgs 94 }
810     }
811     }
812     }
813     if (rank==4) {
814     bp_array.resize(shape[0],shape[1],shape[2],shape[3]);
815     for (int i=0; i<shape[0]; i++) {
816     for (int j=0; j<shape[1]; j++) {
817     for (int k=0; k<shape[2]; k++) {
818     for (int l=0; l<shape[3]; l++) {
819     index = i + shape[0] * ( j + shape[1] * ( k + shape[2] * l ) );
820 gross 436 bp_array[make_tuple(i,j,k,l)] = integrals[index];
821 jgs 94 }
822     }
823     }
824     }
825     }
826    
827     //
828     // return the loaded array
829     return bp_array;
830     }
831    
832     Data
833     Data::sin() const
834     {
835     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::sin);
836     }
837    
838     Data
839     Data::cos() const
840     {
841     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::cos);
842     }
843    
844     Data
845     Data::tan() const
846     {
847     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::tan);
848     }
849    
850     Data
851 jgs 150 Data::asin() const
852     {
853     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::asin);
854     }
855    
856     Data
857     Data::acos() const
858     {
859     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::acos);
860     }
861    
862 phornby 1026
863 jgs 150 Data
864     Data::atan() const
865     {
866     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::atan);
867     }
868    
869     Data
870     Data::sinh() const
871     {
872     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::sinh);
873     }
874    
875     Data
876     Data::cosh() const
877     {
878     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::cosh);
879     }
880    
881     Data
882     Data::tanh() const
883     {
884     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::tanh);
885     }
886    
887 phornby 1026
888 jgs 150 Data
889 phornby 1026 Data::erf() const
890     {
891 gross 1028 #ifdef _WIN32
892     throw DataException("Error - Data:: erf function is not supported on _WIN32 platforms.");
893     #else
894 phornby 1026 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::erf);
895     #endif
896     }
897    
898     Data
899 jgs 150 Data::asinh() const
900     {
901 phornby 1032 #ifdef _WIN32
902     return escript::unaryOp(*this,escript::asinh_substitute);
903     #else
904 jgs 150 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::asinh);
905 phornby 1032 #endif
906 jgs 150 }
907    
908     Data
909     Data::acosh() const
910     {
911 phornby 1032 #ifdef _WIN32
912     return escript::unaryOp(*this,escript::acosh_substitute);
913     #else
914 jgs 150 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::acosh);
915 phornby 1032 #endif
916 jgs 150 }
917    
918     Data
919     Data::atanh() const
920     {
921 phornby 1032 #ifdef _WIN32
922     return escript::unaryOp(*this,escript::atanh_substitute);
923     #else
924 jgs 150 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::atanh);
925 phornby 1032 #endif
926 jgs 150 }
927    
928     Data
929 gross 286 Data::log10() const
930 jgs 94 {
931     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::log10);
932     }
933    
934     Data
935 gross 286 Data::log() const
936 jgs 94 {
937     return escript::unaryOp(*this,(Data::UnaryDFunPtr)::log);
938     }
939    
940 jgs 106 Data
941     Data::sign() const
942 jgs 94 {
943 jgs 106 return escript::unaryOp(*this,escript::fsign);
944 jgs 94 }
945    
946 jgs 106 Data
947     Data::abs() const
948 jgs 94 {
949 jgs 106 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::fabs);
950 jgs 94 }
951    
952 jgs 106 Data
953     Data::neg() const
954 jgs 94 {
955 jgs 106 return escript::unaryOp(*this,negate<double>());
956 jgs 94 }
957    
958 jgs 102 Data
959 jgs 106 Data::pos() const
960 jgs 94 {
961 jgs 148 Data result;
962     // perform a deep copy
963     result.copy(*this);
964     return result;
965 jgs 102 }
966    
967     Data
968 jgs 106 Data::exp() const
969 jgs 102 {
970 jgs 106 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::exp);
971 jgs 102 }
972    
973     Data
974 jgs 106 Data::sqrt() const
975 jgs 102 {
976 jgs 106 return escript::unaryOp(*this,(Data::UnaryDFunPtr)::sqrt);
977 jgs 102 }
978    
979 jgs 106 double
980     Data::Lsup() const
981 jgs 102 {
982 bcumming 751 double localValue, globalValue;
983 jgs 106 //
984     // set the initial absolute maximum value to zero
985 bcumming 751
986 jgs 147 AbsMax abs_max_func;
987 bcumming 751 localValue = algorithm(abs_max_func,0);
988     #ifdef PASO_MPI
989     MPI_Allreduce( &localValue, &globalValue, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
990     return globalValue;
991     #else
992     return localValue;
993     #endif
994 jgs 102 }
995    
996 jgs 106 double
997 jgs 117 Data::Linf() const
998     {
999 bcumming 751 double localValue, globalValue;
1000 jgs 117 //
1001     // set the initial absolute minimum value to max double
1002 jgs 147 AbsMin abs_min_func;
1003 bcumming 751 localValue = algorithm(abs_min_func,numeric_limits<double>::max());
1004    
1005     #ifdef PASO_MPI
1006     MPI_Allreduce( &localValue, &globalValue, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD );
1007     return globalValue;
1008     #else
1009     return localValue;
1010     #endif
1011 jgs 117 }
1012    
1013     double
1014 jgs 106 Data::sup() const
1015 jgs 102 {
1016 bcumming 751 double localValue, globalValue;
1017 jgs 106 //
1018     // set the initial maximum value to min possible double
1019 jgs 147 FMax fmax_func;
1020 bcumming 751 localValue = algorithm(fmax_func,numeric_limits<double>::max()*-1);
1021     #ifdef PASO_MPI
1022     MPI_Allreduce( &localValue, &globalValue, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
1023     return globalValue;
1024     #else
1025     return localValue;
1026     #endif
1027 jgs 102 }
1028    
1029 jgs 106 double
1030     Data::inf() const
1031 jgs 102 {
1032 bcumming 751 double localValue, globalValue;
1033 jgs 106 //
1034     // set the initial minimum value to max possible double
1035 jgs 147 FMin fmin_func;
1036 bcumming 751 localValue = algorithm(fmin_func,numeric_limits<double>::max());
1037     #ifdef PASO_MPI
1038     MPI_Allreduce( &localValue, &globalValue, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD );
1039     return globalValue;
1040     #else
1041     return localValue;
1042     #endif
1043 jgs 102 }
1044    
1045 bcumming 751 /* TODO */
1046     /* global reduction */
1047 jgs 102 Data
1048 jgs 106 Data::maxval() const
1049 jgs 102 {
1050 jgs 113 //
1051     // set the initial maximum value to min possible double
1052 jgs 147 FMax fmax_func;
1053     return dp_algorithm(fmax_func,numeric_limits<double>::max()*-1);
1054 jgs 102 }
1055    
1056     Data
1057 jgs 106 Data::minval() const
1058 jgs 102 {
1059 jgs 113 //
1060     // set the initial minimum value to max possible double
1061 jgs 147 FMin fmin_func;
1062     return dp_algorithm(fmin_func,numeric_limits<double>::max());
1063 jgs 102 }
1064    
1065 jgs 123 Data
1066 gross 804 Data::swapaxes(const int axis0, const int axis1) const
1067 jgs 123 {
1068 gross 804 int axis0_tmp,axis1_tmp;
1069 gross 800 DataArrayView::ShapeType s=getDataPointShape();
1070     DataArrayView::ShapeType ev_shape;
1071     // Here's the equivalent of python s_out=s[axis_offset:]+s[:axis_offset]
1072     // which goes thru all shape vector elements starting with axis_offset (at index=rank wrap around to 0)
1073     int rank=getDataPointRank();
1074 gross 804 if (rank<2) {
1075     throw DataException("Error - Data::swapaxes argument must have at least rank 2.");
1076 gross 800 }
1077 gross 804 if (axis0<0 || axis0>rank-1) {
1078     throw DataException("Error - Data::swapaxes: axis0 must be between 0 and rank-1=" + rank-1);
1079     }
1080     if (axis1<0 || axis1>rank-1) {
1081     throw DataException("Error - Data::swapaxes: axis1 must be between 0 and rank-1=" + rank-1);
1082     }
1083     if (axis0 == axis1) {
1084     throw DataException("Error - Data::swapaxes: axis indices must be different.");
1085     }
1086     if (axis0 > axis1) {
1087     axis0_tmp=axis1;
1088     axis1_tmp=axis0;
1089     } else {
1090     axis0_tmp=axis0;
1091     axis1_tmp=axis1;
1092     }
1093 gross 800 for (int i=0; i<rank; i++) {
1094 gross 804 if (i == axis0_tmp) {
1095     ev_shape.push_back(s[axis1_tmp]);
1096     } else if (i == axis1_tmp) {
1097     ev_shape.push_back(s[axis0_tmp]);
1098 gross 800 } else {
1099     ev_shape.push_back(s[i]);
1100     }
1101     }
1102     Data ev(0.,ev_shape,getFunctionSpace());
1103     ev.typeMatchRight(*this);
1104 gross 804 m_data->swapaxes(ev.m_data.get(), axis0_tmp, axis1_tmp);
1105 gross 800 return ev;
1106    
1107 jgs 123 }
1108    
1109     Data
1110 ksteube 775 Data::symmetric() const
1111 jgs 123 {
1112 ksteube 775 // check input
1113     DataArrayView::ShapeType s=getDataPointShape();
1114     if (getDataPointRank()==2) {
1115     if(s[0] != s[1])
1116     throw DataException("Error - Data::symmetric can only be calculated for rank 2 object with equal first and second dimension.");
1117     }
1118     else if (getDataPointRank()==4) {
1119     if(!(s[0] == s[2] && s[1] == s[3]))
1120     throw DataException("Error - Data::symmetric can only be calculated for rank 4 object with dim0==dim2 and dim1==dim3.");
1121     }
1122     else {
1123     throw DataException("Error - Data::symmetric can only be calculated for rank 2 or 4 object.");
1124     }
1125     Data ev(0.,getDataPointShape(),getFunctionSpace());
1126     ev.typeMatchRight(*this);
1127     m_data->symmetric(ev.m_data.get());
1128     return ev;
1129     }
1130    
1131     Data
1132     Data::nonsymmetric() const
1133     {
1134     // check input
1135     DataArrayView::ShapeType s=getDataPointShape();
1136     if (getDataPointRank()==2) {
1137     if(s[0] != s[1])
1138     throw DataException("Error - Data::nonsymmetric can only be calculated for rank 2 object with equal first and second dimension.");
1139     DataArrayView::ShapeType ev_shape;
1140     ev_shape.push_back(s[0]);
1141     ev_shape.push_back(s[1]);
1142     Data ev(0.,ev_shape,getFunctionSpace());
1143     ev.typeMatchRight(*this);
1144     m_data->nonsymmetric(ev.m_data.get());
1145     return ev;
1146     }
1147     else if (getDataPointRank()==4) {
1148     if(!(s[0] == s[2] && s[1] == s[3]))
1149     throw DataException("Error - Data::nonsymmetric can only be calculated for rank 4 object with dim0==dim2 and dim1==dim3.");
1150     DataArrayView::ShapeType ev_shape;
1151     ev_shape.push_back(s[0]);
1152     ev_shape.push_back(s[1]);
1153     ev_shape.push_back(s[2]);
1154     ev_shape.push_back(s[3]);
1155     Data ev(0.,ev_shape,getFunctionSpace());
1156     ev.typeMatchRight(*this);
1157     m_data->nonsymmetric(ev.m_data.get());
1158     return ev;
1159     }
1160     else {
1161     throw DataException("Error - Data::nonsymmetric can only be calculated for rank 2 or 4 object.");
1162     }
1163     }
1164    
1165     Data
1166 gross 800 Data::trace(int axis_offset) const
1167 ksteube 775 {
1168     DataArrayView::ShapeType s=getDataPointShape();
1169     if (getDataPointRank()==2) {
1170     DataArrayView::ShapeType ev_shape;
1171     Data ev(0.,ev_shape,getFunctionSpace());
1172     ev.typeMatchRight(*this);
1173 gross 800 m_data->trace(ev.m_data.get(), axis_offset);
1174 ksteube 775 return ev;
1175     }
1176     if (getDataPointRank()==3) {
1177     DataArrayView::ShapeType ev_shape;
1178     if (axis_offset==0) {
1179     int s2=s[2];
1180     ev_shape.push_back(s2);
1181     }
1182     else if (axis_offset==1) {
1183     int s0=s[0];
1184     ev_shape.push_back(s0);
1185     }
1186     Data ev(0.,ev_shape,getFunctionSpace());
1187     ev.typeMatchRight(*this);
1188 gross 800 m_data->trace(ev.m_data.get(), axis_offset);
1189 ksteube 775 return ev;
1190     }
1191     if (getDataPointRank()==4) {
1192     DataArrayView::ShapeType ev_shape;
1193     if (axis_offset==0) {
1194     ev_shape.push_back(s[2]);
1195     ev_shape.push_back(s[3]);
1196     }
1197     else if (axis_offset==1) {
1198     ev_shape.push_back(s[0]);
1199     ev_shape.push_back(s[3]);
1200     }
1201     else if (axis_offset==2) {
1202     ev_shape.push_back(s[0]);
1203     ev_shape.push_back(s[1]);
1204     }
1205     Data ev(0.,ev_shape,getFunctionSpace());
1206     ev.typeMatchRight(*this);
1207 gross 800 m_data->trace(ev.m_data.get(), axis_offset);
1208 ksteube 775 return ev;
1209     }
1210     else {
1211 gross 800 throw DataException("Error - Data::trace can only be calculated for rank 2, 3 or 4 object.");
1212 ksteube 775 }
1213     }
1214    
1215     Data
1216     Data::transpose(int axis_offset) const
1217     {
1218     DataArrayView::ShapeType s=getDataPointShape();
1219     DataArrayView::ShapeType ev_shape;
1220     // Here's the equivalent of python s_out=s[axis_offset:]+s[:axis_offset]
1221     // which goes thru all shape vector elements starting with axis_offset (at index=rank wrap around to 0)
1222     int rank=getDataPointRank();
1223     if (axis_offset<0 || axis_offset>rank) {
1224     throw DataException("Error - Data::transpose must have 0 <= axis_offset <= rank=" + rank);
1225     }
1226     for (int i=0; i<rank; i++) {
1227     int index = (axis_offset+i)%rank;
1228     ev_shape.push_back(s[index]); // Append to new shape
1229     }
1230     Data ev(0.,ev_shape,getFunctionSpace());
1231     ev.typeMatchRight(*this);
1232     m_data->transpose(ev.m_data.get(), axis_offset);
1233     return ev;
1234 jgs 123 }
1235    
1236 gross 576 Data
1237     Data::eigenvalues() const
1238     {
1239     // check input
1240     DataArrayView::ShapeType s=getDataPointShape();
1241     if (getDataPointRank()!=2)
1242     throw DataException("Error - Data::eigenvalues can only be calculated for rank 2 object.");
1243     if(s[0] != s[1])
1244     throw DataException("Error - Data::eigenvalues can only be calculated for object with equal first and second dimension.");
1245     // create return
1246     DataArrayView::ShapeType ev_shape(1,s[0]);
1247     Data ev(0.,ev_shape,getFunctionSpace());
1248     ev.typeMatchRight(*this);
1249     m_data->eigenvalues(ev.m_data.get());
1250     return ev;
1251     }
1252    
1253 jgs 121 const boost::python::tuple
1254 gross 576 Data::eigenvalues_and_eigenvectors(const double tol) const
1255     {
1256     DataArrayView::ShapeType s=getDataPointShape();
1257     if (getDataPointRank()!=2)
1258     throw DataException("Error - Data::eigenvalues and eigenvectors can only be calculated for rank 2 object.");
1259     if(s[0] != s[1])
1260     throw DataException("Error - Data::eigenvalues and eigenvectors can only be calculated for object with equal first and second dimension.");
1261     // create return
1262     DataArrayView::ShapeType ev_shape(1,s[0]);
1263     Data ev(0.,ev_shape,getFunctionSpace());
1264     ev.typeMatchRight(*this);
1265     DataArrayView::ShapeType V_shape(2,s[0]);
1266     Data V(0.,V_shape,getFunctionSpace());
1267     V.typeMatchRight(*this);
1268     m_data->eigenvalues_and_eigenvectors(ev.m_data.get(),V.m_data.get(),tol);
1269     return make_tuple(boost::python::object(ev),boost::python::object(V));
1270     }
1271    
1272     const boost::python::tuple
1273 gross 921 Data::minGlobalDataPoint() const
1274 jgs 121 {
1275 gross 921 // NB: calc_minGlobalDataPoint( had to be split off from minGlobalDataPoint( as boost::make_tuple causes an
1276 jgs 148 // abort (for unknown reasons) if there are openmp directives with it in the
1277     // surrounding function
1278    
1279     int DataPointNo;
1280 gross 921 int ProcNo;
1281     calc_minGlobalDataPoint(ProcNo,DataPointNo);
1282     return make_tuple(ProcNo,DataPointNo);
1283 jgs 148 }
1284    
1285     void
1286 gross 921 Data::calc_minGlobalDataPoint(int& ProcNo,
1287     int& DataPointNo) const
1288 jgs 148 {
1289     int i,j;
1290     int lowi=0,lowj=0;
1291     double min=numeric_limits<double>::max();
1292    
1293 jgs 121 Data temp=minval();
1294    
1295     int numSamples=temp.getNumSamples();
1296     int numDPPSample=temp.getNumDataPointsPerSample();
1297    
1298 jgs 148 double next,local_min;
1299     int local_lowi,local_lowj;
1300 jgs 121
1301 jgs 148 #pragma omp parallel private(next,local_min,local_lowi,local_lowj)
1302     {
1303     local_min=min;
1304     #pragma omp for private(i,j) schedule(static)
1305     for (i=0; i<numSamples; i++) {
1306     for (j=0; j<numDPPSample; j++) {
1307     next=temp.getDataPoint(i,j)();
1308     if (next<local_min) {
1309     local_min=next;
1310     local_lowi=i;
1311     local_lowj=j;
1312     }
1313 jgs 121 }
1314     }
1315 jgs 148 #pragma omp critical
1316     if (local_min<min) {
1317     min=local_min;
1318     lowi=local_lowi;
1319     lowj=local_lowj;
1320     }
1321 jgs 121 }
1322    
1323 bcumming 782 #ifdef PASO_MPI
1324     // determine the processor on which the minimum occurs
1325     next = temp.getDataPoint(lowi,lowj)();
1326     int lowProc = 0;
1327     double *globalMins = new double[get_MPISize()+1];
1328     int error = MPI_Gather ( &next, 1, MPI_DOUBLE, globalMins, 1, MPI_DOUBLE, 0, get_MPIComm() );
1329    
1330     if( get_MPIRank()==0 ){
1331     next = globalMins[lowProc];
1332     for( i=1; i<get_MPISize(); i++ )
1333     if( next>globalMins[i] ){
1334     lowProc = i;
1335     next = globalMins[i];
1336     }
1337     }
1338     MPI_Bcast( &lowProc, 1, MPI_DOUBLE, 0, get_MPIComm() );
1339    
1340     delete [] globalMins;
1341     ProcNo = lowProc;
1342 bcumming 790 #else
1343     ProcNo = 0;
1344 bcumming 782 #endif
1345 gross 921 DataPointNo = lowj + lowi * numDPPSample;
1346 jgs 121 }
1347    
1348 jgs 104 void
1349     Data::saveDX(std::string fileName) const
1350     {
1351 jgs 153 boost::python::dict args;
1352     args["data"]=boost::python::object(this);
1353     getDomain().saveDX(fileName,args);
1354 jgs 104 return;
1355     }
1356    
1357 jgs 110 void
1358     Data::saveVTK(std::string fileName) const
1359     {
1360 jgs 153 boost::python::dict args;
1361     args["data"]=boost::python::object(this);
1362     getDomain().saveVTK(fileName,args);
1363 jgs 110 return;
1364     }
1365    
1366 jgs 102 Data&
1367     Data::operator+=(const Data& right)
1368     {
1369 gross 783 if (isProtected()) {
1370     throw DataException("Error - attempt to update protected Data object.");
1371     }
1372 jgs 94 binaryOp(right,plus<double>());
1373     return (*this);
1374     }
1375    
1376 jgs 102 Data&
1377     Data::operator+=(const boost::python::object& right)
1378 jgs 94 {
1379 gross 854 Data tmp(right,getFunctionSpace(),false);
1380     binaryOp(tmp,plus<double>());
1381 jgs 94 return (*this);
1382     }
1383    
1384 jgs 102 Data&
1385     Data::operator-=(const Data& right)
1386 jgs 94 {
1387 gross 783 if (isProtected()) {
1388     throw DataException("Error - attempt to update protected Data object.");
1389     }
1390 jgs 94 binaryOp(right,minus<double>());
1391     return (*this);
1392     }
1393    
1394 jgs 102 Data&
1395     Data::operator-=(const boost::python::object& right)
1396 jgs 94 {
1397 gross 854 Data tmp(right,getFunctionSpace(),false);
1398     binaryOp(tmp,minus<double>());
1399 jgs 94 return (*this);
1400     }
1401    
1402 jgs 102 Data&
1403     Data::operator*=(const Data& right)
1404 jgs 94 {
1405 gross 783 if (isProtected()) {
1406     throw DataException("Error - attempt to update protected Data object.");
1407     }
1408 jgs 94 binaryOp(right,multiplies<double>());
1409     return (*this);
1410     }
1411    
1412 jgs 102 Data&
1413     Data::operator*=(const boost::python::object& right)
1414 jgs 94 {
1415 gross 854 Data tmp(right,getFunctionSpace(),false);
1416     binaryOp(tmp,multiplies<double>());
1417 jgs 94 return (*this);
1418     }
1419    
1420 jgs 102 Data&
1421     Data::operator/=(const Data& right)
1422 jgs 94 {
1423 gross 783 if (isProtected()) {
1424     throw DataException("Error - attempt to update protected Data object.");
1425     }
1426 jgs 94 binaryOp(right,divides<double>());
1427     return (*this);
1428     }
1429    
1430 jgs 102 Data&
1431     Data::operator/=(const boost::python::object& right)
1432 jgs 94 {
1433 gross 854 Data tmp(right,getFunctionSpace(),false);
1434     binaryOp(tmp,divides<double>());
1435 jgs 94 return (*this);
1436     }
1437    
1438 jgs 102 Data
1439 gross 699 Data::rpowO(const boost::python::object& left) const
1440     {
1441     Data left_d(left,*this);
1442     return left_d.powD(*this);
1443     }
1444    
1445     Data
1446 jgs 102 Data::powO(const boost::python::object& right) const
1447 jgs 94 {
1448 gross 854 Data tmp(right,getFunctionSpace(),false);
1449     return powD(tmp);
1450 jgs 94 }
1451    
1452 jgs 102 Data
1453     Data::powD(const Data& right) const
1454 jgs 94 {
1455     Data result;
1456 gross 854 if (getDataPointRank()<right.getDataPointRank()) {
1457     result.copy(right);
1458     result.binaryOp(*this,escript::rpow);
1459     } else {
1460     result.copy(*this);
1461     result.binaryOp(right,(Data::BinaryDFunPtr)::pow);
1462     }
1463 jgs 94 return result;
1464     }
1465    
1466 bcumming 751
1467 jgs 94 //
1468 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1469 jgs 102 Data
1470     escript::operator+(const Data& left, const Data& right)
1471 jgs 94 {
1472     Data result;
1473     //
1474     // perform a deep copy
1475 gross 854 if (left.getDataPointRank()<right.getDataPointRank()) {
1476     result.copy(right);
1477     result+=left;
1478     } else {
1479     result.copy(left);
1480     result+=right;
1481     }
1482 jgs 94 return result;
1483     }
1484    
1485     //
1486 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1487 jgs 102 Data
1488     escript::operator-(const Data& left, const Data& right)
1489 jgs 94 {
1490     Data result;
1491     //
1492     // perform a deep copy
1493 gross 854 if (left.getDataPointRank()<right.getDataPointRank()) {
1494     result=right.neg();
1495     result+=left;
1496     } else {
1497     result.copy(left);
1498     result-=right;
1499     }
1500 jgs 94 return result;
1501     }
1502    
1503     //
1504 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1505 jgs 102 Data
1506     escript::operator*(const Data& left, const Data& right)
1507 jgs 94 {
1508     Data result;
1509     //
1510     // perform a deep copy
1511 gross 854 if (left.getDataPointRank()<right.getDataPointRank()) {
1512     result.copy(right);
1513     result*=left;
1514     } else {
1515     result.copy(left);
1516     result*=right;
1517     }
1518 jgs 94 return result;
1519     }
1520    
1521     //
1522 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1523 jgs 102 Data
1524     escript::operator/(const Data& left, const Data& right)
1525 jgs 94 {
1526     Data result;
1527     //
1528     // perform a deep copy
1529 gross 854 if (left.getDataPointRank()<right.getDataPointRank()) {
1530     result=right.oneOver();
1531     result*=left;
1532     } else {
1533     result.copy(left);
1534     result/=right;
1535     }
1536 jgs 94 return result;
1537     }
1538    
1539     //
1540 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1541 jgs 102 Data
1542     escript::operator+(const Data& left, const boost::python::object& right)
1543 jgs 94 {
1544 gross 854 return left+Data(right,left.getFunctionSpace(),false);
1545 jgs 94 }
1546    
1547     //
1548 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1549 jgs 102 Data
1550     escript::operator-(const Data& left, const boost::python::object& right)
1551 jgs 94 {
1552 gross 854 return left-Data(right,left.getFunctionSpace(),false);
1553 jgs 94 }
1554    
1555     //
1556 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1557 jgs 102 Data
1558     escript::operator*(const Data& left, const boost::python::object& right)
1559 jgs 94 {
1560 gross 854 return left*Data(right,left.getFunctionSpace(),false);
1561 jgs 94 }
1562    
1563     //
1564 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1565 jgs 102 Data
1566     escript::operator/(const Data& left, const boost::python::object& right)
1567 jgs 94 {
1568 gross 854 return left/Data(right,left.getFunctionSpace(),false);
1569 jgs 94 }
1570    
1571     //
1572 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1573 jgs 102 Data
1574     escript::operator+(const boost::python::object& left, const Data& right)
1575 jgs 94 {
1576 gross 854 return Data(left,right.getFunctionSpace(),false)+right;
1577 jgs 94 }
1578    
1579     //
1580 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1581 jgs 102 Data
1582     escript::operator-(const boost::python::object& left, const Data& right)
1583 jgs 94 {
1584 gross 854 return Data(left,right.getFunctionSpace(),false)-right;
1585 jgs 94 }
1586    
1587     //
1588 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1589 jgs 102 Data
1590     escript::operator*(const boost::python::object& left, const Data& right)
1591 jgs 94 {
1592 gross 854 return Data(left,right.getFunctionSpace(),false)*right;
1593 jgs 94 }
1594    
1595     //
1596 jgs 123 // NOTE: It is essential to specify the namespace this operator belongs to
1597 jgs 102 Data
1598     escript::operator/(const boost::python::object& left, const Data& right)
1599 jgs 94 {
1600 gross 854 return Data(left,right.getFunctionSpace(),false)/right;
1601 jgs 94 }
1602    
1603     //
1604 jgs 102 //bool escript::operator==(const Data& left, const Data& right)
1605     //{
1606     // /*
1607     // NB: this operator does very little at this point, and isn't to
1608     // be relied on. Requires further implementation.
1609     // */
1610     //
1611     // bool ret;
1612     //
1613     // if (left.isEmpty()) {
1614     // if(!right.isEmpty()) {
1615     // ret = false;
1616     // } else {
1617     // ret = true;
1618     // }
1619     // }
1620     //
1621     // if (left.isConstant()) {
1622     // if(!right.isConstant()) {
1623     // ret = false;
1624     // } else {
1625     // ret = true;
1626     // }
1627     // }
1628     //
1629     // if (left.isTagged()) {
1630     // if(!right.isTagged()) {
1631     // ret = false;
1632     // } else {
1633     // ret = true;
1634     // }
1635     // }
1636     //
1637     // if (left.isExpanded()) {
1638     // if(!right.isExpanded()) {
1639     // ret = false;
1640     // } else {
1641     // ret = true;
1642     // }
1643     // }
1644     //
1645     // return ret;
1646     //}
1647    
1648 bcumming 751 /* TODO */
1649     /* global reduction */
1650 jgs 102 Data
1651     Data::getItem(const boost::python::object& key) const
1652 jgs 94 {
1653 jgs 102 const DataArrayView& view=getPointDataView();
1654 jgs 94
1655 jgs 102 DataArrayView::RegionType slice_region=view.getSliceRegion(key);
1656 jgs 94
1657 jgs 102 if (slice_region.size()!=view.getRank()) {
1658     throw DataException("Error - slice size does not match Data rank.");
1659 jgs 94 }
1660    
1661 jgs 102 return getSlice(slice_region);
1662 jgs 94 }
1663    
1664 bcumming 751 /* TODO */
1665     /* global reduction */
1666 jgs 94 Data
1667 jgs 102 Data::getSlice(const DataArrayView::RegionType& region) const
1668 jgs 94 {
1669 jgs 102 return Data(*this,region);
1670 jgs 94 }
1671    
1672 bcumming 751 /* TODO */
1673     /* global reduction */
1674 jgs 94 void
1675 jgs 102 Data::setItemO(const boost::python::object& key,
1676     const boost::python::object& value)
1677 jgs 94 {
1678 jgs 102 Data tempData(value,getFunctionSpace());
1679     setItemD(key,tempData);
1680     }
1681    
1682 bcumming 751 /* TODO */
1683     /* global reduction */
1684 jgs 102 void
1685     Data::setItemD(const boost::python::object& key,
1686     const Data& value)
1687     {
1688 jgs 94 const DataArrayView& view=getPointDataView();
1689 jgs 123
1690 jgs 94 DataArrayView::RegionType slice_region=view.getSliceRegion(key);
1691     if (slice_region.size()!=view.getRank()) {
1692     throw DataException("Error - slice size does not match Data rank.");
1693     }
1694 jgs 108 if (getFunctionSpace()!=value.getFunctionSpace()) {
1695     setSlice(Data(value,getFunctionSpace()),slice_region);
1696     } else {
1697     setSlice(value,slice_region);
1698     }
1699 jgs 94 }
1700    
1701 bcumming 751 /* TODO */
1702     /* global reduction */
1703 jgs 94 void
1704 jgs 102 Data::setSlice(const Data& value,
1705     const DataArrayView::RegionType& region)
1706 jgs 94 {
1707 gross 783 if (isProtected()) {
1708     throw DataException("Error - attempt to update protected Data object.");
1709     }
1710 jgs 102 Data tempValue(value);
1711     typeMatchLeft(tempValue);
1712     typeMatchRight(tempValue);
1713     m_data->setSlice(tempValue.m_data.get(),region);
1714     }
1715    
1716     void
1717     Data::typeMatchLeft(Data& right) const
1718     {
1719     if (isExpanded()){
1720     right.expand();
1721     } else if (isTagged()) {
1722     if (right.isConstant()) {
1723     right.tag();
1724     }
1725     }
1726     }
1727    
1728     void
1729     Data::typeMatchRight(const Data& right)
1730     {
1731 jgs 94 if (isTagged()) {
1732     if (right.isExpanded()) {
1733     expand();
1734     }
1735     } else if (isConstant()) {
1736     if (right.isExpanded()) {
1737     expand();
1738     } else if (right.isTagged()) {
1739     tag();
1740     }
1741     }
1742     }
1743    
1744     void
1745 gross 1044 Data::setTaggedValueByName(std::string name,
1746     const boost::python::object& value)
1747     {
1748     if (getFunctionSpace().getDomain().isValidTagName(name)) {
1749     int tagKey=getFunctionSpace().getDomain().getTag(name);
1750     setTaggedValue(tagKey,value);
1751     }
1752     }
1753     void
1754 jgs 94 Data::setTaggedValue(int tagKey,
1755     const boost::python::object& value)
1756     {
1757 gross 783 if (isProtected()) {
1758     throw DataException("Error - attempt to update protected Data object.");
1759     }
1760 jgs 94 //
1761     // Ensure underlying data object is of type DataTagged
1762     tag();
1763    
1764     if (!isTagged()) {
1765     throw DataException("Error - DataTagged conversion failed!!");
1766     }
1767    
1768     //
1769     // Construct DataArray from boost::python::object input value
1770     DataArray valueDataArray(value);
1771    
1772     //
1773     // Call DataAbstract::setTaggedValue
1774     m_data->setTaggedValue(tagKey,valueDataArray.getView());
1775     }
1776    
1777 jgs 110 void
1778 jgs 121 Data::setTaggedValueFromCPP(int tagKey,
1779     const DataArrayView& value)
1780     {
1781 gross 783 if (isProtected()) {
1782     throw DataException("Error - attempt to update protected Data object.");
1783     }
1784 jgs 121 //
1785     // Ensure underlying data object is of type DataTagged
1786     tag();
1787    
1788     if (!isTagged()) {
1789     throw DataException("Error - DataTagged conversion failed!!");
1790     }
1791    
1792     //
1793     // Call DataAbstract::setTaggedValue
1794     m_data->setTaggedValue(tagKey,value);
1795     }
1796    
1797 jgs 149 int
1798     Data::getTagNumber(int dpno)
1799     {
1800     return m_data->getTagNumber(dpno);
1801     }
1802    
1803 jgs 121 void
1804 jgs 119 Data::archiveData(const std::string fileName)
1805     {
1806     cout << "Archiving Data object to: " << fileName << endl;
1807    
1808     //
1809     // Determine type of this Data object
1810     int dataType = -1;
1811    
1812     if (isEmpty()) {
1813     dataType = 0;
1814     cout << "\tdataType: DataEmpty" << endl;
1815     }
1816     if (isConstant()) {
1817     dataType = 1;
1818     cout << "\tdataType: DataConstant" << endl;
1819     }
1820     if (isTagged()) {
1821     dataType = 2;
1822     cout << "\tdataType: DataTagged" << endl;
1823     }
1824     if (isExpanded()) {
1825     dataType = 3;
1826     cout << "\tdataType: DataExpanded" << endl;
1827     }
1828 jgs 123
1829 jgs 119 if (dataType == -1) {
1830     throw DataException("archiveData Error: undefined dataType");
1831     }
1832    
1833     //
1834     // Collect data items common to all Data types
1835     int noSamples = getNumSamples();
1836     int noDPPSample = getNumDataPointsPerSample();
1837     int functionSpaceType = getFunctionSpace().getTypeCode();
1838     int dataPointRank = getDataPointRank();
1839     int dataPointSize = getDataPointSize();
1840     int dataLength = getLength();
1841     DataArrayView::ShapeType dataPointShape = getDataPointShape();
1842 woo409 757 vector<int> referenceNumbers(noSamples);
1843 jgs 119 for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
1844 gross 964 referenceNumbers[sampleNo] = getFunctionSpace().getReferenceIDOfSample(sampleNo);
1845 jgs 119 }
1846 woo409 757 vector<int> tagNumbers(noSamples);
1847 jgs 119 if (isTagged()) {
1848     for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
1849     tagNumbers[sampleNo] = getFunctionSpace().getTagFromSampleNo(sampleNo);
1850     }
1851     }
1852    
1853     cout << "\tnoSamples: " << noSamples << " noDPPSample: " << noDPPSample << endl;
1854     cout << "\tfunctionSpaceType: " << functionSpaceType << endl;
1855     cout << "\trank: " << dataPointRank << " size: " << dataPointSize << " length: " << dataLength << endl;
1856    
1857     //
1858     // Flatten Shape to an array of integers suitable for writing to file
1859     int flatShape[4] = {0,0,0,0};
1860     cout << "\tshape: < ";
1861     for (int dim=0; dim<dataPointRank; dim++) {
1862     flatShape[dim] = dataPointShape[dim];
1863     cout << dataPointShape[dim] << " ";
1864     }
1865     cout << ">" << endl;
1866    
1867     //
1868 jgs 123 // Open archive file
1869 jgs 119 ofstream archiveFile;
1870     archiveFile.open(fileName.data(), ios::out);
1871    
1872     if (!archiveFile.good()) {
1873     throw DataException("archiveData Error: problem opening archive file");
1874     }
1875    
1876 jgs 123 //
1877     // Write common data items to archive file
1878 jgs 119 archiveFile.write(reinterpret_cast<char *>(&dataType),sizeof(int));
1879     archiveFile.write(reinterpret_cast<char *>(&noSamples),sizeof(int));
1880     archiveFile.write(reinterpret_cast<char *>(&noDPPSample),sizeof(int));
1881     archiveFile.write(reinterpret_cast<char *>(&functionSpaceType),sizeof(int));
1882     archiveFile.write(reinterpret_cast<char *>(&dataPointRank),sizeof(int));
1883     archiveFile.write(reinterpret_cast<char *>(&dataPointSize),sizeof(int));
1884     archiveFile.write(reinterpret_cast<char *>(&dataLength),sizeof(int));
1885     for (int dim = 0; dim < 4; dim++) {
1886     archiveFile.write(reinterpret_cast<char *>(&flatShape[dim]),sizeof(int));
1887     }
1888     for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
1889     archiveFile.write(reinterpret_cast<char *>(&referenceNumbers[sampleNo]),sizeof(int));
1890     }
1891     if (isTagged()) {
1892     for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
1893     archiveFile.write(reinterpret_cast<char *>(&tagNumbers[sampleNo]),sizeof(int));
1894     }
1895     }
1896    
1897     if (!archiveFile.good()) {
1898     throw DataException("archiveData Error: problem writing to archive file");
1899     }
1900    
1901     //
1902 jgs 123 // Archive underlying data values for each Data type
1903     int noValues;
1904 jgs 119 switch (dataType) {
1905     case 0:
1906     // DataEmpty
1907 jgs 123 noValues = 0;
1908     archiveFile.write(reinterpret_cast<char *>(&noValues),sizeof(int));
1909     cout << "\tnoValues: " << noValues << endl;
1910 jgs 119 break;
1911     case 1:
1912     // DataConstant
1913 jgs 123 noValues = m_data->getLength();
1914     archiveFile.write(reinterpret_cast<char *>(&noValues),sizeof(int));
1915     cout << "\tnoValues: " << noValues << endl;
1916     if (m_data->archiveData(archiveFile,noValues)) {
1917     throw DataException("archiveData Error: problem writing data to archive file");
1918     }
1919 jgs 119 break;
1920     case 2:
1921     // DataTagged
1922 jgs 123 noValues = m_data->getLength();
1923     archiveFile.write(reinterpret_cast<char *>(&noValues),sizeof(int));
1924     cout << "\tnoValues: " << noValues << endl;
1925     if (m_data->archiveData(archiveFile,noValues)) {
1926     throw DataException("archiveData Error: problem writing data to archive file");
1927     }
1928 jgs 119 break;
1929     case 3:
1930     // DataExpanded
1931 jgs 123 noValues = m_data->getLength();
1932     archiveFile.write(reinterpret_cast<char *>(&noValues),sizeof(int));
1933     cout << "\tnoValues: " << noValues << endl;
1934     if (m_data->archiveData(archiveFile,noValues)) {
1935     throw DataException("archiveData Error: problem writing data to archive file");
1936     }
1937 jgs 119 break;
1938     }
1939    
1940 jgs 123 if (!archiveFile.good()) {
1941     throw DataException("archiveData Error: problem writing data to archive file");
1942     }
1943    
1944     //
1945     // Close archive file
1946     archiveFile.close();
1947    
1948     if (!archiveFile.good()) {
1949     throw DataException("archiveData Error: problem closing archive file");
1950     }
1951    
1952 jgs 119 }
1953    
1954     void
1955     Data::extractData(const std::string fileName,
1956     const FunctionSpace& fspace)
1957     {
1958     //
1959     // Can only extract Data to an object which is initially DataEmpty
1960     if (!isEmpty()) {
1961     throw DataException("extractData Error: can only extract to DataEmpty object");
1962     }
1963    
1964     cout << "Extracting Data object from: " << fileName << endl;
1965    
1966     int dataType;
1967     int noSamples;
1968     int noDPPSample;
1969     int functionSpaceType;
1970     int dataPointRank;
1971     int dataPointSize;
1972     int dataLength;
1973     DataArrayView::ShapeType dataPointShape;
1974     int flatShape[4];
1975    
1976     //
1977 jgs 123 // Open the archive file
1978 jgs 119 ifstream archiveFile;
1979     archiveFile.open(fileName.data(), ios::in);
1980    
1981     if (!archiveFile.good()) {
1982     throw DataException("extractData Error: problem opening archive file");
1983     }
1984    
1985 jgs 123 //
1986     // Read common data items from archive file
1987 jgs 119 archiveFile.read(reinterpret_cast<char *>(&dataType),sizeof(int));
1988     archiveFile.read(reinterpret_cast<char *>(&noSamples),sizeof(int));
1989     archiveFile.read(reinterpret_cast<char *>(&noDPPSample),sizeof(int));
1990     archiveFile.read(reinterpret_cast<char *>(&functionSpaceType),sizeof(int));
1991     archiveFile.read(reinterpret_cast<char *>(&dataPointRank),sizeof(int));
1992     archiveFile.read(reinterpret_cast<char *>(&dataPointSize),sizeof(int));
1993     archiveFile.read(reinterpret_cast<char *>(&dataLength),sizeof(int));
1994     for (int dim = 0; dim < 4; dim++) {
1995     archiveFile.read(reinterpret_cast<char *>(&flatShape[dim]),sizeof(int));
1996     if (flatShape[dim]>0) {
1997     dataPointShape.push_back(flatShape[dim]);
1998     }
1999     }
2000 woo409 757 vector<int> referenceNumbers(noSamples);
2001 jgs 119 for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
2002     archiveFile.read(reinterpret_cast<char *>(&referenceNumbers[sampleNo]),sizeof(int));
2003     }
2004 woo409 757 vector<int> tagNumbers(noSamples);
2005 jgs 119 if (dataType==2) {
2006     for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
2007     archiveFile.read(reinterpret_cast<char *>(&tagNumbers[sampleNo]),sizeof(int));
2008     }
2009     }
2010    
2011     if (!archiveFile.good()) {
2012     throw DataException("extractData Error: problem reading from archive file");
2013     }
2014    
2015 jgs 123 //
2016     // Verify the values just read from the archive file
2017 jgs 119 switch (dataType) {
2018     case 0:
2019     cout << "\tdataType: DataEmpty" << endl;
2020     break;
2021     case 1:
2022     cout << "\tdataType: DataConstant" << endl;
2023     break;
2024     case 2:
2025     cout << "\tdataType: DataTagged" << endl;
2026     break;
2027     case 3:
2028     cout << "\tdataType: DataExpanded" << endl;
2029     break;
2030     default:
2031     throw DataException("extractData Error: undefined dataType read from archive file");
2032     break;
2033     }
2034    
2035     cout << "\tnoSamples: " << noSamples << " noDPPSample: " << noDPPSample << endl;
2036     cout << "\tfunctionSpaceType: " << functionSpaceType << endl;
2037     cout << "\trank: " << dataPointRank << " size: " << dataPointSize << " length: " << dataLength << endl;
2038     cout << "\tshape: < ";
2039     for (int dim = 0; dim < dataPointRank; dim++) {
2040     cout << dataPointShape[dim] << " ";
2041     }
2042     cout << ">" << endl;
2043    
2044     //
2045     // Verify that supplied FunctionSpace object is compatible with this Data object.
2046     if ( (fspace.getTypeCode()!=functionSpaceType) ||
2047     (fspace.getNumSamples()!=noSamples) ||
2048     (fspace.getNumDPPSample()!=noDPPSample)
2049     ) {
2050     throw DataException("extractData Error: incompatible FunctionSpace");
2051     }
2052     for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
2053 gross 964 if (referenceNumbers[sampleNo] != fspace.getReferenceIDOfSample(sampleNo)) {
2054 jgs 119 throw DataException("extractData Error: incompatible FunctionSpace");
2055     }
2056     }
2057     if (dataType==2) {
2058     for (int sampleNo=0; sampleNo<noSamples; sampleNo++) {
2059     if (tagNumbers[sampleNo] != fspace.getTagFromSampleNo(sampleNo)) {
2060     throw DataException("extractData Error: incompatible FunctionSpace");
2061     }
2062     }
2063     }
2064    
2065     //
2066     // Construct a DataVector to hold underlying data values
2067     DataVector dataVec(dataLength);
2068    
2069     //
2070     // Load this DataVector with the appropriate values
2071 jgs 123 int noValues;
2072     archiveFile.read(reinterpret_cast<char *>(&noValues),sizeof(int));
2073     cout << "\tnoValues: " << noValues << endl;
2074 jgs 119 switch (dataType) {
2075     case 0:
2076     // DataEmpty
2077 jgs 123 if (noValues != 0) {
2078     throw DataException("extractData Error: problem reading data from archive file");
2079     }
2080 jgs 119 break;
2081     case 1:
2082     // DataConstant
2083 jgs 123 if (dataVec.extractData(archiveFile,noValues)) {
2084     throw DataException("extractData Error: problem reading data from archive file");
2085     }
2086 jgs 119 break;
2087     case 2:
2088     // DataTagged
2089 jgs 123 if (dataVec.extractData(archiveFile,noValues)) {
2090     throw DataException("extractData Error: problem reading data from archive file");
2091     }
2092 jgs 119 break;
2093     case 3:
2094     // DataExpanded
2095 jgs 123 if (dataVec.extractData(archiveFile,noValues)) {
2096     throw DataException("extractData Error: problem reading data from archive file");
2097     }
2098 jgs 119 break;
2099     }
2100    
2101 jgs 123 if (!archiveFile.good()) {
2102     throw DataException("extractData Error: problem reading from archive file");
2103     }
2104    
2105 jgs 119 //
2106 jgs 123 // Close archive file
2107     archiveFile.close();
2108    
2109     if (!archiveFile.good()) {
2110     throw DataException("extractData Error: problem closing archive file");
2111     }
2112    
2113     //
2114 jgs 119 // Construct an appropriate Data object
2115     DataAbstract* tempData;
2116     switch (dataType) {
2117     case 0:
2118     // DataEmpty
2119     tempData=new DataEmpty();
2120     break;
2121     case 1:
2122     // DataConstant
2123     tempData=new DataConstant(fspace,dataPointShape,dataVec);
2124     break;
2125     case 2:
2126     // DataTagged
2127     tempData=new DataTagged(fspace,dataPointShape,tagNumbers,dataVec);
2128     break;
2129     case 3:
2130     // DataExpanded
2131     tempData=new DataExpanded(fspace,dataPointShape,dataVec);
2132     break;
2133     }
2134     shared_ptr<DataAbstract> temp_data(tempData);
2135     m_data=temp_data;
2136     }
2137    
2138 jgs 94 ostream& escript::operator<<(ostream& o, const Data& data)
2139     {
2140     o << data.toString();
2141     return o;
2142     }
2143 bcumming 782
2144 ksteube 813 Data
2145     escript::C_GeneralTensorProduct(Data& arg_0,
2146     Data& arg_1,
2147     int axis_offset,
2148     int transpose)
2149     {
2150 gross 826 // General tensor product: res(SL x SR) = arg_0(SL x SM) * arg_1(SM x SR)
2151 ksteube 813 // SM is the product of the last axis_offset entries in arg_0.getShape().
2152    
2153    
2154     // Interpolate if necessary and find an appropriate function space
2155 gross 826 Data arg_0_Z, arg_1_Z;
2156 ksteube 813 if (arg_0.getFunctionSpace()!=arg_1.getFunctionSpace()) {
2157     if (arg_0.probeInterpolation(arg_1.getFunctionSpace())) {
2158 gross 826 arg_0_Z = arg_0.interpolate(arg_1.getFunctionSpace());
2159     arg_1_Z = Data(arg_1);
2160 ksteube 813 }
2161     else if (arg_1.probeInterpolation(arg_0.getFunctionSpace())) {
2162 gross 826 arg_1_Z=arg_1.interpolate(arg_0.getFunctionSpace());
2163     arg_0_Z =Data(arg_0);
2164 ksteube 813 }
2165     else {
2166     throw DataException("Error - C_GeneralTensorProduct: arguments have incompatible function spaces.");
2167     }
2168 gross 826 } else {
2169     arg_0_Z = Data(arg_0);
2170     arg_1_Z = Data(arg_1);
2171 ksteube 813 }
2172     // Get rank and shape of inputs
2173 gross 826 int rank0 = arg_0_Z.getDataPointRank();
2174     int rank1 = arg_1_Z.getDataPointRank();
2175     DataArrayView::ShapeType shape0 = arg_0_Z.getDataPointShape();
2176     DataArrayView::ShapeType shape1 = arg_1_Z.getDataPointShape();
2177 ksteube 813
2178     // Prepare for the loops of the product and verify compatibility of shapes
2179     int start0=0, start1=0;
2180     if (transpose == 0) {}
2181     else if (transpose == 1) { start0 = axis_offset; }
2182     else if (transpose == 2) { start1 = rank1-axis_offset; }
2183     else { throw DataException("C_GeneralTensorProduct: Error - transpose should be 0, 1 or 2"); }
2184    
2185     // Adjust the shapes for transpose
2186     DataArrayView::ShapeType tmpShape0;
2187     DataArrayView::ShapeType tmpShape1;
2188     for (int i=0; i<rank0; i++) { tmpShape0.push_back( shape0[(i+start0)%rank0] ); }
2189     for (int i=0; i<rank1; i++) { tmpShape1.push_back( shape1[(i+start1)%rank1] ); }
2190    
2191     #if 0
2192     // For debugging: show shape after transpose
2193     char tmp[100];
2194     std::string shapeStr;
2195     shapeStr = "(";
2196     for (int i=0; i<rank0; i++) { sprintf(tmp, "%d,", tmpShape0[i]); shapeStr += tmp; }
2197     shapeStr += ")";
2198     cout << "C_GeneralTensorProduct: Shape of arg0 is " << shapeStr << endl;
2199     shapeStr = "(";
2200     for (int i=0; i<rank1; i++) { sprintf(tmp, "%d,", tmpShape1[i]); shapeStr += tmp; }
2201     shapeStr += ")";
2202     cout << "C_GeneralTensorProduct: Shape of arg1 is " << shapeStr << endl;
2203     #endif
2204    
2205     // Prepare for the loops of the product
2206     int SL=1, SM=1, SR=1;
2207     for (int i=0; i<rank0-axis_offset; i++) {
2208     SL *= tmpShape0[i];
2209     }
2210     for (int i=rank0-axis_offset; i<rank0; i++) {
2211     if (tmpShape0[i] != tmpShape1[i-(rank0-axis_offset)]) {
2212     throw DataException("C_GeneralTensorProduct: Error - incompatible shapes");
2213     }
2214     SM *= tmpShape0[i];
2215     }
2216     for (int i=axis_offset; i<rank1; i++) {
2217     SR *= tmpShape1[i];
2218     }
2219    
2220     // Define the shape of the output
2221     DataArrayView::ShapeType shape2;
2222 gross 826 for (int i=0; i<rank0-axis_offset; i++) { shape2.push_back(tmpShape0[i]); } // First part of arg_0_Z
2223     for (int i=axis_offset; i<rank1; i++) { shape2.push_back(tmpShape1[i]); } // Last part of arg_1_Z
2224 ksteube 813
2225     // Declare output Data object
2226 gross 826 Data res;
2227 ksteube 813
2228 gross 826 if (arg_0_Z.isConstant() && arg_1_Z.isConstant()) {
2229     res = Data(0.0, shape2, arg_1_Z.getFunctionSpace()); // DataConstant output
2230     double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[0]);
2231     double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[0]);
2232     double *ptr_2 = &((res.getPointDataView().getData())[0]);
2233 ksteube 813 matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2234     }
2235 gross 826 else if (arg_0_Z.isConstant() && arg_1_Z.isTagged()) {
2236 ksteube 813
2237     // Prepare the DataConstant input
2238 gross 826 DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2239 ksteube 813 if (tmp_0==0) { throw DataException("GTP Programming error - casting to DataConstant."); }
2240    
2241     // Borrow DataTagged input from Data object
2242 gross 826 DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2243 ksteube 813 if (tmp_1==0) { throw DataException("GTP_1 Programming error - casting to DataTagged."); }
2244    
2245     // Prepare a DataTagged output 2
2246 gross 826 res = Data(0.0, shape2, arg_1_Z.getFunctionSpace()); // DataTagged output
2247     res.tag();
2248     DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2249 ksteube 813 if (tmp_2==0) { throw DataException("GTP Programming error - casting to DataTagged."); }
2250    
2251     // Prepare offset into DataConstant
2252     int offset_0 = tmp_0->getPointOffset(0,0);
2253 gross 826 double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2254 ksteube 813 // Get the views
2255     DataArrayView view_1 = tmp_1->getDefaultValue();
2256     DataArrayView view_2 = tmp_2->getDefaultValue();
2257     // Get the pointers to the actual data
2258     double *ptr_1 = &((view_1.getData())[0]);
2259     double *ptr_2 = &((view_2.getData())[0]);
2260     // Compute an MVP for the default
2261     matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2262     // Compute an MVP for each tag
2263     const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2264     DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2265     for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2266     tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2267     DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2268     DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2269     double *ptr_1 = &view_1.getData(0);
2270     double *ptr_2 = &view_2.getData(0);
2271     matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2272     }
2273    
2274     }
2275 gross 826 else if (arg_0_Z.isConstant() && arg_1_Z.isExpanded()) {
2276 ksteube 813
2277 gross 826 res = Data(0.0, shape2, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2278     DataConstant* tmp_0=dynamic_cast<DataConstant*>(arg_0_Z.borrowData());
2279     DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2280     DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2281 ksteube 813 if (tmp_0==0) { throw DataException("GTP Programming error - casting to DataConstant."); }
2282     if (tmp_1==0) { throw DataException("GTP Programming error - casting to DataExpanded."); }
2283     if (tmp_2==0) { throw DataException("GTP Programming error - casting to DataExpanded."); }
2284     int sampleNo_1,dataPointNo_1;
2285 gross 826 int numSamples_1 = arg_1_Z.getNumSamples();
2286     int numDataPointsPerSample_1 = arg_1_Z.getNumDataPointsPerSample();
2287 ksteube 813 int offset_0 = tmp_0->getPointOffset(0,0);
2288     #pragma omp parallel for private(sampleNo_1,dataPointNo_1) schedule(static)
2289     for (sampleNo_1 = 0; sampleNo_1 < numSamples_1; sampleNo_1++) {
2290     for (dataPointNo_1 = 0; dataPointNo_1 < numDataPointsPerSample_1; dataPointNo_1++) {
2291     int offset_1 = tmp_1->getPointOffset(sampleNo_1,dataPointNo_1);
2292     int offset_2 = tmp_2->getPointOffset(sampleNo_1,dataPointNo_1);
2293 gross 826 double *ptr_0 = &((arg_0_Z.getPointDataView().getData())[offset_0]);
2294     double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2295     double *ptr_2 = &((res.getPointDataView().getData())[offset_2]);
2296 ksteube 813 matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2297     }
2298     }
2299    
2300     }
2301 gross 826 else if (arg_0_Z.isTagged() && arg_1_Z.isConstant()) {
2302 ksteube 813
2303     // Borrow DataTagged input from Data object
2304 gross 826 DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2305 ksteube 813 if (tmp_0==0) { throw DataException("GTP_0 Programming error - casting to DataTagged."); }
2306    
2307     // Prepare the DataConstant input
2308 gross 826 DataConstant* tmp_1=dynamic_cast<DataConstant*>(arg_1_Z.borrowData());
2309 ksteube 813 if (tmp_1==0) { throw DataException("GTP Programming error - casting to DataConstant."); }
2310    
2311     // Prepare a DataTagged output 2
2312 gross 826 res = Data(0.0, shape2, arg_0_Z.getFunctionSpace()); // DataTagged output
2313     res.tag();
2314     DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2315 ksteube 813 if (tmp_2==0) { throw DataException("GTP Programming error - casting to DataTagged."); }
2316    
2317     // Prepare offset into DataConstant
2318     int offset_1 = tmp_1->getPointOffset(0,0);
2319 gross 826 double *ptr_1 = &((arg_1_Z.getPointDataView().getData())[offset_1]);
2320 ksteube 813 // Get the views
2321     DataArrayView view_0 = tmp_0->getDefaultValue();
2322     DataArrayView view_2 = tmp_2->getDefaultValue();
2323     // Get the pointers to the actual data
2324     double *ptr_0 = &((view_0.getData())[0]);
2325     double *ptr_2 = &((view_2.getData())[0]);
2326     // Compute an MVP for the default
2327     matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2328     // Compute an MVP for each tag
2329     const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2330     DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2331     for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2332     tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2333     DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2334     DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2335     double *ptr_0 = &view_0.getData(0);
2336     double *ptr_2 = &view_2.getData(0);
2337     matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2338     }
2339    
2340     }
2341 gross 826 else if (arg_0_Z.isTagged() && arg_1_Z.isTagged()) {
2342 ksteube 813
2343     // Borrow DataTagged input from Data object
2344 gross 826 DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2345 ksteube 813 if (tmp_0==0) { throw DataException("GTP Programming error - casting to DataTagged."); }
2346    
2347     // Borrow DataTagged input from Data object
2348 gross 826 DataTagged* tmp_1=dynamic_cast<DataTagged*>(arg_1_Z.borrowData());
2349 ksteube 813 if (tmp_1==0) { throw DataException("GTP Programming error - casting to DataTagged."); }
2350    
2351     // Prepare a DataTagged output 2
2352 gross 826 res = Data(0.0, shape2, arg_1_Z.getFunctionSpace());
2353     res.tag(); // DataTagged output
2354     DataTagged* tmp_2=dynamic_cast<DataTagged*>(res.borrowData());
2355 ksteube 813 if (tmp_2==0) { throw DataException("GTP Programming error - casting to DataTagged."); }
2356    
2357     // Get the views
2358     DataArrayView view_0 = tmp_0->getDefaultValue();
2359     DataArrayView view_1 = tmp_1->getDefaultValue();
2360     DataArrayView view_2 = tmp_2->getDefaultValue();
2361     // Get the pointers to the actual data
2362     double *ptr_0 = &((view_0.getData())[0]);
2363     double *ptr_1 = &((view_1.getData())[0]);
2364     double *ptr_2 = &((view_2.getData())[0]);
2365     // Compute an MVP for the default
2366     matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2367     // Merge the tags
2368     DataTagged::DataMapType::const_iterator i; // i->first is a tag, i->second is an offset into memory
2369     const DataTagged::DataMapType& lookup_0=tmp_0->getTagLookup();
2370     const DataTagged::DataMapType& lookup_1=tmp_1->getTagLookup();
2371     for (i=lookup_0.begin();i!=lookup_0.end();i++) {
2372     tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue()); // use tmp_2 to get correct shape
2373     }
2374     for (i=lookup_1.begin();i!=lookup_1.end();i++) {
2375     tmp_2->addTaggedValue(i->first,tmp_2->getDefaultValue());
2376     }
2377     // Compute an MVP for each tag
2378     const DataTagged::DataMapType& lookup_2=tmp_2->getTagLookup();
2379     for (i=lookup_2.begin();i!=lookup_2.end();i++) {
2380     DataArrayView view_0 = tmp_0->getDataPointByTag(i->first);
2381     DataArrayView view_1 = tmp_1->getDataPointByTag(i->first);
2382     DataArrayView view_2 = tmp_2->getDataPointByTag(i->first);
2383     double *ptr_0 = &view_0.getData(0);
2384     double *ptr_1 = &view_1.getData(0);
2385     double *ptr_2 = &view_2.getData(0);
2386     matrix_matrix_product(SL, SM, SR, ptr_0, ptr_1, ptr_2, transpose);
2387     }
2388    
2389     }
2390 gross 826 else if (arg_0_Z.isTagged() && arg_1_Z.isExpanded()) {
2391 ksteube 813
2392     // After finding a common function space above the two inputs have the same numSamples and num DPPS
2393 gross 826 res = Data(0.0, shape2, arg_1_Z.getFunctionSpace(),true); // DataExpanded output
2394     DataTagged* tmp_0=dynamic_cast<DataTagged*>(arg_0_Z.borrowData());
2395     DataExpanded* tmp_1=dynamic_cast<DataExpanded*>(arg_1_Z.borrowData());
2396     DataExpanded* tmp_2=dynamic_cast<DataExpanded*>(res.borrowData());
2397 ksteube 813 if (tmp_0==0) { throw DataException("GTP Programming error - casting to DataTagged."); }
2398