aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortradke <tradke@21a6bef8-4479-4f54-8f8d-0db94a2919ef>2000-09-13 13:49:13 +0000
committertradke <tradke@21a6bef8-4479-4f54-8f8d-0db94a2919ef>2000-09-13 13:49:13 +0000
commit8fe367ecf2cbda79960a68a052fdb84916427c0e (patch)
tree45c017765ab7f0eb6caf97540fc76ffd3bffba59
parentc490022d592551af7c29bc960cbbc09daf45972d (diff)
Importing latest stuff from development repository
git-svn-id: http://svn.cactuscode.org/arrangements/CactusExternal/FlexIO/trunk@2 21a6bef8-4479-4f54-8f8d-0db94a2919ef
-rw-r--r--src/AMRPlus/AMRPlusConv.C168
-rw-r--r--src/AMRPlus/AMRTree.C27
-rw-r--r--src/AMRPlus/AMRTree.h35
-rw-r--r--src/AMRPlus/AMRfilereaderPlus.C175
-rw-r--r--src/AMRPlus/AMRfilereaderPlus.h74
-rw-r--r--src/AMRPlus/AMRgridPlus.h21
-rw-r--r--src/AMRPlus/AMRgridreaderPlus.C90
-rw-r--r--src/AMRPlus/AMRgridreaderPlus.h41
-rw-r--r--src/AMRPlus/AMRreaderPlus.C122
-rw-r--r--src/AMRPlus/AMRreaderPlus.h85
-rw-r--r--src/AMRPlus/AMRwriterPlus.C48
-rw-r--r--src/AMRPlus/AMRwriterPlus.h70
-rw-r--r--src/AMRPlus/Dpndfile193
-rw-r--r--src/AMRPlus/FlexSetTempl.h20
-rw-r--r--src/AMRPlus/filereadtest.C43
-rw-r--r--src/AMRPlus/flexarrays.h184
-rw-r--r--src/AMRPlus/flexmatrix.h20
-rw-r--r--src/AMRPlus/flexset.C215
-rw-r--r--src/AMRPlus/flexset.h209
-rw-r--r--src/AMRPlus/gridreadtest.C40
-rw-r--r--src/AMRPlus/jerror.h291
-rw-r--r--src/AMRPlus/makefile70
-rw-r--r--src/AMRPlus/ordarrays.h23
-rw-r--r--src/AMRPlus/readtest.C54
-rw-r--r--src/AMRPlus/settst.C59
-rw-r--r--src/AMRPlus/testread.C170
-rw-r--r--src/AMRPlus/tst.C42
-rw-r--r--src/AMRwriter.cc473
-rw-r--r--src/AMRwriter.h47
-rw-r--r--src/AMRwriter.hh288
-rw-r--r--src/AVSreadBNB.cc817
-rw-r--r--src/AVSreadHLL.cc768
-rw-r--r--src/AVSreadIEEE.c95
-rw-r--r--src/AVSreadcpp.cc216
-rw-r--r--src/AmrFileReader.cc153
-rw-r--r--src/AmrFileReader.hh69
-rw-r--r--src/AmrGrid.h24
-rw-r--r--src/AmrGrid.hh11
-rw-r--r--src/AmrGridReader.cc87
-rw-r--r--src/AmrGridReader.hh29
-rw-r--r--src/AmrNode.hh42
-rw-r--r--src/AmrUcd.c70
-rw-r--r--src/AmrUcdCompute.cc454
-rw-r--r--src/AmrUcdFileReader.cc27
-rw-r--r--src/AmrUcdFileReader.hh38
-rw-r--r--src/AmrUcdGridHierarchy.cc340
-rw-r--r--src/AmrUcdGridHierarchy.hh134
-rw-r--r--src/AppendTest.c69
-rw-r--r--src/Arch.h74
-rw-r--r--src/Bounds.cc29
-rw-r--r--src/Bounds.hh18
-rw-r--r--src/FlexArrayTmpl.H222
-rw-r--r--src/FlexIO.cc55
-rw-r--r--src/FlexIO.hh27
-rw-r--r--src/GNUmakefile62
-rw-r--r--src/H5IO.cc689
-rw-r--r--src/H5IO.h12
-rw-r--r--src/H5IO.hh130
-rw-r--r--src/H5IOwriter.cc84
-rw-r--r--src/H5writer.c175
-rw-r--r--src/HDFIO.cc413
-rw-r--r--src/HDFIO.h12
-rw-r--r--src/HDFIO.hh79
-rw-r--r--src/IEEEIO.cc1443
-rw-r--r--src/IEEEIO.h13
-rw-r--r--src/IEEEIO.hh709
-rw-r--r--src/IEEEIOWinDllApi.h42
-rw-r--r--src/IEEEIOslave.hh63
-rw-r--r--src/IO.cc371
-rw-r--r--src/IO.hh188
-rw-r--r--src/IOProtos.h63
-rw-r--r--src/IOspeed.cc183
-rw-r--r--src/MPIO.cc199
-rw-r--r--src/MPIO.fast.cc257
-rw-r--r--src/MPIO.fast.hh66
-rw-r--r--src/MPIO.h16
-rw-r--r--src/MPIO.hh39
-rw-r--r--src/MPIO.old.cc344
-rw-r--r--src/MPIO.old.hh80
-rw-r--r--src/MPIO.slow.cc202
-rw-r--r--src/MPIO.slow.hh57
-rw-r--r--src/MPIOspeed.cc201
-rw-r--r--src/MPIutils.cc57
-rw-r--r--src/MPIutils.hh389
-rw-r--r--src/Makefile551
-rw-r--r--src/Makefile.AVS58
-rw-r--r--src/OrderedList.H116
-rw-r--r--src/Reader.cc126
-rw-r--r--src/Reader.hh87
-rw-r--r--src/SampleAmrReader.cc74
-rw-r--r--src/SlaveIO.cc169
-rw-r--r--src/SlaveIO.hh60
-rw-r--r--src/SockIOreader.cc346
-rw-r--r--src/SockIOreader.hh141
-rw-r--r--src/SockIOwriter.cc102
-rw-r--r--src/SockIOwriter.hh181
-rw-r--r--src/Timer.cc44
-rw-r--r--src/Timer.hh39
-rw-r--r--src/Vec3f.hh278
-rw-r--r--src/WildWriter.cc609
-rw-r--r--src/WildWriter.h7
-rw-r--r--src/WildWriter.hh142
-rw-r--r--src/WriteHLL.cc229
-rw-r--r--src/WriteHLL.h32
-rw-r--r--src/WriteHLL.hh52
-rw-r--r--src/Writer.cc169
-rw-r--r--src/Writer.h23
-rw-r--r--src/Writer.hh37
-rw-r--r--src/boxinbox.cc156
-rw-r--r--src/chunkSpeed.cc179
-rw-r--r--src/convert2native.cc50
-rw-r--r--src/copyperf.cc43
-rw-r--r--src/ffio.c108
-rw-r--r--src/ioconvert.cc94
-rw-r--r--src/ioinfo.cc281
-rw-r--r--src/rawSpeed.cc83
-rw-r--r--src/testBigWriter.cc158
-rw-r--r--src/testChunkWriter.cc64
-rw-r--r--src/testSockread.cc29
-rw-r--r--src/testSockwrite.cc21
-rw-r--r--src/testWriter.cc80
-rw-r--r--src/testallocation.cc82
-rw-r--r--src/testhdfReader.cc72
-rw-r--r--src/testio.cc112
-rw-r--r--src/testllReader.cc75
-rw-r--r--src/testllWriter.cc133
-rw-r--r--src/vatoi.cc22
-rw-r--r--src/vatoi.hh6
-rw-r--r--src/writef77.f17
-rw-r--r--src/xmlview.cc272
130 files changed, 19712 insertions, 0 deletions
diff --git a/src/AMRPlus/AMRPlusConv.C b/src/AMRPlus/AMRPlusConv.C
new file mode 100644
index 0000000..7785342
--- /dev/null
+++ b/src/AMRPlus/AMRPlusConv.C
@@ -0,0 +1,168 @@
+// generated by Fast Light User Interface Designer (fluid) version 1.00
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <iostream.h>
+#include "IEEEIO.hh"
+#include "AmrFileReader.hh"
+#include "AMRwriterPlus.h"
+#include "AMRgridPlus.h"
+
+
+
+int main(int argc, char** argv) {
+ IObase *ifile, *ofile;
+ AMRwriterPlus *writer;
+ AmrGridReader *reader;
+ AmrFileReader *freader;
+ int maxlev;
+
+ if (argc!=2){
+ cerr<<"Usage: addscalars <filename>"<<endl;
+ exit(0);
+ }
+ char *fname=strdup(argv[1]);
+ ifile=new IEEEIO(fname, IObase::Read);
+ if (!ifile->isValid()){
+ cerr<<fname<<" is not a valid IEEEIO file."<<endl;
+ exit(0);
+ }
+
+ freader=new AmrFileReader(*ifile);
+ maxlev=freader->nLevels();
+
+ reader=new AmrGridReader(*ifile);
+ if (reader==NULL){
+ cerr<<fname<<" is not a valid AMR file."<<endl;
+ exit(0);
+ }
+ char *outname=(char *)malloc(strlen(fname)+5);
+ strcpy(outname, fname);
+ strcat(outname, "plus");
+
+ ofile=new IEEEIO(outname, IObase::Create);
+ if (!ofile->isValid()){
+ cerr<<"Cannot create "<<outname<<" for output."<<endl;
+ exit(0);
+ }
+ writer = new AMRwriterPlus(*ofile);
+ if (writer==NULL){
+ cerr<<"Something is fishy in denmark. (i.e. at line "<<__LINE__<<")"<<endl;
+ exit(0);
+ }
+
+
+ AMRgridPlus grid;
+ // unsigned long numgrids=reader->getNumGrids();
+ unsigned long datasz;
+
+
+ //prime things:
+ reader->getGridInfo(grid, 0);
+ grid.data=malloc(grid.nbytes);
+ datasz=grid.nbytes;
+ FlexArray< AmrGrid> gridlist;
+
+
+ int tmin, tmax;
+ int numlev = freader->getNumLevels();
+ FlexArray<int> levmask;
+ int lcnt=numlev, tflag=2, tstep=0;
+ double t1, t2, tdiff=0, finetimeref=1.0;
+ int ts1;
+ levmask.setSize(numlev);
+ for(int ii=0;ii<numlev;ii++) levmask[ii]=0;
+ int idx=0;
+ int fixtime=0, fixtimeval;
+ AmrGrid *tgrid;
+ while ( (tgrid=reader->getGridInfo(grid, idx))!=NULL && (lcnt || tflag)){
+ IObase::DataType atype;
+ int length;
+ int attrnum;
+
+ if ((grid.level==0) && tflag){
+ //Getll the time of root grid...
+ double tm;
+ attrnum=ifile->readAttributeInfo("time",atype,length);
+ if(attrnum>=0) ifile->readAttribute(attrnum,&tm);
+ if (tflag==2){
+ t1=tm;
+ ts1=grid.timestep;
+ tflag=1;
+ } else { //tflag==1;
+ t2=tm;
+ tdiff=(t2-t1)/(grid.timestep-(float)ts1);
+ tstep=grid.timestep;
+ if (tdiff!=0) tflag=0;
+ }
+
+ }
+ //If this is a level we havent already seen...
+ if (levmask[grid.level]==0){
+ //Get all the refinement info...
+ attrnum=ifile->readAttributeInfo("time_refinement",atype,length);
+ if(attrnum>=0){
+ ifile->readAttribute(attrnum,&(grid.timeref));
+ }
+ attrnum=ifile->readAttributeInfo("spatial_refinement",atype,length);
+ if(attrnum>=0){
+ ifile->readAttribute(attrnum,&(grid.spaceref));
+ }
+ attrnum=ifile->readAttributeInfo("grid_placement_refinement",atype,length);
+ if(attrnum>=0){
+ ifile->readAttribute(attrnum,&(grid.placeref));
+ }
+ //feed the refinement info to the writer...
+ writer->setLevelRefinement(grid.level,
+ grid.timeref, grid.spaceref, grid.placeref);
+ //and mark the level as done.
+
+ if (grid.level==numlev-1)finetimeref=grid.timeref;
+ levmask[grid.level]=1;
+ lcnt--;
+ }
+ idx++;
+ }
+ tdiff/=finetimeref;
+
+ //Coarse steps should be composed of
+ if (finetimeref!=tstep &&(tstep!=0)){
+ cout<<"Mismatch between max time refinement and timesteps"<<endl;
+ cout<<"Timeref="<<finetimeref<<" | Coarse step="<<tstep<<endl;
+ cout<<"Should I adjust: (C)oarse timestep, or "<<endl;
+ cout<<"should I (I)gnore it?"<<endl;
+ char c=cin.get();
+ if (c=='C' || c=='c') fixtime=1;
+ fixtimeval=tstep/finetimeref;
+ }
+
+ freader->getTimeRange(tmin, tmax);
+ ii=0;
+
+ tgrid=reader->getGridInfo(grid, 0);
+ writer->setType((IObase::DataType)grid.datatype);
+ writer->setTopLevelParameters(grid.rank, grid.origin, grid.delta, tdiff, maxlev);
+
+
+ while (tgrid!=NULL){
+ if (grid.nbytes>datasz) {
+ datasz=grid.nbytes;
+ grid.data=realloc(grid.data, datasz);
+ }
+ reader->getGridData(grid, ii);
+ if (fixtime) grid.timestep/=fixtimeval;
+
+
+
+ writer->write(&grid, 1); //calc scalars & write
+ ii++;
+ tgrid=reader->getGridInfo(grid, ii);
+
+ }
+ delete ifile;
+ delete ofile;
+
+
+}
diff --git a/src/AMRPlus/AMRTree.C b/src/AMRPlus/AMRTree.C
new file mode 100644
index 0000000..9ab86d1
--- /dev/null
+++ b/src/AMRPlus/AMRTree.C
@@ -0,0 +1,27 @@
+#include "AMRTree.h"
+
+void AMRNode::AMRNode(AMRgridPlus *first){
+ subtimes.setsize(first->timeref)
+}
+void AMRNode::buildtree(AMRTree *t, int &idx){
+ AMRgridPlus *g=grids.getData+idx;
+ int clev=g->level;
+ int ctime=c->time;
+ while (g->level==clev && g->time=ctime){
+ idxs.append(idx);
+ idx++;
+ }
+}
+
+
+AMRTree::AMRTree(GridArray *g): timenode{
+ int numlevs=g[0].maxlevel+1;
+ int timeref=g[0].timerefinement;
+ int coarsestep=timeref<<numlevs-1;
+ grids=g;
+
+ for (int ii=0;ii<g.getSize();ii++){
+
+
+ }
+}
diff --git a/src/AMRPlus/AMRTree.h b/src/AMRPlus/AMRTree.h
new file mode 100644
index 0000000..420d4e7
--- /dev/null
+++ b/src/AMRPlus/AMRTree.h
@@ -0,0 +1,35 @@
+#ifndef AMR_TREE_H
+#define AMR_TREE_H
+#include "FlexArrayTempl.H"
+#include "AMRgridPlus.h"
+
+struct idxrec {
+ int idx;
+ int datastat;
+};
+
+typedef FlexArray<int> IntArray;
+
+typedef FlexArray<AMRgridPlus> GridArray
+
+typedef FlexArray<idxrec> IdxArray;
+
+class AMRTree;
+struct AMRNode{
+ IdxArray idxs;
+ AMRTree subtimes;
+};
+
+class AMRTree: protected FlexArray<AMRNode>{
+ void buildtree(AMRTree *t, int &idx);
+ public:
+ AMRTree(GridArray *);
+ ~AMRTree();
+
+ private:
+ AMRNode timenode;
+ GridArray grids;
+};
+
+
+#endif
diff --git a/src/AMRPlus/AMRfilereaderPlus.C b/src/AMRPlus/AMRfilereaderPlus.C
new file mode 100644
index 0000000..17d0e45
--- /dev/null
+++ b/src/AMRPlus/AMRfilereaderPlus.C
@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "AMRfilereaderPlus.h"
+#include "FlexArrayTmpl.H"
+void AMRfilereaderPlus::printGridInfo(AMRgridPlus &g){
+ printf("Grid level=%u step=%u maxtime=%u\n",g.level,g.timestep,g.maxtime);
+ printf("\trank=%u dims[",g.rank);
+ for(int i=0;i<g.rank-1;i++) printf("%u,",g.dims[i]);
+ printf("%u]\n",g.dims[g.rank-1]);
+ printf("\tTimerefine=%u dx[0]=%lf origin[",g.timerefinement,g.delta[0]);
+ for(i=0;i<g.rank-1;i++) printf("%lf,",g.origin[i]);
+ printf("%lf]\n",g.origin[g.rank-1]);
+ printf("\tData Pointer is %u\n",(unsigned long)(g.data));
+ if(g.data){
+ float *fdata = (float *)(g.data);
+ for(int i=0;i<3;i++)
+ printf("\t\tData[%u]=%f\n",i,fdata[i]);
+ }
+ }
+ void AMRfilereaderPlus::printGridInfo(){
+ // print it all out...
+ printf("MaxLevel=%u\n",maxlevel);
+ for(int i=0;i<grids.getSize();i++){
+ printf("Grid[%u]--------------------\n",i);
+ printGridInfo(grids[i]);
+ }
+ }
+ void AMRfilereaderPlus::printActiveGrids(){
+ // print it all out...
+ printf("Num Active Grids=%u\n",activeGrids.getSize());
+ for(int i = 0; i < activeGrids.getSize(); i++){
+ printf(" Grid[%u] mapped from %u --------------------\n",
+ i,activeGrids[i]);
+ printGridInfo(grids[activeGrids[i]]);
+ }
+ }
+#define MAXIMIZE(u, v) {(u)=((u)>(v))?(u):(v);}
+#define MINIMIZE(u, v) {(u)=((u)<(v))?(u):(v);}
+
+void AMRfilereaderPlus::buildInfoTable(){
+ // Load all grids Info
+ int index=0;
+ AMRgridPlus g;
+ while(getGridInfo(g,index++)){
+ if(this->debug) printf("buildInfoTable: getGrid index=%u\n",index);
+ if(this->debug) printGridInfo(g);
+ int i=grids.getSize();
+ g.data=0; // zero out the data
+ if(g.level>maxlevel)
+ maxlevel=g.level;
+ if(!i){
+ smin=g.scalarmin;
+ smax=g.scalarmax;
+ mintime = g.timestep;
+ maxtime = g.timestep;
+ maxtimeres = g.timerefinement;
+ maxlevel= g.level;
+ bounds[0]=g.origin[0];
+ bounds[1]=g.origin[0]+g.delta[0]*g.dims[0];
+ bounds[2]=g.origin[1];
+ bounds[3]=g.origin[1]+g.delta[1]*g.dims[1];
+ bounds[4]=g.origin[2];
+ bounds[5]=g.origin[2]+g.delta[2]*g.dims[2];
+ }
+ else{
+ MINIMIZE(smin, g.scalarmin);
+ MAXIMIZE(smax, g.scalarmax);
+ if (g.level==0){
+ MINIMIZE(bounds[0], g.origin[0]);
+ MAXIMIZE(bounds[1], g.origin[0]+g.delta[0]*g.dims[0]);
+ MINIMIZE(bounds[2], g.origin[1]);
+ MAXIMIZE(bounds[3], g.origin[1]+g.delta[1]*g.dims[1]);
+ MINIMIZE(bounds[4], g.origin[2]);
+ MAXIMIZE(bounds[5], g.origin[2]+g.delta[2]*g.dims[2]);
+ }
+ }
+ if(g.timestep<mintime)
+ mintime=g.timestep;
+ if(g.timestep>maxtime)
+ maxtime=g.timestep;
+ if(g.timerefinement>maxtimeres)
+ maxtimeres=g.timerefinement;
+ grids.append(g);
+ }
+}
+
+void AMRfilereaderPlus::loadGrids(){
+ if(!gridloading) return;
+ for(int i=0;i<activeGrids.getSize();i++){
+ if(this->debug) printf("buildInfoTable: getGrid index=%u activegridindex %u\n",i,activeGrids[i]);
+ if(this->debug) printGridInfo(grids[activeGrids[i]]);
+ getGridData(grids[activeGrids[i]],activeGrids[i]);
+ }
+}
+
+void AMRfilereaderPlus::reclaimGrids(){
+ if(!gridloading) return;
+ for(int i=0;i<grids.getSize();i++){
+ int f=0;
+ for(int j=0;j<activeGrids.getSize();j++){
+ if(activeGrids[j]==i){
+ f=1;
+ break;
+ }
+ }
+ if(!f){
+ free((grids[i]).data);
+ (grids[i]).data=0;
+ }
+ }
+}
+
+void AMRfilereaderPlus::purgeGrids(){
+ for(int i=0;i<grids.getSize();i++){
+ if((grids[i]).data)
+ free((grids[i]).data);
+ (grids[i]).data=0;
+ }
+}
+
+AMRfilereaderPlus::AMRfilereaderPlus(IObase &f):AMRgridreaderPlus(f),debug(0),gridloading(1){
+ // we need to build a table from the file
+ // then select grids based on the timestep
+ buildInfoTable(); // initialize the convertor
+ levelmask.setSize(maxlevel+1);
+ for(int i=0;i<=maxlevel;i++)
+ levelmask[i]=1; // all levels visible is default
+ showAllLevels();
+ setTime(mintime);
+}
+
+void AMRfilereaderPlus::setTime(int timestep){
+ // Make Grid Selections
+ if(timestep<mintime || timestep>maxtime){
+ printf("timestep %u is out of range %u:%u\n",
+ timestep,mintime,maxtime);
+ return;
+ }
+ activeGrids.purge();
+ current_time=timestep;
+ if(this->debug) printf("setTime(%u): mintime=%u maxtime=%u\n",current_time,mintime,maxtime);
+ for(int i=0;i<grids.getSize();i++){
+ if(this->debug) printf("\tgrids[%u].timestep=%u maxtime=%u\n",i,grids[i].timestep,
+ grids[i].maxtime);
+ if(current_time>=grids[i].timestep &&
+ current_time<grids[i].maxtime && levelmask[grids[i].level]){
+ activeGrids.append(i);
+ if(this->debug) printf("\t\tAppendGrid number %u\n",i);
+ }
+ }
+ if(this->debug) puts("load grids");
+ loadGrids();
+ if(this->debug) puts("reclaim grids");
+ reclaimGrids();
+}
+
+void AMRfilereaderPlus::showAllLevels(){
+ for(int i=0;i<levelmask.getSize();i++) levelmask[i]=1;
+}
+
+// For C interface
+
+int AMRfilereaderPlus::getGrids(AMRgridPlus *g){ // assumes number of
+ for(int i=0;i<grids.getSize();i++)
+ g[i]=grids[activeGrids[i]];
+ return activeGrids.getSize();
+}
+
+// For C++ interface
+int AMRfilereaderPlus::getGrids(FlexArray<AMRgridPlus> &g){
+ g.setSize(activeGrids.getSize());
+ for(int i=0;i<g.getSize();i++)
+ g[i]=grids[activeGrids[i]];
+ return activeGrids.getSize();
+}
diff --git a/src/AMRPlus/AMRfilereaderPlus.h b/src/AMRPlus/AMRfilereaderPlus.h
new file mode 100644
index 0000000..a90569d
--- /dev/null
+++ b/src/AMRPlus/AMRfilereaderPlus.h
@@ -0,0 +1,74 @@
+// AmrFileReader
+#ifndef __AMRFILEREADERPLUS_HH_
+#define __AMRFILEREADERPLUS_HH_
+#include <stdio.h>
+#include <IO.hh>
+#include "AMRgridreaderPlus.h"
+#include "FlexArrayTmpl.H"
+
+class AMRfilereaderPlus : public AMRgridreaderPlus {
+protected:
+ int gridloading;
+ FlexArray<int> activeGrids;
+ FlexArray<AMRgridPlus> grids;
+ FlexArray<int> levelmask;
+ IObase::DataType datatype;
+ int maxlevel,maxtimeres,mintime,maxtime;
+ double smax, smin;
+ double bounds[6];
+ int current_time;
+ // Internal Utility methods
+ void buildInfoTable();
+ void loadGrids();
+ void reclaimGrids();
+ void purgeGrids();
+ void printGridInfo(AMRgridPlus &g);
+public:
+ int debug;
+ void printGridInfo();
+ void printActiveGrids();
+ AMRfilereaderPlus(IObase &f);
+ int getNumLevels(){ return maxlevel+1; }
+ void getTimeRange(int &min,int &max){
+ min=mintime;
+ max=maxtime;
+ }
+ void getScalarRange(double &min, double &max){
+ min=smin;max=smax;
+ }
+ void getBounds(double *bnds){for (int ii=0;ii<6;ii++){bnds[ii]=bounds[ii];}}
+ void setTime(int timestep);
+ // starts out with all selected
+ void showLevel(int level=-1){ // default is all (-1)
+ if(level>=levelmask.getSize() || level<0){
+ printf("AmrConvert::showLevel(%u) : Level out of range 0:%u\n",
+ level,levelmask.getSize()-1);
+ }
+ else
+ levelmask[level]=1;
+ }
+ void showAllLevels();
+ void hideAllLevels(){for (int ii=0;ii<maxlevel+1;ii++)hideLevel(ii);}
+ void hideLevel(int level=-1){ // default is all (-1)
+ if(level>=levelmask.getSize() || level<0){
+ printf("AmrConvert::showLevel(%u) : Level out of range 0:%u\n",
+ level,levelmask.getSize()-1);
+ }
+ else
+ levelmask[level]=0;
+ }
+ int nLevels(){ return maxlevel+1; }
+ IObase::DataType getDataType(){return datatype;}
+ // For C interface
+ int getNumGrids(){ // number of active grids
+ return activeGrids.getSize();
+ }
+ int getActiveIndex(int ii){ return activeGrids[ii];}
+ int getGrids(AMRgridPlus *g);
+ // For C++ interface
+ int getGrids(FlexArray<AMRgridPlus> &g);
+ void setDataLoadingOff(){ gridloading=0; purgeGrids();}
+ void setDataLoadingOn(){ gridloading=1; loadGrids();}
+};
+
+#endif
diff --git a/src/AMRPlus/AMRgridPlus.h b/src/AMRPlus/AMRgridPlus.h
new file mode 100644
index 0000000..b8f866c
--- /dev/null
+++ b/src/AMRPlus/AMRgridPlus.h
@@ -0,0 +1,21 @@
+#ifndef __AMR_GRID_HH_
+#define __AMR_GRID_HH_
+#include "AmrGrid.h"
+#include "flexset.h"
+
+struct AMRgridPlus : public AmrGrid {
+ double time;
+ int timeref, spaceref[3], placeref[3];
+ double scalarmin,scalarmax;
+};
+
+struct idxrec{
+ int idx;
+ idxrec(int first=0){idx=first;}
+ int operator<(const idxrec &other)const {return idx<other.idx;}
+ int operator==(const idxrec &other)const {return idx==other.idx;}
+};
+
+typedef flexset<idxrec> IdxSet;
+typedef flexarray<AMRgridPlus > GridArray;
+#endif
diff --git a/src/AMRPlus/AMRgridreaderPlus.C b/src/AMRPlus/AMRgridreaderPlus.C
new file mode 100644
index 0000000..de131d3
--- /dev/null
+++ b/src/AMRPlus/AMRgridreaderPlus.C
@@ -0,0 +1,90 @@
+#include "AMRgridreaderPlus.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream.h>
+
+
+
+
+
+AMRgridPlus *AMRgridreaderPlus::getGridInfo(AMRgridPlus &g,int index){
+ g.dataveclen=1;
+ if(file.seek(index)<index)
+ return 0; // fail if index past end
+ IObase::DataType dt;
+ file.readInfo(dt,g.rank,g.dims);
+ g.datatype = dt;
+ g.nbytes = IObase::nBytes(dt,g.rank,g.dims);
+ // find the deepest level (finest time resolution)
+ // Attrib Names?
+ IObase::DataType atype;
+ int length;
+ int attrnum=file.readAttributeInfo("level",atype,length);
+ if(attrnum>=0){
+ int lev; // should be Int level
+ file.readAttribute(attrnum,&lev);
+ if(lev>g.maxlevel) g.maxlevel=lev;
+ g.level=lev;
+ }
+ attrnum=file.readAttributeInfo("time",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.time));
+ }attrnum=file.readAttributeInfo("time_refinement",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.timerefinement));
+ }
+ attrnum=file.readAttributeInfo("timestep",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.timestep));
+ }
+ attrnum=file.readAttributeInfo("origin",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,(g.origin));
+ attrnum=file.readAttributeInfo("delta",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,(g.delta));
+ attrnum=file.readAttributeInfo("persistence",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.persistence));
+ g.maxtime = g.timestep + g.persistence;
+ }
+
+ attrnum=file.readAttributeInfo("time_refinement",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.timeref));
+ }
+ attrnum=file.readAttributeInfo("spatial_refinement",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.spaceref));
+ }
+ attrnum=file.readAttributeInfo("grid_placement_refinement",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.placeref));
+ }
+
+ attrnum=file.readAttributeInfo("range",atype,length);
+ if(attrnum>=0){
+ double range[2];
+ file.readAttribute(attrnum,&range);
+ g.scalarmin=range[0]; g.scalarmax=range[1];
+ }
+ else {
+ cout<<"Please convert this file with AMRPlusConv"<<endl;
+ exit(0);
+ }
+
+ g.data=0;
+ return &g;
+} // done
+
+AMRgridPlus *AMRgridreaderPlus::getGridData(AMRgridPlus &g,int index){
+ IObase::DataType atype;
+ // if(data) free(data); data=0; // make certain it is empty first
+ g.data = malloc(g.nbytes);
+ file.seek(index);
+ file.readInfo(atype,g.rank,g.dims);
+ g.datatype=atype;
+ file.read(g.data);
+ return &g;
+}
+
diff --git a/src/AMRPlus/AMRgridreaderPlus.h b/src/AMRPlus/AMRgridreaderPlus.h
new file mode 100644
index 0000000..fc6f797
--- /dev/null
+++ b/src/AMRPlus/AMRgridreaderPlus.h
@@ -0,0 +1,41 @@
+#ifndef __AMRGRIDREADERPLUS_HH_
+#define __AMRGRIDREADERPLUS_HH_
+
+#include <IO.hh>
+#include "AMRgridPlus.h"
+#include "IEEEIO.hh"
+
+
+class AMRgridreaderPlus {
+protected:
+ IObase &file;
+
+public:
+ AMRgridreaderPlus(IObase &f) : file(f){};
+ ~AMRgridreaderPlus(){};
+
+ /*
+ * Low level grid/info fetching routines
+ */
+ AMRgridPlus *getGrid(AMRgridPlus &g,int index){
+ if(file.seek(index)<index)
+ return 0; // don't load past end
+ getGridInfo(g,index);
+ getGridData(g,index);
+ return &g;
+ }
+ AMRgridPlus *getGrid(int index){
+ AMRgridPlus *g=new AMRgridPlus;
+ return this->getGrid(*g,index);
+ }
+
+ AMRgridPlus *getGridInfo(AMRgridPlus &g,int index);
+ AMRgridPlus *getGridData(AMRgridPlus &g,int index);
+
+
+
+
+};
+
+
+#endif
diff --git a/src/AMRPlus/AMRreaderPlus.C b/src/AMRPlus/AMRreaderPlus.C
new file mode 100644
index 0000000..bc47e7b
--- /dev/null
+++ b/src/AMRPlus/AMRreaderPlus.C
@@ -0,0 +1,122 @@
+#include "AMRreaderPlus.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream.h>
+#include <algorithm>
+
+
+AMRreaderPlus::AMRreaderPlus(IObase &f) : AMRgridreaderPlus(f), grids(),
+ activeset(), timemask(), levelmask(), realtimes()
+{
+ init();
+ selectTimeStep(0);
+ for (int ii=0;ii<=maxlevel;ii++) showLevel(ii);
+ modflag=1;
+}
+
+
+
+AMRreaderPlus::~AMRreaderPlus(){
+
+}
+
+
+
+void AMRreaderPlus::init(){
+ maxlevel=maxtimeres=maxtime=0;
+ smin=smax=0.0;
+ numgrids=0;
+
+ build_info();
+}
+void AMRreaderPlus::build_info(){
+ AMRgridPlus *res, newg;
+ res=getGridInfo(newg, 0);
+ if (res==NULL) return;
+ maxlevel=0;
+ maxtime=0;
+ numgrids=0;
+ smin=newg.scalarmin;
+ smax=newg.scalarmax;
+ datatype=newg.datatype;
+ while (res!=NULL){ //Load all grid info
+ grids.append(newg);
+ realtimes.insert(newg.time);
+ maxlevel=(maxlevel>newg.level)?maxlevel:newg.level;
+ maxtime=(maxtime>newg.timestep)?maxtime:newg.timestep;
+ smax=smax>newg.scalarmax?smax:newg.scalarmax;
+ smin=smin<newg.scalarmin?smin:newg.scalarmin;
+ numgrids++;
+ res=getGridInfo(newg, numgrids);
+ }
+ levelmask.fill(0, maxlevel+1);
+ timemask.fill(0, maxtime+1);
+
+
+ leveltimes= new flexmatrix<IdxArray> (maxlevel+1, maxtime+1);
+
+ AMRgridPlus *g= grids.getData(0);
+ for(int ii=0;ii<grids.getSize();ii++){//Extract basic info
+ for (int jj=g->timestep;jj<g->timestep+g->persistence;jj++){
+ if (jj<=maxtime){
+ idxrec trec(ii);
+ (*leveltimes)(g->level, jj).append(trec.idx);
+ }
+ }
+ g++;
+ }
+
+ cout<<realtimes.getSize()<<" "<<numgrids<<endl<<endl;
+
+}
+
+void AMRreaderPlus::build_active(){
+ IdxSet newset, delset;
+
+ //Calculate what the set should be
+ for (int ii=0;ii<=maxtime;ii++)
+ for (int jj=0;jj<=maxlevel;jj++)
+ if (timemask[ii]&&levelmask[jj]){
+ for (int kk=0;kk<(*leveltimes)(jj, ii).getSize();kk++){
+ newset.insert((*leveltimes)(jj, ii)[kk]);
+ }
+ }
+
+ //remove all the unneeded grids
+ setdifference(activeset, newset, delset);
+ for (ii=0;ii<delset.getSize();ii++)
+ if (grids[delset[ii].idx].data!=NULL){
+ free(grids[delset[ii].idx].data);
+ grids[delset[ii].idx].data=NULL;
+ }
+ activeset=newset;
+}
+
+
+void AMRreaderPlus::modify(){modflag=1;}
+
+void AMRreaderPlus::getActive(IdxSet &grids){
+ if (modflag!=0){
+ build_active();
+ modflag=0;
+ }
+ grids=activeset;
+}
+
+void AMRreaderPlus::loadData(IdxSet &loadset){
+ if (modflag!=0){
+ build_active();
+ modflag=0;
+ }
+
+ if (!activeset.contains(loadset)){
+ cout<<"Trying to load non-active grids. Hmmmm."<<endl;
+ }
+
+ for (int ii=0;ii<loadset.getSize();ii++){
+ if (grids[loadset[ii].idx].data==NULL){
+ cout<<"Loaded "<<loadset[ii].idx<<endl;
+ getGridData(grids[loadset[ii].idx], loadset[ii].idx);
+ }
+ }
+}
diff --git a/src/AMRPlus/AMRreaderPlus.h b/src/AMRPlus/AMRreaderPlus.h
new file mode 100644
index 0000000..6bd3387
--- /dev/null
+++ b/src/AMRPlus/AMRreaderPlus.h
@@ -0,0 +1,85 @@
+#ifndef __AMRREADERPLUS_HH_
+#define __AMRREADERPLUS_HH_
+
+#include <set>
+#include <vector>
+#include <IO.hh>
+#include "AMRgridreaderPlus.h"
+#include "IEEEIO.hh"
+
+#include "flexmatrix.h"
+#include "flexset.h"
+#define kNoData 0
+#define kHasData 1
+
+/* Method for calculating scalar range - the global range,
+range per fine timestep, per coarse, or per (current) root. */
+typedef enum {kGlobal,kFine,kCoarse,kRoot} ScalarMode;
+
+using namespace std;
+
+
+
+typedef flexarray<int> IntArray;
+
+
+
+typedef flexarray<int> IdxArray;
+
+
+class AMRreaderPlus : public AMRgridreaderPlus {
+ public:
+ int datatype;
+ int numgrids;
+ int maxlevel,maxtimeres,maxtime;
+ double smin,smax;
+ int modflag;
+
+ IdxSet activeset;
+ flexset<float> realtimes;
+ flexmatrix<IdxArray> *leveltimes;
+ GridArray grids;
+ IntArray levelmask, timemask;
+
+ void init();
+ void build_info();
+ void build_active();
+ void modify(); //Flag that tells when active set has changed
+public:
+ AMRreaderPlus(IObase &f);
+ ~AMRreaderPlus();
+
+ int getNumLevels(){return maxlevel+1;}
+ int getNumTimesteps(){return maxtime+1;}
+ int getNumGrids(){return numgrids;}
+ int getDataType(){return datatype;}
+
+ void showTimeStep(int ts){
+ if (ts>=0 && ts<=maxtime) {timemask[ts]=1; modify();}
+ else cout<<"Timestep out of range: "<<ts<<endl;
+ }
+ void hideTimeStep(int ts){
+ if (ts>=0 && ts<=maxtime) {timemask[ts]=0; modify();}
+ else cout<<"Timestep out of range: "<<ts<<endl;
+ }
+ void selectTimeStep(int ts) //Shortcut- hides all times but ts
+ { for (int ii=0;ii<=maxtime;ii++) timemask[ii]=(ii==ts)?1:0;modify();}
+
+ void showLevel(int lev){
+ if (lev>=0 && lev<=maxlevel) {levelmask[lev]=1; modify();}
+ else cout<<"Level out of range: "<<lev<<endl;
+ }
+ void hideLevel(int lev){
+ if (lev>=0 && lev<=maxlevel) {levelmask[lev]=0; modify();}
+ else cout<<"Level out of range: "<<lev<<endl;
+ }
+
+ GridArray *getGridSet(){return &grids;}
+ void getActive(IdxSet &grids);
+ void loadData(IdxSet &loadset);
+ void loadData(){loadData(activeset);}
+
+};
+
+
+#endif
diff --git a/src/AMRPlus/AMRwriterPlus.C b/src/AMRPlus/AMRwriterPlus.C
new file mode 100644
index 0000000..856a356
--- /dev/null
+++ b/src/AMRPlus/AMRwriterPlus.C
@@ -0,0 +1,48 @@
+#include "AMRwriterPlus.h"
+
+
+AMRwriterPlus::AMRwriterPlus(IObase &descriptor) : AMRwriter(descriptor){
+ scalarFlag=0;
+ curscalarmin=curscalarmax=0;
+}
+
+void AMRwriterPlus::calcScalarRange(void *data){
+ long numelts=1;
+ for (int ii=0;ii<drank;ii++) numelts*=ddims[ii];
+
+ switch(this->dtypeID){
+ case IObase::Byte:{
+ char *dptr=(char *)data;
+ curscalarmin=curscalarmax=*dptr;
+ for (long kk=0;kk<numelts;kk++){
+ curscalarmin=(curscalarmin<dptr[kk])?curscalarmin:dptr[kk];
+ curscalarmax=(curscalarmax>=dptr[kk])?curscalarmax:dptr[kk];
+ }
+ } break;
+ case IObase::Float32:{
+ float *fptr=(float *)data;
+ curscalarmin=curscalarmax=*fptr;
+ for (long jj=0;jj<numelts;jj++){
+ curscalarmin=(curscalarmin<fptr[jj])?curscalarmin:fptr[jj];
+ curscalarmax=(curscalarmax>=fptr[jj])?curscalarmax:fptr[jj];
+ }
+ } break;
+ case IObase::Float64:{
+ double *dptr=(double *)data;
+ curscalarmin=curscalarmax=*dptr;
+ for (long kk=0;kk<numelts;kk++){
+ curscalarmin=(curscalarmin<dptr[kk])?curscalarmin:dptr[kk];
+ curscalarmax=(curscalarmax>=dptr[kk])?curscalarmax:dptr[kk];
+ }
+ } break;
+ }
+}
+
+
+void AMRwriterPlus::writePlusattributes(){
+ double range[2];
+ range[0]=curscalarmin;
+ range[1]=curscalarmax;
+ file.writeAttribute("range", IObase::Float64, 2, range);
+ scalarFlag=0; //reset the flag
+}
diff --git a/src/AMRPlus/AMRwriterPlus.h b/src/AMRPlus/AMRwriterPlus.h
new file mode 100644
index 0000000..a3c47ff
--- /dev/null
+++ b/src/AMRPlus/AMRwriterPlus.h
@@ -0,0 +1,70 @@
+#include "AMRwriter.hh"
+#include "AMRgridPlus.h"
+
+/*
+ * AMRwriterPlus:
+ * A subclass of AMRwriter which adds a scalar range attribute
+ * to each dataset. The AMRwriter interface is unchanged, however
+ * for convenience, you can:
+ *
+ * Set the top level parameters or write a dataset by passing a
+ * pointer to an AMRgridPlus datastructure to ::setTopLevelParameters
+ * or ::write respectively
+ *
+ * Set the scalar range of the dataset explicitly (before writing)
+ * with ::setScalarRange. If this is not called, the scalar range will
+ * be computed from within ::write. Useful (and timesaving) if you
+ * have already computed the range.
+ */
+
+class AMRwriterPlus : public AMRwriter{
+ public:
+ AMRwriterPlus(IObase &descriptor);
+
+ virtual void setTopLevelParameters(AMRgridPlus *g){
+ AMRwriter::setTopLevelParameters(g->rank, g->origin, g->delta, \
+ g->timestep, g->maxlevel);
+ }
+
+ // CC forces me to re-overload this inherited method!
+ virtual void setTopLevelParameters(int rank,double *origin,
+ double *delta,double timestep,int maxdepth){
+ AMRwriter::setTopLevelParameters(rank, origin, delta, timestep, maxdepth);
+ }
+
+ void setScalarRange(double smin,double smax){
+ curscalarmin=smin;curscalarmax=smax;scalarFlag=1;}
+
+ void write(int *origin,int *dims,void *data){
+ AMRwriter::write(origin, dims, data);
+ if (!scalarFlag) calcScalarRange(data);
+ writePlusattributes();
+ }
+ void write(float *origin,int *dims,void *data){
+ AMRwriter::write(origin, dims, data);
+ if (!scalarFlag) calcScalarRange(data);
+ writePlusattributes();
+ }
+ void write(double *origin,int *dims,void *data){
+ AMRwriter::write(origin, dims, data);
+ if (!scalarFlag) calcScalarRange(data);
+ writePlusattributes();
+ }
+
+ virtual void write(AMRgridPlus *g, int calcscalars=0){
+
+ setType((IObase::DataType)g->datatype);
+ setLevel(g->level);
+ setTime(g->timestep);
+ write(g->origin, g->dims, g->data);
+ }
+
+ protected:
+ void writePlusattributes();
+
+ private:
+ void calcScalarRange(void *data);
+
+ double curscalarmin, curscalarmax;
+ int scalarFlag;
+};
diff --git a/src/AMRPlus/Dpndfile b/src/AMRPlus/Dpndfile
new file mode 100644
index 0000000..1535d4b
--- /dev/null
+++ b/src/AMRPlus/Dpndfile
@@ -0,0 +1,193 @@
+AMRwriterPlus.o: AMRwriterPlus.C AMRwriterPlus.h \
+ /home/jshalf/Develop/FlexIO/AMRwriter.hh \
+ /home/jshalf/Develop/FlexIO/Arch.h /usr/include/sys/types.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h /usr/include/bits/types.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stddef.h \
+ /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h \
+ /usr/include/string.h /home/jshalf/Develop/FlexIO/IO.hh \
+ /home/jshalf/Develop/FlexIO/IO.h \
+ /home/jshalf/Develop/FlexIO/Writer.hh \
+ /home/jshalf/Develop/FlexIO/Writer.h \
+ /home/jshalf/Develop/FlexIO/FlexArrayTmpl.H \
+ /home/jshalf/Develop/FlexIO/AMRwriter.h AMRgridPlus.h \
+ /home/jshalf/Develop/FlexIO/AmrGrid.h flexset.h flexarrays.h \
+ /usr/include/stdlib.h /usr/include/alloca.h
+AMRgridreaderPlus.o: AMRgridreaderPlus.C AMRgridreaderPlus.h \
+ /home/jshalf/Develop/FlexIO/IO.hh /home/jshalf/Develop/FlexIO/Arch.h \
+ /usr/include/sys/types.h /usr/include/features.h \
+ /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
+ /usr/include/bits/types.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stddef.h \
+ /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h \
+ /usr/include/string.h /home/jshalf/Develop/FlexIO/IO.h AMRgridPlus.h \
+ /home/jshalf/Develop/FlexIO/AmrGrid.h flexset.h flexarrays.h \
+ /usr/include/stdlib.h /usr/include/alloca.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.hh /usr/include/stdio.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stdarg.h \
+ /usr/include/libio.h /usr/include/_G_config.h \
+ /usr/include/bits/stdio_lim.h /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+ /usr/include/getopt.h /usr/include/sys/file.h /usr/include/fcntl.h \
+ /usr/include/bits/fcntl.h \
+ /home/jshalf/Develop/FlexIO/IEEEIOWinDllApi.h \
+ /home/jshalf/Develop/FlexIO/FlexArrayTmpl.H /usr/include/sys/stat.h \
+ /usr/include/bits/stat.h /usr/include/strings.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/iostream.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/streambuf.h
+AMRfilereaderPlus.o: AMRfilereaderPlus.C /usr/include/stdio.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stddef.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stdarg.h \
+ /usr/include/bits/types.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/bits/stdio_lim.h \
+ /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h \
+ /usr/include/alloca.h AMRfilereaderPlus.h \
+ /home/jshalf/Develop/FlexIO/IO.hh /home/jshalf/Develop/FlexIO/Arch.h \
+ /usr/include/string.h /home/jshalf/Develop/FlexIO/IO.h \
+ AMRgridreaderPlus.h AMRgridPlus.h \
+ /home/jshalf/Develop/FlexIO/AmrGrid.h flexset.h flexarrays.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.hh /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+ /usr/include/getopt.h /usr/include/sys/file.h /usr/include/fcntl.h \
+ /usr/include/bits/fcntl.h \
+ /home/jshalf/Develop/FlexIO/IEEEIOWinDllApi.h \
+ /home/jshalf/Develop/FlexIO/FlexArrayTmpl.H /usr/include/sys/stat.h \
+ /usr/include/bits/stat.h /usr/include/strings.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.h
+flexset.o: flexset.C flexset.h flexarrays.h /usr/include/string.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stddef.h \
+ /usr/include/stdlib.h /usr/include/sys/types.h \
+ /usr/include/bits/types.h /usr/include/time.h /usr/include/endian.h \
+ /usr/include/bits/endian.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/sigset.h \
+ /usr/include/sys/sysmacros.h /usr/include/alloca.h
+AMRreaderPlus.o: AMRreaderPlus.C AMRreaderPlus.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/set \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_tree.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_algobase.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_config.h \
+ /usr/include/_G_config.h /usr/include/bits/types.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stddef.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_relops.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_pair.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/type_traits.h \
+ /usr/include/string.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/limits.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/syslimits.h \
+ /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+ /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+ /usr/include/bits/posix2_lim.h /usr/include/stdlib.h \
+ /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \
+ /usr/include/bits/endian.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/sigset.h \
+ /usr/include/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/new.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/new \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/exception \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/iostream.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/streambuf.h \
+ /usr/include/libio.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stdarg.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_iterator.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_alloc.h \
+ /usr/include/assert.h /usr/include/pthread.h /usr/include/sched.h \
+ /usr/include/bits/sched.h /usr/include/bits/time.h \
+ /usr/include/signal.h /usr/include/bits/pthreadtypes.h \
+ /usr/include/bits/sigthread.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_construct.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_function.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_set.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_multiset.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/vector \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_uninitialized.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_vector.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_bvector.h \
+ /home/jshalf/Develop/FlexIO/IO.hh /home/jshalf/Develop/FlexIO/Arch.h \
+ /home/jshalf/Develop/FlexIO/IO.h AMRgridreaderPlus.h AMRgridPlus.h \
+ /home/jshalf/Develop/FlexIO/AmrGrid.h flexset.h flexarrays.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.hh /usr/include/stdio.h \
+ /usr/include/bits/stdio_lim.h /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+ /usr/include/getopt.h /usr/include/sys/file.h /usr/include/fcntl.h \
+ /usr/include/bits/fcntl.h \
+ /home/jshalf/Develop/FlexIO/IEEEIOWinDllApi.h \
+ /home/jshalf/Develop/FlexIO/FlexArrayTmpl.H /usr/include/sys/stat.h \
+ /usr/include/bits/stat.h /usr/include/strings.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.h flexmatrix.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/algorithm \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_tempbuf.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_algo.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_heap.h
+readtest.o: readtest.C /usr/include/stdio.h /usr/include/features.h \
+ /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stddef.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/stdarg.h \
+ /usr/include/bits/types.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/bits/stdio_lim.h \
+ /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h \
+ /usr/include/alloca.h /usr/include/math.h \
+ /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h \
+ /usr/include/bits/mathcalls.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/float.h \
+ /usr/include/string.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/iostream.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/streambuf.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.hh /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \
+ /usr/include/getopt.h /usr/include/sys/file.h /usr/include/fcntl.h \
+ /usr/include/bits/fcntl.h \
+ /home/jshalf/Develop/FlexIO/IEEEIOWinDllApi.h \
+ /home/jshalf/Develop/FlexIO/IO.hh /home/jshalf/Develop/FlexIO/Arch.h \
+ /home/jshalf/Develop/FlexIO/IO.h \
+ /home/jshalf/Develop/FlexIO/FlexArrayTmpl.H /usr/include/sys/stat.h \
+ /usr/include/bits/stat.h /usr/include/strings.h \
+ /home/jshalf/Develop/FlexIO/IEEEIO.h AMRreaderPlus.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/set \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_tree.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_algobase.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_config.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_relops.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_pair.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/type_traits.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/limits.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/syslimits.h \
+ /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+ /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+ /usr/include/bits/posix2_lim.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/new.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/new \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/include/exception \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_iterator.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_alloc.h \
+ /usr/include/assert.h /usr/include/pthread.h /usr/include/sched.h \
+ /usr/include/bits/sched.h /usr/include/bits/time.h \
+ /usr/include/signal.h /usr/include/bits/pthreadtypes.h \
+ /usr/include/bits/sigthread.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_construct.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_function.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_set.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_multiset.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/vector \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_uninitialized.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_vector.h \
+ /usr/lib/gcc-lib/i586-mandrake-linux/2.95.2/../../../../include/g++-3/stl_bvector.h \
+ AMRgridreaderPlus.h AMRgridPlus.h \
+ /home/jshalf/Develop/FlexIO/AmrGrid.h flexset.h flexarrays.h \
+ flexmatrix.h
diff --git a/src/AMRPlus/FlexSetTempl.h b/src/AMRPlus/FlexSetTempl.h
new file mode 100644
index 0000000..27f0d84
--- /dev/null
+++ b/src/AMRPlus/FlexSetTempl.h
@@ -0,0 +1,20 @@
+#ifndef FLEXSETTEMPL_H
+#define FLEXSETTEMPL_H
+
+template <class T>
+class FlexSetOrdered{
+ FlexArray arr;
+
+ FlexSetOrdered() : arr(){};
+
+ int insert(T &item){
+ int a=0;b=getSize()-1, c;
+ if (arr[a]==item || arr[b]==item) return 0;
+ while (a!=b){
+ c=(a+b)/2;
+ if (arr[c]==item) return 0;
+ if (arr[c]<item) a=c; else b=c;
+ }
+};
+
+#endif
diff --git a/src/AMRPlus/filereadtest.C b/src/AMRPlus/filereadtest.C
new file mode 100644
index 0000000..5036f46
--- /dev/null
+++ b/src/AMRPlus/filereadtest.C
@@ -0,0 +1,43 @@
+// generated by Fast Light User Interface Designer (fluid) version 1.00
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <iostream.h>
+#include "IEEEIO.hh"
+#include "AMRfilereaderPlus.h"
+
+
+
+int main(int argc, char** argv) {
+ IObase *ifile, *ofile;
+ AMRfilereaderPlus *reader;
+
+ if (argc!=2){
+ cerr<<"Usage: <filename>"<<endl;
+ exit(0);
+ }
+ char *fname=strdup(argv[1]);
+ ifile=new IEEEIO(fname, IObase::Read);
+ if (!ifile->isValid()){
+ cerr<<fname<<" is not a valid IEEEIO file."<<endl;
+ exit(0);
+ }
+
+ reader=new AMRfilereaderPlus(*ifile);
+ int ii=0;
+ AMRgridPlus grid, *tgrid;
+
+
+ //reader->setTime(0);
+ for (ii=0;ii<reader->getNumGrids();ii++){
+ reader->getGrid(grid, reader->getActiveIndex(ii));
+ cout<<"Level: "<<grid.level<<endl;
+ }
+
+ delete ifile;
+
+
+
+}
diff --git a/src/AMRPlus/flexarrays.h b/src/AMRPlus/flexarrays.h
new file mode 100644
index 0000000..e713e98
--- /dev/null
+++ b/src/AMRPlus/flexarrays.h
@@ -0,0 +1,184 @@
+#ifndef ARRAYS_HDR
+#define ARRAYS_HDR
+#include <string.h>
+#include <stdlib.h>
+//For Shared Objects:
+//#include "SafeList.h"
+//#define TAG :public shObj
+//#define GetMem CAVEMalloc
+//#define FreeMem CAVEFree
+//For Non-shared Objects:
+#define TAG
+
+/* An flexarray is a dynamic flexarray of objecs. No upper limit,
+ * the ability to add and remove objects on the fly, etc.
+ *
+ * Rundown of routines:
+ * Constructor - initializes an empty flexarray with increment 10
+ * Destructor - Deletes the flexarray. Does NOT delete objects in the flexarray
+ * copy constructor/ = :deep copy (override X::operator= if you need
+ * deep copies of the elements)
+ *
+ * Information:
+ * int getLength()/getSize() - returns #objects
+ * int getActualSize() - returns #slots allocated
+ * int getIncrement() - returns #slots allocated at a time
+ * int empty() - true if no elts
+ *
+ * Access:
+ * X& [idx] - return indexed reference, unsafe
+ * X* getData(idx) - Ptr to indexed elt.
+ * X* getDataConst - same as above, but everything is const qualified
+ *
+ * Manip:
+ * setIncrement(int) -
+ * clear() - empties the array
+ * fill(X&, N) - sets the array to N copies of the X
+ * setData(X&, idx) - change entry at index
+ * insertElement(X&, idx) - insert element BEFORE index
+ * (if index=-1, append element);
+ * append(X&) - duh.
+ * InsertElements(start, X*, N) - insert #elements before
+ * start... read values from X*.
+ * removeElements(start, N) - remove N elements starting with start
+ */
+
+template <class X>
+class flexarray TAG {
+ int Length, Size, Increment;
+ X* data;
+
+ public:
+ flexarray(){Length=Size=0; Increment=10;data=NULL;}
+ flexarray(const flexarray<X> &src){
+ Length=src.Length;Size=src.Size;Increment=src.Increment;
+ if (Size==0) data=NULL;
+ else {
+ data=getNewArray(Size);
+ memcpy(this->data, src.data, this->Length*sizeof(X));
+ }
+ }
+ ~flexarray(){if (data) delete[] data;}
+
+ flexarray<X> &operator=(const flexarray<X> &src){
+ if (data!=NULL) delete[] data;
+ Length=src.Length;Size=src.Size;Increment=src.Increment;
+ if (Size==0) data=NULL;
+ else {
+ data=getNewArray(Size);
+ memcpy(this->data, src.data, this->Length*sizeof(X));
+ }
+ return *this;
+ }
+
+ int getActualSize() const{return Size;}
+ int getSize() const{return Length;}
+ int getLength() const{return Length;}
+ int getIncrement() const{return Increment;}
+ int empty() const{return (Size==0);}
+
+
+
+ const X & operator()(int idx) const{return data[idx];}
+ X & operator[](int idx) const{return data[idx];}
+
+ X* getData(int idx)const{
+ if (idx==-1) idx=Length-1;
+ if (idx>=0 && idx<Length)
+ return data+idx;
+ else return NULL;
+ }
+ X* getDataConst(int idx) const{
+ if (idx==-1) idx=Length-1;
+ if (idx>=0 && idx<Length)
+ return data+idx;
+ else return NULL;
+ }
+
+ void setIncrement(int ninc){Increment=ninc;}
+ void clear(){Length=Size=0; if(data) delete[] data;data=NULL;}
+ void fill(const X &elt, int howmany){
+ clear();
+ Length=howmany;
+ Size=Increment * ((Length+howmany)/Increment +1);
+ data=getNewArray(Size);
+ for (int ii=0;ii<howmany;ii++)
+ data[ii]=elt;
+ }
+
+ void setData(int idx, const X &ndata){
+ if (idx>=0 && idx<Length)
+ data[idx]=ndata;
+ }
+
+
+
+
+ void insertElement( const X &elt, int atidx=-1){
+ insertElements(atidx, &elt, 1);
+ }
+ void append( const X &elt){
+ insertElements(-1, &elt, 1);
+ }
+
+
+ void insertElements(int startidx, const X* elts, int howmany){
+ if (howmany<=0) return;
+ if (startidx<-1 || startidx>Length) return;
+ if (startidx==-1) startidx=Length;
+ if (this->data==NULL) data=getNewArray(Increment);
+ if (Size<Length+howmany){
+ Size=Increment * ((Length+howmany)/Increment +1);
+ X* tflexarray=getNewArray(Size);
+ if (startidx>0)
+ memcpy(tflexarray, data, startidx*sizeof(X));
+ if (startidx<Length)
+ memcpy(tflexarray+startidx+howmany, data+startidx, \
+ ((Length-startidx)*sizeof(X)));
+ delete[] data;
+ data=tflexarray;
+ }
+ else
+ if (startidx<Length)
+ memcpy(data+startidx+howmany, data+startidx, \
+ (Length-startidx)*sizeof(X));
+ memcpy(data+startidx, elts, howmany*sizeof(X));
+ Length+=howmany;
+ }
+
+ void removeElements(int startidx, int howmany){
+ if (howmany<=0 || startidx<-1 || startidx>=Length) return;
+ if (startidx==-1) startidx=Length-1;
+ if (startidx+howmany>=Length) howmany=Length-startidx;
+ memcpy(data+startidx, data+startidx+howmany,
+ (Length-(startidx+howmany))*sizeof(X));
+ Length-=howmany;
+ }
+
+
+ private:
+ X* getNewArray(int newSize){
+ return new X [newSize];
+ }
+
+ void resizeArray(int startidx, int numelts){
+ int NSize=Length+numelts;
+ if (NSize>Size){
+ Size=Increment * (NSize/Increment +1);
+ X* tflexarray=getNewArray(Size);
+ if (startidx>0)
+ memcpy(tflexarray, data, startidx*sizeof(X));
+ if (startidx<Length)
+ memcpy(tflexarray+startidx+numelts, data+startidx, \
+ ((Length-startidx)*sizeof(X)));
+ delete[] data;
+ data=tflexarray;
+ }
+ }
+
+
+
+};
+
+
+#endif
diff --git a/src/AMRPlus/flexmatrix.h b/src/AMRPlus/flexmatrix.h
new file mode 100644
index 0000000..6b052e7
--- /dev/null
+++ b/src/AMRPlus/flexmatrix.h
@@ -0,0 +1,20 @@
+#ifndef FLEX_MATRIX_H
+#define FLEX_MATRIX_H
+#include <stdlib.h>
+
+template <class X>
+class flexmatrix{
+ X* data;
+ int M, N;
+
+ public:
+ flexmatrix(int m, int n){
+ M=m;N=n; if (M*N==0) cout<<"Serious Problem! "<<endl;
+ data=new X [M*N];
+ }
+ ~flexmatrix(){delete[] data;}
+ X& operator()(int m, int n){return data[m*N+n];}
+};
+
+
+#endif
diff --git a/src/AMRPlus/flexset.C b/src/AMRPlus/flexset.C
new file mode 100644
index 0000000..529fb1a
--- /dev/null
+++ b/src/AMRPlus/flexset.C
@@ -0,0 +1,215 @@
+#include "flexset.h"
+
+template <class X>
+void setunion(const flexset<X> &A, const flexset<X> &B,flexset<X> &result){
+ int idxA=0, idxB=0;
+ int sizeA=A.getSize(), sizeB=B.getSize();
+
+ if (A.empty()) {result=B;return;}
+ if (B.empty()) {result=A;return;}
+ result.clear();
+ do {
+ //I dont like to rely on shortcut boolean operators, so
+ //that's why I use double ifs
+
+ X *whichadd=NULL; //1,2,3 (A,B, or both)
+ if (idxA<sizeA && idxB<sizeB){
+ if (A(idxA)<B(idxB)) {
+ whichadd=&A(idxA); idxA++;
+ }
+ else if (B(idxB)<A(idxA)){
+ whichadd=&B(idxB); idxB++;
+ }
+ else {
+ whichadd=A(idxA);
+ idxA++; idxB++;
+ }
+ }
+ else {
+ if (idxA<sizeA){whichadd=&A(idxA); idxA++;}
+ else if (idxB<sizeB){whichadd=&B(idxB); idxB++;}
+ }
+
+ if (whichadd!=NULL)
+ result.append(*whichadd);
+ } while (idxA<sizeA || idxB<sizeB);
+}
+
+template <class X>
+void setunion(flexset<X> &A, const flexset<X> &B){
+ flexset<X> tmp=A;
+ setunion(tmp, B, A);
+}
+
+
+template <class X>
+void setintersection(const flexset<X> &A, const flexset<X> &B,flexset<X> &result){
+ int idxA=0, idxB=0;
+ int sizeA=A.getSize(), sizeB=B.getSize();
+
+ result.clear();
+ if (A.empty() || B.empty()) return; //result={}
+ do {
+ //I dont like to rely on shortcut boolean operators, so
+ //that's why I use double ifs
+
+ X *whichadd=NULL; //1,2,3 (A,B, or both)
+ if (idxA<sizeA && idxB<sizeB){
+ if (A(idxA)<B(idxB)) {
+ idxA++;
+ }
+ else if (B(idxB)<A(idxA)){
+ idxB++;
+ }
+ else {
+ whichadd=&A[idxA];
+ idxA++; idxB++;
+ }
+ }
+ else return; //if we've finished off one set, then no more elts in intersection
+
+ if (whichadd!=NULL)
+ result.append(*whichadd);
+ } while (idxA<sizeA || idxB<sizeB);
+}
+
+
+template <class X>
+void setsymmetricdifference(const flexset<X> &A, const flexset<X> &B,flexset<X> &result){
+ int idxA=0, idxB=0;
+ int sizeA=A.getSize(), sizeB=B.getSize();
+ if (A.empty()) {result.clear(); return;}
+ if (B.empty()) {result=A;return;}
+ result.clear();
+ do {
+ //I dont like to rely on shortcut boolean operators, so
+ //that's why I use double ifs
+
+ X *whichadd=NULL; //1,2,3 (A,B, or both)
+ if (idxA<sizeA && idxB<sizeB){
+ if (A(idxA)<B(idxB)) {
+ whichadd=&A(idxA); idxA++;
+ }
+ else if (B(idxB)<A(idxA)){
+ whichadd=&B(idxB); idxB++;
+ }
+ else {
+ idxA++; idxB++;
+ }
+ }
+ else {
+ if (idxA<sizeA){whichadd=&A(idxA); idxA++;}
+ else if (idxB<sizeB){whichadd=&B(idxB); idxB++;}
+ }
+
+ if (whichadd!=NULL)
+ result.append(*whichadd);
+ } while (idxA<sizeA || idxB<sizeB);
+}
+
+template <class X>
+void setdifference(const flexset<X> &A, const flexset<X> &B,flexset<X> &result){
+ int idxA=0, idxB=0;
+ int sizeA=A.getSize(), sizeB=B.getSize();
+ if (A.empty()) {result=A; return;}
+ if (B.empty()) {result=A;return;}
+ result.clear();
+ do {
+ //I dont like to rely on shortcut boolean operators, so
+ //that's why I use double ifs
+
+ X *whichadd=NULL; //1,2,3 (A,B, or both)
+ if (idxA<sizeA && idxB<sizeB){
+ if (A(idxA)<B(idxB)) {
+ whichadd=&A[idxA]; idxA++;
+ }
+ else if (B(idxB)<A(idxA)){
+ idxB++;
+ }
+ else {
+ idxA++; idxB++;
+ }
+ }
+ else {
+ if (idxA<sizeA){whichadd=&A[idxA]; idxA++;}
+ else if (idxB<sizeB){idxB++;}
+ }
+
+ if (whichadd!=NULL)
+ result.append(*whichadd);
+ } while (idxA<sizeA || idxB<sizeB);
+}
+
+
+template <class X>
+void setdifferences(const flexset<X> &A, const flexset<X> &B,flexset<X> &AMB,flexset<X> &BMA){
+ int idxA=0, idxB=0;
+ int sizeA=A.getSize(), sizeB=B.getSize();
+ if (A.empty()) {AMB.clear();BMA=B; return;}
+ if (B.empty()) {BMA.clear();AMB=A;return;}
+ AMB.clear();
+ BMA.clear();
+ do {
+ X *whichaddA=NULL;
+ X *whichaddB=NULL;
+ if (idxA<sizeA && idxB<sizeB){
+ if (A(idxA)<B(idxB)) {
+ whichaddA=&A[idxA]; idxA++;
+ }
+ else if (B(idxB)<A(idxA)){
+ whichaddB=&B[idxB];idxB++;
+ }
+ else {
+ idxA++; idxB++;
+ }
+ }
+ else {
+ if (idxA<sizeA){whichaddA=&A[idxA]; idxA++;}
+ else if (idxB<sizeB){whichaddB=&B[idxB];idxB++;}
+ }
+
+ if (whichaddA!=NULL)
+ AMB.append(*whichaddA);
+ if (whichaddB!=NULL)
+ BMA.append(*whichaddB);
+ } while (idxA<sizeA || idxB<sizeB);
+}
+
+
+template <class X>
+void setconvert(flexset<X> &A, const flexset<X> &B){
+ int idxA=0, idxB=0;
+ int sizeA=A.getSize(), sizeB=B.getSize();
+ if (A.empty()) {return;}
+ if (B.empty()) {
+ cout<<"SetConvert - UHOH! A is not contained in B!"<<endl;
+ return;}
+ do {
+ //I dont like to rely on shortcut boolean operators, so
+ //that's why I use double ifs
+
+ if (idxA<sizeA && idxB<sizeB){
+ if (A(idxA)<B(idxB)) {
+ cout<<"SetConvert - UHOH! A is not contained in B!"<<endl;
+ A.clear();
+ return;
+ }
+ else if (B(idxB)<A(idxA)){
+ idxB++;
+ }
+ else {
+ (A[idxA])=B(idxB);
+ idxA++; idxB++;
+ }
+ }
+ else {
+ if (idxA<sizeA){
+ cout<<"SetConvert - UHOH! A is not contained in B!"<<endl;
+ A.clear();
+ return;
+ }
+ }
+
+ } while (idxA<sizeA || idxB<sizeB);
+}
+
diff --git a/src/AMRPlus/flexset.h b/src/AMRPlus/flexset.h
new file mode 100644
index 0000000..d2e486d
--- /dev/null
+++ b/src/AMRPlus/flexset.h
@@ -0,0 +1,209 @@
+#ifndef FLEX_SET_H
+#define FLEX_SET_H
+#include "flexarrays.h"
+
+/*
+ * A flexset is a set datastructure. Fast insertion/deletion (O(logN)),
+ * and basic set operations (union, difference, etc...). This set is
+ * not completely generalized - you must either use native (non-pointer)
+ * types, or use a class with operators < and == implemented
+ * (i.e: inline int operator<(const X&) const{...};) This is what allows
+ * log time access, and linear time set operations.
+ * Routines:
+ * Constructor/Destructor/copy constructor...
+ *
+ * Information:
+ * int getSize() - returns size of set.
+ * int find(X& x) - return position of x, or -1 if x isn't in the set
+ * int contains(X& x) - boolean version of above
+ * int contains(flexset &s) - returns 1 if s is a subset
+ *
+ * Manipulation:
+ * insert(X& x) - add x to the set. If x is already in the set
+ * (technically, x==e for some e in the set) nothing happens.
+ * remove(X& x) - remove x (only if x is inside, of course);
+ * X& [int idx] - access element by index. Index will change with insertion
+ * buldSubset(flexset<X> &x, int (* test)(X& y)) - creates a subset consisting
+ * of all elements in the set for which 'test' returns true.
+ *
+ * Operations:
+ * [all of form: set<oper>(X& A, X& B, X& result){ result= A <oper> B}]
+ * setunion(A=AUB, or C=AUB), setintersection, setdifference, setsymmetricdifference
+ * setdifferences (returns A-B and B-A in one go)
+ * NOTE: The result of intersection or difference will consist only
+ * of items taken from A. (Important if you are comparing sets with
+ * similar keys and dissimilar data
+ */
+
+/*
+class flexset;
+template <class X> setiter{
+ public:
+ setiter(flexset *nset){itsset=nset; idx=(nset->empty())?-1:0;}
+
+ operator++(){idx++; if (idx>itsset->getSize()-1) idx=-1;}
+ operator--(){idx--; if (idx<0) idx=-1;}
+ int ok(){return idx!=-1;}
+
+ X &operator*(){if (idx==-1) return itsset[0]; return itsset[idx];}
+
+ private:
+ flexset *itsset;
+ int idx;
+}
+*/
+
+
+template <class X>
+class flexset : protected flexarray<X>{
+ public:
+ flexset(): flexarray<X>(){};
+ flexset(const flexset<X> &src): flexarray<X>(src){};
+ ~flexset(){};
+ //by all accounts, this should inherit flexarray operator=
+
+ int getSize() const{return flexarray<X>::getSize();}
+ int findpos(const X &elt, int start=0, int end=-1) const{
+ if (start<0) start=0;
+ if (end==-1) end=getLength()-1;
+
+ int a=start, b=end, e;
+ if (empty()) return 0;
+ if (elt<(*this)(a)) return a;
+ if (elt==(*this)(a)) return a; //don't depend on <= being implemented
+ if (elt==(*this)(b)) return b;
+ if (!(elt<(*this)(b))) return b+1; //given above line, equiv to elt>data[b]
+
+ if ((a+b)&1) e=(a+b+1)/2; //e odd
+ else e=(a+b)/2;
+ while ((b-a>1)){
+ if (elt==(*this)(e)) return e;
+
+ if (elt<(*this)(e)) b=e;
+ else a=e;
+ if ((a+b)&1) e=(a+b+1)/2; //e odd
+ else e=(a+b)/2;
+ }
+ if (elt<(*this)(e)) return e;
+ if (elt==(*this)(e)) return e;
+ else return e+1;
+
+ }
+//If elt is in the set, return its index, otherwise return -1
+ int find(const X &elt, int start=0, int end=-1) const{
+ if (empty()) return -1;
+ int result=findpos(elt, start, end);
+ if (result<getSize() && elt==*getDataConst(result)) return result;
+ return -1;
+ }
+
+ int contains(const X &elt) const{return (find(elt)!=-1);}
+
+ int contains(const flexset<X> &iset) const{
+ if (iset.empty()) return 1; //Empty set is in everything!
+ int a=find(iset(0));
+ if (a<0)return 0;
+ for (int ii=1;ii<iset.getSize();ii++){
+ if ((a=find(iset(ii), a))<0) return 0;
+ }
+
+ return 1;
+ }
+
+
+
+ void clear(){
+ flexarray<X>::clear();
+ }
+
+ int empty() const {return flexarray<X>::empty();}
+
+ void buildSubset(flexset<X> &A, int (* test)(const X&)){
+ A.clear();
+ for (int ii=0;ii<getSize();ii++)
+ if (test((*this)[ii])) A.append((*this)[ii]);
+ }
+
+
+
+//Insert elt into the set. If elt is already in, do nothing
+ void insert(const X &elt){
+ int pos=findpos(elt);
+ if (pos<getSize())
+ if (elt==*getData(pos)) return;
+ insertElement(elt, pos);
+ };
+
+ void remove(const X &elt){
+ if (empty()) return;
+ int pos=findpos(elt);
+ if (pos<getSize())
+ if (elt==*getData(pos)) removeElements(pos, 1);
+ }
+
+ //Indexed removal preserves set ordering, and it's O(1),
+ //so it is safe to include
+ void indexremove(int idx){
+ if (empty()||idx<0||idx>=getSize()) return;
+ removeElements(idx, 1);
+ }
+
+ void append(const X &elt){
+ if (empty()) {
+ insertElement(elt, 0);
+ return;
+ }
+ X *tmp=&(*this)[getSize()-1];
+ if ((*tmp)<elt) insertElement(elt, -1);
+ else if (!((*tmp)==elt)) cout<<"BAD APPEND!"<<endl;
+ }
+ void prepend(const X &elt){
+ if (empty()) {
+ insertElement(elt, 0);
+ return;
+ }
+ X *tmp=&(*this)[getSize()-1];
+ if (elt<(*tmp)) insertElement(elt, 0);
+ else if (!((*tmp)==elt)) cout<<"BAD PREPEND!"<<endl;
+ }
+
+ X &operator[](int idx) const{return *getData(idx);}
+ const X &operator()(int idx)const {return *getDataConst(idx);}
+
+friend
+void setunion(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+friend
+void setintersection(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+friend
+void setsymmetricdifference(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+friend
+void setdifference(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+friend
+void setdifferences(const flexset<X> &A, const flexset<X> &B,flexset<X> &AMB,flexset<X> &BMA);
+friend
+void setconvert(flexset<X> &A, const flexset<X> &B);
+};
+
+template <class X>
+void setunion(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+
+
+template <class X>
+void setunion(flexset<X> &A, const flexset<X> &B);
+
+template <class X>
+void setintersection(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+
+
+template <class X>
+void setsymmetricdifference(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+
+template <class X>
+void setdifference(const flexset<X> &A, const flexset<X> &B,flexset<X> &result);
+
+template <class X>
+void setdifferences(const flexset<X> &A, const flexset<X> &B,flexset<X> &AMB,flexset<X> &BMA);
+
+template <class X>
+void setconvert(flexset<X> &A, const flexset<X> &B);
+#endif
diff --git a/src/AMRPlus/gridreadtest.C b/src/AMRPlus/gridreadtest.C
new file mode 100644
index 0000000..8321d2d
--- /dev/null
+++ b/src/AMRPlus/gridreadtest.C
@@ -0,0 +1,40 @@
+// generated by Fast Light User Interface Designer (fluid) version 1.00
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <iostream.h>
+#include "IEEEIO.hh"
+#include "AMRgridreaderPlus.h"
+
+
+
+int main(int argc, char** argv) {
+ IObase *ifile, *ofile;
+ AMRgridreaderPlus *reader;
+
+ if (argc!=2){
+ cerr<<"Usage: <filename>"<<endl;
+ exit(0);
+ }
+ char *fname=strdup(argv[1]);
+ ifile=new IEEEIO(fname, IObase::Read);
+ if (!ifile->isValid()){
+ cerr<<fname<<" is not a valid IEEEIO file."<<endl;
+ exit(0);
+ }
+
+ reader=new AMRgridreaderPlus(*ifile);
+ int ii=0;
+ AMRgridPlus grid, *tgrid;
+ while ((tgrid=reader->getGridInfo(grid, ii))!=NULL){
+ cout<<"ScalarRange: "<<grid.scalarmin<<" to "<<grid.scalarmax<<endl;
+ ii++;
+ }
+
+ delete ifile;
+
+
+
+}
diff --git a/src/AMRPlus/jerror.h b/src/AMRPlus/jerror.h
new file mode 100644
index 0000000..fc2fffe
--- /dev/null
+++ b/src/AMRPlus/jerror.h
@@ -0,0 +1,291 @@
+/*
+ * jerror.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the JPEG library.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ * A set of error-reporting macros are defined too. Some applications using
+ * the JPEG library may wish to include this file to get the error codes
+ * and/or the macros.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE. To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef JERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* JERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string) code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
+
+/* For maintenance convenience, list is alphabetical by message code name */
+JMESSAGE(JERR_ARITH_NOTIMPL,
+ "Sorry, there are legal restrictions on arithmetic coding")
+JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
+JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
+JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
+JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
+JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
+JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
+JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
+JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
+JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
+JMESSAGE(JERR_BAD_LIB_VERSION,
+ "Wrong JPEG library version: library is %d, caller expects %d")
+JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
+JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
+JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
+JMESSAGE(JERR_BAD_PROGRESSION,
+ "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+JMESSAGE(JERR_BAD_PROG_SCRIPT,
+ "Invalid progressive parameters at scan script entry %d")
+JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
+JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
+JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
+JMESSAGE(JERR_BAD_STRUCT_SIZE,
+ "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
+JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
+JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
+JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
+JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
+JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
+JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
+JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
+JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
+JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
+JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
+JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
+JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
+JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
+JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
+JMESSAGE(JERR_FILE_READ, "Input file read error")
+JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
+JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
+JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
+JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
+JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
+JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
+JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
+JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
+ "Cannot transcode due to multiple use of quantization table %d")
+JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
+JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
+JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
+JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
+JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
+JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
+JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
+JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
+JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
+JMESSAGE(JERR_QUANT_COMPONENTS,
+ "Cannot quantize more than %d color components")
+JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
+JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
+JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
+JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
+JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
+JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
+JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
+JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
+JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
+JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
+JMESSAGE(JERR_TFILE_WRITE,
+ "Write failed on temporary file --- out of disk space?")
+JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
+JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
+JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
+JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
+JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
+JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
+JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
+JMESSAGE(JMSG_VERSION, JVERSION)
+JMESSAGE(JTRC_16BIT_TABLES,
+ "Caution: quantization tables are too coarse for baseline JPEG")
+JMESSAGE(JTRC_ADOBE,
+ "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
+JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
+JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
+JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
+JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
+JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
+JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
+JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
+JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
+JMESSAGE(JTRC_EOI, "End Of Image")
+JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
+JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d")
+JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
+ "Warning: thumbnail image size does not match data length %u")
+JMESSAGE(JTRC_JFIF_EXTENSION,
+ "JFIF extension marker: type 0x%02x, length %u")
+JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
+JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u")
+JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
+JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
+JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
+JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
+JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
+JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
+JMESSAGE(JTRC_RST, "RST%d")
+JMESSAGE(JTRC_SMOOTH_NOTIMPL,
+ "Smoothing not supported with nonstandard sampling ratios")
+JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
+JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
+JMESSAGE(JTRC_SOI, "Start of Image")
+JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
+JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
+JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
+JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
+JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
+JMESSAGE(JTRC_THUMB_JPEG,
+ "JFIF extension marker: JPEG-compressed thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_PALETTE,
+ "JFIF extension marker: palette thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_RGB,
+ "JFIF extension marker: RGB thumbnail image, length %u")
+JMESSAGE(JTRC_UNKNOWN_IDS,
+ "Unrecognized component IDs %d %d %d, assuming YCbCr")
+JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
+JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
+JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
+JMESSAGE(JWRN_BOGUS_PROGRESSION,
+ "Inconsistent progression sequence for component %d coefficient %d")
+JMESSAGE(JWRN_EXTRANEOUS_DATA,
+ "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
+JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
+JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
+JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
+JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
+JMESSAGE(JWRN_MUST_RESYNC,
+ "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
+JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
+JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
+
+#ifdef JMAKE_ENUM_LIST
+
+ JMSG_LASTMSGCODE
+} J_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
+
+
+#ifndef JERROR_H
+#define JERROR_H
+
+/* Macros to simplify using the error and trace message stuff */
+/* The first parameter is either type of cinfo pointer */
+
+/* Fatal errors (print message and exit) */
+#define ERREXIT(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT3(cinfo,code,p1,p2,p3) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXITS(cinfo,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+#define MAKESTMT(stuff) do { stuff } while (0)
+
+/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
+#define WARNMS(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+
+/* Informational/debugging messages */
+#define TRACEMS(cinfo,lvl,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS1(cinfo,lvl,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS2(cinfo,lvl,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMSS(cinfo,lvl,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+
+#endif /* JERROR_H */
diff --git a/src/AMRPlus/makefile b/src/AMRPlus/makefile
new file mode 100644
index 0000000..56b24de
--- /dev/null
+++ b/src/AMRPlus/makefile
@@ -0,0 +1,70 @@
+SRCS= \
+ AMRwriterPlus.C \
+ AMRgridreaderPlus.C \
+ AMRfilereaderPlus.C \
+ flexset.C \
+ AMRreaderPlus.C
+
+OBJS = $(SRCS:.C=.o)
+DEPEND = Dpndfile
+####################
+
+SHELL = /bin/sh
+
+IEEE_ROOT=/nfs/zeus/lcascr1/mahall/AmrProject/FlexIO
+
+
+ALL_INC = -I$(IEEE_ROOT)/include -I$(HDF_ROOT)/include
+
+
+DEFS =
+CC = cc
+#COMP_FLAGS = -n32 -mips4 -LNO -IPA -Ofast
+COMP_FLAGS = -64 -mips4 -g
+
+CFLAGS = -c -float ${COMP_FLAGS} -DOPENGL \
+ -I$(IEEE_ROOT)/include \
+ -DVTK21 $(VTKINCD) -noinline -woff 1681-1682,3322
+CXXFLAGS = ${CFLAGS}
+
+
+LINK = ${CPP}
+LIBS = -L$(IEEE_ROOT)/lib -L$(HDF_ROOT)/lib -L. \
+ -lhlio -lieeeio -lAMR \
+ -lX11 -lm \
+ -lGL -lICE -lXt
+
+.C: $@.o ${OBJS}
+ $(CXX) ${COMP_FLAGS} -o $@ \
+ ${OBJS} $@.o $(LIBS)
+
+
+include $(DEPEND)
+
+AMRPlusConv: AMRPlusConv.o libAMRPlus.a
+ $(CXX) ${COMP_FLAGS} -o $@ \
+ $@.o -lAMRPlus $(LIBS)
+
+gridreadtest: gridreadtest.o libAMRPlus.a
+ $(CXX) ${COMP_FLAGS} -o $@ \
+ $@.o -lAMRPlus $(LIBS)
+
+readtest: readtest.o libAMRPlus.a
+ $(CXX) ${COMP_FLAGS} -o $@ \
+ $@.o -lAMRPlus $(LIBS)
+
+filereadtest:filereadtest.o libAMRPlus.a
+ $(CXX) ${COMP_FLAGS} -o $@ \
+ $@.o -lAMRPlus $(LIBS)
+
+libAMRPlus.a: ${OBJS}
+ rm -f libAMRPlus
+ ar r libAMRPlus.a ${OBJS}
+
+dep: $(SRCS)
+ CC -M ${ALL_INC} $(SRCS) readtest.C > $(DEPEND)
+ smake
+
+
+clean:
+ rm *.o
diff --git a/src/AMRPlus/ordarrays.h b/src/AMRPlus/ordarrays.h
new file mode 100644
index 0000000..b830984
--- /dev/null
+++ b/src/AMRPlus/ordarrays.h
@@ -0,0 +1,23 @@
+#include "arrays.h"
+
+
+
+template <class X>
+class flexset : private array<X>{
+ public:
+ ordarray(): array<X>(){};
+ ~ordarray(){};
+ int insert(const X &elt){
+ int a=0, b=getLength()-1;
+ X* data=this->getData(0);
+ if (elt==data[0]) this->insertElement(elt, 0);
+ if (elt==data[b]) insertElement(elt, b);
+ int c=(a+b)/2;
+ while (elt!=data[c]){
+ if (a==b) {insertElement(elt, a); return a;}
+ if (elt<data[c])
+ }
+
+ };
+
+};
diff --git a/src/AMRPlus/readtest.C b/src/AMRPlus/readtest.C
new file mode 100644
index 0000000..001441b
--- /dev/null
+++ b/src/AMRPlus/readtest.C
@@ -0,0 +1,54 @@
+// generated by Fast Light User Interface Designer (fluid) version 1.00
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <iostream.h>
+#include "IEEEIO.hh"
+#include "AMRreaderPlus.h"
+
+
+
+int main(int argc, char** argv) {
+ IObase *ifile, *ofile;
+ AMRreaderPlus *reader;
+
+ if (argc!=2){
+ cerr<<"Usage: <filename>"<<endl;
+ exit(0);
+ }
+ char *fname=strdup(argv[1]);
+ ifile=new IEEEIO(fname, IObase::Read);
+ if (!ifile->isValid()){
+ cerr<<fname<<" is not a valid IEEEIO file."<<endl;
+ exit(0);
+ }
+
+ reader=new AMRreaderPlus(*ifile);
+
+ IdxSet thegs;
+ reader->getActive(thegs);
+
+
+ for (int ii=0;ii<thegs.getSize();ii++){
+ cout<<"Grid #"<<ii<<" : Level="<<reader->grids(thegs[ii].idx).level<<endl;
+ }
+
+ /*
+ for (int ii=0;ii<reader->maxtime+1;ii++){
+ cout<<endl<<"Timestep #"<<ii<<": "<<endl;
+ for (int jj=0;jj<reader->maxlevel+1;jj++){
+ cout<<"\nLevel #"<<jj<<" grids: ";
+ for (int kk=0;kk<(*reader->leveltimes)(jj, ii).getSize();kk++){
+ cout<<" "<<(*reader->leveltimes)(jj, ii)[kk].idx;
+ }
+ }
+ }
+ */
+ reader->loadData();
+ delete ifile;
+
+
+
+}
diff --git a/src/AMRPlus/settst.C b/src/AMRPlus/settst.C
new file mode 100644
index 0000000..743791b
--- /dev/null
+++ b/src/AMRPlus/settst.C
@@ -0,0 +1,59 @@
+#include <iostream.h>
+#include "flexset.h"
+#include <unistd.h>
+
+int iseven(const int &y){return !(y&1);}
+struct orec;
+struct irec{
+ int key, data;
+ irec(int nkey=0, int ndata=0){key=nkey;data=ndata;}
+ int operator<(const irec &b) const{return key<b.key;}
+ int operator==(const irec &b) const{return key==b.key;}
+ int operator<(const orec &b) const;
+ int operator==(const orec &b) const;
+};
+
+struct orec{
+ int key;
+ char *str;
+ orec(int nkey=0){key=nkey;}
+ int operator<(const orec &b) const{return key<b.key;}
+ int operator==(const orec &b) const{return key==b.key;}
+ int operator<(const irec &b) const{return key<b.key;}
+ int operator==(const irec &b) const{return key==b.key;}
+};
+
+int irec::operator<(const orec &b) const{return key<b.key;};
+int irec::operator==(const orec &b) const{return key<b.key;};
+
+void main(){
+ flexset<irec> arr1, arr2, arr3, arr4, arr5;
+ flexset<orec> iarr1, iarr2;
+ irec tst;
+ int ii;
+
+ for (ii=0;ii<20;ii++){
+ tst.key=rand()%20;
+ tst.data=ii;
+ arr1.insert(tst);
+ }
+
+ for (ii=0;ii<20;ii++){
+ iarr1.insert(rand()%20);
+ }
+
+ setdifferences(arr1, iarr1, arr2, iarr2);
+ for (ii=0;ii<arr1.getSize();ii++)
+ cout<<arr1[ii].key<<" : "<<arr1[ii].data<<endl;
+ cout<<endl;
+ for (ii=0;ii<iarr1.getSize();ii++)
+ cout<<iarr1[ii].key<<endl;
+ cout<<endl;
+ for (ii=0;ii<arr2.getSize();ii++)
+ cout<<arr2[ii].key<<" : "<<arr2[ii].data<<endl;
+ cout<<endl;
+ for (ii=0;ii<iarr2.getSize();ii++)
+ cout<<iarr2[ii].key<<endl;
+ cout<<endl;
+
+}
diff --git a/src/AMRPlus/testread.C b/src/AMRPlus/testread.C
new file mode 100644
index 0000000..b0b7c29
--- /dev/null
+++ b/src/AMRPlus/testread.C
@@ -0,0 +1,170 @@
+// generated by Fast Light User Interface Designer (fluid) version 1.00
+
+#include <vtk.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "vtkAMRStructuredPointsReader.h"
+vtkRenderer *renderer;
+vtkRenderWindow* renWin;
+vtkOutlineFilter *outline;
+vtkContourFilter *contour;
+vtkPolyDataMapper *outlineMapper;
+vtkPolyDataMapper *contMapper;
+vtkActor *outlineActor;
+vtkActor *contActor;
+vtkPolyData *t, *outlineOut, *contOut, *t1;
+vtkStructuredPoints *temp, *out;
+vtkAMRStructuredPointsReader* spr=0;
+
+
+
+int main(int argc, char** argv) {
+ // Make a window to put the rendering window in. FLTK interface.
+ // Fl_Window* w;
+ //{ Fl_Window* o = w = MainWin =
+ // new Fl_Window(500, 500, "AMRTest");
+ // w = o;
+ // o->end();
+ // }
+ //renWin = vtkFlRenderWindow::New();
+ renderer = vtkRenderer::New();
+
+ // uncomment this to use the VTK rendering window
+ //renderer->SetBackground(0.5, 0.5, 0.5);
+ renWin = vtkRenderWindow::New();
+
+ renWin->AddRenderer(renderer);
+
+ // uncomment this to use VTK event handler
+ vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
+ iren->SetRenderWindow(renWin);
+
+ //create a reader and open the file "amr.raw"
+ spr = vtkAMRStructuredPointsReader::New();
+ spr->SetFileName("/nfs/zeus/lcascr1/pushkare/work/amr.raw");
+ cout<<"NLevels: "<<spr->GetNumLevels()<<endl;
+ cout<<"NTime: "<<spr->GetNumTimeSteps()<<endl;
+ int nlevel=0;
+ if (argc>1) nlevel=atoi(argv[1]);
+ spr->SelectLevel(nlevel);
+ spr->SelectTimeStep(0);
+ spr->Update();
+
+ int n = spr->GetNumDatasets();
+ cout<<"NDataSets: "<<n<<endl;
+ //initialize the filters for isosurface and bounding box
+ outline = vtkOutlineFilter::New();
+ contour = vtkContourFilter::New();
+
+ //initialize the data collections to collect data in the various stages of
+ //the pipeline
+ vtkDataSetCollection *Data = vtkDataSetCollection::New();
+ vtkPolyDataCollection *PolyData = vtkPolyDataCollection::New();
+ vtkPolyDataCollection *Outlines = vtkPolyDataCollection::New();
+
+ // This loop reads the grids from a file and puts them into Data, the
+ //dataset collection.
+ for (int i=0; i<n; i++)
+ {
+ spr->SelectDataset(i);
+ spr->Update();
+ out = spr->GetOutput();
+ temp = (vtkStructuredPoints*)out->MakeObject();
+
+ temp->CopyStructure(out);
+ temp->GetPointData()->DeepCopy(out->GetPointData());
+ temp->GetCellData()->DeepCopy(out->GetCellData());
+ temp->ForceUpdate();
+
+ Data->AddItem(temp);
+ }
+
+ int NContours = 0;
+ Data->InitTraversal();
+
+
+ // This loop takes the grids from Data and processes them to get an outline
+ // and isosurface for each grid. The isovalue for the dataset is set to 0.86
+ // for now.
+ for (int j=0; j<n; j++)
+ {
+ float *x1, Iso;
+ temp = (vtkStructuredPoints*)Data->GetNextItem();
+ x1 = temp->GetPointData()->GetScalars()->GetRange();
+ Iso = 0.86;
+
+ //if the isovalue is out of bounds for a particular grid, then just
+ //ignore that grid.
+ if (Iso < x1[0] || Iso > x1[1])
+ continue;
+ NContours++;
+
+ //produce the isosurface and stick it into the PolyData collection.
+ contour->SetInput(temp);
+ contour->SetValue(0, Iso);
+ contour->Update();
+ contOut = contour->GetOutput();
+
+ t = (vtkPolyData*)contOut->MakeObject();
+
+ t->CopyStructure(contOut);
+ t->GetPointData()->DeepCopy(contOut->GetPointData());
+ t->GetCellData()->DeepCopy(contOut->GetCellData());
+ t->ForceUpdate();
+
+ PolyData->AddItem(t);
+
+ //produce a bounding box and put it into an Outlines collection
+ outline->SetInput(temp);
+ outline->Update();
+
+ outlineOut = outline->GetOutput();
+
+ t1 = (vtkPolyData*)outlineOut->MakeObject();
+ t1->CopyStructure(outlineOut);
+
+ Outlines->AddItem(t1);
+
+ }
+
+ PolyData->InitTraversal();
+ Outlines->InitTraversal();
+
+
+ //This loop takes care of the final mapper and actor steps of the pipeline
+ for (int k=0; k<NContours; k++)
+ {
+ //produce and add the isosurface actor
+ contMapper = vtkPolyDataMapper::New();
+ contMapper->SetInput(PolyData->GetNextItem());
+ contMapper->ImmediateModeRenderingOn();
+ contActor = vtkActor::New();
+ contActor->SetMapper(contMapper);
+ contActor->GetProperty()->SetRepresentationToSurface();
+ renderer->AddActor(contActor);
+
+ //produce and add the bounding box actor, which is colored RED
+ outlineMapper = vtkPolyDataMapper::New();
+ outlineMapper->SetInput(Outlines->GetNextItem());
+ outlineActor = vtkActor::New();
+ outlineActor->SetMapper(outlineMapper);
+ outlineActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
+ renderer->AddActor(outlineActor);
+
+ }
+
+ // this part makes sure that something actually does show up on the screen
+ // w->show(argc, argv);
+ // w->begin();
+ // vtkwin = new Fl_vtk_Window( renWin, 1, 1, 498, 498);
+ // vtkwin->show(1, argv);
+ //w->end();
+
+ //return Fl::run();
+
+ //uncomment this and comment the FLTK stuff to use VTK window and event loop.
+ renWin->Render();
+ iren->Start();
+}
diff --git a/src/AMRPlus/tst.C b/src/AMRPlus/tst.C
new file mode 100644
index 0000000..cdc9f03
--- /dev/null
+++ b/src/AMRPlus/tst.C
@@ -0,0 +1,42 @@
+#include <iostream.h>
+#include "flexset.h"
+
+void main(){
+ flexset<int> arr1, arr2;
+ int tst;
+ int ii;
+
+ for (ii=0;ii<15;ii++){
+ tst=rand() %10;
+ arr1.insert(tst);
+ }
+ for (ii=0;ii<15;ii++){
+ tst=rand() %10;
+ arr2.insert(tst);
+ }
+
+ flexset<int> arr3;
+ for (ii=0;ii<arr1.getSize();ii++){cout<<arr1[ii]<<endl;}
+ cout<<endl;
+ for (ii=0;ii<arr2.getSize();ii++){cout<<arr2[ii]<<endl;}
+ cout<<endl;
+
+ setunion(arr1, arr2, arr3);
+ cout<<endl;<<"Union: "<<endl;
+ for (ii=0;ii<arr3.getSize();ii++){cout<<arr3[ii]<<endl;}
+
+ setintersection(arr1, arr2, arr3);
+ cout<<endl;<<"Intersection: "<<endl;
+ for (ii=0;ii<arr3.getSize();ii++){cout<<arr3[ii]<<endl;}
+
+ setdifference(arr1, arr2, arr3);
+ cout<<endl;<<"Difference: "<<endl;
+ for (ii=0;ii<arr3.getSize();ii++){cout<<arr3[ii]<<endl;}
+
+ setsymmetricdifference(arr1, arr2, arr3);
+ cout<<endl;<<"Symmetric Difference: "<<endl;
+ for (ii=0;ii<arr3.getSize();ii++){cout<<arr3[ii]<<endl;}
+
+
+
+}
diff --git a/src/AMRwriter.cc b/src/AMRwriter.cc
new file mode 100644
index 0000000..d46b57a
--- /dev/null
+++ b/src/AMRwriter.cc
@@ -0,0 +1,473 @@
+// AMRwriter.cc
+#include <stdio.h>
+#include <stdlib.h>
+#include "AMRwriter.hh"
+#include <math.h>
+
+void AMRwriter::writeAMRattributes(){
+ double origin[5],delta[5],ext[5],currenttime;
+ // OK, now we get to do the attribs thang...
+ // first compute the coorect origin and delta for this level.
+ //int i;
+ int level_timestep,persistence;
+
+ /*****
+ Must compute the floating point time from the integer timestep.
+ The timestep is based on the finest computational level.
+ Should compute from level_timestep for less numerical error
+ *****/
+ currenttime = (double)currentstep*basetimestep/(double)(levels[levels.getSize()-1].trefine);
+ // compute persistence
+
+ persistence = levels[levels.getSize()-currentlevel-1].trefine;
+ level_timestep = currentstep/persistence;
+ // compute from min-ext...
+ // y-know... there is more point density near 0 in the float
+ // representation... so having sizes instead of extents would
+ // be smarter.... But viz systems generally use the extent... :(
+ // this is VERY inaccurate... Have to think about this more...
+ // Its OK for small subgrids, but inaccuracy is unbearable past
+ // 128 elements. Need to compute relative to basegrid extents!,
+ // but that isn't possible without dims for the basegrid!
+ // IObase::setOrigin(origin);// this will set the IObase:: basegrid origin :(
+ // IObase::setDelta(delta);
+ // Storage is in order of liklihood of that param being accessed.
+ // Less-frequently accessed params go to the end.
+ for(int i=0;i<drank;i++) {
+ currentdelta[i] = ddelta[i]/(levels[currentlevel]).srefine[i];
+ ext[i] = currentorigin[i] +
+ (double)((ddims[i]+1) * currentdelta[i]);
+ }
+
+ file.writeAttribute("level",IObase::Int32,1,&currentlevel);
+ file.writeAttribute("origin",IObase::Float64,drank,currentorigin);
+ file.writeAttribute("delta",IObase::Float64,drank,currentdelta);
+ file.writeAttribute("min_ext",IObase::Float64,drank,currentorigin);
+ file.writeAttribute("max_ext",IObase::Float64,drank,ext);
+ file.writeAttribute("time",IObase::Float64,1,&currenttime);
+
+ // writeBounds();
+ file.writeAttribute("timestep",IObase::Int32,1,&currentstep);
+ file.writeAttribute("level_timestep",IObase::Int32,1,&level_timestep);
+ file.writeAttribute("persistence",IObase::Int32,1,&persistence);
+ file.writeAttribute("time_refinement",IObase::Int32,1,&(levels[currentlevel].trefine));
+
+ // need timestep vs. leveltimestep (must define time-is-local vs. time-is-global)
+ file.writeAttribute("spatial_refinement",IObase::Int32,drank,levels[currentlevel].srefine);
+ file.writeAttribute("grid_placement_refinement",IObase::Int32,drank,levels[currentlevel].prefine);
+ file.writeAttribute("iorigin",IObase::Int32,drank,iorigin);
+ // I guess thats it for integer parameters.
+ // These params are only for informational purposes
+ // Most viz systems will probably find the double precision
+ // parameters most suitable
+}
+
+AMRwriter::AMRwriter(IObase &descriptor):
+ Writer(descriptor),basetimestep(1.0),levels(1),
+ currentlevel(0),currentstep(0){
+ for(int i=0;i<3;i++){
+ levels[0].srefine[i]=levels[0].prefine[i]=1;
+ iorigin[i]=0;
+ }
+ levels[0].trefine=0;
+}
+
+AMRwriter::~AMRwriter(){
+ // destroy whatever....
+ // ... nothing to destroy now (went all static)
+}
+
+void AMRwriter::setTopLevelParameters(int rank,double *origin,
+ double *delta, double timestep,int maxdepth){
+ setRank(rank);
+ Writer::setOrigin(origin);
+ Writer::setDelta(delta);
+ levels.setSize(maxdepth);
+ /*
+ for(int i=0;i<rank;i++){
+ gorigin[i]=origin[i];
+ gdelta[i]=delta[i];
+ }*/
+ basetimestep=timestep;
+}
+
+// Could also make placement refinement FINESTLEVEL=-1000 and then you could
+// say things like gridplacement = FINESTLEVEL -1 or FINESTLEVEL +1
+// or maybe even FINESTLEVELREFINEMENT*2 or FINESTLEVELREFINEMENT/2
+// to get the correct value? Would require float support?
+// This would generate a lot of IF statements to monitor state though...
+void AMRwriter::setRefinement(int timerefinement,
+ int spatialrefinement,
+ int gridplacementrefinement){
+ int tref=1,sref=1,gref=gridplacementrefinement;
+ int maxdepth=levels.getSize()+1;
+ // if gref==-1, then we need to multiply by maxdepth
+ for(int level=0;level<maxdepth;level++){
+ setLevelRefinement(level,tref,sref,gref);
+ tref*=timerefinement;
+ sref*=spatialrefinement;
+ gref*=spatialrefinement;
+ }
+ if(gridplacementrefinement<0){
+ gref = -(levels[maxdepth-1]).prefine[0];
+ for(int level=0;level<maxdepth;level++)
+ for(int i=0;i<3;i++) (levels[level]).prefine[i] = gref;
+ }
+}
+void AMRwriter::setRefinement(int timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement){
+ int maxdepth = 1+levels.getSize();
+ int tref = 1;
+ int *sref = new int[drank];
+ int *gref = new int[drank];
+ for(int i=0;i<drank;i++)
+ { sref[i]=gref[i]=1;
+ if(gridplacementrefinement) gref[i]+=gridplacementrefinement[i];
+ }
+ for(int level=0;level<maxdepth;level++){
+ setLevelRefinement(level,tref,sref,gref);
+ for(int i=0;i<drank;i++) {
+ sref[i]*=spatialrefinement[i];
+ gref[i]*=spatialrefinement[i];
+ }
+ }
+ int isnegative=0,negmask[3]={0,0,0};
+ {for(int i=0;i<drank && i<3 ;i++)
+ if(gridplacementrefinement)
+ if(gridplacementrefinement[i]<0)
+ negmask[i]=isnegative=1;
+ }
+ if(isnegative){ // set max depth for all levels
+ for(int i=0;i<drank;i++) gref[i]=-(levels[maxdepth-1]).prefine[i];
+
+ for(int level=0;level<maxdepth;level++)
+ {
+ for(int i=0;i<drank;i++)
+ if(negmask[i])
+ (levels[level]).prefine[i]=gref[i];
+ }
+ }
+ delete sref;
+ delete gref;
+}
+
+void AMRwriter::setLevelRefinement(int level,int timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement){
+ if(level>=levels.getSize()) levels.setSize(level+1);
+ levels[level].trefine=timerefinement;
+ for(int i=0;i<drank;i++) {
+ (levels[level]).srefine[i]=spatialrefinement[i];
+ if(gridplacementrefinement>0)
+ (levels[level]).prefine[i]=gridplacementrefinement[i];
+ else
+ (levels[level]).prefine[i]=spatialrefinement[i];
+ }
+}
+
+void AMRwriter::setLevelRefinement(int level,int timerefinement,
+ int spatialrefinement,
+ int gridplacementrefinement){
+ if(level>=levels.getSize()) levels.setSize(level+1);
+ levels[level].trefine=timerefinement;
+ for(int i=0;i<drank;i++) {
+ (levels[level]).srefine[i]=spatialrefinement;
+ if(gridplacementrefinement>0)
+ (levels[level]).prefine[i]=gridplacementrefinement;
+ else
+ (levels[level]).prefine[i]=spatialrefinement;
+ }
+}
+
+void AMRwriter::setOrigin(int *origin){
+ for(int i=0;i<drank;i++) {
+ double dx = ddelta[i]/(levels[currentlevel]).prefine[i];
+ iorigin[i]=origin[i]; // integer origin (logical origin)
+ currentorigin[i]=(origin[i]*dx+dorigin[i]); // float origin (real origin)
+ }
+}
+
+void AMRwriter::setOrigin(float *origin){
+ for(int i=0;i<drank;i++) {
+ double dx = ddelta[i]/(levels[currentlevel]).prefine[i];
+ iorigin[i]=(int)floor((origin[i]-dorigin[i])/dx);
+ // set floating point origin
+ currentorigin[i]=origin[i];
+ }
+}
+
+void AMRwriter::setOrigin(double *origin){
+ for(int i=0;i<drank;i++) {
+ double dx = ddelta[i]/(levels[currentlevel]).prefine[i];
+ iorigin[i]=(int)floor((origin[i]-dorigin[i])/dx);
+ // set floating point origin
+ currentorigin[i]=origin[i];
+ }
+}
+
+void AMRwriter::write(void *data){
+ // write data
+ // then write AMR attributes (which will include
+ // the regular complement of attribs)
+ // IObase::write(data); // should call virtual writebounds?
+ file.write(dtypeID,drank,ddims,data);
+ writeAMRattributes();
+}
+
+void FrameworkAMRwriter::init(int rank,
+ double *origin,
+ double *delta,
+ double timestep,
+ int interlevelRefinementFactor,
+ int numLevels){
+ register int i,ref;
+ nlevels=numLevels;
+ refinement = interlevelRefinementFactor; // class member for FrameworkAMRwriter
+ for(i=0,maxrefinement=1;i<nlevels-1;i++) maxrefinement*=interlevelRefinementFactor;
+ AMRwriter::setTopLevelParameters(rank,origin,delta,timestep,numLevels);
+ AMRwriter::setRefinement(numLevels,interlevelRefinementFactor,interlevelRefinementFactor);
+}
+void FrameworkAMRwriter::init(IObase::DataType dt,
+ int rank,
+ double *origin,
+ double *delta,
+ double timestep,
+ int interlevelRefinementFactor,
+ int numLevels){
+ Writer::setType(dt);
+ init(rank,origin,delta,timestep,interlevelRefinementFactor,numLevels);
+}
+
+//===========C Interface======================================
+// should have an RTTI interface and inherit everything from
+// IOobject which contains the RTTI isOfType() information.
+// isOfType() should propagate recursively to determin type info
+// match. must grab typeID from floating point pool. And then
+// we need a static initializer for everything.
+
+// How does performer/inventor do this?
+
+
+AMRFile AMRbeginFile(IOFile *descriptor){
+ IObase *io = (IObase*)descriptor;
+ return (AMRFile)(new AMRwriter(*io));
+}
+
+void AMRendFile(AMRFile afile){
+ AMRwriter *w = (AMRwriter*)afile;
+ delete w;
+}
+
+void AMRsetType(AMRFile afile,int numbertype){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setType(IObase::Int2DataType(numbertype));
+}
+
+void AMRsetToplevelParameters(AMRFile afile,int rank, double *origin,
+ double *delta, double timestep,int maxdepth){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setTopLevelParameters(rank,origin,delta,timestep,maxdepth);
+}
+
+void AMRsetRefinement(AMRFile afile,
+ int timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setRefinement(timerefinement,spatialrefinement,gridplacementrefinement);
+}
+void AMRsetScalarRefinement(AMRFile afile,
+ int timerefinement,
+ int spatialrefinement,
+ int gridplacementrefinement){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setRefinement(timerefinement,spatialrefinement,gridplacementrefinement);
+}
+void AMRsetLevelRefinement(AMRFile afile,int level,
+ int timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setLevelRefinement(level,timerefinement,spatialrefinement,gridplacementrefinement);
+}
+
+
+/* using scalar values) */
+void AMRsetScalarLevelRefinement(AMRFile afile,int level,
+ int timerefinement,
+ int spatialrefinement,
+ int gridplacementrefinement){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setLevelRefinement(level,timerefinement,spatialrefinement,gridplacementrefinement);
+}
+
+void AMRlevel(AMRFile afile,int level){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setLevel(level);
+}
+
+void AMRtime(AMRFile afile,int time){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setTime(time);
+}
+
+void AMRincrementTime(AMRFile afile){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->incrementTime();
+}
+
+void AMRwrite(AMRFile afile,int *origin,int *dims,void *data){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->write(origin,dims,data);
+}
+
+void AMRwriteFloat(AMRFile afile,float *origin,int *dims,void *data){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->write(origin,dims,data);
+}
+
+void AMRwriteDouble(AMRFile afile,double *origin,int *dims,void *data){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->write(origin,dims,data);
+}
+
+fAMRFile fAMRbeginFile(IOFile *descriptor){
+ IObase *io = (IObase*)descriptor;
+ return (fAMRFile)(new FrameworkAMRwriter(*io));
+}
+
+void fAMRendFile(fAMRFile afile){
+ FrameworkAMRwriter *w = (FrameworkAMRwriter*)afile;
+ delete w;
+}
+
+void fAMRinit(fAMRFile afile,
+ int datatype,
+ int rank,
+ double *origin,
+ double *delta,
+ double timestep,
+ int interlevelRefinementRatio,
+ int nlevels){
+ FrameworkAMRwriter *w = (FrameworkAMRwriter*)afile;
+ IObase::DataType dt = IObase::Int2DataType(datatype);
+ w->init(dt,rank,origin,delta,timestep,interlevelRefinementRatio,nlevels);
+}
+void fAMRsetParameters(fAMRFile afile,
+ int datatype,
+ int rank,
+ double *origin,
+ double *delta,
+ double timestep,
+ int interlevelRefinementRatio,
+ int nlevels){
+ fAMRinit(afile,datatype,rank,origin,delta,timestep,interlevelRefinementRatio,nlevels);
+}
+inline void fAMRsetLevelParameters(fAMRFile afile,
+ int datatype,
+ int rank,
+ double *origin,
+ double *delta,
+ double timestep,
+ int interlevelRefinementRatio,
+ int nlevels){
+ fAMRinit(afile,datatype,rank,origin,delta,timestep,interlevelRefinementRatio,nlevels);
+}
+void fAMRwrite(fAMRFile afile,
+ int level,
+ int globaltimestep,
+ int *origin,
+ int *dims,
+ void *data){
+ FrameworkAMRwriter *w = (FrameworkAMRwriter*)afile;
+ w->write(level,globaltimestep,origin,dims,data);
+}
+
+//===========F77/F90 Interface==================================
+
+Long8 f_amr_begin(Long8 *descriptor){
+ IObase *io = (IObase*)descriptor;
+ return (Long8)(new AMRwriter(*io));
+}
+
+int f_amr_end(Long8 *afile){
+ AMRwriter *w = (AMRwriter*)afile;
+ delete w;
+ return 1;
+}
+
+int f_amr_settype(Long8 *afile,int *numbertype){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setType(IObase::Int2DataType(*numbertype));
+ return 1;
+}
+
+int f_amr_setparams(Long8 *afile,int *rank,double *origin,
+ double *delta, double *timestep,int *maxdepth){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setTopLevelParameters(*rank,origin,delta,*timestep,*maxdepth);
+ return 1;
+}
+
+int f_amr_setref(Long8 *afile,int *veclen,
+ int *timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement){
+ AMRwriter *w = (AMRwriter*)afile;
+ if(*veclen==1)
+ w->setRefinement(*timerefinement,
+ *spatialrefinement,*gridplacementrefinement);
+ else
+ w->setRefinement(*timerefinement,
+ spatialrefinement,gridplacementrefinement);
+ return 1;
+}
+
+int f_amr_setlref(Long8 *afile,int *level,int *veclen,
+ int *timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement){
+ AMRwriter *w = (AMRwriter*)afile;
+ if(*veclen==1)
+ w->setLevelRefinement(*level,*timerefinement,
+ *spatialrefinement,*gridplacementrefinement);
+ else
+ w->setLevelRefinement(*level,*timerefinement,
+ spatialrefinement,gridplacementrefinement);
+ return 1;
+}
+
+int f_amr_setlevel (Long8 *afile,int *level){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setLevel(*level);
+ return 1;
+}
+
+int f_amr_settime (Long8 *afile,int *timestep){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->setTime(*timestep);
+ return 1;
+}
+
+int f_amr_incrtime(Long8 *afile){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->incrementTime();
+ return 1;
+}
+
+int f_amr_write(Long8 *afile,int *origin, int *dims, void *data){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->write(origin,dims,data);
+ return 1;
+}
+int f_amr_writef(Long8 *afile,float *origin, int *dims, void *data){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->write(origin,dims,data);
+ return 1;
+}
+int f_amr_writed(Long8 *afile,double *origin, int *dims, void *data){
+ AMRwriter *w = (AMRwriter*)afile;
+ w->write(origin,dims,data);
+ return 1;
+}
diff --git a/src/AMRwriter.h b/src/AMRwriter.h
new file mode 100644
index 0000000..21cae5b
--- /dev/null
+++ b/src/AMRwriter.h
@@ -0,0 +1,47 @@
+#ifndef __AMRWRITER_H_
+#define __AMRWRITER_H_
+
+#include "Arch.h"
+
+typedef IOFile AMRFile; /* its the same, but it is a different object underneath */
+AMRFile AMRbeginFile PROTO((IOFile descriptor));
+void AMRendFile PROTO((AMRFile afile));
+void AMRsetType PROTO((AMRFile afile,int numbertype));
+void AMRsetTopLevelParameters PROTO((AMRFile afile,int rank,double *origin,
+ double *delta, double timestep,int maxdepth));
+void AMRsetRefinement PROTO((AMRFile afile,int timerefinement,
+ int *spatialrefinement,int *gridplacementrefinement));
+void AMRsetScalarRefinement PROTO((AMRFile afile,int timerefinement,
+ int spatialrefinement,int gridplacementrefinement));
+void AMRsetLevelRefinement PROTO((AMRFile afile,int level,int timerefinement,
+ int *spatialrefinement,int *gridplacementrefinement));
+void AMRsetScalarLevelRefinement PROTO((AMRFile afile,int level,int timerefinement,
+ int spatialrefinement,int gridplacementrefinement));
+/* Stepping Methods */
+void AMRsetLevel PROTO((AMRFile afile,int level));
+void AMRsetTime PROTO((AMRFile afile,int timestep));
+void AMRincrementTime PROTO((AMRFile afile));
+void AMRwrite PROTO((AMRFile afile,int *origin, int *dims, void *data));
+void AMRwriteFloat PROTO((AMRFile afile,float *origin, int *dims, void *data));
+void AMRwriteDouble PROTO((AMRFile afile,double *origin, int *dims, void *data));
+
+/*----------For the Framework AMR---------------*/
+typedef IOFile fAMRFile;
+fAMRFile fAMRbeginFile PROTO((IOFile descriptor));
+void fAMRendFile PROTO((fAMRFile afile));
+void fAMRsetParameters PROTO((fAMRFile afile,
+ int datatype,
+ int rank,
+ double *origin,
+ double *delta,
+ double timestep,
+ int interlevelRefinementRatio,
+ int nlevels));
+void fAMRwrite PROTO((fAMRFile afile,
+ int level,
+ int globaltimestep,
+ int *origin,
+ int *dims,
+ void *data));
+#endif
+
diff --git a/src/AMRwriter.hh b/src/AMRwriter.hh
new file mode 100644
index 0000000..61114ca
--- /dev/null
+++ b/src/AMRwriter.hh
@@ -0,0 +1,288 @@
+// AMRwriter
+#ifndef __AMRWRITER_HH_
+#define __AMRWRITER_HH_
+
+#include "Arch.h"
+#include "IO.hh"
+#include "Writer.hh"
+#include "FlexArrayTmpl.H"
+
+class AMRwriter : public Writer{
+protected:
+ struct LevelParams {
+ int srefine[3]; // grid refinement
+ int prefine[3]; // placement refinement
+ int trefine; // time refinement
+ };
+ double basetimestep,currentorigin[3],currentdelta[3];
+ FlexArray<LevelParams> levels;
+ int iorigin[3];
+ int currentlevel,currentstep;
+
+ void writeAMRattributes();
+private:
+ virtual void setOrigin(int *origin); // logical origin
+ virtual void setOrigin(float *origin); // real origin
+ virtual void setOrigin(double *origin); // real origin
+ // virtual void setDelta(double *delta) { Writer::setOrigin(delta); }
+ virtual void setDims(int *dims) { Writer::setDims(dims);}
+ virtual void setDims(int rank, int *dims) { Writer::setDims(rank,dims); }
+ virtual void write(void *data);
+ virtual void setRank(int rank) {Writer::setRank(rank); }
+public: //====================================================
+ enum Flags {MaxDepth=-1};
+ AMRwriter(IObase &descriptor);
+ virtual ~AMRwriter();
+ //------------Initialization Methods------------------
+ virtual void setType(IObase::DataType numbertype) { Writer::setType(numbertype); }
+ virtual void setTopLevelParameters(int rank,double *origin,
+ double *delta,double timestep,int maxdepth);
+ virtual void setRefinement(int timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement=0);
+ virtual void setRefinement(int timerefinement,
+ int spatialrefinement,
+ int gridplacementrefinement=1);
+ virtual void setLevelRefinement(int level,
+ int timerefinement,
+ int *spatialrefinement,
+ int *gridplacementrefinement=0);
+ virtual void setLevelRefinement(int level,
+ int timerefinement,
+ int spatialrefinement,
+ int gridplacementrefinement=1);
+ //-----------Stepping Parameters------------------
+ virtual void setLevel(int level) { currentlevel=level; }
+ virtual void setTime(int timestep) { currentstep=timestep;}
+ virtual void incrementTime() {currentstep++;}
+ // virtual void setDeltaTime(double dt) {deltatime=dt;}
+ virtual void write(int *origin,int *dims,void *data){
+ setOrigin(origin);
+ setDims(dims);
+ write(data);
+ }
+ virtual void write(float *origin,int *dims,void *data){
+ setOrigin(origin);
+ setDims(dims);
+ write(data);
+ }
+ virtual void write(double *origin,int *dims,void *data){
+ // create iorigin from origin...
+ setOrigin(origin);
+ setDims(dims);
+ write(data);
+ }
+};
+
+
+class FrameworkAMRwriter : protected AMRwriter {
+ int nlevels;
+ int maxrefinement;
+ int refinement;
+public:
+ /*@@
+ @routine FrameworkAMRwriter::FrameworkAMRwriter
+ @date Tue Apr 15 14:23:32 1997
+ @author John Shalf
+ @desc
+ Constructor for the FrameworkAMRwriter. It makes many assumptions about the
+ way that users of the framework would like to store their data. This eliminates
+ or hides most of the calls that AMRwriter:: would need to describe the AMR grid
+ heirarchy.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+
+ FrameworkAMRwriter(IObase &descriptor):AMRwriter(descriptor),
+ nlevels(1),maxrefinement(1),refinement(2){}
+ virtual ~FrameworkAMRwriter() {}
+ /*
+ This is set ONCE right after you open your AMR file. It is not
+ built into the constructor because you may not have the information
+ necessary to do this at the time of construction...
+ */
+ /*@@
+ @routine FrameworkAMRwriter::setParameters
+ @date Tue Apr 15 14:00:40 1997
+ @author John Shalf
+ @desc This is set ONCE right after you open your AMR file. It is not
+ built into the constructor because you may not have the information
+ necessary to do this at the time of construction...
+ This sets parameters necessary do define the AMR heirarchy, namely
+ the refinement between levels and the floating-point parameters that
+ form the basis for locating the grids in 3-space in a visualization system.
+ @enddesc
+ @par rank
+ @pdesc The number of dimensions for the dataset
+ @ptype int
+ @pvalues 1-5
+ @pcomment
+ This calls setRank() in the base Writer() class
+ @endpar
+
+ @par origin
+ @pdesc The origin of the toplevel (coarsest) grid in REAL coordinates
+ @ptype double*
+ @endpar
+
+ @par delta
+ @pdesc The inter-grid spacing at the toplevel (coarsest level) in REAL coordinates.
+ @ptype double
+ @pcomment
+ The inter-grid spacing is divided by the refinement factor for a particular level
+ to determine the real grid spacing for that nested grid.
+ This assumes you have a uniform grid delta (same delta in all spatial directions).
+ @endpar
+
+ @par timestep
+ @pdesc The REAL size of a toplevel (coarsest) timestep
+ @ptype double
+ @pvalues
+ @endpar
+
+ @par interlevelRefinementRatio
+ @pdesc The integer ratio of time refinement and spatial refinement between levels.
+ @ptype int
+ @pvalues Any positive integer > 0
+ @pcomment
+ This ratio is used to determine the spatial refinement for a level.
+ So spatialrefinement_on_this_level = toplevel_delta / interlevelRefinementRatio^level
+ Where the levels are numbered from 0:nlevels-1.
+ This assumes that you have the same refinement factor in all spatial directions as
+ well as in time.
+ @endpar
+
+ @par numLevels
+ @pdesc The maximum number of levels in the AMR heirarchy.
+ @ptype int
+ @pvalues Any positive integer > 0
+ @pcomment
+ This is necessary to find out the resolution of the finest-grid for the
+ purposes of grid-placement in the AMR file. Otherwise we wouldn't be able
+ to interpret the above parameters.
+ @endpar
+
+ @calls AMRwriter::setTopLevelParameters
+ @calledby
+ @history
+ @endhistory
+
+@@*/
+
+ virtual void init(int rank, // number of dimensions in the dataset
+ double *origin, // REAL origin or coarsest level grid
+ double *delta, // float grid spacing at coarsest level
+ double timestep, // float timestep at coarsest level
+ int interlevelRefinementRatio, //refinement ratio with
+ // between levels. This covers refinement of time stepping
+ // as well
+ int numLevels); // the maximum depth of the AMR grid heirarchy
+ virtual void init( IObase::DataType dt, // type for all data
+ int rank, // number of dimensions in the dataset
+ double *origin, // REAL origin or coarsest level grid
+ double *delta, // float grid spacing at coarsest level
+ double timestep, // float timestep at coarsest level
+ int interlevelRefinementRatio, //refinement ratio with
+ // between levels. This covers refinement of time stepping
+ // as well
+ int numLevels);
+ // This is called on every write
+ /*@@
+ @routine FrameworkAMRwriter::write
+ @date Tue Apr 15 14:14:48 1997
+ @author John Shalf
+ @desc
+ This is called on every write to set the parameters for a particular grid.
+ @enddesc
+ @calls AMRwriter::setGrid AMRwriter::write
+ @calledby
+ @par level
+ @pdesc The current AMR level for this grid
+ @ptype int
+ @pvalues 0 to nlevels-1
+ @endpar
+
+ @par globaltimestep
+ @pdesc The current global timestep (stepping at the finest resolution level)
+ @ptype int
+ @pvalues Any positive integer
+ @pcomment
+ So we step at finest time resolution instead of resolution relative to this level.
+ @endpar
+
+ @par origin
+ @pdesc The integer origin of the grid using coordinates relative to the finest resolution grid in the heirarchy.
+ @ptype int*
+ @pvalues Any positive integer > 0
+ @pcomment
+ So grid placement is with respect to the finest level integer coordinates.
+ @endpar
+
+ @par dims
+ @pdesc The dimensions of the array (dims of the grid).
+ @ptype int*
+ @endpar
+
+ @par data
+ @pdesc Pointer to the data array for the grid.
+ @ptype void*
+ @endpar
+
+
+ @history
+
+ @endhistory
+
+@@*/
+
+ virtual void write(int level,
+ int globaltimestep,
+ int *origin,
+ int *dims,
+ void *data) {
+ AMRwriter::setLevel(level);
+ AMRwriter::setTime(globaltimestep);
+ AMRwriter::write(origin,dims,data);
+ }
+
+};
+
+#define f_amr_begin F77NAME(amr_begin_,amr_begin,AMR_BEGIN)
+#define f_amr_end F77NAME(amr_end_,amr_end,AMR_END)
+#define f_amr_settype F77NAME(amr_settype_,amr_settype,AMR_SETTYPE)
+#define f_amr_setparams F77NAME(amr_setparams_,amr_setparams,AMR_SETPARAMS)
+#define f_amr_setref F77NAME(amr_setref_,amr_setref,AMR_SETREF)
+#define f_amr_setlref F77NAME(amr_setlref_,amr_setlref,AMR_SETLREF)
+#define f_amr_setdims F77NAME(amr_setdims_,amr_setdims,AMR_SETDIMS)
+#define f_amr_setlevel F77NAME(amr_setlevel_,amr_setlevel,AMR_SETLEVEL)
+#define f_amr_settime F77NAME(amr_settime_,amr_settime,AMR_SETTIME)
+#define f_amr_incrtime F77NAME(amr_incrtime_,amr_incrtime,AMR_INCRTIME)
+#define f_amr_write F77NAME(amr_write_,amr_write,AMR_WRITE)
+
+extern "C" {
+#include "AMRwriter.h"
+Long8 f_amr_begin (Long8 *descriptor);
+int f_amr_end (Long8 *afile);
+int f_amr_settype (Long8 *afile,int *numbertype);
+int f_amr_setparams (Long8 *afile,int *rank,double *origin,
+ double *delta, double *timestep,int maxdepth);
+int f_amr_setref (Long8 *afile,int veclen,
+ int *timerefinement,
+ int *spatialrefinement,int *gridplacementrefinement);
+int f_amr_setlref (Long8 *afile,int *level,int *veclen,
+ int *timerefinement,
+ int *spatialrefinement,int *gridplacementrefinement);
+int f_amr_setlevel (Long8 *afile,int *level);
+int f_amr_settime (Long8 *afile,int *timestep);
+int f_amr_incrtime (Long8 *afile);
+int f_amr_write (Long8 *afile,int *origin,int *dims,void *data);
+ int f_amr_writef (Long8 *afile,float *origin,int *dims,void *data);
+ int f_amr_writed (Long8 *afile,double *origin,int *dims,void *data);
+}
+
+#endif
diff --git a/src/AVSreadBNB.cc b/src/AVSreadBNB.cc
new file mode 100644
index 0000000..b964cc4
--- /dev/null
+++ b/src/AVSreadBNB.cc
@@ -0,0 +1,817 @@
+/*-----------------------------------------------------*
+ * AVSreadHLL: Reads Tom's libHLL data into AVS UCD *
+ * format. This is based on the AVS readUCD.cc *
+ * code snippet. *
+ *-----------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <avs/avs.h>
+#include <avs/geom.h>
+#include <avs/ucd_defs.h>
+#include "IEEEIO.hh"
+#include "WriteHLL.hh"
+#include "FlexArrayTmpl.H"
+#include "AmrNode.hh"
+#include "AmrUcdFileReader.hh"
+#define buffer_size 200
+#define NUM_CELL_TYPES 8
+
+extern char *AVSstatic;
+
+typedef struct _ucd_stats {
+ int size;
+ } Ucd_Stats_Type;
+
+typedef struct _ctype_struct {
+ int id, mat, n, cell_type;
+ } Ctype;
+
+typedef struct _ntype_struct {
+ int n, node_list[20];
+ } Ntype;
+
+typedef struct _model_stats {
+ char node_data_labels[100], cell_data_labels[100], model_data_labels[100],
+ node_data_units[100], cell_data_units[100], model_data_units[100];
+
+ int num_nodes, num_cells, num_node_data, num_cell_data, num_model_data,
+ node_active_list[20], cell_active_list[20], model_active_list[20],
+ num_node_comp, node_comp_list[20], num_cell_comp, cell_comp_list[20],
+ num_model_comp, model_comp_list[20], num_nlist_nodes;
+ } Mtype;
+
+/* ANSI-C/C++ expect functions to be declared before being used and checks
+ argument compatibility */
+
+AVS_STATIC(void add_cell, (UCD_structure **model, int cell, int ucd_cell_type, int n,
+ int *rnode_list, int mat_id));
+AVS_STATIC(int read_binary, (AmrFileReader *file,
+ Ctype **pcells, int **pcell_nlists,
+ Mtype *model, float **pxc, float **pyc, float **pzc,
+ float **pnode_data, float **pcell_data, float **pmodel_data,
+ float **pmin_node_data, float **pmax_node_data,
+ float **pmin_cell_data, float **pmax_cell_data,
+ float **pmin_model_data, float **pmax_model_data));
+
+int read_bnb( UCD_structure** output,
+ const char* file_name,
+ int TimeStep,
+ int cell_con, /* Not used! */
+ const char* td1, /* Not used! */
+ const char* contour, /* Not used! */
+ const char* td2, /* Not used! */
+ const char* cell_sel, /* Not used! */
+ const char* td3, /* Not used! */
+ const char* model_sel /* Not used! */ )
+ {
+
+ char string[40], *model_name, tmp_str[80];
+ static IEEEIO *io=0;
+ static AmrFileReader *file=0;
+ float x, y, z,
+ xmin = 0.0, xmax = 0.0, ymin = 0.0, ymax = 0.0, zmin = 0.0, zmax = 0.0,
+ min_extent[3], max_extent[3];
+
+ int node, cell, n, i, util_flag, j, ucd_flags, cell_tsize, node_csize;
+
+ Ctype *cells;
+
+ float *xc, *yc, *zc, *node_data, *cell_data, *model_data,
+ *min_node_data, *max_node_data, *min_cell_data,
+ *max_cell_data, *min_model_data, *max_model_data;
+
+ int num_nodes, num_cells, num_node_data, num_cell_data, num_model_data,
+ *bcell_nlists;
+
+ Mtype model_stats;
+
+ Ntype *cell_nlists;
+
+ static int clist[] = {1, 2, 3, 4};
+
+ Ucd_Stats_Type *ucd_stats;
+
+ int recompute=0;
+
+ /**************
+ *** body ***
+ **************/
+
+ if (!file_name)
+ return(1);
+
+ if (AVSstatic == NULL) {
+ ucd_stats = (Ucd_Stats_Type *)malloc(sizeof(Ucd_Stats_Type));
+ AVSstatic = (char *) ucd_stats;
+ }
+ else
+ ucd_stats = (Ucd_Stats_Type *)AVSstatic;
+ if(AVSparameter_changed("read file")){
+ io = new IEEEIO(file_name,IObase::Read);
+ if(!io->isValid())
+ return (0);
+ file = new AmrFileReader(*io);
+ int mintime,maxtime;
+ file->getTimeRange(mintime,maxtime);
+ if((maxtime-mintime)<=1){
+ AVSmodify_parameter("TimeStep",AVS_VALUE|AVS_MINVAL|AVS_MAXVAL,
+ mintime,mintime,maxtime+1);
+ AVSparameter_visible("TimeStep",0);
+ }
+ else {
+ AVSmodify_parameter("TimeStep",AVS_MINVAL|AVS_MAXVAL|AVS_VALUE,
+ mintime,mintime,maxtime);
+ AVSparameter_visible("TimeStep",1);
+ }
+ // select current grid
+ file->showAllLevels();
+ file->setTime(mintime);
+ recompute=1;
+ }
+ else if(AVSparameter_changed("TimeStep")){
+ file->setTime(TimeStep);
+ recompute=1;
+ }
+ else
+ recompute=0;
+
+ if (recompute){
+ if (*output) UCDstructure_free (*output);
+ cell_nlists = NULL;
+ bcell_nlists = NULL;
+ /* check to see if file is binary or ascii. */
+ if (!read_binary (file, &cells, &bcell_nlists, &model_stats, &xc,
+ &yc, &zc, &node_data, &cell_data, &model_data,
+ &min_node_data, &max_node_data, &min_cell_data,
+ &max_cell_data, &min_model_data, &max_model_data)) {
+ AVSerror (" Error in read_bnb: can't open bin file. \n");
+ return (0);
+ }
+
+
+
+ /* set the model statistics:
+
+ num_nodes - the number of nodes in the model.
+
+ num_cells - the number of cells (elements) in the model.
+
+ num_node_data - the total number of data values per node. if you
+ wanted to store three scalars and one 3-vector per
+ node then num_node_data would be set to six.
+
+ num_cell_data - the total number of data values per cell.
+
+ num_model_data - model data is used for values which apply to the
+ the model as a whole, not just nodes or cells.
+ for example, the locations of loads could be stored
+ here.
+
+
+ */
+ util_flag = 0;
+ num_nodes = model_stats.num_nodes;
+ num_cells = model_stats.num_cells;
+ num_node_data = model_stats.num_node_data;
+ num_cell_data = model_stats.num_cell_data;
+ num_model_data = model_stats.num_model_data;
+ strcpy (tmp_str, file_name);
+
+ model_name = (char *)(strrchr(tmp_str, '/'));
+
+ if (model_name) model_name++; /* go to the next character */
+
+ for (i = strlen(model_name); model_name[i] != '.'; i--);
+ model_name[i] = '\0';
+
+
+ /* 'cell_tsize' is the size of all of the cell topology (number of
+ nodes per cell) lists. it is used to allocate space for the node
+ lists for each cell. if all the cells were hexahedra (without
+ mid-edge nodes) then this would be set to num_cells*eight, if all
+ the cells were tetrahedra (without mid-edge nodes) then this would
+ be set to num_cells*four.
+
+ 'node_csize' is the size all of the node connectivity lists (the list
+ of cells connected to a node). for a model constructed from all
+ hexahedra this would be less than num_cells*eight.
+
+ both 'cell_tsize' and 'node_csize' are computed when the model is
+ read (in the read_ascii or the read_bin functions) and are always
+ equal.
+
+ 'ucd_flags' specifies how labels for cells and nodes will be stored
+ and whether material id's and cell types will be stored for each cell.
+ the following is a list of flags which can be or'ed together:
+
+ UCD_MATERIAL_IDS - material id's for each cell will be stored.
+ UCD_NODE_NAMES - node names will be stored.
+ UCD_CELL_NAMES - cell names will be stored.
+ UCD_CELL_TYPES - user defined cell type will be stored.
+ UCD_MID_EDGES - cells will have mid-side edges.
+ UCD_CHAR - node/cell labels are character strings.
+ UCD_INT - node/cell labels are integers. */
+
+ cell_tsize = node_csize = model_stats.num_nlist_nodes;
+ ucd_stats->size = cell_tsize;
+
+ ucd_flags = UCD_INT | UCD_MATERIAL_IDS | UCD_NODE_NAMES | UCD_CELL_NAMES |
+ UCD_CELL_TYPES | UCD_MID_EDGES;
+
+ printf("Allocating output structure for nnodedata=%u numcells=%u numnodes=%u\n",
+ num_node_data,num_cells,num_nodes);
+ *output = (UCD_structure *)UCDstructure_alloc (model_name,
+ num_model_data, ucd_flags, num_cells, cell_tsize,
+ num_cell_data, num_nodes, node_csize, num_node_data, util_flag);
+
+
+ /* store nodal coordinates. */
+
+ for (node = 0; node < num_nodes; node++) {
+ x = xc[node], y = yc[node], z = zc[node];
+
+ if (node) {
+ xmin = (x < xmin ? x : xmin), xmax = (x > xmax ? x : xmax);
+ ymin = (y < ymin ? y : ymin), ymax = (y > ymax ? y : ymax);
+ zmin = (z < zmin ? z : zmin), zmax = (z > zmax ? z : zmax);
+ }
+ else {
+ xmin = xmax = x;
+ ymin = ymax = y;
+ zmin = zmax = z;
+ }
+
+ if (!UCDnode_set_information (*output, node, (char *) (node + 1), 0, clist)) {
+ AVSerror ("Error in read_bnb: can't set node %d info.\n", node);
+ return (0);
+ }
+ }
+
+ UCDstructure_set_node_positions (*output, xc, yc, zc);
+
+
+ /* store the model's extent (max/min dimensions). */
+
+ min_extent[0] = xmin, min_extent[1] = ymin, min_extent[2] = zmin;
+ max_extent[0] = xmax, max_extent[1] = ymax, max_extent[2] = zmax;
+
+ UCDstructure_set_extent (*output, min_extent, max_extent);
+
+
+ /* store cell type, topology. */
+
+ if (bcell_nlists) { /* if read in as binary file. */
+ for (cell = 0, j = 0; cell < num_cells; cell++, j += n) {
+ n = cells[cell].n;
+
+ add_cell (output, cell, cells[cell].cell_type, n, &bcell_nlists[j],
+ cells[cell].mat);
+ }
+ }
+ else
+ for (cell = 0; cell < num_cells; cell++)
+ add_cell (output, cell, cells[cell].cell_type, cell_nlists[cell].n,
+ cell_nlists[cell].node_list, cells[cell].mat);
+
+
+ /* store nodal data.
+
+ data at nodes is separated into components. successive nodes of a
+ component are stored contiguously. for example, if you wish to
+ store two scalars and one 3-vector then this would be three
+ components and would be stored as (given n nodes in the model):
+
+ 0 node 0, component 1
+ 1 node 1, component 1
+ .
+ .
+ .
+ n node n, component 1
+ n+1 node 0, component 2
+ n+2 node 1, component 2
+ .
+ .
+ .
+ 2n node n, component 2
+ 2n+1 node 0, component 3, 1st vector component
+ 2n+2 node 0, component 3, 2nd vector component
+ 2n+3 node 0, component 3, 3rd vector component
+ 2n+4 node 1, component 3, 1st vector component
+
+ 2n+5 node 1, component 3, 2nd vector component
+ 2n+6 node 1, component 3, 3rd vector component
+ .
+ .
+ .
+ 5n-2 node n, component 3, 1st vector component
+ 5n-1 node n, component 3, 2nd vector component
+ 5n node n, component 3, 3rd vector component
+
+
+ the node component list has an entry for each compoment. each
+ entry specifies the dimensionality for each component. for example,
+ a scalar component would have an entry of one and a 3-vector would
+ have an entry of three.
+
+ the node active list can be used to specify which data type is
+ currently active (being used to display results). the list has
+ an entry for each data component. if that entry is not zero
+ then it is active. currently, this functionality is not used by
+ any modules.
+
+ node labels specify the user defined name of each data component.
+
+ node units specify the user defined units of each data component.
+
+ node minmax specifies the maximum and minimum values for each
+ data component. this has no meaning for vector components although
+ the max/min magnitude of the vector could be used.
+
+ */
+
+ if (num_node_data) {
+ puts("Set Node Data!");
+ printf("Num node data=%u\n",num_node_data);
+ UCDstructure_set_node_components (*output, model_stats.node_comp_list,
+ model_stats.num_node_comp);
+
+
+ UCDstructure_set_node_active (*output, model_stats.node_active_list);
+
+ UCDstructure_set_node_labels (*output, model_stats.node_data_labels, ".");
+
+ UCDstructure_set_node_units (*output, model_stats.node_data_units, ".");
+
+ if (model_stats.num_node_comp > 1) {
+ for (i = 0; model_stats.node_data_labels[i] != '.'; i++)
+ string[i] = model_stats.node_data_labels[i];
+ string[i] = '\0';
+ }
+ else
+ strcpy (string, model_stats.node_data_labels);
+
+ AVSmodify_parameter ("Node Type", AVS_MINVAL | AVS_VALUE, string,
+ model_stats.node_data_labels, ".");
+
+ printf("Set node minmax %f, %f\n",*min_node_data,*max_node_data);
+ UCDstructure_set_node_minmax (*output, min_node_data, max_node_data);
+
+ if (!UCDstructure_set_node_data (*output, node_data)) {
+ AVSerror ("Error in read_bnb: can't set node data.\n");
+ return (0);
+ }
+ }
+ else
+ AVSmodify_parameter ("Node Type", AVS_MINVAL | AVS_VALUE, " ",
+ "<no data>", ".");
+
+
+ /* store cell data. */
+
+ if (num_cell_data) {
+ UCDstructure_set_cell_components (*output, model_stats.cell_comp_list,
+ model_stats.num_cell_comp);
+
+ UCDstructure_set_cell_active (*output, model_stats.cell_active_list);
+
+ UCDstructure_set_cell_labels (*output, model_stats.cell_data_labels, ".");
+
+ for (i = 0; model_stats.cell_data_labels[i] != '.'; i++)
+ string[i] = model_stats.cell_data_labels[i];
+ string[i] = '\0';
+
+ AVSmodify_parameter ("Cell Type", AVS_MINVAL | AVS_VALUE, string,
+ model_stats.cell_data_labels, ".");
+
+ if (!UCDstructure_set_cell_data (*output, cell_data)) {
+ AVSerror ("Error in read_bnb: can't set cell data.\n");
+ return (0);
+ }
+ }
+ else {
+ AVSmodify_parameter ("Cell Type", AVS_MINVAL | AVS_VALUE, " ",
+ "<no data>", ".");
+ }
+
+
+ /* store model data. */
+
+ if (num_model_data) {
+ UCDstructure_set_data_labels (*output, model_stats.model_data_labels, ".");
+
+ for (i = 0; model_stats.model_data_labels[i] != '.'; i++)
+ string[i] = model_stats.model_data_labels[i];
+ string[i] = '\0';
+
+ AVSmodify_parameter ("Model Type", AVS_MINVAL | AVS_VALUE, string,
+ model_stats.model_data_labels, ".");
+
+ if (!UCDstructure_set_data (*output, model_data)) {
+ AVSerror ("Error in read_bnb: can't set model data.\n");
+ return (0);
+ }
+ }
+ else
+ AVSmodify_parameter ("Model Type", AVS_MINVAL | AVS_VALUE, " ",
+ "<no data>", ".");
+
+ if (*output) {
+ free (xc);
+ free (yc);
+ free (zc);
+
+ if (num_node_data) {
+ free (node_data);
+ free (min_node_data);
+ free (max_node_data);
+ }
+
+ if (num_cell_data) {
+ free (cell_data);
+ free (min_cell_data);
+ free (max_cell_data);
+ }
+
+ if (num_model_data) {
+ free (model_data);
+ free (min_model_data);
+ free (max_model_data);
+ }
+
+ free (cells);
+
+ if (cell_nlists)
+ free (cell_nlists);
+
+ if (bcell_nlists)
+ free (bcell_nlists);
+ }
+ }
+ return(1);
+ }
+
+
+/*-----------------------------------------------------*
+ * *
+ * **** add_cell **** *
+ * *
+ * add a cell topology to the ucd structure. *
+ *-----------------------------------------------------*/
+
+static void add_cell( UCD_structure** model, int cell, int ucd_cell_type, int n,
+ int* rnode_list, int mat_id )
+ {
+
+ static char *cell_type[] = {"pt", "line", "tri", "quad", "tet",
+ "pyr", "prism", "hex"};
+
+ int i, num_me_nodes, num_nodes, /* Not used: cell_found, */
+ me_flag, node_list[40];
+
+ /**************
+ *** body ***
+ **************/
+
+ if (ucd_cell_type < NUM_CELL_TYPES) {
+ me_flag = 0;
+ num_nodes = UCD_num_nodes[ucd_cell_type];
+
+
+ /* if the number of nodes read (n) is equal to the number of
+ nodes without mid-side nodes then send the read node list.
+ else set the mid-edge flag to indicate which edges have
+ mide-edge nodes. */
+
+ for (i = 0; i < num_nodes; i++)
+ node_list[i] = rnode_list[i] - 1;
+
+ if (n != num_nodes) {
+ for (i = num_nodes, num_me_nodes = 0; i < n; i++)
+ if (rnode_list[i] != 0) {
+ node_list[num_nodes + num_me_nodes] = rnode_list[i] - 1;
+ me_flag = me_flag | (0x1 << (i - num_nodes));
+ num_me_nodes++;
+ }
+ }
+
+ UCDcell_set_information (*model, cell, (char *) (cell + 1),
+ cell_type[ucd_cell_type],
+ mat_id - 1, ucd_cell_type, me_flag, node_list);
+ }
+ }
+
+static int add_grid(AmrGrid &g,float *data,
+ int &pindex,int &cindex,
+ float *x,float *y,float *z,int *cells,
+ float &min_node_data,float &max_node_data){
+ int edgemapx[8]={0,0,1,1,0,0,1,1};
+ int edgemapy[8]={0,1,1,0,0,1,1,0};
+ int edgemapz[8]={0,0,0,0,1,1,1,1};
+ int edgemap[8];
+ for(int i=0;i<8;i++)
+ edgemap[i] = edgemapx[i] + g.dims[0]*(edgemapy[i] + edgemapz[i]*g.dims[1]);
+ printf("edgemap=%u:%u:%u:%u:%u:%u:%u:%u\n",
+ edgemap[0],edgemap[1],edgemap[2],edgemap[3],
+ edgemap[4],edgemap[5],edgemap[6],edgemap[7]);
+ // compute edge map based on dims
+ if(g.datatype==IObase::Float64) // for double precision data
+ for(int didx=0,idx=pindex,k=0,klast=g.dims[2];k<klast;k++){
+ float zval = g.delta[2]*(double)k+g.origin[2];
+ for(int j=0,jlast=g.dims[1];j<jlast;j++){
+ float yval = g.delta[1]*(double)j+g.origin[1];
+ for(int i=0,ilast=g.dims[0];i<ilast;i++,idx++,didx++){
+ float xval = g.delta[0]*(double)i+g.origin[0];
+ float dt;
+ x[idx] = xval;
+ y[idx] = yval;
+ z[idx] = zval;
+ data[idx]=dt=(float)(((double*)g.data)[i]);
+ if(dt>max_node_data) max_node_data=dt;
+ if(dt<min_node_data) min_node_data=dt;
+ }
+ }
+ }
+ else // for single precision data
+ for(int didx=0,idx=pindex,k=0,klast=g.dims[2];k<klast;k++){
+ float zval = g.delta[2]*(double)k+g.origin[2];
+ for(int j=0,jlast=g.dims[1];j<jlast;j++){
+ float yval = g.delta[1]*(double)j+g.origin[1];
+ for(int i=0,ilast=g.dims[0];i<ilast;i++,idx++,didx++){
+ float xval = g.delta[0]*(double)i+g.origin[0];
+ float dt;
+ x[idx] = xval;
+ y[idx] = yval;
+ z[idx] = zval;
+ data[idx]=dt=((float*)(g.data))[didx];
+ if(dt>max_node_data) max_node_data=dt;
+ if(dt<min_node_data) min_node_data=dt;
+ }
+ }
+ }
+ // do cell connectivity
+ printf("pindex=%u\n",pindex);
+ for(int idx=pindex+1,k=0,klast=g.dims[2]-1;k<klast;k++){
+ for(int j=0,jlast=g.dims[1]-1;j<jlast;j++){
+ for(int i=0,ilast=g.dims[0]-1;i<ilast;i++,idx++){
+ for(int e=0;e<8;e++,cindex++) cells[cindex]=edgemap[e]+idx;
+ }
+ idx++; // skip last row
+ }
+ idx+=g.dims[0]; // skip last column
+ }
+ pindex+=IObase::nElements(g.rank,g.dims);
+}
+
+/*-----------------------------------------------------*
+ * *
+ * **** read_binary **** *
+ * *
+ * read a ucd binary file. *
+ *-----------------------------------------------------*/
+
+static int read_binary( AmrFileReader *file,
+ Ctype** pcells,
+ int** pcell_nlists,
+ Mtype* model,
+ float** pxc,
+ float** pyc,
+ float** pzc,
+ float** pnode_data,
+ float** pcell_data,
+ float** pmodel_data,
+ float** pmin_node_data,
+ float** pmax_node_data,
+ float** pmin_cell_data,
+ float** pmax_cell_data,
+ float** pmin_model_data,
+ float** pmax_model_data )
+ {
+
+ //char magic;
+
+ Ctype *cells;
+
+ // FILE *fp;
+
+ float *xc, *yc, *zc, *node_data, *cell_data, *model_data,
+ *min_node_data, *max_node_data, *min_cell_data, *max_cell_data,
+ *min_model_data, *max_model_data;
+
+ int num_nodes, num_cells, num_node_data,
+ num_cell_data, num_model_data, *cell_nlists, num_nlist_nodes;
+ int ngrids = file->getNumGrids();
+ FlexArray<AmrGrid> grid;
+ file->getGrids(grid); // get the AMR grids
+ /**************
+ *** body ***
+ **************/
+
+ node_data = cell_data = model_data = NULL;
+ max_cell_data = min_cell_data =max_model_data=min_model_data=NULL;
+
+ int i,ndims, cellsz, celltype,largest_grid=0;
+ model->num_cell_data=model->num_node_data=model->num_model_data=0;
+
+ // Go through and count up how many cells are required
+ // Count up how many nodes are required
+ for(i=0,model->num_nodes=0,model->num_cells=0;i<ngrids;i++){
+ int g_npts=1,g_ncls=1;
+ for(int j=0;j<grid[i].rank;j++){
+ g_npts*=grid[i].dims[j];
+ g_ncls*=(grid[i].dims[j]-1);
+ }
+ if(largest_grid<g_npts) largest_grid=g_npts;
+ model->num_nodes += g_npts;
+ model->num_cells += g_ncls;
+ }
+ model->num_node_data=1; // always
+ model->num_cell_data=0;
+ model->num_model_data=0;
+ ndims=3; // hardcoded
+ switch(ndims){
+ case 0:
+ cellsz=1;
+ celltype=UCD_POINT;
+ break;
+ case 1:
+ cellsz=2;
+ celltype=UCD_LINE;
+ break;
+ case 2:
+ cellsz=4;
+ celltype=UCD_QUADRILATERAL;
+ break;
+ case 3:
+ cellsz=8;
+ celltype=UCD_HEXAHEDRON;
+ break;
+ }
+ model->num_nlist_nodes=cellsz*model->num_cells; // hexahedral cells
+ // fill out basic parameters
+ num_nodes = model->num_nodes;
+ num_cells = model->num_cells;
+ num_node_data = model->num_node_data;
+ num_cell_data = model->num_cell_data;
+ num_model_data = model->num_model_data;
+ num_nlist_nodes = model->num_nlist_nodes;
+
+ printf("Allocating %u cell storage structures. total=%lu\n", num_cells, sizeof(Ctype)*num_cells);
+ cells = (Ctype *)malloc(sizeof(Ctype) * num_cells);
+ printf("cells pointer=%lu\n",(unsigned long)cells);
+ printf("Allocating %u points for cell connectivity storage\n", num_nlist_nodes);
+ cell_nlists = (int *)malloc(sizeof(int) * num_nlist_nodes);
+
+ printf("Init cell info structures\n");
+ for(i=0;i<num_cells;i++){
+ //printf("cellnum=%u\n",i);
+ (cells[i]).id=i+1;
+ (cells[i]).mat=1; // change to level
+ (cells[i]).n=cellsz;
+ (cells[i]).cell_type=celltype;
+ }
+ printf("\nDone init cell info structures\n");
+ // foreach grid, create connectivity
+ xc = (float *)malloc(sizeof(float) * num_nodes);
+ yc = (float *)malloc(sizeof(float) * num_nodes);
+ zc = (float *)malloc(sizeof(float) * num_nodes);
+ // Allocate space for node data
+ node_data = (float *)malloc(sizeof(float) * num_nodes * num_node_data);
+ min_node_data = (float *)malloc(sizeof(float) * num_node_data);
+ max_node_data = (float *)malloc(sizeof(float) * num_node_data);
+ if(grid[0].datatype==IObase::Float32){
+ float *d=(float*)(grid[0].data);
+ *min_node_data = *max_node_data = d[0];
+ }
+ else{
+ double *d=(double*)(grid[0].data);
+ *min_node_data = *max_node_data = (float)(d[0]);
+ }
+ // convert each grid to UCD
+ int cpointindex=0,ccellindex=0;
+ for(/*cpointindex=0,ccellindex=0,*/ i=0;i<ngrids;i++){
+ add_grid(grid[i],node_data,
+ cpointindex,ccellindex,
+ xc,yc,zc,cell_nlists,
+ min_node_data[0],max_node_data[0]);
+ }
+ printf("Sanity check, ncells=%u:%u nnodes=%u:%u\n",num_cells*8,ccellindex,
+ num_nodes,cpointindex);
+
+ model->node_active_list[0]=1;
+ sprintf(model->node_data_labels,"bnbdata");
+ sprintf(model->node_data_units,"unity");
+ model->node_comp_list[0]=1;
+ model->num_node_comp=1;
+
+ *pxc = xc, *pyc = yc, *pzc = zc;
+ *pcells = cells;
+ *pcell_nlists = cell_nlists;
+ *pnode_data = node_data;
+ *pcell_data = cell_data = 0;
+ *pmodel_data = model_data = 0;
+
+ model->num_nodes = num_nodes;
+ model->num_cells = num_cells;
+ model->num_node_data = num_node_data;
+ model->num_cell_data = num_cell_data;
+ model->num_model_data = num_model_data;
+
+ *pmax_node_data = max_node_data;
+ *pmin_node_data = min_node_data;
+ *pmax_cell_data = max_cell_data;
+ *pmin_cell_data = min_cell_data;
+ *pmax_model_data = max_model_data;
+ *pmin_model_data = min_model_data;
+
+ return(1);
+ }
+
+/*-----------------------------------------------------*
+ * *
+ * **** read_bnb_init **** *
+ * *
+ *-----------------------------------------------------*/
+
+static void
+read_bnb_init()
+ {
+ AVSstatic = (char *)0;
+ }
+
+
+/*-----------------------------------------------------*
+ * *
+ * **** read_bnb_finis **** *
+ * *
+ *-----------------------------------------------------*/
+
+static void
+read_bnb_finis()
+ {
+ if (AVSstatic == NULL) return;
+
+ free (AVSstatic);
+ }
+
+
+static void
+read_bnb_desc()
+ {
+ int param;
+
+ static char *choices = "<data 1>.<data 2>.<data 3>.<data 4>.<data 5>";
+
+ /**************
+ *** body ***
+ **************/
+
+ AVSset_module_name ("Read BNB", MODULE_DATA);
+
+ AVScreate_output_port ("tet output", "ucd");
+
+ param = AVSadd_parameter ("read file", "string", 0, 0, ".ieee");
+ AVSconnect_widget (param, "browser");
+ AVSadd_parameter("TimeStep", "integer", 0, 0, 1);
+ AVSadd_parameter("Cell Connect", "boolean", 0, 0, 1);
+
+ param = AVSadd_parameter("Node Data", "string", "Node Data", "Node Data",
+ NULL);
+ AVSconnect_widget(param, "text");
+
+ AVSadd_parameter ("Node Type", "choice", "<data 1>", choices, ".");
+
+ param = AVSadd_parameter("Cell Data", "string", "Cell Data", "Cell Data",
+ NULL);
+ AVSconnect_widget (param, "text");
+
+ AVSadd_parameter ("Cell Type", "choice", "<data 1>", choices, ".");
+
+ param = AVSadd_parameter("Model Data", "string", "Model Data", "Model Data",
+ NULL);
+ AVSconnect_widget (param, "text");
+
+ AVSadd_parameter ("Model Type", "choice", "<data 1>", choices, ".");
+
+ AVSset_init_proc ((AVS_FNCP) read_bnb_init);
+
+ AVSset_destroy_proc ((AVS_FNCP) read_bnb_finis);
+
+ AVSset_compute_proc ((AVS_FNCP) read_bnb);
+ }
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void
+AVSinit_modules()
+ {
+ AVSmodule_from_desc ((AVS_FNCP) read_bnb_desc);
+ }
+
+#if __cplusplus
+}
+#endif
+
diff --git a/src/AVSreadHLL.cc b/src/AVSreadHLL.cc
new file mode 100644
index 0000000..f55e32e
--- /dev/null
+++ b/src/AVSreadHLL.cc
@@ -0,0 +1,768 @@
+/*-----------------------------------------------------*
+ * AVSreadHLL: Reads Tom's libHLL data into AVS UCD *
+ * format. This is based on the AVS readUCD.cc *
+ * code snippet. *
+ *-----------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <avs/avs.h>
+#include <avs/geom.h>
+#include <avs/ucd_defs.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "WriteHLL.hh"
+
+#define buffer_size 200
+#define NUM_CELL_TYPES 8
+
+extern char *AVSstatic;
+
+typedef struct _ucd_stats {
+ int size;
+ } Ucd_Stats_Type;
+
+typedef struct _ctype_struct {
+ int id, mat, n, cell_type;
+ } Ctype;
+
+typedef struct _ntype_struct {
+ int n, node_list[20];
+ } Ntype;
+
+typedef struct _model_stats {
+ char node_data_labels[100], cell_data_labels[100], model_data_labels[100],
+ node_data_units[100], cell_data_units[100], model_data_units[100];
+
+ int num_nodes, num_cells, num_node_data, num_cell_data, num_model_data,
+ node_active_list[20], cell_active_list[20], model_active_list[20],
+ num_node_comp, node_comp_list[20], num_cell_comp, cell_comp_list[20],
+ num_model_comp, model_comp_list[20], num_nlist_nodes;
+ } Mtype;
+
+/* ANSI-C/C++ expect functions to be declared before being used and checks
+ argument compatibility */
+
+AVS_STATIC(void add_cell, (UCD_structure **model, int cell, int ucd_cell_type, int n,
+ int *rnode_list, int mat_id));
+AVS_STATIC(int read_binary, (const char *file_name, Ctype **pcells, int **pcell_nlists,
+ Mtype *model, float **pxc, float **pyc, float **pzc,
+ float **pnode_data, float **pcell_data, float **pmodel_data,
+ float **pmin_node_data, float **pmax_node_data,
+ float **pmin_cell_data, float **pmax_cell_data,
+ float **pmin_model_data, float **pmax_model_data));
+
+int read_hll( UCD_structure** output,
+ const char* file_name,
+ int cell_con, /* Not used! */
+ const char* td1, /* Not used! */
+ const char* contour, /* Not used! */
+ const char* td2, /* Not used! */
+ const char* cell_sel, /* Not used! */
+ const char* td3, /* Not used! */
+ const char* model_sel /* Not used! */ )
+ {
+
+ char string[40], *model_name, tmp_str[80];
+
+ float x, y, z,
+ xmin = 0.0, xmax = 0.0, ymin = 0.0, ymax = 0.0, zmin = 0.0, zmax = 0.0,
+ min_extent[3], max_extent[3];
+
+ int node, cell, n, i, util_flag, j, ucd_flags, cell_tsize, node_csize;
+
+ Ctype *cells;
+
+ float *xc, *yc, *zc, *node_data, *cell_data, *model_data,
+ *min_node_data, *max_node_data, *min_cell_data,
+ *max_cell_data, *min_model_data, *max_model_data;
+
+ int num_nodes, num_cells, num_node_data, num_cell_data, num_model_data,
+ *bcell_nlists;
+
+ Mtype model_stats;
+
+ Ntype *cell_nlists;
+
+ static int clist[] = {1, 2, 3, 4};
+
+ Ucd_Stats_Type *ucd_stats;
+
+ /**************
+ *** body ***
+ **************/
+
+ if (!file_name)
+ return(1);
+
+ if (AVSstatic == NULL) {
+ ucd_stats = (Ucd_Stats_Type *)malloc(sizeof(Ucd_Stats_Type));
+ AVSstatic = (char *) ucd_stats;
+ }
+ else
+ ucd_stats = (Ucd_Stats_Type *)AVSstatic;
+
+ if (AVSparameter_changed("read file")) {
+ if (*output) UCDstructure_free (*output);
+
+ cell_nlists = NULL;
+ bcell_nlists = NULL;
+
+
+ /* check to see if file is binary or ascii. */
+
+ if (!read_binary (file_name, &cells, &bcell_nlists, &model_stats, &xc,
+ &yc, &zc, &node_data, &cell_data, &model_data,
+ &min_node_data, &max_node_data, &min_cell_data,
+ &max_cell_data, &min_model_data, &max_model_data)) {
+ AVSerror (" Error in read_hll: can't open bin file. \n");
+ return (0);
+ }
+
+
+
+ /* set the model statistics:
+
+ num_nodes - the number of nodes in the model.
+
+ num_cells - the number of cells (elements) in the model.
+
+ num_node_data - the total number of data values per node. if you
+ wanted to store three scalars and one 3-vector per
+ node then num_node_data would be set to six.
+
+ num_cell_data - the total number of data values per cell.
+
+ num_model_data - model data is used for values which apply to the
+ the model as a whole, not just nodes or cells.
+ for example, the locations of loads could be stored
+ here.
+
+
+ */
+ util_flag = 0;
+ num_nodes = model_stats.num_nodes;
+ num_cells = model_stats.num_cells;
+ num_node_data = model_stats.num_node_data;
+ num_cell_data = model_stats.num_cell_data;
+ num_model_data = model_stats.num_model_data;
+ strcpy (tmp_str, file_name);
+
+ model_name = (char *)(strrchr(tmp_str, '/'));
+
+ if (model_name) model_name++; /* go to the next character */
+
+ for (i = strlen(model_name); model_name[i] != '.'; i--);
+ model_name[i] = '\0';
+
+
+ /* 'cell_tsize' is the size of all of the cell topology (number of
+ nodes per cell) lists. it is used to allocate space for the node
+ lists for each cell. if all the cells were hexahedra (without
+ mid-edge nodes) then this would be set to num_cells*eight, if all
+ the cells were tetrahedra (without mid-edge nodes) then this would
+ be set to num_cells*four.
+
+ 'node_csize' is the size all of the node connectivity lists (the list
+ of cells connected to a node). for a model constructed from all
+ hexahedra this would be less than num_cells*eight.
+
+ both 'cell_tsize' and 'node_csize' are computed when the model is
+ read (in the read_ascii or the read_bin functions) and are always
+ equal.
+
+ 'ucd_flags' specifies how labels for cells and nodes will be stored
+ and whether material id's and cell types will be stored for each cell.
+ the following is a list of flags which can be or'ed together:
+
+ UCD_MATERIAL_IDS - material id's for each cell will be stored.
+ UCD_NODE_NAMES - node names will be stored.
+ UCD_CELL_NAMES - cell names will be stored.
+ UCD_CELL_TYPES - user defined cell type will be stored.
+ UCD_MID_EDGES - cells will have mid-side edges.
+ UCD_CHAR - node/cell labels are character strings.
+ UCD_INT - node/cell labels are integers. */
+
+ cell_tsize = node_csize = model_stats.num_nlist_nodes;
+ ucd_stats->size = cell_tsize;
+
+ ucd_flags = UCD_INT | UCD_MATERIAL_IDS | UCD_NODE_NAMES | UCD_CELL_NAMES |
+ UCD_CELL_TYPES | UCD_MID_EDGES;
+
+ *output = (UCD_structure *)UCDstructure_alloc (model_name,
+ num_model_data, ucd_flags, num_cells, cell_tsize,
+ num_cell_data, num_nodes, node_csize, num_node_data, util_flag);
+
+
+ /* store nodal coordinates. */
+
+ for (node = 0; node < num_nodes; node++) {
+ x = xc[node], y = yc[node], z = zc[node];
+
+ if (node) {
+ xmin = (x < xmin ? x : xmin), xmax = (x > xmax ? x : xmax);
+ ymin = (y < ymin ? y : ymin), ymax = (y > ymax ? y : ymax);
+ zmin = (z < zmin ? z : zmin), zmax = (z > zmax ? z : zmax);
+ }
+ else {
+ xmin = xmax = x;
+ ymin = ymax = y;
+ zmin = zmax = z;
+ }
+
+ if (!UCDnode_set_information (*output, node, (char *) (node + 1), 0, clist)) {
+ AVSerror ("Error in read_hll: can't set node %d info.\n", node);
+ return (0);
+ }
+ }
+
+ UCDstructure_set_node_positions (*output, xc, yc, zc);
+
+
+ /* store the model's extent (max/min dimensions). */
+
+ min_extent[0] = xmin, min_extent[1] = ymin, min_extent[2] = zmin;
+ max_extent[0] = xmax, max_extent[1] = ymax, max_extent[2] = zmax;
+
+ UCDstructure_set_extent (*output, min_extent, max_extent);
+
+
+ /* store cell type, topology. */
+
+ if (bcell_nlists) { /* if read in as binary file. */
+ for (cell = 0, j = 0; cell < num_cells; cell++, j += n) {
+ n = cells[cell].n;
+
+ add_cell (output, cell, cells[cell].cell_type, n, &bcell_nlists[j],
+ cells[cell].mat);
+ }
+ }
+ else
+ for (cell = 0; cell < num_cells; cell++)
+ add_cell (output, cell, cells[cell].cell_type, cell_nlists[cell].n,
+ cell_nlists[cell].node_list, cells[cell].mat);
+
+
+ /* store nodal data.
+
+ data at nodes is separated into components. successive nodes of a
+ component are stored contiguously. for example, if you wish to
+ store two scalars and one 3-vector then this would be three
+ components and would be stored as (given n nodes in the model):
+
+ 0 node 0, component 1
+ 1 node 1, component 1
+ .
+ .
+ .
+ n node n, component 1
+ n+1 node 0, component 2
+ n+2 node 1, component 2
+ .
+ .
+ .
+ 2n node n, component 2
+ 2n+1 node 0, component 3, 1st vector component
+ 2n+2 node 0, component 3, 2nd vector component
+ 2n+3 node 0, component 3, 3rd vector component
+ 2n+4 node 1, component 3, 1st vector component
+
+ 2n+5 node 1, component 3, 2nd vector component
+ 2n+6 node 1, component 3, 3rd vector component
+ .
+ .
+ .
+ 5n-2 node n, component 3, 1st vector component
+ 5n-1 node n, component 3, 2nd vector component
+ 5n node n, component 3, 3rd vector component
+
+
+ the node component list has an entry for each compoment. each
+ entry specifies the dimensionality for each component. for example,
+ a scalar component would have an entry of one and a 3-vector would
+ have an entry of three.
+
+ the node active list can be used to specify which data type is
+ currently active (being used to display results). the list has
+ an entry for each data component. if that entry is not zero
+ then it is active. currently, this functionality is not used by
+ any modules.
+
+ node labels specify the user defined name of each data component.
+
+ node units specify the user defined units of each data component.
+
+ node minmax specifies the maximum and minimum values for each
+ data component. this has no meaning for vector components although
+ the max/min magnitude of the vector could be used.
+
+ */
+
+ if (num_node_data) {
+ UCDstructure_set_node_components (*output, model_stats.node_comp_list,
+ model_stats.num_node_comp);
+
+
+ UCDstructure_set_node_active (*output, model_stats.node_active_list);
+
+ UCDstructure_set_node_labels (*output, model_stats.node_data_labels, ".");
+
+ UCDstructure_set_node_units (*output, model_stats.node_data_units, ".");
+
+ if (model_stats.num_node_comp > 1) {
+ for (i = 0; model_stats.node_data_labels[i] != '.'; i++)
+ string[i] = model_stats.node_data_labels[i];
+ string[i] = '\0';
+ }
+ else
+ strcpy (string, model_stats.node_data_labels);
+
+ AVSmodify_parameter ("Node Type", AVS_MINVAL | AVS_VALUE, string,
+ model_stats.node_data_labels, ".");
+
+ UCDstructure_set_node_minmax (*output, min_node_data, max_node_data);
+
+ if (!UCDstructure_set_node_data (*output, node_data)) {
+ AVSerror ("Error in read_hll: can't set node data.\n");
+ return (0);
+ }
+ }
+ else
+ AVSmodify_parameter ("Node Type", AVS_MINVAL | AVS_VALUE, " ",
+ "<no data>", ".");
+
+
+ /* store cell data. */
+
+ if (num_cell_data) {
+ UCDstructure_set_cell_components (*output, model_stats.cell_comp_list,
+ model_stats.num_cell_comp);
+
+ UCDstructure_set_cell_active (*output, model_stats.cell_active_list);
+
+ UCDstructure_set_cell_labels (*output, model_stats.cell_data_labels, ".");
+
+ for (i = 0; model_stats.cell_data_labels[i] != '.'; i++)
+ string[i] = model_stats.cell_data_labels[i];
+ string[i] = '\0';
+
+ AVSmodify_parameter ("Cell Type", AVS_MINVAL | AVS_VALUE, string,
+ model_stats.cell_data_labels, ".");
+
+ if (!UCDstructure_set_cell_data (*output, cell_data)) {
+ AVSerror ("Error in read_hll: can't set cell data.\n");
+ return (0);
+ }
+ }
+ else {
+ AVSmodify_parameter ("Cell Type", AVS_MINVAL | AVS_VALUE, " ",
+ "<no data>", ".");
+ }
+
+
+ /* store model data. */
+
+ if (num_model_data) {
+ UCDstructure_set_data_labels (*output, model_stats.model_data_labels, ".");
+
+ for (i = 0; model_stats.model_data_labels[i] != '.'; i++)
+ string[i] = model_stats.model_data_labels[i];
+ string[i] = '\0';
+
+ AVSmodify_parameter ("Model Type", AVS_MINVAL | AVS_VALUE, string,
+ model_stats.model_data_labels, ".");
+
+ if (!UCDstructure_set_data (*output, model_data)) {
+ AVSerror ("Error in read_hll: can't set model data.\n");
+ return (0);
+ }
+ }
+ else
+ AVSmodify_parameter ("Model Type", AVS_MINVAL | AVS_VALUE, " ",
+ "<no data>", ".");
+
+ if (*output) {
+ free (xc);
+ free (yc);
+ free (zc);
+
+ if (num_node_data) {
+ free (node_data);
+ free (min_node_data);
+ free (max_node_data);
+ }
+
+ if (num_cell_data) {
+ free (cell_data);
+ free (min_cell_data);
+ free (max_cell_data);
+ }
+
+ if (num_model_data) {
+ free (model_data);
+ free (min_model_data);
+ free (max_model_data);
+ }
+
+ free (cells);
+
+ if (cell_nlists)
+ free (cell_nlists);
+
+ if (bcell_nlists)
+ free (bcell_nlists);
+ }
+ }
+ return(1);
+ }
+
+
+/*-----------------------------------------------------*
+ * *
+ * **** add_cell **** *
+ * *
+ * add a cell topology to the ucd structure. *
+ *-----------------------------------------------------*/
+
+static void add_cell( UCD_structure** model, int cell, int ucd_cell_type, int n,
+ int* rnode_list, int mat_id )
+ {
+
+ static char *cell_type[] = {"pt", "line", "tri", "quad", "tet",
+ "pyr", "prism", "hex"};
+
+ int i, num_me_nodes, num_nodes, /* Not used: cell_found, */
+ me_flag, node_list[40];
+
+ /**************
+ *** body ***
+ **************/
+
+ if (ucd_cell_type < NUM_CELL_TYPES) {
+ me_flag = 0;
+ num_nodes = UCD_num_nodes[ucd_cell_type];
+
+
+ /* if the number of nodes read (n) is equal to the number of
+ nodes without mid-side nodes then send the read node list.
+ else set the mid-edge flag to indicate which edges have
+ mide-edge nodes. */
+
+ for (i = 0; i < num_nodes; i++)
+ node_list[i] = rnode_list[i] - 1;
+
+ if (n != num_nodes) {
+ for (i = num_nodes, num_me_nodes = 0; i < n; i++)
+ if (rnode_list[i] != 0) {
+ node_list[num_nodes + num_me_nodes] = rnode_list[i] - 1;
+ me_flag = me_flag | (0x1 << (i - num_nodes));
+ num_me_nodes++;
+ }
+ }
+
+ UCDcell_set_information (*model, cell, (char *) (cell + 1),
+ cell_type[ucd_cell_type],
+ mat_id - 1, ucd_cell_type, me_flag, node_list);
+ }
+ }
+
+
+/*-----------------------------------------------------*
+ * *
+ * **** read_binary **** *
+ * *
+ * read a ucd binary file. *
+ *-----------------------------------------------------*/
+
+static int read_binary( const char* file_name,
+ Ctype** pcells,
+ int** pcell_nlists,
+ Mtype* model,
+ float** pxc,
+ float** pyc,
+ float** pzc,
+ float** pnode_data,
+ float** pcell_data,
+ float** pmodel_data,
+ float** pmin_node_data,
+ float** pmax_node_data,
+ float** pmin_cell_data,
+ float** pmax_cell_data,
+ float** pmin_model_data,
+ float** pmax_model_data )
+ {
+
+ //char magic;
+
+ Ctype *cells;
+
+ // FILE *fp;
+
+ float *xc, *yc, *zc, *node_data, *cell_data, *model_data,
+ *min_node_data, *max_node_data, *min_cell_data, *max_cell_data,
+ *min_model_data, *max_model_data;
+
+ int num_nodes, num_cells, num_node_data,
+ num_cell_data, num_model_data, *cell_nlists, num_nlist_nodes;
+
+ /**************
+ *** body ***
+ **************/
+
+ node_data = cell_data = model_data = NULL;
+ max_cell_data = min_cell_data =max_model_data=min_model_data=NULL;
+
+ //if (!(fp = fopen (file_name, "r")))
+ // return (0);
+
+ IEEEIO *file = new IEEEIO(file_name,IObase::Read);
+ if(!file->isValid())
+ return (0);
+ ReadHLL *hll = new ReadHLL(*file);
+ int ndims, cellsz, celltype;
+ model->num_cell_data=model->num_node_data=model->num_model_data=0;
+ hll->selectDataset(0/*index*/,
+ ndims,
+ model->num_nodes,model->num_cells,model->num_node_data);
+ model->num_nlist_nodes=8*model->num_cells; // hexahedral cells
+
+ switch(ndims){
+ case 0:
+ cellsz=1;
+ celltype=UCD_POINT;
+ break;
+ case 1:
+ cellsz=2;
+ celltype=UCD_LINE;
+ break;
+ case 2:
+ cellsz=4;
+ celltype=UCD_QUADRILATERAL;
+ break;
+ case 3:
+ cellsz=8;
+ celltype=UCD_HEXAHEDRON;
+ break;
+ }
+ model->num_nlist_nodes=cellsz*model->num_cells; // hexahedral cells
+ // fill out basic parameters
+ num_nodes = model->num_nodes;
+ num_cells = model->num_cells;
+ num_node_data = model->num_node_data;
+ num_cell_data = model->num_cell_data;
+ num_model_data = model->num_model_data;
+ num_nlist_nodes = model->num_nlist_nodes;
+
+ cells = (Ctype *)malloc(sizeof(Ctype) * num_cells);
+ cell_nlists = (int *)malloc(sizeof(int) * num_nlist_nodes);
+
+ //fread ((char *)cells, sizeof(Ctype), num_cells, fp);
+ for(int i=0;i<num_cells;i++){
+ cells[i].id=i+1;
+ cells[i].mat=1;
+ cells[i].n=cellsz;
+ cells[i].cell_type=celltype;
+ }
+ //fread ((char *)cell_nlists, sizeof(int), num_nlist_nodes, fp);
+ hll->readConnectivity(cell_nlists);
+
+ xc = (float *)malloc(sizeof(float) * num_nodes);
+ yc = (float *)malloc(sizeof(float) * num_nodes);
+ zc = (float *)malloc(sizeof(float) * num_nodes);
+
+ //fread ((char *)xc, sizeof(float), num_nodes, fp);
+ //fread ((char *)yc, sizeof(float), num_nodes, fp);
+ //fread ((char *)zc, sizeof(float), num_nodes, fp);
+ hll->readCoords(xc,yc,zc);
+
+ if (num_node_data) {
+ int nm=0;
+ // Now read in information about the node data
+ char **names=new char*[num_node_data];
+ for(nm=0;nm<num_node_data;nm++) names[nm]=new char[32]; // limit names to 32chars
+ IObase::DataType *datatypes=new IObase::DataType[num_node_data];
+ int *veclens = new int[num_node_data];
+ hll->readDataInfo(names,datatypes,veclens);
+
+ node_data = (float *)malloc(sizeof(float) * num_nodes * num_node_data);
+ min_node_data = (float *)malloc(sizeof(float) * num_node_data);
+ max_node_data = (float *)malloc(sizeof(float) * num_node_data);
+ for(nm=0;nm<num_node_data;nm++){
+ if(veclens[nm]>1) {
+ printf("node_data[%u] has veclen %u which is too large to store in this implementation\n",
+ nm,veclens[nm]);
+ continue;
+ }
+ switch(datatypes[nm]){
+ case IObase::Float32:
+ hll->readData(names[nm],node_data+(nm*num_nodes));
+ break;
+ case IObase::Float64:
+ { double *data=new double[num_nodes];
+ hll->readData(names[nm],data);
+ for(int idx=0,offset=num_nodes*nm;idx<num_nodes;idx++)
+ node_data[idx+offset]=(float)(data[idx]);
+ delete data;
+ } break;
+ case IObase::Int32:
+ { int *data=new int[num_nodes];
+ hll->readData(names[nm],data);
+ for(int idx=0,offset=num_nodes*nm;idx<num_nodes;idx++)
+ node_data[idx+offset]=(float)(data[idx]);
+ delete data;
+ } break;
+ case IObase::Int64:
+ { long long *data=new long long[num_nodes];
+ hll->readData(names[nm],data);
+ for(int idx=0,offset=num_nodes*nm;idx<num_nodes;idx++)
+ node_data[idx+offset]=(float)(data[idx]);
+ delete data;
+ } break;
+ case IObase::Byte:
+ { char *data=new char[num_nodes];
+ hll->readData(names[nm],data);
+ for(int idx=0,offset=num_nodes*nm;idx<num_nodes;idx++)
+ node_data[idx+offset]=(float)(data[idx]);
+ delete data;
+ } break;
+ default:
+ printf("unknown datatype %d for node_data[%u]\n",(int)(datatypes[nm]),nm);
+ break;
+ }
+ // convert data to float (avs only knows floats)
+ // scan for min
+ // scan for max
+ float min,max;
+ min=max=node_data[nm*num_nodes];
+ for(int idx=1,offset=nm*num_nodes;idx<num_nodes;idx++){
+ float pt=node_data[idx+offset];
+ if(pt>max) max=pt;
+ if(pt<min) min=pt;
+ }
+ min_node_data[nm]=min;
+ max_node_data[nm]=max;
+ }
+ //fread ((char *)min_node_data, sizeof(float), num_node_data, fp);
+ //fread ((char *)max_node_data, sizeof(float), num_node_data, fp);
+ //fread ((char *)node_data, sizeof(float), num_node_data * num_nodes, fp);
+ for(nm=0;nm<num_node_data;nm++) delete names[nm];
+ delete names;
+ delete datatypes;
+ delete veclens;
+ }
+
+ *pxc = xc, *pyc = yc, *pzc = zc;
+ *pcells = cells;
+ *pcell_nlists = cell_nlists;
+ *pnode_data = node_data;
+ *pcell_data = cell_data;
+ *pmodel_data = model_data;
+
+ model->num_nodes = num_nodes;
+ model->num_cells = num_cells;
+ model->num_node_data = num_node_data;
+ model->num_cell_data = num_cell_data;
+ model->num_model_data = num_model_data;
+
+ *pmax_node_data = max_node_data;
+ *pmin_node_data = min_node_data;
+ *pmax_cell_data = max_cell_data;
+ *pmin_cell_data = min_cell_data;
+ *pmax_model_data = max_model_data;
+ *pmin_model_data = min_model_data;
+
+ // fclose (fp);
+ delete hll;
+ delete file;
+
+ return(1);
+ }
+
+/*-----------------------------------------------------*
+ * *
+ * **** read_hll_init **** *
+ * *
+ *-----------------------------------------------------*/
+
+static void
+read_hll_init()
+ {
+ AVSstatic = (char *)0;
+ }
+
+
+/*-----------------------------------------------------*
+ * *
+ * **** read_hll_finis **** *
+ * *
+ *-----------------------------------------------------*/
+
+static void
+read_hll_finis()
+ {
+ if (AVSstatic == NULL) return;
+
+ free (AVSstatic);
+ }
+
+
+static void
+read_hll_desc()
+ {
+ int param;
+
+ static char *choices = "<data 1>.<data 2>.<data 3>.<data 4>.<data 5>";
+
+ /**************
+ *** body ***
+ **************/
+
+ AVSset_module_name ("Read HLL", MODULE_DATA);
+
+ AVScreate_output_port ("tet output", "ucd");
+
+ param = AVSadd_parameter ("read file", "string", 0, 0, ".inp");
+ AVSconnect_widget (param, "browser");
+
+ AVSadd_parameter("Cell Connect", "boolean", 0, 0, 1);
+
+ param = AVSadd_parameter("Node Data", "string", "Node Data", "Node Data",
+ NULL);
+ AVSconnect_widget(param, "text");
+
+ AVSadd_parameter ("Node Type", "choice", "<data 1>", choices, ".");
+
+ param = AVSadd_parameter("Cell Data", "string", "Cell Data", "Cell Data",
+ NULL);
+ AVSconnect_widget (param, "text");
+
+ AVSadd_parameter ("Cell Type", "choice", "<data 1>", choices, ".");
+
+ param = AVSadd_parameter("Model Data", "string", "Model Data", "Model Data",
+ NULL);
+ AVSconnect_widget (param, "text");
+
+ AVSadd_parameter ("Model Type", "choice", "<data 1>", choices, ".");
+
+ AVSset_init_proc ((AVS_FNCP) read_hll_init);
+
+ AVSset_destroy_proc ((AVS_FNCP) read_hll_finis);
+
+ AVSset_compute_proc ((AVS_FNCP) read_hll);
+ }
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void
+AVSinit_modules()
+ {
+ AVSmodule_from_desc ((AVS_FNCP) read_hll_desc);
+ }
+
+#if __cplusplus
+}
+#endif
+
diff --git a/src/AVSreadIEEE.c b/src/AVSreadIEEE.c
new file mode 100644
index 0000000..9289c59
--- /dev/null
+++ b/src/AVSreadIEEE.c
@@ -0,0 +1,95 @@
+/* mod_gen Version 1 */
+/* Module Name: "Read IEEE" (Input) (Subroutine) */
+/* Author: John Shalf,50,50,none */
+/* Date Created: Wed Mar 26 13:49:06 1997 */
+/* */
+/* This file is automatically generated by the Module Generator (mod_gen)*/
+/* Please do not modify or move the contents of this comment block as */
+/* mod_gen needs it in order to read module sources back in. */
+/* */
+/* output 0 "out" field */
+/* param 0 "Filename" browser "" "" ":" */
+/* param 1 "RecordNumber" idial 0 0 1 */
+/* End of Module Description Comments */
+
+#include <stdio.h>
+#include <avs/avs.h>
+#include <avs/port.h>
+#include <avs/field.h>
+
+/* *****************************************/
+/* Module Description */
+/* *****************************************/
+int Read_IEEE_desc()
+{
+
+ int in_port, out_port, param, iresult;
+ extern int Read_IEEE_compute();
+
+ AVSset_module_name("Read IEEE", MODULE_DATA);
+
+ /* Output Port Specifications */
+ out_port = AVScreate_output_port("out", "field");
+
+ /* Parameter Specifications */
+ param = AVSadd_parameter("Filename", "string", "", "", ":");
+ AVSconnect_widget(param, "browser");
+ param = AVSadd_parameter("RecordNumber", "integer", 0, 0, 1);
+ AVSconnect_widget(param, "idial");
+
+ /*
+ param = AVSadd_parameter("SetExtents","boolean",0,0,0);
+ AVSconnect_widget(param,"toggle");
+ param = AVSadd_parameter("SetCoordinates","choice",
+ "Set Min/Max",
+ "Set Min/Max:Set Edges:Set None",
+ ":");
+ AVSconnect_widget(param,"radio_buttons");
+ */
+
+ AVSset_compute_proc(Read_IEEE_compute);
+ return(1);
+}
+
+/* *****************************************/
+/* Module Compute Routine */
+/* *****************************************/
+int Read_IEEE_compute(out,Filename,RecordNumber,SetExtents,SetCoordinates)
+ AVSfield **out;
+ char *Filename;
+ int RecordNumber;
+ int SetExtents;
+ char *SetCoordinates;
+{
+ /*
+ Its a pain to integrate C++ directly into the Read_IEEE code and
+ yet so much nicer to use the C++ interface than the C interface.
+ So we'll just call a c++ compute subroutine that is located in
+ another object file, "AVSreadcpp.cc".
+
+ There is a version of this same thing in AVSreadhlcpp.cc which
+ makes use of the even higher level (and hence more convenient)
+ user interface. However there is some concern that it will be
+ harder to debug IEEEIO if we layer the interface too much so
+ its back to the low-level interface again.
+ */
+ extern int readIEEE();
+ return readIEEE(out,Filename,RecordNumber,1,"Set Edges");
+ /* return readIEEE(out,Filename,RecordNumber,SetExtents,SetCoordinates); */
+}
+
+/* ***********************************************************************/
+/* Initialization for modules contained in this file. */
+/* ***********************************************************************/
+static int ((*mod_list[])()) = {
+ Read_IEEE_desc
+};
+#define NMODS (sizeof(mod_list) / sizeof(char *))
+
+AVSinit_modules()
+{
+ AVSinit_from_module_list(mod_list, NMODS);
+}
+
+/* ----> START OF USER-SUPPLIED CODE SECTION #4 (SUBROUTINES, FUNCTIONS, UTILITY ROUTINES)*/
+/* <---- END OF USER-SUPPLIED CODE SECTION #4 */
diff --git a/src/AVSreadcpp.cc b/src/AVSreadcpp.cc
new file mode 100644
index 0000000..eb5f139
--- /dev/null
+++ b/src/AVSreadcpp.cc
@@ -0,0 +1,216 @@
+#include <stdio.h>
+#include <avs/avs.h>
+#include <avs/port.h>
+#include <avs/field.h>
+/* John's Includes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+/* Local Includes */
+#include <IO.hh>
+#include <IEEEIO.hh>
+#ifdef WITH_HDF
+#include <HDFIO.hh>
+#endif
+// #include <Reader.hh> // an even higher level interface, but must skip for now
+
+extern "C" {
+int readIEEE(AVSfield **out,char *Filename,int RecordNumber,
+ int SetExtents,char *SetCoordinates);
+}
+
+int readIEEE(AVSfield **out,char *Filename,int RecordNumber,
+ int SetExtents,char *SetCoordinates){
+ static IObase *infile=0;
+ // Handle case where Filename has changed
+ if(AVSparameter_changed("Filename") || !infile){
+ // Filename has changed, so close any currently open data files
+ // (this is done by delete'ing here.)
+ if(infile) delete infile;
+ infile=0;
+ // Just in case the new file is bogus, hide the dial widgets so
+ // that they can't be messed with if the data isn't valid.
+ AVSparameter_visible("RecordNumber",0);
+#ifdef WITH_HDF
+ if(strstr(strchr(Filename,','),"hdf"))
+ infile = new HDFIO(Filename,IObase::Read);
+ else
+#endif
+ infile = new IEEEIO(Filename,IObase::Read); // open the datafile
+
+ if(!infile->isValid()){ // if the file is not IEEEIO, exit
+ delete infile;
+ infile=0;
+ fprintf(stderr,"%s is not an IEEEIO file",Filename);
+ return 0;
+ }
+ if(infile->nDatasets()>1){// don't set widget dial for min=max=0
+ AVSmodify_parameter("RecordNumber",AVS_VALUE|AVS_MAXVAL,
+ 0,0,infile->nDatasets()-1);
+ AVSparameter_visible("RecordNumber",1);
+ } // so dial widget remains hidden if dataset contains 1 or fewer datasets
+ RecordNumber=0;
+ }
+ // Failsafe sanity check (things are really hosed if this check fails)
+ if(!infile) {
+ puts("Not an IEEEIO file");
+ AVSparameter_visible("RecordNumber",0);
+ return 0;
+ }
+
+ // now do memory allocation for AVS
+ char AllocationDescription[64];
+ char *typname;
+ IObase::DataType datatype;
+ int rank,dims[5];
+ int nelements;
+
+ infile->seek(RecordNumber); // seek to desired record
+ infile->readInfo(datatype,rank,dims); // get info about the dataset
+ // we are building the AVS memory description text string to do the allocation.
+ switch(datatype){
+ case IObase::Float32:
+ puts("Data Type float");
+ typname="float";
+ break;
+ case IObase::Float64:
+ puts("Data Type double");
+ typname="double";
+ break;
+ case IObase::Int32:
+ typname="integer";
+ break;
+ case IObase::uChar:
+ case IObase::Int8:
+ typname="byte";
+ break;
+ }
+
+ if(!strcmp("Set Edges",SetCoordinates))
+ sprintf(AllocationDescription,"field %uD %u-space scalar rectilinear %s",
+ rank,rank,typname); // put it all together into the allocation string
+ else
+ sprintf(AllocationDescription,"field %uD %u-space scalar uniform %s",
+ rank,rank,typname); // put it all together into the allocation string
+
+ //printf("AVS allocating %s\n",AllocationDescription);
+ //printf("With dims[0]=%d dims[1]=%d dims[2]=%d\n",dims[0],dims[1],dims[2]);
+ if(*out) AVSfield_free(*out); // free old memory if its still around
+ *out = (AVSfield *)AVSdata_alloc(AllocationDescription,dims); // and allocate!
+ if(!*out){
+ fprintf(stderr,"Allocation of %s failed\n",
+ AllocationDescription);
+ return 0; // allocation failed
+ }
+
+ /*---
+ Note: So if this read doesn't work, you'll need to use a switch statement
+ with exact casts to the proper datatypes.
+ I skipped using the switch statement because it looks really stupid
+ but its necessary for some machines which align vectors
+ differently depending on the size of the type the vector
+ points to. (yes folks... this is what the "align" keyword is about)
+ Hopefully we won't use such poorly designed machines.
+
+ This need not be done for the parameters though since that field
+ of the avsfld is always float.
+ ---*/
+ AVSfield_float *fld=(AVSfield_float*)(*out);
+ puts("Preparing to read data");
+ infile->read(fld->data); // read the data
+ puts("read data");
+ int minindex,maxindex;
+ /*---
+ In this section we are just setting the extents and edge points information
+ for AVS (the physical size of the dataset in floating point coordinates).
+ There are just two Attribute pairs that it will recognize to do this.
+
+ 1) min_ext,max_ext
+ These are vectors of size <rank of dataset> which contain the
+ coordinates of the minimum and maximum corners of the bounding box.
+ 2) origin,delta
+ The GR people seem to like this. Its the origin (same as the min_ext)
+ of the dataset and then the delta (or "dx") between grid points in the
+ dataset.
+
+ It is now able to handle these parameters as Float32 or Float64 data.
+ Integer is ignored. The dataset will simply be ranged from 0-dim[x]
+ if the above Attributes are not found.
+ ---*/
+ {
+ float min_ext[5],max_ext[5];
+
+ if((minindex=infile->readAttributeInfo("min_ext",datatype,nelements))>0 &&
+ (maxindex=infile->readAttributeInfo("max_ext",datatype,nelements))>0 &&
+ (datatype==IObase::Float32 || datatype==IObase::Float64)) {
+ if(datatype==IObase::Float32){
+ infile->readAttribute(maxindex,min_ext);
+ infile->readAttribute(minindex,max_ext);
+ }
+ else if(datatype==IObase::Float64){
+ double maxext[5],minext[5];
+ infile->readAttribute(maxindex,maxext);
+ infile->readAttribute(minindex,minext);
+ for(int i=0;i<rank;i++){
+ min_ext[i]=(float)(minext[i]);
+ max_ext[i]=(float)(maxext[i]);
+ }
+ }
+
+ } //***** OK, if we cant find extents, then try origin & delta
+ else if((minindex=infile->readAttributeInfo("origin",datatype,nelements))>0 &&
+ (maxindex=infile->readAttributeInfo("delta",datatype,nelements))>0 &&
+ (datatype==IObase::Float32 || datatype==IObase::Float64)) {
+ if(datatype==IObase::Float32){
+ infile->readAttribute(maxindex,fld->min_extent);
+ infile->readAttribute(minindex,fld->max_extent);
+ for(int i=0;i<rank;i++){
+ max_ext[i]*=(float)dims[i];
+ max_ext[i]+=min_ext[i];
+ }
+ }
+ else if(datatype==IObase::Float64){
+ double maxext[5],minext[5];
+ infile->readAttribute(maxindex,maxext);
+ infile->readAttribute(minindex,minext);
+ for(int i=0;i<rank;i++){
+ maxext[i]*=(double)dims[i];
+ maxext[i]+=minext[i];
+ min_ext[i]=(float)(minext[i]);
+ max_ext[i]=(float)(maxext[i]);
+ }
+ }
+ }
+ else { // No information about edges.
+ for(int i=0;i<rank;i++){
+ min_ext[i]=0.0;
+ max_ext[i]=(float)(dims[i]-1);
+ }
+ }
+ if(SetExtents){
+ for(int i=0;i<rank;i++){
+ fld->min_extent[i]=min_ext[i];
+ fld->max_extent[i]=max_ext[i];
+ }
+ }
+ if(!strcmp("Set Min/Max",SetCoordinates)){
+ for(int i=0;i<rank;i++){
+ fld->points[i*2]=min_ext[i];
+ fld->points[i*2 + 1]=max_ext[i];
+ }
+ }
+ else if(!strcmp("Set Edges",SetCoordinates)){
+ for(int index=0,i=0;i<rank;i++){
+ double dx = (max_ext[i]-min_ext[i])/((float)(fld->dimensions[i]));
+ printf("SetEdges[%u]: dx=%lf\n",i,dx);
+ for(int j=0;j<fld->dimensions[i];j++,index++){
+ fld->points[index] = min_ext[i] + ((double)j)*dx;
+ }
+ }
+ }
+ }
+ return 1; // for now
+}
+
+
diff --git a/src/AmrFileReader.cc b/src/AmrFileReader.cc
new file mode 100644
index 0000000..6047ce0
--- /dev/null
+++ b/src/AmrFileReader.cc
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "AmrFileReader.hh"
+#include "FlexArrayTmpl.H"
+void AmrFileReader::printGridInfo(AmrGrid &g){
+ printf("Grid level=%u step=%u maxtime=%u\n",g.level,g.timestep,g.maxtime);
+ printf("\trank=%u dims[",g.rank);
+ for(int i=0;i<g.rank-1;i++) printf("%u,",g.dims[i]);
+ printf("%u]\n",g.dims[g.rank-1]);
+ printf("\tTimerefine=%u dx[0]=%lf origin[",g.timerefinement,g.delta[0]);
+ {for(int i=0;i<g.rank-1;i++) printf("%lf,",g.origin[i]);}
+ printf("%lf]\n",g.origin[g.rank-1]);
+ printf("\tData Pointer is %u\n",(unsigned long)(g.data));
+ if(g.data){
+ float *fdata = (float *)(g.data);
+ for(int i=0;i<3;i++)
+ printf("\t\tData[%u]=%f\n",i,fdata[i]);
+ }
+ }
+ void AmrFileReader::printGridInfo(){
+ // print it all out...
+ printf("MaxLevel=%u\n",maxlevel);
+ for(int i=0;i<grids.getSize();i++){
+ printf("Grid[%u]--------------------\n",i);
+ printGridInfo(grids[i]);
+ }
+ }
+ void AmrFileReader::printActiveGrids(){
+ // print it all out...
+ printf("Num Active Grids=%u\n",activeGrids.getSize());
+ for(int i = 0; i < activeGrids.getSize(); i++){
+ printf(" Grid[%u] mapped from %u --------------------\n",
+ i,activeGrids[i]);
+ printGridInfo(grids[activeGrids[i]]);
+ }
+ }
+
+void AmrFileReader::buildInfoTable(){
+ // Load all grids Info
+ int index=0;
+ AmrGrid g;
+ while(gridreader.getGridInfo(g,index++)){
+ if(this->debug) printf("buildInfoTable: getGrid index=%u\n",index);
+ if(this->debug) printGridInfo(g);
+ int i=grids.getSize();
+ g.data=0; // zero out the data
+ grids.append(g);
+ if(g.level>maxlevel)
+ maxlevel=g.level;
+ if(!i){
+ mintime = g.timestep;
+ maxtime = g.timestep;
+ maxtimeres = g.timerefinement;
+ maxlevel= g.level;
+ }
+ if(g.timestep<mintime)
+ mintime=g.timestep;
+ if(g.timestep>maxtime)
+ maxtime=g.timestep;
+ if(g.timerefinement>maxtimeres)
+ maxtimeres=g.timerefinement;
+ }
+}
+
+void AmrFileReader::loadGrids(){
+ if(!gridloading) return;
+ for(int i=0;i<activeGrids.getSize();i++){
+ if(this->debug) printf("buildInfoTable: getGrid index=%u activegridindex %u\n",i,activeGrids[i]);
+ if(this->debug) printGridInfo(grids[activeGrids[i]]);
+ gridreader.getGridData(grids[activeGrids[i]],activeGrids[i]);
+ }
+}
+
+void AmrFileReader::reclaimGrids(){
+ if(!gridloading) return;
+ for(int i=0;i<grids.getSize();i++){
+ int f=0;
+ for(int j=0;j<activeGrids.getSize();j++){
+ if(activeGrids[j]==i){
+ f=1;
+ break;
+ }
+ }
+ if(!f){
+ free((grids[i]).data);
+ (grids[i]).data=0;
+ }
+ }
+}
+
+void AmrFileReader::purgeGrids(){
+ for(int i=0;i<grids.getSize();i++){
+ if((grids[i]).data)
+ free((grids[i]).data);
+ (grids[i]).data=0;
+ }
+}
+
+AmrFileReader::AmrFileReader(IObase &f):gridreader(f),debug(0),gridloading(1){
+ // we need to build a table from the file
+ // then select grids based on the timestep
+ buildInfoTable(); // initialize the convertor
+ levelmask.setSize(maxlevel+1);
+ for(int i=0;i<=maxlevel;i++)
+ levelmask[i]=1; // all levels visible is default
+ showAllLevels();
+ setTime(mintime);
+}
+
+void AmrFileReader::setTime(int timestep){
+ // Make Grid Selections
+ if(timestep<mintime || timestep>maxtime){
+ printf("timestep %u is out of range %u:%u\n",
+ timestep,mintime,maxtime);
+ return;
+ }
+ activeGrids.purge();
+ current_time=timestep;
+ if(this->debug) printf("setTime(%u): mintime=%u maxtime=%u\n",current_time,mintime,maxtime);
+ for(int i=0;i<grids.getSize();i++){
+ if(this->debug) printf("\tgrids[%u].timestep=%u maxtime=%u\n",i,grids[i].timestep,
+ grids[i].maxtime);
+ if(current_time>=grids[i].timestep &&
+ current_time<grids[i].maxtime && levelmask[grids[i].level]){
+ activeGrids.append(i);
+ if(this->debug) printf("\t\tAppendGrid number %u\n",i);
+ }
+ }
+ if(this->debug) puts("load grids");
+ loadGrids();
+ if(this->debug) puts("reclaim grids");
+ reclaimGrids();
+}
+
+void AmrFileReader::showAllLevels(){
+ for(int i=0;i<levelmask.getSize();i++) levelmask[i]=1;
+}
+
+// For C interface
+
+int AmrFileReader::getGrids(AmrGrid *g){ // assumes number of
+ for(int i=0;i<activeGrids.getSize();i++)
+ g[i]=grids[activeGrids[i]];
+ return activeGrids.getSize();
+}
+
+// For C++ interface
+int AmrFileReader::getGrids(FlexArray<AmrGrid> &g){
+ g.setSize(activeGrids.getSize());
+ for(int i=0;i<activeGrids.getSize();i++)
+ g[i]=grids[activeGrids[i]];
+ return activeGrids.getSize();
+}
diff --git a/src/AmrFileReader.hh b/src/AmrFileReader.hh
new file mode 100644
index 0000000..a771ca7
--- /dev/null
+++ b/src/AmrFileReader.hh
@@ -0,0 +1,69 @@
+// AmrFileReader
+#ifndef __AMRFILEREADER_HH_
+#define __AMRFILEREADER_HH_
+#include <stdio.h>
+#include <IO.hh>
+#include "AmrGridReader.hh"
+#include "FlexArrayTmpl.H"
+
+class AmrFileReader {
+protected:
+ int gridloading;
+ AmrGridReader gridreader;
+ FlexArray<int> activeGrids;
+ FlexArray<AmrGrid> grids; // perhaps use a hashtable to find grids?
+ // Change to AmrGridFile structures
+ FlexArray<int> levelmask;
+ IObase::DataType datatype;
+ int maxlevel,maxtimeres,mintime,maxtime;
+ int current_time;
+ // Internal Utility methods
+ void buildInfoTable();
+ void loadGrids();
+ void reclaimGrids();
+ void purgeGrids();
+ void printGridInfo(AmrGrid &g);
+public:
+ int debug;
+ void printGridInfo();
+ void printActiveGrids();
+ AmrFileReader(IObase &f);
+ int getActiveIndex(int ii){ return activeGrids[ii];}
+ int getNumLevels(){ return maxlevel+1; }
+ void getTimeRange(int &min,int &max){
+ min=mintime;
+ max=maxtime;
+ }
+ void setTime(int timestep);
+ // starts out with all selected
+ void showLevel(int level=-1){ // default is all (-1)
+ if(level>=levelmask.getSize() || level<0){
+ printf("AmrConvert::showLevel(%u) : Level out of range 0:%u\n",
+ level,levelmask.getSize()-1);
+ }
+ else
+ levelmask[level]=1;
+ }
+ void showAllLevels();
+ void hideLevel(int level=-1){ // default is all (-1)
+ if(level>=levelmask.getSize() || level<0){
+ printf("AmrConvert::showLevel(%u) : Level out of range 0:%u\n",
+ level,levelmask.getSize()-1);
+ }
+ else
+ levelmask[level]=0;
+ }
+ int nLevels(){ return maxlevel+1; }
+ IObase::DataType getDataType(){return datatype;}
+ // For C interface
+ int getNumGrids(){ // number of active grids
+ return activeGrids.getSize();
+ }
+ int getGrids(AmrGrid *g);
+ // For C++ interface
+ int getGrids(FlexArray<AmrGrid> &g);
+ void setDataLoadingOff(){ gridloading=0; purgeGrids();}
+ void setDataLoadingOn(){ gridloading=1; loadGrids();}
+};
+
+#endif
diff --git a/src/AmrGrid.h b/src/AmrGrid.h
new file mode 100644
index 0000000..cfa411f
--- /dev/null
+++ b/src/AmrGrid.h
@@ -0,0 +1,24 @@
+#ifndef __AMR_GRID_H_
+#define __AMR_GRID_H_
+/*
+ Definition of the AMR grid structure for C
+ Defined so that the structure will be flat.
+*/
+typedef struct AmrGrid {
+ int level;
+ int maxlevel;
+ int maxtime,timestep,persistence; /* at finest-level timestep */
+ int rank,dims[3]; /* hardcode to 3D maximum dims */
+ double delta[3],origin[3]; /* stored in file as delta and origin */
+ //
+ double minext[3],maxext[3];
+ int timerefinement,spatialrefinement[3];
+ int nbytes;
+ int dataveclen;
+ int datatype;
+ int iorigin[3];
+ int gridplacementrefinement[3];
+ void *data;
+} AmrGrid;
+
+#endif
diff --git a/src/AmrGrid.hh b/src/AmrGrid.hh
new file mode 100644
index 0000000..b29ec63
--- /dev/null
+++ b/src/AmrGrid.hh
@@ -0,0 +1,11 @@
+#ifndef __AMR_GRID_HH_
+#define __AMR_GRID_HH_
+/*
+ Definition of the AMR grid structure for C
+*/
+
+struct AmrGrid : public AmrGridT {
+ IObase::DataType datatype;
+};
+
+#endif
diff --git a/src/AmrGridReader.cc b/src/AmrGridReader.cc
new file mode 100644
index 0000000..3ea8f90
--- /dev/null
+++ b/src/AmrGridReader.cc
@@ -0,0 +1,87 @@
+// AmrGridReader
+#include "AmrGridReader.hh"
+#include <stdio.h>
+#include <stdlib.h>
+
+// Other stuff
+AmrGrid *AmrGridReader::getGridInfo(AmrGrid &g,int index){
+ g.dataveclen=1;
+ if(file.seek(index)<index)
+ return 0; // fail if index past end
+ IObase::DataType dt;
+ file.readInfo(dt,g.rank,g.dims);
+ g.datatype = dt;
+ g.nbytes = IObase::nBytes(dt,g.rank,g.dims);
+ // find the deepest level (finest time resolution)
+ // Attrib Names?
+ IObase::DataType atype;
+ int length;
+ int attrnum=file.readAttributeInfo("level",atype,length);
+ if(attrnum>=0){
+ int lev; // should be Int level
+ file.readAttribute(attrnum,&lev);
+ if(lev>g.maxlevel) g.maxlevel=lev;
+ g.level=lev;
+ }
+ // check for existence of attribute named "time_refinement"
+ attrnum=file.readAttributeInfo("time_refinement",atype,length);
+ // "time_refinement" exists, so lets read it into the member g.timerefinement
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.timerefinement));
+ }
+ // check for existence of the attribute named "spatial_refinement"
+ attrnum=file.readAttributeInfo("spatial_refinement",atype,length);
+ // it exists, so lets read it into the datastruct member g.spatialrefinement
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.spatialrefinement));
+ }
+
+ attrnum=file.readAttributeInfo("timestep",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.timestep));
+ }
+
+ attrnum=file.readAttributeInfo("origin",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,(g.origin));
+
+ attrnum=file.readAttributeInfo("delta",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,(g.delta));
+
+ attrnum=file.readAttributeInfo("min_ext",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,(g.minext));
+
+ attrnum=file.readAttributeInfo("max_ext",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,(g.maxext));
+
+ attrnum=file.readAttributeInfo("persistence",atype,length);
+ if(attrnum>=0){
+ file.readAttribute(attrnum,&(g.persistence));
+ g.maxtime = g.timestep + g.persistence;
+ }
+
+ attrnum=file.readAttributeInfo("iorigin",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,&(g.iorigin));
+
+ attrnum=file.readAttributeInfo("grid_placement_refinement",atype,length);
+ if(attrnum>=0)
+ file.readAttribute(attrnum,&(g.gridplacementrefinement));
+
+ g.data=0;
+ return &g;
+} // done
+
+AmrGrid *AmrGridReader::getGridData(AmrGrid &g,int index){
+ IObase::DataType atype;
+ // if(data) free(data); data=0; // make certain it is empty first
+ g.data = malloc(g.nbytes);
+ file.seek(index);
+ file.readInfo(atype,g.rank,g.dims);
+ g.datatype=atype;
+ file.read(g.data);
+ return &g;
+}
diff --git a/src/AmrGridReader.hh b/src/AmrGridReader.hh
new file mode 100644
index 0000000..4c7e84c
--- /dev/null
+++ b/src/AmrGridReader.hh
@@ -0,0 +1,29 @@
+#ifndef __AMRGRIDREADER_HH_
+#define __AMRGRIDREADER_HH_
+
+#include <IO.hh>
+#include "AmrGrid.h"
+
+class AmrGridReader {
+ IObase &file;
+public:
+ AmrGridReader(IObase &f):file(f){}
+ // get specific grid
+ AmrGrid *getGrid(AmrGrid &g,int index){
+ if(file.seek(index)<index)
+ return 0; // don't load past end
+ getGridInfo(g,index);
+ getGridData(g,index);
+ return &g;
+ }
+ AmrGrid *getGrid(int index){
+ AmrGrid *g=new AmrGrid;
+ return this->getGrid(*g,index);
+ }
+ // Other stuff
+ AmrGrid *getGridInfo(AmrGrid &g,int index);
+ AmrGrid *getGridData(AmrGrid &g,int index);
+};
+
+
+#endif // __AMRGRIDREADER_HH_
diff --git a/src/AmrNode.hh b/src/AmrNode.hh
new file mode 100644
index 0000000..9765939
--- /dev/null
+++ b/src/AmrNode.hh
@@ -0,0 +1,42 @@
+#ifndef __AMRNODE_HH_
+#define __AMRNODE_HH_
+
+//#include "config.h"
+#include "Bounds.hh"
+#include <IO.hh>
+
+struct sPoint { double x,y,z; };
+union pPoint {
+ double array[3];
+ sPoint cartesian;
+};
+
+struct AmrNode {
+ pPoint location;
+ struct AmrNode *parent,*child;
+ int index;
+ int gridID;
+ int level;
+ float *data;
+ /*
+ IObase::DataType datatype;
+ union {
+ void *vdata;
+ float *fdata;
+ double *ddata;
+ int *idata;
+ char *cdata;
+ short *sdata;
+ }; */
+ // DATATYPE data;
+ // my local ref to data...
+ // The grid is going to need the smarts to assign this...
+ // So data segment length is important.
+ // Or we need a struct with a copy operator
+ void setIndex(int i){
+ index=i;
+ if(parent) parent->setIndex(i);
+ }
+};
+
+#endif
diff --git a/src/AmrUcd.c b/src/AmrUcd.c
new file mode 100644
index 0000000..b8067c6
--- /dev/null
+++ b/src/AmrUcd.c
@@ -0,0 +1,70 @@
+/* *****************************************/
+/* Includes and Global Defs */
+/* *****************************************/
+#include <stdio.h>
+#include <math.h>
+/* IAC CODE CHANGE : #include <math.h> */
+#include <avs/avs_math.h>
+
+#include <avs/avs.h>
+#include <avs/port.h>
+#include <avs/field.h>
+#include <avs/ucd_defs.h>
+#include <stdlib.h>
+#include <string.h>
+/*#include "sds.h"*/
+
+typedef union Coord {
+ struct {
+ int x,y,z;
+ } axis;
+ int vect[3];
+} Coord;
+
+int debug=0;
+
+int amrucd_desc (){
+ int in_port, out_port, param, iresult;
+ extern int amrucd_compute();
+ extern int amrucd_destroy();
+ /*extern int amrucd_destroy();*/
+
+ AVSset_module_name("AMR-UCD Reader", MODULE_DATA);
+
+ /* Output Port Specifications */
+ out_port = AVScreate_output_port("Output", "ucd" );
+ /* out_port = AVScreate_output_port("output","field uniform");*/
+ /* Parameter Specifications */
+
+
+ param = AVSadd_parameter("Filename", "string", "", "", ":");
+ AVSconnect_widget(param, "browser");
+
+ param = AVSadd_parameter("Hold","boolean",0,0,1);
+ AVSconnect_widget(param,"toggle");
+
+ param = AVSadd_parameter("Threshold","boolean",1,0,1);
+ AVSconnect_widget(param,"toggle");
+
+ param = AVSadd_parameter("Generate Level Data","boolean",1,0,1);
+ AVSconnect_widget(param,"toggle");
+
+ param = AVSadd_parameter("Step", "integer", 0, 0, 1);
+ AVSconnect_widget(param, "idial");
+
+ param = AVSadd_float_parameter("Min",0.0,FLOAT_UNBOUND,FLOAT_UNBOUND);
+ param = AVSadd_float_parameter("Max",1.0,FLOAT_UNBOUND,FLOAT_UNBOUND);
+
+ param = AVSadd_parameter("VisibleLevels","choice","<no data>","<no data>",":");
+ AVSconnect_widget(param,"choice");
+
+ AVSset_compute_proc(amrucd_compute);
+ AVSset_destroy_proc(amrucd_destroy);
+
+ return 1;
+}
+
+AVSinit_modules()
+{
+ AVSmodule_from_desc (amrucd_desc);
+}
diff --git a/src/AmrUcdCompute.cc b/src/AmrUcdCompute.cc
new file mode 100644
index 0000000..6eae19c
--- /dev/null
+++ b/src/AmrUcdCompute.cc
@@ -0,0 +1,454 @@
+/* *****************************************/
+/* Includes and Global Defs */
+/* *****************************************/
+#include <stdio.h>
+#include <math.h>
+#include <avs/avs_math.h>
+
+#include <avs/avs.h>
+#include <avs/port.h>
+#include <avs/field.h>
+#include <avs/ucd_defs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucd_defs.h>
+
+// #include "config.h"
+#include "FlexArrayTmpl.H"
+#include <IEEEIO.hh>
+#include "AmrNode.hh"
+// #include "AmrConvert.hh"
+#include "AmrUcdFileReader.hh"
+void DumpUCD(UCD_structure *u);
+
+extern "C"
+{
+ int amrucd_compute(UCD_structure **Output,char *Filename,int Hold,int Threshold,
+ int GenerateLevelData, int Step,float *Min,float *Max,
+ char *VisibleLevels);
+ void amrucd_destroy();
+}
+
+void amrucd_destroy(){
+ puts("Destroyed AmrUcd"); // erase UCD datastructures?
+}
+
+void GenerateFakeUCD(int Step,FlexArray<AmrNode *> &nodes,FlexArray<int> &cells){
+ float data[128];
+ int i,index;
+
+ //********* Generate some fake data (nsds quads in the z direction)
+ for(i=0;i<128;i++) data[i]=(float)i;
+ for(index=index=i=0;i<Step+2;i++){
+ int z = i;
+ for(int y=0;y<2;y++){
+ for(int x=0;x<2;x++,index++){
+ AmrNode *node=new AmrNode;
+ node->location.cartesian.x=(float)x;
+ node->location.cartesian.y=(float)y;
+ node->location.cartesian.z=-(float)z;
+ node->data = data+index;
+ node->index=index;
+ nodes.append(node);
+ }
+ }
+ }
+ for(index=i=0;i<Step+1;i++){
+ int connectmap[4]={0,1,3,2};
+ for(int y=0;y<4;y++){
+ cells.append(connectmap[y]+index);
+ }
+ index+=4;
+ for(y=0;y<4;y++){
+ cells.append(connectmap[y]+index);
+ }
+ }
+ printf("Ncellentries = %u /8 = %u: nnodes=%u /4 = %u\n",
+ cells.getSize(),cells.getSize()/8,nodes.getSize(), nodes.getSize()/4);
+ /*
+ for(i=0;i<nodes.getSize();i++){
+ printf("node[%3u]: %f:%f:%f\n",i,
+ (nodes[i])->location.cartesian.x,
+ (nodes[i])->location.cartesian.y,
+ (nodes[i])->location.cartesian.z);
+ }
+ for(i=0;i<cells.getSize();i++){
+ if(!(i%8)) printf("\ncell[%3u]:",i);
+ printf("%2u,",cells[i]);
+ //if(!((i+1)%8)) puts("");
+ }
+ */
+ puts("");
+}
+
+int amrucd_compute (UCD_structure **Output,char *Filename,int Hold,int Threshold,
+ int GenerateLevelData, int Step,float *Min,float *Max,
+ char *VisibleLevels){
+ static IObase *datafile; // Need Global Delete
+ static AmrUcdFileReader *convertor; // Need Global Delete
+ static FlexArray<char> VisibleLevelString;
+ // must be pointers to nodes because some are possibly shared...
+ FlexArray<AmrNode *> nodes; // the nodes with their data values
+ FlexArray<int> cells; // connectivity between the nodes
+ //AVSfield *GenerateFakeData();
+ //AVSfield *ReadHDF();
+ UCD_structure *ConvertToUCD(FlexArray<AmrNode*> &,FlexArray<int> &,int);
+ if(AVSparameter_changed("Filename")){
+ int mintime,maxtime;
+ IObase *newfile = new IEEEIO(Filename,IObase::Read);
+ if(!newfile->isValid()){
+ printf("AmrUcd: Error opening datafile %s\n",Filename);
+ delete newfile;
+ return 0;
+ }
+ if(datafile) delete datafile;
+ datafile=newfile; // make current file
+ if(convertor) delete convertor;
+ convertor = new AmrUcdFileReader(*datafile);
+ // convertor->printGridInfo();
+ convertor->getTimeRange(mintime,maxtime);
+ if((maxtime-mintime)<=1){
+ AVSmodify_parameter("Step",AVS_VALUE|AVS_MINVAL|AVS_MAXVAL,mintime,mintime,maxtime+1);
+ AVSparameter_visible("Step",0);
+ }
+ else {
+ AVSmodify_parameter("Step",AVS_MINVAL|AVS_MAXVAL|AVS_VALUE,mintime,mintime,maxtime);
+ AVSparameter_visible("Step",1);
+ }
+ Step=mintime;
+
+ // Now setup the VisibleLevelString
+ if(VisibleLevelString.getSize()>0)
+ VisibleLevelString.purge();
+ for(int i=0;i<convertor->nLevels();i++){
+ char buffer[12];
+ sprintf(buffer,"*Level %2u:",i);
+
+ // Only display first 3 levels
+ if(i>=3) {
+ *buffer='.';
+ convertor->hideLevel(i);
+ }
+
+ buffer[10]='\0';
+ VisibleLevelString.append(buffer,10);
+ }
+ VisibleLevelString[convertor->nLevels()*10 - 1]='\0'; // cap the string off
+ // Now assign the string for the choice widget
+ AVSmodify_parameter("VisibleLevels",AVS_MINVAL|AVS_MAXVAL|AVS_VALUE,
+ "*Level 0",VisibleLevelString.getData(),":");
+ }
+ if(!datafile || !convertor){
+ puts("No valid datafile or convertor exists. No action taken.");
+ return 0;
+ }
+
+ if(AVSparameter_changed("VisibleLevels")){
+ int choicenum = AVSchoice_number("VisibleLevels",VisibleLevels) - 1;
+ if(choicenum>=0){
+ if(VisibleLevelString[choicenum*10]=='*'){ // toggle off
+ VisibleLevelString[choicenum*10]='.';
+ convertor->hideLevel(choicenum);
+ }
+ else {
+ VisibleLevelString[choicenum*10]='*';
+ convertor->showLevel(choicenum);
+ }
+ AVSmodify_parameter("VisibleLevels",AVS_VALUE|AVS_MINVAL|AVS_MAXVAL,
+ VisibleLevels,VisibleLevelString.getData(),":");
+ }
+ }
+ if(Hold) return 0; // no change as of yet
+ // GenerateFakeUCD(Step,nodes,cells);
+ if(*Output){
+ puts("FREE UCD");
+ DumpUCD(*Output);
+ UCDstructure_free(*Output);
+ }
+ // *Output=NULL;
+ convertor->setTime(Step);
+ convertor->getUcd(nodes,cells);
+ *Output=ConvertToUCD(nodes,cells,GenerateLevelData); // final gen of output
+ if(!*Output) return 0;
+ // Now if thresholding is there
+ if(Threshold){
+ int idx;
+ if(GenerateLevelData) idx=1;
+ else idx=0;
+ (*Output)->min_node_data[idx]=*Min;
+ (*Output)->max_node_data[idx]=*Max;
+ for(int n=0;n<(*Output)->node_veclen;n++){
+ printf("Component[%u] min/max data=%f:%f\n",
+ n,(*Output)->min_node_data[n],(*Output)->max_node_data[n]);
+ }
+ }
+ //for(int i=0;i<nodes.getSize();i++) {delete nodes[i]; nodes[i]=0;}
+ return 1;
+}
+
+UCD_structure *ConvertToUCD(FlexArray<AmrNode*> &nodes,FlexArray<int> &cells,
+ int GenerateLevelData){
+ int i,j,k;
+ int util_flag,ucd_flags;/* define which components will be availible in structure */
+ int num_cells,num_nodes;
+ char model_name[65];
+ int cell_tsize, node_csize;
+ int num_model_data, num_cell_data, num_node_data;
+ int node_comp_list[10], num_node_comp,nodelist[8],active_node_list[10];
+ float min_ext[3],max_ext[3],node_data_max[10],node_data_min[10],*xc,*yc,*zc;
+ int cell,node;
+ UCD_structure *output;
+
+ printf("Convert to UCD\n");
+ strcpy(model_name,"AMRUCD model");
+ /*********************************/
+ /* establish the UCD structure */
+ /*********************************/
+ /* Options: UCD_INT | UCD_MATERIAL_IDS | UCD_NODE_NAMES
+ | UCD_CELL_NAMES | UCD_CELL_TYPES */
+ ucd_flags = UCD_INT;
+ num_cells = cells.getSize()/8;
+ num_nodes = nodes.getSize();
+ printf("So numcells=%u and numnodes=%u\n",num_cells,num_nodes);
+ /* node connectivity, and only scalar nodal data */
+ num_model_data = 0;
+ num_cell_data = 0; /* scalar cell data */
+ util_flag = 0; /* no cell-edge connectivity */
+
+ /* or should it be total size */
+ cell_tsize = num_cells*8; // This is tested to be correct (will warn)
+ node_csize = 0; // no node connectivity
+ if(GenerateLevelData){
+ num_node_data = 2; /* how much ??? */
+ node_comp_list[0]=1;
+ node_comp_list[1]=1;
+ num_node_comp = 2; /* no nodal data */
+ }
+ else{
+ num_node_data = 1; /* how much ??? */
+ node_comp_list[0]=1;
+ node_comp_list[1]=0;
+ num_node_comp = 1;
+ }
+
+ printf("Allocate UCD structure\n");
+ printf("Params:\n\tmodel_name: %s\n\t\
+num_model_data: %u\n\t\
+ucd_flags: %u\n\t\
+num_cells: %u\n\t\
+cell_tsize: %u\n\t\
+num_cell_data: %u\n\t\
+num_nodes: %u\n\t\
+node_csize: %u\n\t\
+num_node_data: %u\n\t\
+util_flag: %u\n",model_name,
+ num_model_data,
+ ucd_flags,
+ num_cells,
+ cell_tsize,
+ num_cell_data,
+ num_nodes,
+ node_csize,
+ // num_node_data,
+ num_node_comp,
+ util_flag);
+
+ output = (UCD_structure *)UCDstructure_alloc (model_name,
+ num_model_data,
+ ucd_flags,
+ num_cells,
+ cell_tsize,
+ num_cell_data,
+ num_nodes,
+ node_csize,
+ num_node_data,
+ util_flag);
+ DumpUCD(output);
+ if(!output){
+ puts("AmrUcdCompute: UCD structure Allocation Failed!!!!");
+ return 0;
+ }
+ // printf("Address of struct is %u\n",(unsigned)output);
+ // should copy directly
+ xc = new float[num_nodes];
+ yc = new float[num_nodes];
+ zc = new float[num_nodes];
+ puts("Set Node connectivity and coords");
+ for(i=0;i<3;i++)
+ min_ext[i]=max_ext[i]=(nodes[0])->location.array[i];
+
+ for(node=0;node < nodes.getSize();node++){
+ float x,y,z;
+ int clist[8]={0,0,0,0,0,0,0,0};
+ AmrNode *n=nodes[node];
+ xc[node]=x=n->location.cartesian.x;
+ if(x<min_ext[0]) min_ext[0]=x;
+ if(x>max_ext[0]) max_ext[0]=x;
+ yc[node]=y=n->location.cartesian.y;
+ if(y<min_ext[1]) min_ext[1]=y;
+ if(y>max_ext[1]) max_ext[1]=y;
+ zc[node]=z=n->location.cartesian.z;
+ if(z<min_ext[2]) min_ext[2]=z;
+ if(z>max_ext[2]) max_ext[2]=z;
+ // was (char *) node+1
+ if(!UCDnode_set_information(output,node,(char *)(node+1),0,clist)){
+ puts("Error setting node information!!!!");
+ }
+ }
+ printf("need to store %u positions\n",node);
+ printf("set positions in 3-space minext=%f:%f:%f\tmaxext=%f:%f:%f\n",
+ min_ext[0],min_ext[1],min_ext[2],
+ max_ext[0],max_ext[1],max_ext[2]);
+ //for(i=0;i<3;i++) min_ext[i]=max_ext[i]=0.0;
+ if(!UCDstructure_set_node_positions(output,xc,yc,zc)){
+ puts("Error setting node positions!!!!");
+ }
+ //printf("Now free the pointers");
+ //for(i=0;i<nodes.getSize();i++)
+ // xc[i]=yc[i]=zc[i]=0;
+ delete xc;
+ delete yc;
+ delete zc;
+ puts("Set Extents");
+ printf("Set Extents-> %u\n",
+ UCDstructure_set_extent(output,min_ext,max_ext));
+ /* now cell topology */
+ puts("Set cell connectivity");
+ int cellidx;
+ for(cell=cellidx=0;cell<cells.getSize();cell+=8,cellidx++){
+ int nodelist[8];
+ for(i=0;i<8;i++) nodelist[i]=cells[cell+i]; // superfluous copy
+ UCDcell_set_information(output,cellidx,
+ // (char *)(cellidx+1),"hex", // was (char *)(cellidx+1)
+ (char*)cellidx,"hex",
+ 1/*material ID*/,
+ UCD_HEXAHEDRON,
+ 0/*no mid-edged nodes*/,
+ nodelist);
+ if(cellidx>=num_cells || cell>=cells.getSize()) puts("Error!!!! Too many Cells");
+ }
+ puts("now set the data");
+ /* Order of operations
+ for each node position
+ UCDnode_set_information(*output,nodenumber,nodenumber+1,*/
+ /* Now Set the node/vertex data */
+ /* nodedata is in the field */
+ printf("set node Data numcomp=%u compsize=%u:%u\n",
+ num_node_comp,node_comp_list[0],node_comp_list[1]);
+ UCDstructure_set_node_components(output,node_comp_list,num_node_comp);
+
+ // Just manually set stuff in the data structure
+ printf("util_flag=%u\n",output->util_flag);
+ printf("max_ext[2]=%u\n",output->max_extent[2]);
+
+ active_node_list[0]=1; active_node_list[1]=0;
+ UCDstructure_set_node_active(output,active_node_list);
+ int dataindex;
+ if(GenerateLevelData){
+ UCDstructure_set_node_labels(output,"level.data",".");
+ node_data_min[0]=node_data_max[0]=(float)((nodes[0])->level);
+ node_data_min[1]=node_data_max[1]=(float)((nodes[0])->data[0]);
+ dataindex=1;
+ }
+ else {
+ UCDstructure_set_node_labels(output,"data",".");
+ //node_data_min[0]=node_data_max[0]=(float)((nodes[0])->level);
+ node_data_min[0]=node_data_max[0]=(float)((nodes[0])->data[0]);
+ dataindex=0;
+ }
+ // KLUDGE!!! Possibly redundant malloc
+
+ float *node_data = new float[nodes.getSize()*num_node_data];
+ // Crash!!
+ printf("Num Node Data= %u floats\n",nodes.getSize());
+ int index=0;
+ // Colorize by GridID??? wah?
+ if(GenerateLevelData){
+ for(i=0,index=0;i<nodes.getSize();i++,index++){
+ float val = (float)((nodes[i])->level); // need level later!!!
+ // printf("index[%u] valI=%u val=%f\n",i,nodes[i]->gridID,val);
+ if(node_data_max[0]<val) node_data_max[0]=val;
+ if(node_data_min[0]>val) node_data_min[0]=val;
+ if(val>6) printf("index[%u] valI=%u val=%f\n",i,nodes[i]->gridID,val);
+ node_data[index]=val;
+ } // Crash here
+ printf("node_data_max[0]=%f node_data_min[0]=%f\n",node_data_max[0],node_data_min[0]);
+ puts("done setting levelinfo");
+ }
+
+ for(i=0;i<nodes.getSize();i++,index++){
+ float *valptr = (nodes[i])->data;
+ //printf("DataPtr[%u]=%lu val=%f\r",i,valptr,*valptr);
+ float val = *valptr;
+ if(node_data_max[dataindex]<val) node_data_max[dataindex]=val;
+ if(node_data_min[dataindex]>val) node_data_min[dataindex]=val;
+ node_data[index]=val;
+ }
+ puts("\nset node data");
+ printf("UCDstructure_set_node_data->%u\n",
+ UCDstructure_set_node_data(output,node_data));
+
+ printf("After set node data util_flag=%u\n",output->util_flag);
+ printf("max_ext[2]=%u\n",output->max_extent[2]);
+
+ printf("UCDstructure_set_node_minmax->%u\n",
+ UCDstructure_set_node_minmax(output,node_data_min,node_data_max));
+ printf("Set Data min:max %f:%f %f:%f\n",
+ node_data_min[0],node_data_max[0],
+ node_data_min[1],node_data_max[1]);
+ // for(i=0;i<nodes.getSize();i++) node_data[i]=0.0; // see if clobbering data
+ delete node_data;
+
+ // Just manually set stuff in the data structure
+ printf("util_flag=%u\n",output->util_flag);
+ printf("max_ext[2]=%u\n",output->max_extent[0]);
+ //output->util_flag=0;
+ DumpUCD(output);
+ return output;
+}
+
+
+void DumpUCD(UCD_structure *u){
+ if(u->name) printf("UCD_Structure: name=%s\n",u->name);
+ else printf("UCD_Structure: <no name>\n");
+ printf("\tnameflag=%u util_flag=%u ncells=%u nnodes=%u\n",
+ u->name_flag,u->util_flag,
+ u->ncells,u->nnodes);
+ printf("\tmin:max extent %f,%f,%f:%f,%f,%f\n",
+ u->min_extent[0], u->min_extent[1], u->min_extent[2],
+ u->max_extent[0], u->max_extent[1], u->max_extent[2]);
+ printf("\tStructure data=%lu\n",(unsigned long)(u->data));
+ if(u->cell_name) printf("Has Cell Names\n");
+ else printf("<no cell names>\n");
+ printf("\tCell: veclen=%u, node_conn_size=%u last_cell=%u\n",
+ u->cell_veclen,u->node_conn_size,u->ucd_last_cell);
+ if(u->node_conn_size){
+ if(u->node_list) {
+ printf("\thas cell list %lu\n",u->node_list);
+ }
+ if(u->node_list_ptr){
+ printf("\thas node list pointer %lu\n",u->node_list_ptr);
+ printf("\tFirstNode %u:%u ++ %u:%u 8th node = %u:%u\n",
+ u->node_list[0],u->node_list_ptr[0],
+ u->node_list[1],u->node_list_ptr[1],
+ u->node_list[8],u->node_list_ptr[8]);
+ }
+ }
+ if(u->node_name) printf("\tHas Node Names\n");
+ else printf("\t<no node names>\n");
+ printf("\tNode: veclen=%u, cell__conn_size=%u last_node=%u\n",
+ u->node_veclen,u->cell_conn_size,u->ucd_last_node);
+ if(u->cell_conn_size){
+ if(u->cell_list) {
+ printf("\thas cell list %lu\n",u->cell_list);
+ }
+ if(u->cell_list_ptr){
+ printf("\thas cell list pointer %lu\n",u->cell_list_ptr);
+ printf("\tFirstCell %u:%u ++ %u:%u 8th cell = %u:%u\n",
+ u->cell_list[0],u->cell_list_ptr[0],
+ u->cell_list[1],u->cell_list_ptr[1],
+ u->cell_list[8],u->cell_list_ptr[8]);
+ }
+ }
+ printf("\trefcount=%u shm_base=%lu\n",u->refcnt,(unsigned long)(u->shm_base));
+}
diff --git a/src/AmrUcdFileReader.cc b/src/AmrUcdFileReader.cc
new file mode 100644
index 0000000..9057f8f
--- /dev/null
+++ b/src/AmrUcdFileReader.cc
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "AmrUcdFileReader.hh"
+
+void AmrUcdFileReader::getUcd(FlexArray<AmrNode*> &nodes,
+ FlexArray<int> &cells){
+ genUCD.purge(); // Auto-Purges AmrNode's
+ for(int i=0;i<activeGrids.getSize();i++){
+ int lev = grids[activeGrids[i]].level;
+ if(levelmask[lev]){
+ printf("Add Grid %u to the hierarchy [%u]\n",activeGrids[i],i);
+ // genUCD.addGrid(grid->level, grid->origin, grid->dx, grid->rank,
+ // grid->dims, (float *)(grid->data));
+ genUCD.addGrid(grids[activeGrids[i]]);
+ }
+ else {
+ //printf("Grid is active, but level mask is OFF for grid [%u] level %u\n",
+ // activeGrids[i],lev);
+ }
+ }
+ printf("****buildNodeHierarchy\n");
+ genUCD.buildNodeHierarchy();
+ printf("****buildUCD\n");
+ genUCD.buildUCD(nodes,cells);
+ printf("nnodes = %u ncells = %u\n",nodes.getSize(),cells.getSize());
+ puts("*** done ucd build");
+}
diff --git a/src/AmrUcdFileReader.hh b/src/AmrUcdFileReader.hh
new file mode 100644
index 0000000..9e10496
--- /dev/null
+++ b/src/AmrUcdFileReader.hh
@@ -0,0 +1,38 @@
+/*
+ Code objects with attibutes for behavior on instantiation
+ For example
+ Array
+ fast indexing
+ slow copy
+ button
+ texturemapped
+
+*/
+
+#ifndef __AMRUCDFILEREADER_HH_
+#define __AMRUCDFILEREADER_HH_
+#include <IO.hh>
+#include "AmrFileReader.hh"
+#include "AmrUcdGridHierarchy.hh"
+
+/*
+ It appears that AmrUcdGrid should not be an
+ external data structure.
+
+ It should be hidden inside of the AmrGridHierarchy
+*/
+class AmrUcdFileReader : public AmrFileReader {
+protected:
+ AmrUcdGridHierarchy genUCD;
+ // feed the AmrUcdGrid's to the hierarchy
+ // but reclaimation of those grids is questionable.
+
+ // However, the amrgridhierarchy should accept a
+ // reference to AmrGrid as input.
+public:
+ AmrUcdFileReader(IObase &f):AmrFileReader(f){
+ }
+ void getUcd(FlexArray<AmrNode*> &nodes, FlexArray<int> &cells);
+};
+
+#endif
diff --git a/src/AmrUcdGridHierarchy.cc b/src/AmrUcdGridHierarchy.cc
new file mode 100644
index 0000000..adaf8e5
--- /dev/null
+++ b/src/AmrUcdGridHierarchy.cc
@@ -0,0 +1,340 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "AmrUcdGridHierarchy.hh"
+
+void AmrUcdGridHierarchy::AmrUcdGrid::copyFromAmrGrid(AmrGrid &g){
+ level = g.level;
+ dataveclen=g.dataveclen;
+ rank = g.rank;
+ datatype = IObase::Int2DataType(g.datatype);
+ // Perhaps should do floating point only
+ vdata = g.data;
+ // copy to float datatype
+ printf("AmrUcdGridHierarchy:: dataveclen=%u\n",dataveclen);
+ if(g.data){
+ int nelements = IObase::nElements(g.rank,g.dims);
+ register int i;
+ //if(datatype!=IObase::Float32)
+ data = new float[nelements];
+ switch(datatype){
+ case IObase::Float32:
+ printf("AmrUcdGridHierarchy:: Original data is float use directly\n");
+ printf("\tpointerbase=%lu last=%lu\n",data,(data+nelements));
+ //data=(float*)g.data;
+ for(i=0;i<nelements;i++) data[i]=(float)((float*)(g.data))[i];
+ break;
+ case IObase::Float64:
+ printf("AmrUcdGridHierarchy:: Original data is double... copy\n");
+ for(i=0;i<nelements;i++) data[i]=(float)((double*)(g.data))[i];
+ break;
+ case IObase::Int32:
+ case IObase::uInt32:
+ for(i=0;i<nelements;i++) data[i]=(float)((int*)(g.data))[i];
+ break;
+ case IObase::Int16:
+ case IObase::uInt16:
+ for(i=0;i<nelements;i++) data[i]=(float)((short*)(g.data))[i];
+ break;
+ case IObase::Int8:
+ case IObase::uInt8:
+ default:
+ for(i=0;i<nelements;i++) data[i]=(float)((char*)(g.data))[i];
+ break;
+ };
+ }
+ else
+ data=0; // danger
+ register int i;
+ for(i=0;i<3;i++){
+ dims[i]=g.dims[i];
+ origin[i]=g.origin[i];
+ delta[i]=g.delta[i];
+ }
+ bounds.setFromExtents(g.minext,g.maxext);
+ for(i=0,nelements=1;i<rank;i++) nelements*=dims[i];
+}
+
+void AmrUcdGridHierarchy::AmrUcdGrid::regenPoints(){
+ int i;
+ //bounds.setFromOriginDx(origin,delta,dims); // already set from ext
+ // should set from extents
+ // create points
+ points.setSize(nelements);
+ points.setSize(nelements);
+ // for each point, lets initialize
+ long index,dataindex;
+ int mindex[3]={0,0,0};
+ //----------Node Initialization Cycle-----------------
+ printf("AmrUcdGridHierarchy:: dataveclen=%u\n",dataveclen);
+ for(index=0,dataindex=0;index<nelements;index++,dataindex+=dataveclen,(mindex[0])++){
+ AmrNode *n = points.getData()+index;
+ for(i=0;mindex[i]>=dims[i] && i<2;i++){
+ mindex[i]=0;
+ (mindex[i+1])++;
+ }
+ // assign using correct type (could put outside of loop to optimize)
+ n->data = data+dataindex;
+ n->level = level; // semiredunant, but necessary for AVS
+ /*
+ if(datatype==IObase::Float32)
+ n->fdata=fdata+dataindex;
+ else if(IObase::Float64)
+ n->ddata=ddata+dataindex;
+ else if(IObase::Int32 || IObase::uInt32)
+ n->idata=idata+dataindex;
+ else if(IObase::Int16 || IObase::uInt16)
+ n->sdata=sdata+dataindex;
+ else if(IObase::Int8 || IObase::uInt8)
+ n->cdata=cdata+dataindex;
+ */
+ n->child=n->parent=0; // for now (will fix this up later)
+ n->index=-1; // nil index for now
+ n->gridID = gridID;
+ for(i=0;i<3;i++)
+ n->location.array[i] = origin[i] + delta[i]*(double)(mindex[i]);
+ // assumes f77 order for arrays
+ }
+}
+
+
+AmrUcdGridHierarchy::~AmrUcdGridHierarchy() { purge(); }
+
+void AmrUcdGridHierarchy::purge(){
+ for(int l=0;l<grids.getSize();l++){
+ AmrUcdGrid *grid;
+ FOREACH(grid,grids[l]){
+ delete grid;
+ }
+ }
+ grids.purge();
+ levelinfo.purge();
+}
+
+void AmrUcdGridHierarchy::addGrid(AmrGrid &g){
+ if(grids.getSize()<g.level+1)
+ grids.setSize(g.level+1);
+ AmrUcdGrid *grid,*parent;
+ grid = new AmrUcdGrid(g);
+ //--------------Grid Parenting Cycle----------------
+ if(g.level>0){ // make grid hierarchy (eg. assign parents) (perhaps doubly-link)
+ // compare the bounding box to all grids in parent level
+ FOREACH(parent,grids[g.level-1]){ // OrderedList needs copy constructor
+ if(parent->bounds.contains(grid->bounds)){ // compared
+ grid->parent=parent;
+ parent->children.append(grid);// do forward ref
+ break;
+ }
+ }
+ }
+ grids[g.level].add(grid);
+}
+
+void AmrUcdGridHierarchy::buildNodeHierarchy(){
+ int i;
+ levelinfo.setSize(grids.getSize());
+ for(i=0;i<levelinfo.getSize();i++){
+ grids[i].reset(); // restart
+ AmrUcdGrid *g = grids[i].getNext();
+ if(g)
+ levelinfo[i].setDelta(g->delta);
+ else{
+ double fakedelta[5]={1,1,1,1,1};
+ printf("AmrUcdGridHierarchy::buildNodeHierarchy(): Using Fake delta for level %u (shouldn't do that)\n",i);
+ levelinfo[i].setDelta(fakedelta);
+ }
+ }
+ for(i=0;i<(levelinfo.getSize()-1);i++)
+ levelinfo[i].setStride(levelinfo[i+1].delta);
+ // cycle through each level and find parent nodes for each node
+ //-------------Node Parenting Cycle----------------------------
+ puts("node parenting cycle");
+ for(i=1;i<levelinfo.getSize();i++){
+ AmrUcdGrid *grid;
+ printf("\tL%u\n",i);
+ FOREACH(grid,grids[i]){ // level 2 grids should not be here!!!
+ // First find offset
+ int offset[3]; // we'll skip that for now and assume aligned
+ int origin[3]; // origin with respect to parent
+ int stride[3]; // just here for convenience
+ // now stride through the parent grid doing parenting replacement
+ AmrUcdGrid *parent=grid->parent;
+ if(!parent) continue; // failsafe for NULL parent
+ // stride through the parent doing replacement
+ // first compute the strides through the parent grid
+ // as well as the origin in parent coordinates
+ for(int j=0;j<3;j++){
+ register double dp=parent->origin[j];
+ register double dc=grid->origin[j];
+ register double dx=dc-dp; // difference between origins
+ dx /= parent->delta[j]; // if diff > .5 then use it?
+ if(j==0) printf("dparent=%lf dchild=%lf dx=%lf\n",dp,dc,dx);
+ // (no just need to round it)
+ origin[j]=(int)(dx+0.5); // this is a marginally bogus way to round up.
+ stride[j]=levelinfo[i-1].childstride[j];
+ }
+ printf("NodeParenting L%u: origin=%u:%u:%u stride=%u\n",i,origin[0],origin[1],origin[2],stride[0]);
+ int px,x,py,y,pz,z;
+ // typedef DATATYPE AmrNode;
+ FlexArray<AmrNode> *pnodes=&(parent->points);
+ FlexArray<AmrNode> *nodes=&(grid->points);
+ for(z=0,pz=origin[2];z<grid->dims[2];z+=stride[2],pz++){
+ int zi=grid->dims[1]*z;
+ int pzi=parent->dims[1]*pz;
+ for(y=0,py=origin[1];y<grid->dims[1];y+=stride[1],py++){
+ int yi=(zi+y)*grid->dims[0];
+ int pyi=(pzi+py)*parent->dims[0];
+ for(x=0,px=origin[0];x<grid->dims[0];x+=stride[0],px++){
+ register int pindex=px+pyi;
+ register int cindex=x+yi;
+ // ugh! finally we get to assign parents to the nodes
+ (*pnodes)[pindex].child=&((*nodes)[cindex]);
+ (*nodes)[cindex].parent=&((*pnodes)[pindex]);
+ }
+ }
+ }
+ }
+ }
+}
+
+void AmrUcdGridHierarchy::print(){
+ //************Print Some Results***********************
+ for(int i=0;i<levelinfo.getSize();i++){
+ AmrUcdGrid *grid;
+ printf("Level %u\n",i);
+ FOREACH(grid,grids[i]){ // level 2 grids should not be here!!!
+ printf("-------------Slice grid %lu ID=%u---------\n",(unsigned long)grid,grid->gridID);
+ int x,y,index;
+
+ printf("=====: ");
+ for(x=0;x<grid->dims[0];x++){
+ // print a row
+ printf("%5u ",x);
+ }
+
+ //puts("-----------------------------")
+ for(y=0,index=0;y<grid->dims[1];y++,index+=grid->dims[0]){
+ printf("\n[%3u]X: ",y);
+ for(x=0;x<grid->dims[0];x++){
+ // print a row
+ printf("%5.3f ",grid->points[index+x].location.cartesian.x);
+ }
+ printf("\n Y: ");
+ for(x=0;x<grid->dims[0];x++){
+ // print a row
+ printf("%5.3f ",grid->points[index+x].location.cartesian.y);
+ }
+ printf("\n Z: ");
+ for(x=0;x<grid->dims[0];x++){
+ // print a row
+ printf("%5.3f ",grid->points[index+x].location.cartesian.z);
+ }
+ printf("\n P: ");
+ for(x=0;x<grid->dims[0];x++){
+ if(grid->points[index+x].parent)
+ printf("%5u ",grid->points[index+x].parent->gridID);
+ else
+ printf("None ");
+ }
+ printf("\n C: ");
+ for(x=0;x<grid->dims[0];x++){
+ if(grid->points[index+x].child)
+ printf("%5u ",grid->points[index+x].child->gridID);
+ else
+ printf(" None ");
+ }
+ }
+ printf("\n");
+ }
+ }
+}
+
+void AmrUcdGridHierarchy::buildUCD(FlexArray<AmrNode*> &nodes,FlexArray<int> &cells){
+ // OK, first build pointlist by adding only cells without children
+ // for each one added to list, set its index member
+ // also set index for all parents recursively. (have recursive setindex in
+ // as a static member function of each node)
+ int ctr,i;
+ //**** Init all node indexes to -1
+ printf("AmrUcdGridHierarchy::buildUCD(): Initialize UCD\n");
+ for(i=0;i<levelinfo.getSize();i++){
+ AmrUcdGrid *grid;
+ FOREACH(grid,grids[i]){
+ AmrNode *points=grid->points.getData();
+ for(long idx=0;idx<grid->nelements;idx++)
+ points[i].index=-1;
+ }
+ }
+ // print();
+ //**** Top-down assignment of indices for each node without child
+ // If a node has a child, then the child will be superceding it
+ // for indices
+ printf("\ttop-down assign indices\n");
+ for(i=levelinfo.getSize()-1;i>=0;--i){
+ printf("\tLevel[%u]\n",i);
+ AmrUcdGrid *grid;
+ FOREACH(grid,grids[i]){
+ AmrNode *points=grid->points.getData();
+ for(long idx=0;idx<grid->nelements;idx++){
+ if(!points[idx].child){ // if no child
+ // then assign unique index
+ points[idx].setIndex(nodes.getSize());
+ nodes.append(points+idx); // append to nodelist
+ }
+ }
+ }
+ }
+ printf("Number of nodes in all = %u\n",nodes.getSize());
+ // OK, nows the time in schprockets when we dance...
+ //**** Top-down building of Hexahedral cells
+ //printf("now build hexahedral cells\n");
+ for(i=levelinfo.getSize()-1;i>=0;i--){
+ printf("\tL%u\n",i);
+ AmrUcdGrid *grid;
+ int nodeindices[8],mapped[8];
+ FOREACH(grid,grids[i]){
+ AmrNode *points=grid->points.getData();
+ // verify that at least one point doesn't have a child
+ // if all have children then continue
+ int x,y,z;
+ int *dims=grid->dims;
+ int zstep=dims[1]*dims[0];
+ int ystep=dims[0]; // xstep=1
+ int idx;
+ // setup the cell indices
+ for(idx=0;idx<8;idx++){
+ nodeindices[idx]=0;
+ }
+ for(idx=0;idx<4;idx++) {
+ nodeindices[idx]+=zstep;
+ }
+ for(idx=0;idx<=4;idx+=4){
+ nodeindices[idx+2]+=1;
+ nodeindices[idx+3]+=1;
+ nodeindices[idx]+=ystep;
+ nodeindices[idx+3]+=ystep;
+ }
+ //***** Build the Cell list
+ for(z=0;z<(dims[2]-1);z++){
+ //printf("\t\tZ%u\n",z);
+ for(y=0;y<(dims[1]-1);y++){
+ for(x=0;x<(dims[0]-1);x++){
+ // OK, now we find the real indices and
+ for(idx=0;idx<8;idx++){
+ mapped[idx]=points[nodeindices[idx]].index;
+ if(mapped[idx]>nodes.getSize()){
+ printf("indexing error at grid %u, position %u,%u,%u idx[%u]=%u\n",
+ grid->gridID,x,y,z,idx,mapped[idx]);
+ }
+ }
+ // append to cells list
+ cells.append(mapped,8); // copies the mapped array?
+ // now we save this sequence;
+ for(idx=0;idx<8;idx++) (nodeindices[idx])++;
+ }
+ for(idx=0;idx<8;idx++) (nodeindices[idx])++;
+ }
+ for(idx=0;idx<8;idx++) (nodeindices[idx])+=ystep;
+ }
+ }
+ }
+}
diff --git a/src/AmrUcdGridHierarchy.hh b/src/AmrUcdGridHierarchy.hh
new file mode 100644
index 0000000..94835a3
--- /dev/null
+++ b/src/AmrUcdGridHierarchy.hh
@@ -0,0 +1,134 @@
+#ifndef __AMRUCDGRIDHIERARCHY_HH_
+#define __AMRUCDGRIDHIERARCHY_HH_
+
+#include "FlexArrayTmpl.H"
+#include "OrderedList.H"
+#include "AmrNode.hh"
+#include "Bounds.hh"
+#include "IO.hh"
+#include "AmrGrid.h"
+#include "Vec3f.hh"
+
+class AmrUcdGridHierarchy {
+ struct AmrUcdGrid {
+ int level;
+ int rank;
+ int dims[3];
+ double origin[3],delta[3];
+ IObase::DataType datatype;
+ union {
+ void *vdata;
+ int *idata;
+ float *fdata;
+ double *ddata;
+ short *sdata;
+ char *cdata;
+ };
+ float *data; // local data
+ // Attributes
+ long nelements;
+ int gridID,complete;
+ // DATATYPE data; // assume f77 order (should be void*)
+ int dataveclen;
+ Bounds bounds;
+ FlexArray<AmrNode> points; // assume f77 order
+ AmrUcdGrid *parent;
+ FlexArray<AmrUcdGrid*> children;
+ // Constructors
+ AmrUcdGrid(AmrGrid &g):complete(0),parent(0){
+ copyFromAmrGrid(g);
+ regenPoints();
+ }
+ ~AmrUcdGrid(){
+ if(fdata!=data) delete data;
+ data=0;
+ }
+ private:
+ // utilities
+ void copyFromAmrGrid(AmrGrid &g);
+ void regenPoints();
+ };
+ struct LevelInfo {
+ double delta[3]; // find differences in delta
+ int childstride[3]; // stride through children
+ void setDelta(double *dx){
+ for(int i=0;i<3;i++){
+ // childstride[i]=1; // why?
+ delta[i]=dx[i]; // CRASH !!!
+ }
+ printf("setDelta=%lf\n",delta[0]);
+ }
+ void setStride(double *childdx){
+ for(int i=0;i<3;i++)
+ childstride[i] = (int)(delta[i]/childdx[i] + 0.5);
+
+ printf("Stride=%u from dx=%lf\n",childstride[0],childdx[0]);
+ }
+ };
+public:
+ typedef OrderedList<AmrUcdGrid*> GridList;
+ FlexArray<GridList> grids;
+
+ FlexArray<LevelInfo> levelinfo;
+// public:
+ ~AmrUcdGridHierarchy();
+ void addGrid(AmrGrid &grid); // copy from
+ //*** Now do parenting of the nodes (can be combined with the addGrid
+#if 0 // disabled
+ struct CellInfo {
+ struct Face {
+ Vec3f normal;
+ // int neighbor[3]; return as -1,0,1 values
+ Vec3f minext[3];
+ Vec3f maxext[3];
+ };
+ Face faces[6];
+ float Vec3f[3],Vec3f[3];
+ };
+ static inline AmrUcdGrid *Grid2Cell(int coord[3],AmrUcdGrid *gridinfo ,CellInfo *cellinfo){
+ // automatically hoists grid reference if intersection with denser region
+ // automatically deprecates grid reference if intersection with boundary
+ // returns null if encounter with outer boundary
+ // Ordering of faces are {+x -x +y -y +z -z}
+
+ // actually totally wrong... need to compute cell min max!!!!!!
+ Vec3f min(gridinfo->bounds.min),max(gridinfo->bounds.max);
+
+ cellinfo->face[0].minext.set(min[0],min[1],min[2]); // m000
+ cellinfo->face[0].maxext.set(min[0],max[1],max[2]); // M011
+ cellinfo->face[1].minext.set(max[0],min[1],min[2]); // m100
+ cellinfo->face[1].maxext.set(max[0],max[1],max[2]); // M111
+ cellinfo->face[2].minext.set(min[0],min[1],min[2]); // m000
+ cellinfo->face[2].maxext.set(max[0],min[1],max[2]); // M101
+ cellinfo->face[3].minext.set(min[0],max[1],min[2]); // m010
+ cellinfo->face[3].maxext.set(max[0],max[1],max[2]); // M111
+ cellinfo->face[4].minext.set(min[0],min[1],min[2]); // m000
+ cellinfo->face[4].maxext.set(max[0],max[1],min[2]); // M110
+ cellinfo->face[5].minext.set(min[0],min[1],max[2]); // m001
+ cellinfo->face[5].maxext.set(max[0],max[1],max[2]); // M111
+
+ Vec3f p1(min[0],min[1],min[2]),// (0,0,0),
+ p2(max[0],min[1],min[2]),// (1,0,0),
+ p3(max[0],max[1],min[2]),// (1,1,0),
+ p4(min[0],max[1],min[2]),// (0,1,0),
+ p5(min[0],min[1],max[2]),// (0,0,1),
+ p6(max[0],min[1],max[2]),// (1,0,1),
+ p7(max[0],max[1],max[2]),// (1,1,1),
+ p8(min[0],max[1],max[2]); // (0,1,1)
+ cellinfo->face[0].normal.norm(p1,p4,p8);
+ cellinfo->face[1].normal.norm(p3,p2,p6);
+ cellinfo->face[2].normal.norm(p2,p1,p5);
+ cellinfo->face[3].normal.norm(p4,p3,p7);
+ cellinfo->face[4].normal.norm(p1,p4,p3);
+ cellinfo->face[5].normal.norm(p8,p7,p6);
+ }
+#endif // disabled
+ void purge();
+ void buildNodeHierarchy();
+ void print();
+ void buildUCD(FlexArray<AmrNode*> &nodes,FlexArray<int> &cells);
+};
+
+
+#endif
+
diff --git a/src/AppendTest.c b/src/AppendTest.c
new file mode 100644
index 0000000..d1e1349
--- /dev/null
+++ b/src/AppendTest.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include "IEEEIO.h"
+
+int main(int argc, char **argv) {
+ IOFile noapp, app, appch;
+ Int i,j,k;
+ double x[20][20][20];
+ double y[10][20][20];
+ int dims[3],chdim[3],chori[3];
+
+ dims[0] = 20; dims[1] = 20; dims[2] = 20;
+
+ for (i=0;i<20;i++)
+ for (j=0;j<20;j++)
+ for (k=0;k<20;k++) {
+ x[i][j][k] = 20*i + j + k*0.05;
+ if (i < 10) y[i][j][k] = x[i][j][k];
+ }
+
+ /* OK so first write the one three times without appending */
+ noapp = IEEEopen("noapp.ieee","w");
+ for (i=0;i<3;i++) {
+ IOwrite(noapp, FLOAT64, 3, dims, x);
+ }
+ IOclose(noapp);
+
+ /* Now do the appended one */
+ for (i=0;i<3;i++) {
+ if (i == 0)
+ app = IEEEopen("app.ieee","w");
+ else
+ app = IEEEopen("app.ieee","a");
+ IOwrite(app, FLOAT64, 3, dims, x);
+ IOclose(app);
+ }
+
+ /* Now do a chunked one */
+ for (i=0;i<3;i++) {
+ if (i == 0)
+ appch = IEEEopen("appch.ieee","w");
+ else
+ appch = IEEEopen("appch.ieee","a");
+
+ IOreserveChunk(appch,FLOAT64,3,dims);
+ chdim[0] = 20;
+ chdim[1] = 20;
+ chdim[2] = 20;
+ chori[0] = 0;
+ chori[1] = 0;
+ chori[2] = 0;
+ IOwriteChunk(appch,chdim,chori,x);
+ IOclose(appch);
+ }
+
+ /* Now do a chunked one without appending */
+ appch = IEEEopen("noappch.ieee","w");
+ for (i=0;i<3;i++) {
+ IOreserveChunk(appch,FLOAT64,3,dims);
+ chdim[0] = 20;
+ chdim[1] = 20;
+ chdim[2] = 20;
+ chori[0] = 0;
+ chori[1] = 0;
+ chori[2] = 0;
+ IOwriteChunk(appch,chdim,chori,x);
+ }
+ IOclose(appch);
+
+}
diff --git a/src/Arch.h b/src/Arch.h
new file mode 100644
index 0000000..5d0eeb0
--- /dev/null
+++ b/src/Arch.h
@@ -0,0 +1,74 @@
+#ifndef _MACHDEFS_H_
+#define _MACHDEFS_H_
+
+#ifdef ANSI
+#define PROTO(x) x
+#else
+#define PROTO(x) ()
+#endif
+
+#if defined(SGI) || defined(CM5) || defined (DEC)
+#define F77NAME(a,b,c) a
+#else
+#ifdef HP
+#define F77NAME(a,b,c) b
+#else
+#ifdef CRAY
+#define F77NAME(a,b,c) c
+#endif
+#endif
+#endif
+
+#ifndef F77NAME
+#define F77NAME(a,b,c) a
+#endif
+
+
+#ifndef SGI
+#ifdef WIN32
+typedef __int64 Long8;
+#else
+typedef long Long8;
+#endif
+#else /* default SGI behavior. long longs=8 bytes long=4 bytes*/
+typedef long long Long8;
+#endif
+
+#ifdef T3E
+#ifndef FFIO
+#define FFIO /* forces it to use FFIO if on a T3E */
+#endif
+typedef short Int; /* T3E uses 8-byte integers as default */
+typedef short Long; /* this is wierd, but its a T3E... */
+#else
+typedef int Int; /* every other sane design uses 4-byte ints */
+typedef int Long; /* for now Long *MUST* be 32bit integer for PC compatability */
+/* if we run into problems later we'll just need have a separate rev of the file format for PC's */
+#endif
+
+#ifdef WIN32 /* this aint a happenin thang yet... */
+/* #include <sys/types.h> ... bahh!!! Win32 doesn't have this! */
+typedef unsigned int IOFile; /* cast to integer for pointers :( */
+union Integer8 {
+ long l;
+ int i[2];
+ char c[8];
+}; /* what can be said about the byte order though? */
+#else /* its a Mac or Unix box probably */
+#include <sys/types.h>
+typedef caddr_t IOFile; /* use caddr_t to store pointers */
+#endif
+
+#ifdef HP
+#define NO_RECURSIVE_INLINE
+#endif
+
+#ifndef CONST_BROKEN
+#define CONST const
+#else
+#ifdef CONST
+#undef CONST
+#endif
+#endif
+
+#endif
diff --git a/src/Bounds.cc b/src/Bounds.cc
new file mode 100644
index 0000000..f291050
--- /dev/null
+++ b/src/Bounds.cc
@@ -0,0 +1,29 @@
+#include "Bounds.hh"
+
+void Bounds::setFromExtents(double *p1,double *p2){
+ for(int i=0;i<3;i++){
+ if(p1[i]<p2[i]){
+ min[i]=p1[i];
+ max[i]=p2[i];
+ }
+ else {
+ min[i]=p2[i];
+ max[i]=p1[i];
+ }
+ }
+}
+void Bounds::setFromOriginDx(double *origin,double *dx,int *dims){
+ for(int i=0;i<3;i++){
+ min[i]=origin[i];
+ if(dims[i]>1)
+ max[i]=origin[i]+dx[i]*(double)(dims[i]-1);
+ else max[i]=origin[i]; // failsafe for cheating on dims
+ }
+}
+int Bounds::contains(double point[3]) {
+ for(int i=0;i<3;i++){
+ if(min[i]>point[i]) return 0;
+ if(max[i]<point[i]) return 0;
+ }
+ return 1;
+}
diff --git a/src/Bounds.hh b/src/Bounds.hh
new file mode 100644
index 0000000..df7b9f3
--- /dev/null
+++ b/src/Bounds.hh
@@ -0,0 +1,18 @@
+#ifndef __BOUNDS_HH_
+#define __BOUNDS_HH_
+
+struct Bounds {
+ double min[3],max[3];
+ void setFromExtents(double *p1,double *p2);
+ void setFromOriginDx(double *origin,double *dx,int *dims);
+ int contains(double point[3]);
+ // uses restricted assumption that box is entirely inside or
+ // entirely outside its parent
+ inline int contains(Bounds &b){
+ if(contains(b.min) && contains(b.max)) return 1;
+ else return 0;
+ }
+};
+
+#endif
+
diff --git a/src/FlexArrayTmpl.H b/src/FlexArrayTmpl.H
new file mode 100644
index 0000000..627dac8
--- /dev/null
+++ b/src/FlexArrayTmpl.H
@@ -0,0 +1,222 @@
+// FlexArrayTmpl.hh
+#ifndef __FLEXARRAY_TMPL_HH_
+#define __FLEXARRAY_TMPL_HH_
+
+#ifdef SGI
+#include <new.h>
+#endif
+
+#include "Arch.h"
+// #define DOUBLEWORD 8 // sgi doubleword == -align64 at a minimum
+#define DOUBLEWORD 1 // kludge for space efficiency (should allow setting of blocksize
+// #define FLEXARRAYDEBUG
+/*-------------
+ Template: FlexArray
+ Purpose: Simplifies dynamically allocated array management since it contains
+ array size information and manages array resizing. However, since speed-critical
+ operations like indexing (the [] operator) are inlined, it adds no speed
+ penalty for the most common speed-critical operations.
+ Method Summary:
+ constructor: The initial "size" is 0 (the size of the array that is accessible
+ using the indexing operator []. However, the internally allocated size is
+ a minimum of 8 elements.
+ [] : Indexing operator. Acts just like [] would for a generic array. Since
+ it is inlined, there is actually no penalty in performance compared to
+ using a generic array.
+ append : Add an element to the end of the array, resizing the array if necessary.
+ The arrays are allocated in blocks so it doesn't need to realloc on every append.
+ For arrays < 1024 elements long, it doubles the array size on each realloc. When
+ larger than 1024 elements, it adds 1024 elements to the array on every realloc.
+ setSize(): Sets the internal and externally availible array sizes to the
+ specified size; shrinking a larger internal array if necessary.
+ getSize(): Return the current externally availible array size. The internal
+ size may be larger.
+---------------*/
+template<class T>
+class FlexArray {
+ int size,maxsize;
+ T *data;
+ // Internal reallocation procedure.
+ void grow(int targetSize=1);
+public:
+ // constructor
+ FlexArray(int sz=0);
+ // copy constructor
+ FlexArray(FlexArray<T> &src);
+ FlexArray<T> &operator=(FlexArray<T> &src);
+ // destructor
+ ~FlexArray();
+ inline int getSize(){return size;}
+ int setSize(int s);
+ int append(T value);
+ int append(T *values,int nvals);
+#ifdef FLEXARRAYDEBUG
+ T &operator[](int index){
+ if(index>=size || index<0) { // range check
+ printf("FlexArray:: Bad index. Arraysize=%u Index=%u\n",
+ size,index);
+ index=0;
+ }
+ return (data[index]);
+ }
+#else
+ inline T &operator[](int index){ return (data[index]); }
+#endif
+ // purge? which forces array delete
+ inline void purge(){
+ if(data)
+ delete[] data;
+#ifdef FLEXARRAYDEBUG
+ else
+ printf("-----FlexArray.purge(): Data was already 0\n");
+ printf("****Flexarray.purge() maxsize=%u size=%u data was = %lX\n",
+ maxsize,size,data);
+#endif
+ data=0;
+ maxsize=size=0;
+ }
+ //inline operator T*() { return data; } // typecasting operator
+ inline T *getData() { return data; } // sometimes you need direct access to the contained array.
+};
+
+template<class T>
+FlexArray<T>::FlexArray(int sz):size(sz){
+ /*
+ if(sz>DOUBLEWORD) maxsize=sz;
+ else maxsize=DOUBLEWORD; always allocate in doubleword chunks
+ data = new T[maxsize];
+ */
+
+ maxsize=sz; // problem here is that virtually guarauntees reallocation
+ if(maxsize>0) data = new T[maxsize];
+ else data = 0;
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray constructor: Init with maxsize=%u size=%u data was = %lX\n",
+ maxsize,size,data);
+#endif
+}
+
+template<class T>
+FlexArray<T>::~FlexArray(){
+ if(maxsize>0 && data)
+ delete[] data;
+ size=maxsize=0;
+ data=0;
+}
+
+
+template<class T>
+void FlexArray<T>::grow(int targetSize){
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray.grow(targ=%u): Init with maxsize=%u size=%u data was = %lX\n",
+ targetSize,maxsize,size,data);
+#endif
+ do{
+ if(!maxsize) maxsize=1;
+ //if(maxsize<1024)
+ maxsize<<=1; // double in size
+ //else
+ // maxsize+=1024; // increase by 1k element block
+ }while(maxsize<targetSize);
+ //printf("FlexArray::grow(%u)->%u\n",targetSize,maxsize);
+ T *newdata=new T[maxsize];
+ // has to do its own copy because realloc is not always compatible with
+ // new/delete on all machines
+ if(data){
+ for(int i=0;i<size;i++)
+ newdata[i]=data[i];
+ delete[] data;
+ }
+ data=newdata;
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray.grow(targ=%u): Changed to maxsize=%u size=%u data was = %lX\n",
+ targetSize,maxsize,size,data);
+#endif
+}
+
+template<class T>
+FlexArray<T>::FlexArray(FlexArray<T> &src):data(0),size(0),maxsize(0){
+ setSize(src.getSize());
+ //puts("\tFlexArray<T>copy constructor***********");
+ for(int i=0;i<src.getSize();i++)
+ data[i]=src.data[i];
+ //this->data[i]=src->data[i];
+
+ // (*this)[i]=src[i]; // a full stupid copy!!
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray copy constructor: Init with maxsize=%u size=%u data was = %lX\n",
+ maxsize,size,data);
+#endif
+}
+
+template<class T>
+FlexArray<T> &FlexArray<T>::operator=(FlexArray<T> &src){
+ if(this == &src) return *this;
+ setSize(src.getSize());
+ //puts("\t\tFlexArray<T>copy operator");
+ for(int i=0;i<src.getSize();i++)
+ data[i]=src[i]; // a full stupid copy!!
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray::=: Copied with maxsize=%u size=%u data was = %lX\n",
+ maxsize,size,data);
+#endif
+ return *this;
+}
+
+template<class T>
+int FlexArray<T>::setSize(int s){
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray.setSize(%u): Init with maxsize=%u size=%u data was = %lX\n",
+ s,maxsize,size,data);
+#endif
+ if(s<0) s=0; // make sure size isn't negative
+ if(s<=maxsize){
+ size=s;
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray.setSize(%u): Changed to maxsize=%u size=%u data was = %lX\n",
+ s,maxsize,size,data);
+#endif
+ return size; // can't allow shrinkage below current size
+ }
+ // otherwise if >, then set array size to exactly requested size
+ maxsize=s;
+ T *newdata=new T[maxsize];
+ if(data){
+ for(int i=0;i<size && i<maxsize;i++)
+ newdata[i]=data[i];
+ delete[] data;
+ }
+ data=newdata;
+ size=maxsize;
+#ifdef FLEXARRAYDEBUG
+ printf("****FlexArray.setSize(%u): Changed to maxsize=%u size=%u data was = %lX\n",
+ s,maxsize,size,data);
+#endif
+ return size;
+}
+
+template<class T>
+int FlexArray<T>::append(T value){
+ if(size>=maxsize) // failsafe check
+ grow(size+1); // this array only increases in size
+ data[size++]=value;
+ return size;
+}
+
+template<class T>
+int FlexArray<T>::append(T *values,int nvals){
+ if(size+nvals >= maxsize)
+ grow(size+nvals);//this array only increases in size
+ for(int i=0;i<nvals;i++)
+ data[size++]=values[i];
+ return size;
+}
+
+/*
+ 1) Refcount must be fixed
+ 2) Need to have more flexibility in how the block allocation
+ is defined (eg. memory allocation blocksize) Use obstacks?
+ This would require a more global memory pool
+*/
+
+#endif // __FLEXARRAY_TMPL_HH_
diff --git a/src/FlexIO.cc b/src/FlexIO.cc
new file mode 100644
index 0000000..d6587d0
--- /dev/null
+++ b/src/FlexIO.cc
@@ -0,0 +1,55 @@
+#include <FlexIO.hh>
+#include <IEEEIO.hh>
+#include <string.h>
+
+#ifdef WITH_HDF5
+#include <H5IO.hh>
+#endif
+
+#ifdef WITH_HDF4
+#include <HDFIO.hh>
+#endif
+
+/*
+ This check should be more advanced, of course.
+ It currently just checks if the extension is anywhere in the
+ filename. This might be ok in most situation, but will fail
+ if the filename is e.g. /tmp/dir.h5/data.ieee ...
+ Should check for true file extension (I'm too lazy here).
+ Possibly it might be even better to read the first four bytes of
+ the file - if it already exists - and determine the file type based
+ on that.
+ */
+
+/*
+In preparation for the automatic detection and opening of the proper file
+type, IEEEIO was designed so that you can sense the file type using the 1st 4
+bytes of the file (the magic number), so that you don't have to rely on the
+file extensions. HDF4 and HDF5 also use this same methodology. IEEEIO's
+magic number is 0x01020304. HDF4 uses the ascii representation for ctrl-n
+ctrl-c ctrl-s ctrl-a (^N^C^S^A). These are stored as individual characters
+and so must be read consecutively from the file so as to counteract the
+effects of byte-swapping. In IEEEIO, I actually store the magic number as a
+sequence of characters followed by the same magic number written as an
+integer. This is how IEEEIO auto-detects the byte-order of the file (or at
+least whether the file's byte order is opposite that of the machine
+architecture which is reading it).
+
+-john
+*/
+IObase* FlexIOopen(const char*filename, IObase::AccessMode mode)
+{
+
+#ifdef WITH_HDF5
+ if (strstr(filename, ".h5") )
+ return new H5IO(filename, mode);
+#endif
+
+#ifdef WITH_HDF4
+ if (strstr(filename, ".hdf") )
+ return new HDFIO(filename, mode);
+#endif
+
+ return new IEEEIO(filename, mode);
+}
+
diff --git a/src/FlexIO.hh b/src/FlexIO.hh
new file mode 100644
index 0000000..233188a
--- /dev/null
+++ b/src/FlexIO.hh
@@ -0,0 +1,27 @@
+/////////////////////////////////////////////////////////////////
+//
+// $Id$
+//
+// $Log$
+// Revision 1.1 2000/04/28 08:51:16 werner
+// Wrapper function for runtime detection of IEEEIO,HDF5,HDF4 format.
+// Takes a filename and returns an IObase* object.
+// For compilation, the flags -DWITH_HDF5 and -DWITH_HDF4 have to be set
+// to enable HDF{4|5} functionality, otherwise just IEEEIO is available.
+// These flags have to be set in the makefile, depending on wether the HDF{4|5}
+// libraries are available at compilation time.
+//
+// Created 2000/04/28 10:28:21 werner
+// Initial version
+//
+//
+/////////////////////////////////////////////////////////////////
+#ifndef __FLEXIO_HPP
+#define __FLEXIO_HPP "Created 28.04.2000 10:28:21 by werner"
+
+#include <IO.hh>
+
+IObase* FlexIOopen(const char*filename, IObase::AccessMode = IObase::Read);
+
+
+#endif /* __FLEXIO_HPP */
diff --git a/src/GNUmakefile b/src/GNUmakefile
new file mode 100644
index 0000000..b9fcc49
--- /dev/null
+++ b/src/GNUmakefile
@@ -0,0 +1,62 @@
+#
+# FlexIO Interface to the Makefile Configuration System, as
+# described and available at
+#
+# http://amira.zib.de/make/
+#
+# $Revision: 1.1.1.1 $
+# $Date: 2000-09-13 13:49:09 $
+# $Log: not supported by cvs2svn $
+# Revision 1.4 2000/05/29 14:06:11 werner
+# Using VPATH instead of PWD is much saver.
+#
+# Revision 1.3 2000/05/25 16:20:38 werner
+# HDF4 interface enabled
+#
+# Revision 1.2 2000/05/17 10:45:38 werner
+# GNUmakefile falls back to include the Makefile in the same directory, if
+# no ../GNUmakefile.rules exists.
+#
+# Revision 1.1 2000/05/10 11:36:52 werner
+# A GNUmakefile to enable compilation of FlexIO directly in the context of
+# Amira. Please cry if this leads to problems; if so, we have to find some
+# more complicated mechanism...
+#
+#
+#
+
+OBJECTS = IO.$O IEEEIO.$O FlexIO.$O
+
+HDF4OBJECTS = HDFIO.$O
+HDF5OBJECTS = H5IO.$O
+
+AMROBJECTS = AmrGridReader.$O AmrUcdFileReader.$O \
+ AmrFileReader.$O Bounds.$O \
+ AmrUcdGridHierarchy.$O AMRwriter.$O \
+ Writer.$O
+
+SOCKOBJECTS = SockIOreader.$O SockIOwriter.$O
+MPOBJECTS = MPIO.$O MPIutils.$O
+
+OBJS = $(OBJECTS) $(AMROBJECTS) $(HDF5OBJECTS_${HDF5}) $(HDF4OBJECTS_${HDF4})
+
+HDF4OBJECTS_true=$(HDF4OBJECTS)
+HDF5OBJECTS_true=$(HDF5OBJECTS)
+
+TARGET = FlexIO
+PACKAGE = $(TARGET)
+
+all.dtor=remove-config visible
+
+RULEFILE = $(shell if [ -r $(VPATH)../GNUmakefile.rules ] ; then echo $(VPATH)../GNUmakefile.rules ; else echo Makefile ; fi)
+
+include $(RULEFILE)
+
+CXXFLAGS += $(hdf5_FLAGS) $(hdf4_FLAGS) -I$(VPATH)./
+LIBS += $(hdf5_LIB) $(hdf4_LIB) -lm
+
+#
+# Add a variable to the makefile configuration
+#
+TARGET_FLAGS=-I$$(MAKE_LOCAL)/external/FlexIO -I$$(MAKE_ROOT)/external/FlexIO $(hdf5_FLAGS) $(hdf4_FLAGS)
+
diff --git a/src/H5IO.cc b/src/H5IO.cc
new file mode 100644
index 0000000..f41471b
--- /dev/null
+++ b/src/H5IO.cc
@@ -0,0 +1,689 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+//#include <hdf.h>
+#include "H5IO.hh"
+#include <hdf5.h>
+
+hid_t H5IO::DataType2H5(IObase::DataType nt){
+ switch(nt){
+ case Int8:
+ return H5T_NATIVE_CHAR; // means data
+ case Char8: // distinct from INT8..
+ return H5T_NATIVE_CHAR; // means string
+ case Float32:
+ return H5T_NATIVE_FLOAT;
+ case Float64:
+ return H5T_NATIVE_DOUBLE;
+ case Int32:
+ return H5T_NATIVE_INT;
+ case Int64:
+ return H5T_NATIVE_LLONG;
+ case Int16:
+ return H5T_NATIVE_SHORT;
+ case uInt8:
+ return H5T_NATIVE_UCHAR;
+ case uInt16:
+ return H5T_NATIVE_USHORT;
+ case uInt32:
+ return H5T_NATIVE_UINT;
+ case uInt64:
+ return H5T_NATIVE_ULLONG;
+ case Char16: // unicode character type
+ return H5T_NATIVE_USHORT;
+ }
+ printf("H5IO::H52DataType(): Don't recognize type %d\n",(int)nt);
+ return -1;
+}
+
+IObase::DataType H5IO::H5DataType2DataType(hid_t nt){
+ H5T_class_t typeclass;
+ size_t typesize;
+
+ typeclass = H5Tget_class(nt);
+ typesize = H5Tget_size(nt);
+
+ switch(typeclass){
+ case H5T_INTEGER:
+ printf("Int %d bytes\n",typesize);
+ switch(typesize){
+ case 1:
+ return Int8;
+ case 2:
+ return Int16;
+ case 4:
+ return Int32;
+ case 8:
+ return Int64;
+ default:
+ printf("Cannot convert type for integer with %d bytes\n",
+ typesize);
+ break;
+ }
+ break;
+ case H5T_FLOAT:
+ // printf("Float %d bytes\n",typesize);
+ switch(typesize){
+ case 4:
+ return Float32;
+ case 8:
+ return Float64;
+ default:
+ printf("Cannot convert type for floating point with %d bytes\n",
+ typesize);
+ }
+ break;
+ case H5T_TIME:
+ puts("Cannot convert type Time");
+ break;
+ case H5T_STRING:
+ //puts("String");
+ switch(typesize){
+ case 1:
+ return Char8;
+ case 2:
+ return Char16;
+ default:
+ printf("Cannot convert type for string element with %d bytes\n",
+ typesize);
+ break;
+ }
+ break;
+ case H5T_BITFIELD:
+ puts("Cannot convert type Bitfield");
+ break;
+ case H5T_OPAQUE:
+ puts("Cannot convert type Opaque");
+ break;
+ case H5T_COMPOUND:
+ default:
+ puts("Cannot convert type Unknown");
+ break;
+ }
+ puts("Type conversion failed");
+ return Error;
+}
+#if 0
+IObase::DataType H5IO::H52DataType(hid_t &nt){
+ switch(nt){
+ case H5T_NATIVE_CHAR:
+ return Int8;
+ case H5T_NATIVE_CHAR:
+ return Char8;
+ case H5T_NATIVE_FLOAT:
+ return Float32;
+ case H5T_NATIVE_DOUBLE:
+ return Float64;
+ case H5T_NATIVE_INT:
+ return Int32;
+ case H5T_NATIVE_LONGLONG:
+ return Int64;
+ case H5T_NATIVE_SHORT:
+ return Int16;
+ case H5T_NATIVE_UCHAR:
+ return uInt8;
+ case H5T_NATIVE_USHORT:
+ return uInt16;
+ case H5T_NATIVE_UINT:
+ return uInt32;
+ case H5T_NATIVE_ULONGLONG:
+ return uInt64;
+ // no translation to Char16 from HDF5 right now (unclear what to do)
+ }
+ fprintf(stderr,"H5IO::H52DataType(): Don't recognize type %d\n",(int)nt);
+ return Error;
+}
+#endif
+int H5IO::createdataspace(int rank,CONST int *dims){
+ if(dataspacevalid && rankf==rank){
+ // lets compare dims
+ int val=1;
+ for(int i=0;i<rank;i++) if(dims[i]!=dimsf[i]) val=0;
+ if(val){ // current dataspace is sufficient
+ nitems++;
+ index=nitems-1; // error in returnval here!
+ return 1; // success
+ }
+ // otherwise, must nuke current dataspace
+ enddataspace();
+ }
+ for(int i=0;i<rank;i++) dimsf[i]=dims[i];
+ rankf=rank;
+ dataspace = H5Screate_simple(rankf, dimsf, NULL);
+ dataspacevalid=1;
+ nitems++;
+ index=nitems-1;
+ return 1; // created new datapace
+}
+
+int H5IO::createdatatype(IObase::DataType dt){
+ if(currentdatatype==dt) return 0;
+ enddatatype();
+ datatype = H5Tcopy(DataType2H5(dt));
+ currentdatatype = dt;
+ datatypevalid = 1;
+ return 1;
+}
+
+int H5IO::selectdataset(int i){
+ // printf("datasetvalid=%u i=%d index=%d nitems=%d\n",datasetvalid,i,index,nitems);
+
+ if(index==i && datasetvalid)
+ return index;
+ index=i;
+ if(index>=nitems) index=nitems-1;
+ if(index<0) index=0;
+ // must iterate to select or for now just
+ char dataname[128];
+ //char dataname2[128];
+ sprintf(dataname,"H5IO-Dataset%u",index); // was a KLUDGE!
+ //getdatasetname(index,dataname2);
+ //printf("Datasetname for dataset[%u]=[%s] [%s]\n",index,dataname,dataname2);
+ enddataset(); // close current dataset
+ dataset = H5Dopen(file,dataname); // open a dataset
+ if(!dataset) puts("error no dataset");
+ datasetvalid=1; // we have a new dataset
+ // if(!datasetvalid) return -1;
+ enddataspace();
+ dataspace = H5Dget_space(dataset);
+ if(!dataspace) puts("error no dataspace");
+ enddatatype();
+ datatype = H5Dget_type(dataset);
+ enddataspace();
+ rankf = H5Sget_simple_extent_ndims(dataspace);
+ H5Sget_simple_extent_dims(dataspace,dimsf,NULL);
+ //printf("\tdimsf is now %lu:%lu:%lu\n",dimsf[0],dimsf[1],dimsf[2]);
+ datasetvalid=dataspacevalid=datatypevalid=1; // all valid now
+ return index;
+}
+
+herr_t H5IOcounter(hid_t group_id,
+ const char *member_name,
+ void *operator_data){
+ int *count = (int*)operator_data;
+ (*count)++;
+ return 0;
+}
+
+struct H5IO_getname_t {
+ int index,count;
+ char *name;
+};
+herr_t H5IOgetname(hid_t group_id,
+ const char *member_name,
+ void *operator_data){
+ H5IO_getname_t *getn = (H5IO_getname_t*)operator_data;
+ if(getn->index==getn->count){
+ strcpy(getn->name,member_name);
+ return 1; // success
+ }
+ getn->count++;
+ return 0;
+}
+
+int H5IO::getndatasets(){
+ int count=0;
+ int idx=0;
+ while(H5Giterate(file, /* hid_t loc_id, */
+ "/", /*const char *name, */
+ &idx, /* int *idx, */
+ H5IOcounter,
+ &count)<0){}
+ //if(nitems!=count){
+ //printf("getndatasets: nitems{%d}!=count{%d}\n",
+ // nitems,count);
+ //}
+ nitems = count; // just for internal bookkeeping
+ return count;
+}
+
+void H5IO::getdatasetname(int _index, // in
+ char *name){ // out
+ H5IO_getname_t getn;
+ int idx=_index;
+ getn.index=_index; getn.name=name; getn.count=_index;
+ while(H5Giterate(file, /* hid_t loc_id, */
+ "/", /*const char *name, */
+ &idx, /* int *idx, */
+ H5IOgetname,
+ &getn)<0){}
+}
+
+void H5IO::enddataspace(){
+ if(!dataspacevalid) return;
+ dataspacevalid=0;
+ for(int i=0;i<rankf;i++) dimsf[i]=0;
+ rankf=0;
+ H5Sclose(dataspace);
+}
+void H5IO::enddatatype(){
+ if(!datatypevalid) return;
+ datatypevalid=0;
+ currentdatatype = IObase::Error;
+ H5Tclose(datatype);
+}
+
+// This is broken: It must create a different name for each dataset
+// for the purpose of indexing. So the "name" as it is passed here
+// should actually be an attribute of the dataset which is tacked on
+// right here.
+int H5IO::createdataset(char *name,IObase::DataType nt,int rank,CONST int *dims){
+ //printf("++createdataset index=%u\n",index);
+ createdataspace(rank,dims);
+ createdatatype(nt);
+ //printf("+++createdataset index=%u\n",index);
+ // dump the old one and create a new one
+ dataset = H5Dcreate(file, name, datatype, dataspace,
+ H5P_DEFAULT);
+ datasetvalid=1;
+ return 1;
+}
+
+int H5IO::createdataset(IObase::DataType nt,int rank,CONST int *dims){
+ //printf("++createdataset index=%u\n",index);
+ createdataspace(rank,dims);
+ createdatatype(nt);
+ //printf("+++createdataset index=%u\n",index);
+ // dump the old one and create a new one
+ char buffer[32];
+ sprintf(buffer,"H5IO-Dataset%u",index); // current index in file
+ //printf("Creating dataset [%s]\n",buffer);
+ dataset = H5Dcreate(file,buffer, datatype, dataspace,
+ H5P_DEFAULT);
+ datasetvalid=1;
+ return 1;
+}
+
+int H5IO::getdatasetinfo(int &rank, int *dims, IObase::DataType &nt){
+ if(!datasetvalid) return 0;
+ rank = rankf;
+ //printf("getdatasetinfo: Rankf = %u dimsf= %u %u %u\n",
+ // (int)rankf,(int)dimsf[0],(int)dimsf[1],(int)dimsf[2]);
+ for(int i=0;i<rank;i++){
+ dims[i]=dimsf[i];
+ //printf("[%u] %u:%u ",i,dims[i],dimsf[i]);
+ }
+ //puts("<---were copied dims");
+ nt = H5DataType2DataType(datatype);
+ return 1;
+}
+
+void H5IO::enddataset(){
+ if(!datasetvalid) return;
+ H5Dclose(dataset);
+ datasetvalid=0;
+}
+
+H5IO::H5IO(CONST char *fname,AccessMode access):IObase(fname,access),filevalid(0),datasetvalid(0),dataspacevalid(0),datatypevalid(0),hasread(0){
+ filevalid=1;
+ switch(accessmode){
+ case Read:
+ file=H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
+ nitems = getndatasets();
+ break;
+ case Write:
+ file=H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+ nitems = 0;
+ break;
+ case Append:
+ file=H5Fopen(fname, H5F_ACC_RDWR, H5P_DEFAULT);
+ nitems = getndatasets();
+ break;
+ default:
+ filevalid=0; // set filevalid flag to failure value
+ puts("H5IO: constructor... invalid accessmode");
+ break;
+ }
+}
+
+H5IO::~H5IO(){
+ // printf("Destroying H5 file fid=%u, sid=%u\n",fid,sid);
+ enddataset(); // close all dataset and datatype IDs which are open
+ enddatatype();
+ enddataspace();
+ if(filevalid>=0) H5Fclose(file);
+ filevalid=0;
+}
+
+int H5IO::isValid() { return filevalid; }
+
+int H5IO::write(IObase::DataType typeID,int rank,CONST int *dims,void *data){
+ hasread=0;
+ //printf("++Write index=%u\n",index);
+ createdataset(typeID,rank,dims);
+ status = H5Dwrite(dataset, DataType2H5(typeID), H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, data);
+ enddataset(); // commit it now
+ return status;
+}
+
+//int H5IO::write(char *name, IObase::DataType typeID,int rank,CONST int *dims,void *data){
+// hasread=0;
+// createdataset(name,typeID,rank,dims);
+// return status = H5Dwrite(dataset, DataType2H5(typeID), H5S_ALL, H5S_ALL,
+// H5P_DEFAULT, data);
+//}
+
+int H5IO::readInfo(char *name,IObase::DataType &typeID,int &rank,int *dims,int maxdims){
+
+ // name shouls be attribute "long_name");
+ if(hasread){
+ //printf("hasread=1, so get next dataset index %u\n",index+1);
+ hasread=0;
+ selectdataset(index+1);
+ }
+ else {
+ //printf("hasread=0, so select current index for dataset %u\n",index);
+ selectdataset((int)index);
+ }
+ getdatasetinfo(rank,dims,typeID);
+ //sprintf(name,"H5IO-Dataset%u",index);
+ getdatasetname(index,name);
+ hasread=1;
+ return 1;
+}
+
+int H5IO::readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims){
+ // name is an attribute "long_name");
+ if(hasread){
+ hasread=0;
+ selectdataset(index+1);
+ }
+ else {
+ selectdataset((int)index);
+ }
+ getdatasetinfo(rank,dims,typeID);
+ hasread=1;
+ return 1;
+}
+
+int H5IO::read(void *data){
+ selectdataset(index); // make certain its selected
+ // we will be getting all of the dataset
+ //SDgetinfo(sid,name,&rank,dims,&nt,&natt);
+ // set up memspace
+ hid_t memspace = H5Screate_simple(rankf,dimsf,NULL);
+ //printf("rankf=%u dimsf=%u:%u:%u\n",(int)rankf,
+ // (int)dimsf[0],(int)dimsf[1],(int)dimsf[2]);
+ // printf("Data = %u\n",data);
+ // if(!memspace) puts("no memspace");
+ //if(!dataset) puts("no dataset");
+ status = H5Dread(dataset,DataType2H5(H5DataType2DataType(datatype)),
+ memspace,dataspace,H5P_DEFAULT,data);
+ // printf("H5Dread status = %d\n",status);
+ hasread=1;
+ return status;
+}
+
+int H5IO::seek(int i) { selectdataset((int)i); hasread=0; return index; }
+
+int H5IO::nDatasets(){ // not completely correct due to coordvar's
+ // must scan for coordvar's and eliminate them from the count.
+ // int32 ndatasets,nattribs;
+ //SDfileinfo(fid,&ndatasets,&nattribs);
+ // return (int)ndatasets; //?
+ return getndatasets();
+}
+
+int H5IO::writeAnnotation(CONST char *annotation){
+#if 0
+ select((int)index); // select if not already selected
+ int32 ref=SDidtoref(sid);
+ return (int)DFANputlabel(filename,DFTAG_NDG,ref,(char*)annotation);
+#endif
+}
+
+int H5IO::readAnnotationInfo(int number,int &length){
+#if 0
+ select(index);
+ int32 ref=SDidtoref(sid);
+ length=(int)DFANgetlablen(filename,DFTAG_NDG,ref);
+ return length;
+#endif
+ return 1;
+}
+
+int H5IO::readAnnotation(int number,char *annotation,int maxlen){
+#if 0
+ // number=0; // How do I get the number of annotations availible?
+ // use get lablist to get list of tags
+ number=0; // number is ALWAYS 0 for hdf files
+ select(index);
+ int32 ref=SDidtoref(sid);
+ return (int)DFANgetlabel(filename,DFTAG_NDG,ref,annotation,maxlen);
+#endif
+ return 1;
+}
+
+
+int H5IO::nAnnotations(){
+#if 0
+ select(index);
+ int32 ref=SDidtoref(sid);
+ if(DFANgetlablen(filename,DFTAG_NDG,ref)<=0) return 0; // no labels found
+ return 1; // always 1 annotation per object limit for H5 is appears
+#endif
+ return 1;
+}
+
+int H5IO::writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data){
+ //printf("writeAttrib index=%u\n",index);
+ selectdataset(index); // make sure it is selected
+ //printf("\tindex=%u\n",index);
+ // create a datashape
+ hsize_t dimsa[2]={0,0};
+ dimsa[0]=length;
+ hid_t shape = H5Screate_simple(1, dimsa, NULL);
+ hid_t attrib = H5Acreate(dataset,name,DataType2H5(typeID),shape,H5P_DEFAULT);
+ H5Awrite(attrib, DataType2H5(typeID), data);
+ H5Aclose(attrib);
+ H5Sclose(shape);
+ return 1;
+}
+
+int H5IO::readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen){
+ selectdataset(index); // make sure current dataset is selected
+ hid_t attrib = H5Aopen_idx(dataset,number);
+ hid_t atype = H5Aget_type(attrib);
+ hid_t ashape = H5Aget_space(attrib);
+ H5Aget_name(attrib,maxnamelen,name);
+ hsize_t ranka = H5Sget_simple_extent_ndims(ashape);
+ // rank should always be 1;
+ hsize_t dimsa[5];
+ H5Sget_simple_extent_dims(ashape,dimsa,NULL);
+ typeID = H5DataType2DataType(atype);
+ nelem = dimsa[0]; // single-dimensional array for attributes
+
+ H5Tclose(atype);
+ H5Sclose(ashape);
+ H5Aclose(attrib);
+ return 1;
+}
+
+struct H5IOatt_name2index_t {
+ char *name;
+ int count;
+};
+herr_t H5IOattr_name2index(hid_t group_id,
+ const char *member_name,
+ void *operator_data){
+ H5IOatt_name2index_t *s=(H5IOatt_name2index_t*)operator_data;
+ s->count++;
+ if(!strcmp(member_name,s->name))
+ return s->count;
+ else{
+ return 0;
+ }
+}
+
+herr_t H5IOattr_count(hid_t group_id,
+ const char *member_name,
+ void *operator_data){
+ // cycle through all attribs as a dummy counter
+ int *count = (int *)operator_data;
+ (*count)++;
+ return 0;
+}
+
+int H5IO::readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem){
+ selectdataset(index); // make sure current dataset is selected
+ H5IOatt_name2index_t stype;
+ stype.name=(char*)name;
+ stype.count=0;
+ unsigned idx=0;
+ int aindex = H5Aiterate(dataset,&idx,H5IOattr_name2index,&stype);
+ if(aindex<=0) return -1;
+ aindex--; // index is one more than the actual index of the item
+ hid_t attrib = H5Aopen_name(dataset,name);
+ hid_t atype = H5Aget_type(attrib);
+ hid_t ashape = H5Aget_space(attrib);
+ hsize_t ranka = H5Sget_simple_extent_ndims(ashape);
+ // rank should always be 1;
+ hsize_t dimsa[5];
+ H5Sget_simple_extent_dims(ashape,dimsa,NULL);
+ typeID = H5DataType2DataType(atype);
+ nelem = dimsa[0]; // single-dimensional array for attributes
+
+ H5Tclose(atype);
+ H5Sclose(ashape);
+ H5Aclose(attrib);
+ return aindex;
+}
+
+int H5IO::readAttribute(int number,void *data){
+ // now must openIDX again
+ selectdataset(index); // just to be sure we've got data
+ hid_t attrib = H5Aopen_idx(dataset,number);
+ hid_t atype = H5Aget_type(attrib);
+ H5Aread(attrib,DataType2H5(H5DataType2DataType(atype)),data);
+ H5Tclose(atype);
+ H5Aclose(attrib);
+ return 1;
+}
+
+int H5IO::nAttributes(){
+ selectdataset(index);
+ unsigned idx=0;
+ int count=0;
+ int aindex = H5Aiterate(dataset,&idx,H5IOattr_count,&count);
+ return count;
+}
+//================Chunking Interface-----------------------
+int H5IO::reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){
+#if 0
+ hasread=0;
+ for(int i=0;i<rank;i++) chunkdims[i]=dims[i];
+ create(rank,dims,typeID);
+ current_rank=rank;
+ return 1;
+#endif
+ return 1;
+}
+
+int H5IO::writeChunk(CONST int *dims,CONST int *origin,void *data){
+#if 0
+ int32 horigin[5]={0,0,0,0,0};
+ int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ int32 hdims[5]={0,0,0,0,0};
+ int32 rank = current_rank;
+ for(int i=0;i<rank;i++) { hdims[i]=dims[i]; horigin[i]=origin[i]; }
+ return (int)SDwritedata(sid,horigin,stride,hdims,data);
+#endif
+ return 1;
+}
+
+
+int H5IO::readChunk(CONST int *dims,CONST int *origin,void *data){
+#if 0
+ int32 horigin[5]={0,0,0,0,0};
+ int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ int32 rank,nt,natt,hdims[5]={0,0,0,0,0};
+ char name[128];
+ select(index);
+ SDgetinfo(sid,name,&rank,hdims,&nt,&natt);
+ for(int i=0;i<rank;i++) {hdims[i]=dims[i]; horigin[i]=origin[i];}
+ return (int)SDreaddata(sid,horigin,stride,hdims,data);
+#endif
+return 1;
+}
+
+//===============F77 Interface
+Long8 f_h5_open (char *file,char *accessname,int flen,int alen){
+ // would have used tolower(), but it doesn't exist everywhere.... :(
+ IObase::AccessMode mode;
+ if(*accessname=='R' || *accessname=='r')
+ mode=IObase::Read;
+ else if(*accessname=='W' || *accessname=='w' ||
+ *accessname=='C' || *accessname=='c')
+ mode=IObase::Write;
+ else if(*accessname=='A' || *accessname=='a')
+ mode=IObase::Append;
+ else {
+ fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n",
+ accessname,file);
+ return 0;
+ }
+ IObase *fid=new H5IO(file,mode);
+ if(fid->isValid())
+ return (Long8)fid;
+ else
+ delete fid; // file open failed
+ return 0;
+}
+
+Long8 f_h5_openr (char *file,int flen){
+ file[flen]='\0'; // null terminate
+ return (Long8)(new H5IO(file,IObase::Read));
+}
+
+Long8 f_h5_openw (char *file,int flen){
+ file[flen]='\0'; // null terminate
+ return (Long8)(new H5IO(file,IObase::Create));
+}
+
+Long8 f_h5_opena (char *file,int flen){
+ file[flen]='\0'; // null terminate
+ return (Long8)(new H5IO(file,IObase::Append));
+}
+
+IOFile H5IOopen (char *file,char *accessname){
+ // Parse all of the ansi stdio access option strings
+ IObase::AccessMode mode;
+ if(!strcmp(accessname,"read") ||
+ !strcmp(accessname,"r") ||
+ !strcmp(accessname,"rb"))
+ mode=IObase::Read;
+ else if(*accessname=='a')
+ mode=IObase::Append;
+ else if(!strcmp(accessname,"write") ||
+ !strcmp(accessname,"create") ||
+ !strcmp(accessname,"wb"))
+ mode = IObase::Write;
+ else if(!strcmp(accessname,"w+") ||
+ !strcmp(accessname,"w+b") ||
+ !strcmp(accessname,"wb+"))
+ mode=IObase::Append;
+ else{
+ fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n",
+ accessname,file);
+ return 0;
+ }
+ IObase *fid=new H5IO(file,mode);
+ if(fid->isValid())
+ return (IOFile)fid;
+ else
+ delete fid; // file open failed
+ return 0; // unknown option
+}
+
+IOFile H5IOopenRead (char *file){
+ return (IOFile)(new H5IO(file,IObase::Read));
+}
+
+IOFile H5IOopenWrite (char *file){
+ return (IOFile)(new H5IO(file,IObase::Write));
+}
+
+IOFile H5IOopenAppend (char *file){
+ return (IOFile)(new H5IO(file,IObase::Append));
+}
diff --git a/src/H5IO.h b/src/H5IO.h
new file mode 100644
index 0000000..28637c9
--- /dev/null
+++ b/src/H5IO.h
@@ -0,0 +1,12 @@
+#ifndef __H5IO_H_
+#define __H5IO_H_
+
+#include "IOProtos.h"
+#include "Arch.h"
+
+IOFile H5IOopen PROTO((char *filename,char *accessname));
+IOFile H5IOopenRead PROTO((char *filename));
+IOFile H5IOopenWrite PROTO((char *filename));
+IOFile H5IOopenAppend PROTO((char *filename));
+
+#endif
diff --git a/src/H5IO.hh b/src/H5IO.hh
new file mode 100644
index 0000000..97ded33
--- /dev/null
+++ b/src/H5IO.hh
@@ -0,0 +1,130 @@
+#ifndef __H5IO_HH_
+#define __H5IO_HH_
+#include "Arch.h"
+#include "IO.hh"
+
+/*
+H5stream for networking & message passing!
+This is not the same as HDF5 because you cannot ask for a subset of the
+data that arrives. You can only ask what is in the pipe and recieve it or
+dump it. This is only for marshalling and unmarshalling datastructures
+into a network pipe for transport in a platform independent manner (ie.
+use the HDF5 data translation mechanisms)
+
+Should have pluggable transport layer!
+Just provide a VFT with read/write/connect/terminate
+ perhaps block/nonblock/and poll for connections too?
+ If we can make do with blocking that should be sufficient
+ Also need an exception handling mechanism in the embeded/pluggable
+ transport.
+
+Transport policies should also be pluggable. They would be
+* periodic (timer-based)
+* synchronous/rendezvous (MPI or Occam-like)
+* transport on write (active message push)
+* transport on read (on-demand-based active message request w/ round-trip)
+* virtual shared memory background async transport (implicit sync on read or sync on write, or explicit sync or no-sync)
+
+Query Policy
+* Blocking
+* nonblocking
+
+Buffer Policy
+* WriteBufferSize
+* ReadBufferSize
+
+ */
+#include <hdf5.h>
+
+class H5IO : public IObase {
+ // *** Flags for usage of each type
+ char filevalid,datasetvalid,datatypevalid,dataspacevalid;
+ IObase::DataType currentdatatype;
+ hid_t file, dataset; /* file and dataset handles */
+ hid_t datatype, dataspace; /* handles */
+ hsize_t dimsf[5],rankf; /* current dataset dimensions */
+ herr_t status;
+
+ hid_t DataType2H5(IObase::DataType nt); // in-memory type is *always* native
+ // IObase::DataType H52DataType(hid_t &nt);
+ IObase::DataType H5DataType2DataType(hid_t nt);
+ int createdataspace(int rank,CONST int *dims);
+ int createdatatype(IObase::DataType dt);
+ int selectdataset(int i);
+ // void selectdataset(char *name);
+ int createdataset(char *name,IObase::DataType nt,
+ int rank,CONST int *dims);
+ int createdataset(IObase::DataType nt,int rank,CONST int *dims);
+ int getdatasetinfo(int &rank, int *dims,
+ IObase::DataType &nt);
+ void enddataspace();
+ void enddatatype();
+ void enddataset();
+ int getndatasets();
+ void getdatasetname(int _index, // in
+ char *name);
+
+
+ int chunkdims[5];
+ int hasread;
+public:
+ H5IO(CONST char *fname,AccessMode access);
+ virtual ~H5IO();
+ virtual int isValid();
+ virtual int write(IObase::DataType typeID,int rank,CONST int *dims,void *data);
+ // virtual int write(char *name,IObase::DataType typeID,int rank,CONST int *dims,void *data);
+ virtual int readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims=3);
+ virtual int readInfo(char *name,IObase::DataType &typeID,int &rank,int *dims,int maxdims=3);
+ virtual int read(void *data);
+ virtual int seek(int i);
+ virtual int nDatasets();
+ virtual int writeAnnotation(CONST char *annotation);
+ virtual int readAnnotationInfo(int number,int &length); // NEW
+ virtual int readAnnotation(int index,char *annotation,int maxlen); // changed
+ virtual int nAnnotations(); // New
+
+ virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data); // New
+ virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128); // New
+ virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem); // New
+ virtual int readAttribute(int number,void *data); // New
+ // virtual Long readAttribute(CONST char *name,void *data);
+ virtual int nAttributes(); // New
+
+ //-----------------Chunking Utilities..................
+ virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims);
+ virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ //-----------------Streaming interface (for PANDA, Sockets & MPIO).........
+ virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims) {return -1; }
+ virtual int writeStream(void *data,int length){ return -1; } // not implemented yet
+ virtual int readStream(void *data,int length) { return -1; } // not implemented yet
+ //----------------Special HDF5-specific methods.........
+ // will put some hyperslab definition stuff here
+};
+
+#define f_h5_open F77NAME(h5_open_,h5_open,H5_OPEN)
+#define f_h5_openr F77NAME(h5_openr_,h5_openr,H5_OPENR)
+#define f_h5_openw F77NAME(h5_openw_,h5_openw,H5_OPENW)
+#define f_h5_opena F77NAME(h5_opena_,h5_opena,H5_OPENA)
+
+extern "C" {
+#ifdef CRAY // Note: This isn't really implemented yet...
+#include <fortran.h>
+ Long8 f_h5_open(_fcd fcfilename,_fcd accessname);
+ Long8 f_h5_openr(_fcd fcfilename);
+ Long8 f_h5_openw(_fcd fcfilename);
+ Long8 f_h5_opena(_fcd fcfilename);
+#else
+ Long8 f_h5_open(char *file,char *access,int flen,int alen);
+ Long8 f_h5_openr(char *file,int flen);
+ Long8 f_h5_openw(char *file,int flen);
+ Long8 f_h5_opena(char *file,int flen);
+#endif
+#include "H5IO.h"
+}
+/*
+ long io_open_ieee_(constCONST char *file,constCONST char *access,int flen,int alen);
+*/
+
+#endif
+
diff --git a/src/H5IOwriter.cc b/src/H5IOwriter.cc
new file mode 100644
index 0000000..2b133fe
--- /dev/null
+++ b/src/H5IOwriter.cc
@@ -0,0 +1,84 @@
+/*
+ * This example writes data to the HDF5 file.
+ * Data conversion is performed during write operation.
+ */
+#include <H5IO.hh>
+#include <hdf5.h>
+
+#define FILE "SDS.h5"
+#define DATASETNAME "IntArray"
+#define NX 5 /* dataset dimensions */
+#define NY 6
+#define RANK 2
+/*
+Perhaps support a filtration/pattern matching architecture which
+recognizes particular patterns of values in the file and offers those
+patterns as a new typename in the architecture or even a particular
+callback. So for instance you could have a group of "dataset" with
+"edgecoords" is a rectilinear dataset. Otherwise we'll need to
+match groupnames? Could have a "type" attribute which disambiguates
+this because each object must have a unique text name.
+ */
+
+main (void)
+{
+ // int data[NX][NY]; /* data to write */
+ int *data = new int[NX*NY];
+ int i, j;
+ int idx,rval;
+ int dims[3];
+ int rank=RANK;
+
+ /*
+ * Data and output buffer initialization.
+ */
+ for (j = 0; j < NX; j++) {
+ for (i = 0; i < NY; i++)
+ data[j*NY + i] = i + j;
+ }
+ /*
+ * 0 1 2 3 4 5
+ * 1 2 3 4 5 6
+ * 2 3 4 5 6 7
+ * 3 4 5 6 7 8
+ * 4 5 6 7 8 9
+ */
+
+ /*
+ * Create a new file using H5F_ACC_TRUNC access,
+ * default file creation properties, and default file
+ * access properties.
+ */
+ H5IO *file = new H5IO(FILE,IObase::Write);
+ /*
+ * Describe the size of the array and create the data space for fixed
+ * size dataset.
+ */
+ dims[0] = NX;
+ dims[1] = NY;
+ float attr[3]={1.0,2.0,3.0};
+ file->write(IObase::Int32,2,dims,data);
+ file->writeAttribute("floatattr",IObase::Float32,3,attr);
+ file->write(IObase::Int32,2,dims,data);
+ delete file;
+
+ puts("**********************Now read the file*******************");
+ /* typedef herr_t *(H5G_operator_t)(hid_t group_id,
+ const char *member_name,
+ void *operator_data // in,out); */
+ file = new H5IO(FILE,IObase::Read);
+ int nds = file->nDatasets();
+ printf("number of datasets = %u\n",nds);
+ for(int i=0;i<nds;i++){
+ char name[32];
+ IObase::DataType datatype;
+ int rank,dims[3];
+ file->readInfo(name,datatype,rank,dims);
+ printf("name = [%s] rank=%u dims=%u,%u\n",name,rank,dims[0],dims[1]);
+ if(datatype==IObase::Int32) puts("\tcorrect type Int32\n");
+ else puts("\ttype failed");
+ printf("\tnattribs=%u\n",file->nAttributes());
+ }
+ delete file;
+ return 0;
+}
diff --git a/src/H5writer.c b/src/H5writer.c
new file mode 100644
index 0000000..2f133f7
--- /dev/null
+++ b/src/H5writer.c
@@ -0,0 +1,175 @@
+/*
+ * This example writes data to the HDF5 file.
+ * Data conversion is performed during write operation.
+ */
+// #include <H5IO.hh>
+#include <hdf5.h>
+#define WRITE_H5
+#define FILE "SDS.h5"
+#define DATASETNAME "IntArray"
+#define NX 5 /* dataset dimensions */
+#define NY 6
+#define RANK 2
+/*
+Perhaps support a filtration/pattern matching architecture which
+recognizes particular patterns of values in the file and offers those
+patterns as a new typename in the architecture or even a particular
+callback. So for instance you could have a group of "dataset" with
+"edgecoords" is a rectilinear dataset. Otherwise we'll need to
+match groupnames? Could have a "type" attribute which disambiguates
+this because each object must have a unique text name.
+ */
+
+herr_t GroupOp(hid_t group_id,
+ const char *member_name,
+ void *operator_data){
+ hid_t dataset,space,datatype;
+ hsize_t rank, dims[5];
+ H5T_class_t typeclass;
+ size_t typesize;
+ int i;
+
+ printf("GroupOp: member_name = %s id %u\n",member_name,group_id);
+ /* get info on a particular member */
+ dataset = H5Dopen(group_id,member_name);
+ space = H5Dget_space(dataset);
+ datatype = H5Dget_type(dataset);
+ rank = H5Sget_simple_extent_ndims(space);
+ H5Sget_simple_extent_dims(space,dims,NULL);
+ printf("\tndims=%d Dims ",rank);
+ for(i=0;i<rank;i++)
+ printf("%u ",dims[i]);
+ puts("");
+
+ typeclass = H5Tget_class(datatype);
+ typesize = H5Tget_size(datatype);
+
+ printf("\tNbytes=%u Type = ",typesize);
+ switch(typeclass){
+ case H5T_INTEGER:
+ puts("Int");
+ break;
+ case H5T_FLOAT:
+ puts("Float");
+ break;
+ case H5T_TIME:
+ puts("Time");
+ break;
+ case H5T_STRING:
+ puts("String");
+ break;
+ case H5T_BITFIELD:
+ puts("Bitfield");
+ break;
+ case H5T_OPAQUE:
+ puts("Opaque");
+ break;
+ case H5T_COMPOUND:
+ default:
+ puts("Unknown");
+ break;
+ }
+
+ H5Sclose(space);
+ H5Tclose(datatype);
+ H5Dclose(dataset);
+ return 0;
+}
+
+main (void)
+{
+ hid_t file, dataset; /* file and dataset handles */
+ hid_t datatype, dataspace; /* handles */
+ hsize_t dimsf[2]; /* dataset dimensions */
+ herr_t status;
+ int data[NX][NY]; /* data to write */
+ int i, j;
+ int idx,rval;
+
+ /*
+ * Data and output buffer initialization.
+ */
+ for (j = 0; j < NX; j++) {
+ for (i = 0; i < NY; i++)
+ data[j][i] = i + j;
+ }
+ /*
+ * 0 1 2 3 4 5
+ * 1 2 3 4 5 6
+ * 2 3 4 5 6 7
+ * 3 4 5 6 7 8
+ * 4 5 6 7 8 9
+ */
+
+ /*
+ * Create a new file using H5F_ACC_TRUNC access,
+ * default file creation properties, and default file
+ * access properties.
+ */
+#ifdef WRITE_H5
+ file = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+
+/*
+ * Describe the size of the array and create the data space for fixed
+ * size dataset.
+ */
+ dimsf[0] = NX;
+ dimsf[1] = NY;
+ dataspace = H5Screate_simple(RANK, dimsf, NULL);
+
+ /*
+ * Define datatype for the data in the file.
+ * We will store little endian INT numbers.
+ */
+ datatype = H5Tcopy(H5T_NATIVE_INT);
+ status = H5Tset_order(datatype, H5T_ORDER_LE);
+
+ /*
+ * Create a new dataset within the file using defined dataspace and
+ * datatype and default dataset creation properties.
+ */
+ dataset = H5Dcreate(file, DATASETNAME, datatype, dataspace,
+ H5P_DEFAULT);
+
+ /*
+ * Write the data to the dataset using default transfer properties.
+ */
+ status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, data);
+ H5Dclose(dataset);
+
+ // writing second ------------------------------------------
+ dataset = H5Dcreate(file, "anothername", datatype, dataspace,
+ H5P_DEFAULT);
+
+ /*
+ * Write the data to the dataset using default transfer properties.
+ */
+ status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, data);
+
+ /*
+ * Close/release resources.
+ */
+ H5Sclose(dataspace);
+ H5Tclose(datatype);
+ H5Dclose(dataset);
+ H5Fclose(file);
+#endif
+ /* typedef herr_t *(H5G_operator_t)(hid_t group_id,
+ const char *member_name,
+ void *operator_data // in,out); */
+ file = H5Fopen(FILE, H5F_ACC_RDONLY, H5P_DEFAULT);
+ printf("FileID=%u\n",file);
+ idx=0;
+
+ rval=H5Giterate(file, /* hid_t loc_id, */
+ "/", /*const char *name, */
+ &idx, /* int *idx, */
+ GroupOp,
+ NULL);
+ printf("Iteration info was %u rval=%d\n",idx,rval);
+ puts("done");
+ H5Fclose(file);
+ return 0;
+}
diff --git a/src/HDFIO.cc b/src/HDFIO.cc
new file mode 100644
index 0000000..5005c70
--- /dev/null
+++ b/src/HDFIO.cc
@@ -0,0 +1,413 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+//#include <hdf.h>
+#include "HDFIO.hh"
+#include <mfhdf.h>
+
+int32 HDFIO::DataType2HDF(IObase::DataType nt){
+ switch(nt){
+ case Int8:
+ return DFNT_INT8; // means data
+ case Char8: // distinct from INT8..
+ return DFNT_CHAR8; // means string
+ case Float32:
+ return DFNT_FLOAT32;
+ case Float64:
+ return DFNT_FLOAT64;
+ case Int32:
+ return DFNT_INT32;
+ case Int64:
+ return DFNT_INT64;
+ case Int16:
+ return DFNT_INT16;
+ case uInt8:
+ return DFNT_UINT8;
+ case uInt16:
+ return DFNT_UINT16;
+ case uInt32:
+ return DFNT_UINT32;
+ case uInt64:
+ return DFNT_UINT64;
+ case Char16: // unicode character type
+ return DFNT_CHAR16;
+ }
+ printf("HDFIO::HDF2DataType(): Don't recognize type %d\n",(int)nt);
+ return -1;
+}
+
+IObase::DataType HDFIO::HDF2DataType(int32 nt){
+ switch(nt){
+ case DFNT_INT8:
+ return Int8;
+ case DFNT_CHAR8:
+ return Char8;
+ case DFNT_FLOAT32:
+ return Float32;
+ case DFNT_FLOAT64:
+ return Float64;
+ case DFNT_INT32:
+ return Int32;
+ case DFNT_INT64:
+ return Int64;
+ case DFNT_INT16:
+ return Int16;
+ case DFNT_UINT8:
+ case DFNT_UCHAR8:
+ return uInt8;
+ case DFNT_UINT16:
+ return uInt16;
+ case DFNT_UINT32:
+ return uInt32;
+ case DFNT_UINT64:
+ return uInt64;
+ case DFNT_CHAR16:
+ return Char16;
+ }
+ printf("HDFIO::HDF2DataType(): Don't recognize type %d\n",(int)nt);
+ return Error;
+}
+
+void HDFIO::create(int rank,CONST int *dims,IObase::DataType nt){
+ int32 hdims[5];
+ if(sid>=0) SDendaccess(sid);
+ nitems++;
+ index=nitems-1;
+ for(int i=0;i<rank;i++) hdims[i]=dims[i];
+ sid=SDcreate(fid,"",DataType2HDF(nt),rank,hdims);
+}
+
+void HDFIO::select(int i){
+ if(index==i && sid>=0)
+ return;
+ if(index>=nitems) index=nitems-1;
+ if(index<0) index=0;
+ if(sid>=0) SDendaccess(sid);
+ sid=SDselect(fid,i);
+ index=i;
+}
+void HDFIO::endaccess(){
+ if(sid<0) return;
+ SDendaccess(sid);
+ sid=-1;
+}
+
+HDFIO::HDFIO(CONST char *fname,AccessMode access):IObase(fname,access),sid(-1),fid(-1),hasread(0){
+ switch(accessmode){
+ case Read:
+ fid=SDstart(filename,DFACC_RDONLY);
+ break;
+ case Write:
+ fid=SDstart(filename,DFACC_CREATE);
+ break;
+ case Append:
+ fid=SDstart(filename,DFACC_RDWR);
+ break;
+ default:
+ puts("HDFIO: constructor... invalid accessmode");
+ break;
+ }
+}
+
+HDFIO::~HDFIO(){
+ // printf("Destroying HDF file fid=%u, sid=%u\n",fid,sid);
+ endaccess();
+ if(fid>=0) SDend(fid);
+ // SDend(fid);
+}
+
+int HDFIO::isValid() { if(fid>=0) return 1; else return 0; }
+
+int HDFIO::write(IObase::DataType typeID,int rank,CONST int *dims,void *data){
+ int32 origin[5]={0,0,0,0,0};
+ int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ int32 hdims[5]={0,0,0,0,0};
+ hasread=0;
+ for(int i=0;i<rank;i++) hdims[i]=dims[i];
+ create(rank,dims,typeID);
+ //printf("write: sdsid=%u index=%u\n",sid,index);
+ current_rank=rank;
+ return (int)SDwritedata(sid,origin,stride,hdims,data);
+}
+
+int HDFIO::readInfo(char *name,IObase::DataType &typeID,int &rank,int *dims,int maxdims){
+ int32 nt,nattr,hrank;
+ int32 hdims[5];
+ if(hasread)
+ select(index+1);
+ else
+ select((int)index);
+ SDgetinfo(sid,name,&hrank,hdims,&nt,&nattr);
+ rank=(int)hrank;
+ for(int i=0;i<rank && i<maxdims;i++) dims[i]=(int)(hdims[i]);
+ typeID=HDF2DataType(nt);
+ hasread=1;
+ return 1;
+}
+
+int HDFIO::readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims){
+ int32 nt,nattr,hrank;
+ int32 hdims[5];
+ char name[128];
+ if(hasread)
+ select(index+1);
+ else
+ select((int)index);
+ SDgetinfo(sid,name,&hrank,hdims,&nt,&nattr);
+ rank=(int)hrank;
+ for(int i=0;i<rank && i<maxdims;i++) dims[i]=(int)(hdims[i]);
+ typeID=HDF2DataType(nt);
+ // index++?
+ hasread=1;
+ return 1;
+}
+
+int HDFIO::read(void *data){
+ int32 origin[5]={0,0,0,0,0};
+ int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ int32 rank,dims[5],nt,natt;
+ char name[128];
+ select(index); // make certain its selected
+ SDgetinfo(sid,name,&rank,dims,&nt,&natt);
+ hasread=1;
+ return (int)SDreaddata(sid,origin,stride,dims,data);
+}
+
+int HDFIO::seek(int i) { select((int)i); hasread=0; return index; }
+
+int HDFIO::nDatasets(){ // not completely correct due to coordvar's
+ // must scan for coordvar's and eliminate them from the count.
+ int32 ndatasets,nattribs;
+ SDfileinfo(fid,&ndatasets,&nattribs);
+ return (int)ndatasets; //?
+}
+
+int HDFIO::writeAnnotation(CONST char *annotation){
+ select((int)index); // select if not already selected
+ int32 ref=SDidtoref(sid);
+ return (int)DFANputlabel(filename,DFTAG_NDG,ref,(char*)annotation);
+}
+
+int HDFIO::readAnnotationInfo(int number,int &length){
+ select(index);
+ int32 ref=SDidtoref(sid);
+ length=(int)DFANgetlablen(filename,DFTAG_NDG,ref);
+ return length;
+}
+
+int HDFIO::readAnnotation(int number,char *annotation,int maxlen){
+ // number=0; // How do I get the number of annotations availible?
+ // use get lablist to get list of tags
+ number=0; // number is ALWAYS 0 for hdf files
+ select(index);
+ int32 ref=SDidtoref(sid);
+ return (int)DFANgetlabel(filename,DFTAG_NDG,ref,annotation,maxlen);
+}
+
+
+int HDFIO::nAnnotations(){
+ select(index);
+ int32 ref=SDidtoref(sid);
+ if(DFANgetlablen(filename,DFTAG_NDG,ref)<=0) return 0; // no labels found
+ return 1; // always 1 annotation per object limit for HDF is appears
+}
+
+int HDFIO::writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data){
+ select(index); // select if not already selected
+ //printf("write attrib: sdsid=%u index=%u\n",sid,index);
+ return (int)SDsetattr(sid,(char*)name,DataType2HDF(typeID),(int32)length,data);
+}
+
+int HDFIO::readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen){
+ select(index);
+ int32 numbertype;
+ int32 nelements;
+ int sz= SDattrinfo(sid,number,name,&numbertype,&nelements);
+ typeID=HDF2DataType(numbertype);
+ nelem=(int)nelements;
+ return sz;
+}
+
+int HDFIO::readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem){
+ char fakename[128];
+ select(index);
+ int number=(int)SDfindattr(sid,(char*)name);
+ if(number>0)
+ return readAttributeInfo(number,fakename,typeID,nelem);
+ else return -1;
+}
+
+int HDFIO::readAttribute(int number,void *data){
+ select(index);
+ return (int)SDreadattr(sid,number,data);
+}
+
+int HDFIO::nAttributes(){
+ int32 nt,nattr,rank,dims[5];
+ char name[128];
+ select(index);
+ SDgetinfo(sid,name,&rank,dims,&nt,&nattr);
+ return (int)nattr;
+}
+//================Chunking Interface-----------------------
+int HDFIO::reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){
+ //int32 origin[5]={0,0,0,0,0};
+ //int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ //int32 hdims[5]={0,0,0,0,0};
+ hasread=0;
+ for(int i=0;i<rank;i++) chunkdims[i]=dims[i];
+ create(rank,dims,typeID);
+ current_rank=rank;
+ return 1;
+}
+
+int HDFIO::writeChunk(CONST int *dims,CONST int *origin,void *data){
+ int32 horigin[5]={0,0,0,0,0};
+ int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ int32 hdims[5]={0,0,0,0,0};
+ int32 rank = current_rank;
+ for(int i=0;i<rank;i++) { hdims[i]=dims[i]; horigin[i]=origin[i]; }
+ return (int)SDwritedata(sid,horigin,stride,hdims,data);
+}
+
+
+int HDFIO::readChunk(CONST int *dims,CONST int *origin,void *data){
+ int32 horigin[5]={0,0,0,0,0};
+ int32 stride[5]={1,1,1,1,1}; // kludge... we'll fix later
+ int32 rank,nt,natt,hdims[5]={0,0,0,0,0};
+ char name[128];
+ select(index);
+ SDgetinfo(sid,name,&rank,hdims,&nt,&natt);
+ for(int i=0;i<rank;i++) {hdims[i]=dims[i]; horigin[i]=origin[i];}
+ return (int)SDreaddata(sid,horigin,stride,hdims,data);
+}
+int HDFIO::isCoord() { // for HDFIO only!!
+ select(index); // make sure it has been selected
+ return SDiscoordvar(sid);
+}
+
+int HDFIO::readDimInfo(int dimnumber, char *name, IObase::DataType &datatype, int &length){
+ int32 len,nt,nattribs;
+ length=-1; // initial value
+ // printf("HDFIO:readDimInfo\n");
+ if(sid<0) return -1;
+ int32 dim_id = SDgetdimid(sid,dimnumber);
+ if(dim_id<0) return -1;
+ SDdiminfo(dim_id,name,&len,&nt,&nattribs);
+ //printf("HDFIO: dim_id=%u name=%s len=%u nt=%u nattribs=%u\n",
+ // dim_id,name,len,nt,nattribs);
+ length=len;
+ if(!nt) {
+ datatype=IObase::Float32;
+ }
+ else {// compute custom datatype
+ datatype = HDF2DataType(nt);
+ }
+ return length;
+}
+
+int HDFIO::readDim(int dimnumber, void *dim){
+ if(sid<0) return -1;
+ int32 dim_id = SDgetdimid(sid,dimnumber);
+ if(dim_id<0) return -1;
+ SDgetdimscale(dim_id,dim);
+ return 1;
+}
+
+int HDFIO::writeDim(int dimnumber,IObase::DataType datatype,int length,void *dim){
+ if(sid<0) return -1;
+ int32 dim_id = SDgetdimid(sid,dimnumber);
+ if(dim_id<0) return -1;
+ SDsetdimscale(dim_id,length,DataType2HDF(datatype),dim);
+ return 1;
+}
+
+int HDFIO::writeDimName(int dimnumber,CONST char *name){
+ if(sid<0) return -1;
+ int32 dim_id = SDgetdimid(sid,dimnumber);
+ if(dim_id<0) return -1;
+ SDsetdimname(dim_id,(char *)name);
+ return 1;
+}
+
+//===============F77 Interface
+Long8 f_hdf_open (char *file,char *accessname,int flen,int alen){
+ // would have used tolower(), but it doesn't exist everywhere.... :(
+ IObase::AccessMode mode;
+ if(*accessname=='R' || *accessname=='r')
+ mode=IObase::Read;
+ else if(*accessname=='W' || *accessname=='w' ||
+ *accessname=='C' || *accessname=='c')
+ mode=IObase::Write;
+ else if(*accessname=='A' || *accessname=='a')
+ mode=IObase::Append;
+ else {
+ fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n",
+ accessname,file);
+ return 0;
+ }
+ IObase *fid=new HDFIO(file,mode);
+ if(fid->isValid())
+ return (Long8)fid;
+ else
+ delete fid; // file open failed
+ return 0;
+}
+
+Long8 f_hdf_openr (char *file,int flen){
+ file[flen]='\0'; // null terminate
+ return (Long8)(new HDFIO(file,IObase::Read));
+}
+
+Long8 f_hdf_openw (char *file,int flen){
+ file[flen]='\0'; // null terminate
+ return (Long8)(new HDFIO(file,IObase::Create));
+}
+
+Long8 f_hdf_opena (char *file,int flen){
+ file[flen]='\0'; // null terminate
+ return (Long8)(new HDFIO(file,IObase::Append));
+}
+
+IOFile HDFIOopen (char *file,char *accessname){
+ // Parse all of the ansi stdio access option strings
+ IObase::AccessMode mode;
+ if(!strcmp(accessname,"read") ||
+ !strcmp(accessname,"r") ||
+ !strcmp(accessname,"rb"))
+ mode=IObase::Read;
+ else if(*accessname=='a')
+ mode=IObase::Append;
+ else if(!strcmp(accessname,"write") ||
+ !strcmp(accessname,"create") ||
+ !strcmp(accessname,"wb"))
+ mode = IObase::Write;
+ else if(!strcmp(accessname,"w+") ||
+ !strcmp(accessname,"w+b") ||
+ !strcmp(accessname,"wb+"))
+ mode=IObase::Append;
+ else{
+ fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n",
+ accessname,file);
+ return 0;
+ }
+ IObase *fid=new HDFIO(file,mode);
+ if(fid->isValid())
+ return (IOFile)fid;
+ else
+ delete fid; // file open failed
+ return 0; // unknown option
+}
+
+IOFile HDFIOopenRead (char *file){
+ return (IOFile)(new HDFIO(file,IObase::Read));
+}
+
+IOFile HDFIOopenWrite (char *file){
+ return (IOFile)(new HDFIO(file,IObase::Write));
+}
+
+IOFile HDFIOopenAppend (char *file){
+ return (IOFile)(new HDFIO(file,IObase::Append));
+}
+
diff --git a/src/HDFIO.h b/src/HDFIO.h
new file mode 100644
index 0000000..a3f8f89
--- /dev/null
+++ b/src/HDFIO.h
@@ -0,0 +1,12 @@
+#ifndef __HDFIO_H_
+#define __HDFIO_H_
+
+#include "IOProtos.h"
+#include "Arch.h"
+
+IOFile HDFIOopen PROTO((char *filename,char *accessname));
+IOFile HDFIOopenRead PROTO((char *filename));
+IOFile HDFIOopenWrite PROTO((char *filename));
+IOFile HDFIOopenAppend PROTO((char *filename));
+
+#endif
diff --git a/src/HDFIO.hh b/src/HDFIO.hh
new file mode 100644
index 0000000..5041030
--- /dev/null
+++ b/src/HDFIO.hh
@@ -0,0 +1,79 @@
+#ifndef __HDFIO_HH_
+#define __HDFIO_HH_
+#include "Arch.h"
+#include "IO.hh"
+#include <hdf.h>
+
+class HDFIO : public IObase {
+ int32 fid,sid,current_rank;
+ int32 DataType2HDF(IObase::DataType nt);
+ IObase::DataType HDF2DataType(int32 nt);
+ int chunkdims[5];
+ int hasread;
+ void create(int rank,CONST int *dims,DataType nt);
+ void select(int i);
+ void endaccess();
+public:
+ HDFIO(CONST char *fname,AccessMode access);
+ virtual ~HDFIO();
+ virtual int isValid();
+ virtual int write(IObase::DataType typeID,int rank,CONST int *dims,void *data);
+ virtual int readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims=3);
+ virtual int readInfo(char *name,IObase::DataType &typeID,int &rank,int *dims,int maxdims=3);
+ virtual int read(void *data);
+ virtual int seek(int i);
+ virtual int nDatasets();
+ virtual int writeAnnotation(CONST char *annotation);
+ virtual int readAnnotationInfo(int number,int &length); // NEW
+ virtual int readAnnotation(int index,char *annotation,int maxlen); // changed
+ virtual int nAnnotations(); // New
+
+ virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data); // New
+ virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128); // New
+ virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem); // New
+ virtual int readAttribute(int number,void *data); // New
+ // virtual Long readAttribute(CONST char *name,void *data);
+ virtual int nAttributes(); // New
+
+ //-----------------Chunking Utilities..................
+ virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims);
+ virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ //-----------------Streaming interface (for PANDA, Sockets & MPIO).........
+ virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims) {return -1; }
+ virtual int writeStream(void *data,int length){ return -1; } // not implemented yet
+ virtual int readStream(void *data,int length) { return -1; } // not implemented yet
+ //----------------Special HDF-specific methods.........
+ int isCoord(); // Tells whether the dataset is a coordinate or a dataset
+ int readDimInfo(int dimnumber,char *name, IObase::DataType &datatype, int &length);
+ int readDim(int dimnumber, void *dim);
+ int writeDim(int dimnumber,IObase::DataType datatype,int length,void *dim);
+ int writeDimName(int dimnumber,CONST char *name);
+};
+
+#define f_hdf_open F77NAME(hdf_open_,hdf_open,HDF_OPEN)
+#define f_hdf_openr F77NAME(hdf_openr_,hdf_openr,HDF_OPENR)
+#define f_hdf_openw F77NAME(hdf_openw_,hdf_openw,HDF_OPENW)
+#define f_hdf_opena F77NAME(hdf_opena_,hdf_opena,HDF_OPENA)
+
+extern "C" {
+#ifdef CRAY // Note: This isn't really implemented yet...
+#include <fortran.h>
+ Long8 f_hdf_open(_fcd fcfilename,_fcd accessname);
+ Long8 f_hdf_openr(_fcd fcfilename);
+ Long8 f_hdf_openw(_fcd fcfilename);
+ Long8 f_hdf_opena(_fcd fcfilename);
+#else
+ Long8 f_hdf_open(char *file,char *access,int flen,int alen);
+ Long8 f_hdf_openr(char *file,int flen);
+ Long8 f_hdf_openw(char *file,int flen);
+ Long8 f_hdf_opena(char *file,int flen);
+#endif
+#include "HDFIO.h"
+}
+/*
+ long io_open_ieee_(constCONST char *file,constCONST char *access,int flen,int alen);
+*/
+
+#endif
+
diff --git a/src/IEEEIO.cc b/src/IEEEIO.cc
new file mode 100644
index 0000000..c2f653b
--- /dev/null
+++ b/src/IEEEIO.cc
@@ -0,0 +1,1443 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "IEEEIO.hh"
+
+#ifdef WIN32
+// Are we Microsoft VC++ 5.0 or 6.0?
+#if defined(_MSC_VER) && ( (_MSC_VER == 1100) || (_MSC_VER == 1200) ) // yes we are
+#include <fcntl.h>
+#ifdef O_RDONLY
+#undef O_RDONLY
+#endif
+#define O_RDONLY _O_RDONLY|_O_BINARY
+#ifdef O_RDWR
+#undef O_RDWR
+#endif
+#define O_RDWR _O_RDWR|_O_BINARY
+#ifdef O_WRONLY
+#undef O_WRONLY
+#endif
+#define O_WRONLY _O_WRONLY|_O_BINARY
+#ifdef O_CREAT
+#undef O_CREAT
+#endif
+#define O_CREAT _O_CREAT|_O_BINARY
+#ifdef O_TRUNC
+#undef O_TRUNC
+#endif
+#define O_TRUNC _O_TRUNC|_O_BINARY
+#ifdef O_APPEND
+#undef O_APPEND
+#endif
+#define O_APPEND _O_APPEND|_O_BINARY
+#else // not an MSC compiler (use the old defines)
+#define O_RDONLY _O_RDONLY
+#define O_RDWR _O_RDWR
+#define O_WRONLY _O_WRONLY
+#define O_CREAT _O_CREAT
+#define O_TRUNC _O_TRUNC
+#define O_APPEND _O_APPEND
+#endif // not an MSC compiler
+#endif // WIN32
+
+#ifdef FFIO
+#include <ffio.h>
+static struct ffsw ffopens_status;
+//#define open(x,y,z) ffopens(x,y,z, 0, 0, &ffopens_status, "bufa.bufsize=256.num_buffers=4")
+#define LAYERS ""
+#ifdef T3E
+#define open(x,y,z) ffopens(x,y,S_IWRITE|S_IREAD,0,100,&ffopens_status,LAYERS);
+#else // its probably an SGI
+#define open(x,y,z) ffopens(x,y,S_IWRITE|S_IREAD,0,0,&ffopens_status,LAYERS);
+#endif
+#define close(x) ffclose(x)
+#endif
+
+#ifdef T3E
+int IEEEIO::ffioIsTrue(){
+#ifdef FFIO
+ return 1;
+#else
+ return 0;
+#endif
+}
+#endif
+
+
+// int IEEEIO::nextRecord() (stores state in current_record)
+// also garauntees integrity of datasetnumber and
+// the current_rec and current_dat
+
+IEEEIO::AttribRef::AttribRef(IEEEIO::AttribRef &src){
+ //puts("AttribRef::copy constructor");
+ rec=src.rec;
+ offset=src.offset;
+ strcpy(name,src.name);
+}
+
+IEEEIO::AttribRef::AttribRef(){
+ //puts("empty attribref constructor");
+}
+/*
+IEEEIO::AttribRef::~AttribRef(){
+ //puts("delete an attrib ref");
+}
+IEEEIO::RecRef::~RecRef(){
+ //puts("delete a recref");
+}
+*/
+
+IEEEIO::AttribRef &IEEEIO::AttribRef::operator=(IEEEIO::AttribRef &src){
+ if(this != &src) {
+ //puts("\tAttribRef::copy operator");
+ rec=src.rec;
+ offset=src.offset;
+ //name=src.name; // uses the flexarray copy constructor
+ strcpy(name,src.name);
+ }
+ return *this;
+}
+
+IEEEIO::DataRef::DataRef():end_offset(0){
+ //puts("Empty DataRef Constructor!!");
+}
+
+
+IEEEIO::DataRef::DataRef(IEEEIO::DataRef &src){
+ //puts("DataRef:: copy constructor");
+ rec=src.rec;
+ offset=src.offset;
+ end_offset=src.end_offset;
+ annotations = src.annotations;
+ attributes = src.attributes;
+ //puts("DataRef:: copy constructor DONE");
+}
+/*
+IEEEIO::DataRef::~DataRef(){
+ // puts("dataref destructor");
+}*/
+
+IEEEIO::DataRef &IEEEIO::DataRef::operator=(IEEEIO::DataRef &src){
+ if(this != &src){
+ rec=src.rec;
+ offset=src.offset;
+ end_offset=src.end_offset;
+ annotations = src.annotations;
+ attributes = src.attributes;
+ }
+ return *this;
+}
+
+void IEEEIO::initPosition(){
+ // init
+#ifdef FFIO
+ actual_position = ::ffseek(fid,0,L_INCR);
+#else
+ actual_position = ::lseek(fid,0,L_INCR);
+#endif
+ virtual_position = actual_position + writebuffercount;
+ // get actual filesize
+
+#ifdef FFIO
+ file_length = ::ffseek(fid,0,L_XTND);
+ ::ffseek(fid,actual_position,L_SET); // seek back to original pos
+#else
+#ifdef SGI
+ file_length = ::lseek64(fid,0,L_XTND);
+ ::lseek64(fid,actual_position,L_SET); // seek back to original pos
+#else
+ file_length = ::lseek(fid,0,L_XTND);
+ ::lseek(fid,actual_position,L_SET); // seek back to original pos
+#endif
+#endif
+ if(virtual_position > file_length)
+ file_length = virtual_position;
+ // printf("Init position: a=%ld v=%ld f=%ld\n",
+ // actual_position,virtual_position,file_length);
+}
+
+
+//long IEEEIO::getPosition(int immediate) {
+//#ifdef FFIO
+// if(!writebuffer || immediate)
+// return ::ffseek(fid,0,L_INCR);
+// else
+// return ::ffseek(fid,0,L_INCR)+writebuffercount;
+//#else
+// if(!writebuffer || immediate)
+// return ::lseek(fid,0,L_INCR);
+// else
+// return ::lseek(fid,0,L_INCR)+writebuffercount;
+//#endif
+//}
+
+void IEEEIO::restart(){
+ // this->initPosition();
+ //puts("restart seek");
+ IEEEIO::lseek(FileHdrSize,L_SET); // T3E Kludge
+ //puts("restart");
+ current_rec_offset=current_dat_offset=FileHdrSize; // T3E Kludge
+ current_rec.recordsize=0;
+ current_dat.datasize=0;
+ current_dat.rank=0;
+ datasetnumber=0; // initial
+ hasread=0; // and it hasn't been read yet...
+}
+
+int IEEEIO::nextRecord(){
+ RecordHdr rec;
+ // should have it check the datasetnumber before seeking
+ // this will require consistancy checks for the datasetnumber
+ // elsewhere in the code
+ Long8 src=current_rec_offset;
+ Long8 dst=src+current_rec.recordsize;
+ current_rec_offset=IEEEIO::lseek(dst,L_SET); // seek from start
+ // or use rec.read(rec,fid)
+ // or IEEEIO::RecordHdr::read(rec,fid)
+ if(RecordHdr::read(this,rec) <= 0)
+ return 0;
+ current_rec_offset=dst+RecordHdrSize;
+ current_rec=rec;
+ return 1;
+}
+
+int IEEEIO::nextDataRecord(){
+ hasread=0; // reset the hasread field
+ if(current_rec.recordtype==DataRecord &&
+ datasetnumber!=current_rec.sequenceID){
+ IEEEIO::lseek(current_rec_offset,L_SET); // seek to record start
+ }
+ else {
+ do { // scan through records for the next DataRecord
+ if(!nextRecord())
+ return 0; // reached end of file
+ } while(current_rec.recordtype!=DataRecord);
+ }
+ // dat_offset is same as current_rec_offset for the data record
+ // so nextRecord() can be used for scanning for annotations
+ current_dat_offset=current_rec_offset;
+ DataRecordHdr::read(this,current_dat);
+ datasetnumber=current_rec.sequenceID;
+ return 1;
+}
+
+//long IEEEIO::getLength(int immediate){
+//#ifdef FFIO
+// long currentpos=::ffseek(fid,0,L_INCR); // find currentposition
+// long auspos = ::ffseek(fid,0,L_XTND); // seek to end to find length
+//#else
+// long currentpos=::lseek(fid,0,L_INCR); // find currentposition
+// long auspos = ::lseek(fid,0,L_XTND); // seek to end to find length
+//#endif
+// if(writebuffer && writebuffercount && !immediate){
+// // must compute real end of file
+// register long pos1=currentpos+writebuffercount;
+// if(pos1>auspos) auspos=pos1;
+// }
+//#ifdef FFIO
+// ::ffseek(fid,currentpos,L_SET); // seek back to original position
+//#else
+// ::lseek(fid,currentpos,L_SET); // seek back to original position
+//#endif
+// return auspos; // return end position
+//}
+
+void IEEEIO::byteswapBuffer(void *buf,Long8 nelements,int elementsize){
+ char *buffer=(char *)buf; // treat as a character buffer
+ if(elementsize<=1) return;
+ for(Long8 i=0;i<nelements;i++,buffer+=elementsize){
+ register int s,d;
+ register char c;
+ // do the swap thang on each element
+ for(s=0,d=elementsize-1;s<d;s++,d--){
+ c=buffer[s];
+ buffer[s]=buffer[d];
+ buffer[d]=c;
+ }
+ }
+}
+
+void IEEEIO::byteswapBuffer(void *source,void *dest,Long8 nelements,int elementsize){
+ if(elementsize<=1) return;
+ // Lets optimize for integers
+ switch(elementsize){
+ case 4:
+ {
+ Int *src=(Int*)source;
+ Int *dst=(Int*)dest;
+ for(Long8 i=0;i<nelements;i++){
+ union IntChar {
+ int i;
+ char a[4];
+ };
+ register IntChar ts,td;
+ // do the swap thang on each element
+ td.i=ts.i=src[i];
+ td.a[0]=ts.a[3];
+ td.a[1]=ts.a[2];
+ td.a[2]=ts.a[1];
+ td.a[3]=ts.a[0];
+ dst[i]=td.i;
+ }
+ }
+ break;
+ //#ifndef WIN32 // Win32 can't have 8byte integers
+ case 8:
+ {
+ Long8 *src=(Long8*)source;
+ Long8 *dst=(Long8*)dest;
+ for(long i=0;i<nelements;i++){
+ union LongChar {
+ Long8 l;
+ char a[8];
+ };
+ register LongChar ts,td;
+ // do the swap thang on each element
+ td.l=ts.l=src[i];
+ td.a[0]=ts.a[7];
+ td.a[1]=ts.a[6];
+ td.a[2]=ts.a[5];
+ td.a[3]=ts.a[4];
+ td.a[4]=ts.a[3];
+ td.a[5]=ts.a[2];
+ td.a[6]=ts.a[1];
+ td.a[7]=ts.a[0];
+ dst[i]=td.l;
+ }
+ }
+ break;
+ //#endif
+ default:
+ {
+ char *src=(char *)source; // treat as a character buffer
+ char *dst=(char *)dest;
+ for(Long8 i=0;i<nelements;i++,src+=elementsize,dst+=elementsize){
+ register int s,d;
+ // do the swap thang on each element
+ for(s=0,d=elementsize-1;s<d;s++,d--){
+ dst[d]=src[s];
+ dst[s]=src[d];
+ }
+ }
+ }
+ break;
+ }
+}
+
+int IEEEIO::writeFileHeader(){
+ // Long8 pos=getPosition(); // use virtual_position
+ // this->flush();
+ //puts("WriteHeader");
+ for(char c=0;c<4;c++) // make sure magic is correct
+ file_header.magic.c[c]=c+1;
+ if(swapbytes)
+ file_header.byteorder.i=IEEE_REVERSE_MAGIC;
+ else
+ file_header.byteorder.i=IEEE_NATIVE_MAGIC;
+ file_header.majorversion = IEEE_MAJORVERSION;
+ file_header.minorversion = IEEE_MINORVERSION;
+ IEEEIO::lseek(0,L_SET); // will force a flush (if needed)
+ //puts("done writeheader seek");
+ if(swapbytes) file_header.byteswap();
+ // T3E Kludge
+ int sz=FileHdr::write(this,file_header);
+ if(swapbytes) file_header.byteswap();
+ // if(pos>=FileHdrSize) // T3E Kludge
+ // IEEEIO::lseek(pos,L_SET);
+ return sz;
+}
+
+// reads the start of the file (including the magic number)
+// and determines if this is
+// 1) A valid IEEEIO file
+// 2) what the byte order is
+// 3) How many datasets are contained
+int IEEEIO::readFileHeader(){
+ Long8 pos=getPosition(); // use virtual_position
+ IEEEIO::lseek(0,L_SET);
+ // T3E Kludge
+ // int sz=FileHdr::read(this,file_header);
+ FileHdr::read(this,file_header);
+ IEEEIO::lseek(pos,L_SET); // return to original position
+ for(char c=0;c<4;c++){
+ if((c+1)!=file_header.magic.c[c]){
+ file_header.ndatasets=0;
+ // fprintf(stderr,"IEEEIO: File %s has the wrong magic number\n",filename);
+ return -1; // bad magic
+ }
+ }
+ // now compare byte order
+ if(file_header.byteorder.i==IEEE_NATIVE_MAGIC)
+ swapbytes=0;
+ else{
+ swapbytes=1;
+ //puts("byteswapping is On !!!!!!!!!!!!!!!");
+ }
+ if(swapbytes) file_header.byteswap();
+ ndatasets=file_header.ndatasets;
+ return 1;
+}
+
+void IEEEIO::rebuildFileHeader(){
+ int lndatasets;
+ Long8 pos=getPosition(); // save file position (use virtual position
+ restart();
+ // steal seek loop from the nextDataRecord()
+ for(lndatasets=0;
+ nextDataRecord()>0;
+ lndatasets++){
+ // now check the length of the record
+ // for each record.
+ }
+ file_header.ndatasets=lndatasets;
+ writeFileHeader();
+ IEEEIO::lseek(pos,L_SET);
+}
+
+void IEEEIO::appendRecordTable(){
+ //printf("appending records==================\n");
+ while(nextRecord()>0){
+ //printf("appending record\n");
+ switch(current_rec.recordtype){
+ case DataRecord:
+ //fprintf(stderr,"DataRecord");
+ (rec_table[current_rec.sequenceID]).rec=current_rec;
+ // use virtual_position
+ (rec_table[current_rec.sequenceID]).offset=getPosition()-RecordHdrSize;
+ break;
+ case AnnotationRecord:{
+ //fprintf(stderr,"\tAnnotationRecord\n");
+ RecRef ref;
+ ref.rec=current_rec;
+ ref.offset=getPosition()- RecordHdrSize; // T3E Kludge
+ (rec_table[current_rec.sequenceID]).annotations.append(ref);
+ }
+ break;
+ case AttributeRecord:{
+ //fprintf(stderr,"\tAttributeRecord\n");
+ AttribRef ref,*refp;
+ AttributeRecordHdr attribhdr;
+ ref.rec=current_rec;
+ ref.offset=getPosition()- RecordHdrSize; // T3E Kludge
+ (rec_table[current_rec.sequenceID]).attributes.append(ref);
+ int idx=(rec_table[current_rec.sequenceID]).attributes.getSize()-1;
+ refp = &((rec_table[current_rec.sequenceID]).attributes[idx]);
+ AttributeRecordHdr::read(this,attribhdr);
+ IEEEIO::read(refp->name,attribhdr.namesize);
+ }
+ break;
+ default:
+ fprintf(stderr,"\tIEEEIO::Error UNKNOWN RECORD TYPE [%d]... recovering.",
+ (int)(current_rec.recordtype));
+ return;
+ }
+ (rec_table[current_rec.sequenceID]).end_offset =
+ current_rec_offset + current_rec.recordsize;
+ }
+}
+
+void IEEEIO::buildRecordTable(){
+ if(file_header.ndatasets<0)
+ return; // failure
+ restart();
+ rec_table.setSize(file_header.ndatasets);
+ appendRecordTable();
+}
+
+void IEEEIO::openFile(CONST char *fname,IObase::AccessMode access,int swbytes){
+ switch(access){
+ case IObase::Read:
+ fid=open(fname,O_RDONLY,0644);
+ if(fid<0){
+ fprintf(stderr,"IEEEIO: Failed to open %s for reading\n",fname);
+ return;
+ }
+ initPosition();
+ if(readFileHeader()<=0){
+ close(fid);
+ // fprintf(stderr,"IEEEIO: File %s is empty (opened for reading)\n",fname);
+ fid=-1; // invalid file
+ return;
+ }
+ if(file_header.ndatasets<0){
+ // must recover from crash
+ close(fid);
+ fid=open(fname,O_RDWR,0644);
+ rebuildFileHeader();
+ close(fid);
+ fid=open(fname,O_RDONLY,0644);
+ readFileHeader(); // reread..
+ }
+ buildRecordTable();
+ restart(); // go to start of file
+ ndatasets = file_header.ndatasets;
+ nextRecord(); // prime the recordnumber
+ break;
+ case IObase::Write: // truncates
+ fid=open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
+ if(fid<0){
+ fprintf(stderr,"IEEEIO: Failed to create %s for writing\n",fname);
+ return;
+ }
+ initPosition();
+ file_header.ndatasets=-1;
+ ndatasets=0;
+ writeFileHeader();
+ restart();
+ break;
+ case IObase::Append:
+ default:
+ fid=open(fname,O_RDWR,0644); // PW: We *don't* want O_APPEND here.
+ // O_Append moves the file ptr to end
+ // of file before a write; this means
+ // when we do the writeHeader() below
+ // this is stuck at the end of this file
+ // which makes it puke.
+ if(fid<0){
+ fprintf(stderr,"IEEEIO: Failed to open %s for append\n",fname);
+ return;
+ }
+ initPosition();
+ if(readFileHeader()<=0){
+ close(fid);
+ fprintf(stderr,"IEEEIO: File %s is empty (opened for append)\n",fname);
+ fid=-1; // invalid file
+ return;
+ }
+ if(file_header.ndatasets<0){
+ // must recover from crash
+ close(fid);
+ fid=open(fname,O_RDWR,0644);
+ initPosition();
+ rebuildFileHeader();
+ close(fid);
+ fid=open(fname,O_RDWR,0644); // PW: We want to open RDWR again
+ initPosition();
+ readFileHeader(); // reread..
+ }
+ buildRecordTable();
+ restart(); // go to start of file
+ ndatasets = file_header.ndatasets;
+ // now we sync up in the way we would for a write
+ file_header.ndatasets=-1;
+ writeFileHeader(); // write header with -1 to indicate we are writing
+ // could refcount by increasing the - of numbers in header
+ // (needs extra flag for synced)
+ restart();
+ nextRecord(); // prime the recordnumber
+ //seek(ndatasets);
+ break;
+ }
+}
+
+IEEEIO::IEEEIO(IEEEIO *file): // read only dup
+ IObase(file->filename,IObase::Read),fid(dup(file->fid)),
+ datasetnumber(0),ndatasets(file->ndatasets),
+ swapbytes(file->swapbytes),hasread(0),
+ writebuffersize(0),writebuffercount(0),writebuffer(0),
+ savedposition(-1),virtual_position(-1),actual_position(-1),
+ file_length(-1)
+{
+ if(file->masterfile) masterfile=file->masterfile;
+ else masterfile=file;
+ initPosition(); // initial positional pointers
+ ndatasets = file_header.ndatasets = file->ndatasets;
+ buildRecordTable();
+ restart(); // go to start of file
+ nextRecord(); // prime the recordnumber
+}
+
+
+IEEEIO::IEEEIO(CONST char *fname, ExtendedAccessMode access,int swbytes):
+ IObase(fname,mode(access)),fid(-1),datasetnumber(0),
+ ndatasets(0),swapbytes(swbytes),hasread(0),masterfile(0),
+ writebuffersize(0),writebuffercount(0),writebuffer(0),
+ savedposition(-1),virtual_position(-1),actual_position(-1),
+ file_length(-1)
+{
+ if(access==IEEEIO::SharedRead){
+ masterfile=this; // we are multi-reading
+ fid=open(fname,O_RDONLY,0644);
+ if(fid<0){
+ fprintf(stderr,"IEEEIO: Failed to open %s for reading\n",fname);
+ return;
+ }
+ this->initPosition();
+ if(readFileHeader()<=0){
+ close(fid);
+ fprintf(stderr,"IEEEIO: File %s is empty (opened for reading)\n",fname);
+ fid=-1; // invalid file
+ return;
+ }
+ buildRecordTable();
+ restart(); // go to start of file
+ ndatasets = file_header.ndatasets;
+ nextRecord(); // prime the recordnumber
+ }
+ else
+ openFile(fname,mode(access),swbytes);
+}
+
+IEEEIO::IEEEIO(CONST char *fname,IObase::AccessMode access,int swbytes):
+ IObase(fname,access),fid(-1),datasetnumber(0),
+ ndatasets(0),swapbytes(swbytes),hasread(0),masterfile(0),
+ writebuffersize(0),writebuffercount(0),writebuffer(0),
+ savedposition(-1)
+{
+ // Long8 fpos;
+ openFile(fname,access,swbytes);
+}
+
+IEEEIO::~IEEEIO(){
+ if(fid<0 && savedposition>=0) resume();
+ // resume IO only if it is paused so that
+ // we can do the final writes to the file before
+ // closing
+ //puts("do bufferoff");
+ if(writebuffer) bufferOff(); // automatically flushes buffer
+ //puts("now rewrite header");
+ if(fid>=0){
+ if(accessmode!=IObase::Read){
+ file_header.ndatasets=ndatasets;
+ writeFileHeader();
+ }
+ close(fid);
+ }
+ fid=-1;
+}
+
+int IEEEIO::isValid(){
+ if(fid>=0) return 1;
+ else return 0;
+}
+
+int IEEEIO::write(IObase::DataType typeID,int rank,CONST int *dims,void *data){
+ int i;
+ RecordHdr rec;
+ DataRecordHdr hdr;
+ // make sure its the EOF
+ if(accessmode==IObase::Read) return 0;
+ hasread=0; // reset hasread; (JMS: changed from local Thu Mar 12 13:53:13 CST 1998)
+ if(rec_table.getSize()>0){
+ Long8 endpos = rec_table[rec_table.getSize()-1].end_offset;
+ IEEEIO::lseek(endpos,L_SET); // don't know if this is costly
+ }
+ else
+ IEEEIO::lseek(0,L_XTND); // seek to end of file
+ // if 0-length seeks are costly, then alternative
+ // logic can be constructed to ensure writes to end of file
+ for(i=0,hdr.datasize=1;i<rank;i++)
+ hdr.datasize*=dims[i];
+
+ if(chunkdims.getSize()<rank)
+ chunkdims.setSize(rank);
+ for(i=0;i<rank;i++) chunkdims[i]=dims[i];
+
+ hdr.datasize*=sizeOf(typeID);
+ hdr.numbertype=typeID;
+ hdr.rank=rank;
+ // if last annotation slot is filled, it is a pointer
+ // to another block of 8 annotation pointers.
+ rec.recordtype = DataRecord;
+ rec.recordsize = hdr.datasize +
+ DataRecordHdrSize +
+ sizeof(Int) * rank;
+ rec.sequenceID = datasetnumber = ndatasets++;
+ // need to byteswap the header and records if swapbytes==True
+ current_dat=hdr; // first copy native info to current
+ current_rec=rec;
+ RecordHdr::write(this,rec);
+ current_dat_offset=current_rec_offset=getPosition();
+ DataRecordHdr::write(this,hdr);
+ // write the dims.... (byteswap if necessary)
+ if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int));
+ IEEEIO::write(chunkdims.getData(),sizeof(Int)*rank);
+ if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int)); // swap back
+ if(swapbytes) byteswapBuffer(data,hdr.datasize/sizeOf(typeID),sizeOf(typeID));
+ int sz = IEEEIO::write(data,hdr.datasize);
+ // yeah! double bytswap seem stupid, but consider the alternatives
+ // write one byte at a time (swapping as we go) == systemcall overhead
+ // copy to a temporary buffer and swap bytes == malloc, copy, and free!
+ // strangely its faster to swap twice
+ if(swapbytes) byteswapBuffer(data,hdr.datasize/sizeOf(typeID),sizeOf(typeID));
+ DataRef dref;
+ dref.rec=current_rec;
+ // Must find exact size!!!
+ dref.offset = current_rec_offset - RecordHdrSize;
+ dref.end_offset = current_rec_offset + current_rec.recordsize;
+ if(accessmode!=IObase::Write) // do not store if in write-only mode
+ rec_table.append(dref);
+ return sz;
+}
+
+//setCurrentRec(offset);
+// storing in 8*1024 byte blocks (always aligned to chunk boundaries)
+// will result in more efficient seeking behavior due to
+// disk block size... thus file is always aligned to unix
+// filesystem blocks. (for now, we'll use die method maximo-stupido...
+int IEEEIO::readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims){
+ if(accessmode!=IObase::Read && accessmode!=IObase::Append)
+ return 0;
+ //int sz;
+ if(hasread) datasetnumber++; // increment to the next one if this has been read
+ if(datasetnumber>=rec_table.getSize()) return 0; // end of file
+ // read the record + header
+ hasread=1; // we've read this, so next time we hit it, we'll increment again
+ IEEEIO::lseek(rec_table[datasetnumber].offset,L_SET);
+ // T3E Kludge
+ RecordHdr::read(this,current_rec);
+ DataRecordHdr::read(this,current_dat);
+ rank=current_dat.rank;
+ if(chunkdims.getSize()<rank) chunkdims.setSize(rank);
+ typeID=Int2DataType(current_dat.numbertype);
+ IEEEIO::read(chunkdims.getData(),sizeof(Int)*rank);
+ if(swapbytes) byteswapBuffer(chunkdims.getData(),(rank>maxdims)?maxdims:rank,sizeof(Int));
+
+ for(int i=0;i<maxdims && i<rank;i++) dims[i]=chunkdims[i];
+ streaming=0;
+ return 1;
+}
+
+/*
+ It does not appear that the bytswapping is really configured here...
+ */
+int IEEEIO::read(void *data){
+ if(accessmode!=IObase::Read && accessmode!=IObase::Append)
+ return 0; // can't readif write only
+ if(datasetnumber>=rec_table.getSize()) return 0; // seek past end.
+ Long8 datapos=rec_table[datasetnumber].offset+RecordHdrSize+DataRecordHdrSize+
+ sizeof(Int)*current_dat.rank;
+ // should make certain current file position is correct
+ // if(getPosition() != datapos) (redundant call to lseek())
+ IEEEIO::lseek(datapos,L_SET); // seek to position
+ int sz=IEEEIO::read(data,current_dat.datasize); // read nbytes
+ int typelen = sizeOf(Int2DataType(current_dat.numbertype));// compute elem sz
+ if(swapbytes) byteswapBuffer(data,current_dat.datasize/typelen,typelen);
+ return sz;
+}
+
+int IEEEIO::seek(int idx){
+ if(accessmode!=IObase::Read &&
+ accessmode!=IObase::Append) // can't seek unless readable
+ return -1; // failed to seek
+ if (idx >= ndatasets || idx < 0) {
+ return -1; // do a bounds check (probably should just clip)
+ }
+ // bound the index
+ if((1+idx)>rec_table.getSize()) idx=rec_table.getSize();
+ if(idx<0) idx=0;
+ index = idx;
+ IEEEIO::lseek(rec_table[index].offset,L_SET);
+ // T3E Kludge
+ RecordHdr::read(this,current_rec);
+ current_rec_offset=getPosition();
+ datasetnumber=current_rec.sequenceID; // Changed: had -1
+ hasread=0; // new file position
+ return current_rec.sequenceID;
+}
+
+int IEEEIO::nDatasets() {
+ // can work across threads or across processes since
+ // it gathers information directly from the file.
+ // it does not need to share info with masterfile
+ // in fact you can delete the masterfile
+ if(masterfile){ // we are passive read-only. update nDatasets
+ // seek-scan to find datasets?
+ int oldlength = (rec_table.getSize())?(rec_table[rec_table.getSize()-1].end_offset):0;
+ //printf("oldlength=%u newlength=%u\n",oldlength,(unsigned int)(getLength()));
+ if(getLength()>oldlength){
+ // lets scan to find the end
+ int lndatasets;
+ puts("We should clearly not be here!!!");
+ restart(); // go to beginning
+ // steal seek loop from the nextDataRecord()
+ for(lndatasets=0;
+ nextDataRecord()>0;
+ lndatasets++){
+ //printf("scan dataset[%u]\n",lndatasets);
+ }
+ file_header.ndatasets = lndatasets;
+ rec_table.setSize(lndatasets);
+ // printf("counted %u datasets. old was %u datasets\n",lndatasets,ndatasets);
+ seek(ndatasets); // seek to current last
+ ndatasets = lndatasets; // then reset the last
+ appendRecordTable(); // append new stuff to record table
+ }
+ }
+ return ndatasets;
+}
+
+int IEEEIO::writeAnnotation(CONST char *annotation){
+ int stringlen;
+ RecRef aref;
+ RecordHdr rec;
+ if(accessmode==IObase::Read || !annotation) return 0;
+ stringlen=strlen(annotation)+1;
+
+ if(rec_table.getSize()>0){
+ Long8 endpos = rec_table[rec_table.getSize()-1].end_offset;
+ IEEEIO::lseek(endpos,L_SET); // don't know if this is costly
+ }
+ else
+ IEEEIO::lseek(0,L_XTND); // seek to end of file
+
+ rec.recordtype=AnnotationRecord;
+ rec.recordsize=stringlen;
+ if(datasetnumber>=0) rec.sequenceID=datasetnumber;
+ else rec.sequenceID=current_rec.sequenceID; // a kludge for error immunity
+ current_rec = rec;
+ // T3E Kludge
+ current_rec_offset = getPosition() + RecordHdrSize;
+ // T3E Kludge
+ RecordHdr::write(this,rec);
+ // if(swapbytes) byteswap(rec);
+ int sz=IEEEIO::write(annotation,stringlen);
+
+ aref.rec=current_rec;
+ // T3E Kludge
+ aref.offset=current_rec_offset-RecordHdrSize;
+ if(accessmode!=IObase::Write){ // don't write to index cache if in write-only mode
+ rec_table[datasetnumber].annotations.append(aref);
+ rec_table[datasetnumber].end_offset=getPosition();
+ }
+ return sz;
+}
+/*
+ If objects could have all attributes implicitly availible for querying
+ when passed to subroutines. Basic object methods for data movement like
+ linearize() or object.linearized[index] object.linearized.size.
+ Then for objects that a receiver can't deal with either
+ 1: have compiletime "gatekeepers" that restrict allowable types
+ that it can receive
+ 2: Do a treesearch through object space to find a convertor sequence
+ that can convert the current type into the one that the object
+ accepts. If no such object can be found, indicate runtime
+ object adaptor failure.
+*/
+int IEEEIO::readAnnotationInfo(int number,int &length){
+ if(datasetnumber<0 ||
+ number>=rec_table[datasetnumber].annotations.getSize()){
+ length=0;
+ return -1;
+ }
+ length=rec_table[datasetnumber].annotations[number].rec.recordsize;
+ return length;
+}
+
+int IEEEIO::readAnnotation(int number,char *annotation,int maxsize){
+ // returns actual size of annotation or -1 if error
+ if(datasetnumber<0 || accessmode==IObase::Write ||
+ number>=rec_table[datasetnumber].annotations.getSize()){
+ return -1;
+ }
+ IEEEIO::lseek(rec_table[datasetnumber].annotations[number].offset,L_SET);
+ // T3E Kludge
+ RecordHdr::read(this,current_rec);
+ IEEEIO::read(annotation,(maxsize<rec_table[datasetnumber].annotations[number].rec.recordsize)?
+ maxsize:(rec_table[datasetnumber].annotations[number].rec.recordsize));
+ annotation[maxsize-1]='\0';
+ return rec_table[datasetnumber].annotations[number].rec.recordsize;
+}
+
+int IEEEIO::nAnnotations(){
+ if(datasetnumber<0 || accessmode==IObase::Write)
+ return -1;
+ return rec_table[datasetnumber].annotations.getSize();
+}
+
+// for attributes
+int IEEEIO::writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data){
+ int stringlen;
+ AttribRef aref;
+ RecordHdr rec;
+ AttributeRecordHdr attrib;
+
+ if(datasetnumber<0){
+ fprintf(stderr,"IEEEIO::writeAttribute(): Error, cannot write attribute before any datasets have been written!\n");
+ return 0;
+ }
+ if(accessmode==IObase::Read) return 0;
+ stringlen=strlen(name)+1;
+
+ if(rec_table.getSize()>0){
+ Long8 endpos = rec_table[rec_table.getSize()-1].end_offset;
+ IEEEIO::lseek(endpos,L_SET); // don't know if this is costly
+ }
+ else
+ IEEEIO::lseek(0,L_XTND); // seek to end of file
+ attrib.datasize=length*sizeOf(typeID);
+ attrib.namesize=stringlen;
+ attrib.numbertype=typeID;
+ rec.recordtype=AttributeRecord;
+ rec.recordsize=attrib.datasize+attrib.namesize+AttributeRecordHdrSize;
+ if(datasetnumber>=0) rec.sequenceID=datasetnumber;
+ else rec.sequenceID=current_rec.sequenceID; // a kludge for error immunity
+ current_rec=rec;
+ current_rec_offset=getPosition() + RecordHdrSize;
+ aref.rec=current_rec;
+ aref.offset=current_rec_offset-RecordHdrSize;
+ // no copy constructor for aref, so must do manually
+ if(accessmode != IObase::Write){
+ int lastindex;
+ rec_table[datasetnumber].attributes.append(aref);
+ lastindex=rec_table[datasetnumber].attributes.getSize()-1;
+ strcpy(rec_table[datasetnumber].attributes[lastindex].name,name);
+ }
+ // T3E Kludge
+ RecordHdr::write(this,rec);
+ AttributeRecordHdr::write(this,attrib);
+ //printf("\tnow write the string\n");
+ IEEEIO::write(name,stringlen);
+ //printf("\tdone IEEEIO::stringlen=%u typeid=%u\n",attrib.namesize,attrib.numbertype);
+ // data is not byte-reversed...
+ int sz=0;
+ if(swapbytes) byteswapBuffer(data,length,sizeOf(typeID));
+ IEEEIO::write(data,length*sizeOf(typeID));
+ if(swapbytes) byteswapBuffer(data,length,sizeOf(typeID)); // swap back
+ if(accessmode != IObase::Write)
+ rec_table[datasetnumber].end_offset=getPosition();
+ // doesn't appear to store attributes properly
+ return sz;
+}
+
+int IEEEIO::readAttributeInfo(int number,char *name,IObase::DataType &typeID,
+ Long &nelem,int maxnamelen){
+ if(accessmode==IObase::Write) return -1;
+ FlexArray<AttribRef> *attribs= &(rec_table[datasetnumber].attributes);
+ if(number>=(*attribs).getSize()) return -1; // > number of attributes
+ AttribRef *attrib=&((*attribs)[number]);
+ if(strlen(attrib->name)>(size_t)maxnamelen){
+ strncpy(name,attrib->name,maxnamelen); // don't we want to copy the other way?
+ name[maxnamelen-1]='\0';
+ }
+ else strcpy(name,attrib->name);
+ name[maxnamelen-1]='\0'; // make certain it is null capped
+ AttributeRecordHdr attribhdr;
+ IEEEIO::lseek((*attribs)[number].offset,L_SET);
+ RecordHdr::read(this,current_rec);
+ AttributeRecordHdr::read(this,attribhdr);
+//printf("IEEEIO:attribrechdr = ds,nt,ns %d,%d,%d\n",
+// attribhdr.datasize,
+// attribhdr.numbertype,
+// attribhdr.namesize);
+ typeID = Int2DataType(attribhdr.numbertype);
+ nelem = attribhdr.datasize/sizeOf(typeID);
+ return -1;
+}
+
+int IEEEIO::readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem){
+ // by name
+ if(accessmode==IObase::Write) return -1;
+ FlexArray<AttribRef> *attribs= &(rec_table[datasetnumber].attributes);
+ for(int i=0;i<attribs->getSize();i++){
+ if(!strcmp(name,(*attribs)[i].name)){
+ // must read the record to get this info
+ AttributeRecordHdr attribhdr;
+ IEEEIO::lseek((*attribs)[i].offset,L_SET);
+ RecordHdr::read(this,current_rec);
+ AttributeRecordHdr::read(this,attribhdr);
+ typeID = Int2DataType(attribhdr.numbertype);
+ nelem = attribhdr.datasize/sizeOf(typeID);
+ return i;
+ }
+ }
+ return -1; // Attribute not found
+}
+
+int IEEEIO::readAttribute(int number,void *data){
+ if(accessmode==IObase::Write) return -1;
+ FlexArray<AttribRef> *attribs= &(rec_table[datasetnumber].attributes);
+ if(number>=(*attribs).getSize()) return -1; // > number of attributes
+ AttributeRecordHdr attribhdr;
+ IEEEIO::lseek((*attribs)[number].offset,L_SET);
+ RecordHdr::read(this,current_rec);
+ AttributeRecordHdr::read(this,attribhdr);
+ IObase::DataType typeID = Int2DataType(attribhdr.numbertype);
+ if(typeID==IObase::Error) return -1; // read failed due to bad datatype
+ // Long8 nelem = attribhdr.datasize/sizeOf(typeID);
+ IEEEIO::lseek(attribhdr.namesize,L_INCR);
+ int sz=IEEEIO::read(data,attribhdr.datasize)/sizeOf(typeID);
+ if(swapbytes) byteswapBuffer(data,sz,sizeOf(typeID));
+ if(typeID==IObase::String){
+ char *cdata=(char *)data;
+ cdata[sz]='\0'; /* Null Terminate String data */
+ }
+ return sz; // returns number of elements read
+}
+
+int IEEEIO::nAttributes(){
+ if(datasetnumber<0 || accessmode == IObase::Write) return -1;
+ return rec_table[datasetnumber].attributes.getSize();
+}
+
+//================Chunking Interface-----------------------
+void IEEEIO::clearChunk(int nbytes){
+#ifdef T3E
+#define DISKBLOCKSIZE 128*1024
+#else
+#define DISKBLOCKSIZE 8192
+#endif
+// This is a wasteful feature that will be eliminated in later releases
+// This is currently done because I needed the disk space to be zero'ed
+// prior to writing for debugging purposes... Could have a writeStream
+// class.
+ int nwritten;
+ char dummy[DISKBLOCKSIZE];
+ for(int i=0;i<DISKBLOCKSIZE;i++)
+ dummy[i]=0; // bzero it (reserve space with zero'ed data)
+ while(nbytes>DISKBLOCKSIZE){
+ nwritten=IEEEIO::write(dummy,DISKBLOCKSIZE);
+ if(nwritten<=0) return; // this aint working
+ nbytes-=nwritten;
+ }
+ if(nbytes>0) IEEEIO::write(dummy,nbytes); // write the remaining bytes
+#undef DISKBLOCKSIZE
+}
+
+int IEEEIO::reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){
+ reserveStream(typeID,rank,dims); // sets up the chunking state machine
+ // clearing does not appear to be needed... just need header
+ //clearChunk(IObase::nBytes(typeID,rank,dims)); // this pre-clears the reserved area to 0. (inefficient)
+ return 1;
+}
+
+// Chunking should probably include striding....
+// But thats a pain since you'll need to read + write to
+// Accomplish that (yuck!). Lots of seeking.
+// Lets leave striding out for now.
+
+// should also check for contiguous data (eg. slicing) and optimize for that layout
+// for now, the streaming interface best serves contiguous data.
+int IEEEIO::writeChunk(CONST int *dims,CONST int *origin,void *data){
+ int i,sz=-1;
+ // make sure its the EOF
+ if(accessmode==IObase::Read) {
+ fprintf(stderr,"IEEEIO::writeChunk(): Error! Access is ReadOnly\n");
+ return 0;
+ }
+ // should have a "chunk reserved" flag set.
+ if(current_reserved_chunk!=datasetnumber){
+ fprintf(stderr,"IEEEIO::writeChunk(): Error! You forgot to reserve space for the chunk using IO::reserveChunk()\n");
+ return 0;
+ }
+
+ // now we need to seek to the position of the data
+ int rank = current_dat.rank;
+ IObase::DataType typeID = IObase::Int2DataType(current_dat.numbertype);
+ int typesize=sizeOf(typeID);
+ // Long8 basefileoffset = rec_table[datasetnumber].offset+
+ Long8 basefileoffset = stream_offset +
+ RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank; // T3E Kludge
+ Long8 chunkcolumnsize=dims[0]*typesize; // stride between columns in chunk
+ Long8 filecolumnsize=chunkdims[0]*typesize; // stride between columns on disk (full array size)
+ Long8 originoffset;
+ Long8 accumdims;
+ for(originoffset=0,accumdims=typesize,i=0;i<rank;i++){
+ originoffset += (origin[i]*accumdims);
+ accumdims *= chunkdims[i];
+ }
+ for(i=0;i<rank;i++){
+ if((origin[i]+dims[i])>chunkdims[i]){
+ fprintf(stderr,"IEEEIO::writeChunk(): ERROR!! specified dims and origin exceed reserved block size\n");
+ fprintf(stderr,"\tfor dimension %u origin=%u and dims=%u\n",i,origin[i],
+ dims[i]);
+ fprintf(stderr,"\torigin+dims=%u whereas the maximum must be less than %u\n",origin[i]+dims[i],chunkdims[i]);
+ }
+ }
+ originoffset+=basefileoffset; // for absolute seeking
+ Long8 maxindex,minindex;
+ minindex=basefileoffset;
+ maxindex=basefileoffset+current_dat.datasize;
+ int ncolumns; // computed in loop below
+ for(ncolumns=1,i=1;i<rank;i++) ncolumns*=dims[i];
+ if(swapbytes)
+ byteswapBuffer(data,IObase::nElements(rank,dims),typesize);
+ for(i=0;i<ncolumns;i++){ // read the columns
+ if(originoffset<minindex){
+ fprintf(stderr,"WriteChunk() inconsistency. Writing less than min index\n");
+ fprintf(stderr,"\tCol[%u]: Requested %u, but minidex= %u\n",
+ i,(unsigned int)originoffset,(unsigned int)minindex);
+ }
+ if(originoffset>maxindex){
+ fprintf(stderr,"WriteChunk() inconsistency. Writing greater than maximum index\n");
+ fprintf(stderr,"\tCol[%u]: Requested %u, but maxindex= %u\n",
+ i,(unsigned int)originoffset,(unsigned int)maxindex);
+ }
+ if((originoffset+chunkcolumnsize)>maxindex){
+ fprintf(stderr,"WriteChunk() inconsistency. This write will overrun the reserved data\n");
+ fprintf(stderr,"\tCol[%u]: Requested %u, maxindex %u, and the write of %u will run to %u\n",
+ i,(unsigned int)originoffset,(unsigned int)maxindex,(unsigned int)chunkcolumnsize,(unsigned int)(originoffset+chunkcolumnsize));
+ }
+ IEEEIO::lseek(originoffset,L_SET);
+ sz=IEEEIO::write(((char*)data)+i*chunkcolumnsize,(int)chunkcolumnsize);
+ originoffset+=filecolumnsize;
+ for(Long8 j=1,idx=dims[1],planesize=filecolumnsize;
+ j<(rank-1) && !((i+1)%idx);
+ idx*=dims[++j]){
+ Long8 extraoffset=planesize*(chunkdims.getData()[j]-dims[j]);
+ originoffset+=extraoffset;
+ planesize*=dims[j];
+ }
+ }
+ // now swap the data back to native order...
+ if(swapbytes)
+ byteswapBuffer(data,IObase::nElements(rank,dims),typesize);
+
+ return sz;
+}
+int IEEEIO::readChunk(CONST int *dims,CONST int *origin,void *data){
+ int sz=-1,i;
+ if(accessmode!=IObase::Read && accessmode!=IObase::Append)
+ return 0;
+ // gonna have to stride through this sucker... (yuck)
+ // use the same chunkdims for this. Must set during readinfo...
+ // now we need to seek to the position of the data
+ int rank = current_dat.rank;
+ IObase::DataType typeID = IObase::Int2DataType(current_dat.numbertype);
+ int typesize=sizeOf(typeID);
+ Long8 basefileoffset = rec_table[datasetnumber].offset+
+ // sizeof(RecordHdr)+sizeof(DataRecordHdr)+sizeof(Int)*current_dat.rank;
+ RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank; // T3E Kludge
+ Long8 chunkcolumnsize=dims[0]*typesize; // stride between columns in chunk
+ Long8 filecolumnsize=chunkdims[0]*typesize; // stride between columns on disk (full array size)
+ Long8 originoffset;
+ Long8 accumdims;
+ // compute the offset into the data on disk required by the chunk origin (initial offset)
+ for(originoffset=0,accumdims=typesize,i=0;i<rank;i++){
+ originoffset += (origin[i]*accumdims);
+ accumdims *= chunkdims[i];
+ }
+ originoffset+=basefileoffset; // for absolute seeking
+ Long8 ncolumns; // computed in loop below
+ for(ncolumns=1,i=1;i<rank;i++) ncolumns*=dims[i];
+ for(i=0;i<ncolumns;i++){ // read the columns
+ IEEEIO::lseek(originoffset,L_SET);
+ sz=IEEEIO::read(((char*)data)+i*chunkcolumnsize,(int)chunkcolumnsize);
+ originoffset+=filecolumnsize;
+ for(Long8 j=1,idx=dims[1],planesize=filecolumnsize;
+ j<(rank-1) && !((i+1)%idx);
+ idx*=dims[++j]){
+ Long8 extraoffset=planesize*(chunkdims.getData()[j]-dims[j]);
+ originoffset+=extraoffset;
+ planesize*=dims[j];
+ }
+ }
+ // now swap the data back to native order...
+ if(swapbytes)
+ byteswapBuffer(data,IObase::nElements(rank,dims),typesize);
+ return sz;
+}
+// Nearly identical to reserveChunk except that we don't need to pre-clear
+// the space to 0 for streamed data.
+int IEEEIO::reserveStream(IObase::DataType typeID,int rank,CONST int *dims){
+ int i;
+ RecordHdr rec;
+ DataRecordHdr hdr;
+ // make sure its the EOF
+ if(accessmode==IObase::Read) return 0;
+
+ if(rec_table.getSize()>0){
+ Long8 endpos = rec_table[rec_table.getSize()-1].end_offset;
+ IEEEIO::lseek(endpos,L_SET); // don't know if this is costly
+ }
+ else {
+ IEEEIO::lseek(0,L_XTND); // seek to end of file
+ }
+ // if 0-length seeks are costly, then alternative
+ // logic can be constructed to ensure writes to end of file
+ if(chunkdims.getSize() != rank)
+ chunkdims.setSize(rank); // KLUDGE!
+ for(i=0,hdr.datasize=1;i<rank;i++) {
+ hdr.datasize*=dims[i];
+ chunkdims[i]=dims[i];
+ }
+ cur_type_size=sizeOf(typeID); // KLUDGE: for writeStream()
+ hdr.datasize*=sizeOf(typeID);
+ hdr.numbertype=typeID;
+ hdr.rank=rank;
+ // if last annotation slot is filled, it is a pointer
+ // to another block of 8 annotation pointers.
+ rec.recordtype = DataRecord;
+ rec.recordsize = hdr.datasize +
+ DataRecordHdrSize + // T3E Kludge
+ sizeof(Int) * rank; // need to change sizeof(Int) to something larger? For 64, yes!
+ rec.sequenceID = datasetnumber = ndatasets++;
+ // need to byteswap the header and records if swapbytes==True
+ current_dat=hdr; // first copy native info to current
+ current_rec=rec;
+ RecordHdr::write(this,rec);
+ current_dat_offset = current_rec_offset = getPosition();
+ DataRecordHdr::write(this,hdr);
+ if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int));
+ IEEEIO::write(chunkdims.getData(),sizeof(Int)*rank); // for better for worse...
+ if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int)); // swap back
+ // OK, now writing 8k at a time, reserve the space with 0's
+ current_reserved_chunk=datasetnumber;
+ DataRef dref;
+ dref.rec=current_rec;
+ dref.offset=current_rec_offset-RecordHdrSize;
+ dref.end_offset=current_rec_offset+current_rec.recordsize;
+ if(accessmode!=IObase::Write)
+ rec_table.append(dref);
+ // else (JMS debugging change 5/12/98)
+ stream_offset = current_rec_offset-RecordHdrSize;
+ streaming=0;
+ return 1;
+}
+
+int IEEEIO::writeStream(void *data,int length){
+ Long8 len;
+ if(!streaming){// seek to starting offset
+ Long8 basefileoffset = stream_offset +
+ RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank;
+ IEEEIO::lseek(basefileoffset,L_SET);
+ streaming=1;
+ }
+ // need to do a bounds check on the stream... for now it'll play dumb...
+ Long8 nbytes=cur_type_size * length;
+ len = IEEEIO::write((char *)data,nbytes); // record file position??
+ if(len<0)
+ return -1; // write failure
+ return len;
+}
+
+int IEEEIO::readStream(void *data,int length){
+ int len;
+ if(!streaming){// seek to starting offset
+ Long8 basefileoffset = rec_table[datasetnumber].offset+
+ RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank;
+ IEEEIO::lseek(basefileoffset,L_SET);
+ streaming=1;
+ }
+ // need to do a bounds check on the stream... for now it'll play dumb...
+ int typesize= sizeOf(Int2DataType(current_dat.numbertype));
+ Long8 nbytes = typesize * length;
+ len = IEEEIO::read((char *)data,nbytes);
+ if(len<0)
+ return -1; // read failure
+ else
+ if(swapbytes) byteswapBuffer(data,length,typesize);
+ return len;
+}
+
+void IEEEIO::bufferOn(long size){
+ if(writebuffer) {
+ if(size==0)
+ bufferOff();
+ return;
+ }
+ else {
+// if not Windows, use fstat() to choose optimal blocksiz
+#if !defined(WIN32) && !defined(T3E)
+ if(size<0){
+ struct stat mystat;
+ fstat(fid,&mystat);
+ size=mystat.st_blksize;
+ }
+#endif
+ // if windows then take a wild guess
+#ifdef T3E
+ size=(size<=64)?8*1024*1024:size; // 8Meg is a good guess for T3E
+#else
+ size=(size<=64)?8*1024:size; //(8k is a good guess for workstations/WinTel)
+#endif
+#ifdef SGI
+ { // allocate the buffer block-aligned (most imp for DirIO)
+ struct stat mystat;
+ fstat(fid,&mystat);
+ writebuffer = (char*)memalign(mystat.st_blksize,size);
+ }
+#else
+ writebuffer = new char[size];
+#endif
+ }
+ writebuffersize=size;
+ writebuffercount=0;
+}
+
+void IEEEIO::bufferOff(){
+ if(!writebuffer) return;
+ if(fid<0 && writebuffercount>0){
+ fprintf(stderr,"IEEEIO::bufferOff() ERROR!!!!");
+ fprintf(stderr,"\tFile %s is either paused or invalid, so I can't deallocate the write buffer safely\n",filename);
+ return;
+ }
+ //printf("bufferoff on a=%ld v=%ld f=%ld b=%d\n",
+ // actual_position,virtual_position,file_length,writebuffercount);
+ this->flush();
+#ifdef SGI // block-aligned write buffer
+ free(writebuffer);
+#else
+ delete writebuffer;
+#endif
+ writebuffer=0;
+}
+
+int IEEEIO::pause(){
+ if(fid<0) return 0; // fail
+ this->flush(); // flush the buffer to pause
+ savedposition=getPosition();
+ close(fid);
+ fid=-1;
+ return 1; // success
+}
+
+int IEEEIO::resume(){
+ if(fid>=0 || savedposition<0) return 0; // fail
+ switch(IObase::accessmode){
+ case IObase::Read:
+ fid=open(filename,O_RDONLY,0644);
+ break;
+ case IObase::Write:
+ fid=open(filename,O_WRONLY,0644);
+ break;
+ case IObase::Append:
+ fid=open(filename,O_RDWR,0644);
+ break;
+ }
+ if(fid<0){
+ printf("IEEEIO::resume failed for file %s\n",filename);
+ return -1;
+ }
+ ::lseek(fid,savedposition,L_SET); // this is OK..
+ savedposition=-1;
+ return 1; // success
+}
+
+//=================== Experimental MPIO methods =================
+void IEEEIO::getFilename(char *fn,int maxlen){
+ strncpy(fn,filename,maxlen-1);
+}
+
+int IEEEIO::reserveStream(IObase::DataType typeID,int rank,CONST int *dims,Long8 &soffset){
+ int rv=this->reserveStream(typeID,rank,dims);
+ soffset = stream_offset + RecordHdrSize+DataRecordHdrSize+sizeof(Int)*
+ current_dat.rank;
+ return rv;
+}
+
+// writes to explicit offset in file!
+// always overrides the current filepointer position!
+// only useful for the master process *if* it
+// must write to a non-zero location
+// *** So the usage scenario is that the master
+// has the IEEEIO file handle and getFilename() is
+// used to pass the name of the file to the slave procs
+// which open it O_WRITE. The master gets the offset
+// for a particular stream from the special version
+// of the method reserverStream and uses that to position
+// their respective file pointers. All slaves and
+// the master then write to the file simultaneously to
+// different file offsets. It remains to be seen how
+// well this works without O_DIRECT. We can use timing
+// loops to stagger the writes somewhat though.
+int IEEEIO::writeStream(void *data,int length,Long8 soffset){
+ IEEEIO::lseek(soffset,L_SET);
+ streaming=1;
+ return writeStream(data,length);
+}
+
+/*********************Fortran Interface**********************/
+Long8 f_ieee_open (char *file,char *accessname,int flen,int alen){
+ // would have used tolower(), but it doesn't exist everywhere.... :(
+ IObase::AccessMode mode;
+ if(*accessname=='R' || *accessname=='r')
+ mode=IObase::Read;
+ else if(*accessname=='W' || *accessname=='w' ||
+ *accessname=='C' || *accessname=='c')
+ mode=IObase::Write;
+ else if(*accessname=='A' || *accessname=='a')
+ mode=IObase::Append;
+ else {
+ fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n",
+ accessname,file);
+ return 0;
+ }
+ IObase *fid=new IEEEIO(file,mode);
+ if(fid->isValid())
+ return (Long8)fid;
+ else
+ delete fid; // file open failed
+ return 0;
+}
+
+Long8 f_ieee_openr(char *filename,int namelen){
+ filename[namelen]='\0';
+ return (Long8)(new IEEEIO(filename,IObase::Read));
+}
+
+Long8 f_ieee_openw(char *filename,int namelen){
+ filename[namelen]='\0';
+ return (Long8)(new IEEEIO(filename,IObase::Write));
+}
+
+Long8 f_ieee_opena(char *filename,int namelen){
+ filename[namelen]='\0';
+ return (Long8)(new IEEEIO(filename,IObase::Append));
+}
+
+void ieee_bufon(Long8 *fileID,int bufsize){
+ IEEEIO *f=(IEEEIO*)(*fileID);
+ if(bufsize<0) f->bufferOn(); // use default size
+ else f->bufferOn(bufsize); // or specify
+}
+
+void ieee_bufoff(Long8 *fileID){
+ IEEEIO *f=(IEEEIO*)(*fileID);
+ f->bufferOff();
+}
+
+IOFile IEEEopen(char *filename,char *accessname){
+ // Parse all of the ansi stdio access option strings
+ IObase::AccessMode mode;
+ if(!strcmp(accessname,"read") ||
+ !strcmp(accessname,"r") ||
+ !strcmp(accessname,"rb"))
+ mode=IObase::Read;
+ else if(*accessname=='a')
+ mode=IObase::Append;
+ else if(!strcmp(accessname,"write") ||
+ !strcmp(accessname,"create") ||
+ !strcmp(accessname,"w") ||
+ !strcmp(accessname,"wb") ||
+ !strcmp(accessname,"w+") ||
+ !strcmp(accessname,"w+b") ||
+ !strcmp(accessname,"wb+"))
+ mode=IObase::Write;
+ else{
+ fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n",
+ accessname,filename);
+ return 0;
+ }
+ IObase *fid=new IEEEIO(filename,mode);
+ if(fid->isValid())
+ return (IOFile)fid;
+ else
+ delete fid; // file open failed
+ return 0; // unknown option
+}
+
+IOFile IEEEopenRead(char *filename){
+ return (IOFile)(new IEEEIO(filename,IObase::Read));
+}
+
+IOFile IEEEopenWrite(char *filename){
+ return (IOFile)(new IEEEIO(filename,IObase::Create));
+}
+
+IOFile IEEEopenAppend(char *filename){
+ return (IOFile)(new IEEEIO(filename,IObase::Append));
+}
+
+void IEEEbufferOn(IOFile fileID,int bufsize){
+ IEEEIO *f=(IEEEIO*)fileID;
+ if(bufsize<0) f->bufferOn(); // use default size
+ else f->bufferOn(bufsize); // or specify
+}
+
+void IEEEbufferOff(IOFile fileID){
+ IEEEIO *f=(IEEEIO*)fileID;
+ f->bufferOff();
+}
+
diff --git a/src/IEEEIO.h b/src/IEEEIO.h
new file mode 100644
index 0000000..8b57ac2
--- /dev/null
+++ b/src/IEEEIO.h
@@ -0,0 +1,13 @@
+#ifndef __IEEEIO_H_
+#define __IEEEIO_H_
+
+#include "IOProtos.h"
+#include "Arch.h"
+
+IOFile IEEEopen PROTO((char *filename,char *accessname));
+IOFile IEEEopenRead PROTO((char *filename));
+IOFile IEEEopenWrite PROTO((char *filename));
+IOFile IEEEopenAppend PROTO((char *filename));
+void IEEEbufferOn PROTO((IOFile fileID,int bufsize));
+void IEEEbufferOff PROTO((IOFile fileID));
+#endif
diff --git a/src/IEEEIO.hh b/src/IEEEIO.hh
new file mode 100644
index 0000000..1b81dbb
--- /dev/null
+++ b/src/IEEEIO.hh
@@ -0,0 +1,709 @@
+#ifndef __IEEEIO_HH_
+#define __IEEEIO_HH_
+#ifndef WIN32
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/file.h>
+#else
+#include <io.h>
+#endif
+
+#include "IEEEIOWinDllApi.h"
+
+#include "IO.hh"
+#include "FlexArrayTmpl.H"
+#include "Arch.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#if defined(WIN32) || defined(SOLARIS)
+// I'm a WIN32 box and I ignore standards
+// or I'm a Sun box and I hate BSD.
+#define bcopy(src,dest,len) memcpy(dest,src,len)
+#else
+#include <strings.h> // available non-ANSI/Posix compliant
+#endif
+
+#ifdef FFIO
+#include <ffio.h>
+#endif
+
+// Win32/Solaris lseek crap...
+#if defined(WIN32) || defined(SOLARIS) || defined (HITACHI) || defined(sun)
+#define L_INCR SEEK_CUR
+#ifndef L_SET // for that wanky Solaris compiler
+#define L_SET SEEK_SET
+#endif
+#define L_XTND SEEK_END
+#endif
+// T3E lseek crap...
+#ifdef T3E // I'm a T3E and I ignore ANSI/Posix standards
+#define L_INCR SEEK_CUR
+#define L_SET SEEK_SET
+#define L_XTND SEEK_END
+#endif
+
+#define IEEE_NATIVE_MAGIC 0x01020304
+#define IEEE_REVERSE_MAGIC 0x04030201
+#define IEEE_ALTERNATING_MAGIC 0x02010403
+
+#define IEEE_BIG_ENDIAN IEEE_NATIVE_MAGIC
+#define IEEE_LITTLE_ENDIAN IEEE_REVERSE_MAGIC
+#define IEEE_VAX_ENDIAN IEEE_ALTERNATING_MAGIC
+
+#define IEEE_MAJORVERSION 1
+#define IEEE_MINORVERSION 1
+
+class IEEEIO_API IEEEIO : public IObase {
+public:
+ enum RecordType {DataRecord=1,AnnotationRecord,AttributeRecord};
+ union btorder {
+ char c[4]; // write as Int, read as Int
+ Int i;
+ };
+#define FileHdrSize (4+4+4+2+2) // T3E Kludge
+ struct FileHdr {
+ // do magic twice so we can figure out which byte-order
+ // the current machine is in addition (without hardcoding) in
+ // addition to which byte order the file is in
+ btorder magic;
+ btorder byteorder;
+ Long ndatasets;
+ // T3E will be stupid for this, but thats OK
+ short majorversion;
+ short minorversion;
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ static int write(IEEEIO *ieeeio,FileHdr &rec){
+ int r=0;
+#ifdef T3E // data structures are not packed contiguously in memory
+ r+=ieeeio->write((rec.magic.c),4);
+ r+=ieeeio->write((rec.byteorder.c),4);
+ r+=ieeeio->write(&(rec.ndatasets),4);
+ // this may be incorrect, but it will work for now
+ // It assumes the low order bytes will be first to
+ // be written.
+ r+=ieeeio->write(&(rec.majorversion),2);
+ r+=ieeeio->write(&(rec.minorversion),2);
+#else
+ // problem if this includes pointers to static methods
+ // will require an extra degree of inheritance. (inherit
+ // from a base structure.
+ r=ieeeio->write(&rec,FileHdrSize);
+#endif
+ return r;
+ }
+ static int read(IEEEIO *ieeeio,FileHdr &rec){
+ int r=0;
+#ifdef T3E // data structures are not packed contiguously in memory
+ char buffer[FileHdrSize];
+ r=ieeeio->read(buffer,FileHdrSize); // read full buffer in and then copy to struct
+ ::bcopy(buffer,(rec.magic.c),4);
+ ::bcopy(buffer+4,(rec.byteorder.c),4);
+ ::bcopy(buffer+8,&(rec.ndatasets),4);
+ // May be invalid if low order bytes are not the
+ // proper ones to load. (eg. may fail on big-endian systems)
+ ::bcopy(buffer+12,&(rec.majorversion),2);
+ ::bcopy(buffer+14,&(rec.minorversion),2);
+#else
+ r=ieeeio->read(&rec,FileHdrSize);
+#endif
+ return r;
+ }
+ static void byteswap(FileHdr &hdr){
+ IEEEIO::byteswapBuffer(&(hdr.ndatasets),1,sizeof(hdr.ndatasets));
+ // because the t3e doesn't have a 2-byte datatype, must do this manually
+ IEEEIO::byteswapBuffer(&(hdr.majorversion),1,2);
+ IEEEIO::byteswapBuffer(&(hdr.minorversion),1,2);
+ }
+ // May be a problem to have a nonstatic class member here because
+ // this will create a vtable entry.
+ void byteswap(){
+ IEEEIO::byteswapBuffer(&ndatasets,1,sizeof(ndatasets));
+ // because the t3e doesn't have a 2-byte datatype, must do this manually
+ IEEEIO::byteswapBuffer(&majorversion,1,2);
+ IEEEIO::byteswapBuffer(&minorversion,1,2);
+ }
+ };
+#define RecordHdrSize (4+4+4) // T3E Kludge
+ struct RecordHdr {
+ Int recordtype;
+ Long recordsize;
+ Int sequenceID;
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ static int write(IEEEIO *ieeeio,RecordHdr &rec){
+ int r=0;
+ // copy into buffer
+ if(ieeeio->swapbytes){
+ char buffer[RecordHdrSize];
+ IEEEIO::byteswapBuffer(&(rec.recordtype),buffer,1,4);
+ IEEEIO::byteswapBuffer(&(rec.recordsize),buffer+4,1,4);
+ IEEEIO::byteswapBuffer(&(rec.sequenceID),buffer+8,1,4);
+ r=ieeeio->write(buffer,RecordHdrSize);
+ }
+ else {
+#ifdef T3E // data structures are not packed contiguously in memory
+ r+=ieeeio->write(&(rec.recordtype),4);
+ r+=ieeeio->write(&(rec.recordsize),4);
+ r+=ieeeio->write(&(rec.sequenceID),4);
+#else
+ r=ieeeio->write(&rec,RecordHdrSize);
+ //printf("Wrote rechdr %u,%u,%u\n",rec.recordtype,rec.recordsize,rec.sequenceID);
+#endif
+ }
+ return r;
+ }
+ static int read(IEEEIO *ieeeio,RecordHdr &rec){
+ char buffer[RecordHdrSize];
+ int r=ieeeio->read(buffer,RecordHdrSize);
+ if(ieeeio->swapbytes)
+ IEEEIO::byteswapBuffer(buffer,3,4);//3 elements of 4 bytes
+#ifdef T3E // data structures are not packed contiguously in memory
+ // do it the stupid way first
+ // would be smarter to pack buffers really
+ ::bcopy(buffer,&(rec.recordtype),4);
+ ::bcopy(buffer+4,&(rec.recordsize),4);
+ ::bcopy(buffer+8,&(rec.sequenceID),4);
+#else
+ ::bcopy(buffer,(char*)&rec,RecordHdrSize);
+#endif
+ return r;
+ }
+ };
+
+#define DataRecordHdrSize (4+4+4) // T3E Kludge
+ struct DataRecordHdr {
+ Long datasize;
+ Int numbertype;
+ Int rank;
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ static int write(IEEEIO *ieeeio,DataRecordHdr &rec){
+ int r=0;
+ // copy into buffer
+ if(ieeeio->swapbytes){
+ char buffer[DataRecordHdrSize];
+ IEEEIO::byteswapBuffer(&(rec.datasize),buffer,1,4);
+ IEEEIO::byteswapBuffer(&(rec.numbertype),buffer+4,1,4);
+ IEEEIO::byteswapBuffer(&(rec.rank),buffer+8,1,4);
+ r=ieeeio->write(buffer,DataRecordHdrSize);
+ }
+ else {
+#ifdef T3E
+ r+=ieeeio->write(&(rec.datasize),4);
+ r+=ieeeio->write(&(rec.numbertype),4);
+ r+=ieeeio->write(&(rec.rank),4);
+#else
+ r=ieeeio->write(&rec,DataRecordHdrSize);
+#endif
+ }
+ return r;
+ }
+ static int read(IEEEIO *ieeeio,DataRecordHdr &rec){
+ char buffer[DataRecordHdrSize];
+ int r=ieeeio->read(buffer,DataRecordHdrSize);
+ if(ieeeio->swapbytes)
+ IEEEIO::byteswapBuffer(buffer,3,4);//3 elements of 4 bytes
+#ifdef T3E
+ // do it the stupid way first
+ // would be smarter to pack buffers really
+ ::bcopy(buffer,&(rec.datasize),4);
+ ::bcopy(buffer+4,&(rec.numbertype),4);
+ ::bcopy(buffer+8,&(rec.rank),4);
+#else
+ ::bcopy(buffer,(char*)&rec,DataRecordHdrSize);
+#endif
+ return r;
+ }
+ };
+#define DataRecordHdr64Size (8+4+4) // T3E Kludge
+ struct DataRecordHdr64 {
+ Long8 datasize;
+ Int numbertype;
+ Int rank;
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ static int write(IEEEIO *ieeeio,DataRecordHdr64 &rec){
+ int r=0;
+ // copy into buffer
+ if(ieeeio->swapbytes){
+ char buffer[DataRecordHdr64Size];
+ IEEEIO::byteswapBuffer(&(rec.datasize),buffer,1,8);
+ IEEEIO::byteswapBuffer(&(rec.numbertype),buffer+8,1,4);
+ IEEEIO::byteswapBuffer(&(rec.rank),buffer+12,1,4);
+ r=ieeeio->write(buffer,DataRecordHdr64Size);
+ }
+ else {
+#ifdef T3E
+ r+=ieeeio->write(&(rec.datasize),8);
+ r+=ieeeio->write(&(rec.numbertype),4);
+ r+=ieeeio->write(&(rec.rank),4);
+#else
+ r=ieeeio->write(&rec,DataRecordHdr64Size);
+#endif
+ }
+ return r;
+ }
+ static int read(IEEEIO *ieeeio,DataRecordHdr64 &rec){
+ char buffer[DataRecordHdr64Size];
+ int r=ieeeio->read(buffer,DataRecordHdr64Size);
+ if(ieeeio->swapbytes){
+ IEEEIO::byteswapBuffer(buffer,1,8);
+ IEEEIO::byteswapBuffer(buffer+8,2,4);//2 elements of 4 bytes
+ }
+#ifdef T3E
+ // do it the stupid way first
+ // would be smarter to pack buffers really
+ ::bcopy(buffer,&(rec.datasize),8);
+ ::bcopy(buffer+4,&(rec.numbertype),4);
+ ::bcopy(buffer+8,&(rec.rank),4);
+#else
+ ::bcopy(buffer,(char*)&rec,DataRecordHdr64Size);
+#endif
+ return r;
+ }
+ };
+#define AttributeRecordHdrSize (4+4+4) // T3E Kludge
+ struct AttributeRecordHdr {
+ Long datasize;
+ Int numbertype;
+ Int namesize; // attributes are named
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ static int write(IEEEIO *ieeeio,AttributeRecordHdr &rec){
+ int r=0;
+ // copy into buffer
+ if(ieeeio->swapbytes){ // pack a buffer
+ char buffer[AttributeRecordHdrSize];
+ IEEEIO::byteswapBuffer(&(rec.datasize),buffer,1,4);
+ IEEEIO::byteswapBuffer(&(rec.numbertype),buffer+4,1,4);
+ IEEEIO::byteswapBuffer(&(rec.namesize),buffer+8,1,4);
+ r=ieeeio->write(buffer,RecordHdrSize);
+ }
+ else {
+#ifdef T3E
+ r+=ieeeio->write(&(rec.datasize),4);
+ r+=ieeeio->write(&(rec.numbertype),4);
+ r+=ieeeio->write(&(rec.namesize),4);
+#else
+ //printf("AttribRec::writing ds,nt,ns %d,%d,%d\n",rec.datasize,rec.numbertype,rec.namesize);
+ r = ieeeio->write(&rec,AttributeRecordHdrSize);
+ //printf("Wrote attribhdr %d,%d,%d\n",rec.datasize,rec.numbertype,rec.namesize);
+ //printf("\tr=%u\n",r);
+#endif
+ }
+ return r;
+ }
+ static int read(IEEEIO *ieeeio,AttributeRecordHdr &rec){
+ int r=0;
+ char buffer[AttributeRecordHdrSize];
+ r=ieeeio->read(buffer,AttributeRecordHdrSize);
+ if(ieeeio->swapbytes)
+ IEEEIO::byteswapBuffer(buffer,3,4);
+#ifdef T3E
+ ::bcopy(buffer,&(rec.datasize),4);
+ ::bcopy(buffer+4,&(rec.numbertype),4);
+ ::bcopy(buffer+8,&(rec.namesize),4);
+#else
+ ::bcopy(buffer,(char*)&rec,AttributeRecordHdrSize);
+ //printf("AttribRec::reading ds,nt,ns %d,%d,%d\n",rec.datasize,rec.numbertype,rec.namesize);
+#endif
+ return r;
+ }
+ };
+#define AttributeRecordHdr64Size (8+4+4) // T3E Kludge
+ struct AttributeRecordHdr64 {
+ Long8 datasize;
+ Int numbertype;
+ Int namesize; // attributes are named
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ static int write(IEEEIO *ieeeio,AttributeRecordHdr64 &rec){
+ int r=0;
+ // copy into buffer
+ if(ieeeio->swapbytes){ // pack a buffer
+ char buffer[AttributeRecordHdr64Size];
+ IEEEIO::byteswapBuffer(&(rec.datasize),buffer,1,4);
+ IEEEIO::byteswapBuffer(&(rec.numbertype),buffer+4,1,4);
+ IEEEIO::byteswapBuffer(&(rec.namesize),buffer+8,1,4);
+ r=ieeeio->write(buffer,AttributeRecordHdr64Size);
+ }
+ else {
+#ifdef T3E
+ r+=ieeeio->write(&(rec.datasize),4);
+ r+=ieeeio->write(&(rec.numbertype),4);
+ r+=ieeeio->write(&(rec.namesize),4);
+#else
+ //printf("AttribRec::writing ds,nt,ns %d,%d,%d\n",rec.datasize,rec.numbertype,rec.namesize);
+ r = ieeeio->write(&rec,AttributeRecordHdr64Size);
+ //printf("Wrote attribhdr %d,%d,%d\n",rec.datasize,rec.numbertype,rec.namesize);
+ //printf("\tr=%u\n",r);
+#endif
+ }
+ return r;
+ }
+ static int read(IEEEIO *ieeeio,AttributeRecordHdr64 &rec){
+ int r=0;
+ char buffer[AttributeRecordHdr64Size];
+ r=ieeeio->read(buffer,AttributeRecordHdr64Size);
+ if(ieeeio->swapbytes)
+ IEEEIO::byteswapBuffer(buffer,3,4);
+#ifdef T3E
+ ::bcopy(buffer,&(rec.datasize),4);
+ ::bcopy(buffer+4,&(rec.numbertype),4);
+ ::bcopy(buffer+8,&(rec.namesize),4);
+#else
+ ::bcopy(buffer,(char*)&rec,AttributeRecordHdr64Size);
+ //printf("AttribRec::reading ds,nt,ns %d,%d,%d\n",rec.datasize,rec.numbertype,rec.namesize);
+#endif
+ return r;
+ }
+ };
+
+ struct RecRef {
+ RecordHdr rec;
+ Long8 offset;
+ // should have a cached flag to indicate if Attribs should be scanned for
+ //virtual ~RecRef();
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ };
+
+ struct AttribRef : public RecRef {
+ //FlexArray<char> name;
+ char name[64];
+ AttribRef();
+ AttribRef(AttribRef &src);
+ //virtual ~AttribRef();
+ AttribRef &operator=(AttribRef &src);
+ // ** Inline these because they are
+ // ** actually kludges for the T3E
+ };
+
+ struct DataRef : public RecRef {
+ // should have a cached flag to indicate if Attribs should be scanned for
+ FlexArray<RecRef> annotations;
+ FlexArray<AttribRef> attributes;
+ Long8 end_offset;
+ DataRef();
+ //virtual ~DataRef();
+ DataRef(DataRef &src);
+ DataRef &operator=(DataRef &src);
+ };
+private:
+ friend class AttribRef;
+ friend class DataRef;
+ friend class FileHdr;
+ friend class RecordHdr;
+ friend class DataRecordHdr;
+ friend class AttributeRecordHdr;
+ friend class DataRecordHdr64;
+ friend class AttributeRecordHdr64;
+ // convenience utilities
+#ifdef T3E
+ int ffioIsTrue();
+#endif
+ void initPosition();
+ inline Long8 getPosition(){return this->lseek(0,L_INCR);}
+ void restart();
+ int nextRecord();
+ int nextDataRecord();
+ inline Long8 getLength(){ return file_length; }
+ static void byteswapBuffer(void *buf,Long8 nelements,int elementsize);
+ static void byteswapBuffer(void *source,void *dest,Long8 nelements,int elementsize);
+ int writeFileHeader();
+ int readFileHeader();
+ void rebuildFileHeader();
+ void appendRecordTable();
+ void buildRecordTable();
+ void clearChunk(int nbytes);
+ void openFile(CONST char *fname,IObase::AccessMode access,int swbytes);
+ // annotations don't need a header
+ // for c, size includes null terminator.
+ // must decrement size for f77
+ //inline int write(int fid,void *data,int size);
+protected:
+ FlexArray<DataRef> rec_table;
+ FlexArray<Int> chunkdims;
+ FileHdr file_header;
+ RecordHdr current_rec,current_data_rec;
+ DataRecordHdr current_dat;
+ Long8 current_rec_offset; // offset past the record header
+ Long8 stream_offset; // kludge to allow index cache to be turned off
+ Long8 current_dat_offset; // to datarec
+ int fid,datasetnumber,ndatasets,swapbytes,current_reserved_chunk;
+ int hasread,streaming,cur_type_size;
+ IEEEIO *masterfile;
+ int writebuffersize,writebuffercount;
+ char *writebuffer;
+ Long8 savedposition;
+ Long8 virtual_position,actual_position;
+ Long8 file_length;
+protected:
+ inline int write(const void *data,size_t size);
+ inline void flush();
+ inline Long8 lseek(Long8 len, int direction);
+ inline int read(void *data,size_t size);
+public:
+ //------------------------core stuff.....................
+ enum ExtendedAccessMode {Read=0,Write=1,Create=1,Append=2,SharedRead=4};
+
+ IObase::AccessMode mode(ExtendedAccessMode amode)
+ {
+ switch(amode){
+ case Read:
+ return IObase::Read;
+ case Write:
+ return IObase::Write;
+ case Append:
+ return IObase::Append;
+ default:
+ return IObase::Read;
+ }
+ }
+ // the IEEEIO:: commented out to satisfy Microsoft Compiler
+ IEEEIO(CONST char *fname, ExtendedAccessMode access,int swbytes=0);
+ IEEEIO(CONST char *fname, AccessMode access,int swbytes=0);
+ IEEEIO(IEEEIO *file); // read-only dup an existing open file
+ virtual ~IEEEIO();
+ virtual int isValid();
+ // could use overloading to differentiate type here... (but I'm going simple)
+ virtual int write(IObase::DataType typeID,int rank,CONST int *dims,void *data);
+ virtual int readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims=3);
+ virtual int read(void *data);
+ //virtual int readChunk(int dims,int origin,int stride,void *data)=0;
+ virtual int seek(int dataset_index);
+ virtual int nDatasets();
+
+ virtual int writeAnnotation(CONST char *annotation);
+ virtual int readAnnotationInfo(int number,int &length); // returns length (-1 if none left)
+ virtual int readAnnotation(int number,char *annotation,int maxsize=128);
+ virtual int nAnnotations();
+
+ virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data);
+ // returns number
+ virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128);
+ virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem); // returns number
+ virtual int readAttribute(int number,void *data);
+ // virtual Long readAttribute(CONST char *name,void *data);
+ virtual int nAttributes();
+
+ //-----------------Chunking Utilities..................
+ virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims);
+ virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ // Streaming interface is for support of PANDA, Sockets etc..
+ virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims);
+ virtual int writeStream(void *data,int length);
+ virtual int readStream(void *data,int length);
+ virtual int pause();
+ virtual int resume();
+ void bufferOn(long size=-1);
+ void bufferOff();
+ //---------------------MPIO Experimental Methods------------
+ void getFilename(char *fn,int maxlen=256);
+ int reserveStream(IObase::DataType typeID,int rank,CONST int *dims,Long8 &offset);
+ int writeStream(void *data,int length,Long8 offset);
+};
+/*
+int bcopy(char *src,char *dst,int len){
+ // copying bytes on the DEC Alpha processor can be costly due
+ // to the penalty of non-aligned memory accesses. This tries
+ // to align the copys.
+
+ You can use the program copyperf to see how bcopy() improves performance
+ You must build copyperf separately using
+ gmake copyperf
+
+ The following will test copy a 64meg buffer 1 time.
+ copyperf 64m
+ The following will test copy a 32k buffer 1000 times
+ copyperf 32k 1000
+ The performance differences are 4-to-1 or greater in favor of bcopy().
+}
+*/
+int IEEEIO::write(const void *data,size_t size){
+ //puts("***********write()");
+#ifdef T3E
+ static int ffio_inline_true=0;
+ if(ffio_inline_true >= 0){
+ // do this test only once on first write
+ // this just gives someone a clue that they've done the
+ // wrong thing when they compiled
+#ifdef FFIO
+ if(!ffioIsTrue()){
+ fprintf(stderr,"Error!!! Inconsistent FFIO flags on a T3E!\n");
+ fprintf(stderr,"Your libraries have been compiled without -DFFIO, but your executable has been compled and linked with them with -DFFIO.\n");
+ fprintf(stderr,"\t*****Please either rebuild the IEEEIO library with -DFFIO or *remove* -DFFIO from your own build.******\n");
+ }
+#else
+ if(ffioIsTrue()){
+ fprintf(stderr,"Error!!! Inconsistent FFIO flags on a T3E!\n");
+ fprintf(stderr,"Your libraries have been compiled with -DFFIO, but your executable has been compled and linked with them without -DFFIO\n");
+ fprintf(stderr,"\t*****Please recompile with -DFFIO******\n");
+ }
+#endif
+ ffio_inline_true = -1;
+ }
+#endif
+ if(!writebuffer){
+ register Long8 r=0;
+#ifdef FFIO
+ r = ::ffwrite(fid,data,size);
+#else
+ r = ::write(fid,data,size);
+#endif
+ if(r>0) actual_position += r;
+ virtual_position = actual_position;
+ // if(r>0) virtual_position = actual_position = (actual_position+r);
+ if(virtual_position>file_length) file_length = virtual_position;
+ return r;
+ }
+ // otherwise, do a buffered write
+ int retval=0;
+ char *datap = (char *)data;
+ if(writebuffercount>0){
+ // copy as much as you can to the writebuffer
+ // should use bcopy... its a whole lot faster!!!
+ Long8 copysize = (size>(size_t)(writebuffersize-writebuffercount))?(writebuffersize-writebuffercount):size;
+ bcopy(datap,writebuffer+writebuffercount,copysize);
+ writebuffercount += copysize;
+ virtual_position += copysize;
+ retval += copysize;
+ if(writebuffercount>=writebuffersize)
+ this->flush(); // dump immediately (updates both virtual and actual pos)
+ size-=copysize; datap+=copysize;
+ if(size<=0) {
+ // virtual_position = actual_position + writebuffercount;
+ if(virtual_position>file_length) file_length=virtual_position;
+ return retval;
+ }
+ }
+ // at this point size>0 and writebuffercount=0
+ if(size<=0 || writebuffercount!=0){
+ printf("***Write Failed: size=%u writebuffercount=%u\n",
+ (unsigned int)size,writebuffercount);
+ }
+ if(size<(size_t)writebuffersize){// store to buffer (size>0 is implicit in loop)
+ bcopy(datap,writebuffer+writebuffercount,size);
+ writebuffercount += size;
+ virtual_position += size;
+ retval += size;
+ }
+ else {
+ register Long8 r=0;
+ // its larger than buffer, so bypass it and
+ // write it directly to the disk.
+#ifdef FFIO
+ r = ::ffwrite(fid,datap,size);
+#else
+ r = ::write(fid,datap,size);
+#endif
+ actual_position += r;
+ virtual_position = actual_position; // essentially equiv to flush
+ if(r>0) retval+=r;
+ }
+ // double-check virtual position
+ // virtual_position = actual_position + writebuffercount;
+ if(virtual_position>file_length) file_length = virtual_position;
+ return retval;
+}
+void IEEEIO::flush(){
+ register Long8 r=0;
+ if(writebuffercount){
+#ifdef FFIO
+ r = ::ffwrite(fid,writebuffer,writebuffercount);
+#else
+ r = ::write(fid,writebuffer,writebuffercount);
+#endif
+ }
+ writebuffercount=0;
+ if((r+actual_position)!=virtual_position){
+ fprintf(stderr,"IEEEIO::flush() : inconsistent file positions! r=%ld v=%ld a=%ld\n",
+ r,virtual_position,actual_position);
+ }
+ actual_position = virtual_position;
+ if(virtual_position>file_length) file_length=virtual_position;
+}
+Long8 IEEEIO::lseek(Long8 len, int direction){
+ // compute new pos
+ register Long8 npos=0;
+ // can seek beyond end of file
+ switch(direction){
+ case L_XTND: /* should do special case for 0 len */
+ npos = file_length + len;
+ break;
+ case L_SET:
+ npos = len;
+ break;
+ case L_INCR:;
+ npos = virtual_position + len;
+ break;
+ }
+ if(npos>file_length)
+ file_length = npos;
+ if(virtual_position != npos) {
+ if(writebuffer)
+ this->flush(); // must flush current buffer contents
+ // printf("Actually seeking from %ld to %ld\n",virtual_position,npos);
+ virtual_position = actual_position = npos;
+#ifdef FFIO
+ // if(!writebuffer)
+ return ::ffseek(fid,npos,L_SET);
+#else
+ // if(!writebuffer)
+#ifdef SGI
+ return ::lseek64(fid,npos,L_SET);
+#else
+ return ::lseek(fid,npos,L_SET);
+#endif
+#endif
+ }
+ return npos; // otherwise no change required
+}
+/* Will eventually want to buffer the reads as well... */
+int IEEEIO::read(void *data,size_t size){
+ register int r=0;
+ if(writebuffercount>0)
+ flush();
+#ifdef FFIO
+ r = ::ffread(fid,data,size);
+#else
+ r = ::read(fid,data,size);
+#endif
+ if(r>0) virtual_position += r;
+ actual_position=virtual_position;
+ // can't read past end of file of course so no need to update file_length;
+ return r;
+}
+
+
+//==========F77 Interface=============
+#define f_ieee_open F77NAME(ieee_open_,ieee_open,IEEE_OPEN)
+#define f_ieee_openr F77NAME(ieee_openr_,ieee_openr,IEEE_OPENR)
+#define f_ieee_openw F77NAME(ieee_openw_,ieee_openw,IEEE_OPENW)
+#define f_ieee_opena F77NAME(ieee_opena_,ieee_opena,IEEE_OPENA)
+#define f_ieee_bufon F77NAME(ieee_bufon_,ieee_bufon,IEEE_BUFON)
+#define f_ieee_bufoff F77NAME(ieee_bufoff_,ieee_bufoff,IEEE_BUFOFF)
+extern "C"{
+#ifdef CRAY // Note: This isn't really implemented yet...
+#include <fortran.h>
+ Long8 f_ieee_open (_fcd fcfilename,_fcd fcaccessmode);
+ Long8 f_ieee_openr (_fcd fcfilename);
+ Long8 f_ieee_openw (_fcd fcfilename);
+ Long8 f_ieee_opena (_fcd fcfilename);
+#else
+ Long8 f_ieee_open (char *filename,char *accessmode,int namelen,int accesslength);
+ Long8 f_ieee_openr (char *filename,int namelen);
+ Long8 f_ieee_openw (char *filename,int namelen); // actually IObase::Create
+ Long8 f_ieee_opena (char *filename,int namelen);
+#endif
+ void f_ieee_bufon (Long8 *fileID,int *bufsize);
+ void f_ieee_bufoff (Long8 *fileID);
+ //=====================ANSI C interface
+#include "IEEEIO.h" // ANSI C interface
+ }
+
+#endif
diff --git a/src/IEEEIOWinDllApi.h b/src/IEEEIOWinDllApi.h
new file mode 100644
index 0000000..8d1296c
--- /dev/null
+++ b/src/IEEEIOWinDllApi.h
@@ -0,0 +1,42 @@
+/////////////////////////////////////////////////////////////////
+//
+// $Id$
+//
+// $Log$
+// Revision 1.3 2000/09/11 14:58:45 tradke
+// Undo my last commit. #ifdef _WIN32 should be fine.
+//
+// Revision 1.2 2000/09/11 14:07:22 tradke
+// #ifdef _WIN32 -> #ifdef WIN32
+//
+// Revision 1.1 2000/02/24 05:47:45 jshalf
+//
+// More minor bugfixes to eliminate compiler warnings.
+// Added Windows support file which was formerly forgotten in
+// the repos.
+//
+// Revision 1.1 2000/01/11 15:56:01 werner
+// Windows Compliance, added WinDLL API.
+//
+// Revision 1.1 2000/01/07 17:52:48 bzfbenge
+// Template file for Win DLL API generation
+//
+//
+/////////////////////////////////////////////////////////////////
+
+#ifndef __IEEEIO_WIN_DLL_API_H
+#define __IEEEIO_WIN_DLL_API_H
+
+
+#ifdef _WIN32
+# ifdef IEEEIO_EXPORTS
+# define IEEEIO_API __declspec(dllexport)
+# else
+# define IEEEIO_API __declspec(dllimport)
+# endif
+#else
+# define IEEEIO_API
+#endif
+
+#endif /* __IEEEIO_WIN_DLL_API_H */
+
diff --git a/src/IEEEIOslave.hh b/src/IEEEIOslave.hh
new file mode 100644
index 0000000..79e7b3e
--- /dev/null
+++ b/src/IEEEIOslave.hh
@@ -0,0 +1,63 @@
+#ifndef __IEEEIOSLAVE_HH_
+#define __IEEEIOSLAVE_HH_
+
+class IEEEIOslave {
+ // open two fid's (one for O_DIRECT and the other for buffered)
+ // determine which sections of the buffer are remainders and
+ // write them buffered which requires nasty locking
+ // since this is SGI_specific, we can use aio for the remainders
+ int fid;
+ struct ffsw ffopens_status;
+public:
+ IEEEIOslave(char *filename):fid(-1){
+ // opens read/write
+ fid = open(fname,O_RDWR,0644);
+ }
+ ~IEEEIOslave(){
+ if(fid>=0){
+ close(fid);
+ }
+ }
+};
+
+#ifdef T3E
+// T3E-specific ffio slaves
+// #define open(x,y,z) ffopens(x,y,z, 0, 0, &ffopens_status, "bufa.bufsize=256.num_buffers=4")
+
+class ffIEEEIOslave {
+ int fid;
+public:
+ IEEEIOslave(char *filename):fid(-1){
+ // opens read/write
+ fid = ffopens(fname,O_RDWR,0644);
+ }
+ ~IEEEIOslave(){
+ if(fid>=0){
+ ffclose(fid);
+ }
+ }
+};
+
+
+
+#ifdef SGI
+// SGI-specific slaves
+
+class asyncIEEEIOslave {
+ int fid;
+public:
+ IEEEIOslave(char *filename):fid(-1){
+ // opens read/write
+ }
+ ~IEEEIOslave(){
+ if(fid>=0){
+ close(fid);
+ }
+ }
+};
+
+
+
+#endif
+
+#endif
diff --git a/src/IO.cc b/src/IO.cc
new file mode 100644
index 0000000..a6c8eab
--- /dev/null
+++ b/src/IO.cc
@@ -0,0 +1,371 @@
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "IO.hh"
+
+IObase::IObase(CONST char *fname,AccessMode access):index(0),nitems(0),accessmode(access){
+ strcpy(filename,fname);
+}
+
+IObase::DataType IObase::Int2DataType(int dt){
+ if(dt==Byte)
+ return Byte;
+ else if(dt==Int16)
+ return Int16;
+ else if(dt==Int32)
+ return Int32;
+ else if(dt==Int64)
+ return Int64;
+ else if(dt==Float32)
+ return Float32;
+ else if(dt==Float64)
+ return Float64;
+ else if(dt==uInt8)
+ return uInt8;
+ else if(dt==uInt16)
+ return uInt16;
+ else if(dt==uInt32)
+ return uInt32;
+ else if(dt==uInt64)
+ return uInt64;
+ else if(dt==Char8)
+ return Char8;
+ else if(dt==Char16)
+ return Char16;
+ else return Error;
+}
+
+int IObase::sizeOf(IObase::DataType dt){
+ switch(dt){
+ case Int8:
+ case uInt8:
+ case Char8:
+ return 1;
+ case Int16:
+ case uInt16:
+ case Char16:
+ return 2;
+ case Int32:
+ case uInt32:
+ case Float32:
+ return 4;
+ case Int64:
+ case uInt64:
+ case Float64:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+int IObase::nElements(int rank,CONST int *dims){
+ int nelem,i;
+ for(i=0,nelem=1;i<rank;i++) nelem*=dims[i];
+ return nelem;
+}
+
+int IObase::nBytes(IObase::DataType dt, int rank,CONST int *dims){
+ return nElements(rank,dims)*sizeOf(dt);
+}
+
+int f_io_close(Long8 *deviceID){
+ IObase *dev=(IObase*)(*deviceID);
+ delete dev;
+ *deviceID=0;
+ return 1;
+}
+
+int f_io_isvalid(Long8 *deviceID){
+ if(!deviceID || !*deviceID) return 0;
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->isValid();
+}
+
+int f_io_sizeof(int *type){
+ return IObase::sizeOf(IObase::Int2DataType(*type));
+}
+
+int f_io_nelements(int *rank,int *dims){
+ return IObase::nElements(*rank,dims);
+}
+
+int f_io_nbytes(int *type,int *rank,int *dims){
+ return IObase::nBytes(IObase::Int2DataType(*type),*rank,dims);
+}
+
+int f_io_write(Long8 *deviceID,int *typeID,int *rank,int *dims,void *data){
+ IObase *dev=(IObase*)(*deviceID);
+ dev->write(dev->Int2DataType(*typeID),*rank,dims,data);
+ return 1;
+}
+
+int f_io_readinfo(Long8 *deviceID,int *typeID,int *rank,int *dims,int *maxdims){
+ IObase *dev=(IObase*)(*deviceID);
+ IObase::DataType tid;
+ if(*maxdims<0) *maxdims=0;
+ int r=dev->readInfo(tid,*rank,dims,*maxdims);
+ //int r=dev->readInfo(tid,*rank,dims);
+ *typeID=tid;
+ return r;
+}
+
+int f_io_numdata(Long8 *deviceID){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->nDatasets();
+}
+int f_io_read(Long8 *deviceID,void *data){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->read(data);
+}
+
+int f_io_seek(Long8 *deviceID,int *dataset_index){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->seek(*dataset_index);
+}
+//--------------Annotations
+int f_io_writenote(Long8 *deviceID,char *annotation,int size){
+ IObase *dev=(IObase*)(*deviceID);
+ annotation[size]='\0'; // Yeah! its unsafe I know..!! (but it works!)
+ return dev->writeAnnotation(annotation);
+}
+
+int f_io_readnote(Long8 *deviceID,int *index,char *annotation,int maxsize){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->readAnnotation(*index,annotation,maxsize);
+}
+
+int f_io_noteinfo(Long8 *deviceID,int *index,int *length){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->readAnnotationInfo(*index,*length);
+}
+
+int f_io_numnote(Long8 *deviceID){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->nAnnotations();
+}
+
+//---------------Attributes
+int f_io_writeatt(Long8 *deviceID,char *name,
+ int *datatype,Long *nelements,void *data,int namesize){
+ IObase *dev=(IObase*)(*deviceID);
+ name[namesize]='\0'; // cap name (to be certain).. unsafe but it works
+ // should copy into a flexarray which will be destroyed on return
+ IObase::DataType typeID = IObase::Int2DataType(*datatype);
+ return dev->writeAttribute(name,typeID,*nelements,data);
+}
+
+int f_io_attinfo(Long8 *deviceID,char *name,
+ int *datatype,Long *nelements,int namesize){
+ IObase *dev=(IObase*)(*deviceID);
+ IObase::DataType typeID;
+ if(namesize>0)
+ name[namesize]='\0';
+ int i=dev->readAttributeInfo(name,typeID,*nelements);
+ *datatype=typeID;
+ return i;
+}
+
+int f_io_iattinfo(Long8 *deviceID,int *index,char *name,
+ int *datatype,Long *nelements,int namesize){
+ int i;
+ IObase *dev=(IObase*)(*deviceID);
+ IObase::DataType typeID;
+ for(i=0;i<namesize;i++) name[i]='\0';
+ //printf("io_iattinfo(): Namesize=%u Name=[%s]\n",namesize,name);
+ i=dev->readAttributeInfo(*index,name,typeID,*nelements,namesize);
+ // need to zero the array
+ //printf("io_iattinfo(): Newname=[%s]\n",name);
+ *datatype=typeID;
+ //printf("io_iattinfo(): attribs are index=%u type=%u nelements=%u namesize=%u\n",
+ // *index,*datatype,*nelements,namesize);
+ return i;
+}
+
+int f_io_readatt(Long8 *deviceID,int *number,void *data){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->readAttribute(*number,data);
+}
+
+int f_io_numatt(Long8 *deviceID){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->nAttributes();
+}
+
+//==========F77 Chunking interface--------------------
+int f_io_reserveck(Long8 *deviceID,int *typeID,int *rank,int *dims){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->reserveChunk(dev->Int2DataType(*typeID),*rank,dims);
+}
+
+int f_io_writeck(Long8 *deviceID,int *chunkdims,int *chunkorigin,void *data){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->writeChunk(chunkdims,chunkorigin,data);
+}
+
+int f_io_readck(Long8 *deviceID,int *chunkdims,int *chunkorigin,void *data){
+ IObase *dev=(IObase*)(*deviceID);
+ return dev->readChunk(chunkdims,chunkorigin,data);
+}
+int f_io_writestrm(Long8 *deviceID,void *data,int *length){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->writeStream(data,*length);
+}
+
+int f_io_readstrm(Long8 *deviceID,void *data,int *length){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->readStream(data,*length);
+}
+
+int f_io_pause(Long8 *deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->pause();
+}
+
+int f_io_resume(Long8 *deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->resume();
+}
+
+//====================C Interface========================
+int IOclose(IOFile deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ delete dev;
+ deviceID=0;
+ return 1;
+}
+
+int IOisValid(IOFile deviceID){
+ if(!deviceID) return 0;
+ IObase *dev=(IObase*)(deviceID);
+ return dev->isValid();
+}
+
+int IOsizeOf(int type){
+ return IObase::sizeOf(IObase::Int2DataType(type));
+}
+
+int IOnElements(int rank,int *dims){
+ return IObase::nElements(rank,dims);
+}
+
+int IOnBytes(int type,int rank,int *dims){
+ return IObase::nBytes(IObase::Int2DataType(type),rank,dims);
+}
+
+int IOwrite(IOFile deviceID,int typeID,int rank,int *dims,void *data){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->write(dev->Int2DataType(typeID),rank,dims,data);
+}
+
+int IOreadInfo(IOFile deviceID,int *typeID,int *rank,int *dims,int maxdims){
+ IObase *dev=(IObase*)(deviceID);
+ IObase::DataType tid;
+ int r=dev->readInfo(tid,*rank,dims,maxdims);
+ *typeID=tid;
+ return r;
+}
+
+int IOread(IOFile deviceID,void *data){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->read(data);
+}
+
+int IOseek(IOFile deviceID,int dataset_index){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->seek(dataset_index);
+}
+
+int IOnDatasets(IOFile deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->nDatasets();
+}
+
+int IOwriteAnnotation(IOFile deviceID,char *annotation){
+ IObase *dev=(IObase*)(deviceID);
+ //annotation[size]='\0'; // Yeah! its unsafe I know..!! (but it works!)
+ return dev->writeAnnotation(annotation);
+}
+
+int IOreadAnnotation(IOFile deviceID,int index,char *annotation,int maxsize){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->readAnnotation(index,annotation,maxsize);
+}
+
+int IOreadAnnotationInfo(IOFile deviceID,int index,int *size){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->readAnnotationInfo(index,*size);
+}
+
+int IOnAnnotations(IOFile deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->nAnnotations();
+}
+
+int IOwriteAttribute(IOFile deviceID,char *name,int type,Long length,void *data){
+ IObase *dev=(IObase*)(deviceID);
+ IObase::DataType typeID = IObase::Int2DataType(type);
+ return dev->writeAttribute(name,typeID,length,data);
+}
+
+int IOreadIndexedAttributeInfo(IOFile deviceID,int number,char *name,
+ int *type,Long *nelem,int maxnamelen){
+ IObase *dev=(IObase*)(deviceID);
+ IObase::DataType typeID;
+ int i=dev->readAttributeInfo(number,name,typeID,*nelem,maxnamelen);
+ *type=typeID; // convert from enum
+ return i;
+}
+
+int IOreadAttributeInfo(IOFile deviceID,char *name,int *type,Long *nelem){
+ IObase *dev=(IObase*)(deviceID);
+ IObase::DataType typeID;
+ int i=dev->readAttributeInfo(name,typeID,*nelem);
+ *type=typeID; // convert from enum
+ return i;
+}
+
+int IOreadAttribute(IOFile deviceID,int number,void *data){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->readAttribute(number,data);
+}
+
+int IOnAttributes(IOFile deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->nAttributes();
+}
+
+//=============C Chunking interface---------------
+int IOreserveChunk(IOFile deviceID,int typeID,int rank,int *dims){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->reserveChunk(dev->Int2DataType(typeID),rank,dims);
+}
+
+int IOwriteChunk(IOFile deviceID,int *chunkdims,int *chunkorigin,void *data){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->writeChunk(chunkdims,chunkorigin,data);
+}
+
+int IOreadChunk(IOFile deviceID,int *chunkdims,int *chunkorigin,void *data){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->readChunk(chunkdims,chunkorigin,data);
+}
+
+int IOwriteStream(IOFile deviceID,void *data,int length){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->writeStream(data,length);
+}
+
+int IOreadStream(IOFile deviceID,void *data,int length){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->readStream(data,length);
+}
+int IOpause(IOFile deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->pause();
+}
+
+int IOresume(IOFile deviceID){
+ IObase *dev=(IObase*)(deviceID);
+ return dev->resume();
+}
diff --git a/src/IO.hh b/src/IO.hh
new file mode 100644
index 0000000..330a8d1
--- /dev/null
+++ b/src/IO.hh
@@ -0,0 +1,188 @@
+#ifndef __IO_HH_
+#define __IO_HH_
+#include "Arch.h"
+
+class IObase {
+public:
+ //-----------------------Public Enums....................
+ enum AccessMode {Read=0,Write=1,Create=1,Append=2};
+ enum DataType {Byte=0,Int8=0,Int16=1,Int32=2,Int64=3,
+ Float32=4,Float64=5,
+ uInt8=6,uChar=6,uInt16=7,uInt32=8,uInt64=9,
+ Char=10,Char8=10,String=10,Unicode=11,Char16=11, // special string types
+ Error=-1};
+protected:
+ //-----------------------State variables.................
+ int index,nitems;
+ AccessMode accessmode;
+ char filename[256];
+public:
+ //------------------------core stuff.....................
+ IObase(CONST char *fname,AccessMode access);
+ virtual ~IObase() {}
+ virtual int isValid() { return 0; }
+ // could use overloading to differentiate type here... (but I'm going simple)
+ virtual int write(DataType typeID,int rank,CONST int *dims,void *data)=0;
+ virtual int readInfo(DataType &typeID,int &rank,int *dims,int maxdims=3)=0;
+ virtual int read(void *data)=0;
+ virtual int seek(int dataset_index)=0;
+ virtual int nDatasets()=0;
+ virtual int writeAnnotation(CONST char *annotation)=0;
+ virtual int readAnnotationInfo(int number,int &length)=0; // returns length (-1 if none left)
+ virtual int readAnnotation(int number,char *annotation,int maxsize=128)=0;
+ virtual int nAnnotations()=0;
+
+ virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data)=0;
+ // returns number
+ virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128)=0;
+ virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem)=0; // returns number
+
+#ifdef T3E
+ /********** Kludge for T3E support*/
+ inline int readAttributeInfo(int number,char *name,IObase::DataType &typeID,int &nelem,int maxnamelen=128){
+ register Long n=nelem;
+ register int r=this->readAttributeInfo(number,name,typeID,n,maxnamelen);
+ nelem=n;
+ return r;
+}
+ inline int readAttributeInfo(CONST char *name,IObase::DataType &typeID,int &nelem){
+ register Long n=nelem;
+ register int r=this->readAttributeInfo(name,typeID,n);
+ nelem=n;
+ return r;
+}
+ // returns number
+#endif
+
+ virtual int readAttribute(int number,void *data)=0;
+ // virtual Long readAttribute(char *name,void *data);
+ virtual int nAttributes()=0;
+
+ //-----------------Chunking Features (for MPI/HPF)................
+ virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims)=0;
+
+ virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data)=0;
+ // virtual int writeStridedChunk()=0;
+ // virtual int writeHPF(int processorID,int *proclayout,IObase::HPFlayout *arraylayout,void *data)=0;
+ virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data)=0;
+ // virtual int readStrided()=0;
+ // virtual int readHPF(int processorID,int *proclayout,IObase::HPFlayout *arraylayout,void *data)=0;
+ //-----------------Streaming interface (for PANDA, Sockets & MPIO).........
+ virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims)=0;
+ virtual int writeStream(void *data,int length)=0;
+ virtual int readStream(void *data,int length)=0;
+ //-----------------------Utilities........................
+ // unfortunately you can cast enums to int but not the reverse
+ static DataType Int2DataType(int dt);
+ static int sizeOf(DataType dt);
+ static int nElements(int rank,CONST int *dims); // returns number of elements in dataset
+ static int nBytes(DataType dt,int rank,CONST int *dims); // returns number of bytes (good for malloc)
+ CONST char *name() { return filename; }
+ virtual int pause() { return 0; }
+ virtual int resume() { return 0; }
+};
+
+//===================Fortran77 Interface
+#define f_io_close F77NAME(io_close_,io_close,IO_CLOSE)
+#define f_io_isvalid F77NAME(io_isvalid_,io_isvalid,IO_ISVALID)
+#define f_io_sizeof F77NAME(io_sizeof_,io_sizeof,IO_SIZEOF)
+#define f_io_nbytes F77NAME(io_nbytes_,io_nbytes,IO_NBYTES)
+#define f_io_nelements F77NAME(io_nelements_,io_nelements,IO_NELEMENTS)
+#define f_io_write F77NAME(io_write_,io_write,IO_WRITE)
+#define f_io_readinfo F77NAME(io_readinfo_,io_readinfo,IO_READINFO)
+#define f_io_read F77NAME(io_read_,io_read,IO_READ)
+#define f_io_seek F77NAME(io_seek_,io_seek,IO_SEEK)
+#define f_io_numdata F77NAME(io_numdata_,io_numdata,IO_NUMDATA)
+#define f_io_writenote F77NAME(io_writenote_,io_writenote,IO_WRITENOTE)
+#define f_io_readnote F77NAME(io_readnote_,io_readnote,IO_READNOTE)
+#define f_io_numnote F77NAME(io_numnote_,io_numnote,IO_NUMNOTE)
+#define f_io_writeatt F77NAME(io_writeatt_,io_writeatt,IO_WRITEATT)
+#define f_io_attinfo F77NAME(io_attinfo_,io_attinfo,IO_ATTINFO)
+#define f_io_iattinfo F77NAME(io_iattinfo_,io_iattinfo,IO_IATTINFO)
+#define f_io_readatt F77NAME(io_readatt_,io_readatt,IO_READATT)
+#define f_io_numatt F77NAME(io_numatt_,io_numatt,IO_NUMATT)
+#define f_io_reserveck F77NAME(io_reserveck_,io_reserveck,IO_RESERVECK)
+#define f_io_writeck F77NAME(io_writeck_,io_writeck,IO_WRITECK)
+#define f_io_readck F77NAME(io_readck_,io_readck,IO_READCK)
+#define f_io_writestrm F77NAME(io_writestrm_,io_writestrm,IO_WRITESTRM)
+#define f_io_readstrm F77NAME(io_readstrm_,io_readstrm,IO_READSTRM)
+#define f_io_pause F77NAME(io_pause_,io_pause,IO_PAUSE)
+#define f_io_resume F77NAME(io_resume_,io_resume,IO_RESUME)
+extern "C"{
+//================Ansi C interface
+#include "IOProtos.h"
+//==== f77 interface
+#ifdef CRAY
+ // Cray fortran uses an _fcd data structure to pass strings. This is in preparation
+ // for using this on Crays, but since nobody is using them yet, I've left the code for
+ // these versions of the routines blank. It'll be filled in later if the need arises
+#include <fortran.h>
+ int f_io_close (Long8 *deviceID);
+ int f_io_isvalid (Long8 *deviceID);
+ int f_io_sizeof (int *datatype);
+ int f_io_nelements (int *rank,int *dims);
+ int f_io_nbytes (int *datatype,int *rank,int *dims);
+ int f_io_write (Long8 *deviceID,int *typeID,int *rank,int *dims,void *data);
+ int f_io_readinfo (Long8 *deviceID,int *typeID,int *rank,int *dims,int *maxdims);
+ int f_io_read (Long8 *deviceID,void *data);
+ int f_io_seek (Long8 *deviceID,int *dataset_index);
+ int f_io_numdata (Long8 *deviceID);
+ int f_io_writenote (Long8 *deviceID,_fcd fcannotation);
+ int f_io_noteinfo (Long8 *deviceID,int *number,int *length);
+ int f_io_readnote (Long8 *deviceID,int *number,_fcd fcannotation);
+ int f_io_numnote (Long8 *deviceID);
+
+ int f_io_writeatt (Long8 *deviceID,_fcd fcname,
+ int *datatype,Long *nelements,void *data);
+ int f_io_attinfo (Long8 *deviceID,_fcd fcname,
+ int *datatype,Long *nelements);
+ int f_io_iattinfo (Long8 *deviceID,int *index,_fcd fcname,
+ int *datatype,Long *nelements);
+ int f_io_readatt (Long8 *deviceID,int *number,void *data);
+ int f_io_numatt (Long8 *deviceID);
+ int f_io_reserveck(Long8 *deviceID,int *typeID,int *rank,int *dims);
+ int f_io_writeck(Long8 *deviceID,int *chunkdims,int *chunkorigin,void *data);
+ int f_io_readck(Long8 *deviceID,int *chunkdims,int *chunkorigin,void *data);
+ int f_io_writestrm(Long8 *deviceID,void *data,int *length);
+ int f_io_readstrm(Long8 *deviceID,void *data,int *length);
+ int f_io_pause(Long8 *deviceID);
+ int f_io_resume(Long8 *deviceID);
+#else
+ int f_io_close (Long8 *deviceID);
+ int f_io_isvalid (Long8 *deviceID);
+ int f_io_sizeof (int *datatype);
+ int f_io_nelements (int *rank,int *dims);
+ int f_io_nbytes (int *datatype,int *rank,int *dims);
+ int f_io_write (Long8 *deviceID,int *typeID,int *rank,int *dims,void *data);
+ int f_io_readinfo (Long8 *deviceID,int *typeID,int *rank,int *dims,int *maxdims);
+ int f_io_read (Long8 *deviceID,void *data);
+ int f_io_seek (Long8 *deviceID,int *dataset_index);
+ int f_io_numdata (Long8 *deviceID);
+
+ int f_io_writenote (Long8 *deviceID,char *annotation,int size);
+ int f_io_noteinfo (Long8 *deviceID,int *number,int length);
+ int f_io_readnote (Long8 *deviceID,int *number,char *annotation,int maxsize);
+ int f_io_numnote (Long8 *deviceID);
+
+ int f_io_writeatt (Long8 *deviceID,char *name,
+ int *datatype,Long *nelements,void *data,int namesize);
+ int f_io_attinfo (Long8 *deviceID,char *name,
+ int *datatype,Long *nelements,int namesize);
+ int f_io_iattinfo (Long8 *deviceID,int *index,char *name,
+ int *datatype,Long *nelements,int namesize);
+ int f_io_readatt (Long8 *deviceID,int *number,void *data);
+ int f_io_numatt (Long8 *deviceID);
+ int f_io_reserveck(Long8 *deviceID,int *typeID,int *rank,int *dims);
+ int f_io_writeck(Long8 *deviceID,int *chunkdims,int *chunkorigin,void *data);
+ int f_io_readck(Long8 *deviceID,int *chunkdims,int *chunkorigin,void *data);
+ int f_io_writestrm(Long8 *deviceID,void *data,int *length);
+ int f_io_readstrm(Long8 *deviceID,void *data,int *length);
+ int f_io_pause(Long8 *deviceID);
+ int f_io_resume(Long8 *deviceID);
+#endif
+}
+
+#endif
+
+
+
diff --git a/src/IOProtos.h b/src/IOProtos.h
new file mode 100644
index 0000000..e2d475c
--- /dev/null
+++ b/src/IOProtos.h
@@ -0,0 +1,63 @@
+/* IOProtos.h C header */
+#ifndef __IO_H_
+#define __IO_H_
+#ifndef UNITYPE
+#define UNITYPE
+#define BYTE 0
+#define INT8 0
+#define INT16 1
+#define INT32 2
+#define INT64 3
+#define FLOAT32 4
+#define FLOAT64 5
+#define UCHAR 6
+#define UINT8 6
+#define UINT16 7
+#define UINT32 8
+#define UINT64 9
+/* special string types */
+#define CHAR 10
+#define CHAR8 10
+#define STRING 10
+#define UNICODE 11
+#define CHAR16 11
+#endif
+/* error */
+#define TYPEERROR -1
+
+#define IOREAD 0
+#define IOWRITE 1
+#define IOAPPEND 2
+#define IOCREATE 1 /* Same as IOWRITE */
+
+#include "Arch.h"
+
+int IOclose PROTO((IOFile deviceID));
+int IOisValid PROTO((IOFile deviceID));
+int IOsizeOf PROTO((int datatype));
+int IOnElements PROTO((int rank,int *dims));
+int IOnBytes PROTO((int datatype,int rank,int *dims));
+int IOwrite PROTO((IOFile deviceID,int typeID,int rank,int *dims,void *data));
+int IOreadInfo PROTO((IOFile deviceID,int *typeID,int *rank,int *dims,int maxdims));
+int IOread PROTO((IOFile deviceID,void *data));
+int IOseek PROTO((IOFile deviceID,int dataset_index));
+int IOnDatasets PROTO((IOFile deviceID));
+int IOwriteAnnotation PROTO((IOFile deviceID,char *annotation));
+int IOreadAnnotation PROTO((IOFile deviceID,int index,char *annotation,int maxsize));
+int IOreadAnnotationInfo PROTO((IOFile deviceID,int index,int *size));
+int IOnAnnotations PROTO((IOFile deviceID));
+
+int IOwriteAttribute PROTO((IOFile deviceID,char *name,int type,Long length,void *data));
+int IOreadIndexedAttributeInfo PROTO((IOFile deviceID,int number,
+ char *name,int *type,Long *nelem,int maxnamelen));
+int IOreadAttributeInfo PROTO((IOFile deviceID,char *name,int *type,Long *nelem));
+int IOreadAttribute PROTO((IOFile deviceID,int number,void *data));
+int IOnAttributes PROTO((IOFile deviceID));
+int IOreserveChunk PROTO((IOFile deviceID,int typeID,int rank,int *dims));
+int IOwriteChunk PROTO((IOFile deviceID,int *chunkdims,int *chunkorigin,void *data));
+int IOreadChunk PROTO((IOFile deviceID,int *chunkdims,int *chunkorigin,void *data));
+int IOwriteStream PROTO((IOFile deviceID,void *data,int length));
+int IOreadStream PROTO((IOFile deviceID,void *data,int length));
+int IOpause PROTO((IOFile deviceID));
+int IOresume PROTO((IOFile deviceID));
+#endif
diff --git a/src/IOspeed.cc b/src/IOspeed.cc
new file mode 100644
index 0000000..a0003e4
--- /dev/null
+++ b/src/IOspeed.cc
@@ -0,0 +1,183 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <limits.h>
+#include <time.h>
+#include "Arch.h"
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "HDFIO.hh"
+#include "FlexArrayTmpl.H"
+
+#define f_openf77 F77NAME(openf77_,openf77,OPENF77)
+#define f_writef77 F77NAME(writef77_,writef77,WRITEF77)
+#define f_closef77 F77NAME(closef77_,closef77,CLOSEF77)
+extern "C" {
+void f_openf77();
+void f_writef77(double *data);
+void f_closef77();
+}
+
+//typedef FlexArray<float> FloatVector;
+//
+//class fVectorStatistics : public FloatVector {
+// fVectorStatistics(int sz=0):FloatVector(sz){}
+//};
+
+struct ResultRecord {
+ float usertime,systemtime,realtime,combined,nbytes,megs_per_second;
+ // ResultRecord():usertime(0),systemtime(0),realtime(0),
+ // combined(0),nbytes(0),megs_per_second(0){}
+};
+
+#define ClearLine fprintf(stderr,"\r \r")
+
+struct ResultRecordList {
+ FlexArray<ResultRecord> results;
+ ResultRecord average_results;
+ ResultRecordList(){}
+ void append(ResultRecord &rec);
+ ResultRecord &operator[](int index){
+ return results[index];
+ }
+
+};
+
+void ResultRecordList::append(ResultRecord &rec){
+ int idx=results.getSize();
+ float nrecs=(float)idx;
+ results.append(rec);
+ average_results.usertime=(average_results.usertime*nrecs+rec.usertime)/(nrecs+1);
+ average_results.systemtime=(average_results.systemtime*nrecs+rec.systemtime)/(nrecs+1);
+ average_results.realtime=(average_results.realtime*nrecs+rec.realtime)/(nrecs+1);
+ average_results.combined=(average_results.combined*nrecs+rec.combined)/(nrecs+1);
+ average_results.nbytes=(average_results.nbytes*nrecs+rec.nbytes)/(nrecs+1);
+ rec.megs_per_second = (double)(rec.nbytes)/(1024.0L*1024.0L*(double)rec.realtime);
+ average_results.megs_per_second = (average_results.megs_per_second*nrecs+rec.megs_per_second)/(nrecs+1);
+}
+
+void main(int argc,char *argv[]){
+ double data[64*64*64];
+ int dims[3]={64,64,64};
+ int i,nds;
+ int ntests;
+ struct tms stms,etms;
+ struct timeval stmv,etmv;
+ double srt,ert;
+ ResultRecordList ieeeio_results,f77_results,hdf_results;
+
+ if(argc>1){
+ ntests=atoi(argv[1]);
+ printf("Ntests=%u\n",ntests);
+ }
+ else {
+ ntests=1;
+ }
+
+ for(int tst=0;tst<ntests;tst++){
+ ResultRecord results;
+
+ printf("\nTrial %u --------------\n",tst); // next line
+ puts("--------------IEEE--------------");
+ for(i=0,nds=5;i<8;i++,nds+=5){
+ fprintf(stderr,"IEEEIO <open speed.raw> ");
+ times(&stms);
+ gettimeofday(&stmv);
+ IObase *file = new IEEEIO("speed.raw",IObase::Write);
+ fprintf(stderr,"Write %2u datasets:",nds);
+ for(int n=0;n<nds;n++){
+ fprintf(stderr,"*");
+ file->write(IObase::Float64,3,dims,data);
+ }
+ delete file;
+ gettimeofday(&etmv);
+ times(&etms); // times after close to account for buffer flushing
+ puts("");
+ ert=(double)etmv.tv_sec + (double)etmv.tv_usec/1000000.0L;
+ srt=(double)stmv.tv_sec + (double)stmv.tv_usec/1000000.0L;
+ results.realtime = ert-srt;
+ results.usertime = (float)(etms.tms_utime-stms.tms_utime)/CLK_TCK;
+ results.systemtime = (float)(etms.tms_stime-stms.tms_stime)/CLK_TCK;
+ results.combined = (float)(etms.tms_utime-stms.tms_utime+
+ etms.tms_stime-stms.tms_stime)/CLK_TCK;
+ results.nbytes = (float)(nds*IObase::nBytes(IObase::Float64,3,dims));
+ ieeeio_results.append(results);
+ }
+ puts("--------------HDF---------------");
+ for(i=0,nds=5;i<8;i++,nds+=5){
+ fprintf(stderr,"HDF <open speed.hdf> ");
+ times(&stms);
+ gettimeofday(&stmv);
+ IObase *file = new HDFIO("speed.hdf",IObase::Write);
+ fprintf(stderr,"Write %2u datasets:",nds);
+ for(int n=0;n<nds;n++){
+ fprintf(stderr,"*");
+ file->write(IObase::Float64,3,dims,data);
+ }
+ delete file;
+ gettimeofday(&etmv);
+ times(&etms); // times after close to account for buffer flushing
+ puts("");
+ ert=(double)etmv.tv_sec + (double)etmv.tv_usec/1000000.0L;
+ srt=(double)stmv.tv_sec + (double)stmv.tv_usec/1000000.0L;
+ results.realtime = ert-srt;
+ results.usertime = (float)(etms.tms_utime-stms.tms_utime)/CLK_TCK;
+ results.systemtime = (float)(etms.tms_stime-stms.tms_stime)/CLK_TCK;
+ results.combined = (float)(etms.tms_utime-stms.tms_utime+
+ etms.tms_stime-stms.tms_stime)/CLK_TCK;
+ results.nbytes = (float)(nds*IObase::nBytes(IObase::Float64,3,dims));
+ hdf_results.append(results);
+ }
+ puts("-------------F77 Unformatted---------------");
+ for(i=0,nds=5;i<8;i++,nds+=5){
+ fprintf(stderr,"F77 Unf <open f77speed.unf> ");
+ times(&stms);
+ gettimeofday(&stmv);
+ f_openf77();
+ fprintf(stderr,"Write %2u datasets:",nds);
+ for(int n=0;n<nds;n++){
+ fprintf(stderr,"*");
+ f_writef77(data);
+ }
+ f_closef77();
+ gettimeofday(&etmv);
+ times(&etms); // times after close to account for buffer flushing
+ puts("");
+ ert=(double)etmv.tv_sec + (double)etmv.tv_usec/1000000.0L;
+ srt=(double)stmv.tv_sec + (double)stmv.tv_usec/1000000.0L;
+ results.realtime = ert-srt;
+ results.usertime = (float)(etms.tms_utime-stms.tms_utime)/CLK_TCK;
+ results.systemtime = (float)(etms.tms_stime-stms.tms_stime)/CLK_TCK;
+ results.combined = (float)(etms.tms_utime-stms.tms_utime+
+ etms.tms_stime-stms.tms_stime)/CLK_TCK;
+ results.nbytes = (float)(nds*IObase::nBytes(IObase::Float64,3,dims));
+ f77_results.append(results);
+ }
+ }
+
+ // Now for all of the results
+ printf("-------IEEE: Average of %u trials------------\n",ntests);
+ printf("\tRealtime=%f, UserTime=%f, SystemTime=%f, Combined=%f Megs/sec=%f\n",
+ ieeeio_results.average_results.realtime,
+ ieeeio_results.average_results.usertime,
+ ieeeio_results.average_results.systemtime,
+ ieeeio_results.average_results.combined,
+ ieeeio_results.average_results.megs_per_second);
+ printf("-------HDF: Average of %u trials------------\n",ntests);
+ printf("\tRealtime=%f, UserTime=%f, SystemTime=%f, Combined=%f Megs/sec=%f\n",
+ hdf_results.average_results.realtime,
+ hdf_results.average_results.usertime,
+ hdf_results.average_results.systemtime,
+ hdf_results.average_results.combined,
+ hdf_results.average_results.megs_per_second);
+ printf("-------F77 UNF: Average of %u trials------------\n",ntests);
+ printf("\tRealtime=%f, UserTime=%f, SystemTime=%f, Combined=%f Megs/sec=%f\n",
+ f77_results.average_results.realtime,
+ f77_results.average_results.usertime,
+ f77_results.average_results.systemtime,
+ f77_results.average_results.combined,
+ f77_results.average_results.megs_per_second);
+}
+
+
diff --git a/src/MPIO.cc b/src/MPIO.cc
new file mode 100644
index 0000000..dcba3f8
--- /dev/null
+++ b/src/MPIO.cc
@@ -0,0 +1,199 @@
+#include <stdio.h>
+#include "MPIO.hh"
+
+MPIO::MPIO(IEEEIO *io, MPIcomm &c):file(io),comm(c),sendreq(0){
+
+ for(int i=0;i<3;i++) globaldims[i]=localdims[i]=localorigin[i]=0;
+ myid=comm.rank();
+
+ int *rootarray=0;
+ if(!myid) rootarray=new int[comm.numProcs()];
+ int hasfile= file?1:0;
+ comm.gather(0,1,&hasfile,rootarray);
+ if(!myid){
+ int count,p;
+ for(count=0,p=0;p<comm.numProcs();p++){
+ if(rootarray[p]) { count++; if(count<=1) root=p; }
+ }
+ if(count<=0 || count>1){
+ fprintf(stderr,"MPIO only accepts a single IO node right now.\n");
+ fprintf(stderr,"You chose %u io nodes\n",count);
+ fprintf(stderr,"I will select only the first one\n");
+ }
+ }
+ for(int i=0;i<3;i++) slicebuffer[i]=0;
+ for(int i=0;i<2;i++) recvreq[i]=0;
+ comm.bcast(0,root); // tell everyone which proc is root
+ if(rootarray) {delete rootarray; rootarray=0;}
+}
+
+MPIO::~MPIO(){}
+
+void MPIO::setLocalDims(int rank,int *origin, int *dims){
+ if(rank!=3) perror("MPIO is only for 3D IO for now (sorry)!");
+ if(sendreq) { puts("Bad move!!! Die!!!"); exit(0); }
+ // now check to see if anything has changed
+ // actually we still need to do this collection because we
+ // don't know if something might have changed on some other processor
+ // URK...
+ allorigins = new int[3*comm.numProcs()];
+ alldims = new int[3*comm.numProcs()];
+ for(int i=0;i<3;i++) {
+ //printf("localdims-n-origin[%u] = %u:%u\n",i,dims[i],origin[i]);
+ localdims[i]=dims[i];
+ localorigin[i]=origin[i];
+ }
+ for(int i=0;i<comm.numProcs()*3;i++) alldims[i]=allorigins[i]=-1;
+ comm.gather(0,3,localdims,alldims);
+ comm.gather(0,3,localorigin,allorigins);
+
+ comm.bcast(0,comm.numProcs()*3,alldims);
+ comm.bcast(0,comm.numProcs()*3,allorigins);
+
+ // now everyone figures out the global dimensions
+ // from max offset+dims
+ for(int p=0,last=3*comm.numProcs();p<last;p++){
+ // if(myid) fprintf(stderr,"Proc[%u] p=%d p%3=%d size=%d\n\to:d = %d:%d\n",
+ // if(myid) fprintf(stderr,"Proc[%u] p=%d o:d = %d:%d\n",
+ // myid,p,/* p%3,alldims[p]+allorigins[p],*/
+ // allorigins[p],alldims[p]);
+ if(globaldims[p%3] < alldims[p]+allorigins[p])
+ globaldims[p%3] = alldims[p]+allorigins[p];
+ }
+ // nothing to rebroadcast here...
+ //fprintf(stderr,"PE(%u): setLocalDims: globaldims=%u,%u,%d\n",
+ // myid,globaldims[0],globaldims[1],globaldims[2]);
+ // lets re-compute the requests and stuff
+ if(sendreq) delete sendreq; // clean out the old stuff
+ sendreq = new MPI_Request[localdims[2]];
+ if(isRoot()){
+ for(int i=0;i<3;i++) {
+ if(slicebuffer[i]) delete slicebuffer[i];
+ slicebuffer[i] = new float[globaldims[0]*globaldims[1]*3+27]; // padded (extremely)
+ }
+ // printf("Slicebuffer size=%u\n",globaldims[0]*globaldims[1]*2);
+ for(int i=0;i<2;i++) {
+ if(recvreq[i]) delete recvreq[i];
+ recvreq[i] = new MPI_Request[comm.numProcs()*4+7]; // padded
+ }
+ }
+}
+
+void MPIO::asyncWrite(float *data){
+ //puts("Begin AsyncWrite");
+ // get things started by getting root to request initial slice
+ if(isRoot()){
+ requestSlice(0,slicebuffer[0],recvreq[0]);
+ }
+ // comm.print("Requested First Slice");
+ // now everyone sends their slice over
+ sendSlice(0,data,sendreq); // separate request for each slice
+ //comm.print("Sent First slice");
+ if(isRoot()){
+ file->reserveStream(IObase::Float32,3,globaldims);
+ }
+ for(int i=1;i<globaldims[2];i++){
+ if(isRoot()) // if I'm root, then make request for nex slice
+ requestSlice(i,slicebuffer[i%2],recvreq[i%2]);
+ sendSlice(i,data,sendreq); // separate sendreq for each slice
+ if(isRoot()) {
+ // waitfor slice and assemble into the slicebuffer
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ // now write assembled slice to disk stream
+ // can make disk buffer huge to simulate recieving multiple
+ // slices
+ //fprintf(stderr,"WriteStream Slice %u\n",i-1);
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ }
+ }
+ if(isRoot()){
+ int n = globaldims[2]-1;
+ waitForSlice(n,slicebuffer[(n)%2],slicebuffer[2],recvreq[(n)%2]);
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ // do requestfree (double-buffered request free-s)
+ //for(int i=0;i<3;i++) delete slicebuffer[i]; // free everything up
+ //for(int i=0;i<2;i++) delete recvreq[i];
+ }
+ //**** At end (matching deletes) ****
+ // fprintf(stderr,"Cleanup proc %u\n",myid);
+ // comm.print("Cleanup");
+ for(int n=0;n<localdims[2];n++){
+ MPI_Status stat;
+ comm.wait(sendreq[n],stat);
+ }
+ // perhaps should be a persistent variable
+ // delete sendreq;
+ //sendreq=0; // null it out so we know we are done
+}
+
+void MPIO::sendSlice(int z,float *data,MPI_Request *req){
+ int lz = z - localorigin[2]; // find local z-offset here
+ // filter out bogus requests
+ // send even redundant information though...
+ if(lz<0 || lz >=localdims[2]) return;
+ // fprintf(stderr,"\tSendSlice: Proc %u Slice %u sndindex=%u\n",
+ // myid,z,lz);
+ comm.iSend(root,z,
+ localdims[0]*localdims[1], // size of the data
+ data+localdims[0]*localdims[1]*lz,req[lz]);
+}
+
+int MPIO::requestSlice(int z,float *slicebuf, MPI_Request *req){
+ if(!isRoot()) return 0; // only root performs this operation
+ // for every processor that intersects this slice boundary,
+ // make a request for the contents of that slice!
+ int reqindex =0;
+ for(int offset=0,p=0;p<comm.numProcs();p++){
+ int idx = 3*p;
+ int *dims = alldims+idx;
+ int *origin = allorigins+idx; // need to pre-fix the origins here?
+ // thus to prevent mishandling of ghost zones here.
+ // or else have provision to support multi-reception of the same
+ // tile..... well actually we can do that already...
+ // we just have to have buckets for 2x more requests.
+ if(z>=origin[2] && z<origin[2]+dims[2]){
+ // fprintf(stderr,"\tRequestSlice: Proc %u Slice %u reqindex=%u\n",
+ // p,z,reqindex);
+ comm.iRecv(p,z,dims[0]*dims[1],slicebuf+offset,req[reqindex++]);
+ // fprintf(stderr,"\tSlicebuf offset=%u of size %u ++ end=%u vs sbsize=%u %u:%u @ %u:%u\n",
+ // offset,dims[0]*dims[1],
+ // offset+dims[0]*dims[1],globaldims[0]*globaldims[1]*2,
+ // globaldims[0],globaldims[1],dims[0],dims[1]);
+ offset+=dims[0]*dims[1];
+ }
+ }
+ return reqindex;
+}
+
+/*
+Problems: Slice size is too small for slice reception with ghost zones
+Also doesn't get proper offset to each slice in the slice buffer (maybe ok)
+
+ */
+
+void MPIO::waitForSlice(int z,float *slicebuf,
+ float *destbuffer,MPI_Request *req){
+ if(!isRoot()) return;
+ for(int p=0,reqindex=0;p<comm.numProcs();p++) {
+ MPI_Status stat;
+ int idx = 3*p;
+ int *dims = alldims+idx;
+ int *origin = allorigins+idx; // need to pre-fix the origins here?
+ // thus to prevent mishandling of ghost zones here.
+ if(z>=origin[2] && z<origin[2]+dims[2]){
+ // wiat for the data transfer to complete
+ //fprintf(stderr,"\tWaitSlice: Proc %u Slice %u reqindex=%u\n",
+ // p,z,reqindex);
+ comm.wait(req[reqindex++],stat); // frees request object too
+ // now we integrate the slices together. (data unscrambling phase)
+ //fprintf(stderr,"\t****Now Unscramble\n");
+ int offset = origin[1]*globaldims[0] + origin[0]; // initial offset for dst
+ for(int idx=0,pos=offset,j=0;j<dims[1];j++,pos+=(globaldims[0]-dims[0])){
+ for(int i=0;i<dims[0];i++){
+ destbuffer[pos++]=slicebuf[idx++]; // FUCK!!!! idx is questionable
+ }
+ }
+ // fprintf(stderr,"\t*****\n");
+ }
+ }
+}
diff --git a/src/MPIO.fast.cc b/src/MPIO.fast.cc
new file mode 100644
index 0000000..d9d6bf5
--- /dev/null
+++ b/src/MPIO.fast.cc
@@ -0,0 +1,257 @@
+#include <stdio.h>
+#include "MPIutils.hh"
+#include "MPIO.hh"
+
+void MPIO::requestSlice(int z,float *slicebuffer,MPI_Request *req){
+ // skip to z
+ //loop (foreach p of pe's)
+ if(!isRoot()) return;
+ //printf("requestSlice %u",z);
+ for(int reqindex=0,offset=0,idx=slicemap[z],lastchunk=slicemap[z]+chunkindexcount[z];
+ idx<lastchunk;idx++,reqindex++){
+ int p = procmap[idx];
+ int *idims = gdims+chunkindex[idx];
+ int *iorigin = gorigins + chunkindex[idx];
+ comm.iRecv(p,z,idims[0]*idims[1],slicebuffer+offset,req[reqindex]);
+ //printf("reqslice(%u):MPI_Request=%u\n",z,req[reqindex]);
+ offset+=idims[0]*idims[1];
+ }
+ // break if outside of z-range (dangerous if non-canonical proc layout)
+}
+
+void MPIO::waitForSlice(int z,float *slicebuffer,float *destbuffer,MPI_Request *req){
+ if(!isRoot()) return;
+ // printf("waitforslice %u\n",z);
+ // could do this 8k at a time
+ // loop for each p of pe's
+ // if within z-range, compute nelem based on dims at p
+ // wait for current request.
+ // re-copy based on offset & origin
+ sliceallwait.start();
+ //printf("z(%u) slicemap(%u) len(%u)\n",z,slicemap[z],chunkindexcount[z]);
+ for(int reqindex=0,chunkidx=slicemap[z],lastchunk=slicemap[z]+chunkindexcount[z];
+ chunkidx<lastchunk;chunkidx++,reqindex++){
+ //int debug=0;
+ //if(z>=38) debug=1;
+ int p = procmap[chunkidx];
+ //if(debug) printf("\tp=%u\n",p);
+ int *idims = gdims + chunkindex[chunkidx];
+ //if(debug) printf("\tdims(%u)=%u:%u:%u\n",chunkidx,idims[0],idims[1],idims[2]);
+ int *iorigin = gorigins + chunkindex[chunkidx];
+ //if(debug) printf("\torigin=%u:%u:%u\n",iorigin[0],iorigin[1],iorigin[2]);
+ MPI_Status stat;
+ //printf("waitfor(%u):MPI_Request[%u]=%u\n",z,reqindex,req[reqindex]);
+ // slicewait.start();
+ comm.wait(req[reqindex],stat); // frees request object too
+ //slicewait.stop();
+ // get information out of the status object!!!!
+ //slicecollect.start();
+ int offset = iorigin[1]*globaldims[0] + iorigin[0];
+ for(int idx=0,pos=offset,j=0;j<idims[1];j++,pos+=(globaldims[0]-idims[0]))
+ for(int i=0;i<idims[0];i++)
+ destbuffer[pos++]=slicebuffer[idx++];
+ // slicecollect.stop();
+ }
+ sliceallwait.stop();
+ // proclist array
+}
+
+MPIO::MPIO(IObase *io,MPIcomm &c):file(io),comm(c),slicemap(0),procmap(0),chunkindex(0),chunkindexcount(0){
+ for(int i=0;i<3;i++) globaldims[i]=localdims[i]=localorigin[i]=0;
+ int *rootarray;
+ myid = comm.rank();
+ //printf("my rank = %u\n",myid);
+ if(!myid) rootarray = new int[comm.numProcs()];
+ int rootscale = file?1:0;
+ //printf("rootscale[pid=%u] = %u\n",myid,rootscale);
+ comm.gather(0,1,&rootscale,rootarray); // gather to 0
+ globaldims[0]=globaldims[1]=globaldims[2]=0;
+ if(!myid){
+ for(int count=0,p=0;p<comm.numProcs();p++){
+ //printf("rootarray[%u]=%u\n",p,rootarray[p]);
+ if(rootarray[p]) count++;
+ }
+ if(count<=0 || count>1){
+ fprintf(stderr,"MPIO only accepts a single IO node right now.\n");
+ fprintf(stderr,"You chose %u io nodes\n",count);
+ fprintf(stderr,"I will select only the first one\n");
+ }
+ for(root=-1,p=0;p<comm.numProcs() && root<0;p++)
+ if(rootarray[p]) root=p;
+ delete rootarray;
+ }
+ comm.bcast(0,root); // now everyone knows root
+ //printf("broadcasting root node = %u\n",root);
+}
+
+MPIO::~MPIO(){
+ char buffer[32];
+ sprintf(buffer,"PE(%3u)",comm.rank());
+ if(myid==root) {
+ sprintf(buffer+7,"slicewait"); slicewait.print(buffer);
+ sprintf(buffer+7,"slicewrite"); slicewrite.print(buffer);
+ sprintf(buffer+7,"slicecollect"); slicecollect.print(buffer);
+ //sprintf(buffer+7,"sliceselect"); sliceselect.print(buffer);
+ sprintf(buffer+7,"sliceallwait"); sliceallwait.print(buffer);
+ }
+}
+
+void MPIO::setLocalDims(int rank,int *origin, int *dims){
+ if(rank!=3) perror("MPIO is only for 3D IO for now (sorry)!");
+ if(isRoot()){
+ gorigins = new int[3*comm.numProcs()];
+ gdims = new int[3*comm.numProcs()];
+ }
+ else gdims=gorigins=0; // null for everyone else
+ for(int i=0;i<3;i++) {
+ //printf("localdims-n-origin[%u] = %u:%u\n",i,dims[i],origin[i]);
+ localdims[i]=dims[i];
+ localorigin[i]=origin[i];
+ }
+ comm.gather(root,3,localdims,gdims);
+ comm.gather(root,3,localorigin,gorigins);
+ //if(isRoot()) for(i=0;i<3*comm.numProcs();i++)
+ //printf("gdims-n-origin[%u] = %u:%u\n",i,gdims[i],gorigins[i]);
+ globaldims[0]=globaldims[1]=globaldims[2]=0;
+ if(isRoot())
+ for(int p=0,last=3*comm.numProcs();p<last;p++){
+ //printf("globaldims[%u]: gdims[%u]+gorigins[%u] = %u\n",
+ // p%3,p,p,gdims[p],gorigins[p]);
+ if(globaldims[p%3] < gdims[p]+gorigins[p])
+ globaldims[p%3] = gdims[p]+gorigins[p];
+ }
+ // rebroadcast globaldims to all PE's
+ comm.bcast(root,3,globaldims);
+ // do we bcast the layout?
+ // Now organize the info hierarchially by Z (index into)
+ if(isRoot()){
+ if(slicemap){
+ delete slicemap;
+ delete procmap;
+ delete chunkindex;
+ delete chunkindexcount;
+ }
+ //puts("(1)");
+ slicemap = new int[globaldims[2]+1];
+ chunkindexcount = new int[globaldims[2]+1];
+ {
+ for(int thickness=0,chunkcount=0,z=0;z<globaldims[2];z+=thickness){
+ for(int p=0;p<comm.numProcs();p++){
+ // count slices
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ thickness = gdims[2]; // assumes uniform domain decomp in Z
+ chunkcount++;
+ }
+ }
+ // procmap = new int[chunkcount];
+ //chunkindex = new int[chunkcount]; // points into iorigin/idims
+ // chunkindexcount = chunkcount;
+ }
+ procmap = new int[comm.numProcs()];
+ chunkindex = new int [comm.numProcs()];
+ // printf("(2): chunkindexcount = %u\n",chunkindexcount);
+ for(int thickness=0,mapcount=0,chunkcount=0,z=0;z<globaldims[2];z+=thickness){
+ for(int p=0;p<comm.numProcs();p++){
+ // count slices
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ thickness = gdims[2];
+ procmap[chunkcount] = p;
+ chunkindex[chunkcount] = dindex; // point into iorogin/idims
+ //printf("chunkcount=%u chunkindex=%u\n",chunkcount,chunkindex[chunkcount]);
+ chunkcount++;
+ }
+ }
+ //puts("(3)");
+ for(chunkcount=0,z=0;z<globaldims[2];){
+ int thickness=0;
+ for(int levelcount=0,p=0;p<comm.numProcs();p++){
+ // count slices
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ thickness = gdims[2];
+ levelcount++; chunkcount++;
+ }
+ for(int pz=0;pz<thickness && z<=globaldims[2];pz++,z++){
+ chunkindexcount[z]=levelcount;
+ slicemap[z] = chunkcount - levelcount; // selects chunkindex from slicenum
+ //printf("slicemap[%u]= %u\n",z,slicemap[z]);
+ }
+ }
+ //printf("last map count = %u\n",z);
+ //slicemap[z] = chunkcount;
+ }
+}
+
+int MPIO::write(IObase::DataType type,int rank,int *dims,void *data){
+ int recalc_layout=0;
+ if(rank!=3) recalc_layout=1;
+ for(int i=0;i<rank;i++) if(localdims[i]!=dims[i]) recalc_layout=1;
+ if(recalc_layout) setLocalDims(rank,localorigin,dims);
+ switch(type){
+ case IObase::Float32:
+ write((float*)data);
+ break;
+ case IObase::Float64:
+ default:
+ break;
+ }
+ return 1; // for now, no error checking
+}
+
+void MPIO::write(float *data){
+ MPI_Request *sendreq = new MPI_Request[localdims[2]];
+ typedef float *floatP;
+ int sliceindex=0;
+ floatP slicebuffer[3]; // double-buffer the slices as they arrive
+ typedef MPI_Request *MPI_RequestP;
+ MPI_RequestP recvreq[2];
+ // the third one is a scratch buffer for reorganizing the slice
+ if(isRoot()){
+ for(int i=0;i<3;i++) slicebuffer[i] = new float[globaldims[0]*globaldims[1]];
+ for(i=0;i<2;i++) recvreq[i] = new MPI_Request[comm.numProcs()];
+ }
+ if(isRoot()){
+ // puts("request initial slice");
+ requestSlice(0,slicebuffer[0],recvreq[0]);
+ }
+ // not good! Everyone is sending a slice here!
+ sendSlice(0,data,sendreq);
+ // hide latency behind the costly io->reserveChunk operation
+ if(isRoot()) file->reserveStream(IObase::Float32,3,globaldims);
+ int writecount=0;
+ for(int i=1;i<globaldims[2];i++){
+ comm.barrier(); // clearly not!
+ if(isRoot())
+ requestSlice(i,slicebuffer[i%2],recvreq[i%2]);
+ sendSlice(i,data,sendreq); // jms
+ if(isRoot()) {
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ writecount+=globaldims[0]*globaldims[1];
+ slicewrite.start();
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ slicewrite.stop();
+ }
+ }
+ if(isRoot()){
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ writecount+=globaldims[0]*globaldims[1];
+ // do requestfree (double-buffered request free-s)
+ for(i=0;i<3;i++) delete slicebuffer[i]; // free everything up
+ for(i=0;i<2;i++) delete recvreq[i];
+ }
+ MPI_Status stat;
+ for(i=0;i<localdims[2];i++) comm.wait(sendreq[i],stat);
+ delete sendreq;
+}
diff --git a/src/MPIO.fast.hh b/src/MPIO.fast.hh
new file mode 100644
index 0000000..51d5b03
--- /dev/null
+++ b/src/MPIO.fast.hh
@@ -0,0 +1,66 @@
+#ifndef __MPIO_HH_
+#define __MPIO_HH_
+#include "IO.hh"
+#include "MPIutils.hh"
+#include "Timer.H"
+
+/* Simplifies assumptions about domain decomposition */
+/*
+ Module: MPIO
+
+ Description:
+ Implements slice-based Parallel IO for IEEEIO libraries.
+ Uses iSend/iRecv of XY slices to hide message passing latency.
+ This is a simplified version of PIO which makes fewer assumptions
+ about the layout of the data.
+
+ Will eventually be subclassed from IObase so that you can
+ drop-in replace a single-threaded IO system with this
+ multithreaded one. writeChunk() will be used to announce
+ the local chunks and perform the write in parallel rather
+ than collecting serially.
+
+ Needs to have extensions to automatically remove ghost zones
+ setLocalDims(origin,dims,minindex,maxindex)
+
+ Limitations:
+ * currently only works for 3D grids
+ * only understands Float32 and Float64 datatypes
+ * Assumes HPF layout (eg, canonical processor layout where
+ all PE's are aligned to grid... no partial overlaps)
+ * Uses XY slices (assumes fortran ordering for dimensions)
+ * Collects only to a single file (cannot do a multi-gather).
+ */
+class MPIO /* : public IObase */ {
+ int *gdims,*gorigins,grank;
+ MPIcomm &comm;
+ int globaldims[3]; // for master
+ int localorigin[3],localdims[3];
+ int root,myid;
+ IObase *file;
+ Timer slicewait,slicewrite,slicecollect,sliceselect;
+ Timer sliceallwait;
+ int *chunkindex,*chunkindexcount,*slicemap,*procmap;
+ inline int isRoot(){ return ((myid == root)?1:0);}
+ // MPI_Request *slice_send_requests;
+protected:
+ inline void sendSlice(int z,float *data,MPI_Request *req);
+ void requestSlice(int z,float *slicebuffer,MPI_Request *req);
+ void waitForSlice(int z,float *slicebuffer,float *destbuffer,MPI_Request *req);
+public:
+ MPIO(IObase *io,MPIcomm &c);
+ ~MPIO();
+ void setLocalDims(int rank,int *origin, int *dims);
+ virtual int write(IObase::DataType type,int rank,int *dims,void *data);
+ void write(float *data);
+};
+
+void MPIO::sendSlice(int z,float *data,MPI_Request *req){
+ int iz = z - localorigin[2];
+ if(iz<0 || iz>=localdims[2]) return;
+ //printf("sendslice %u\n",z);
+ comm.isSend(root,z,localdims[0]*localdims[1],
+ data+localdims[0]*localdims[1]*iz,req[iz]);
+}
+
+#endif // __MPIO_HH_
diff --git a/src/MPIO.h b/src/MPIO.h
new file mode 100644
index 0000000..cf969f8
--- /dev/null
+++ b/src/MPIO.h
@@ -0,0 +1,16 @@
+#ifndef __MPIO_H_
+#define __MPIO_H_
+
+#include "Arch.h"
+
+/*********************C Interface**********************/
+
+IOFile MPIOopen (IOFile fid);
+
+int MPIOclose (IOFile deviceID);
+
+void MPIOsetLocalDims (IOFile deviceID, int rank, int *origin, int *dims);
+
+int MPIOwrite (IOFile deviceID, int typeID, void *data);
+
+#endif
diff --git a/src/MPIO.hh b/src/MPIO.hh
new file mode 100644
index 0000000..67bfebd
--- /dev/null
+++ b/src/MPIO.hh
@@ -0,0 +1,39 @@
+#ifndef __MPIO_HH_
+#define __MPIO_HH_
+
+#include "IEEEIO.hh"
+#include "MPIutils.hh"
+#include "Timer.hh"
+
+class MPIO {
+typedef float *floatP;
+typedef MPI_Request *MPI_RequestP;
+
+ MPIcomm &comm;
+ int *alldims,*allorigins;
+ int globaldims[3]; // for all procs
+ int localorigin[3],localdims[3]; // local dims are full extent + bound & ghost
+ int root, myid;
+ IEEEIO *file; // only on master
+ MPI_Request *sendreq; // is it proper to have a pointer here?
+ MPI_RequestP recvreq[2]; // double-buffered
+ floatP slicebuffer[3]; // double-buffered + a scratch space
+
+
+protected:
+ void sendSlice(int z, float *data, MPI_Request *req);
+ int requestSlice(int z, float *slicebuffer, MPI_Request *req);
+ void waitForSlice(int z, float *slicebuffer, float *destbuffer, MPI_Request *req);
+ void asyncWrite(float *data);
+public:
+ MPIO(IEEEIO *io,MPIcomm &c);
+ ~MPIO();
+ inline int isRoot() { return ((myid==root)?1:0);}
+ void setLocalDims(int rank,int *origin,int *dims);
+ virtual int write(float *data){
+ asyncWrite(data);
+ return 1;
+ }
+};
+
+#endif
diff --git a/src/MPIO.old.cc b/src/MPIO.old.cc
new file mode 100644
index 0000000..ef609f1
--- /dev/null
+++ b/src/MPIO.old.cc
@@ -0,0 +1,344 @@
+#include <stdio.h>
+#include "MPIutils.hh"
+#include "MPIO.hh"
+
+#define CollectTime 0 /* not collecting timing data right now */
+
+void MPIO::sendSlice(int z,float *data,MPI_Request *req){
+ int iz = z - localorigin[2];
+ if(iz<0 || iz>=localdims[2]) return;
+ if(syncsend)
+ comm.isSend(root,z,localdims[0]*localdims[1],
+ data+localdims[0]*localdims[1]*iz,req[iz]);
+ else
+ comm.iSend(root,z,localdims[0]*localdims[1],
+ data+localdims[0]*localdims[1]*iz,req[iz]);
+}
+
+void MPIO::requestSlice(int z,float *slicebuffer,MPI_Request *req){
+ // skip to z
+ //loop (foreach p of pe's)
+ if(!isRoot()) return;
+ //printf("PE(%u) request slice %u\n",myid,z);
+ for(int offset=0,p=0,reqindex=0;p<comm.numProcs();p++) {
+ // if within z-range, compute nelem based on dims at p
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ comm.iRecv(p,z,idims[0]*idims[1],slicebuffer+offset,req[reqindex++]);
+ //printf("reqslice(%u):MPI_Request=%u\n",iz,req[reqindex-1]);
+ offset+=idims[0]*idims[1];
+ }
+ // break if outside of z-range (dangerous if non-canonical proc layout)
+}
+
+void MPIO::waitForSlice(int z,float *slicebuffer,float *destbuffer,MPI_Request *req){
+ if(!isRoot()) return;
+ // could do this 8k at a time
+ // loop for each p of pe's
+ // if within z-range, compute nelem based on dims at p
+ // wait for current request.
+ // re-copy based on offset & origin
+ if(CollectTime) sliceallwait.start();
+ for(int p=0,reqindex=0;p<comm.numProcs();p++) {
+ // if within z-rang e, compute nelem based on dims at p
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ MPI_Status stat;
+ //printf("waitfor(%u):MPI_Request=%u\n",iz,req[reqindex]);
+ if(CollectTime) slicewait.start();// this is a timer (start the timer)
+ comm.wait(req[reqindex++],stat); // frees request object too
+ if(CollectTime) slicewait.stop();
+ // get information out of the status object!!!!
+ if(CollectTime) slicecollect.start();
+ int offset = iorigin[1]*globaldims[0] + iorigin[0];
+ for(int idx=0,pos=offset,j=0;j<idims[1];j++,pos+=(globaldims[0]-idims[0]))
+ for(int i=0;i<idims[0];i++)
+ destbuffer[pos++]=slicebuffer[idx++];
+ if(CollectTime) slicecollect.stop();
+ }
+ if(CollectTime) sliceallwait.stop();
+ // proclist array
+
+}
+
+void MPIO::sendSlice(int z,double *data,MPI_Request *req){
+ int iz = z - localorigin[2];
+ if(iz<0 || iz>=localdims[2]) return;
+ if(syncsend)
+ comm.isSend(root,z,localdims[0]*localdims[1],
+ data+localdims[0]*localdims[1]*iz,req[iz]);
+ else
+ comm.iSend(root,z,localdims[0]*localdims[1],
+ data+localdims[0]*localdims[1]*iz,req[iz]);
+}
+
+void MPIO::requestSlice(int z,double *slicebuffer,MPI_Request *req){
+ // skip to z
+ //loop (foreach p of pe's)
+ if(!isRoot()) return;
+ //printf("PE(%u) request slice %u\n",myid,z);
+ for(int offset=0,p=0,reqindex=0;p<comm.numProcs();p++) {
+ // if within z-range, compute nelem based on dims at p
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ comm.iRecv(p,z,idims[0]*idims[1],slicebuffer+offset,req[reqindex++]);
+ //printf("reqslice(%u):MPI_Request=%u\n",iz,req[reqindex-1]);
+ offset+=idims[0]*idims[1];
+ }
+ // break if outside of z-range (dangerous if non-canonical proc layout)
+}
+
+void MPIO::waitForSlice(int z,double *slicebuffer,double *destbuffer,MPI_Request *req){
+ if(!isRoot()) return;
+ // could do this 8k at a time
+ // loop for each p of pe's
+ // if within z-range, compute nelem based on dims at p
+ // wait for current request.
+ // re-copy based on offset & origin
+ if(CollectTime) sliceallwait.start();
+ for(int p=0,reqindex=0;p<comm.numProcs();p++) {
+ // if within z-rang e, compute nelem based on dims at p
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ MPI_Status stat;
+ //printf("waitfor(%u):MPI_Request=%u\n",iz,req[reqindex]);
+ if(CollectTime) slicewait.start();// this is a timer (start the timer)
+ comm.wait(req[reqindex++],stat); // frees request object too
+ if(CollectTime) slicewait.stop();
+ // get information out of the status object!!!!
+ if(CollectTime) slicecollect.start();
+ int offset = iorigin[1]*globaldims[0] + iorigin[0];
+ for(int idx=0,pos=offset,j=0;j<idims[1];j++,pos+=(globaldims[0]-idims[0]))
+ for(int i=0;i<idims[0];i++)
+ destbuffer[pos++]=slicebuffer[idx++];
+ if(CollectTime) slicecollect.stop();
+ }
+ if(CollectTime) sliceallwait.stop();
+ // proclist array
+
+}
+
+MPIO::MPIO(IObase *io,MPIcomm &c):file(io),comm(c),sendreq(0){
+ for(int i=0;i<3;i++) globaldims[i]=localdims[i]=localorigin[i]=0;
+ int *rootarray;
+ myid = comm.rank();
+ //printf("my rank = %u\n",myid);
+ if(!myid) rootarray = new int[comm.numProcs()];
+ int rootscale = file?1:0;
+ //printf("rootscale[pid=%u] = %u\n",myid,rootscale);
+ comm.gather(0,1,&rootscale,rootarray); // gather to 0
+ globaldims[0]=globaldims[1]=globaldims[2]=0;
+ if(!myid){
+ int count,p;
+ for(count=0,p=0;p<comm.numProcs();p++){
+ //printf("rootarray[%u]=%u\n",p,rootarray[p]);
+ if(rootarray[p]) count++;
+ }
+ if(count<=0 || count>1){
+ fprintf(stderr,"MPIO only accepts a single IO node right now.\n");
+ fprintf(stderr,"You chose %u io nodes\n",count);
+ fprintf(stderr,"I will select only the first one\n");
+ }
+ for(root=-1,p=0;p<comm.numProcs() && root<0;p++)
+ if(rootarray[p]) root=p;
+ delete rootarray;
+ }
+ comm.bcast(0,root); // now everyone knows root
+ //printf("broadcasting root node = %u\n",root);
+}
+
+MPIO::~MPIO(){
+ char buffer[32];
+ if(CollectTime){
+ if(myid==root) {
+ sprintf(buffer+7,"slicewait"); slicewait.print(buffer);
+ sprintf(buffer+7,"slicewrite"); slicewrite.print(buffer);
+ sprintf(buffer+7,"slicecollect"); slicecollect.print(buffer);
+ //sprintf(buffer+7,"sliceselect"); sliceselect.print(buffer);
+ sprintf(buffer+7,"sliceallwait"); sliceallwait.print(buffer);
+ }
+ }
+}
+
+void MPIO::setLocalDims(int rank,int *origin, int *dims){
+ if(rank!=3) perror("MPIO is only for 3D IO for now (sorry)!");
+ if(sendreq) asyncFinalize();
+ if(isRoot()){
+ gorigins = new int[3*comm.numProcs()];
+ gdims = new int[3*comm.numProcs()];
+ }
+ else gdims=gorigins=0; // null for everyone else
+ for(int i=0;i<3;i++) {
+ //printf("localdims-n-origin[%u] = %u:%u\n",i,dims[i],origin[i]);
+ localdims[i]=dims[i];
+ localorigin[i]=origin[i];
+ ghostmin[i]=ghostmax[i]=0;
+ }
+ comm.gather(root,3,localdims,gdims);
+ comm.gather(root,3,localorigin,gorigins);
+ //if(isRoot()) for(i=0;i<3*comm.numProcs();i++)
+ //printf("gdims-n-origin[%u] = %u:%u\n",i,gdims[i],gorigins[i]);
+ globaldims[0]=globaldims[1]=globaldims[2]=0;
+ if(isRoot())
+ for(int p=0,last=3*comm.numProcs();p<last;p++){
+ //printf("globaldims[%u]: gdims[%u]+gorigins[%u] = %u\n",
+ // p%3,p,p,gdims[p],gorigins[p]);
+ if(globaldims[p%3] < gdims[p]+gorigins[p])
+ globaldims[p%3] = gdims[p]+gorigins[p];
+ }
+ // rebroadcast globaldims to all PE's
+ comm.bcast(root,3,globaldims);
+}
+void MPIO::setLocalDims(int rank,int *origin, int *dims,
+ int *nghostmin,int *nghostmax){
+ setLocalDims(rank,origin,dims);
+ for(int i=0;i<rank;i++){
+ ghostmin[i]=nghostmin[i];
+ ghostmax[i]=nghostmax[i];
+ }
+}
+int MPIO::write(IObase::DataType type,int rank,int *dims,void *data){
+ int recalc_layout=0;
+ if(rank!=3) recalc_layout=1;
+ for(int i=0;i<rank;i++) if(localdims[i]!=dims[i]) recalc_layout=1;
+ if(recalc_layout) setLocalDims(rank,localorigin,dims);
+ return write(type,data); // for now, no error checking
+}
+
+/* no layout recompute here.
+ This is for C and F77 support. */
+void MPIO::asyncWrite(IObase::DataType type,void *data){
+ switch(type){
+ case IObase::Float32:
+ asyncWrite((float*)data);
+ break;
+ case IObase::Float64:
+ asyncWrite((double*)data);
+ default:
+ break;
+ }
+}
+
+int MPIO::write(IObase::DataType type,void *data){
+ switch(type){
+ case IObase::Float32:
+ write((float*)data);
+ break;
+ case IObase::Float64:
+ write((double*)data);
+ default:
+ break;
+ }
+ return 1; // for now, no error checking
+}
+
+void MPIO::asyncWrite(float *data){
+ if(sendreq) return;
+ sendreq = new MPI_Request[localdims[2]];
+ typedef float *floatP;
+ // int sliceindex=0;
+ floatP slicebuffer[3]; // double-buffer the slices as they arrive
+ typedef MPI_Request *MPI_RequestP;
+ MPI_RequestP recvreq[2];
+ // the third one is a scratch buffer for reorganizing the slice
+ if(isRoot()){
+ for(int i=0;i<3;i++) slicebuffer[i] = new float[globaldims[0]*globaldims[1]];
+ for(int i=0;i<2;i++) recvreq[i] = new MPI_Request[comm.numProcs()];
+ }
+ if(isRoot()){
+ // puts("request initial slice");
+ requestSlice(0,slicebuffer[0],recvreq[0]);
+ }
+ // not good! Everyone is sending a slice here!
+ sendSlice(0,data,sendreq);
+ // hide latency behind the costly io->reserveChunk operation
+ if(isRoot()) file->reserveStream(IObase::Float32,3,globaldims);
+ int writecount=0;
+ for(int i=1;i<globaldims[2];i++){
+ // comm.barrier();
+ if(isRoot())
+ requestSlice(i,slicebuffer[i%2],recvreq[i%2]);
+ sendSlice(i,data,sendreq); // jms
+ if(isRoot()) {
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ writecount+=globaldims[0]*globaldims[1];
+ slicewrite.start();
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ slicewrite.stop();
+ }
+ }
+ if(isRoot()){
+ int n=globaldims[2]-1;
+ waitForSlice(n,slicebuffer[(n)%2],slicebuffer[2],recvreq[(n)%2]);
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ writecount+=globaldims[0]*globaldims[1];
+ // do requestfree (double-buffered request free-s)
+ for(int i=0;i<3;i++) delete slicebuffer[i]; // free everything up
+ for(int i=0;i<2;i++) delete recvreq[i];
+ }
+}
+
+void MPIO::asyncWrite(double *data){
+ if(sendreq) return;
+ sendreq = new MPI_Request[localdims[2]];
+ typedef double *doubleP;
+ // int sliceindex=0;
+ doubleP slicebuffer[3]; // double-buffer the slices as they arrive
+ typedef MPI_Request *MPI_RequestP;
+ MPI_RequestP recvreq[2];
+ // the third one is a scratch buffer for reorganizing the slice
+ if(isRoot()){
+ for(int i=0;i<3;i++) slicebuffer[i] = new double[globaldims[0]*globaldims[1]];
+ for(int i=0;i<2;i++) recvreq[i] = new MPI_Request[comm.numProcs()];
+ }
+ if(isRoot()){
+ // puts("request initial slice");
+ requestSlice(0,slicebuffer[0],recvreq[0]);
+ }
+ // not good! Everyone is sending a slice here!
+ sendSlice(0,data,sendreq);
+ // hide latency behind the costly io->reserveChunk operation
+ if(isRoot()) file->reserveStream(IObase::Float64,3,globaldims);
+ int writecount=0;
+ for(int i=1;i<globaldims[2];i++){
+ // comm.barrier();
+ if(isRoot())
+ requestSlice(i,slicebuffer[i%2],recvreq[i%2]);
+ sendSlice(i,data,sendreq); // jms
+ if(isRoot()) {
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ writecount+=globaldims[0]*globaldims[1];
+ slicewrite.start();
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ slicewrite.stop();
+ }
+ }
+ if(isRoot()){
+ int n = globaldims[2]-1;
+ waitForSlice(n,slicebuffer[(n)%2],slicebuffer[2],recvreq[(n)%2]);
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ writecount+=globaldims[0]*globaldims[1];
+ // do requestfree (double-buffered request free-s)
+ for(int i=0;i<3;i++) delete slicebuffer[i]; // free everything up
+ for(int i=0;i<2;i++) delete recvreq[i];
+ }
+}
+void MPIO::asyncFinalize(){
+ MPI_Status stat;
+ if(!sendreq) return;
+ for(int i=0;i<localdims[2];i++) comm.wait(sendreq[i],stat);
+ delete sendreq;
+ sendreq=0;
+}
diff --git a/src/MPIO.old.hh b/src/MPIO.old.hh
new file mode 100644
index 0000000..8b90946
--- /dev/null
+++ b/src/MPIO.old.hh
@@ -0,0 +1,80 @@
+#ifndef __MPIO_HH_
+#define __MPIO_HH_
+#include "IO.hh"
+#include "MPIutils.hh"
+#include "Timer.hh"
+
+/* Simplifies assumptions about domain decomposition */
+/*
+ Module: MPIO
+
+ Description:
+ Implements slice-based Parallel IO for IEEEIO libraries.
+ Uses iSend/iRecv of XY slices to hide message passing latency.
+ This is a simplified version of PIO which makes fewer assumptions
+ about the layout of the data.
+
+ Will eventually be subclassed from IObase so that you can
+ drop-in replace a single-threaded IO system with this
+ multithreaded one. writeChunk() will be used to announce
+ the local chunks and perform the write in parallel rather
+ than collecting serially.
+
+ Needs to have extensions to automatically remove ghost zones
+ setLocalDims(origin,dims,minindex,maxindex)
+
+ Limitations:
+ * currently only works for 3D grids
+ * only understands Float32 and Float64 datatypes
+ * Assumes HPF layout (eg, canonical processor layout where
+ all PE's are aligned to grid... no partial overlaps)
+ * Uses XY slices (assumes fortran ordering for dimensions)
+ * Collects only to a single file (cannot do a multi-gather).
+ */
+class MPIO /* : public IObase */ {
+ int *gdims,*gorigins,grank;
+ MPIcomm &comm;
+ int globaldims[3]; // for master
+ int localorigin[3],localdims[3];
+ int root,myid;
+ IObase *file;
+ Timer slicewait,slicewrite,slicecollect,sliceselect;
+ Timer sliceallwait;
+ // MPI_Request *slice_send_requests;
+ int ghostmin[3],ghostmax[3];
+ MPI_Request *sendreq;
+ int syncsend;
+protected:
+ void sendSlice(int z,float *data,MPI_Request *req);
+ void requestSlice(int z,float *slicebuffer,MPI_Request *req);
+ void waitForSlice(int z,float *slicebuffer,float *destbuffer,MPI_Request *req);
+ void sendSlice(int z,double *data,MPI_Request *req);
+ void requestSlice(int z,double *slicebuffer,MPI_Request *req);
+ void waitForSlice(int z,double *slicebuffer,double *destbuffer,MPI_Request *req);
+public:
+ //MPIO(IObase *io);
+ MPIO(IObase *io,MPIcomm &c=*(new MPIcomm()));
+ ~MPIO();
+ inline int isRoot(){ return ((myid == root)?1:0);}
+ inline void useSyncrhonousSend(int f=1){syncsend=f;}
+ inline IObase *getFileHandle() { return (isRoot())?file:(IObase*)0; }
+ void setLocalDims(int rank,int *origin, int *dims);
+ void setLocalDims(int rank,int *origin, int *dims,
+ int *nghostmin,int *nghostmax);
+ virtual int write(IObase::DataType type,int rank,int *dims,void *data);
+ virtual int write(IObase::DataType type,void *data);
+ void write(float *data){
+ asyncWrite(data);
+ asyncFinalize();
+ }
+ void write(double *data){
+ asyncWrite(data);
+ asyncFinalize();
+ }
+ void asyncWrite(IObase::DataType type, void *data);
+ void asyncWrite(float *data);
+ void asyncWrite(double *data);
+ void asyncFinalize();
+};
+
+#endif // __MPIO_HH_
diff --git a/src/MPIO.slow.cc b/src/MPIO.slow.cc
new file mode 100644
index 0000000..8675d06
--- /dev/null
+++ b/src/MPIO.slow.cc
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include "MPIutils.hh"
+#include "MPIO.hh"
+
+void MPIO::sendSlice(int z,float *data,MPI_Request *req){
+ int iz = z - localorigin[2];
+ if(iz<0 || iz>=localdims[2]) return;
+ //printf("PE(%u) send slice z=%u. iz=%u\n",myid,z,iz);
+ // z == the tag
+ //printf("localdims[0]*localdims[1]=%u iz=%u\n",localdims[0]*localdims[1],iz);
+ // if(isRoot())
+ //comm.iSend(root,z,localdims[0]*localdims[1],
+ // data+localdims[0]*localdims[1]*iz,req[iz]);
+ //else
+ comm.isSend(root,z,localdims[0]*localdims[1],
+ data+localdims[0]*localdims[1]*iz,req[iz]);
+ //for(int i=0;i<4;i++) //printf("\tslicedata[%u]@z(%u) = %f\n",i,iz,(data+localdims[0]*localdims[1]*iz)[i]);
+ //printf("PE(%u) send %u complete\n",myid,iz);
+}
+
+void MPIO::requestSlice(int z,float *slicebuffer,MPI_Request *req){
+ // skip to z
+ //loop (foreach p of pe's)
+ if(!isRoot()) return;
+ //printf("PE(%u) request slice %u\n",myid,z);
+ for(int offset=0,p=0,reqindex=0;p<comm.numProcs();p++) {
+ // if within z-range, compute nelem based on dims at p
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ comm.iRecv(p,z,idims[0]*idims[1],slicebuffer+offset,req[reqindex++]);
+ //printf("reqslice(%u):MPI_Request=%u\n",iz,req[reqindex-1]);
+ offset+=idims[0]*idims[1];
+ }
+ // break if outside of z-range (dangerous if non-canonical proc layout)
+}
+
+void MPIO::waitForSlice(int z,float *slicebuffer,float *destbuffer,MPI_Request *req){
+ if(!isRoot()) return;
+ // could do this 8k at a time
+ // loop for each p of pe's
+ // if within z-range, compute nelem based on dims at p
+ // wait for current request.
+ // re-copy based on offset & origin
+ sliceallwait.start();
+ for(int p=0,reqindex=0;p<comm.numProcs();p++) {
+ // if within z-rang e, compute nelem based on dims at p
+ int dindex = 3*p;
+ int *idims = gdims + dindex;
+ int *iorigin = gorigins + dindex;
+ int iz = z-iorigin[2];
+ if(iz<0 || iz>=idims[2]) continue;
+ MPI_Status stat;
+ //printf("waitfor(%u):MPI_Request=%u\n",iz,req[reqindex]);
+ slicewait.start();
+ comm.wait(req[reqindex++],stat); // frees request object too
+ slicewait.stop();
+ // get information out of the status object!!!!
+ slicecollect.start();
+ int offset = iorigin[1]*globaldims[0] + iorigin[0];
+ for(int idx=0,pos=offset,j=0;j<idims[1];j++,pos+=(globaldims[0]-idims[0]))
+ for(int i=0;i<idims[0];i++)
+ destbuffer[pos++]=slicebuffer[idx++];
+ slicecollect.stop();
+ }
+ sliceallwait.stop();
+ // proclist array
+
+}
+
+MPIO::MPIO(IObase *io,MPIcomm &c):file(io),comm(c){
+ for(int i=0;i<3;i++) globaldims[i]=localdims[i]=localorigin[i]=0;
+ int *rootarray;
+ myid = comm.rank();
+ //printf("my rank = %u\n",myid);
+ if(!myid) rootarray = new int[comm.numProcs()];
+ int rootscale = file?1:0;
+ //printf("rootscale[pid=%u] = %u\n",myid,rootscale);
+ comm.gather(0,1,&rootscale,rootarray); // gather to 0
+ globaldims[0]=globaldims[1]=globaldims[2]=0;
+ if(!myid){
+ for(int count=0,p=0;p<comm.numProcs();p++){
+ //printf("rootarray[%u]=%u\n",p,rootarray[p]);
+ if(rootarray[p]) count++;
+ }
+ if(count<=0 || count>1){
+ fprintf(stderr,"MPIO only accepts a single IO node right now.\n");
+ fprintf(stderr,"You chose %u io nodes\n",count);
+ fprintf(stderr,"I will select only the first one\n");
+ }
+ for(root=-1,p=0;p<comm.numProcs() && root<0;p++)
+ if(rootarray[p]) root=p;
+ delete rootarray;
+ }
+ comm.bcast(0,root); // now everyone knows root
+ //printf("broadcasting root node = %u\n",root);
+}
+
+MPIO::~MPIO(){
+ char buffer[32];
+ sprintf(buffer,"PE(%3u)",comm.rank());
+ if(myid==root) {
+ sprintf(buffer+7,"slicewait"); slicewait.print(buffer);
+ sprintf(buffer+7,"slicewrite"); slicewrite.print(buffer);
+ sprintf(buffer+7,"slicecollect"); slicecollect.print(buffer);
+ //sprintf(buffer+7,"sliceselect"); sliceselect.print(buffer);
+ sprintf(buffer+7,"sliceallwait"); sliceallwait.print(buffer);
+ }
+}
+
+void MPIO::setLocalDims(int rank,int *origin, int *dims){
+ if(rank!=3) perror("MPIO is only for 3D IO for now (sorry)!");
+ if(isRoot()){
+ gorigins = new int[3*comm.numProcs()];
+ gdims = new int[3*comm.numProcs()];
+ }
+ else gdims=gorigins=0; // null for everyone else
+ for(int i=0;i<3;i++) {
+ //printf("localdims-n-origin[%u] = %u:%u\n",i,dims[i],origin[i]);
+ localdims[i]=dims[i];
+ localorigin[i]=origin[i];
+ }
+ comm.gather(root,3,localdims,gdims);
+ comm.gather(root,3,localorigin,gorigins);
+ //if(isRoot()) for(i=0;i<3*comm.numProcs();i++)
+ //printf("gdims-n-origin[%u] = %u:%u\n",i,gdims[i],gorigins[i]);
+ globaldims[0]=globaldims[1]=globaldims[2]=0;
+ if(isRoot())
+ for(int p=0,last=3*comm.numProcs();p<last;p++){
+ //printf("globaldims[%u]: gdims[%u]+gorigins[%u] = %u\n",
+ // p%3,p,p,gdims[p],gorigins[p]);
+ if(globaldims[p%3] < gdims[p]+gorigins[p])
+ globaldims[p%3] = gdims[p]+gorigins[p];
+ }
+ // rebroadcast globaldims to all PE's
+ comm.bcast(root,3,globaldims);
+}
+
+int MPIO::write(IObase::DataType type,int rank,int *dims,void *data){
+ int recalc_layout=0;
+ if(rank!=3) recalc_layout=1;
+ for(int i=0;i<rank;i++) if(localdims[i]!=dims[i]) recalc_layout=1;
+ if(recalc_layout) setLocalDims(rank,localorigin,dims);
+ switch(type){
+ case IObase::Float32:
+ write((float*)data);
+ break;
+ case IObase::Float64:
+ default:
+ break;
+ }
+ return 1; // for now, no error checking
+}
+
+void MPIO::write(float *data){
+ MPI_Request *sendreq = new MPI_Request[localdims[2]];
+ typedef float *floatP;
+ int sliceindex=0;
+ floatP slicebuffer[3]; // double-buffer the slices as they arrive
+ typedef MPI_Request *MPI_RequestP;
+ MPI_RequestP recvreq[2];
+ // the third one is a scratch buffer for reorganizing the slice
+ if(isRoot()){
+ for(int i=0;i<3;i++) slicebuffer[i] = new float[globaldims[0]*globaldims[1]];
+ for(i=0;i<2;i++) recvreq[i] = new MPI_Request[comm.numProcs()];
+ }
+ if(isRoot()){
+ // puts("request initial slice");
+ requestSlice(0,slicebuffer[0],recvreq[0]);
+ }
+ // not good! Everyone is sending a slice here!
+ sendSlice(0,data,sendreq);
+ // hide latency behind the costly io->reserveChunk operation
+ if(isRoot()) file->reserveStream(IObase::Float32,3,globaldims);
+ int writecount=0;
+ for(int i=1;i<globaldims[2];i++){
+ // comm.barrier();
+ if(isRoot())
+ requestSlice(i,slicebuffer[i%2],recvreq[i%2]);
+ sendSlice(i,data,sendreq); // jms
+ if(isRoot()) {
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ writecount+=globaldims[0]*globaldims[1];
+ slicewrite.start();
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ slicewrite.stop();
+ }
+ }
+ if(isRoot()){
+ waitForSlice(i-1,slicebuffer[(i-1)%2],slicebuffer[2],recvreq[(i-1)%2]);
+ file->writeStream(slicebuffer[2],globaldims[0]*globaldims[1]);
+ writecount+=globaldims[0]*globaldims[1];
+ // do requestfree (double-buffered request free-s)
+ for(i=0;i<3;i++) delete slicebuffer[i]; // free everything up
+ for(i=0;i<2;i++) delete recvreq[i];
+ }
+ MPI_Status stat;
+ for(i=0;i<localdims[2];i++) comm.wait(sendreq[i],stat);
+ delete sendreq;
+}
diff --git a/src/MPIO.slow.hh b/src/MPIO.slow.hh
new file mode 100644
index 0000000..af15bdb
--- /dev/null
+++ b/src/MPIO.slow.hh
@@ -0,0 +1,57 @@
+#ifndef __MPIO_HH_
+#define __MPIO_HH_
+#include "IO.hh"
+#include "MPIutils.hh"
+#include "Timer.H"
+
+/* Simplifies assumptions about domain decomposition */
+/*
+ Module: MPIO
+
+ Description:
+ Implements slice-based Parallel IO for IEEEIO libraries.
+ Uses iSend/iRecv of XY slices to hide message passing latency.
+ This is a simplified version of PIO which makes fewer assumptions
+ about the layout of the data.
+
+ Will eventually be subclassed from IObase so that you can
+ drop-in replace a single-threaded IO system with this
+ multithreaded one. writeChunk() will be used to announce
+ the local chunks and perform the write in parallel rather
+ than collecting serially.
+
+ Needs to have extensions to automatically remove ghost zones
+ setLocalDims(origin,dims,minindex,maxindex)
+
+ Limitations:
+ * currently only works for 3D grids
+ * only understands Float32 and Float64 datatypes
+ * Assumes HPF layout (eg, canonical processor layout where
+ all PE's are aligned to grid... no partial overlaps)
+ * Uses XY slices (assumes fortran ordering for dimensions)
+ * Collects only to a single file (cannot do a multi-gather).
+ */
+class MPIO /* : public IObase */ {
+ int *gdims,*gorigins,grank;
+ MPIcomm &comm;
+ int globaldims[3]; // for master
+ int localorigin[3],localdims[3];
+ int root,myid;
+ IObase *file;
+ Timer slicewait,slicewrite,slicecollect,sliceselect;
+ Timer sliceallwait;
+ inline int isRoot(){ return ((myid == root)?1:0);}
+ // MPI_Request *slice_send_requests;
+protected:
+ void sendSlice(int z,float *data,MPI_Request *req);
+ void requestSlice(int z,float *slicebuffer,MPI_Request *req);
+ void waitForSlice(int z,float *slicebuffer,float *destbuffer,MPI_Request *req);
+public:
+ MPIO(IObase *io,MPIcomm &c);
+ ~MPIO();
+ void setLocalDims(int rank,int *origin, int *dims);
+ virtual int write(IObase::DataType type,int rank,int *dims,void *data);
+ void write(float *data);
+};
+
+#endif // __MPIO_HH_
diff --git a/src/MPIOspeed.cc b/src/MPIOspeed.cc
new file mode 100644
index 0000000..8ad0019
--- /dev/null
+++ b/src/MPIOspeed.cc
@@ -0,0 +1,201 @@
+#include <stdio.h>
+#include "vatoi.hh"
+#include "IEEEIO.hh"
+#include "MPIutils.hh"
+#include "MPIO.hh"
+#include "Timer.hh"
+
+int StupidProcLayoutSeive(int np,int decomp[3]){
+ // Brute-Force method
+ // stupidly attempts all decomposition combinations
+ // and filters out unusable combinations.
+ // trys to select minimum surface area processor arrangement
+ int minarea = np*np*np; // impossibly high value
+ for(int i=1;i<=np;i++){
+ for(int j=1;i*j<=np;j++){
+ for(int k=1;i*j*k<=np;k++){
+ if(i*j*k!=np) continue;
+ int area = i+j+k; // area metric (optimizing this weakly minimizes surface area)
+ if(area<minarea) {
+ minarea=area;
+ decomp[0]=i;
+ decomp[1]=j;
+ decomp[2]=k;
+ }
+ }
+ }
+ }
+ return minarea;
+}
+
+class CommandLine {
+public:
+ enum DimType {Local,Global};
+ int verbose,dims[3],dimtype;
+ char *programname;
+ int bufsize;
+ int ntrials;
+ int syncsends;
+ void setDefaults(){
+ verbose=0;
+ ntrials=40;
+ dims[0]=dims[1]=dims[2]=20;
+ dimtype = Local;
+ bufsize=0;
+ syncsends=1; // default for now because it does so much better
+ }
+ CommandLine(int argc,char *argv[],MPIcomm *comm){
+ setDefaults();
+ parse(argc,argv,comm);
+ }
+ void parse(int argc,char *argv[],MPIcomm *comm){
+ programname=argv[0];
+ for(int i=1;i<argc;i++){
+ char *flag = argv[i],*val=argv[i+1];
+ if(*flag=='-') flag++;
+ else continue; // ignore non-flags
+ if(*flag=='v') {verbose=1;}
+ else if(!strcmp(flag,"dimtype")){
+ if((++i<argc) && (!strcmp(val,"global") || !strcmp(val,"Global")))
+ dimtype=Global;
+ }
+ else if(!strcmp(flag,"dims")){
+ if(++i<argc) sscanf(val,"%u,%u,%u",dims,dims+1,dims+2);
+ }
+ else if(*flag=='n'){
+ ntrials = atoi(val);
+ i++;
+ }
+ else if(*flag=='s'){
+ syncsends=1;
+ }
+ else if(!strcmp(flag,"buffer")) {
+ if(++i<argc)
+ bufsize = vatoi(val);
+ }
+ else if(*flag=='h' && !comm->rank()) usage();
+ }
+ }
+ void usage(){
+ printf("Usage: %s <-verbose> <-dims int,int,int> <-dimtype global|local>",
+ programname);
+ printf("\tverbose: Opens file for reading after complete and prints all values.\n");
+ printf("\tdims: Set the dimensions of the dataset. By default this is per-cpu.\n");
+ printf("\t\tThis can be Global dimensions if you use -dimtype flag.\n");
+ printf("\t\tDefault is 20,20,20.\n");
+ printf("\tdimtype: \'global\' makes dimensions apply to the overall dataset\n");
+ printf("\t\tregardless of number of processors and \'local\' is per-processor.\n");
+ printf("\t\tThe default is per-processor.\n");
+ }
+ void printStatus(FILE *f=stdout){
+ fprintf(f,"%s: verbose=%u dims=%u,%u,%u dimtype=%s\n",
+ programname,verbose,
+ dims[0],dims[1],dims[2],
+ (dimtype==Local)?"Local":"Global");
+ fprintf(f,"\t Buffer Cache is at %u bytes\n",bufsize);
+ }
+};
+
+int main(int argc,char *argv[]){
+ MPIenv env(argc,argv); // start MPI threads
+ MPIcomm *comm = env.getComm();
+ CommandLine cmdln(argc,argv,comm);
+
+ int origin[3],dims[3];
+ int proclayout[3],area;
+ int nghost=1;
+ area=StupidProcLayoutSeive(comm->numProcs(),proclayout);
+ // if(!comm->rank()) {
+ cmdln.printStatus();
+ fprintf(stderr,"Proclayout = %u : %u,%u,%u\n",area,
+ proclayout[0],proclayout[1],proclayout[2]);
+ //}
+ for(int i=0;i<3;i++) dims[i]=cmdln.dims[i];
+ if(cmdln.dimtype==CommandLine::Global)
+ for(int i=0;i<3;i++) dims[i]/=proclayout[i]; // create dims for layout computation
+ for(int p=0,k=0;k<proclayout[2];k++){
+ for(int j=0;j<proclayout[1];j++){
+ for(int i=0;i<proclayout[0];i++,p++){
+ if(p==comm->rank()){
+ // assumes same dims per process
+ origin[0]=dims[0]*i;
+ origin[1]=dims[1]*j;
+ origin[2]=dims[2]*k;
+ for(int n=0;n<3;n++){
+ if(origin[n]-nghost>0) {origin[n]-=nghost; dims[n]+=(nghost);}
+ dims[n]+=nghost;
+ }
+ if(cmdln.dimtype==CommandLine::Global){
+ // compute remainder for globaldims
+ if(k==(proclayout[2]-1))
+ dims[2]=cmdln.dims[2]-origin[2];
+ if(j==(proclayout[1]-1))
+ dims[1]=cmdln.dims[1]-origin[1];
+ if(i==(proclayout[0]-1))
+ dims[0]=cmdln.dims[0]-origin[0];
+ }
+ }
+ }
+ }
+ }
+ fprintf(stderr,"PE(%u) origin{%u,%u,%u} localdims{%u,%u,%u} nghost=%u\n",
+ comm->rank(),origin[0],origin[1],origin[2],
+ dims[0],dims[1],dims[2],nghost);
+ int size=1;
+ for(int i=0;i<3;i++) size*=dims[i];
+ // Everybody allocates their own local data
+ float *data = new float[size];
+ for(int i=0;i<size;i++) data[i] = (float)i;
+ IEEEIO *file=0;
+ if(!comm->rank()){ // only PE0 needs to open a file
+ IEEEIO *iofile;
+ file = iofile = new IEEEIO("mpdata.raw",IObase::Write);
+ if(cmdln.bufsize>0)
+ iofile->bufferOn(cmdln.bufsize);
+ }
+ else file=0; // else it is null
+
+ MPIO *pfile = new MPIO(file,*comm); // but everyone creates the pfile
+ pfile->setLocalDims(3,origin,dims);
+ // if(cmdln.syncsends) pfile->useSyncrhonousSend();
+ // puts("Write");
+ comm->barrier();
+ double stime = MPI_Wtime(); // start timing
+ //Timer t;
+ // t.start();
+ for(int i=0;i<cmdln.ntrials;i++){
+ // if(comm->rank()==0) fprintf(stderr,"Trial %4u\n",i);
+ comm->barrier();
+ pfile->write(data);
+ }
+ comm->barrier(); // synchronize completion
+ double etime = MPI_Wtime();
+ // t.end();
+ if(!comm->rank()){
+ printf("\nElapsed time to write=%lf\n",etime-stime);
+ }
+ puts("done writing");
+ delete pfile;
+ if(file) delete file;
+ delete data;
+ if(!comm->rank()){
+ file = new IEEEIO("mpdata.raw",IObase::Read);
+ int ndims[3],nrank;
+ IObase::DataType dt;
+ file->readInfo(dt,nrank,ndims);
+ printf("IO performance = %f Megabytes/sec\n",
+ (float)(cmdln.ntrials)*(float)(IObase::nBytes(dt,nrank,ndims))/(1024*1024*(etime-stime)));
+ printf("Read mpdata.raw: rank=%u dims=%u,%u,%u\n",nrank,ndims[0],ndims[1],ndims[2]);
+ if(cmdln.verbose){ // dangerous on T3E
+ data = new float[IObase::nElements(nrank,ndims)];
+ file->read(data);
+ for(int k=0,p=0;k<ndims[2];k++)
+ for(int j=0;j<ndims[1];j++)
+ for(int i=0;i<ndims[0];i++,p++)
+ printf("data[%u:%u:%u](%u) = %f\n",i,j,k,p,data[p]);
+ delete data;
+ }
+ delete file;
+ }
+ return 0;
+}
diff --git a/src/MPIutils.cc b/src/MPIutils.cc
new file mode 100644
index 0000000..6f2c83e
--- /dev/null
+++ b/src/MPIutils.cc
@@ -0,0 +1,57 @@
+#include "MPIutils.hh"
+
+
+void MPIbuffer::attach(int size){
+ bufsize=size;
+ char *mybuf = new char[bufsize];
+ MPI_Buffer_attach(mybuf,bufsize);
+}
+void MPIbuffer::detach(){
+ char *tmp;
+ int size;
+ MPI_Buffer_detach(&tmp,&size);
+ if(tmp==mybuf) delete tmp;
+ else MPI_Buffer_attach(tmp,size); // wasn't my buffer
+}
+
+MPIbuffer::MPIbuffer(int size):mybuf(0),bufsize(size){
+ attach(size);
+}
+MPIbuffer::~MPIbuffer() {detach();}
+void MPIbuffer::resize(int size){
+ // check for pending requests using the buffer detach
+ // actually done by MPI_Buffer_detach() itself
+ detach();
+ attach(size);
+}
+void MPIbuffer::grow(int size){
+ if(bufsize<size)
+ resize(size);
+}
+void MPIbuffer::check(){ // make sure the buffersize is what we thought it was..
+ char *tmp;
+ int size;
+ MPI_Buffer_detach(&tmp,&size);
+ if(!tmp || tmp!=mybuf)
+ attach(bufsize);
+ else if(tmp!=mybuf){
+ if(size>=bufsize)
+ MPI_Buffer_attach(tmp,size); // reattach
+ else {
+ delete tmp;
+ attach(bufsize);
+ }
+ }
+ else
+ MPI_Buffer_attach(tmp,size); // reattach
+ /* fails if existing buffer was too small and
+ the source process deallocates the buffer without getting
+ a handle to it.
+ Can also fail if malloc != new on that architecture.
+ */
+}
+
+
+// Must watch buffer attachment from external processes
+MPIbuffer *MPIcomm::buffer;
+MPI_Status MPIcomm::defstat;
diff --git a/src/MPIutils.hh b/src/MPIutils.hh
new file mode 100644
index 0000000..e4da9d4
--- /dev/null
+++ b/src/MPIutils.hh
@@ -0,0 +1,389 @@
+#ifndef __MPIUTILS_HH_
+#define __MPIUTILS_HH_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mpi.h>
+
+struct HpfBlockType { // or just HPFblock
+ enum Type {Block,None};
+};
+
+/*
+struct MPItype {
+ enum Type {
+};*/
+
+class MPIbuffer {
+ char *mybuf;
+ int bufsize;
+ void attach(int size);
+ void detach();
+public:
+ MPIbuffer(int size);
+ ~MPIbuffer();
+ void resize(int size);
+ void grow(int size);
+ void check();
+};
+/*
+class MPIthread{
+public:
+ MPI_Comm createCommunicator();
+ int getRank();
+ int growBufferTo(int size);
+ int snapBufferTo(int size);
+ int getTypeSize(MPI_Datatype type);
+};
+*/
+/* Everything is inlined... this is a wrapper after all */
+
+class MPIcomm {
+ int mypid;
+ int nprocs;
+ MPI_Comm comm;
+ int default_tag;
+ static MPIbuffer *buffer;
+public:
+ static MPI_Status defstat;
+ MPIcomm(MPI_Comm commworld = MPI_COMM_WORLD):
+ comm(commworld),default_tag(0){
+ // since these don't change, optimize by assigning
+ // to class variables to reduce subroutine call overhead
+ MPI_Comm_rank(comm,&mypid);
+ MPI_Comm_size(comm,&nprocs);
+ }
+ double time(){return MPI_Wtime();}
+ int numProcs() { return nprocs; }
+ int rank() { return mypid; }
+ void setDefaultTag(int d){ default_tag=d; }
+ inline int send(int dest,int tag,MPI_Datatype type,int nelem,void *data){
+ return MPI_Send(data,nelem,type,dest,tag,comm);
+ }
+ inline int send(int dest,MPI_Datatype type,int nelem,void *data){
+ return send(dest,default_tag,type,nelem,data);
+ }
+ inline int send(int dest,int nelem,float *data){
+ return send(dest,default_tag,MPI_FLOAT,nelem,data);
+ }
+ inline int send(int dest,int nelem,double *data){
+ return send(dest,default_tag,MPI_DOUBLE,nelem,data);
+ }
+ inline int send(int dest,int nelem,int *data){
+ return send(dest,default_tag,MPI_INT,nelem,data);
+ }
+ inline int send(int dest,int nelem,char *data){
+ return send(dest,default_tag,MPI_CHAR,nelem,data);
+ }
+ inline int recv(int src,int tag,MPI_Datatype type,int nelem,void *data,MPI_Status &s=MPIcomm::defstat){
+ return MPI_Recv(data,nelem,type,src,tag,comm,&s);
+ }
+ inline int recv(MPI_Datatype type,int nelem,void *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(MPI_ANY_SOURCE,MPI_ANY_TAG,type,nelem,data,s);
+ }
+
+ inline int recv(int src,int nelem,float *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(src,MPI_ANY_TAG,MPI_FLOAT,nelem,data,s);
+ }
+ inline int recv(int src,int nelem,double *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(src,MPI_ANY_TAG,MPI_DOUBLE,nelem,data,s);
+ }
+ inline int recv(int src,int nelem,int *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(src,MPI_ANY_TAG,MPI_INT,nelem,data,s);
+ }
+ inline int recv(int src,int nelem,char *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(src,MPI_ANY_TAG,MPI_CHAR,nelem,data,s);
+ }
+
+ inline int recv(int nelem,float *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_FLOAT,nelem,data,s);
+ }
+ inline int recv(int nelem,double *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_DOUBLE,nelem,data,s);
+ }
+ inline int recv(int nelem,int *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_INT,nelem,data,s);
+ }
+ inline int recv(int nelem,char *data,MPI_Status &s=MPIcomm::defstat){
+ return recv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_CHAR,nelem,data,s);
+ }
+ // Need support for
+ // S, B, R sends
+ // Buffered: Need to preallocate or auto-alloc back buffers.
+ // Synchronous: Blocks until matching receive posted
+ // Ready: Error unless matching receive has already been posted.
+ void setBufferSize(int nbytes){
+ if(buffer) buffer->resize(nbytes);
+ else buffer = new MPIbuffer(nbytes);
+ }
+ void setBufferSize(MPI_Datatype type,int nelem){
+ // compute size
+ int elemsize = 8;
+ if(buffer) buffer->resize(nelem*elemsize);
+ else buffer = new MPIbuffer(nelem*elemsize);
+ }
+ void growBufferSize(int nbytes){
+ if(buffer) buffer->grow(nbytes);
+ else buffer = new MPIbuffer(nbytes);
+ }
+ void growBufferSize(MPI_Datatype type,int nelem){
+ // compute size
+ int elemsize = 8;
+ if(buffer) buffer->grow(nelem*elemsize);
+ else buffer = new MPIbuffer(nelem*elemsize);
+ }
+ inline int bSend(int dest,int tag,MPI_Datatype type,int nelem,void *data){
+ // need to get MPI size for the datatype
+ if(!buffer) growBufferSize(nelem*8);
+ return MPI_Bsend(data,nelem,type,dest,tag,comm);
+ }
+ inline int bSend(int dest,MPI_Datatype type,int nelem,void *data){
+ return bSend(dest,default_tag,type,nelem,data);
+ }
+
+ inline int bSend(int dest,int nelem,float *data){
+ return bSend(dest,default_tag,MPI_FLOAT,nelem,data);
+ }
+ inline int bSend(int dest,int nelem,double *data){
+ return bSend(dest,default_tag,MPI_DOUBLE,nelem,data);
+ }
+ inline int bSend(int dest,int nelem,int *data){
+ return bSend(dest,default_tag,MPI_INT,nelem,data);
+ }
+ inline int bSend(int dest,int nelem,char *data){
+ return bSend(dest,default_tag,MPI_CHAR,nelem,data);
+ }
+ inline int iSend(int dest,int tag,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ // need to get MPI size for the datatype
+ return MPI_Isend(data,nelem,type,dest,tag,comm,&req);
+ }
+ inline int iSend(int dest,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ return iSend(dest,default_tag,type,nelem,data,req);
+ }
+
+ inline int iSend(int dest,int tag,int nelem,float *data,MPI_Request &req){
+ return iSend(dest,tag,MPI_FLOAT,nelem,data,req);
+ }
+ inline int iSend(int dest,int tag,int nelem,double *data,MPI_Request &req){
+ return iSend(dest,tag,MPI_DOUBLE,nelem,data,req);
+ }
+ inline int iSend(int dest,int tag,int nelem,int *data,MPI_Request &req){
+ return iSend(dest,tag,MPI_INT,nelem,data,req);
+ }
+ inline int iSend(int dest,int tag,int nelem,char *data,MPI_Request &req){
+ return iSend(dest,tag,MPI_CHAR,nelem,data,req);
+ }
+
+ inline int iSend(int dest,int nelem,float *data,MPI_Request &req){
+ return iSend(dest,default_tag,MPI_FLOAT,nelem,data,req);
+ }
+ inline int iSend(int dest,int nelem,double *data,MPI_Request &req){
+ return iSend(dest,default_tag,MPI_DOUBLE,nelem,data,req);
+ }
+ inline int iSend(int dest,int nelem,int *data,MPI_Request &req){
+ return iSend(dest,default_tag,MPI_INT,nelem,data,req);
+ }
+ inline int iSend(int dest,int nelem,char *data,MPI_Request &req){
+ return iSend(dest,default_tag,MPI_CHAR,nelem,data,req);
+ }
+
+ inline int isSend(int dest,int tag,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ // need to get MPI size for the datatype
+ return MPI_Issend(data,nelem,type,dest,tag,comm,&req);
+ }
+ inline int isSend(int dest,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ return isSend(dest,default_tag,type,nelem,data,req);
+ }
+
+ inline int isSend(int dest,int tag,int nelem,float *data,MPI_Request &req){
+ return isSend(dest,tag,MPI_FLOAT,nelem,data,req);
+ }
+ inline int isSend(int dest,int tag,int nelem,double *data,MPI_Request &req){
+ return isSend(dest,tag,MPI_DOUBLE,nelem,data,req);
+ }
+ inline int isSend(int dest,int tag,int nelem,int *data,MPI_Request &req){
+ return isSend(dest,tag,MPI_INT,nelem,data,req);
+ }
+ inline int isSend(int dest,int tag,int nelem,char *data,MPI_Request &req){
+ return isSend(dest,tag,MPI_CHAR,nelem,data,req);
+ }
+
+ inline int isSend(int dest,int nelem,float *data,MPI_Request &req){
+ return isSend(dest,default_tag,MPI_FLOAT,nelem,data,req);
+ }
+ inline int isSend(int dest,int nelem,double *data,MPI_Request &req){
+ return isSend(dest,default_tag,MPI_DOUBLE,nelem,data,req);
+ }
+ inline int isSend(int dest,int nelem,int *data,MPI_Request &req){
+ return isSend(dest,default_tag,MPI_INT,nelem,data,req);
+ }
+ inline int isSend(int dest,int nelem,char *data,MPI_Request &req){
+ return isSend(dest,default_tag,MPI_CHAR,nelem,data,req);
+ }
+
+ inline int ibSend(int dest,int tag,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ // need to get MPI size for the datatype
+ if(!buffer) growBufferSize(nelem*8);
+ return MPI_Ibsend(data,nelem,type,dest,tag,comm,&req);
+ }
+ inline int ibSend(int dest,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ return ibSend(dest,default_tag,type,nelem,data,req);
+ }
+ inline int iRecv(int src,int tag,MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ return MPI_Irecv(data,nelem,type,src,tag,comm,&req);
+ }
+ inline int iRecv(MPI_Datatype type,int nelem,void *data,MPI_Request &req){
+ return iRecv(MPI_ANY_SOURCE,MPI_ANY_TAG,type,nelem,data,req);
+ }
+
+ inline int iRecv(int src, int tag, int nelem,float *data,MPI_Request &req){
+ return iRecv(src,tag,MPI_FLOAT,nelem,data,req);
+ }
+ inline int iRecv(int src, int tag, int nelem,double *data,MPI_Request &req){
+ return iRecv(src,tag,MPI_DOUBLE,nelem,data,req);
+ }
+ inline int iRecv(int src, int tag, int nelem,int *data,MPI_Request &req){
+ return iRecv(src,tag,MPI_INT,nelem,data,req);
+ }
+ inline int iRecv(int src, int tag, int nelem,char *data,MPI_Request &req){
+ return iRecv(src,tag,MPI_CHAR,nelem,data,req);
+ }
+
+ inline int iRecv(int nelem,float *data,MPI_Request &req){
+ return iRecv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_FLOAT,nelem,data,req);
+ }
+ inline int iRecv(int nelem,double *data,MPI_Request &req){
+ return iRecv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_DOUBLE,nelem,data,req);
+ }
+ inline int iRecv(int nelem,int *data,MPI_Request &req){
+ return iRecv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_INT,nelem,data,req);
+ }
+ inline int iRecv(int nelem,char *data,MPI_Request &req){
+ return iRecv(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_CHAR,nelem,data,req);
+ }
+ // waiting routines
+ int wait(MPI_Request &req,MPI_Status &stat){
+ return MPI_Wait(&req,&stat);
+ }
+ int test(MPI_Request &req,MPI_Status &stat,int &flag){
+ return MPI_Test(&req,&flag,&stat);
+ }
+ int requestFree(MPI_Request &req){
+ return MPI_Request_free(&req);
+ }
+ int waitAny(int nrequests,MPI_Request *requestarray,int &completed,MPI_Status &stat){
+ return MPI_Waitany(nrequests,requestarray,&completed,&stat);
+ }
+ int waitAll(int nreq, MPI_Request *reqarray,MPI_Status *statarray){
+ return MPI_Waitall(nreq,reqarray,statarray);
+ }
+ int probe(int source,int tag,MPI_Status &stat){
+ return MPI_Probe(source,tag,comm,&stat);
+ }
+ int probe(int &flag,MPI_Status &stat){
+ return MPI_Probe(MPI_ANY_SOURCE,MPI_ANY_TAG,comm,&stat);
+ }
+ int iProbe(int source,int tag,int &flag,MPI_Status &stat){
+ return MPI_Iprobe(source,tag,comm,&flag,&stat);
+ }
+ int iProbe(int &flag,MPI_Status &stat){
+ return MPI_Iprobe(MPI_ANY_SOURCE,MPI_ANY_TAG,comm,&flag,&stat);
+ }
+ //-collective comm--
+ int gather(int root,MPI_Datatype type,int localnelem,void *senddata,void *recvdata){
+ return MPI_Gather(senddata,localnelem,type,recvdata,localnelem,type,root,comm);
+ }
+
+ int gather(int root,int localnelem,float *senddata,float *recvdata){
+ return MPI_Gather(senddata,localnelem,MPI_FLOAT,recvdata,localnelem,MPI_FLOAT,root,comm);
+ }
+ int gather(int root,int localnelem,double *senddata,double *recvdata){
+ return MPI_Gather(senddata,localnelem,MPI_DOUBLE,recvdata,localnelem,MPI_DOUBLE,root,comm);
+ }
+ int gather(int root,int localnelem,int *senddata,int *recvdata){
+ return MPI_Gather(senddata,localnelem,MPI_INT,recvdata,localnelem,MPI_INT,root,comm);
+ }
+ int gather(int root,int localnelem,char *senddata,char *recvdata){
+ return MPI_Gather(senddata,localnelem,MPI_CHAR,recvdata,localnelem,MPI_CHAR,root,comm);
+ }
+
+ int gatherv(int root,MPI_Datatype type,
+ int localnelem,int *globalnelem,int *displacements,
+ void *senddata,void *recvdata){
+ return MPI_Gatherv(senddata,localnelem,type,
+ recvdata,globalnelem,displacements,type,root,comm);
+ }
+ int allgather(MPI_Datatype type,int nelem,void *senddata,void *recvdata){
+ return MPI_Allgather(senddata,nelem,type,recvdata,nelem,type,comm);
+ }
+ int alltoall(MPI_Datatype type,int nelem,void *senddata,void *recvdata){
+ return MPI_Alltoall(senddata,nelem,type,recvdata,nelem,type,comm);
+ }
+ int scatter(int root,MPI_Datatype type,int localnelem,void *senddata,void *recvdata){
+ return MPI_Scatter(senddata,localnelem,type,recvdata,localnelem,type,root,comm);
+ }
+ int scatter(int root,int localnelem,float *senddata,float *recvdata){
+ return MPI_Scatter(senddata,localnelem,MPI_FLOAT,recvdata,localnelem,MPI_FLOAT,root,comm);
+ }
+ int scatter(int root,int localnelem,double *senddata,double *recvdata){
+ return MPI_Scatter(senddata,localnelem,MPI_DOUBLE,recvdata,localnelem,MPI_DOUBLE,root,comm);
+ }
+ int scatter(int root,int localnelem,int *senddata,int *recvdata){
+ return MPI_Scatter(senddata,localnelem,MPI_INT,recvdata,localnelem,MPI_INT,root,comm);
+ }
+ int scatter(int root,int localnelem,char *senddata,char *recvdata){
+ return MPI_Scatter(senddata,localnelem,MPI_CHAR,recvdata,localnelem,MPI_CHAR,root,comm);
+ }
+ int scatterv(int root,MPI_Datatype type,
+ int localnelem,int *globalnelem,int *displacements,
+ void *senddata,void *recvdata){
+ return MPI_Scatterv(senddata,globalnelem,displacements,type,
+ recvdata,localnelem,type,root,comm);
+ }
+ void print(char *s){
+ for(int i=0,last=numProcs();i<last;i++){
+ barrier();
+ if(rank()==i)
+ fprintf(stderr,"PE(%u): %s\n",i,s);
+ }
+ }
+ int bcast(int root,MPI_Datatype type,int nelements,void *data){
+ return MPI_Bcast(data,nelements,type,root,comm);
+ }
+ int bcast(int root,int nelements,float *data){
+ return bcast(root,MPI_FLOAT,nelements,data);
+ }
+ int bcast(int root,int nelements,double *data){
+ return bcast(root,MPI_DOUBLE,nelements,data);
+ }
+ int bcast(int root,int nelements,int *data){
+ // fprintf(stderr,"\tBCAST: PE=%u Nelem=%u\n",rank(),nelements);
+ return bcast(root,MPI_INT,nelements,data);
+ }
+ int bcast(int root,int &data){
+ return bcast(root,1,&data);
+ }
+ int barrier(){
+ return MPI_Barrier(comm);
+ }
+ //double time(){
+ // return MPI_Wtime();
+ //}
+};
+
+/* grouping mechanisms must be here in the MPIenv */
+class MPIenv {
+ MPIcomm *defaultcomm;
+public:
+ MPIenv(int &argc,char **&argv){
+ MPI_Init(&argc,&argv);
+ defaultcomm = new MPIcomm(MPI_COMM_WORLD);
+ }
+ ~MPIenv(){ delete defaultcomm; MPI_Finalize();}
+ MPIcomm *getComm() { return defaultcomm; }
+ MPIcomm *getComm(int custom_communicator){
+ return new MPIcomm(custom_communicator);
+ }
+};
+
+#endif // __MPIUTILS_HH_
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..bc416c0
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,551 @@
+# Makefile for the IEEE library
+# You *MUST* use GNU gmake for this to work!!!!!
+# Go get it from ftp://prep.ai.mit.edu/gnu/make
+# The 9000 names of the cygwin tools and T3E...
+TMPUN := $(shell uname)
+ifeq ($(TMPUN), CYGWIN32/95)
+UNAME = CYGWIN
+else
+# treat NT the same as 95 (historically, 95 came first...)
+ifeq ($(TMPUN), CYGWIN32_NT)
+UNAME = CYGWIN
+else
+ifeq ($(TMPUN), CYGWIN_NT-4.0)
+UNAME = CYGWIN
+else
+ifeq ($(TMPUN), CYGWIN_NT-5.0)
+UNAME = CYGWIN
+else
+UNAME := $(shell uname | perl -pe 's/(sn\d\d\d\d|jsimpson)/UNICOS\/mk/')
+endif
+endif
+endif
+endif
+
+# F77 = f77 # default fortran compiler
+
+# Various architecture defaults
+#Solaris/SunOS
+ifeq ($(UNAME), SunOS)
+#CC = gcc
+#C++ = g++
+CC = cc
+C++ = CC -pto
+F77 = f77
+INCLUDES = -I.
+HDFROOT = /afs/ncsa.uiuc.edu/packages/hdf/SunOS_5.4
+HDFINCLUDES = -I$(HDFROOT)/include
+HDFLIBPATH = $(HDFROOT)/lib
+HDFLIBS = -L$(HDFROOT)/lib -lmfhdf -ldf -lz -ljpeg -lrpcsvc -lnsl
+LIBS = -L. -lieeeio
+CFLAGS = -O $(INCLUDES) -DANSI -DSUN -DSOLARIS
+CCFLAGS = $(CFLAGS)
+FFLAGS = -O $(INCLUDES) -DANSI -DSUN -DSOLARIS
+CCFLAGS = $(CFLAGS)
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -L/usr/local/lib -lmpi
+DEFINE_DRIVERS = -DWITH_HDF4
+DRIVER_LIBS = -lhdfio
+DRIVER_LIBDEPS = libhdfio.a
+EXTERNAL_INCLUDES = $(HDFINCLUDES)
+EXTERNAL_LIBS = $(HDFLIBS)
+endif
+
+# 64 bit IRIX
+ifeq ($(UNAME), IRIX64)
+CC = cc
+C++ = CC
+INCLUDES = -I.
+H5ROOT = /usr/local/apps/hdf5
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm
+#HDFROOT = /afs/ncsa.uiuc.edu/packages/hdf/IRIX_6.5
+HDFROOT = /usr/local/hdf
+HDFINCLUDES = -I$(HDFROOT)/include
+HDFLIBS = -L$(HDFLIBPATH) -lmfhdf -ldf -lz -ljpeg
+LIBS = -L. -lieeeio -lffio
+MPILIB = -L/usr/local/lib -lmpi
+HDFLIBPATH = $(HDFROOT)/lib
+CFLAGS = -64 -mips4 -LANG:ansi-for-init-scope=ON -IPA -LNO -O3 -ptused $(INCLUDES) -DANSI -DSGI -DFFIO
+ifeq ($(SGI_BITS), n32)
+H5ROOT = /usr/local
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm
+HDFROOT = /afs/ncsa.uiuc.edu/packages/ieeeio/IRIXn32_6.4
+HDFLIBPATH = $(HDFROOT)/lib
+CFLAGS = -mips4 -n32 -LANG:ansi-for-init-scope=ON -O -ptused $(INCLUDES) -DANSI -DSGI
+endif
+ifeq ($(SGI_BITS), 32)
+H5ROOT = /usr/local
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm
+HDFROOT = /afs/ncsa.uiuc.edu/packages/ieeeio/IRIX_5.3
+HDFLIBPATH = $(HDFROOT)/lib
+CFLAGS = -32 -O -ptused $(INCLUDES) -DANSI -DSGI
+endif
+CCFLAGS= $(CFLAGS)
+FFLAGS = $(CFLAGS)
+ARCHIVE = /bin/ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+
+DEFINE_DRIVERS = -DWITH_HDF4 -DWITH_HDF5
+DRIVER_LIBS = -lhdfio -lh5io
+DRIVER_LIBDEPS = libhdfio.a libh5io.a
+EXTERNAL_INCLUDES = $(H5INCLUDES) $(HDFINCLUDES)
+EXTERNAL_LIBS = $(H5LIBS) $(HDFLIBS)
+endif
+
+# 32/n32 bit Irix
+ifeq ($(UNAME), IRIX)
+CC = cc
+C++ = CC
+INCLUDES = -I.
+H5ROOT = /usr/local
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm
+HDFROOT = /afs/ncsa.uiuc.edu/packages/hdf/IRIX_5.3
+HDFINCLUDES = -I$(HDFROOT)/include
+LIBS = -L. -lieeeio
+ifeq ($(SGI_BITS), n32)
+H5ROOT = /usr/local
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm
+HDFROOT = /afs/ncsa.uiuc.edu/packages/ieeeio/IRIXn32_6.2
+HDFLIBPATH = $(HDFROOT)/lib
+CFLAGS = -n32 -mips3 -LANG:ansi-for-init-scope=ON -ptused -O $(INCLUDES) -DANSI
+FFLAGS = $(CFLAGS)
+CCFLAGS = $(CFLAGS)
+else
+HDFLIBPATH = $(HDFROOT)/lib
+CFLAGS = -32 -ptused -O $(INCLUDES) -DANSI
+FFLAGS = $(CFLAGS)
+CCFLAGS = $(CFLAGS)
+endif
+HDFLIBS = -L$(HDFLIBPATH) -lmfhdf -ldf -ljpeg -lz
+ARCHIVE = /bin/ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -L/usr/local/lib -lmpi
+DEFINE_DRIVERS = -DWITH_HDF4 -DWITH_HDF5
+DRIVER_LIBS = -lhdfio -lh5io
+DRIVER_LIBDEPS = libhdfio.a libh5io.a
+EXTERNAL_INCLUDES = $(H5INCLUDES) $(HDFINCLUDES)
+EXTERNAL_LIBS = $(H5LIBS) $(HDFLIBS)
+endif
+
+# HP-UX / Convex SPP-2000
+ifeq ($(UNAME), HP-UX)
+CC = cc
+C++ = CC
+F77 = f77
+INCLUDES = -I.
+HDFROOT = /afs/ncsa.uiuc.edu/packages/hdf/SPP2000
+HDFINCLUDES = -I$(HDFROOT)/include
+HDFLIBPATH = $(HDFROOT)/lib
+HDFLIBS = -L$(HDFROOT)/lib -lmfhdf -ldf -ljpeg -lz
+LIBS = -L. -lieeeio
+# Kludge for HP S/X-class
+CFLAGS = -O $(INCLUDES) -DANSI -DHP +a1
+CCFLAGS = $(CFLAGS)
+FFLAGS = -O $(INCLUDES) -DANSI -DHP
+CCFLAGS = $(CFLAGS)
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -L/usr/local/lib -lmpi
+DEFINE_DRIVERS = -DWITH_HDF4
+DRIVER_LIBS = -lhdfio
+DRIVER_LIBDEPS = libhdfio.a
+EXTERNAL_INCLUDES = $(HDFINCLUDES)
+EXTERNAL_LIBS = $(HDFLIBS)
+endif
+
+# DEC Alpha
+ifeq ($(UNAME), OSF1)
+CC = gcc
+C++ = g++
+INCLUDES = -I.
+HDFROOT = /usr/local/hdf
+#HDFROOT = /afs/.aei-potsdam.mpg.de/alpha_osf32/local/hdf/lib
+HDFINCLUDES = -I$(HDFROOT)/include
+HDFLIBPATH = $(HDFROOT)/lib
+HDFLIBS = -L$(HDFROOT)/lib -lmfhdf -ldf -ljpeg -lz
+H5ROOT = /usr/local
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm
+LIBS = -L. -lieeeio
+CFLAGS = $(INCLUDES) -DANSI -O
+FFLAGS = $(CFLAGS)
+CCFLAGS = $(CFLAGS)
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -L/usr/local/lib -lmpi
+DEFINE_DRIVERS = -DWITH_HDF4 -DWITH_HDF5
+DRIVER_LIBS = -lhdfio -lh5io
+DRIVER_LIBDEPS = libhdfio.a libh5io.a
+EXTERNAL_INCLUDES = $(H5INCLUDES) $(HDFINCLUDES)
+EXTERNAL_LIBS = $(H5LIBS) $(HDFLIBS)
+endif
+
+# Linux PPC/Intel
+ifeq ($(UNAME), Linux)
+CC = gcc
+C++ = g++
+INCLUDES = -I.
+HDFROOT = /usr/local
+HDFINCLUDES = -I$(HDFROOT)/include
+HDFLIBPATH = $(HDFROOT)/lib
+HDFLIBS = -L$(HDFROOT)/lib -lmfhdf -ldf -ljpeg -lz
+LIBS = -L. -lieeeio
+H5ROOT = /usr/local
+H5INCLUDES = -I$(H5ROOT)/include
+H5LIBS = -L$(H5ROOT)/lib -lhdf5 -lm -lz
+CFLAGS = $(INCLUDES) -DANSI -O2 -g -Wall
+FFLAGS = $(CFLAGS)
+CCFLAGS = $(CFLAGS)
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -L/usr/local/lib -lmpich
+DEFINE_DRIVERS = -DWITH_HDF4 -DWITH_HDF5
+DRIVER_LIBS = -lhdfio -lh5io
+DRIVER_LIBDEPS = libhdfio.a libh5io.a
+EXTERNAL_INCLUDES = $(H5INCLUDES) $(HDFINCLUDES)
+EXTERNAL_LIBS = $(H5LIBS) $(HDFLIBS)
+endif
+
+# Macintosh / PowerMach-MachTen
+ifeq ($(UNAME), machten)
+CC = gcc
+C++ = g++
+INCLUDES = -I.
+HDFROOT =
+HDFINCLUDES = -I$(HDFROOT)/include
+HDFLIBPATH = $(HDFROOT)/lib
+HDFLIBS = -L$(HDFROOT)/lib -lmfhdf -ldf -ljpeg -lz
+LIBS = -L. -lieeeio
+CFLAGS = $(INCLUDES) -DANSI -O
+FFLAGS = $(CFLAGS)
+CCFLAGS = $(CFLAGS)
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -L/usr/local/lib -lmpich
+DEFINE_DRIVERS = -DWITH_HDF4
+DRIVER_LIBS = -lhdfio
+DRIVER_LIBDEPS = libhdfio.a
+EXTERNAL_INCLUDES = $(HDFINCLUDES)
+EXTERNAL_LIBS = $(HDFLIBS)
+endif
+
+# Windows 95/NT with Cygwin
+ifeq ($(UNAME), CYGWIN)
+CC = cl
+C++ = cl
+INCLUDES = -I.
+LIBS = -L. -lieeeio
+CFLAGS = $(INCLUDES) -DANSI -DWIN32 -DIEEEIO_EXPORTS
+FFLAGS = $(CFLAGS)
+CCFLAGS = $(CFLAGS)
+ARCHIVE = ar crs
+OBJ_SUFF = .obj
+C2OBJ = -c /Tp
+endif
+
+# T3E
+ifeq ($(UNAME), UNICOS/mk)
+CC = cc
+C++ = CC
+INCLUDES = -I.
+LIBS = -L. -lieeeio
+CFLAGS = $(INCLUDES) -DANSI -DT3E -DFFIO -hinstantiate=used -h new_for_init
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -lmpi
+endif
+
+# Hitachi SR-8000
+ifeq ($(UNAME), HI-UX/MPP)
+CC = cc
+C++ = CC
+INCLUDES = -I.
+LIBS = -L. -lieeeio
+CFLAGS = $(INCLUDES) -DANSI -DHITACHI
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -lmpi
+endif
+
+# SP2 running AIX
+ifeq ($(UNAME), AIX)
+CC = xlc
+C++ = xlC
+INCLUDES = -I.
+LIBS = -L. -lieeeio
+CFLAGS = $(INCLUDES) -DANSI -DAIX
+ARCHIVE = ar crs
+OBJ_SUFF = .o
+C2OBJ = -c
+MPILIB = -lmpi
+endif
+
+
+OBJECTS = IO$(OBJ_SUFF) IEEEIO$(OBJ_SUFF)
+# HLOBJECTS = Reader$(OBJ_SUFF) Writer$(OBJ_SUFF)
+HLOBJECTS = Writer$(OBJ_SUFF)
+HDFOBJECTS = HDFIO$(OBJ_SUFF)
+AMROBJECTS = AmrGridReader$(OBJ_SUFF) AmrUcdFileReader$(OBJ_SUFF) \
+ AmrFileReader$(OBJ_SUFF) Bounds$(OBJ_SUFF) \
+ AmrUcdGridHierarchy$(OBJ_SUFF) AMRwriter$(OBJ_SUFF)
+TCPINCLUDES = -ITCP++ -LTCP++
+SOCKOBJECTS = SockIOreader$(OBJ_SUFF) SockIOwriter$(OBJ_SUFF)
+MPOBJECTS = MPIO$(OBJ_SUFF) MPIutils$(OBJ_SUFF)
+
+CXX = $(C++)
+
+all: archive data3d.raw utilities
+
+objects: $(OBJECTS)
+
+tests: data3d.raw
+
+archive: libieeeio.a libhlio.a libAMR.a libhdfio.a
+
+H5writer: H5writer.c
+ $(CC) $(CFLAGS) $(H5INCLUDES) -o H5writer H5writer.c $(H5LIBS)
+
+H5IOwriter: H5IOwriter.cc libh5io.a
+ $(C++) $(CFLAGS) $(H5INCLUDES) -o H5IOwriter H5IOwriter.cc -L. -lh5io -lieeeio $(H5LIBS)
+
+# always hits libTCP makefile for updates
+libTCP++.a:
+ (cd TCP++ ; $(MAKE) libTCP++.a)
+
+libAMR.a: IO.hh IOProtos.h $(AMROBJECTS)
+ $(ARCHIVE) libAMR.a $(AMROBJECTS)
+
+libh5io.a: IO.hh IOProtos.h H5IO.hh H5IO.o
+ $(ARCHIVE) libh5io.a H5IO.o
+
+H5IO$(OBJ_SUFF): H5IO.hh H5IO.cc IO.hh
+ $(C++) $(CCFLAG) $(CFLAGS) $(H5INCLUDES) $(C2OBJ) H5IO.cc
+
+libhdfio.a: IO.hh IOProtos.h HDFIO.hh $(HDFOBJECTS)
+ $(ARCHIVE) libhdfio.a $(HDFOBJECTS)
+
+# $(HDFLIBPATH)/libmfhdf.a \
+# $(HDFLIBPATH)/libdf.a \
+# $(HDFLIBPATH)/libjpeg.a \
+# $(HDFLIBPATH)/libz.a
+
+libieeeio.a: $(OBJECTS) IOProtos.h IO.hh IEEEIO.hh
+ $(ARCHIVE) libieeeio.a $(OBJECTS)
+
+libhlio.a: $(HLOBJECTS) IOProtos.h IO.hh Writer.hh AMRwriter.hh
+ $(ARCHIVE) libhlio.a $(HLOBJECTS)
+
+libsockio.a: $(SOCKOBJECTS) SockIOwriter.hh SockIOreader.hh libTCP++.a
+ $(ARCHIVE) libsockio.a $(SOCKOBJECTS)
+
+AVSreadIEEE: libieeeio.a
+ (gmake -f Makefile.AVS AVSreadIEEE)
+
+AppendTest: AppendTest.c libieeeio.a
+ $(CC) -c $(CFLAGS) AppendTest.c
+ $(C++) -o AppendTest $(CFLAGS) AppendTest.o -L. -lieeeio
+ rm AppendTest.o
+
+libmpio.a: MPIO.o MPIutils.o
+ $(ARCHIVE) libmpio.a $(MPOBJECTS)
+
+MPIutils.o: MPIutils.hh MPIutils.cc
+ $(C++) -c MPIutils.cc $(CFLAGS)
+
+MPIO.o: IO.hh MPIutils.hh MPIO.hh MPIO.cc Timer.hh
+ $(C++) -c MPIO.cc $(CFLAGS)
+
+MPIOspeed: MPIOspeed.cc IEEEIO.hh MPIutils.o MPIO.o Timer.o vatoi.o libieeeio.a
+ $(C++) $(CFLAGS) -o MPIOspeed MPIOspeed.cc MPIO.o MPIutils.o Timer.o vatoi.o -L. -lieeeio -lffio $(MPILIB)
+
+vatoi.o: vatoi.cc vatoi.hh
+ $(C++) -c vatoi.cc $(CFLAGS)
+
+Timer.o: Timer.cc Timer.hh
+ $(C++) -c Timer.cc $(CFLAGS)
+
+chunkSpeed: chunkSpeed.o vatoi.o libieeeio.a
+ $(C++) $(CFLAGS) -o chunkSpeed chunkSpeed.o vatoi.o -L. -lieeeio
+
+chunkSpeed.o: chunkSpeed.cc IEEEIO.hh vatoi.hh
+ $(C++) $(CFLAGS) -c chunkSpeed.cc
+
+rawSpeed: rawSpeed.o vatoi.o libieeeio.a
+ $(C++) $(CFLAGS) -o rawSpeed rawSpeed.o vatoi.o -L. -lieeeio -lffio
+
+rawSpeed.o: rawSpeed.cc IEEEIO.hh vatoi.hh
+ $(C++) $(CFLAGS) -c rawSpeed.cc -L. -lieeeio
+
+mpspeed.csh: MPIOspeed chunkSpeed rawSpeed
+ touch mpspeed.csh
+ chmod +rx mpspeed.csh
+
+MPItestIsend: MPItestIsend.cc MPIutils.o
+ $(C++) $(CFLAGS) -o MPItestIsend MPItestIsend.cc MPIutils.o -L. -lmpi
+
+data3d.raw: testllWriter
+ ./testllWriter
+ touch data3d.raw
+
+IO$(OBJ_SUFF): IO.cc IO.hh IOProtos.h
+ $(C++) $(CFLAGS) $(C2OBJ) IO.cc
+
+Writer$(OBJ_SUFF): Writer.cc Writer.hh IO.hh
+ $(C++) $(CFLAGS) $(C2OBJ) Writer.cc
+
+WildWriter$(OBJ_SUFF): WildWriter.cc WildWriter.hh IO.hh
+ $(C++) $(CFLAGS) $(C2OBJ) -I/nfs/origin/data/wild/3D/ WildWriter.cc
+
+AmrGridReader$(OBJ_SUFF): AmrGridReader.cc AmrGridReader.hh \
+ IO.hh FlexArrayTmpl.H AmrGrid.h
+ $(C++) $(CFLAGS) $(C2OBJ) AmrGridReader.cc
+
+AmrFileReader$(OBJ_SUFF): AmrFileReader.cc AmrFileReader.hh \
+ IO.hh FlexArrayTmpl.H AmrGrid.h AmrGridReader.hh
+ $(C++) $(CFLAGS) $(C2OBJ) AmrFileReader.cc
+
+AmrUcdFileReader$(OBJ_SUFF): AmrUcdFileReader.cc AmrUcdFileReader.hh \
+ AmrFileReader.hh AmrUcdGridHierarchy.hh \
+ IO.hh FlexArrayTmpl.H AmrGrid.h AmrGridReader.hh
+ $(C++) $(CFLAGS) $(C2OBJ) AmrUcdFileReader.cc
+
+AmrUcdGridHierarchy$(OBJ_SUFF): AmrUcdGridHierarchy.cc \
+ AmrUcdGridHierarchy.hh AmrGrid.h \
+ AmrNode.hh Bounds.hh IO.hh FlexArrayTmpl.H
+ $(C++) $(CFLAGS) $(C2OBJ) AmrUcdGridHierarchy.cc
+
+Bounds$(OBJ_SUFF): Bounds.hh Bounds.cc
+ $(C++) $(CFLAGS) $(C2OBJ) Bounds.cc
+
+AMRwriter$(OBJ_SUFF): AMRwriter.cc AMRwriter.hh AMRwriter.h \
+ Writer.hh IO.hh FlexArrayTmpl.H
+ $(C++) $(CFLAGS) $(C2OBJ) AMRwriter.cc
+
+SockIOreader$(OBJ_SUFF): SockIOreader.cc SockIOreader.hh IO.hh IEEEIO.hh
+ $(C++) $(CFLAGS) $(C2OBJ) $(TCPINCLUDES) SockIOreader.cc
+
+SockIOwriter$(OBJ_SUFF): SockIOwriter.cc SockIOwriter.hh IO.hh
+ $(C++) $(CFLAGS) $(C2OBJ) $(TCPINCLUDES) SockIOwriter.cc
+
+testSockwrite: testSockwrite.cc libieeeio.a libsockio.a
+ $(C++) $(CFLAGS) $(TCPINCLUDES) -o testSockwrite testSockwrite.cc \
+ -lsockio $(LIBS) -lTCP++
+
+testSockread: testSockread.cc libieeeio.a libsockio.a
+ $(C++) $(CFLAGS) $(TCPINCLUDES) -o testSockread testSockread.cc \
+ -lsockio $(LIBS) -lTCP++
+
+testLeak: testLeak.cc
+ $(C++) $(CFLAGS) -o testLeak testLeak.cc $(LIBS)
+
+SlaveIO$(OBJ_SUFF): SlaveIO.cc SlaveIO.hh
+ $(C++) $(CFLAGS) $(C2OBJ) SlaveIO.cc
+
+IEEEIO$(OBJ_SUFF): IEEEIO.cc IEEEIO.hh IO.hh FlexArrayTmpl.H
+ $(C++) $(CFLAGS) $(C2OBJ) IEEEIO.cc
+
+HDFIO$(OBJ_SUFF): HDFIO.hh HDFIO.cc IO.hh
+ $(C++) $(CCFLAG) $(CFLAGS) $(HDFINCLUDES) $(C2OBJ) HDFIO.cc
+
+Reader$(OBJ_SUFF): Reader.cc Reader.hh IO.hh FlexArrayTmpl.H
+ $(C++) $(CFLAGS) $(C2OBJ) Reader.cc
+
+testWriter: testWriter.cc libieeeio.a libhlio.a libhlio.a
+ $(C++) $(CFLAGS) -o testWriter testWriter.cc $(LIBS) -lhlio
+
+testllWriter: testllWriter.cc libieeeio.a libhlio.a
+ $(C++) $(CFLAGS) -o testllWriter testllWriter.cc $(LIBS) -lhlio
+
+testBigWriter: testBigWriter.cc libieeeio.a libhlio.a Timer.o
+ $(C++) $(CFLAGS) -o testBigWriter testBigWriter.cc Timer.o $(LIBS) -lhlio
+
+testllReader: testllReader.cc libieeeio.a
+ $(C++) $(CFLAGS) -o testllReader testllReader.cc $(LIBS)
+
+testChunkReader: testChunkReader.cc libieeeio.a
+ $(C++) $(CFLAGS) -o testChunkReader testChunkReader.cc $(LIBS)
+
+testChunkWriter: testChunkWriter.cc libieeeio.a
+ $(C++) $(CFLAGS) -o testChunkWriter testChunkWriter.cc $(LIBS)
+
+SampleAmrReader: SampleAmrReader.cc libieeeio.a libAMR.a
+ $(C++) $(CFLAGS) -o SampleAmrReader SampleAmrReader.cc -lAMR $(LIBS)
+
+testhdfReader: testhdfReader.cc libieeeio.a libhdfio.a
+ $(C++) $(CFLAGS) $(HDFINCLUDES) -o testhdfReader testhdfReader.cc -lhdfio $(LIBS) $(HDFLIBS)
+
+convert2native: convert2native.cc libieeeio.a
+ $(C++) $(CFLAGS) -o convert2native convert2native.cc $(LIBS)
+
+ioconvert: ioconvert.cc libieeeio.a libhdfio.a
+ $(C++) $(CFLAGS) $(HDFINCLUDES) -o ioconvert ioconvert.cc -lhdfio $(LIBS) $(HDFLIBS)
+
+ioinfo: ioinfo.cc libieeeio.a $(DRIVER_LIBDEPS)
+ $(C++) $(CFLAGS) $(DEFINE_DRIVERS) $(EXTERNAL_INCLUDES) -o ioinfo ioinfo.cc $(LIBS) $(DRIVER_LIBS) $(EXTERNAL_LIBS)
+
+writef77.o: writef77.f
+ $(F77) $(FFLAGS) -c writef77.f
+
+IOspeed: IOspeed.cc writef77.o libieeeio.a libhdfio.a
+ $(C++) $(CCFLAGS) $(HDFINCLUDES) -o IOspeed IOspeed.cc writef77.o -lftn $(LIBS) -lhdfio $(HDFLIBS)
+
+utilities: ioinfo ioconvert convert2native xmlview
+
+testtio: testio.cc libieeeio.a
+ $(C++) $(CFLAGS) -o testio testio.cc $(LIBS)
+
+AmrUcd: libAMR.a AmrUcd.c AmrUcdCompute.cc
+ (gmake -f Makefile.AVS AmrUcd)
+
+#AVSreadIEEE: libhlio.a libIEEEIO.a
+# (gmake -f Makefile.AVS AVSreadIEEE)
+
+xmlview: xmlview.cc archive
+ $(C++) $(CFLAGS) $(HDFINCLUDES) $(DEFINE_DRIVERS) $(EXTERNAL_INCLUDES) -o xmlview xmlview.cc -lhdfio $(LIBS) $(HDFLIBS) $(DRIVER_LIBS) $(EXTERNAL_LIBS)
+
+AMRdata: AMRwriter.o Writer.o archive
+ $(C++) $(CFLAGS) GenerateFakeAMR.cc AMRwriter.o -lhlio $(LIBS) -o GenerateFakeAMR
+
+GenerateFakeAMR.o: GenerateFakeAMR.cc
+ $(C++) $(CFLAGS) -c GenerateFakeAMR.cc
+
+GenerateFakeAMR: GenerateFakeAMR.o archive
+ $(C++) $(CFLAGS) GenerateFakeAMR.o -lhlio $(LIBS) -o GenerateFakeAMR
+
+readf77.o: readf77.f
+ f77 $(CFLAGS) -c readf77.f
+
+readf77: readf77.o archive
+ $(C++) $(CFLAGS) readf77.o $(LIBS) -lftn -o readf77
+
+clean:
+ touch t.o ii_files Templates.DB
+ rm -rf *.o *.obj ii_files Templates.DB
+ touch data3d.raw testio testWriter
+ rm -rf data3d.raw testio testWriter
+
+# (cd TCP++ ; make distclean)
+
+distclean: clean
+ touch t.a t.so
+ rm -rf *.a t.so
+ touch ioinfo ioconvert convert2native IOspeed testllWriter xmlview \
+ SampleAmrReader
+ rm -f ioinfo ioconvert convert2native IOspeed testllWriter xmlview \
+ SampleAmrReader
+
diff --git a/src/Makefile.AVS b/src/Makefile.AVS
new file mode 100644
index 0000000..bce0800
--- /dev/null
+++ b/src/Makefile.AVS
@@ -0,0 +1,58 @@
+#
+# Makefile for AVSreadIEEE
+#
+UNAME := $(shell uname)
+#defaults
+AVS_LIBS = $(AVS_PATH)/lib
+INC = $(AVS_PATH)/include
+
+ifeq ($(UNAME),IRIX)
+SGFLAGS = -32
+endif
+
+ifeq ($(UNAME),IRIX64)
+AVS_PATH = /usr/avs
+AVS_LIBS = $(AVS_PATH)/lib
+INC = $(AVS_PATH)/include
+SGFLAGS= -64 -mips4
+endif
+
+INC_FILE=$(INC)/Makeinclude
+include $(INC_FILE)
+BASELIBS=-lgeom -lutil -lm $(LASTLIBS)
+CFLAGS = $(SGFLAGS) -I$(INC) $(AOPTCFLAGS) $(LOCAL_CFLAGS) $(G) -I.
+CFLOWLIBS=-L$(AVS_LIBS) -lflow_c $(BASELIBS)
+CSIMLIBS=-L$(AVS_LIBS) -lsim_c $(BASELIBS)
+LIBS = $(CFLOWLIBS) -L. -lieeeio
+
+all: AVSreadIEEE AVSreadHLL
+
+AVSreadIEEE: AVSreadIEEE.o AVSreadcpp.o
+ CC $(CFLAGS) -o AVSreadIEEE AVSreadIEEE.o AVSreadcpp.o $(LIBS)
+
+AVSreadIEEE.o: AVSreadIEEE.c
+ $(CC) $(CFLAGS) -c AVSreadIEEE.c
+
+AVSreadcpp.o: AVSreadcpp.cc
+ CC $(CFLAGS) -c AVSreadcpp.cc
+
+AmrUcd: AmrUcd.o AmrUcdCompute.o libAMR.a
+ CC $(CFLAGS) AmrUcd.o AmrUcdCompute.o -lAMR $(LIBS) -o AmrUcd
+
+AmrUcd.o: AmrUcd.c libAMR.a
+ $(CC) $(CFLAGS) -c AmrUcd.c
+
+AmrUcdCompute.o: AmrUcdCompute.cc libAMR.a
+ CC $(CFLAGS) -c AmrUcdCompute.cc
+
+AVSreadHLL: AVSreadHLL.o libHLLIO.a libieeeio.a
+ CC $(CFLAGS) AVSreadHLL.o -lHLLIO $(LIBS) -o AVSreadHLL
+
+AVSreadHLL.o: AVSreadHLL.cc libHLLIO.a libieeeio.a
+ CC $(CFLAGS) -c AVSreadHLL.cc
+
+AVSreadBNB: AVSreadBNB.o libHLLIO.a libieeeio.a
+ CC $(CFLAGS) AVSreadBNB.o -L. -lAMR $(LIBS) -o AVSreadBNB
+
+AVSreadBNB.o: AVSreadBNB.cc libHLLIO.a libieeeio.a
+ CC $(CFLAGS) -c AVSreadBNB.cc
diff --git a/src/OrderedList.H b/src/OrderedList.H
new file mode 100644
index 0000000..c5caf1d
--- /dev/null
+++ b/src/OrderedList.H
@@ -0,0 +1,116 @@
+#ifndef __ORDEREDLIST__TMPL_
+#define __ORDEREDLIST__TMPL_
+/*------------------------------------------------------------
+ Typical use of the orderd list type
+
+ List<sphere *> SphereList;
+ sphere *s;
+ SphereList.reset();
+ while(s=SphereList.getNext())
+ s->visible=1;
+------------------------------------------------------------*/
+// #include <stdio.h>
+// #include <iostream.h>
+// #include <string.h>
+// #include "NewString.H"
+
+#define FOREACH(item,list) list.reset(); while(item=list.getNext())
+#define PFOREACH(item,list) list->reset(); while(item=list->getNext())
+
+template <class T>
+class OrderedList
+{
+ class LLink
+ {
+ public:
+ T data;
+ LLink *next,*prev;
+ LLink(T d,LLink *nxt,LLink *prv=0):
+ data(d),next(nxt),prev(prv)
+ {
+ if(nxt)
+ nxt->prev=this;
+ if(prv)
+ prv->next=this;
+ }
+ ~LLink()
+ {
+ if(prev)
+ prev->next=next;
+ if(next)
+ next->prev=prev;
+ }
+ };
+ LLink *head,*current,*tail;
+ int size;
+public:
+ T nullentry;
+ OrderedList():head(0),size(0),current(0),nullentry(0){}
+ OrderedList(OrderedList<T> &src):head(0),size(0),current(0),nullentry(0){
+ T elem;
+ FOREACH(elem,src)
+ this->add(elem);
+ }
+ ~OrderedList(){
+ while(head) {
+ LLink *tmp=head->next;
+ delete head;
+ head=tmp;
+ }
+ }
+ void add(T data)
+ {
+ head=new LLink(data,head);
+ size++;
+ }
+ inline void addToHead(T data){add(data);}
+ void addToTail(T data){
+ // Whaaaaaa! Totally Bogus Man!!
+ // This type aint complete!!!
+ }
+ void insertAfterCurrent(T data){
+ if(!current || !current->next)
+ addToTail(data);
+ else
+ current=new LLink(data,current->next,current);
+ }
+ void insertBeforeCurrent(T data) {
+ if(!current)
+ addToTail(data);
+ else{
+ if(!current->prev)
+ add(data);
+ else
+ new LLink(data,current,current->prev);
+ }
+ }
+ void remove(T data)
+ {
+ for(LLink *tmp=head;tmp;tmp=tmp->next) {
+ if(tmp->data==data){
+ if(tmp==head) head=tmp->next;
+ if(tmp==current) current=tmp->next;
+ delete tmp;
+ size--;
+ }
+ }
+ }
+ void reset() { current=head; }
+ T getNext() {
+ T rval;
+ if(!current) return nullentry;
+ rval=current->data;
+ current=current->next;
+ return rval;
+ }
+ inline int getSize(){return size;}
+ OrderedList &operator=(OrderedList<T> &src){
+ if(this==&src) return *this;
+ T elem;
+ FOREACH(elem,src)
+ this->add(elem);
+ return *this;
+ }
+};
+
+#endif // __ORDEREDLIST__TMPL_
diff --git a/src/Reader.cc b/src/Reader.cc
new file mode 100644
index 0000000..b243113
--- /dev/null
+++ b/src/Reader.cc
@@ -0,0 +1,126 @@
+#include <stdio.h>
+#include <string.h>
+#include "Reader.hh"
+
+AttribInfoGroup::AttribInfoGroup(IOdataset *ds):dataset(ds){
+ nilattrib.name[0]='\0';
+ nilattrib.datatype=IObase::Error;
+ nilattrib.nelements=0;
+}
+
+AttributeInfo &AttribInfoGroup::operator[](char *name){
+ for(int i=0;i<attribs.getSize();i++){
+ if(!strcmp((*this)[i].name,name)){
+ return attribs[i];
+ }
+ }
+ return nilattrib;
+}
+
+AttribInfoGroup::AttribInfoGroup(AttribInfoGroup &src){
+ //printf("AttribInfoGroup: copy constructor nattribs=%u\n",src.attribs.getSize());
+ nilattrib=src.nilattrib;
+ attribs=src.attribs;
+ dataset=src.dataset;
+}
+
+AttribInfoGroup &AttribInfoGroup::operator=(AttribInfoGroup &src){
+ //puts("AttribInfo = operator");
+ if(&src==this) return *this;
+ //printf("\tAttribInfoGroup: nattribs=%u\n",src.attribs.getSize());
+ nilattrib=src.nilattrib;
+ attribs=src.attribs;
+ dataset=src.dataset;
+ return *this;
+}
+
+int AttributeInfo::read(void *data){
+ return dataset->readAttribute(index,data);
+}
+
+void IOdataset::update(){
+ int i;
+ // read values
+ file.seek(index);
+ file.readInfo(datatype,rank,dims);
+ typesize=IObase::sizeOf(datatype);
+ for(i=0,nelements=1;i<rank;i++) nelements*=dims[i];
+ nbytes=nelements*typesize;
+ annotation.setSize(nannotations=file.nAnnotations());
+ attribute.setSize(nattributes=file.nAttributes());
+ for(i=0;i<file.nAnnotations();i++){
+ file.readAnnotationInfo(i,annotation[i].length);
+ }
+ for(i=0;i<file.nAttributes();i++){
+ file.readAttributeInfo(i,
+ attribute[i].name,
+ attribute[i].datatype,
+ attribute[i].nelements,
+ 127);
+ }
+}
+
+IOdataset::IOdataset(IObase &infile,int idx):file(infile),index(idx),attribute(this){
+ //puts("IOdataset constructor");
+ update();
+ // printf("\tIOdataset nattribs=%u:%u\n",attribute.getSize(),nattributes);
+}
+
+IOdataset::IOdataset(IOdataset &src):file(src.file),attribute(this){
+ //printf("\tIOdataset: copy constructor start nattribs=%u:%u\n",src.attribute.getSize(),src.nattributes);
+ index=src.index;
+ datatype=src.datatype;
+ rank=src.rank;
+ for(int i=0;i<rank;i++) dims[i]=src.dims[i];
+ nannotations=src.nannotations;
+ annotation=src.annotation;
+ nattributes=src.nattributes;
+ attribute=src.attribute;
+ nbytes=src.nbytes;
+ nelements=src.nelements;
+ typesize=src.typesize;
+ // printf("\tIOdataset: copy constructor end nattribs=%u:%u\n",attribute.getSize(),nattributes);
+}
+
+IOdataset &IOdataset::operator=(IOdataset &src){
+ //puts("IOdataset = operator");
+ if(&src==this) return *this;
+ //printf("\tIOdataset: = operator start nattribs=%u:%u\n",src.attribute.getSize(),src.nattributes);
+ file=src.file;
+ index=src.index;
+ datatype=src.datatype;
+ rank=src.rank;
+ for(int i=0;i<rank;i++) dims[i]=src.dims[i];
+ nannotations=src.nannotations;
+ annotation=src.annotation;
+ nattributes=src.nattributes;
+ attribute=src.attribute;
+ nbytes=src.nbytes;
+ nelements=src.nelements;
+ typesize=src.typesize;
+ //printf("\tIOdataset: = operator end nattribs=%u:%u\n",attribute.getSize(),nattributes);
+ return *this;
+}
+
+int IOdataset::readAttribute(int i,void *data){
+ file.seek(index);
+ file.readInfo(datatype,rank,dims);
+ return file.readAttribute(i,data);
+}
+
+int IOdataset::attributeIndex(char *name){
+ for(int i=0;i<attribute.getSize();i++){
+ if(!strcmp(attribute[i].name,name)){
+ return i;
+ }
+ }
+ return -1; // failed
+}
+
+int IOdataset::read(void *data){
+ file.seek(index);
+ file.readInfo(datatype,rank,dims);
+ return file.read(data);
+}
+
+
diff --git a/src/Reader.hh b/src/Reader.hh
new file mode 100644
index 0000000..01529ba
--- /dev/null
+++ b/src/Reader.hh
@@ -0,0 +1,87 @@
+#ifndef __READER_HH_
+#define __READER_HH_
+
+#include "IO.hh"
+#include "FlexArrayTmpl.H"
+
+struct AnnotationInfo{
+ int length;
+};
+
+class IOdataset;
+
+struct AttributeInfo{
+ Long nelements;
+ IObase::DataType datatype;
+ char name[128];
+ IOdataset *dataset;
+ int index;
+ int read(void *data);
+};
+
+class AttribInfoGroup {
+ FlexArray<AttributeInfo> attribs;
+ IOdataset *dataset;
+public:
+ AttributeInfo nilattrib;
+ AttribInfoGroup(IOdataset *ds);
+ ~AttribInfoGroup(){/*puts("Delete AttribInfoGroup");*/ }
+ inline void setSize(int sz) {
+ attribs.setSize(sz);
+ }
+ inline int getSize() {
+ return attribs.getSize();
+ }
+ inline AttributeInfo &operator[](int index){
+ attribs[index].index=index;
+ attribs[index].dataset = dataset;
+ return attribs[index];
+ }
+ AttributeInfo &operator[](char *name);
+ AttribInfoGroup(AttribInfoGroup &src);
+ AttribInfoGroup &operator=(AttribInfoGroup &src);
+};
+
+class IOdataset {
+ IObase &file;
+ void update();
+public:
+ int index;
+ int rank; // should put in constructor for const
+ int dims[5];
+ long nbytes;
+ long nelements;
+ IObase::DataType datatype;
+ int typesize;
+
+
+ FlexArray<AnnotationInfo> annotation;
+ int nannotations;
+ //FlexArray<AttributeInfo> attribute;
+ AttribInfoGroup attribute;
+ int nattributes;
+
+ IOdataset(IObase &infile,int idx);
+ IOdataset(IOdataset &src);
+ ~IOdataset(){/*puts("delete IOdataset");*/}
+ IOdataset &operator=(IOdataset &src);
+ int readAttribute(int index,void *data);
+ int attributeIndex(char *name);
+ int read(void *data);
+};
+
+class Reader {
+ IObase &file;
+public:
+ int ndatasets;
+ Reader(IObase &infile):file(infile){
+ ndatasets=file.nDatasets();
+ }
+ ~Reader(){/*puts("Delete Reader");*/}
+ inline IOdataset operator[](int index){
+ IOdataset ds(file,index); // to satisfy GCC 2.95-2
+ return ds;
+ }
+};
+
+#endif
diff --git a/src/SampleAmrReader.cc b/src/SampleAmrReader.cc
new file mode 100644
index 0000000..ea2b51b
--- /dev/null
+++ b/src/SampleAmrReader.cc
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <IEEEIO.hh>
+#include "AmrFileReader.hh"
+
+int main(int argc,char *argv[]){
+ IEEEIO *file;
+ AmrFileReader *amrfile;
+
+ if (argc < 2) {
+ fprintf(stderr,"Usage: SampleAmrReader AMRfile\n");
+ exit(0);
+ }
+
+ printf("Open the file named %s\n\n",argv[1]);
+ file = new IEEEIO(argv[1],IObase::Read);
+
+ if (!file->isValid()) {
+ fprintf(stderr,"Couldn't open %s for reading\n",argv[1]);
+ exit(0);
+ }
+
+ printf("Now we put the file into an AMR parsing framework\n\n");
+ amrfile = new AmrFileReader(*file);
+
+ printf("Number of Levels = %u\n\n",amrfile->nLevels());
+
+ int min,max;
+ amrfile->getTimeRange(min,max);
+
+ printf("The time range of AMR data in this file\n (in terms of finest-level-of-resolution timesteps) = %u:%u\n\n",min,max);
+ printf("Lets tell the driver to load up all of the grids for the first timestep\n\n");
+
+ amrfile->showAllLevels();
+ amrfile->setTime(min);
+
+ printf("========================> ActiveGrids are (all levels)...\n");
+ amrfile->printActiveGrids();
+ // printf("========================> Grid Info is...\n");
+ // amrfile->printGridInfo();
+
+ printf("\nLet's hide level %d\n",amrfile->nLevels() - 2);
+ amrfile->hideLevel(amrfile->nLevels() - 2);
+ printf("Let's hide level %d\n",amrfile->nLevels() - 1);
+ amrfile->hideLevel(amrfile->nLevels() - 1);
+ printf("Tell the driver to load up the active grids for the first timestep\n");
+ amrfile->setTime(min);
+ printf("========================> ActiveGrids are (all but finest level)...\n");
+ amrfile->printActiveGrids();
+
+ printf("\nActually load the grid data into %u standard arrays\n",amrfile->getNumGrids());
+ AmrGrid *grids = new AmrGrid[amrfile->getNumGrids()];
+ amrfile->getGrids(grids); // that loaded all of the data
+
+ printf("We read %u grids\n\n",amrfile->getNumGrids());
+
+ printf("Let's grab the grids into a flexarray (a dynamically resizable array)\n");
+ FlexArray<AmrGrid> gridarray;
+ amrfile->getGrids(gridarray);
+
+ printf("We read %u grids\n",gridarray.getSize());
+
+ // You can access individual grids with gridarray[]
+
+ // Take a look at AmrGrid.hh to see whats in the datastruct
+ // or take a look at docs
+ // http://infinite-entropy.lbl.gov/FlexIO/AmrGrid.html
+
+ // To get rid of the data associated with these grids we can do a
+ // amrfile->setDataLoadingOff(); // this deletes the data arrays
+ // amrfile->setDataLoadingOn(); // reloads the data arrays from disk
+
+ return 1;
+}
diff --git a/src/SlaveIO.cc b/src/SlaveIO.cc
new file mode 100644
index 0000000..bb14b09
--- /dev/null
+++ b/src/SlaveIO.cc
@@ -0,0 +1,169 @@
+#include "SlaveIO.hh"
+#ifndef WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+#else
+#include <io.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#ifdef T3E
+#include <ffio.h>
+#endif
+
+#ifdef SGI
+#include <aio.h>
+#endif
+
+// Win32/Solaris lseek crap...
+#if defined(WIN32) || defined(SOLARIS) || defined(sun)
+#define L_INCR SEEK_CUR
+#ifndef L_SET // for that wanky Solaris compiler
+#define L_SET SEEK_SET
+#endif
+#define L_XTND SEEK_END
+#endif
+// T3E lseek crap...
+#ifdef T3E // I'm a T3E and I ignore ANSI/Posix standards
+#define L_INCR SEEK_CUR
+#define L_SET SEEK_SET
+#define L_XTND SEEK_END
+#endif
+
+SlaveIO::SlaveIO():fid(-1){}
+SlaveIO::SlaveIO(char *name){
+ fid = open(name,O_RDWR,0644); // should fail if file doesn't exist
+}
+SlaveIO::~SlaveIO(){
+ if(fid>=0) close(fid);
+ fid=-1; // closed state
+}
+int SlaveIO::writeTo(void *data,Long8 len,Long8 offset){
+ lseek(fid,offset,L_SET); // seek from beginning of file
+ return write(fid,data,len);
+}
+
+#ifdef SGI
+SGISlaveIO::SGISlaveIO(char *name):SlaveIO(name){}
+// use writepos elemental operation rather than separate lseek
+int SGISlaveIO::writeTo(void *data,Long8 len,Long8 offset){
+ return pwrite64(fid,data,len,offset);
+}
+
+AIOSlaveIO::AIOSlaveIO(char *name):SlaveIO(name),write_complete(0){
+ // init AIO (check global var for that)
+}
+AIOSlaveIO::~AIOSlaveIO(){
+ // flush file first (make sure it is flushed)
+ if(fid>=0) close(fid);
+ fid=-1;
+}
+int AIOSlaveIO::writeTo(void *data,Long8 len, Long8 offset){
+ return 1;
+}
+void AIOSlaveIO::sync(){
+ // do wait on the file operation
+}
+
+#endif // SGI
+
+#ifdef T3E
+
+FFSlaveIO::FFSlaveIO(char *name,char *optionstring){
+ struct ffsw ffopens_status;
+
+ fid = ffopens(name,O_RDWR,0644,0, 0, &ffopens_status,optionstring);
+}
+FFSlaveIO::FFSlaveIO(char *name,int bufsize,int numbufs){
+ char optionstring[256];
+ int cblks;
+ long cbits;
+ struct statfs statfs_info;
+ struct ffsw ffopens_status;
+ sprintf(optionstring,"bufa.bufsize=%u.num_buffers=%u",bufsize,numbufs);
+ fid = ffopens(name,O_RDWR,0644,0, 0, &ffopens_status,optionstring);
+ ffwrite(fid,optionstring,255); // bogus write to testfile
+ ffclose(name); // now close it
+ statfs(name,&statfs_info,sizeof(statfs_info),0);
+ cbits=0;
+ cbits|=(1<<24);
+ cbits|=(1<<06);
+ cbits|=(1<<26);
+ cbits|=(1<<23);
+ cblks=100;
+ fid = ffopens(name,O_WRONLY|O_PLACE,O_IWRITE|O_IREAD,
+ cbits,cblks,&ffopens_status,LAYERS); // ?
+ system("setf -n32768b:128b -c -p 24:06:23:26 bla"); // ?
+}
+FFSlaveIO::FFSlaveIO(char *name){
+ struct ffsw ffopens_status;
+
+ fid = ffopens(name,O_RDWR,0644,0, 0, &ffopens_status, "bufa.bufsize=256.num_buffers=4");
+}
+FFSlaveIO::~FFSlaveIO(){
+ if(fid>=0) ffclose(fid);
+ fid=-1; // closed state
+}
+int FFSlaveIO::writeTo(void *data,Long8 len,Long8 offset){
+ ffseek(fid,offset,L_SET); // seek from beginning of file
+ return ffwrite(fid,data,len);
+}
+
+#endif // T3E
+
+#ifdef SGI
+
+DirectSlaveIO::DirectSlaveIO(char *name):SlaveIO(name){
+ struct dioattr dio;
+ dfid = open(name,O_WRONLY|O_DIRECT,0644); // unbuffered writes
+ fcntl(dfid,F_DIOINFO,&dio);
+ blocksize = dio.d_miniosz;
+ maxiosize = dio.d_maxiosz;
+ memoryalignment = dio.d_mem;
+ diobuffersize=8*blocksize;
+ diobuffer = (char*)memalign(memoryalignment,8*blocksize);
+}
+
+DirectSlaveIO::~DirectSlaveIO(){
+ if(fid>=0) close(fid);
+ fid=-1; // closed state
+ if(dfid>=0) close(dfid);
+ dfid=-1;
+}
+int DirectSlaveIO::writeTo(void *vdata,Long8 len,Long8 offset){
+ char *data = (char *)vdata;
+ Long8 startlen,midlen,endlen;
+ Long8 startoffset,midoffset,endoffset;
+
+ // compute starts based on blocksize
+ startlen = offset % blocksize; // so now we have the start remainder
+ endlen = (offset+len) % blocksize; // computed end-remainder
+ midlen = len - (startlen+endlen);
+
+ // compute offsets
+ startoffset = offset;
+ midoffset = startoffset + startlen;
+ endoffset = midoffset + midlen;
+
+ // should probably use aio for the end-writes
+ pwrite64(fid,data,startlen,startoffset); // should use write
+ // try this with AIO as well perhaps
+ lseek(dfid,midoffset,L_SET);
+ for(register int off=0;off<midlen;off+=diobuffersize){
+ int sz=(diobuffersize+off>midlen)?midlen-off:diobuffersize;
+ memcpy(diobuffer,data+off+startlen,sz);
+ write(dfid,data+startlen,sz); // write direct and unbuffered
+ }
+ // now here we use the blockbuffer to manage writing of
+ // the non-aligned portions of the data
+ pwrite64(fid,data+startlen+midlen,endlen,endoffset);
+ // block at the end if AIO
+}
+
+#endif // SGI
diff --git a/src/SlaveIO.hh b/src/SlaveIO.hh
new file mode 100644
index 0000000..83665de
--- /dev/null
+++ b/src/SlaveIO.hh
@@ -0,0 +1,60 @@
+#ifndef __SLAVEIO_HH_
+#define __SLAVEIO_HH_
+#include <Arch.h>
+
+class SlaveIO {
+protected:
+ int fid;
+public:
+ SlaveIO();
+ SlaveIO(char *name);
+ virtual ~SlaveIO();
+ virtual int writeTo(void *data,Long8 len,Long8 offset);
+};
+
+#ifdef SGI
+class SGISlaveIO : public SlaveIO {
+public:
+ SGISlaveIO(char *name);
+ // use writepos elemental operation rather than separate lseek
+ virtual int writeTo(void *data,Long8 len,Long8 offset);
+};
+
+class AIOSlaveIO : public SlaveIO {
+ int write_complete;
+public:
+ AIOSlaveIO(char *name);
+ ~AIOSlaveIO();
+ virtual int writeTo(void *data,Long8 len, Long8 offset);
+ void sync();
+};
+
+#endif // SGI
+
+#ifdef T3E
+class FFSlaveIO : public SlaveIO {
+public:
+ FFSlaveIO(char *name,char *optionstring);
+ FFSlaveIO(char *name,int bufsize,int numbufs);
+ FFSlaveIO(char *name);
+ virtual ~FFSlaveIO();
+ virtual int writeTo(void *data,Long8 len,Long8 offset);
+};
+#endif // T3E
+
+#ifdef SGI
+
+class DirectSlaveIO : public SlaveIO {
+ int dfid;
+ int blocksize,maxiosize,memoryalignment;
+ char *diobuffer;
+ int diobuffersize;
+public:
+ DirectSlaveIO(char *name);
+ virtual ~DirectSlaveIO();
+ virtual int writeTo(void *data,Long8 len,Long8 offset);
+};
+
+#endif // SGI
+
+#endif
diff --git a/src/SockIOreader.cc b/src/SockIOreader.cc
new file mode 100644
index 0000000..392d28a
--- /dev/null
+++ b/src/SockIOreader.cc
@@ -0,0 +1,346 @@
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "FlexArrayTmpl.H"
+
+#include "SockIOreader.hh"
+
+#if defined(T3E) || defined(__hpux)
+#define SIGNAL_CAST
+#else
+#define SIGNAL_CAST (SIG_PF)
+#endif
+
+// Globals
+FlexArray<SockIOreader*> sock_io_readers;
+void IOsigHandler(int sig);
+void reaper(int sig);
+
+// enable signals (needs a refcount)
+class SigMgr {
+ static int sigrefcount;
+ static int nwatchers;
+public:
+ static void AddObserver(){
+ nwatchers++;
+ }
+ static void RemoveObserver(){
+ nwatchers--;
+ // should check refcount status change
+ }
+ static void SigOn(){
+ //puts("sigOn");
+ sigrefcount++;
+ if(sigrefcount>nwatchers){
+ // error
+ sigrefcount=nwatchers;
+ puts("SigMgr: Error... the Signal refcount is > numwatchers");
+ puts("correcting");
+ }
+ if(sigrefcount==nwatchers){
+ // call the handlertest just in case
+ //IOsigHandler((int)SIGIO);
+ for(int i=0; i<sock_io_readers.getSize();i++){
+ //printf("poll reader %u\n",i);
+ sock_io_readers[i]->sigHandler(SIGIO);
+ }
+ signal(SIGIO,SIGNAL_CAST IOsigHandler); // reenable the signal handler
+ signal(SIGURG,SIGNAL_CAST IOsigHandler);// reenable the signal handler
+ }
+ }
+ // disable signals until elemental IO operation completes
+ static void SigOff(){
+ //puts("sigOff");
+ sigrefcount--;
+ if(sigrefcount<0){
+ puts("SigMgr::SigOff(): Signal refcount < 0... correcting");
+ sigrefcount=0;
+ }
+ signal(SIGIO,SIG_DFL); // prevent double-interrupt
+ signal(SIGURG,SIG_DFL);
+ }
+};
+
+int SigMgr::sigrefcount=0;
+int SigMgr::nwatchers=0;
+
+// If any IO event occurs, this will call handlers for all availible SockIOreaders
+// to see if they have an event to take care of.
+void IOsigHandler(int sig){
+ //puts("SigHandler: IO Interrupt");
+ SigMgr::SigOff();
+ // So here we look at the global list of SockIOreaders and pass the event on
+ for(int i=0; i<sock_io_readers.getSize();i++){
+ //printf("poll reader %u\n",i);
+ sock_io_readers[i]->sigHandler(sig);
+ }
+ SigMgr::SigOn();
+}
+
+// This gobbles up zombie children... kind of like Night of the Living Dead
+void reaper(int sig){
+ puts("Reaper: Child Interrupt");
+#ifndef T3E
+ // Eat dead children :b
+ struct rusage status;
+ int statptr;
+ while(wait3(&statptr,WNOHANG,&status)>=0) {} // get all the deadsters
+#endif
+
+ signal(SIGCHLD,SIGNAL_CAST reaper); // reenable the signal handler
+}
+
+// Alarm handler to escape from hanging socket reads (crash in mid-send)
+jmp_buf senv,tenv;
+void timeout(int sig){
+ signal(SIGALRM,SIGNAL_CAST timeout); // reset the handler
+ longjmp(tenv,1); // jump to the error recovery vector
+}
+
+/*
+void InterruptRecovery(int sig){
+ SockIOwriter::halt(); // kill app on first opportunity
+ if(SockIOwriter::sendInProgress()>0){
+ signal(SIGALRM,SIGNAL_CAST timeout); // reset the handler
+ longjmp(tenv,1);
+ }
+ else
+ exit(0);
+}
+*/
+
+// kludge
+int SockIOreader::blockingRead(void *buffer,int size){
+ int nremaining,nreceived;
+ if(!connected_client) return 0;
+ // read in 1k blocks (perhaps have 15-30sec timeout)
+ // should be able to set variable blocksize
+ for(nremaining=size;nremaining>0;nremaining-=nreceived)
+ {
+ nreceived=connected_client->read((char*)buffer,nremaining);
+ if (nreceived<1) // read error
+ return size-nremaining;
+ }
+ return size; // can return alt value if timeout occurs
+}
+//=======================================================================================
+
+void SockIOreader::sigHandler(int sig){
+ // do a select...
+ RawPort *port = master_mux.select();
+ if(port){
+ if(connected_client)
+ //pending++; // (if we didn't prefer new clients....) but....
+ delete connected_client; // has preference for new clients!!
+ // pref for new clients is good for error recovery. (eg. death of client program)
+ puts("\nOpen New Client Port\n");
+ connected_client = ServerPort.accept();
+ mux.addInport(connected_client); // add to select mux list
+ // close and reopent the file trunc
+ delete scratchfile;
+ scratchfile=new IEEEIO(scratchfilename,IObase::Write);
+ delete scratchfile;
+ scratchfile=new IEEEIO(scratchfilename,IObase::Append); // kludge to purge file
+ }
+ scratchfile->seek(scratchfile->nDatasets()-1);
+ while(mux.select()>0){
+ int dims[5];
+ char name[128];
+ int bufsize;
+ void *current_buffer;
+ blockingRead(&current_rec,sizeof(RecordHdr));
+ switch(current_rec.recordtype){
+ case 1: // data record
+ blockingRead(&current_data_rec,sizeof(DataRecordHdr));
+ blockingRead(dims,sizeof(int)*current_data_rec.rank);
+ bufsize=current_data_rec.datasize;
+ break;
+ case 2: // annotation record
+ // do nothing for now.
+ bufsize=current_rec.recordsize;
+ break;
+ case 3: // attribrecord
+ blockingRead(&current_att_rec,sizeof(AttributeRecordHdr));
+ blockingRead(name,current_att_rec.namesize);
+ bufsize=current_att_rec.datasize;
+ break;
+ }
+ current_buffer = new char[bufsize];
+ blockingRead(current_buffer,bufsize);
+ // now commit it to disk
+ switch(current_rec.recordtype){
+ case 1:
+ scratchfile->write(IObase::Int2DataType(current_data_rec.numbertype),
+ current_data_rec.rank,
+ dims,
+ current_buffer);
+ break;
+ case 2:
+ scratchfile->writeAnnotation((char*)current_buffer);
+ break;
+ case 3:
+ scratchfile->writeAttribute(name,IObase::Int2DataType(current_att_rec.numbertype),
+ bufsize/IObase::sizeOf(IObase::Int2DataType(current_att_rec.numbertype)),
+ current_buffer);
+ break;
+ }
+ delete current_buffer;
+ current_buffer=0;
+ }
+ if (current_ds > 0)
+ scratchfile->seek(current_ds);
+}
+
+//------------------------core stuff.....................
+SockIOreader::SockIOreader(CONST char *scratchfilenm,int port):IObase(scratchfilenm,IObase::Read),
+ scratchfile(0),ServerPort(port),
+ pending(0),connected_client(0){
+ current_ds = -1;
+ strcpy(scratchfilename,scratchfilenm);
+ scratchfile=new IEEEIO(scratchfilename,IObase::Write);
+ delete scratchfile;// kludge to purge file
+ scratchfile=new IEEEIO(scratchfilename,IObase::Append);
+ // sockport is open, now set up the select
+ fprintf(stderr,"ServerPort validity=%u\n",ServerPort.isAlive());
+ master_mux.addInport(&ServerPort);
+ // the master mux should always return immediately
+ // (a non-blocking select())
+ master_mux.setTimeout(0,0); // seconds and microseconds =0
+ mux.setTimeout(0,0);
+ // set signals for capturing events
+ sock_io_readers.append(this); // append to handler list
+ SigMgr::AddObserver();
+ puts("Signals On");
+ SigMgr::SigOn();
+ signal(SIGCHLD,SIGNAL_CAST reaper); // reenable the signal reaper handler
+ puts("construction completed");
+}
+
+SockIOreader::SockIOreader(CONST char *scratchfilenm,int port,int windowsize):
+ IObase(scratchfilenm,IObase::Read),
+ scratchfile(0),ServerPort(port,windowsize),
+ pending(0),connected_client(0){
+ current_ds = -1;
+ strcpy(scratchfilename,scratchfilenm);
+ scratchfile=new IEEEIO(scratchfilename,IObase::Write);
+ delete scratchfile;// kludge to purge file
+ scratchfile=new IEEEIO(scratchfilename,IObase::Append);
+ // sockport is open, now set up the select
+ fprintf(stderr,"ServerPort validity=%u\n",ServerPort.isAlive());
+ master_mux.addInport(&ServerPort);
+ // the master mux should always return immediately
+ // (a non-blocking select())
+ master_mux.setTimeout(0,0); // seconds and microseconds =0
+ mux.setTimeout(0,0);
+ // set signals for capturing events
+ sock_io_readers.append(this); // append to handler list
+ SigMgr::AddObserver();
+ puts("Signals On");
+ SigMgr::SigOn();
+ signal(SIGCHLD,SIGNAL_CAST reaper); // reenable the signal reaper handler
+ puts("construction completed");
+}
+
+SockIOreader::~SockIOreader(){
+ SigMgr::SigOff();
+ SigMgr::RemoveObserver();
+ // shut all of the sockets down
+ if(connected_client)
+ delete connected_client; // need to remove from mux list
+ connected_client=0;
+}
+
+// should check server status too
+int SockIOreader::isValid() {
+ if(scratchfile && connected_client) return 1;
+ return 0;
+}
+
+// could use overloading to differentiate type here... (but I'm going simple)
+int SockIOreader::readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims){
+ // just hand this off to the datafile (and hope that APPEND mode works correctly)
+ SigMgr::SigOff();
+ int retval = scratchfile->readInfo(typeID,rank,dims,maxdims);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::read(void *data){
+ SigMgr::SigOff();
+ int retval = scratchfile->read(data);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::seek(int dataset_index){
+ SigMgr::SigOff();
+ current_ds=scratchfile->seek(dataset_index);
+ int retval = current_ds;
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::nDatasets(){
+ SigMgr::SigOff();
+ int retval = scratchfile->nDatasets(); // must not interrupt these operations...
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::readAnnotationInfo(int number,int &length){ // returns length (-1 if none left)
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->readAnnotationInfo(number,length);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::readAnnotation(int number,char *annotation,int maxsize){
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->readAnnotation(number,annotation,maxsize);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::nAnnotations(){
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->nAnnotations();
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen){
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->readAttributeInfo(number,name,typeID,nelem,maxnamelen);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem){ // returns number
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->readAttributeInfo(name,typeID,nelem);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::readAttribute(int number,void *data){
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->readAttribute(number,data);
+ SigMgr::SigOn();
+ return retval;
+}
+int SockIOreader::nAttributes(){
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->nAttributes();
+ SigMgr::SigOn();
+ return retval;
+}
+//-----------------Chunking Utilities..................
+int SockIOreader::readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data){
+ SigMgr::SigOff();
+ scratchfile->seek(current_ds);
+ int retval = scratchfile->readChunk(chunkdims,chunkorigin,data);
+ SigMgr::SigOn();
+ return retval;
+}
diff --git a/src/SockIOreader.hh b/src/SockIOreader.hh
new file mode 100644
index 0000000..19f16bf
--- /dev/null
+++ b/src/SockIOreader.hh
@@ -0,0 +1,141 @@
+#ifndef __SOCKIOREADER_HH_
+#define __SOCKIOREADER_HH_
+
+#include "Arch.h"
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "RawTCP.H"
+#include "PortMux.H"
+
+/*=========================================================================
+class: SockIOreader
+description: Implements IEEEIO IO interface described in
+ http://bach.ncsa.uiuc.edu/IEEEIO over a socket connection.
+ The interface is read-only. This is the client and the SockIOwriter
+ is a server which sends data out to the SockIOreader from the
+ application. All data is cached in an IEEEIO file on the client
+ end (this side) for rapid local access by the client application.
+
+Problems: The background IO methods are kludgy at best. Currently it
+ depends on SigIO in order to determine when some new data is availible
+ on the socket. However, it is very difficult to demultiplex that
+ signal when you have more than one instance of SockIOreader active.
+
+ Need a garaunteed method to determine if a client has dropped it connection.
+ A dropped connection can cause a lockup if it occurs during a blocking read.
+ This needs to have a SigALRM in order to recover from such errors.
+===========================================================================*/
+//void IOsigHandler(int sig); // prototype
+
+class SockIOreader : public IObase {
+
+ // The following data structures come straight out of IEEEIO and
+ // are necessary for interpreting the data coming in through the
+ // socket connection. Other than that, you can completely ignore them
+ // or refer directly to the docs in IEEEIO.hh if you really feel the
+ // need to understand what is happening here.
+ enum RecordType {DataRecord=1,AnnotationRecord,AttributeRecord};
+
+#ifdef __hpux
+// silly HPUX compiler doesn't allow FileHdr access to btorder...
+public:
+#endif
+
+ // Structure for determining the native byte-order of data stored in the file
+ union btorder {
+ char c[4]; // write as int, read as int
+ int i;
+ };
+
+ // File header describes how many data records are in the file and what the
+ // version of the IEEEIO wrote this data.
+ struct FileHdr {
+ // do magic twice so we can figure out which byte-order
+ // the current machine is in addition (without hardcoding) in
+ // addition to which byte order the file is in
+ btorder magic;
+ btorder byteorder;
+ Long ndatasets;
+ short majorversion;
+ short minorversion;
+ };
+
+ // At the head of each data or attribute record. Identifies the type of
+ // record and how large it is so that it can be skipped if it doesn't contain
+ // relevant data.
+ struct RecordHdr {
+ int recordtype;
+ Long recordsize;
+ int sequenceID;
+ };
+
+ // This immediately follows a RecordHeader if the record contains raw data.
+ // this stores the number of dimensions and the datatype of the record
+ struct DataRecordHdr {
+ Long datasize;
+ int numbertype;
+ int rank;
+ };
+
+ // The immediately follows the RecordHeader if the record contains a
+ // NetCDF attribute. It stores the datatype, name and datasize of the
+ // attribute vector.
+ struct AttributeRecordHdr {
+ Long datasize;
+ int numbertype;
+ int namesize; // attributes are named
+ };
+
+ char scratchfilename[256]; // name of scratchfile in which to store the IEEEIO data
+ IEEEIO *scratchfile; // IEEEIO file descriptor for the scratch file
+ FastTCPserver ServerPort; // Server port from which connections from SockIOwriters are accept()'ed
+ RawTCPport *connected_client; // Only one client can be attached at a time.
+ //**** State information for IEEEIO management
+ RecordHdr current_rec;
+ DataRecordHdr current_data_rec;
+ AttributeRecordHdr current_att_rec;
+ //**** master_mux is the serverport (accept calls) and mux is the connected ports (new data)
+ PortMux master_mux,mux;
+ int n_complete_ds,current_ds,last_ds; // number of completely received datasets + current&last
+ int pending; // Flag if a new dataset transfer is currently in progress in the background.
+
+ // Make this functionality inacessible since this class is read-only.
+ virtual int write(IObase::DataType typeID,int rank,CONST int *dims,void *data){return 0;}
+ virtual int writeAnnotation(CONST char *annotation){return 0;}
+ virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data){return 0;}
+ virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){return 0;}
+ virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims){return 0;}
+ virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data){return 0;}
+ virtual int writeStream(void *data,int length){return 0;}
+protected:
+ int blockingRead(void *buffer,int size); // kludge
+ //static void halt(){}
+ //static int sendInProgress(){return 0;}
+public:
+ void sigHandler(int sig);
+ friend void IOsigHandler(int *handler); // give the sighandler internal access to sigHandler();
+ //------------------------core stuff.....................
+ SockIOreader(CONST char *scratchfilenm,int port);
+ SockIOreader(CONST char *scratchfilenm,int port,int tcpwindowsize);
+ virtual ~SockIOreader();
+ // should check server status too
+ virtual int isValid();
+ // could use overloading to differentiate type here... (but I'm going simple)
+ virtual int readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims=3);
+ virtual int read(void *data);
+ virtual int seek(int dataset_index);
+ virtual int nDatasets();
+ virtual int readAnnotationInfo(int number,int &length);
+ virtual int readAnnotation(int number,char *annotation,int maxsize=128);
+ virtual int nAnnotations();
+ virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128);
+ virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem);
+ virtual int readAttribute(int number,void *data);
+ virtual int nAttributes();
+ //-----------------Chunking Utilities..................
+ //---Not implemented quite yet on server side, but you can read in chunks on client.
+ virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data);
+ virtual int readStream(void *data,int length){return 0;}
+};
+
+#endif
diff --git a/src/SockIOwriter.cc b/src/SockIOwriter.cc
new file mode 100644
index 0000000..c68c557
--- /dev/null
+++ b/src/SockIOwriter.cc
@@ -0,0 +1,102 @@
+#include <iostream.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "SockIOwriter.hh"
+
+SockIOwriter::SockIOwriter(CONST char *hostname,int port):IObase(hostname,IObase::Write),
+ clientsock(0),ndatasets(0),datasetnumber(-1){
+ //RawTCPclient *clientsock = new RawTCPclient(hostname,port);
+ clientsock = new RawTCPclient(hostname,port); // One Megabyte window
+ fprintf(stderr,"ClientSock=%lu\n",(long)clientsock);
+ // this will block until it connects
+}
+
+SockIOwriter::SockIOwriter(CONST char *hostname,int port,int windowsize):IObase(hostname,IObase::Write),
+ clientsock(0),ndatasets(0),datasetnumber(-1){
+ clientsock = new FastTCPclient(hostname,port,windowsize); // open bigwindow socket
+ fprintf(stderr,"Open ClientSock=%lu with %u windowsize\n",(long)clientsock,windowsize);
+}
+
+SockIOwriter::~SockIOwriter(){
+ delete clientsock;
+}
+
+int SockIOwriter::isValid(){
+ if(clientsock && clientsock->isAlive())
+ return 1;
+ else
+ return 0;
+}
+
+// could use overloading to differentiate type here... (but I'm going simple)
+int SockIOwriter::write(IObase::DataType typeID,int rank,CONST int *dims,void *data){
+ register int i;
+ Int sdims[5];
+ for (i = 0; i < rank ; i++)
+ sdims[i] = dims[i];
+ RecordHdr rec;
+ DataRecordHdr hdr;
+ if(!isValid()){
+ puts("no valid connection");
+ return 0;
+ }
+ for(i=0,hdr.datasize=1;i<rank;i++) hdr.datasize*=dims[i];
+ hdr.datasize*=sizeOf(typeID);
+ hdr.numbertype=typeID;
+ hdr.rank=rank;
+ rec.recordtype = DataRecord;
+ rec.recordsize = hdr.datasize +
+ sizeof(DataRecordHdr) +
+ sizeof(int) * rank;
+ rec.sequenceID = datasetnumber = ndatasets++;
+ current_rec=rec;
+ fprintf(stderr,"Current clientsock=%lu\n",(unsigned long)clientsock);
+ fprintf(stderr,"Portnumber=%u\n",clientsock->getPortNum());
+ fprintf(stderr,"Socket validity=%u\n",clientsock->isAlive());
+ int sz = RecordHdr::write(rec, clientsock);
+ sz = DataRecordHdr::write(hdr, clientsock);
+
+ //clientsock->write((char*)(&rec),sizeof(rec));
+ //clientsock->write((char*)(&hdr),sizeof(hdr));
+ clientsock->write((char*)sdims,rank*sizeof(Int));
+ return clientsock->write((char*)data,hdr.datasize);
+}
+
+int SockIOwriter::writeAnnotation(CONST char *annotation){
+ RecordHdr rec;
+ int stringlen=strlen(annotation)+1;
+ rec.recordtype=AnnotationRecord;
+ rec.recordsize=stringlen;
+ if(datasetnumber>=0) rec.sequenceID=datasetnumber;
+ else rec.sequenceID=current_rec.sequenceID;
+ clientsock->write((char*)(&rec),sizeof(RecordHdr));
+ return clientsock->write((char*)annotation,stringlen);
+}
+
+// Write a NetCDF attribute across the socket connection
+int SockIOwriter::writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data){
+ int i;
+ AttributeRecordHdr attrib;
+ RecordHdr rec;
+ int stringlen=strlen(name)+1;
+
+ attrib.datasize=length*sizeOf(typeID);
+ attrib.namesize=stringlen;
+ attrib.numbertype=typeID;
+ rec.recordtype=AttributeRecord;
+ rec.recordsize=attrib.datasize+attrib.namesize+AttributeRecordHdr::size();
+ if(datasetnumber>=0) rec.sequenceID=datasetnumber;
+ else rec.sequenceID=current_rec.sequenceID; // a kludge for error immunity
+
+// clientsock->write((char*)(&rec),sizeof(RecordHdr));
+// clientsock->write((char*)(&attrib),sizeof(AttributeRecordHdr));
+
+ RecordHdr::write(rec, clientsock);
+ attrib.write(clientsock);
+
+ clientsock->write((char*)name,stringlen);
+ return clientsock->write((char*)(data),length*sizeOf(typeID));
+}
+
+
diff --git a/src/SockIOwriter.hh b/src/SockIOwriter.hh
new file mode 100644
index 0000000..96a6223
--- /dev/null
+++ b/src/SockIOwriter.hh
@@ -0,0 +1,181 @@
+#ifndef __SOCKIOWRITER_HH_
+#define __SOCKIOWRITER_HH_
+
+#include "IO.hh"
+#include "Arch.h"
+#include "RawTCP.H"
+#include "PortMux.H"
+
+/*====================================================
+class: sockIOwriter
+description: This class extends the IO & IEEEIO architecture
+ to write data across a newtork socket. Please
+ consult http://bach.ncsa.uiuc.edu/IEEEIO for details
+ on how IEEEIO works. This interface only works
+ for *writing* data (write-only interface).
+
+ The writer opens a socket to the destination address
+ and then ships data to the destination processor
+ whenever a write occurs. Sending is immediate.
+ There is no local caching (all caching is on the
+ client/reader-side). It could be double-buffered but
+ this would cause problems for MPI jobs on distributed
+ memory machines like the T3E and SP2.
+problems: All sends are in the foreground. This can hurt
+ application performance, but we can't afford double-buffering
+ because of the memory limitations of distributed memory machines.
+ (a background send would require double buffering but we
+ can't afford the memory to do that on a distributed memory
+ machine).
+======================================================*/
+
+class SockIOwriter : public IObase {
+ enum RecordType {DataRecord=1,AnnotationRecord,AttributeRecord};
+
+#ifdef __hpux
+// silly HPUX compiler won't give FileHdr access to btorder...
+public:
+#endif
+
+ union btorder {
+ char c[4]; // write as int, read as int
+ Int i;
+ };
+
+ struct FileHdr {
+ // do magic twice so we can figure out which byte-order
+ // the current machine is in addition (without hardcoding) in
+ // addition to which byte order the file is in
+ btorder magic;
+ btorder byteorder;
+ Long ndatasets;
+ short majorversion;
+ short minorversion;
+ static int write(FileHdr &rec, RawTCPclient *clientsock){
+#ifdef T3E
+ // T3E pads structures and Unions (even if embedded in other structures).
+ // So we can't simply write the entire structure in-place. Must write
+ // each component of the structure independently.
+ // do it the stupid way first
+ // would be smarter to pack buffers really
+ int r=0;
+ r+=clientsock->write((char *)(rec.magic.c),4);
+ r+=clientsock->write((char *)(rec.byteorder.c),4);
+ r+=clientsock->write((char *)&(rec.ndatasets),4);
+ // this may be incorrect, but it will work for now
+ // It assumes the low order bytes will be first to
+ // be written.
+ r+=clientsock->write((char *)&(rec.majorversion),2);
+ r+=clientsock->write((char *)&(rec.minorversion),2);
+ return r;
+#else
+ // problem if this includes pointers to static methods
+ // will require an extra degree of inheritance. (inherit
+ // from a base structure.
+ return clientsock->write((char *)&rec,sizeof(FileHdr));
+#endif
+ }
+ };
+
+ struct RecordHdr {
+ Int recordtype;
+ Long recordsize;
+ Int sequenceID;
+
+ static int write(RecordHdr &rec,RawTCPclient *clientsock){
+#ifdef T3E
+ // do it the stupid way first
+ // would be smarter to pack buffers really
+ int r=0;
+ r+=clientsock->write((char *)&(rec.recordtype),4);
+ r+=clientsock->write((char *)&(rec.recordsize),4);
+ r+=clientsock->write((char *)&(rec.sequenceID),4);
+ return r;
+#else
+ return clientsock->write((char *)&rec,sizeof(RecordHdr));
+#endif
+ }
+ };
+
+ struct DataRecordHdr {
+ Long datasize;
+ Int numbertype;
+ Int rank;
+ static int write(DataRecordHdr &rec, RawTCPclient *clientsock){
+#ifdef T3E
+ // do it the stupid way first
+ // would be smarter to pack buffers really
+ int r=0;
+ r+=clientsock->write((char *)&(rec.datasize),4);
+ r+=clientsock->write((char *)&(rec.numbertype),4);
+ r+=clientsock->write((char *)&(rec.rank),4);
+ return r;
+#else
+ return clientsock->write((char *)&rec,sizeof(DataRecordHdr));
+#endif
+ }
+
+ };
+
+ struct AttributeRecordHdr {
+ Long datasize;
+ Int numbertype;
+ Int namesize; // attributes are named
+
+ /// Alignment-save write
+ int write(RawTCPclient *clientsock)
+ {
+ /// shouldn't there be some hton() conversion??
+ int r = clientsock->write(&datasize , 4);
+ r+= clientsock->write(&numbertype, 4);
+ r+= clientsock->write(&namesize , 4);
+ return r;
+ }
+
+ static int size() { return 12; }
+ };
+
+ virtual int readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims=3){ return 0; }
+ virtual int read(void *data){ return 0; }
+ virtual int seek(int dataset_index){ return 0; }
+ virtual int nDatasets() { return 0; }
+ virtual int readAnnotationInfo(int number,int &length){ return 0; } // returns length (-1 if none left)
+ virtual int readAnnotation(int number,char *annotation,int maxsize=128){ return 0; }
+ virtual int nAnnotations(){ return 0; } // returns number
+ virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128)
+ { return 0; }
+ virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem){ return 0; } // returns number
+ virtual int readAttribute(int number,void *data){ return 0; }
+ virtual int nAttributes(){ return 0; }
+ virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data){ return 0; }
+ virtual int readStream(void *data,int length){return 0;}
+ RawTCPclient *clientsock;
+ int ndatasets,datasetnumber;
+ RecordHdr current_rec;
+public:
+ //------------------------core stuff.....................
+ SockIOwriter(CONST char *hostname,int port);
+ SockIOwriter(CONST char *hostname,int port,int tcpwindowsize);
+ virtual ~SockIOwriter();
+ virtual int isValid();
+ // could use overloading to differentiate type here... (but I'm going simple)
+ virtual int write(IObase::DataType typeID,int rank,CONST int *dims,void *data);
+ virtual int writeAnnotation(CONST char *annotation);
+ virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data);
+ //-----------------Chunking Utilities..................
+ virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){
+ return 0; // this will require a fourth data descriptor type
+ }
+ virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims){
+ return 0; // this will require a fourth data descriptor type
+ }
+ virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data){
+ // need to fix this
+ return 0;
+ }
+ virtual int writeStream(void *data,int length){return 0;}
+
+ RawTCPclient*TCPclient() const { return clientsock; }
+};
+
+#endif
diff --git a/src/Timer.cc b/src/Timer.cc
new file mode 100644
index 0000000..5e4d937
--- /dev/null
+++ b/src/Timer.cc
@@ -0,0 +1,44 @@
+#include <unistd.h>
+#include "Timer.hh"
+#include <limits.h>
+int Timer::start(){
+ // struct timezone tz;
+ if(running) return 0; // already running
+ running=1;
+ times(&tm); // set current time
+ gettimeofday(&tv,0);
+ return 1;
+}
+
+int Timer::stop(){
+ // timezone tz;
+ tms tmc; // current time
+ timeval tvc; // current realtime
+ if(!running) return 0; // already stopped
+ running=0;
+ // copy back current time
+ gettimeofday(&tvc,0);
+ times(&tmc);
+ treal += ((double)(tvc.tv_sec - tv.tv_sec) +
+ ((double)(tvc.tv_usec - tv.tv_usec))/1000000.0L);
+ tuser += (double)(tmc.tms_utime-tm.tms_utime)/CLK_TCK;
+ tsystem += (double)(tmc.tms_stime-tm.tms_stime)/CLK_TCK;
+ return 1;
+}
+
+void Timer::elapsedTimeSeconds(double &system,double &user,double &real){
+ int wasrunning=running;
+ stop();
+ system=tsystem;
+ user=tuser;
+ real=treal;
+ if(wasrunning) start();
+}
+
+void Timer::print(char *preface,FILE *f){
+ double s,u,r;
+ elapsedTimeSeconds(s,u,r);
+ fprintf(f,"%s: SystemTime=%lfs\tUserTime=%lfs\tRealTime=%lfs\n",
+ preface,s,u,r);
+}
+
diff --git a/src/Timer.hh b/src/Timer.hh
new file mode 100644
index 0000000..e801cf3
--- /dev/null
+++ b/src/Timer.hh
@@ -0,0 +1,39 @@
+#ifndef __TIMER_HH_
+#define __TIMER_HH_
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <sys/time.h>
+
+class Timer {
+ int running;
+ double treal,tuser,tsystem;
+ tms tm;
+ timeval tv;
+public:
+ Timer() { reset(); }
+ void reset(){
+ treal=tuser=tsystem=0;
+ running=0;
+ }
+ int start();
+ int stop();
+ void elapsedTimeSeconds(double &system,double &user,double &real);
+ void elapsedTimeSeconds(float &system,float &user,float &real){
+ double s,u,r;
+ elapsedTimeSeconds(s,u,r);
+ system=s; user=u; real=r;
+ }
+ void print(char *preface="",FILE *f=stdout);
+};
+
+class Counter {
+ int count;
+public:
+ Counter():count(0){}
+ void reset() {count = 0;}
+ int incr(){ return count++;}
+ int nCount() { return count;}
+};
+
+#endif
diff --git a/src/Vec3f.hh b/src/Vec3f.hh
new file mode 100644
index 0000000..c9e58d1
--- /dev/null
+++ b/src/Vec3f.hh
@@ -0,0 +1,278 @@
+#ifndef __VEC3F_HH_
+#define __VEC3F_HH_
+
+#include <stdlib.h>
+#include <math.h>
+
+ //CAPI:verb SqrDistancePt3
+#define PF_SQUARE(_x) ((_x)*(_x))
+#define PF_MIN2(a,b) ((a) < (b) ? (a) : (b))
+#define PF_MAX2(a,b) ((a) > (b) ? (a) : (b))
+#define PF_MIN3(a,b,c) ((a) < (b) ? PF_MIN2(a,c) : PF_MIN2(b,c))
+#define PF_MAX3(a,b,c) ((a) > (b) ? PF_MAX2(a,c) : PF_MAX2(b,c))
+#define PF_MIN4(a,b,c,d) ((a) < (b) ? PF_MIN3(a,c,d) : PF_MIN3(b,c,d))
+#define PF_MAX4(a,b,c,d) ((a) > (b) ? PF_MAX3(a,c,d) : PF_MAX3(b,c,d))
+#define PF_CLAMP(_x, _lo, _hi) \
+ (((_x) < (_lo)) ? (_lo) : (_x) > (_hi) ? (_hi) : (_x))
+
+/*
+ * PF_ABS is faster than calling fabsf
+ * PF_ABSLT etc are faster than (PF_ABS(x1) < x2)
+ */
+#define PF_ABS(_x1) ((_x1 < 0) ? -(_x1) : (_x1))
+#define PF_ABSLT(_x1,_x2) ((_x1) < (_x2) && -(_x1) < (_x2))
+#define PF_ABSGT(_x1,_x2) ((_x1) > (_x2) || -(_x1) > (_x2))
+#define PF_ABSLE(_x1,_x2) ((_x1) <= (_x2) && -(_x1) <= (_x2))
+#define PF_ABSGE(_x1,_x2) ((_x1) >= (_x2) || -(_x1) >= (_x2))
+/*
+ * Speed oriented macros
+ */
+#define PF_PI 3.14159265358979323846f /* F for SP float */
+#define PF_PI_D 3.14159265358979323846 /* slower DP for more precision */
+
+#define PF_DEG2RAD(x) ((x)*PF_PI /180.0f)
+#define PF_DEG2RAD_D(x) ((x)*PF_PI_D/180.0)
+
+#define PF_RAD2DEG(x) ((x)*180.0f/PF_PI)
+#define PF_RAD2DEG_D(x) ((x)*180.0 /PF_PI_D)
+
+#define PF_HUGEVAL 3.40282347e+37f
+
+
+/* macro for fast square roots */
+/* thresholds chosen so it's no worse than pfSqrt() */
+#define PF_SQRT1(_x) \
+ (((_x) > 0.9996f && (_x) < 1.001f) ? \
+ 0.5f + 0.5f*(_x) : \
+ pfSqrt(_x))
+
+#define PF_1OVERSQRT1(_x) \
+ (((_x) > 0.9996f && (_x) < 1.001f) ? \
+ 1.5f - 0.5f*(_x) : \
+ 1.0f/pfSqrt(_x))
+
+struct Vec3f {
+ // PFSTRUCT_DECLARE
+
+public:
+ float vec[3];
+
+public:
+ // constructors and destructors
+ //CAPI:private
+ Vec3f(float _x, float _y, float _z) { set(_x, _y, _z); }
+ Vec3f(float *_p) { set(_p); }
+ Vec3f() {};
+
+public:
+ // sets and gets
+ //CAPI:arrayclass
+ //CAPI:verb SetVec3
+ void set(float _x, float _y, float _z) {
+ vec[0] = _x;
+ vec[1] = _y;
+ vec[2] = _z;
+ }
+ void set(float *_p){
+ vec[0]=_p[0];
+ vec[1]=_p[1];
+ vec[2]=_p[2];
+ }
+
+public:
+ // other functions
+ //CAPI:verb
+ void copy(const Vec3f& _v) { *this = _v; }
+ int equal(const Vec3f& _v) const {
+ return (vec[0] == _v[0] &&
+ vec[1] == _v[1] &&
+ vec[2] == _v[2]);
+ }
+ int almostEqual(const Vec3f& _v, float _tol) const;
+
+ void negate(const Vec3f& _v) {
+ vec[0] = -_v[0];
+ vec[1] = -_v[1];
+ vec[2] = -_v[2];
+ }
+
+ float dot(const Vec3f& _v) const {
+ return (vec[0] * _v[0] +
+ vec[1] * _v[1] +
+ vec[2] * _v[2]);
+ }
+
+ void add(const Vec3f& _v1, const Vec3f& _v2) {
+ vec[0] = _v1[0] + _v2[0];
+ vec[1] = _v1[1] + _v2[1];
+ vec[2] = _v1[2] + _v2[2];
+ }
+
+ void sub(const Vec3f& _v1, const Vec3f& _v2) {
+ vec[0] = _v1[0] - _v2[0];
+ vec[1] = _v1[1] - _v2[1];
+ vec[2] = _v1[2] - _v2[2];
+ }
+
+ void scale(float _s, const Vec3f& _v) {
+ vec[0] = _s * _v[0];
+ vec[1] = _s * _v[1];
+ vec[2] = _s * _v[2];
+ }
+
+ void addScaled(const Vec3f& _v1, float _s, const Vec3f& _v2) {
+ vec[0] = _v1[0] + _s * _v2[0];
+ vec[1] = _v1[1] + _s * _v2[1];
+ vec[2] = _v1[2] + _s * _v2[2];
+ }
+
+ void combine(float _a, const Vec3f& _v1, float _b, const Vec3f& _v2) {
+ vec[0] = _a * _v1[0] + _b * _v2[0];
+ vec[1] = _a * _v1[1] + _b * _v2[1];
+ vec[2] = _a * _v1[2] + _b * _v2[2];
+ }
+
+
+ float sqrDistance(const Vec3f& _v) const {
+ return (PF_SQUARE(vec[0] - _v[0]) +
+ PF_SQUARE(vec[1] - _v[1]) +
+ PF_SQUARE(vec[2] - _v[2]));
+ }
+ void norm(const Vec3f& _v1, const Vec3f& _v2, const Vec3f& _v3){
+ Vec3f s1,s2;
+ s1 = _v1-_v2;
+ s2 = _v3-_v2;
+ cross(s1,s2);
+ normalize();
+ }
+ float normalize(){
+ float len=length();
+ if(len==0) this->set(len,len,len);
+ vec[0]/=len; vec[1]/=len; vec[2]/=len;
+ return len;
+ }
+ float length() const{
+ return sqrt(PF_SQUARE(vec[0]) +
+ PF_SQUARE(vec[1]) +
+ PF_SQUARE(vec[2]));
+ }
+ //CAPI:verb DistancePt3
+ float distance(const Vec3f& _v) const{
+ return sqrt(this->sqrDistance(_v));
+ }
+ void cross(const Vec3f& v1, const Vec3f& v2){
+ float temp[3];
+
+ temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+ temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+ temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+ set(temp);
+ }
+ void cross(const Vec3f& v2){
+ float temp[3];
+
+ temp[0] = (vec[1] * v2[2]) - (vec[2] * v2[1]);
+ temp[1] = (vec[2] * v2[0]) - (vec[0] * v2[2]);
+ temp[2] = (vec[0] * v2[1]) - (vec[1] * v2[0]);
+ set(temp);
+ }
+ /*CAPI:verb XformVec3
+ void xformVec(const Vec3f& _v, const pfMatrix& _m);
+
+ //CAPI:verb XformPt3
+ void xformPt(const Vec3f& _v, const pfMatrix& _m);
+
+ //CAPI:verb FullXformPt3
+ void fullXformPt(const Vec3f& _v, const pfMatrix& _m);*/
+
+public:
+ // Operators
+ float& operator [](int i) { return vec[i]; }
+
+ const float& operator [](int i) const { return vec[i]; }
+
+ int operator ==(const Vec3f& _v) const {
+ return vec[0] == _v[0] && vec[1] == _v[1] && vec[2] == _v[2];
+ }
+ int operator !=(const Vec3f& _v) const {
+ return !(*this == _v);
+ }
+
+public:
+ // Vec3f operators (N.B. return by value can be slow)
+
+ Vec3f operator -() const {
+ return Vec3f(-vec[0], -vec[1], -vec[2]);
+ }
+
+ Vec3f operator +(const Vec3f& _v) const {
+ return Vec3f(vec[0]+_v[0], vec[1]+_v[1], vec[2]+_v[2]);
+ }
+
+ Vec3f operator -(const Vec3f& _v) const {
+ return Vec3f(vec[0]-_v[0], vec[1]-_v[1], vec[2]-_v[2]);
+ }
+
+ friend inline Vec3f operator *(float _s, const Vec3f&);
+ friend inline Vec3f operator *(const Vec3f& _v, float _s);
+ friend inline Vec3f operator /(const Vec3f& _v, float _s);
+ // friend inline Vec3f operator *(const Vec3f& _v, const pfMatrix& _m);
+
+public:
+ // Assignment Operators
+ Vec3f& operator =(const Vec3f& _v) {
+ vec[0] = _v[0];
+ vec[1] = _v[1];
+ vec[2] = _v[2];
+ return *this;
+ }
+
+ Vec3f& operator *=(float _s) {
+ vec[0] *= _s;
+ vec[1] *= _s;
+ vec[2] *= _s;
+ return *this;
+ }
+
+ Vec3f& operator /=(float _s) {
+ _s = 1.0/_s;
+ return *this *= _s;
+ }
+
+ Vec3f& operator +=(const Vec3f& _v) {
+ vec[0] += _v[0];
+ vec[1] += _v[1];
+ vec[2] += _v[2];
+ return *this;
+ }
+
+ Vec3f& operator -=(const Vec3f& _v) {
+ vec[0] -= _v[0];
+ vec[1] -= _v[1];
+ vec[2] -= _v[2];
+ return *this;
+ }
+};
+
+
+inline Vec3f operator *(float _s, const Vec3f& _v) {
+ return Vec3f(_v[0]*_s, _v[1]*_s, _v[2]*_s);
+}
+
+inline Vec3f operator *(const Vec3f& _v, float _s) {
+ return Vec3f(_v[0]*_s, _v[1]*_s, _v[2]*_s);
+}
+
+inline Vec3f operator /(const Vec3f& _v, float _s) {
+ _s = 1.0f/_s;
+ return Vec3f(_v[0]*_s, _v[1]*_s, _v[2]*_s);
+}
+
+//inline Vec3f operator *(const Vec3f& _v, const pfMatrix& _m) {
+ // transform as point (w=1), assuming affine transformation
+ // i.e. does not use slower dst.xformFullPt().
+// Vec3f dst; dst.xformPt(_v, _m); return dst;
+//}
+
+#endif
+
diff --git a/src/WildWriter.cc b/src/WildWriter.cc
new file mode 100644
index 0000000..b6bcf9c
--- /dev/null
+++ b/src/WildWriter.cc
@@ -0,0 +1,609 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "WildWriter.hh"
+
+//#define DISKBLOCKSIZE 8192
+
+void WildWriterB::beginDataset(int numnodes,
+ int numcells,
+ IObase::DataType datacomponenttype,
+ int numdatacomponents,
+ int *componentsizes,
+ char *componentnames,
+ char componentnameseparator){
+ int i;
+ nnodes=numnodes;
+ ncells=numcells;
+ comptype=datacomponenttype;
+ ncomp = numdatacomponents;
+ compsizes.setSize(ncomp);
+ if(componentsizes){
+ for(i=0,totalcomp=1;i<ncomp;i++) {
+ totalcomp+=compsizes[i]=1;
+ }
+ }
+ else {
+ for(i=0,totalcomp=1;i<ncomp;i++) {
+ totalcomp+=compsizes[i]=1;
+ }
+ }
+ compnames.setSize(strlen(componentnames)+2);
+ compnames[0]=componentnameseparator;
+ strcpy(compnames.getData()+1,componentnames);
+ // if(!buffer) buffer = new char[BLOCKSIZE];
+}
+
+void WildWriterB::beginNodes(){
+ int dims[2]={3,0};
+ dims[1]=nnodes;
+ file.reserveChunk(IObase::Float32,2,dims);
+ // set size of nodebuffer
+ bufferindex=masterindex=0;
+ segsize=BLOCKSIZE/(3*sizeof(float));
+}
+
+void WildWriterB::beginNodes(int numnodes){
+ //setMode(WriteNodes);
+ int dims[2]={3,0};
+ nnodes=numnodes;
+ dims[1]=nnodes;
+ file.reserveChunk(IObase::Float32,2,dims);
+ // set size of nodebuffer
+ bufferindex=masterindex=0;
+ segsize=BLOCKSIZE/(3*sizeof(float));
+}
+/*
+ inline void addNode(float *coords){
+ // attrib WildNode[%u] (should buffer internally)
+ // but we can only chunk on Datasets :(
+ // so collect data in 8k buffers
+ checkMode(WriteNodes);
+ float *copyptr=(float *)buffer;
+ // copy into master buffer.
+ int index=bufferindex*3;
+ for(int i=0;i<3;i++) copyptr[index+i]=coords[i];
+ bufferindex++;
+ masterindex++;
+ if(bufferindex>=segsize){ // dump the buffer to disk
+ int origin[2]={0,0},dims[2]={3,0};
+ dims[1]=segsize;
+ origin[1]=masterindex-segsize;
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0; // reset the bufferindex for next seg
+ }
+ }
+ */
+
+void WildWriterB::endNodes(){
+ // Flush buffers for final writeChunk()
+ //setMode(Idle);
+ int origin[2]={0,0},dims[2]={0,0};
+ dims[0]=totalcomp;
+ dims[1]=bufferindex;
+ origin[1]=masterindex-bufferindex;
+ // Flush buffers for final writeChunk()
+ // dump the remainder of buffer
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0;
+}
+
+void WildWriterB::beginCells(){
+ int dims[2]={9,0};
+ dims[1]=ncells;
+ file.reserveChunk(IObase::Int32,2,dims);
+ bufferindex=masterindex=0;
+ segsize=BLOCKSIZE/(9*sizeof(int));
+}
+void WildWriterB::beginCells(int numcells){
+ int dims[2]={9,0};
+ ncells=numcells;
+ dims[1]=ncells;
+ file.reserveChunk(IObase::Int32,2,dims);
+ bufferindex=masterindex=0;
+ segsize=BLOCKSIZE/(9*sizeof(int));
+}
+/*
+ inline void addCell(int level,int *neighborlist){
+ //checkMode(WriteCells);
+ int *copyptr=(int *)buffer;
+ int index=bufferindex*9;
+ // copy into master buffer.
+ copyptr[index+i]=level;
+ for(int i=0;i<8;i++)
+ copyptr[index+i+1]=neighborlist[i];
+ bufferindex++;
+ masterindex++;
+ if(bufferindex>=segsize){ // dump the buffer to disk
+ int origin[2]={0,0},dims[2]={3,0};
+ dims[1]=segsize;
+ origin[1]=masterindex-segsize;
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0; // reset the bufferindex for next seg
+ }
+ }
+ */
+
+void WildWriterB::endCells(){
+ // Flush buffers for final writeChunk()
+ //setMode(Idle);
+ int origin[2]={0,0},dims[2]={0,0};
+ dims[0]=totalcomp;
+ dims[1]=bufferindex;
+ origin[1]=masterindex-bufferindex;
+ // Flush buffers for final writeChunk()
+ // dump the remainder of buffer
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0;
+}
+void WildWriterB::beginData(){
+ int dims[2]={0,0};
+ dims[0]=totalcomp;
+ dims[1]=nnodes;
+ file.reserveChunk(comptype,2,dims);
+ bufferindex=masterindex=0;
+ segsize=BLOCKSIZE/(totalcomp*IObase::sizeOf(comptype));
+}
+
+void WildWriterB::beginData(IObase::DataType datacomponenttype,
+ int numdatacomponents,
+ int *componentsizes,
+ char *componentnames,
+ char componentnameseparator){
+ int dims[2]={0,0};
+ int i;
+ comptype=datacomponenttype;
+ ncomp = numdatacomponents;
+ compsizes.setSize(ncomp);
+ if(componentsizes){
+ for(i=0,totalcomp=1;i<ncomp;i++)
+ totalcomp+=compsizes[i]=componentsizes[i];
+ }
+ else {
+ for(i=0,totalcomp=1;i<ncomp;i++)
+ totalcomp+=compsizes[i]=1;
+ }
+ compnames.setSize(strlen(componentnames)+2);
+ compnames[0]=componentnameseparator;
+ strcpy(compnames.getData(),componentnames);
+ dims[0]=totalcomp;
+ dims[1]=nnodes;
+ file.reserveChunk(comptype,2,dims);
+ bufferindex=masterindex=0;
+ segsize=BLOCKSIZE/(totalcomp*IObase::sizeOf(comptype));
+}
+/*
+inline void WildWriterB::addData(void *data){
+ //checkMode(WriteCells);
+ if(comptype==IObase::Float32){
+ float *copyptr=(float *)buffer;
+ int index = bufferindex*totalcomp*sizeof(double);
+ for(int i=0;i<totalcomp;i++) copyptr[index+i]=data[i];
+ }
+ else if(comptype==IObase::Float64){
+ double *copyptr=(double *)buffer;
+ int index = bufferindex*totalcomp*sizeof(double);
+ for(int i=0;i<totalcomp;i++) copyptr[index+i]=data[i];
+ }
+ bufferindex++;
+ masterindex++;
+ if(bufferindex>=segsize){ // dump the buffer to disk
+ int origin[2]={0,0},dims[2]={0,0};
+ dims[0]=totalcomp;
+ dims[1]=segsize;
+ origin[1]=masterindex-segsize;
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0; // reset the bufferindex for next seg
+ }
+}
+*/
+void WildWriterB::endData(){
+ int origin[2]={0,0},dims[2]={0,0};
+ dims[0]=totalcomp;
+ dims[1]=bufferindex;
+ origin[1]=masterindex-bufferindex;
+ // Flush buffers for final writeChunk()
+ // dump the remainder of buffer
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0;
+}
+
+void WildWriterB::endDataset() {
+ // flush all buffers (not really necessary in "dumb mode")
+ // and make certain ncells & nnodes have been written
+ // delete the master buffer if dynamically allocated
+}
+
+//#include "declare_extern.h"
+
+void WriteNodes(char *filename){
+ int i,j,k,d,cell_id,vertex_id;
+ // FILE *fp;
+ // char output_file[16];
+ treenode *gp;
+ // Later On, we'll need to keep the file open persistently
+ IObase *iofile = new IEEEIO(filename,IObase::Write);
+ WildWriterB *file = new WildWriterB(*iofile);
+
+ for ( d=0 ; d<=total_depth ; d++ )
+ for ( i=0 ; i<=(x[d]-1) ; i++ ) {
+ gp = start_x[d][i];
+ do {
+ if ((gp->xyz[0] < xmax-e)&&
+ (gp->xyz[1] < ymax-e)&&
+ (gp->xyz[2] < zmax-e)){
+ cell_id++;
+ if (connectivity) {
+ if (gp->sib[1] != NULL)
+ if ((gp->sib[1]->xyz[0] < xmax-e)&&
+ (fabs(gp->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e))
+ cell_id++;
+
+ if (gp->sib[3] != NULL)
+ if ((gp->sib[3]->xyz[1] < ymax-e)&&
+ (fabs(gp->sib[3]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e))
+ cell_id++;
+
+ if ((gp->sib[1] != NULL)&&(gp->sib[3] != NULL))
+ if (gp->sib[3]->sib[1] != NULL)
+ if ((gp->sib[3]->sib[1]->xyz[0] < xmax-e)&&
+ (gp->sib[3]->sib[1]->xyz[1] < ymax-e)&&
+ (fabs(gp->sib[3]->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e)&&
+ (fabs(gp->sib[3]->sib[1]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e))
+ cell_id++;
+
+ if (gp->sib[5] != NULL)
+ if ((gp->sib[5]->xyz[2] < zmax-e)&&
+ (fabs(gp->sib[5]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ cell_id++;
+
+ if (gp->sib[5] != NULL)
+ if (gp->sib[5]->sib[1] != NULL)
+ if ((gp->sib[5]->xyz[2] < zmax-e)&&
+ (gp->sib[5]->sib[1]->xyz[0] < xmax-e)&&
+ (fabs(gp->sib[5]->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e)&&
+ (fabs(gp->sib[5]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ cell_id++;
+
+ if (gp->sib[5] != NULL)
+ if (gp->sib[5]->sib[3] != NULL)
+ if ((gp->sib[5]->xyz[2] < zmax-e)&&
+ (gp->sib[5]->sib[3]->xyz[1] < ymax-e)&&
+ (fabs(gp->sib[5]->sib[3]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e)&&
+ (fabs(gp->sib[5]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ cell_id++;
+
+ if (gp->sib[5] != NULL)
+ if ((gp->sib[5]->sib[3] != NULL)&&(gp->sib[5]->sib[1] != NULL))
+ if (gp->sib[5]->sib[3]->sib[1] != NULL)
+ if ((gp->sib[5]->sib[3]->sib[1]->xyz[0] < xmax-e)&&
+ (gp->sib[5]->sib[3]->sib[1]->xyz[1] < ymax-e)&&
+ (gp->sib[5]->sib[3]->sib[1]->xyz[2] < zmax-e)&&
+ (fabs(gp->sib[5]->sib[3]->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e)&&
+ (fabs(gp->sib[5]->sib[3]->sib[1]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e)&&
+ (fabs(gp->sib[5]->sib[3]->sib[1]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ cell_id++;
+ }
+ }
+ gp = gp->sib[1];
+ } while (gp != NULL);
+ }
+ for ( d=0 ; d<=total_depth ; d++ )
+ for ( i=0 ; i<=(x[d]-1) ; i++ ) {
+ gp = start_x[d][i];
+
+ do {
+ if ((gp->xyz[0] < xmax-e)&&
+ (gp->xyz[1] < ymax-e)&&
+ (gp->xyz[2] < zmax-e)) {
+ if (d == 0) {
+ gp->hex_id[0] = vertex_id+1;
+ gp->hex_id[1] = vertex_id+2;
+ gp->hex_id[2] = vertex_id+3;
+ gp->hex_id[3] = vertex_id+4;
+ gp->hex_id[4] = vertex_id+5;
+ gp->hex_id[5] = vertex_id+6;
+ gp->hex_id[6] = vertex_id+7;
+ gp->hex_id[7] = vertex_id+8;
+ vertex_id += 8;
+ }
+ else {
+ gp->hex_id[0] = gp->par->hex_id[gp->par_grid_point];
+ gp->hex_id[1] = vertex_id+1;
+ gp->hex_id[2] = vertex_id+2;
+ gp->hex_id[3] = vertex_id+3;
+ gp->hex_id[4] = vertex_id+4;
+ gp->hex_id[5] = vertex_id+5;
+ gp->hex_id[6] = vertex_id+6;
+ gp->hex_id[7] = vertex_id+7;
+ vertex_id += 7;
+ }
+ }
+ gp = gp->sib[1];
+ } while (gp != NULL);
+ }
+
+ // Set the var names
+ char str[256];
+ str[0]='\0';
+ for(i=0;i<variables;i++){
+ char tmpstr[5];
+ sprintf(tmpstr,"v%u,",i);
+ strcat(str,tmpstr);
+ }
+ str[strlen(str)-1]='\0';
+ /* Collected total sizes, now write UCD file header
+ fprintf(fp,"%d %d %d 0 0\n",vertex_id,cell_id,variables); */
+ file->beginDataset(vertex_id, /* number of vertices */
+ cell_id, /* number of cells */
+ IObase::Float32, /* datatype for the data components */
+ variables, /* number of data components */
+ 0,/* no array for componentsizes implies each is a scalar */
+ str,','); /* names */
+ /* Now do the nodes */
+ file->beginNodes();
+ for ( d=0 ; d<=total_depth ; d++ )
+ for ( i=0 ; i<=(x[d]-1) ; i++ ) {
+ gp = start_x[d][i];
+ do {
+ if ((gp->xyz[0] < xmax-e)&&
+ (gp->xyz[1] < ymax-e)&&
+ (gp->xyz[2] < zmax-e)) {
+ float coords[3];
+ if (d == 0){
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[0], */
+ coords[0]=gp->xyz[0];
+ coords[1]=gp->xyz[1];
+ coords[2]=gp->xyz[2];
+ file->addNode(coords);
+ }
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[1], */
+ coords[0]=gp->xyz[0]+info[d][0];
+ coords[1]=gp->xyz[1];
+ coords[2]=gp->xyz[2];
+ file->addNode(coords);
+
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[2],*/
+ coords[0]=gp->xyz[0];
+ coords[1]=gp->xyz[1]+info[d][1];
+ coords[2]=gp->xyz[2];
+ file->addNode(coords);
+
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[3],*/
+ coords[0]=gp->xyz[0]+info[d][0];
+ coords[1]=gp->xyz[1]+info[d][1];
+ coords[2]=gp->xyz[2];
+ file->addNode(coords);
+
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[4], */
+ coords[0]=gp->xyz[0];
+ coords[1]=gp->xyz[1];
+ coords[2]=gp->xyz[2]+info[d][2];
+ file->addNode(coords);
+
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[5], */
+ coords[0]=gp->xyz[0]+info[d][0];
+ coords[1]=gp->xyz[1];
+ coords[2]=gp->xyz[2]+info[d][2];
+ file->addNode(coords);
+
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[6], */
+ coords[0]=gp->xyz[0];
+ coords[1]=gp->xyz[1]+info[d][1];
+ coords[2]=gp->xyz[2]+info[d][2];
+ file->addNode(coords);
+
+ /* fprintf(fp,"%d %f %f %f\n",gp->hex_id[7], */
+ coords[0]=gp->xyz[0]+info[d][0];
+ coords[1]=gp->xyz[1]+info[d][1];
+ coords[2]=gp->xyz[2]+info[d][2];
+ file->addNode(coords);
+ }
+ gp = gp->sib[1];
+ } while (gp != NULL);
+ }
+ file->endNodes();
+
+ file->beginCells();
+ for ( cell_id=0,d=0 ; d<=total_depth ; d++ ){
+ int cellvec[8],level;
+ level=d;
+ for ( i=0 ; i<=(x[d]-1) ; i++ ) {
+ gp = start_x[d][i];
+ do {
+ if ((gp->xyz[0] < xmax-e)&&
+ (gp->xyz[1] < ymax-e)&&
+ (gp->xyz[2] < zmax-e)) {
+ cell_id++;
+
+ //fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]=gp->hex_id[4];
+ cellvec[1]=gp->hex_id[5];
+ cellvec[2]=gp->hex_id[7];
+ cellvec[3]=gp->hex_id[6];
+ cellvec[4]=gp->hex_id[0];
+ cellvec[5]=gp->hex_id[1];
+ cellvec[6]=gp->hex_id[3];
+ cellvec[7]=gp->hex_id[2];
+ file->addCell(level,cellvec);
+ if (connectivity) {
+ if (gp->sib[1] != NULL)
+ if ((gp->sib[1]->xyz[0] < xmax-e)&&
+ (fabs(gp->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e))
+ {
+ cell_id++;
+
+ // fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]=gp->hex_id[5];
+ cellvec[1]=gp->sib[1]->hex_id[4];
+ cellvec[2]=gp->sib[1]->hex_id[6];
+ cellvec[3]=gp->hex_id[7];
+ cellvec[4]=gp->hex_id[1];
+ cellvec[5]=gp->sib[1]->hex_id[0];
+ cellvec[6]=gp->sib[1]->hex_id[2];
+ cellvec[7]=gp->hex_id[3];
+ file->addCell(level,cellvec);
+ }
+
+ if (gp->sib[3] != NULL)
+ if ((gp->sib[3]->xyz[1] < ymax-e)&&
+ (fabs(gp->sib[3]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e))
+ {
+ cell_id++;
+ //fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]= gp->hex_id[6];
+ cellvec[1]=gp->hex_id[7];
+ cellvec[2]=gp->sib[3]->hex_id[5];
+ cellvec[3]= gp->sib[3]->hex_id[4];
+ cellvec[4]=gp->hex_id[2];
+ cellvec[5]=gp->hex_id[3];
+ cellvec[6]= gp->sib[3]->hex_id[1];
+ cellvec[7]= gp->sib[3]->hex_id[0];
+ file->addCell(level,cellvec);
+ }
+
+ if ((gp->sib[1] != NULL)&&(gp->sib[3] != NULL))
+ if (gp->sib[3]->sib[1] != NULL)
+ if ((gp->sib[3]->sib[1]->xyz[0] < xmax-e)&&
+ (gp->sib[3]->sib[1]->xyz[1] < ymax-e)&&
+ (fabs(gp->sib[3]->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e)&&
+ (fabs(gp->sib[3]->sib[1]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e))
+ {
+ cell_id++;
+ //fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]= gp->hex_id[7];
+ cellvec[1]= gp->sib[1]->hex_id[6];
+ cellvec[2]= gp->sib[3]->sib[1]->hex_id[4];
+ cellvec[3]= gp->sib[3]->hex_id[5];
+ cellvec[4]= gp->hex_id[3];
+ cellvec[5]= gp->sib[1]->hex_id[2];
+ cellvec[6]= gp->sib[3]->sib[1]->hex_id[0];
+ cellvec[7]= gp->sib[3]->hex_id[1];
+ file->addCell(level,cellvec);
+ }
+
+ if (gp->sib[5] != NULL)
+ if ((gp->sib[5]->xyz[2] < zmax-e)&&
+ (fabs(gp->sib[5]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ {
+ cell_id++;
+ //fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]=gp->sib[5]->hex_id[0];
+ cellvec[1]=gp->sib[5]->hex_id[1];
+ cellvec[2]=gp->sib[5]->hex_id[3];
+ cellvec[3]=gp->sib[5]->hex_id[2];
+ cellvec[4]= gp->hex_id[4];
+ cellvec[5]=gp->hex_id[5];
+ cellvec[6]=gp->hex_id[7];
+ cellvec[7]= gp->hex_id[6];
+ file->addCell(level,cellvec);
+ }
+
+ if (gp->sib[5] != NULL)
+ if (gp->sib[5]->sib[1] != NULL)
+ if ((gp->sib[5]->xyz[2] < zmax-e)&&
+ (gp->sib[5]->sib[1]->xyz[0] < xmax-e)&&
+ (fabs(gp->sib[5]->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e)&&
+ (fabs(gp->sib[5]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ {
+ cell_id++;
+ //fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]=gp->sib[5]->hex_id[1];
+ cellvec[1]= gp->sib[5]->sib[1]->hex_id[0];
+ cellvec[2]= gp->sib[5]->sib[1]->hex_id[2];
+ cellvec[3]= gp->sib[5]->hex_id[3];
+ cellvec[4]= gp->hex_id[5];
+ cellvec[5]= gp->sib[1]->hex_id[4];
+ cellvec[6]= gp->sib[1]->hex_id[6];
+ cellvec[7]= gp->hex_id[7];
+ file->addCell(level,cellvec);
+ }
+
+ if (gp->sib[5] != NULL)
+ if (gp->sib[5]->sib[3] != NULL)
+ if ((gp->sib[5]->xyz[2] < zmax-e)&&
+ (gp->sib[5]->sib[3]->xyz[1] < ymax-e)&&
+ (fabs(gp->sib[5]->sib[3]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e)&&
+ (fabs(gp->sib[5]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ {
+ cell_id++;
+
+ //fprintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]=gp->sib[5]->hex_id[2];
+ cellvec[1]=gp->sib[5]->hex_id[3];
+ cellvec[2]=gp->sib[5]->sib[3]->hex_id[1];
+ cellvec[3]=gp->sib[5]->sib[3]->hex_id[0];
+ cellvec[4]=gp->hex_id[6];
+ cellvec[5]=gp->hex_id[7];
+ cellvec[6]=gp->sib[3]->hex_id[5];
+ cellvec[7]=gp->sib[3]->hex_id[4];
+ file->addCell(level,cellvec);
+ }
+
+ if (gp->sib[5] != NULL)
+ if ((gp->sib[5]->sib[3] != NULL)&&(gp->sib[5]->sib[1] != NULL))
+ if (gp->sib[5]->sib[3]->sib[1] != NULL)
+ if ((gp->sib[5]->sib[3]->sib[1]->xyz[0] < xmax-e)&&
+ (gp->sib[5]->sib[3]->sib[1]->xyz[1] < ymax-e)&&
+ (gp->sib[5]->sib[3]->sib[1]->xyz[2] < zmax-e)&&
+ (fabs(gp->sib[5]->sib[3]->sib[1]->xyz[0]-gp->xyz[0]) <= info[d][0]+info[d][0]+e)&&
+ (fabs(gp->sib[5]->sib[3]->sib[1]->xyz[1]-gp->xyz[1]) <= info[d][1]+info[d][1]+e)&&
+ (fabs(gp->sib[5]->sib[3]->sib[1]->xyz[2]-gp->xyz[2]) <= info[d][2]+info[d][2]+e))
+ {
+ cell_id++;
+ //rintf(fp,"%d 1 hex %d %d %d %d %d %d %d %d\n",cell_id,
+ cellvec[0]=gp->sib[5]->hex_id[3];
+ cellvec[1]=gp->sib[5]->sib[1]->hex_id[2];
+ cellvec[2]=gp->sib[5]->sib[3]->sib[1]->hex_id[0];
+ cellvec[3]=gp->sib[5]->sib[3]->hex_id[1];
+ cellvec[4]=gp->hex_id[7];
+ cellvec[5]=gp->sib[1]->hex_id[6];
+ cellvec[6]=gp->sib[3]->sib[1]->hex_id[4];
+ cellvec[7]=gp->sib[3]->hex_id[5];
+ file->addCell(level,cellvec);
+ }
+ }
+ }
+ gp = gp->sib[1];
+ } while (gp != NULL);
+ }
+ }
+ file->endCells(); // Done with writing Cells
+ //rintf(fp,"%d",variables);
+ //for ( i=1 ; i<=(variables-1) ; i++ )
+ // fprintf(fp," 1");
+ // fprintf(fp," 1\n");
+ file->beginData(); // Start writing Data
+ //for ( i=1 ; i<=variables ; i++ )
+ // fprintf(fp,"v%d, 1b/in**2\n",i);
+ for ( d=0 ; d<=total_depth ; d++ )
+ for ( i=0 ; i<=(x[d]-1) ; i++ ) {
+ gp = start_x[d][i];
+ do {
+ if ((gp->xyz[0] < xmax-e)&&
+ (gp->xyz[1] < ymax-e)&&
+ (gp->xyz[2] < zmax-e)) {
+ if (d == 0) { // The toplevel
+ for ( k=0 ; k<=7 ; k++ ) {
+ /* fprintf(fp,"%d ",gp->hex_id[k]);
+ for ( j=0 ; j<=(variables-2) ; j++ )
+ fprintf(fp,"%f ",gp->u[k][t[d][0]][j]);
+ fprintf(fp,"%f\n",gp->u[k][t[d][0]][variables-1]);*/
+ file->addData(gp->u[k][t[d][0]]);
+ }
+ }
+ else {
+ for ( k=1 ; k<=7 ; k++ ) {
+ /*fprintf(fp,"%d ",gp->hex_id[k]);
+ for ( j=0 ; j<=(variables-2) ; j++ )
+ fprintf(fp,"%f ",gp->u[k][t[d][0]][j]);
+ fprintf(fp,"%f\n",gp->u[k][t[d][0]][variables-1]);*/
+ file->addData(gp->u[k][t[d][0]]);
+ }
+ }
+ }
+ gp = gp->sib[1];
+ } while (gp != NULL);
+ }
+ file->endData();
+ file->endDataset();
+}
diff --git a/src/WildWriter.h b/src/WildWriter.h
new file mode 100644
index 0000000..c2b4a3b
--- /dev/null
+++ b/src/WildWriter.h
@@ -0,0 +1,7 @@
+#ifndef __WILDWRITER_H_
+#define __WILDWRITER_H_
+
+#include "declare_extern.h"
+void WriteNodes(char *filename);
+
+#endif
diff --git a/src/WildWriter.hh b/src/WildWriter.hh
new file mode 100644
index 0000000..a391ea3
--- /dev/null
+++ b/src/WildWriter.hh
@@ -0,0 +1,142 @@
+#ifndef __WILDWRITER_HH_
+#define __WILDWRITER_HH_
+
+#include <IO.hh>
+#include <IEEEIO.hh>
+#include <FlexArrayTmpl.H>
+
+#define DISKBLOCKSIZE 8192
+#define BLOCKSIZE 2*DISKBLOCKSIZE
+
+// Does not assume contiguous data (writes in chunks)
+class WildWriterB {
+ IObase &file;
+ int nnodes,ncells,ncomp;
+ char buffer[BLOCKSIZE]; // could dynamically allocate
+ FlexArray<char> compnames;
+ int totalcomp;
+ IObase::DataType comptype;
+ FlexArray<int> compsizes;
+ int bufferindex,masterindex,segsize;
+public:
+ WildWriterB(IObase &descriptor):file(descriptor){
+ }
+ ~WildWriterB(){}
+ void beginDataset(int numnodes,
+ int numcells,
+ IObase::DataType datacomponenttype,
+ int numdatacomponents,
+ int *componentsizes,
+ char *componentnames,
+ char componentnameseparator);
+
+ void beginNodes(int numnodes);
+ void beginNodes();
+ inline void addNode(float *coords){
+ // attrib WildNode[%u] (should buffer internally)
+ // but we can only chunk on Datasets :(
+ // so collect data in 8k buffers
+ //checkMode(WriteNodes);
+ float *copyptr=(float *)buffer;
+ // copy into master buffer.
+ int index=bufferindex*3;
+ for(int i=0;i<3;i++) copyptr[index+i]=coords[i];
+ bufferindex++;
+ masterindex++;
+ if(bufferindex>=segsize){ // dump the buffer to disk
+ int origin[2]={0,0},dims[2]={3,0};
+ dims[1]=segsize;
+ origin[1]=masterindex-segsize;
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0; // reset the bufferindex for next seg
+ }
+ }
+ void endNodes();
+ void beginCells(int numcells);
+ void beginCells();
+ inline void addCell(int level,int *neighborlist){
+ // checkMode(WriteCells);
+ int *copyptr=(int *)buffer;
+ int index=bufferindex*9;
+ // copy into master buffer.
+ copyptr[index+1]=level;
+ for(int i=0;i<8;i++)
+ copyptr[index+i+1]=neighborlist[i];
+ bufferindex++;
+ masterindex++;
+ if(bufferindex>=segsize){ // dump the buffer to disk
+ int origin[2]={0,0},dims[2]={3,0};
+ dims[1]=segsize;
+ origin[1]=masterindex-segsize;
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0; // reset the bufferindex for next seg
+ }
+ }
+ void endCells();
+ void beginData();
+ void beginData(IObase::DataType datacomponenttype,
+ int numdatacomponents,
+ int *componentsizes,
+ char *componentnames,
+ char componentnameseparator);
+ inline void addData(void *data){
+ // checkMode(WriteCells);
+ if(comptype==IObase::Float32){
+ float *copyptr=(float *)buffer;
+ float *dptr=(float*)data;
+ int index = bufferindex*totalcomp*sizeof(double);
+ for(int i=0;i<totalcomp;i++) copyptr[index+i]=dptr[i];
+ }
+ else if(comptype==IObase::Float64){
+ double *copyptr=(double *)buffer;
+ double *dptr = (double *)data;
+ int index = bufferindex*totalcomp*sizeof(double);
+ for(int i=0;i<totalcomp;i++) copyptr[index+i]=dptr[i];
+ }
+ bufferindex++;
+ masterindex++;
+ if(bufferindex>=segsize){ // dump the buffer to disk
+ int origin[2]={0,0},dims[2]={0,0};
+ dims[0]=totalcomp;
+ dims[1]=segsize;
+ origin[1]=masterindex-segsize;
+ file.writeChunk(dims,origin,buffer);
+ bufferindex=0; // reset the bufferindex for next seg
+ }
+ }
+ void endData();
+ void endDataset() ;
+};
+
+extern "C" {
+#include "WildWriter.h"
+}
+
+#endif
+
+/*
+// Assumes Contiguous Data
+class WildWriterA {
+ IO &file;
+public:
+ WildWriter(IO &descriptor):file(descriptor){
+ }
+ ~WildWriter(){
+ }
+ // All nodes for all levels
+ void writeNodes(int numnodes,float *node_coords){
+ int dims[2]={3,0};
+ dims[1]=numnodes;
+ file.write(IObase::Float32,2,dims,node_coords);
+ file.writeAttribute("WildNodes",IObase::Int,0,dims);
+ }
+ // Must Be Hexahedral Cells
+ void writeCells(int level,int ncells,int *celllist){
+
+ }
+ // Assumes Node-centered data
+ void writeData(char *name,IObase::DataType type,int veclen,void *data){
+
+ }
+};
+*/
diff --git a/src/WriteHLL.cc b/src/WriteHLL.cc
new file mode 100644
index 0000000..cdb8095
--- /dev/null
+++ b/src/WriteHLL.cc
@@ -0,0 +1,229 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <IO.hh>
+#include "WriteHLL.hh"
+
+// declare a new dataset
+void WriteHLL::newDataset(int ndims,long npoints){
+ int dt=1;
+ current_ndims=ndims;
+ file.write(IObase::Int32,dt,&dt,&ndims); // single integer (ndims)
+ switch(ndims){
+ case 1:
+ current_cellsize=2;
+ current_celltype="line";
+ break;
+ case 2:
+ current_cellsize=4;
+ current_celltype="quad";
+ break;
+ case 3:
+ current_cellsize=8;
+ current_celltype="hex";
+ break;
+ default:
+ fprintf(stderr,"WriteHLL:newDataset(), ndims=%d is invalid\n",ndims);
+ break;
+ }
+ current_npoints=npoints;
+ file.writeAttribute("cellsize",IObase::Int32,1,&current_cellsize);
+ file.writeAttribute("celltype",IObase::String,strlen(current_celltype),current_celltype);
+}
+// each array is npoints long
+void WriteHLL::writeCoords(void *xcoords,void *ycoords,void *zcoords){
+ if(xcoords)
+ file.writeAttribute("xcoords",IObase::Float32,current_npoints,xcoords);
+ if(ycoords)
+ file.writeAttribute("ycoords",IObase::Float32,current_npoints,ycoords);
+ if(zcoords)
+ file.writeAttribute("zcoords",IObase::Float32,current_npoints,zcoords);
+}
+
+void WriteHLL::writeCoordsXYZ(void *xyzcoordsp){ // this is npoints *3 long
+ register long s,d,last=current_npoints*3;
+ float *xyzcoords=(float*)xyzcoordsp;
+ char coordname[32];
+ float *coords = new float[current_npoints];
+ strcpy(coordname,"xcoords");
+ for(int i=0;i<current_ndims;i++,(*coordname)++){
+ for(s=i;s<last;s+=current_ndims,d++) coords[d]=xyzcoords[s];
+ file.writeAttribute(coordname,IObase::Float32,current_npoints,coords);
+ }
+ delete coords;
+}
+void WriteHLL::writeConnectivity(void *cellsp,long ncells){
+ ncells=(ncells<0)?current_npoints:ncells;
+ int *cells=(int*)cellsp;
+ file.writeAttribute("cells",IObase::Int32,ncells*current_cellsize,cells);
+}
+// npoints data points since the data is vertex-centered
+// each dataset can be of independent type
+void WriteHLL::writeData(char *dataname,IObase::DataType datatype,void *data,int veclen){
+ char dname[128];
+ sprintf(dname,"data_%s",dataname);
+ file.writeAttribute(dname,datatype,current_npoints*veclen,data);
+}
+// declare a new dataset
+void ReadHLL::selectDataset(int step,int &ndims,int &npoints,int &ncells,int &ndata){
+ IObase::DataType dt;
+ int index,dims,len;
+ file.seek(step);
+ file.readInfo(dt,index,&dims);
+ file.read(&ndims);
+ file.readAttributeInfo("xcoords",dt,npoints);
+ file.readAttributeInfo("cells",dt,ncells);
+ index=file.readAttributeInfo("cellsize",dt,len);
+ file.readAttribute(index,&current_cellsize);
+ ncells/=current_cellsize;
+
+ current_ndims=ndims;
+ current_npoints=npoints;
+ current_ncells=ncells;
+}
+void ReadHLL::readDataInfo(char *names[],
+ IObase::DataType *datatypes,
+ int *veclens){
+ for(int i=0,dataindex=0,nannotations=file.nAnnotations();
+ i<nannotations;i++){
+ char name[128];
+ file.readAttributeInfo(i,name,datatypes[dataindex],veclens[dataindex]);
+ if(!strncmp(name,"data_",5)){
+ strcpy(names[dataindex],name+5);
+ veclens[dataindex]/=current_npoints;
+ dataindex++;
+ }
+ }
+}
+void ReadHLL::readDataInfo(char *names[],
+ int *datatypes,
+ int *veclens){
+ for(int i=0,dataindex=0,nannotations=file.nAnnotations();
+ i<nannotations;i++){
+ char name[128];
+ IObase::DataType dt;
+ file.readAttributeInfo(i,name,dt,veclens[dataindex]);
+ datatypes[dataindex]=dt;
+ if(!strncmp(name,"data_",5)){
+ strcpy(names[dataindex],name+5);
+ veclens[dataindex]/=current_npoints;
+ dataindex++;
+ }
+ }
+}
+// each array is npoints long
+void ReadHLL::readCoords(float *xcoords,float *ycoords,float *zcoords){
+ IObase::DataType dt;
+ int npoints,idx;
+ if(current_ndims>=1 && xcoords)
+ idx=file.readAttributeInfo("xcoords",dt,npoints);
+ if(idx>=0 && npoints==current_npoints)
+ file.readAttribute(idx,xcoords);
+ if(current_ndims>=1 && ycoords)
+ idx=file.readAttributeInfo("ycoords",dt,npoints);
+ if(idx>=0 && npoints==current_npoints)
+ file.readAttribute(idx,ycoords);
+ if(current_ndims>=1 && zcoords)
+ idx=file.readAttributeInfo("zcoords",dt,npoints);
+ if(idx>=0 && npoints==current_npoints)
+ file.readAttribute(idx,zcoords);
+}
+// will assume ncells=npoints unless overridden.
+void ReadHLL::readConnectivity(int *cells){
+ int arraysize,idx;
+ IObase::DataType dt;
+ idx=file.readAttributeInfo("cells",dt,arraysize);
+ file.readAttribute(idx,cells);
+}
+
+// npoints data points since the data is vertex-centered
+// each dataset can be of independent type
+void ReadHLL::readData(char *name,void *data){
+ char dname[128];
+ IObase::DataType datatype;
+ int len,idx;
+ sprintf(dname,"data_%s",name);
+ idx=file.readAttributeInfo(dname,datatype,len);
+ file.readAttribute(idx,data);
+}
+
+
+
+IOFile *HLLnewWriter(IOFile *file){
+ IObase *iofile = (IObase *)file;
+ return (IOFile *)(new WriteHLL(*iofile));
+}
+void HLLdeleteWriter(IOFile *file){
+ if(!file) return;
+ WriteHLL *h = (WriteHLL *)file;
+ delete h;
+}
+
+void HLLsetCoordType(IOFile *handle,int coordtype){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->setCoordType(IObase::Int2DataType(coordtype));
+}
+
+void HLLsetIndexType(IOFile *handle,int indextype){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->setIndexType(IObase::Int2DataType(indextype));
+}
+
+void HLLnewDataset(IOFile *handle,int ndims,long npoints){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->newDataset(ndims,npoints);
+}
+void HLLwriteCoords(IOFile *handle,
+ float *xcoords,float *ycoords,float *zcoords){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->writeCoords(xcoords,ycoords,zcoords);
+}
+void HLLwriteCoordsXYZ(IOFile *handle,float *xcoords){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->writeCoordsXYZ(xcoords);
+}
+void HLLwriteConnectivity(IOFile *handle,int *cells,int ncells){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->writeConnectivity(cells,ncells);
+}
+void HLLwriteData(IOFile *handle,char *dataname,int datatype,
+ void *data,int veclen){
+ WriteHLL *h = (WriteHLL *)handle;
+ h->writeData(dataname,IObase::Int2DataType(datatype),data,veclen);
+}
+
+IOFile *HLLnewReader(IOFile *base){
+ IObase *iofile = (IObase *)base;
+ return (IOFile *)(new ReadHLL(*iofile));
+}
+void HLLdeleteReader(IOFile *handle){
+ if(!handle) return;
+ ReadHLL *h = (ReadHLL *)handle;
+ delete h;
+}
+
+void HLLselectDataset(IOFile *handle,
+ int index,int *ndims,int *npoints,
+ int *ncells,int *ndata){
+ ReadHLL *h = (ReadHLL *)handle;
+ h->selectDataset(index,*ndims,*npoints,*ncells,*ndata);
+}
+void HLLreadDataInfo(IOFile *handle,char *names[],
+ int *datatypes,int *veclens){
+ ReadHLL *h = (ReadHLL *)handle;
+ h->readDataInfo(names,datatypes,veclens);
+}
+void HLLreadCoords(IOFile *handle,
+ float *xcoords,float *ycoords,float *zcoords){
+ ReadHLL *h = (ReadHLL *)handle;
+ h->readCoords(xcoords,ycoords,zcoords);
+}
+void HLLreadConnectivity(IOFile *handle,int *cells){
+ ReadHLL *h = (ReadHLL *)handle;
+ h->readConnectivity(cells);
+}
+void HLLreadData(IOFile *handle,char *name,void *data){
+ ReadHLL *h = (ReadHLL *)handle;
+ h->readData(name,data);
+}
+
diff --git a/src/WriteHLL.h b/src/WriteHLL.h
new file mode 100644
index 0000000..7d02130
--- /dev/null
+++ b/src/WriteHLL.h
@@ -0,0 +1,32 @@
+
+#ifndef __HLL_WRITER_H_
+#define __HLL_WRITER_H_
+
+IOFile *HLLnewWriter(IOFile *file);
+void HLLdeleteWriter(IOFile *file);
+
+void HLLsetCoordType(IOFile *handle,int coordtype);
+void HLLsetIndexType(IOFile *handle,int indextype);
+void HLLnewDataset(IOFile *handle,int ndims,long npoints);
+void HLLwriteCoords(IOFile *handle,
+ void *xcoords,void *ycoords,void *zcoords);
+void HLLwriteCoordsXYZ(IOFile *handle,void *xcoords);
+void HLLwriteConnectivity(IOFile *handle,void *cells,long ncells);
+void HLLwriteData(IOFile *handle,char *dataname,int datatype,
+ void *data,int veclen);
+
+IOFile *HLLnewReader(IOFile *base);
+void HLLdeleteReader(IOFile *handle);
+
+void HLLselectDataset(IOFile *handle,
+ int index,int *ndims,int *npoints,
+ int *ncells,int *ndata);
+void HLLreadDataInfo(IOFile *handle,char *names[],
+ int *datatypes,int *veclens);
+void HLLreadCoords(IOFile *handle,
+ float *xcoords,float *ycoords,float *zcoords);
+void HLLreadConnectivity(IOFile *handle,int *cells);
+void HLLreadData(IOFile *handle,char *name,void *data);
+
+
+#endif
diff --git a/src/WriteHLL.hh b/src/WriteHLL.hh
new file mode 100644
index 0000000..90c4ba1
--- /dev/null
+++ b/src/WriteHLL.hh
@@ -0,0 +1,52 @@
+#ifndef __HLL_WRITER_HH_
+#define __HLL_WRITER_HH_
+#include <IO.hh>
+
+class WriteHLL {
+ IObase &file;
+ int current_npoints,current_cellsize,current_ndims;
+ char *current_celltype;
+ IObase::DataType coordtype,indextype;
+public:
+ WriteHLL(IObase &iofile):file(iofile),current_npoints(0),
+ coordtype(IObase::Float32),indextype(IObase::Int32){}
+ ~WriteHLL(){}
+ // declare a new dataset
+ void newDataset(int ndims,long npoints);
+ void setCoordType(IObase::DataType dt){ coordtype=dt; }
+ void setIndexType(IObase::DataType dt){ indextype=dt; }
+ // each array is npoints long
+ void writeCoords(void *xcoords,void *ycoords=0,void *zcoords=0); // for 3D
+ void writeCoordsXYZ(void *xcoords); // for Packed Coords (any dimension)
+ // will assume ncells=npoints unless overridden.
+ void writeConnectivity(void *cells,long ncells=-1); // implicit cellsize
+ void writeConnectivity(int cellsize,void *cells,long ncells=-1);
+ // npoints data points since the data is vertex-centered
+ // each dataset can be of independent type
+ void writeData(char *dataname,IObase::DataType datatype,
+ void *data,int veclen=1);
+};
+
+class ReadHLL {
+ IObase &file;
+ int current_npoints,current_ncells,current_cellsize,current_ndims;
+public:
+ ReadHLL(IObase &iofile):
+ file(iofile),current_npoints(0),current_ncells(0),
+ current_cellsize(0),current_ndims(0){}
+ ~ReadHLL(){}
+ // declare a new dataset
+ void selectDataset(int index,int &ndims,int &npoints,int &ncells,int &ndata);
+ // each array is npoints long
+ void readDataInfo(char *names[],IObase::DataType *datatypes,int *veclens);
+ void readDataInfo(char *names[],int *datatypes,int *veclens);
+ void readCoords(float *xcoords,float *ycoords=0,float *zcoords=0);
+ void readConnectivity(int *cells);
+ // npoints data points since the data is vertex-centered
+ // each dataset can be of independent type
+ void readData(char *name,void *data);
+};
+extern "C" {
+#include "WriteHLL.h"
+ }
+#endif
diff --git a/src/Writer.cc b/src/Writer.cc
new file mode 100644
index 0000000..e904f64
--- /dev/null
+++ b/src/Writer.cc
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include "Writer.hh"
+
+void Writer::writeBounds(){
+ if(!ddelta || !dorigin) return;
+ /*
+ if(extsize!=drank){
+ if(dext) delete dext;
+ dext=new double[drank];
+ }*/
+ for(int i=0;i<drank;i++) // always recompute extents
+ dext[i]=dorigin[i]+ddelta[i]*(double)(ddims[i]);
+ file.writeAttribute("origin",IObase::Float64,drank,dorigin);
+ file.writeAttribute("delta",IObase::Float64,drank,ddelta);
+ file.writeAttribute("min_ext",IObase::Float64,drank,dorigin);
+ file.writeAttribute("max_ext",IObase::Float64,drank,dext);
+}
+
+Writer::Writer(IObase &outfile):
+ file(outfile),dtypeID(IObase::Float32),drank(3),extsize(0) {
+ // zero the values here... Set to sensible initial values
+ for(int i=0;i<5;i++){
+ dorigin[i]=0;
+ ddims[i]=0;
+ dext[i]=1.0;
+ ddelta[i]=1.0;
+ }
+}
+
+Writer::~Writer() {
+/*
+ if(ddims) delete ddims;
+ if(ddelta) delete ddelta;
+ if(dorigin) delete dorigin;
+ if(dext) delete dext;
+*/
+}
+
+void Writer::setRank(int rank){
+ drank=rank;
+ /*
+ if(ddims) delete ddims;
+ ddims=new int[rank];
+ */
+}
+
+void Writer::setDims(int *dims){
+ for(int i=0;i<drank;i++) ddims[i]=dims[i];
+}
+
+void Writer::setDims(int rank,int *dims){
+ setRank(rank);
+ setDims(dims);
+}
+
+void Writer::setType(IObase::DataType typeID){
+ dtypeID=typeID;
+}
+
+void Writer::setOrigin(double *origin){
+/*
+ if(dorigin) delete dorigin;
+ dorigin = new double[drank]; */
+ for(int i=0;i<drank;i++) dorigin[i]=origin[i];
+}
+
+void Writer::setDelta(double *delta){
+/*
+ if(ddelta) delete ddelta;
+ ddelta = new double[drank]; */
+ for(int i=0;i<drank;i++) ddelta[i]=delta[i];
+}
+
+void Writer::setParams(int rank,int *dims,IObase::DataType typeID,
+ double *origin,double *delta){
+ setDims(rank,dims);
+ setType(typeID);
+ setOrigin(origin);
+ setDelta(delta);
+}
+
+void Writer::write(void *data){
+ file.write(dtypeID,drank,ddims,data);
+ //puts("writebounds after data");
+ writeBounds();
+}
+
+void Writer::reserveChunk(){
+ file.reserveChunk(dtypeID,drank,ddims);
+ writeBounds(); // write the boundary information
+}
+
+void Writer::writeChunk(int *dims,int *origin,void *data){
+ // make certain the chunk is reserved?
+ file.writeChunk(dims,origin,data);
+}
+//===========C Interface======================================
+// should have an RTTI interface and inherit everything from
+// IOobject which contains the RTTI isOfType() information.
+// isOfType() should propagate recursively to determin type info
+// match. must grab typeID from floating point pool. And then
+// we need a static initializer for everything.
+
+// How does performer/inventor do this?
+// if it hits an undefined interface (-1 default static value) then
+// nobody has constructed an interface of that type yet. So that would
+// determine that the class is unrelated...
+
+WRFile WRbeginFile(IOFile descriptor){
+ IObase *io = (IObase*)descriptor;
+ return (WRFile)(new Writer(*io));
+}
+
+void WRendFile(WRFile afile){
+ Writer *w = (Writer*)afile;
+ delete w;
+}
+
+void WRsetRank(WRFile afile,int rank){
+ Writer *w = (Writer*)afile;
+ w->setRank(rank);
+}
+
+void WRsetType(WRFile afile,int numbertype){
+ Writer *w = (Writer*)afile;
+ w->setType(IObase::Int2DataType(numbertype));
+}
+
+void WRsetParams(WRFile afile,
+ int rank,int *dims,int type,
+ double *origin,double *delta){
+ Writer *w = (Writer*)afile;
+ w->setParams(rank,dims,IObase::Int2DataType(type),origin,delta);
+}
+
+void WRsetDims(WRFile afile,int *dims){
+ Writer *w = (Writer*)afile;
+ w->setDims(dims);
+}
+
+void WRsetRankDims(WRFile afile,int rank, int *dims){
+ Writer *w = (Writer*)afile;
+ w->setDims(rank,dims);
+}
+
+void WRsetOrigin(WRFile afile,double *origin){
+ Writer *w = (Writer*)afile;
+ w->setOrigin(origin);
+}
+
+void WRsetDelta(WRFile afile,double *delta){
+ Writer *w = (Writer*)afile;
+ w->setOrigin(delta);
+}
+
+void WRwrite(WRFile afile,void *data){
+ Writer *w = (Writer*)afile;
+ w->write(data);
+}
+
+void WRwriteChunk(WRFile afile){
+ Writer *w = (Writer*)afile;
+ w->reserveChunk();
+}
+
+void WRwriteChunk(WRFile afile,int *dims,int *origin,void *data){
+ Writer *w = (Writer*)afile;
+ w->writeChunk(dims,origin,data);
+}
diff --git a/src/Writer.h b/src/Writer.h
new file mode 100644
index 0000000..99500df
--- /dev/null
+++ b/src/Writer.h
@@ -0,0 +1,23 @@
+#ifndef __WRITER_H_
+#define __WRITER_H_
+
+#include "Arch.h"
+
+typedef IOFile WRFile;/* its the same, but it is a different object underneath */
+WRFile WRbeginFile PROTO((IOFile *descriptor));
+void WRendFile PROTO((WRFile afile));
+
+void WRsetRank PROTO((WRFile afile,int rank));
+void WRsetType PROTO((WRFile afile,int numbertype));
+void WRsetParams PROTO((WRFile afile,
+ int rank,int *dims,int type,
+ double *origin,double *delta));
+void WRsetDims PROTO((WRFile afile,int *dims));
+void WRsetRankDims PROTO((WRFile afile,int rank, int *dims));
+void WRsetOrigin PROTO((WRFile afile,double *origin));
+void WRsetDelta PROTO((WRFile afile,double *delta));
+void WRwrite PROTO((WRFile afile,void *data));
+void WRreserveChunk PROTO((WRFile afile));
+void WRwriteChunk PROTO((WRFile afile,int *dims,int *origin,void *data));
+#endif
+
diff --git a/src/Writer.hh b/src/Writer.hh
new file mode 100644
index 0000000..94f2a70
--- /dev/null
+++ b/src/Writer.hh
@@ -0,0 +1,37 @@
+#ifndef __UNIWRITER_HH_
+#define __UNIWRITER_HH_
+
+#include "IO.hh"
+
+class Writer {
+protected:
+ IObase &file;
+ int drank;
+ //int *ddims;
+ int ddims[5];
+ IObase::DataType dtypeID;
+ // double *ddelta,*dorigin,*dext;
+ double ddelta[5],dorigin[5],dext[5];
+ int extsize;
+ virtual void writeBounds();
+public:
+ Writer(IObase &outfile);
+ virtual ~Writer();
+ virtual void setRank(int rank); // more efficient to set rank once for all
+ virtual void setDims(int *dims);//only if rank has been set(should have flag)
+ virtual void setDims(int rank,int *dims);
+ virtual void setType(IObase::DataType typeID);
+ virtual void setOrigin(double *origin);
+ virtual void setDelta(double *delta);
+ virtual void setParams(int rank,int *dims,IObase::DataType typeID,
+ double *origin,double *delta);
+ virtual void write(void *data);
+ virtual void reserveChunk();
+ virtual void writeChunk(int *chunkdims,int *chunkorigin,void *data);
+};
+
+extern "C" {
+#include "Writer.h"
+}
+
+#endif
diff --git a/src/boxinbox.cc b/src/boxinbox.cc
new file mode 100644
index 0000000..c5864fc
--- /dev/null
+++ b/src/boxinbox.cc
@@ -0,0 +1,156 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <IEEEIO.hh>
+#include "AMRwriter.hh"
+typedef char *charp;
+struct CommandLine {
+ char *programname;
+ charp infile[32];
+ char outfile[128];
+ int maxlevel;
+
+ void setDefaults(){
+ programname="";
+ for(int i=0;i<32;i++) infile[i]=0;
+ strcpy(outfile,"amrout.ieee");
+ maxlevel=0;
+ }
+
+ CommandLine(){
+ setDefaults();
+ }
+
+ CommandLine(int argc,char *argv[]){
+ setDefaults();
+ parse(argc,argv);
+ }
+
+ void parse(int argc,char *argv[]){
+ programname=argv[0];
+ for(int i=1;i<argc;i++){
+ char *str=argv[i];
+ if(*str=='-'){
+ char *val=argv[i+1];
+ str++;
+ //printf("read option[%u]=[%s]\n",i,str);
+ if(*str=='i') {
+ puts("option -i: input files");
+ i++;
+ for(maxlevel=0;i<argc &&
+ (*(argv[i])!='-') &&
+ maxlevel<32;
+ maxlevel++,i++)
+ infile[maxlevel]=argv[i];
+ i--;
+ }
+ else if(*str=='o') {
+ puts("option -o: output files");
+ strcpy(outfile,val);
+ }
+ }
+ }
+ if(!maxlevel) {
+ usage();
+ exit(0);
+ }
+ }
+ void usage(){
+ printf("Incorrect usage. You should use\n");
+ printf("%s -i <infile Level0> <infile Level1> ...<infile LevelN> -o <outfile>\n",programname);
+ puts("Files must appear in order as they are read in.");
+ }
+};
+
+int main(int argc, char *argv[]){
+ CommandLine cmdln(argc,argv);
+ typedef IEEEIO *IEEEIOp;
+ int ninfiles;
+ IEEEIOp infid[32],outfid;
+ AMRwriter *amrfile;
+ int i;
+
+ for(i=0;i<cmdln.maxlevel;i++){
+ infid[i]=new IEEEIO(cmdln.infile[i],IObase::Read);
+ if(!infid[i]->isValid()) {
+ printf("file %s is not an IEEEIO file\n",cmdln.infile[i]);
+ exit(0);
+ }
+ else
+ printf("Opening file %s as level %u for reading\n",
+ cmdln.infile[i],i);
+ }
+ outfid = new IEEEIO(cmdln.outfile,IObase::Write);
+ if(!outfid->isValid()) {
+ printf("file %s could not be opened for writing\n",cmdln.outfile);
+ exit(0);
+ }
+ amrfile = new AMRwriter(*outfid);
+ printf("Opened file %s for output\n",cmdln.outfile);
+
+ // lets get info about the toplevel grid
+ IObase::DataType type;
+ int rank,dims[3];
+ int nelements,attribnum;
+ double delta[3],timestep,origin[3];
+
+ infid[0]->seek(0);
+ infid[0]->readInfo(type,rank,dims);
+ amrfile->setType(type);
+
+ // read delta (spacing between grid points at toplevel grid)
+ attribnum=infid[0]->readAttributeInfo("delta",type,nelements);
+ infid[0]->readAttribute(attribnum,delta);
+ // read timestep size (in floating point realtime)
+ //attribnum=infid[0]->readAttributeInfo("",type,nelements);
+ //infid[0]->readAttribute(attribnum,timestep);
+ timestep=1.0;
+ // read origin (floating point origin).
+ attribnum=infid[0]->readAttributeInfo("origin",type,nelements);
+ infid[0]->readAttribute(attribnum,origin);
+
+ printf("Setting toplevel params origin[%lf,%lf,%lf],Timestep[%lf],delta[%lf,%lf,%lf],maxlevel[%u]\n",
+ origin[0],origin[1],origin[2],
+ timestep,
+ delta[0],delta[1],delta[2],
+ cmdln.maxlevel);
+ amrfile->setTopLevelParameters(rank,origin,delta,timestep,cmdln.maxlevel);
+ amrfile->setRefinement(1, // timerefinement of 1 because we currently
+ // don't save intermedite timesteps. In the future
+ // this would be 2 if you dump the intermediate
+ // timesteps
+ 2 // spatial refinement between levels is 2 in each
+ // dimension
+ );
+ // now we read all of the data from the input files
+ // and write them out into the AMR file
+ for(int n=0,ndatasets=infid[0]->nDatasets();n<ndatasets;n++){
+ printf("Reading step %u\n",n);
+ for(int level=0;level<cmdln.maxlevel;level++){
+ printf("\tReading Level %u\n",level);
+ char *data;
+ infid[level]->seek(n); // make everyone seek to the same place
+ amrfile->setTime(n);
+ // this is assuming that all levels are dumped at the same time
+ // rather than dumping them at the rate which they are computed.
+ // (eg. this is a snapshot of the entire heirarchy at each timestep).
+ // however this library can handle each level stepping at a different
+ // rate.
+ printf("Readinfo on %u\n",n);
+ infid[level]->readInfo(type,rank,dims); // read in the data from src file
+ printf("Info is type(%u) rank(%u) dims[%u,%u,%u]\n",
+ type,rank,dims[0],dims[1],dims[2]);
+ data = new char[IObase::nBytes(type,rank,dims)]; // allocate space
+ infid[level]->read(data); // read the actual data in
+ amrfile->setLevel(level); // set the level to write to in amr output file
+ // read the floating point origin attribute
+ attribnum=infid[level]->readAttributeInfo("origin",type,nelements);
+ infid[level]->readAttribute(attribnum,origin); // read it
+ // write out the data to the AMR file
+ amrfile->write(origin,dims,data); // write the data out
+ delete data; // free the data storage
+ }
+ }
+}
diff --git a/src/chunkSpeed.cc b/src/chunkSpeed.cc
new file mode 100644
index 0000000..757c7e1
--- /dev/null
+++ b/src/chunkSpeed.cc
@@ -0,0 +1,179 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IEEEIO.hh"
+#include "vatoi.hh"
+#include <sys/time.h>
+
+double MPI_Wtime(){
+ timeval tv;
+ gettimeofday(&tv);
+ return tv.tv_sec + tv.tv_usec/1000000.0l;
+}
+int StupidProcLayoutSeive(int np,int decomp[3]){
+ // Brute-Force method
+ // stupidly attempts all decomposition combinations
+ // and filters out unusable combinations.
+ // trys to select minimum surface area processor arrangement
+ int minarea = np*np*np; // impossibly high value
+ for(int i=1;i<=np;i++){
+ for(int j=1;i*j<=np;j++){
+ for(int k=1;i*j*k<=np;k++){
+ if(i*j*k!=np) continue;
+ int area = i+j+k; // area metric (optimizing this weakly minimizes surface area)
+ if(area<minarea) {
+ minarea=area;
+ decomp[0]=i;
+ decomp[1]=j;
+ decomp[2]=k;
+ }
+ }
+ }
+ }
+ return minarea;
+}
+
+class CommandLine {
+public:
+ enum DimType {Local,Global};
+ int verbose,dims[3],dimtype,np;
+ char *programname;
+ int bufsize;
+ void setDefaults(){
+ verbose=0;
+ dims[0]=dims[1]=dims[2]=20;
+ dimtype = Local;
+ np=1;
+ bufsize=0;
+ }
+ CommandLine(int argc,char *argv[]){
+ setDefaults();
+ parse(argc,argv);
+ }
+ void parse(int argc,char *argv[]){
+ programname=argv[0];
+ for(int i=1;i<argc;i++){
+ char *flag = argv[i],*val=argv[i+1];
+ if(*flag=='-') flag++;
+ else continue; // ignore non-flags
+ if(!strcmp(flag,"np")) {
+ if(++i<argc)
+ np = atoi(val);
+ }
+ if(*flag=='v') {verbose=1;}
+ else if(!strcmp(flag,"dimtype")){
+ if((++i<argc) && (!strcmp(val,"global") || !strcmp(val,"Global")))
+ dimtype=Global;
+ }
+ else if(!strcmp(flag,"dims")){
+ if(++i<argc) sscanf(val,"%u,%u,%u",dims,dims+1,dims+2);
+ }
+ else if(!strcmp(flag,"buffer")) {
+ if(++i<argc)
+ bufsize = vatoi(val);
+ }
+ else if(*flag=='h') usage();
+ }
+ }
+ void usage(){
+ printf("Usage: %s -np int <-verbose> <-dims int,int,int> <-dimtype global|local>",
+ programname);
+ printf("\tnp: Number of virtual processors (pretends to be parallel)\n");
+ printf("\tverbose: Opens file for reading after complete and prints all values.\n");
+ printf("\tdims: Set the dimensions of the dataset. By default this is per-cpu.\n");
+ printf("\t\tThis can be Global dimensions if you use -dimtype flag.\n");
+ printf("\t\tDefault is 20,20,20.\n");
+ printf("\tdimtype: \'global\' makes dimensions apply to the overall dataset\n");
+ printf("\t\tregardless of number of processors and \'local\' is per-processor.\n");
+ printf("\t\tThe default is per-processor.\n");
+ }
+ void printStatus(FILE *f=stdout){
+ fprintf(f,"%s: np=%u verbose=%u dims=%u,%u,%u dimtype=%s\n",
+ programname,np,verbose,
+ dims[0],dims[1],dims[2],
+ (dimtype==Local)?"Local":"Global");
+ }
+};
+
+int main(int argc,char *argv[]){
+ CommandLine cmdln(argc,argv);
+
+ typedef int Array[3];
+ //int origin[3],dims[3];
+ Array *vorigin,*vdims;
+ int *origin,*dims;
+ int proclayout[3],area;
+ area=StupidProcLayoutSeive(cmdln.np,proclayout);
+ cmdln.printStatus();
+ printf("Proclayout = %u : %u,%u,%u\n",area,
+ proclayout[0],proclayout[1],proclayout[2]);
+ vorigin = new Array[cmdln.np];
+ vdims = new Array[cmdln.np];
+ int i;
+ for(int p=0;p<cmdln.np;p++){
+ dims=vdims[p];
+ for(i=0;i<3;i++) dims[i]=cmdln.dims[i];
+ if(cmdln.dimtype==CommandLine::Global)
+ for(i=0;i<3;i++) dims[i]/=proclayout[i]; // create dims for layout computation
+ }
+ for(int p=0,k=0;k<proclayout[2];k++){
+ for(int j=0;j<proclayout[1];j++){
+ for(i=0;i<proclayout[0];i++,p++){
+ origin = vorigin[p];
+ dims = vdims[p];
+ // assumes same dims per process
+ origin[0]=dims[0]*i;
+ origin[1]=dims[1]*j;
+ origin[2]=dims[2]*k;
+ if(cmdln.dimtype==CommandLine::Global){
+ // compute remainder for globaldims
+ if(k==(proclayout[2]-1)) dims[2]=cmdln.dims[2]-dims[2]*(k);
+ if(j==(proclayout[1]-1)) dims[1]=cmdln.dims[1]-dims[1]*(j);
+ if(i==(proclayout[0]-1)) dims[0]=cmdln.dims[0]-dims[0]*(i);
+ }
+ }
+ }
+ }
+ int globaldims[3]={0,0,0};
+ for(int p=0;p<cmdln.np;p++){
+ dims=vdims[p];
+ origin=vorigin[p];
+ printf("PE(%u) origin{%u,%u,%u} localdims{%u,%u,%u}\n",
+ p,origin[0],origin[1],origin[2],
+ dims[0],dims[1],dims[2]);
+ for(i=0;i<3;i++)
+ if(globaldims[i]<origin[i]+dims[i])
+ globaldims[i]=origin[i]+dims[i];
+ }
+ printf("Globaldims=%u,%u,%u\n",globaldims[0],globaldims[1],globaldims[2]);
+ int size,maxsize;
+ // find maxsize
+ {
+ int p;
+ for(p=0,maxsize=0;p<cmdln.np;p++){
+ size = IObase::nElements(3,vdims[p]);
+ // Everybody allocates their own local data
+ if(size>maxsize) maxsize=size;
+ }
+ size = maxsize; // for convenience
+ }
+ float *data = new float[size];
+ for(i=0;i<size;i++) data[i] = (float)i;
+ IEEEIO *file = new IEEEIO("chunkdata.raw",IObase::Write);
+ if(cmdln.bufsize>0)
+ file->bufferOn(cmdln.bufsize);
+ double stime = MPI_Wtime();
+ for(i=0;i<3;i++){ // do this 3 times
+ file->reserveChunk(IObase::Float32,3,globaldims);
+ for(int p=0;p<cmdln.np;p++){
+ dims=vdims[p];
+ origin=vorigin[p];
+ file->writeChunk(origin,dims,data); // should be same as MPIO file contents
+ }
+ }
+ double etime = MPI_Wtime();
+ printf("Elapsed time to write=%lf\n",etime-stime);
+ printf("IO performance = %f Megabytes/sec\n",
+ IObase::nBytes(IObase::Float32,3,globaldims)/(1024*1024*(etime-stime)));
+ delete file;
+ delete data;
+}
diff --git a/src/convert2native.cc b/src/convert2native.cc
new file mode 100644
index 0000000..eb14dae
--- /dev/null
+++ b/src/convert2native.cc
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+int main(int argc,char *argv[]){
+ if(argc!=3){
+ printf("Correct usage is %s <infile> <outfile>\n",argv[0]);
+ exit(1); // failure code
+ }
+ IObase *infile=new IEEEIO(argv[1],IObase::Read);
+ if(!infile->isValid()){printf("cant read %s\n",argv[1]); exit(0);}
+ IObase *outfile=new IEEEIO(argv[2],IObase::Create);
+ if(!outfile->isValid()){
+ printf("cant write %s\n",argv[2]);
+ delete infile;
+ exit(0);
+ }
+ for(int i=0;i<infile->nDatasets();i++){
+ int rank,dims[5];
+ IObase::DataType type;
+ char *data;
+
+ fprintf(stderr,".%u",i);
+ infile->readInfo(type,rank,dims);
+ {
+ int j,sz;
+ for(j=0,sz=1;j<rank;j++) sz*=dims[j];
+ sz*=IObase::sizeOf(type);
+ data=new char[sz];
+ }
+ infile->read(data);
+ outfile->write(type,rank,dims,data);
+ delete data; // OK, so I'm not being smart about mem allocation here
+ for(int j=0;j<infile->nAttributes();j++){
+ char name[256]; // should be big enough
+ int length;
+ fprintf(stderr,"a");
+ infile->readAttributeInfo(j,name,type,length);
+ data = new char[length * IObase::sizeOf(type)];
+ infile->readAttribute(j,data);
+ outfile->writeAttribute(name,type,length,data);
+ delete data;
+ }
+ }
+ puts("");
+ delete infile;
+ delete outfile;
+ return 0; // success code
+}
diff --git a/src/copyperf.cc b/src/copyperf.cc
new file mode 100644
index 0000000..2f9950a
--- /dev/null
+++ b/src/copyperf.cc
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "vatoi.hh"
+#include "Timer.hh"
+
+int main(int argc,char *argv[]){
+ // compare speed of bcopy to character loop
+ if(argc<2){
+ puts("need to define buffer length");
+ exit(0);
+ }
+ long size = vatoi(argv[1]);
+ int ntimes = 1;
+ register int n;
+ register long i;
+ if(argc>2)
+ ntimes = vatoi(argv[2]);
+ printf("Buffer is %lu bytes %u times\n",size,ntimes);
+ Timer t1,t2;
+ char *dst = new char[size];
+ char *src = new char[size];
+ // prime the caches
+ for(i=0;i<size;i++){
+ src[i]=(char)(i%255);
+ dst[i]=0;
+ }
+ t1.start();
+ for(n=0;n<ntimes;n++)
+ for(i=0;i<size;i++)
+ dst[i]=src[i];
+ t1.stop();
+ t2.start();
+ for(n=0;n<ntimes;n++)
+ bcopy(src,dst,size);
+ t2.stop();
+ t1.print("Std copy timing: ");
+ t2.print("bcopy timing: ");
+ delete src;
+ delete dst;
+ return 1;
+}
diff --git a/src/ffio.c b/src/ffio.c
new file mode 100644
index 0000000..a8bfca3
--- /dev/null
+++ b/src/ffio.c
@@ -0,0 +1,108 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/times.h>
+#include <sys/statfs.h>
+#include <ffio.h>
+
+
+#define MINBLOCKSIZE (1*1024)
+#define MAXBLOCKSIZE (512*1024) /* multiple of MINBLOCKSIZE */
+
+#define MAXFILESIZE (128*1024*1024) /* multiple of MAXBLOCKSIZE */
+#define DATAFILE "bla"
+#define STATFILE "ffio.c"
+
+#define LAYERS "" /*bufa.bufsize=1024.num_buffers=1"*/
+
+#ifdef T3E
+#define S_IWRITE 00200
+#define S_IREAD 00400
+#endif
+
+
+int main (int argc, char *argv [])
+{
+ int i, blocksize, rank=3;
+ int outfile;
+ void *data;
+ struct tms starttime, stoptime;
+ double utime, stime;
+ int open_mode;
+ int cblks; /* size = cblks * 512 words */
+ long cbits;
+ char layers [256];
+ struct ffsw ffopens_status;
+#ifdef T3E
+ struct statfs statfs_info;
+#endif
+
+
+ data = (void *) calloc (sizeof (char), MAXBLOCKSIZE);
+ if (! data) {
+ printf ("Couldn't allocate enough memory\n");
+ exit (1);
+ }
+
+ /* set file open parameters */
+#ifdef T3E
+#if 0
+ if (statfs (STATFILE, &statfs_info, sizeof (statfs_info), 0) < 0) {
+ perror ("statfs() failed: ");
+ exit (1);
+ }
+ printf ("secondary partitions' bitmask: 0x%lx\n", statfs_info.f_secparts);
+
+ cbits = 0;
+ cbits |= (1 << 24);
+ cbits |= (1 << 06);
+ cbits |= (1 << 26);
+ cbits |= (1 << 23);
+#endif
+ open_mode = O_WRONLY | O_CREAT | O_PLACE;
+ cbits = 0;
+ cblks = 100;
+#else
+ open_mode = O_WRONLY | O_CREAT;
+ cbits = 0;
+ cblks = 0;
+#endif
+
+ for (blocksize = MINBLOCKSIZE; blocksize <= MAXBLOCKSIZE; blocksize *= 2) {
+
+ times (&starttime);
+
+ /* open the file */
+ outfile = ffopens (DATAFILE, open_mode, S_IWRITE | S_IREAD,
+ cbits, cblks, &ffopens_status, LAYERS);
+ if (! outfile) {
+ perror ("ffopens() failed: ");
+ exit (1);
+ }
+
+ /* system ("setf -n32768b:128b -c -p 24:06:23:26 bla");*/
+
+ /* write some data */
+ for (i = 0; i < MAXFILESIZE / blocksize; i++)
+ if (ffwrite (outfile, data, blocksize) < 0) {
+ perror ("ffwrite() failed: ");
+ exit (1);
+ }
+
+ /* close and remove the file */
+ ffclose (outfile);
+ remove (DATAFILE);
+
+ times (&stoptime);
+ utime = (stoptime.tms_utime -starttime.tms_utime) / (double) CLK_TCK;
+ stime = (stoptime.tms_stime -starttime.tms_stime) / (double) CLK_TCK;
+ printf ("blocksize [bytes]: %d\ttimes(u/s) [s]: %f %f\tbandwidth [MB/s]: %f\n",
+ blocksize, utime, stime,
+ MAXFILESIZE / (utime + stime) / (1024*1024));
+ }
+ free (data);
+
+ return (0);
+}
diff --git a/src/ioconvert.cc b/src/ioconvert.cc
new file mode 100644
index 0000000..c816df0
--- /dev/null
+++ b/src/ioconvert.cc
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "HDFIO.hh"
+
+char *programname;
+void usage(){
+ printf("Correct usage is %s <infile> <outfile> [-swapbytes]\n",programname);
+ puts("-swapbytes requests opposite of native byte-order for IEEEIO output");
+ puts("The default is to write IEEE files in native byte-order");
+ exit(1); // failure code
+}
+
+int main(int argc,char *argv[]){
+ programname=argv[0]; // for usage/error_exit routine
+ if(argc<3) usage();
+ int i,swap;
+ int sindex=0,dindex=0,findex=0;
+ IObase *infile,*outfile;
+ HDFIO *hdffile;
+ int hdfin=0;
+ for(i=1;i<argc;i++){
+ if(*(argv[i])=='-') findex=i;
+ else if(!sindex) sindex=i;
+ else dindex=i;
+ }
+ if(!sindex || !dindex || // doesn't have both infile and outfile specified
+ (findex && !strcmp("-help",argv[findex])) || // used help flag
+ (findex && strcmp("-swapbytes",argv[findex])) ) // invalid flag
+ usage();
+ if(findex && !strcmp("-swapbytes",argv[findex])) swap=1;
+ else swap=0;
+
+ // for the input file
+ char *s_ext=strrchr(argv[sindex],'.');
+ char *d_ext=strrchr(argv[dindex],'.');
+ if(s_ext && !strcmp(s_ext,".hdf")){
+ infile=hdffile=new HDFIO(argv[sindex],IObase::Read);
+ hdfin=1;
+ }
+ else // assume its raw
+ infile=new IEEEIO(argv[sindex],IObase::Read);
+ if(!infile->isValid()){
+ printf("cant read %s\n",argv[sindex]);
+ usage();
+ }
+
+ // for the outfile,
+ if(d_ext && !strcmp(d_ext,".hdf"))
+ outfile=new HDFIO(argv[dindex],IObase::Create);
+ else // assume its raw
+ outfile=new IEEEIO(argv[dindex],IObase::Create,swap); // swap only affects IEEEIO output
+ if(!outfile->isValid()){
+ printf("cant write %s\n",argv[dindex]);
+ delete infile;
+ usage();
+ }
+
+ // Now do the conversion
+ for(i=0;i<infile->nDatasets();i++){
+ int rank,dims[5];
+ IObase::DataType type;
+ char *data;
+ infile->seek(i);
+ if(hdfin && hdffile->isCoord()) continue; // skip coord vars
+ fprintf(stderr,".%u",i);
+ infile->readInfo(type,rank,dims);
+ {
+ int j,sz;
+ for(j=0,sz=1;j<rank;j++) sz*=dims[j];
+ sz*=IObase::sizeOf(type);
+ data=new char[sz];
+ }
+ infile->read(data);
+ outfile->write(type,rank,dims,data);
+ delete data; // OK, so I'm not being smart about mem allocation here
+ for(int j=0;j<infile->nAttributes();j++){
+ char name[256]; // should be big enough
+ int length;
+ fprintf(stderr,"a");
+ infile->readAttributeInfo(j,name,type,length);
+ data = new char[length * IObase::sizeOf(type)];
+ infile->readAttribute(j,data);
+ outfile->writeAttribute(name,type,length,data);
+ delete data;
+ }
+ }
+ puts("");
+ delete outfile;
+ // delete infile;
+ return 0; // success code
+}
diff --git a/src/ioinfo.cc b/src/ioinfo.cc
new file mode 100644
index 0000000..91e487d
--- /dev/null
+++ b/src/ioinfo.cc
@@ -0,0 +1,281 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "Arch.h"
+#include "IO.hh"
+#include "IEEEIO.hh"
+
+#ifdef WITH_HDF4
+#include "HDFIO.hh"
+#endif
+#ifdef WITH_HDF5
+#include "H5IO.hh"
+#endif
+
+struct CmdlnParams {
+ char *programname;
+ char *filename,*filetype;
+ int showdatasetinfo,showannotationinfo,showattribinfo;
+ int showdatamax,showannotationmax,showattribmax;
+ int showdatastats,showattribstats;
+
+ void setDefaults(){
+ programname="";
+ filename=0;
+ filetype=0;
+ showdatasetinfo=1;
+ showannotationinfo=0;
+ showattribinfo=0;
+ showdatamax=0;
+ showannotationmax=0;
+ showattribmax=0;
+ showdatastats=0;
+ showattribstats=0;
+ }
+
+ CmdlnParams(){
+ setDefaults();
+ }
+
+ CmdlnParams(int argc,char *argv[]){
+ setDefaults();
+ parse(argc,argv);
+ }
+
+ void parse(int argc,char *argv[]){
+ programname=argv[0];
+ for(int i=1;i<argc;i++){
+ char *str=argv[i];
+ if(*str=='-'){
+ char *val=argv[i+1];
+ str++;
+ //printf("read option[%u]=[%s]\n",i,str);
+ if(!strcmp(str,"showdata")) {
+ puts("option -showdata:\tShow first 10 data entries");
+ showdatamax=10;}
+ else if(!strcmp(str,"hidedata")) {
+ puts("option -hidedata:\tDon't show data");
+ showdatamax=0; }
+ else if(!strncmp(str,"showann",7)&&
+ strstr(str,"data")) {
+ puts("option -showanndata:\tShow annotation text (max of 10 chars)");
+ showannotationmax=10; showannotationinfo=1; }
+ else if(!strncmp(str,"hideann",7)&&
+ strstr(str,"data")) {
+ puts("option -hideanndata:\tSupress printing of annotation text");
+ showannotationmax=0; }
+ else if(!strncmp(str,"showatt",7) &&
+ strstr(str,"data")) {
+ puts("option -showattdata:\tShow first 10 elements of attribute data");
+ showattribmax=10;
+ showattribinfo=1;}
+ else if(!strncmp(str,"hideatt",7)&&
+ strstr(str,"data")) {
+ puts("option -hideatt:\tHide attribute info");
+ showattribmax=0; }
+ else if(!strncmp(str,"showann",7)&&
+ strstr(str,"info")) {showannotationinfo=1;}
+ else if(!strncmp(str,"hideann",7)&&
+ strstr(str,"info")) {showannotationinfo=0; }
+ else if(!strncmp(str,"showatt",7) &&
+ strstr(str,"info")) {
+ puts("option -showattinfo:\tShow attribute info (name,type,length)");
+ showattribinfo=1; }
+ else if(!strncmp(str,"hideatt",7) &&
+ strstr(str,"info")) {showattribinfo=0; }
+ else if(!strcmp(str,"file")) {
+ filename=val;
+ i++;
+ filetype=strrchr(str,'.') + 1;
+ printf("option -file %s: Read file named [%s]\n",filename,filetype);
+ }
+ else if(!strcmp(str,"type")) {filetype=val; i++;}
+ }
+ else { // its probably a filename
+ filename=str;
+ filetype=strrchr(str,'.');
+ if(filetype) filetype++; // skip the '.'
+ else filetype = "";
+ }
+ }
+ }
+};
+
+char *Typename(IObase::DataType datatype){
+ char *typestring;
+ switch(datatype){
+ case IObase::Int8:
+ typestring="Int8";
+ break;
+ case IObase::Int16:
+ typestring="Int16";
+ break;
+ case IObase::Int32:
+ typestring="Int32";
+ break;
+ case IObase::Int64:
+ typestring="Int64";
+ break;
+ case IObase::Float32:
+ typestring="Float32";
+ break;
+ case IObase::Float64:
+ typestring="Float64";
+ break;
+ case IObase::Char8:
+ typestring="String";
+ break;
+ default:
+ typestring="<Unknown>";
+ break;
+ }
+ return typestring;
+}
+
+int main(int argc,char *argv[]){
+ CmdlnParams cmdln(argc,argv); // parse commandline parameters & flags
+ if(!cmdln.filename) {
+ puts("HEY! Need a filename there buddy!");
+ exit(1); // failure code
+ }
+
+ int i;
+ IObase *infile = NULL;
+
+ // Figure out what kind of file to open as
+#ifdef WITH_HDF5
+ if(!strcmp(cmdln.filetype,"h5")){
+ infile = new H5IO(cmdln.filename,IObase::Read);
+ }
+#endif
+#ifdef WITH_HDF4
+ if(!strcmp(cmdln.filetype,"hdf")){
+ infile = new HDFIO(cmdln.filename,IObase::Read);
+ }
+#endif
+ if(!strcmp(cmdln.filetype,"raw") || !strcmp(cmdln.filetype,"ieee")){
+ infile = new IEEEIO(cmdln.filename,IObase::Read);
+ }
+ if(!infile){
+ puts("I don't recognize that type of file, but I'll try to open as ieee");
+ cmdln.filetype="ieee";
+ infile = new IEEEIO(cmdln.filename,IObase::Read);
+ }
+ if(!infile->isValid()){
+ printf("%s: The file %s is not a valid %s file... sorry\n",
+ cmdln.programname,cmdln.filename,cmdln.filetype);
+ exit(1);
+ }
+ int ndatasets=infile->nDatasets();
+ printf("Number of datasets=%d\n",ndatasets);
+ puts ("===========================");
+
+ // OK... now its time for da main event loop....
+ for(i=0;i<ndatasets;i++){
+ int j;
+ int rank,dims[5];
+ IObase::DataType datatype;
+
+ printf("Dataset[%u]\n",i);
+ puts("--------------");
+ infile->readInfo(datatype,rank,dims);
+
+ printf("Datatype=%s Rank=%u Dims=",Typename(datatype),rank);
+ for(j=0;j<rank-1;j++)
+ printf("%u,",dims[j]);
+ printf("%u\n",dims[rank-1]);
+#if 0 // blow this away for now
+ if(cmdln.showdatamax){// || cmdln.showdatastats (not implemented yet)
+ // must allocate memory for it
+ void *buffer=0;
+ int *idims=new int[rank];
+ for(int dim=0;dim<rank;dim++) idims[dim]=0;
+ idim[0]=showdatamax;
+ if(IObase::sizeOf(datatype)>0 && dims[0]>0)
+ buffer=new char[idims[0] * IObase::sizeOf(datatype)];
+ //infile->readChunk(buffer);
+ delete buffer;
+ delete idims;
+ }
+#endif
+ int nattribs=infile->nAttributes();
+ int nannotations=infile->nAnnotations();
+ printf("Annotations: %u\n",nannotations);
+ printf("Attributes: %u\n",nattribs);
+
+ if(cmdln.showattribinfo){
+ for(j=0;j<nattribs;j++){
+ char attribname[64];
+ Long length;
+ infile->readAttributeInfo(j,attribname,datatype,length);
+ printf("\tAttribute[%u] Name=%s Type=%s Length=%u\n",
+ j,attribname,Typename(datatype),length);
+ if(cmdln.showattribmax || cmdln.showattribstats){
+ //printf("Length of Attribute=%u for total bytes=%u\n",length,IObase::sizeOf(datatype));
+ void *dataptr;
+ dataptr=0;
+ if(IObase::sizeOf(datatype)>0 && length>0)
+ dataptr=new char[length * IObase::sizeOf(datatype)];
+ else {
+ //puts("no data to display");
+ continue; // no data to display
+ }
+
+ infile->readAttribute(j,dataptr);
+ switch(datatype){
+ case IObase::Char8:{
+ char *d=(char*)dataptr;
+ d[length]='\0';
+ //puts("show char data");
+ printf("\t%s string[%u]:= %s\n",attribname,length,d);
+ }break;
+ case IObase::Int8:
+ case IObase::uInt8:{
+ char *d=(char*)dataptr;
+ for(int k=0;k<cmdln.showattribmax && k<length;k++)
+ if(d[k]>=0x20 && d[k]<=0x7e)
+ printf("\t%s[%u]:=%c\n",attribname,k,d[k]);
+ else {
+ int intchar=(unsigned int)(d[k]);
+ printf("\t%s[%u]:=%u\n",attribname,k,intchar);
+ }
+ }break;
+ case IObase::Int16:{
+ short *d=(short*)dataptr;
+ for(int k=0;k<cmdln.showattribmax && k<length;k++)
+ printf("\t%s[%u]:=%u\n",attribname,k,d[k]);
+ }break;
+ case IObase::Int32:{
+ int *d=(int*)dataptr;
+ for(int k=0;k<cmdln.showattribmax && k<length;k++)
+ printf("\t%s[%u]:=%u\n",attribname,k,d[k]);
+ }break;
+ case IObase::Int64:{
+ Long8 *d=(Long8*)dataptr;
+ for(int k=0;k<cmdln.showattribmax && k<length;k++)
+ printf("\t%s[%u]:=%lu\n",attribname,k,d[k]);
+ }break;
+ case IObase::Float32:{
+ float *d=(float*)dataptr;
+ for(int k=0;k<cmdln.showattribmax && k<length;k++)
+ printf("\t%s[%u]:=%f\n",attribname,k,d[k]);
+ }break;
+ case IObase::Float64:{
+ double *d=(double*)dataptr;
+ for(int k=0;k<cmdln.showattribmax && k<length;k++)
+ printf("\t%s[%u]:=%f\n",attribname,k,d[k]);
+ }break;
+ default:
+ puts("-----<nil>-----");
+ break;
+ }
+ if(dataptr)
+ delete dataptr;
+ }
+ }
+ }
+ }
+ puts("Closing file");
+ delete infile;
+ puts("***done");
+ return 0;
+}
diff --git a/src/rawSpeed.cc b/src/rawSpeed.cc
new file mode 100644
index 0000000..9f7e4b0
--- /dev/null
+++ b/src/rawSpeed.cc
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IEEEIO.hh"
+#include "vatoi.hh"
+#include <sys/time.h>
+double MPI_Wtime(){
+ timeval tv;
+ gettimeofday(&tv,0);
+ return tv.tv_sec + tv.tv_usec/1000000.0l;
+}
+
+class CommandLine {
+public:
+ int dims[3];
+ char *programname;
+ int bufsize;
+ int ntrials;
+ void setDefaults(){
+ dims[0]=dims[1]=dims[2]=128;
+ bufsize=0;
+ ntrials=40;
+ }
+ CommandLine(int argc,char *argv[]){
+ setDefaults();
+ parse(argc,argv);
+ }
+ void parse(int argc,char *argv[]){
+ programname=argv[0];
+ for(int i=1;i<argc;i++){
+ char *flag = argv[i],*val=argv[i+1];
+ if(*flag=='-') flag++;
+ else continue; // ignore non-flags
+ if(!strcmp(flag,"dims")){
+ if(++i<argc) sscanf(val,"%u,%u,%u",dims,dims+1,dims+2);
+ }
+ else if(!strcmp(flag,"buffer")) {
+ if(++i<argc)
+ bufsize = vatoi(val);
+ }
+ else if(*flag=='n') {
+ ntrials=atoi(val);
+ i++;
+ }
+ else if(*flag=='h') usage();
+ }
+ }
+ void usage(){
+ printf("Usage: %s <-dims int,int,int> -n <ntrials>\n",
+ programname);
+ printf("\tdims: Set the dimensions of the dataset.\n");
+ printf("\tn: Set number of trials of writing the dataset.\n");
+ printf("\tbuffer: Set buffer cache size in bytes.\n");
+ }
+ void printStatus(FILE *f=stdout){
+ fprintf(f,"%s: dims=%u,%u,%u\n",
+ programname,
+ dims[0],dims[1],dims[2]);
+ }
+};
+
+int main(int argc,char *argv[]){
+ CommandLine cmdln(argc,argv);
+
+ int size=IObase::nElements(3,cmdln.dims);
+ int i;
+ float *data = new float[size];
+ for(i=0;i<size;i++) data[i] = (float)i;
+ IEEEIO *file = new IEEEIO("rawdata.raw",IObase::Write);
+ if(cmdln.bufsize>0) file->bufferOn(cmdln.bufsize);
+ double stime = MPI_Wtime();
+ for(i=0;i<cmdln.ntrials;i++){ // do this 40 times
+ file->reserveStream(IObase::Float32,3,cmdln.dims);
+ file->writeStream(data,size);
+ }
+ if(file) delete file; // make sure the file is deleted
+ double etime = MPI_Wtime();
+ printf("Elapsed time to write=%lf\n",etime-stime);
+ printf("IO performance = %f Megabytes/sec\n",
+ (float)(IObase::nBytes(IObase::Float32,3,cmdln.dims))*(float)(cmdln.ntrials)/(1024*1024*(etime-stime)));
+ delete data;
+}
+
+
diff --git a/src/testBigWriter.cc b/src/testBigWriter.cc
new file mode 100644
index 0000000..7f71555
--- /dev/null
+++ b/src/testBigWriter.cc
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "Reader.hh"
+#include "Writer.hh"
+#include "Timer.hh"
+// #include "vatoi.hh"
+
+int main(int argc,char *argv[]){
+ float *data = new float[256*256*256];
+ float *buffer = data;
+ double origin[3]={0,0,0};
+ double dx[3]={0.25,0.25,0.25};
+ int rank=3;
+ int dims[3]={256,256,256};
+ //int dims[3]={1,1,1};
+ int ngigs = 5;
+ Timer t;
+ char label[31];
+ Writer *writer;
+ IEEEIO *iefile;
+ IObase *outfile = iefile = new IEEEIO("data3d.raw",IObase::Create);
+ //iefile->bufferOn(128*1024); // set up a 128k write buffer
+ if(argc>=2) ngigs=atoi(argv[1]);
+ int ndatawrites = (int)(((double)ngigs*1024.0L*1024.0L*1024.0L) / (256.0L*256.0L*256.0L*4.0L));
+
+ printf("==========================================\n");
+ printf("ngigs=%u ndatawrites=%u each of size %f megs\n",
+ ngigs,ndatawrites,256.0*256.0*256.0*4.0/(1024*1024));
+ writer = new Writer(*outfile);
+ writer->setParams(rank,dims,IObase::Float32,origin,dx);
+ // data[0]=1.0;
+ int i;
+ for(i=0;i<256*256*256;i++)
+ data[i]=(float)i;
+ t.start();
+ for(i=0;i<ndatawrites;i++){
+ float s,u,r;
+ writer->setDims(dims);
+ writer->write(data);
+ //outfile->pause();
+ //puts("paused");
+ //outfile->resume();
+ //puts("resumed");
+ t.elapsedTimeSeconds(s,u,r);
+ sprintf(label,"mylabel.%04u",i);
+ printf("Cycle[%u] label[%s] %fGigs %fMegs/sec\n",
+ i,label,
+ (float)(((double)i*256.0L*256.0L*256.0L*4.0L)/(1024.0L*1024.0L*1024.0L)),
+ (float)(((double)i*256.0L*256.0L*256.0L*4.0L)/(1024.0L*1024.0L))/r);
+ //puts("after mylabel");
+ outfile->writeAttribute("Mylabel",IObase::Char,31,label);
+ }
+
+ /* puts("\tnow seek to end\n");
+ outfile->seek(outfile->nDatasets());
+
+ puts("\treserve a chunk");
+ outfile->reserveChunk(IObase::Float32,rank,dims);
+ puts("\tWrite a stream fo 40x40x40");
+ outfile->writeStream(data,40*40*20);
+ puts("\tWrite the next stream of 40x40x20");
+ outfile->writeStream(data+40*40*20,40*40*20);*/
+ puts("\t writer done!!\n\n");
+
+ delete writer;
+ delete outfile;
+ /*
+ puts("Start appending");
+ outfile = new IEEEIO("data3d.raw",IObase::Append);
+ printf("Isvalid? %d\n",outfile->isValid());
+
+ outfile->reserveStream(IObase::Float32,rank,dims);
+ outfile->writeStream(data,40*40*20);
+ outfile->writeStream(data+40*40*20,40*40*20);
+ printf("nrecords=%u\n",outfile->nDatasets());
+ delete outfile;
+
+ puts("Done appending : Reopen for reading.");
+ */
+ //exit(0);
+ puts("start reader***************************");
+ Reader *reader;
+ IObase *infile = new IEEEIO("data3d.raw",IObase::Read);
+ //printf("nrecords=%u\n",outfile->nDatasets());
+ // reader = new Reader(*infile);
+ int ndatasets=infile->nDatasets();
+ printf("Number of datasets=%d\n",ndatasets);
+ t.reset();
+ t.start();
+ for(i=0;i<ndatasets;i++){
+ int j,r;
+ // float buffer[40*40*40];
+ for(j=0;j<40*40*40;j++) buffer[j]=0;
+ int rank,dims[3];
+ float s,u,rl;
+ IObase::DataType datatype;
+
+ printf("Cycle %u\n",i);
+ infile->readInfo(datatype,rank,dims);
+ printf("Data info dt=%u,rank=%u,dims=%u,%u,%u\n",
+ (int)(datatype),rank,dims[0],dims[1],dims[2]);
+ r=infile->read(buffer);
+ // r=infile->readStream(buffer,dims[0]*dims[1]*dims[2]);
+ t.elapsedTimeSeconds(s,u,rl);
+ printf("\tread %d elements\n",r);
+ printf("\tReadDataset[%u] %fGigs %fMegs/sec\n",
+ i,
+ (float)(((double)i*256.0L*256.0L*256.0L*4.0L)/(1024.0L*1024.0L*1024.0L)),
+ (float)(((double)i*256.0L*256.0L*256.0L*4.0L)/(1024.0L*1024.0L))/rl);
+ for(j=0;j<10;j++)
+ printf("Data[%u]=%f\n",j,buffer[j]);
+ puts("***done printing data");
+ int nattribs=infile->nAttributes();
+ printf("Number of Attributes=%d\n",nattribs);
+ for(j=0;j<nattribs;j++){
+ char attribname[64];
+ Long length;
+ infile->readAttributeInfo(j,attribname,datatype,length);
+ printf("\tAttribute[%u] name=%s\n",j,attribname);
+ switch(datatype){
+ case IObase::Float32:{
+ //float buf[5];
+ puts("Float");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::Float64:{
+ double buf[5];
+ puts("Double");
+ printf("length=%u\n",length);
+ infile->readAttribute(j,buf);
+ for(int k=0;k<length;k++)
+ printf("\tElement[%u]=%lf\n",k,buf[k]);
+ } break;
+ case IObase::Int32:{
+ //int buf[5];
+ puts("Integer");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::String:{
+ char buf[128];
+ puts("String");
+ infile->readAttribute(j,buf);
+ printf("len=%u val=[%s]\n",length,buf);
+ break;
+ }
+ default:
+ printf("unknown type %d\n",(int)datatype);
+ break;
+ }
+ }
+ }
+ //delete reader;
+ delete infile;
+ puts("done");
+ return 0;
+}
diff --git a/src/testChunkWriter.cc b/src/testChunkWriter.cc
new file mode 100644
index 0000000..e35c159
--- /dev/null
+++ b/src/testChunkWriter.cc
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+
+int main(int argc,char *argv[]){
+ float data[40*40*40];
+ double origin[3]={0,0,0};
+ double dx[3]={0.25,0.25,0.25};
+ int rank=3;
+ int dims[3]={40,40,40};
+ IObase *outfile = new IEEEIO("data3d.raw",IObase::Create);
+ int i,k;
+ for(i=0;i<40*40*40;i++)
+ data[i]=(float)i;
+
+ puts("reserving chunk for z-slicing");
+ outfile->reserveChunk(IObase::Float32,rank,dims);
+ for(i=0;i<40;i+=10){
+ int cdims[3]={40,40,10};
+ int corigin[3]={0,0,0};
+ corigin[2]=i;
+ outfile->writeChunk(cdims,corigin,data);
+ }
+
+ puts("reserving chunk for y-slicing");
+ outfile->reserveChunk(IObase::Float32,rank,dims);
+ for(i=0;i<40;i+=10){
+ int cdims[3]={40,10,40};
+ int corigin[3]={0,0,0};
+ corigin[1]=i;
+ outfile->writeChunk(cdims,corigin,data);
+ }
+
+ puts("reserving chunk for x-slicing");
+ outfile->reserveChunk(IObase::Float32,rank,dims);
+ for(i=0;i<40;i+=10){
+ int cdims[3]={10,40,40};
+ int corigin[3]={0,0,0};
+ corigin[0]=i;
+ outfile->writeChunk(cdims,corigin,data);
+ }
+
+
+ puts("reserving chunk for domain-block chunking (10x10x10 blocks)");
+ for(int x=0;x<40;x+=10){
+ int cdims[3]={10,10,10};
+ for(int y=0;y<40;y+=10){
+ for(int z=0;z<40;z+=10){
+ int corigin[3];
+ corigin[0]=x;
+ corigin[1]=y;
+ corigin[2]=z;
+ outfile->writeChunk(cdims,corigin,data);
+ }
+ }
+ }
+
+ puts("done... deleting");
+ delete outfile;
+ puts("done");
+ return 1;
+}
+
diff --git a/src/testSockread.cc b/src/testSockread.cc
new file mode 100644
index 0000000..723d1a8
--- /dev/null
+++ b/src/testSockread.cc
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "SockIOreader.hh"
+
+void main(int argc,char *argv[]){
+ // Open a SockIOreader using 512k TCP windowsize
+ SockIOreader *reader= new SockIOreader("scratch.raw",7052,512*1024);
+ puts("begin\n");
+ while(reader->nDatasets()<4){
+ int ndsets=reader->nDatasets();
+ fprintf(stderr,"reader->nDatasets()=%u\r",ndsets);
+ }
+ // now go through and verify each dataset
+ for(int i=0;i<4;i++){
+ float buffer[16*16*16];
+ int rank,dims[3];
+ IObase::DataType type;
+ reader->seek(i); // seek to dataset
+ reader->readInfo(type,rank,dims);
+ printf("Dataset[%u]: Rank=%u Dims={%u,%u,%u}\n",i,rank,dims[0],dims[1],dims[2]);
+ reader->read(buffer);
+ puts("Print out dataset info to verify correctness");
+ for(int j=0;j<IObase::nElements(rank,dims);j+=100){
+ float f=(float)j;
+ printf("Data[%u]=%f\n",j,buffer[j]);
+ }
+ }
+ puts("\ndone\n");
+}
diff --git a/src/testSockwrite.cc b/src/testSockwrite.cc
new file mode 100644
index 0000000..6f2e381
--- /dev/null
+++ b/src/testSockwrite.cc
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "SockIOwriter.hh"
+
+void main(int argc,char *argv[]){
+ // Open a SockIOwriter using 512k TCP windowsize
+ SockIOwriter *writer= new SockIOwriter("localhost",7052,512*1024);
+ puts("begin\n");
+ float data[16*16*16]; // send 64^3 data for performance tests
+ int rank=3;
+ int dims[3]={16,16,16};
+
+ for(int i=0;i<16*16*16;i++) data[i]=(float)i;
+ for(i=0;i<4;i++){
+ fprintf(stderr,"Writing Dataset %u\n",i);
+ fprintf(stderr,"Wrote %u characters\n",
+ writer->write(IObase::Float32,rank,dims,data));
+ fprintf(stderr,"\tWrote Dataset %u\n",i);
+ sleep(1);
+ }
+}
diff --git a/src/testWriter.cc b/src/testWriter.cc
new file mode 100644
index 0000000..d5c4ed2
--- /dev/null
+++ b/src/testWriter.cc
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+// #include "Reader.hh"
+#include "Writer.hh"
+
+int main(int argc,char *argv[]){
+ float data[40*40*40];
+ double origin[3]={0,0,0};
+ double dx[3]={0.25,0.25,0.25};
+ int i,rank=3;
+ int dims[3]={40,40,40};
+ Writer *writer;
+ IObase *outfile = new IEEEIO("data3d.raw",IObase::Create);
+ writer = new Writer(*outfile);
+ writer->setParams(rank,dims,IObase::Float32,origin,dx);
+ // data[0]=1.0;
+ for(i=0;i<40*40*40;i++)
+ data[i]=(float)i;
+ for(i=0;i<2;i++)
+ writer->write(data);
+
+ delete writer;
+ delete outfile;
+#if 0
+ Reader *reader;
+ IObase *infile = new IEEEIO("data3d.raw",IObase::Read);
+ reader = new Reader(*infile);
+
+ for(i=0;i<reader->ndatasets;i++){
+ int j;
+ float buffer[40*40*40];
+ for(j=0;j<40*40*40;j++) buffer[j]=0;
+ (*reader)[i].read(buffer);
+ for(j=0;j<10;j++)
+ printf("Data[%u]=%f\n",j,buffer[j]);
+ puts("***done printing data");
+ for(j=0;j<(*reader)[i].nattributes;j++){
+ //IOdataset ds=(*reader)[i];
+ //char c1,c2;
+ //int attrlen;
+ //printf("\tnattribs=%u\n",ds.nattributes);
+ //c1=ds.attribute[j].name[0];
+ //c2=ds.attribute[j].name[0];
+ //printf("\tFirst two chars of name [%c][%c]\n",c1,c2);
+ //attrlen=ds.attribute[j].nelements;
+ printf("\tAttribute[%u] name=%s\n",j,(*reader)[i].attribute[j].name);
+ long length=(*reader)[i].attribute[j].nelements;
+ switch((*reader)[i].attribute[j].datatype){
+ case IObase::Float32:{
+ //float buf[5];
+ puts("Float");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::Float64:{
+ double buf[5];
+ puts("Double");
+ printf("length=%u\n",length);
+ (*reader)[i].attribute[j].read(buf);
+ for(int k=0;k<length;k++)
+ printf("\tElement[%u]=%lf\n",k,buf[k]);
+ } break;
+ case IObase::Int32:{
+ //int buf[5];
+ puts("Integer");
+ printf("length=%u\n",length);
+ } break;
+ default:
+ puts("unknown type");
+ break;
+ }
+ }
+ }
+ delete reader;
+ delete infile;
+#endif
+ puts("done");
+ return 0;
+}
diff --git a/src/testallocation.cc b/src/testallocation.cc
new file mode 100644
index 0000000..75bc48c
--- /dev/null
+++ b/src/testallocation.cc
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FlexArrayTmpl.H"
+
+struct InnerContainer {
+ int num;
+
+ InnerContainer(InnerContainer &src){
+ this->num=src.num;
+ }
+ InnerContainer &operator=(InnerContainer &src){
+ if(this==&src) return src;
+ this->num=src.num;
+ return *this;
+ }
+ InnerContainer(){
+ printf("\tNew InnerContainer %lu\n",(unsigned long)this);
+ num=-1; /* uninitialized */
+ }
+ ~InnerContainer(){
+ printf("\tInnerContainer[%lu] destruct %d\n",(unsigned long)this,num);
+ }
+};
+
+struct OuterContainer {
+ int num;
+ FlexArray<InnerContainer> inner;
+ OuterContainer(OuterContainer &src){
+ this->num=src.num;
+ this->inner=src.inner;
+ }
+ OuterContainer &operator=(OuterContainer &src){
+ if(this==&src) return src;
+ this->num=src.num;
+ this->inner=src.inner;
+ return *this;
+ }
+ OuterContainer(){
+ printf("New OuterContainer %lu\n",(unsigned long)this);
+ num=-1;
+ }
+ ~OuterContainer(){
+ printf("OuterContainer[%lu] destruct %d innersize=%u\n",
+ (unsigned long)this,num,inner.getSize());
+ }
+};
+
+struct Container {
+ FlexArray<OuterContainer> outer;
+
+ Container(int sz){
+ int i,j;
+ outer.setSize(sz);
+ for(i=0;i<sz;i++){
+ OuterContainer o;
+ printf("***Outer create [%u]\n",i);
+ o.num=i;
+ o.inner.setSize(sz);
+ for(j=0;j<sz;j++){
+ printf("\t***Inner create [%u]\n",j);
+ (o.inner[j]).num=j;
+ }
+ outer[i]=o;
+ }
+ }
+
+ ~Container(){
+ printf("Container Destructor outersize=%u\n",outer.getSize());
+ }
+};
+
+void main(int argc,char *argv[]){
+ Container *c;
+ puts("new container");
+ c = new Container(3);
+ puts("CREATED--------(now destroy)");
+ delete c;
+ puts("DONE");
+}
+
diff --git a/src/testhdfReader.cc b/src/testhdfReader.cc
new file mode 100644
index 0000000..5c4b74e
--- /dev/null
+++ b/src/testhdfReader.cc
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IO.hh"
+#include "HDFIO.hh"
+
+int main(int argc,char *argv[]){
+ float data[40*40*40];
+ double origin[3]={0,0,0};
+ double dx[3]={0.25,0.25,0.25};
+ int i;
+ int rank=3;
+ int dims[3]={40,40,40};
+ IObase *infile;
+ if(argc>1)
+ infile = new HDFIO(argv[1],IObase::Read);
+ else
+ infile = new HDFIO("data3d.raw",IObase::Read);
+ // reader = new Reader(*infile);
+ int ndatasets=infile->nDatasets();
+ printf("Number of datasets=%d\n",ndatasets);
+ for(i=0;i<ndatasets;i++){
+ int j;
+ float buffer[40*40*40];
+ for(j=0;j<40*40*40;j++) buffer[j]=0;
+ int rank,dims[3];
+ IObase::DataType datatype;
+
+ printf("Cycle %u\n",i);
+ infile->readInfo(datatype,rank,dims);
+ printf("Data info dt=%u,rank=%u,dims=%u,%u,%u\n",
+ (int)(datatype),rank,dims[0],dims[1],dims[2]);
+ infile->read(buffer);
+ for(j=0;j<10;j++)
+ printf("Data[%u]=%f\n",j,buffer[j]);
+ puts("***done printing data");
+ int nattribs=infile->nAttributes();
+ printf("Number of Attributes=%d\n",nattribs);
+ for(j=0;j<nattribs;j++){
+ char attribname[64];
+ int length;
+ infile->readAttributeInfo(j,attribname,datatype,length);
+ printf("\tAttribute[%u] name=%s\n",j,attribname);
+ switch(datatype){
+ case IObase::Float32:{
+ //float buf[5];
+ puts("Float");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::Float64:{
+ double buf[5];
+ puts("Double");
+ printf("length=%u\n",length);
+ infile->readAttribute(j,buf);
+ for(int k=0;k<length;k++)
+ printf("\tElement[%u]=%lf\n",k,buf[k]);
+ } break;
+ case IObase::Int32:{
+ //int buf[5];
+ puts("Integer");
+ printf("length=%u\n",length);
+ } break;
+ default:
+ puts("unknown type");
+ break;
+ }
+ }
+ }
+ //delete reader;
+ delete infile;
+ puts("done");
+ return 0;
+}
diff --git a/src/testio.cc b/src/testio.cc
new file mode 100644
index 0000000..cd71601
--- /dev/null
+++ b/src/testio.cc
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IEEEIO.hh"
+
+void main(int argc,char *argv[]){
+ int i;
+ float bogusdata[16*16];
+ //float attribdata[128];
+ int bogusdims[2]={16,16};
+ int bogusrank=2;
+ IO *outfile = new IEEEIO("testfile.raw",IO::Create);
+ if(!outfile->isValid()){
+ perror("IO open failed");
+ exit(0);
+ }
+ else puts("Writing File");
+ for(i=0;i<16*16;i++)
+ bogusdata[i]=(float)i;
+ char *string="I am annotation[0]";
+ char *name="attrib0";
+ for(i=0;i<5;i++){
+ outfile->write(IO::Float32,bogusrank,bogusdims,bogusdata);
+ (string[16])='0';
+ for(int j=0;j<i;j++,(string[16])='0'+j)
+ outfile->writeAnnotation(string);
+ name[6]='0';
+ //if(i<4)
+ for(j=0;j<i;j++,name[6]='0'+j)
+ outfile->writeAttribute(name,IO::Float32,2*j,bogusdata+j);
+
+ }
+ delete outfile;
+ puts("##################REOPEN#######################");
+ outfile = new IEEEIO("testfile.raw",IO::Read);
+
+ if(!outfile->isValid()){
+ perror("IO open failed");
+ exit(0);
+ }
+ for(i=0;i<10;i++){
+ IO::DataType dt;
+ int idt;
+ int rank,dims[3];
+ for(int j=0;j<16*16;j++) bogusdata[j]=0.0; // clear bogusdata
+ if(outfile->readInfo(dt,rank,dims)<=0){
+ puts("***********************end****************");
+ break;
+ }
+ outfile->read(bogusdata);
+ printf("----------------------Data Read[%u]-------------------\n",i);
+ idt=dt;
+ printf("\tDatatype=%u rank=%u\n",idt,rank);
+ for(j=0;j<3;j++) printf("\tDims[%u]=%u\n",j,dims[j]);
+ puts("+++++++Annotations");
+ for(j=0;j<outfile->nAnnotations();j++){
+ char buffer[128];
+ outfile->readAnnotation(j,buffer,sizeof(buffer));
+ printf("\tAnnotation[%u]=[%s]\n",j,buffer);
+ }
+ puts("");
+ for(j=0;j<16*16;j++) printf("data[%4u]=%f\n",j,bogusdata[j]);
+ }
+ printf("Seek=%d\n",outfile->seek(3));
+ for(i=0;i<10;i++){
+ IO::DataType dt;
+ int idt;
+ int rank,dims[3];
+ for(int j=0;j<16*16;j++) bogusdata[j]=0.0; // clear bogusdata
+ if(outfile->readInfo(dt,rank,dims)<=0){
+ puts("***********************end****************");
+ break;
+ }
+ outfile->read(bogusdata);
+ printf("----------------------Data Read[%u]-------------------\n",i);
+ idt=dt;
+ printf("\tDatatype=%u rank=%u\n",idt,rank);
+ for(j=0;j<3;j++) printf("\tDims[%u]=%u\n",j,dims[j]);
+ puts("+++++++Annotations");
+ for(j=0;j<outfile->nAnnotations();j++){
+ char buffer[128];
+ outfile->readAnnotation(j,buffer,sizeof(buffer));
+ printf("\tAnnotation[%u]=[%s]\n",j,buffer);
+ }
+ puts("xxxxxxxAttribs");
+ int buflen;
+ IO::DataType attribtype;
+ for(j=0;j<outfile->nAttributes();j++){
+ float buffer[128];
+ char namebuf[128];
+ IO::DataType dt;
+ outfile->readAttributeInfo(j,namebuf,dt,buflen);
+ printf("\tAttribname[%u] = [%s]\n",j,namebuf);
+ outfile->readAttribute(j,buffer);
+ for(int k=0;k<buflen;k++)
+ printf("\tattr data[%u]=%f\n",k,buffer[k]);
+ }
+ int i;
+ if((i=outfile->readAttributeInfo("attrib2",attribtype,buflen))>=0){
+ float buffer[128];
+ outfile->readAttribute(i,buffer);
+ puts("&&&&&Read [attrib2]");
+ for(int k=0;k<buflen;k++)
+ printf("\tattr data[%u]=%f\n",k,buffer[k]);
+ }
+ else puts("&&&&There is no [attrib2]");
+
+ puts("");
+ for(j=0;j<16*16;j++) printf("data[%4u]=%f\n",j,bogusdata[j]);
+ }
+ delete outfile;
+}
+
diff --git a/src/testllReader.cc b/src/testllReader.cc
new file mode 100644
index 0000000..86258d1
--- /dev/null
+++ b/src/testllReader.cc
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "Reader.hh"
+#include "Writer.hh"
+
+int main(int argc,char *argv[]){
+ float data[4*4*8];
+ double origin[3]={0,0,0};
+ double dx[3]={0.25,0.25,0.25};
+ int i;
+ int rank=3;
+ int dims[3]={4,4,8};
+ Reader *reader;
+ IObase *infile;
+ if(argc>1)
+ infile = new IEEEIO(argv[1],IObase::Read);
+ else
+ infile = new IEEEIO("data3d.raw",IObase::Read);
+ // reader = new Reader(*infile);
+ int ndatasets=infile->nDatasets();
+ printf("Number of datasets=%d\n",ndatasets);
+ for(i=0;i<ndatasets;i++){
+ int j;
+ float buffer[8*4*4];
+ for(j=0;j<8*4*4;j++) buffer[j]=0;
+ int rank,dims[3];
+ IObase::DataType datatype;
+
+ printf("Cycle %u\n",i);
+ infile->readInfo(datatype,rank,dims);
+ printf("Data info dt=%u,rank=%u,dims=%u,%u,%u\n",
+ (int)(datatype),rank,dims[0],dims[1],dims[2]);
+ infile->read(buffer);
+ for(j=0;j<8*4*4;j++)
+ printf("Data[%u]=%f\n",j,buffer[j]);
+ puts("***done printing data");
+ int nattribs=infile->nAttributes();
+ printf("Number of Attributes=%d\n",nattribs);
+ for(j=0;j<nattribs;j++){
+ char attribname[64];
+ Long length;
+ infile->readAttributeInfo(j,attribname,datatype,length);
+ printf("\tAttribute[%u] name=%s\n",j,attribname);
+ switch(datatype){
+ case IObase::Float32:{
+ //float buf[5];
+ puts("Float");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::Float64:{
+ double buf[5];
+ puts("Double");
+ printf("length=%u\n",length);
+ infile->readAttribute(j,buf);
+ for(int k=0;k<length;k++)
+ printf("\tElement[%u]=%lf\n",k,buf[k]);
+ } break;
+ case IObase::Int32:{
+ //int buf[5];
+ puts("Integer");
+ printf("length=%u\n",length);
+ } break;
+ default:
+ puts("unknown type");
+ break;
+ }
+ }
+ }
+ //delete reader;
+ delete infile;
+ puts("done");
+ return 0;
+}
diff --git a/src/testllWriter.cc b/src/testllWriter.cc
new file mode 100644
index 0000000..e2febbf
--- /dev/null
+++ b/src/testllWriter.cc
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "IO.hh"
+#include "IEEEIO.hh"
+#include "Reader.hh"
+#include "Writer.hh"
+
+int main(int argc,char *argv[]){
+ float data[40*40*40];
+ double origin[3]={0,0,0};
+ double dx[3]={0.25,0.25,0.25};
+ int rank=3;
+ int dims[3]={40,40,40};
+ //int dims[3]={1,1,1};
+ char label[31];
+ Writer *writer;
+ IEEEIO *iefile;
+ IObase *outfile = iefile = new IEEEIO("data3d.raw",IObase::Create);
+ //iefile->bufferOn(128*1024); // set up a 128k write buffer
+ writer = new Writer(*outfile);
+ writer->setParams(rank,dims,IObase::Float32,origin,dx);
+ // data[0]=1.0;
+ int i;
+ for(i=0;i<40*40*40;i++)
+ data[i]=(float)i;
+ for(i=0;i<4;i++){
+ dims[2]=10+i*10;
+ writer->setDims(dims);
+ writer->write(data);
+ //outfile->pause();
+ //puts("paused");
+ //outfile->resume();
+ //puts("resumed");
+ sprintf(label,"mylabel.%04u",i);
+ //puts("after mylabel");
+ outfile->writeAttribute("Mylabel",IObase::Char,31,label);
+ }
+
+ /* puts("\tnow seek to end\n");
+ outfile->seek(outfile->nDatasets());
+
+ puts("\treserve a chunk");
+ outfile->reserveChunk(IObase::Float32,rank,dims);
+ puts("\tWrite a stream fo 40x40x40");
+ outfile->writeStream(data,40*40*20);
+ puts("\tWrite the next stream of 40x40x20");
+ outfile->writeStream(data+40*40*20,40*40*20);*/
+ puts("\t writer done!!\n\n");
+
+ delete writer;
+ delete outfile;
+ /*
+ puts("Start appending");
+ outfile = new IEEEIO("data3d.raw",IObase::Append);
+ printf("Isvalid? %d\n",outfile->isValid());
+
+ outfile->reserveStream(IObase::Float32,rank,dims);
+ outfile->writeStream(data,40*40*20);
+ outfile->writeStream(data+40*40*20,40*40*20);
+ printf("nrecords=%u\n",outfile->nDatasets());
+ delete outfile;
+
+ puts("Done appending : Reopen for reading.");
+ */
+ //exit(0);
+ puts("start reader***************************");
+ Reader *reader;
+ IObase *infile = new IEEEIO("data3d.raw",IObase::Read);
+ //printf("nrecords=%u\n",outfile->nDatasets());
+ // reader = new Reader(*infile);
+ int ndatasets=infile->nDatasets();
+ printf("Number of datasets=%d\n",ndatasets);
+ for(i=0;i<ndatasets;i++){
+ int j,r;
+ float buffer[40*40*40];
+ for(j=0;j<40*40*40;j++) buffer[j]=0;
+ int rank,dims[3];
+ IObase::DataType datatype;
+
+ printf("Cycle %u\n",i);
+ infile->readInfo(datatype,rank,dims);
+ printf("Data info dt=%u,rank=%u,dims=%u,%u,%u\n",
+ (int)(datatype),rank,dims[0],dims[1],dims[2]);
+ //r=infile->read(buffer);
+ r=infile->readStream(buffer,dims[0]*dims[1]*dims[2]);
+ printf("read %d elements\n",r);
+ for(j=0;j<10;j++)
+ printf("Data[%u]=%f\n",j,buffer[j]);
+ puts("***done printing data");
+ int nattribs=infile->nAttributes();
+ printf("Number of Attributes=%d\n",nattribs);
+ for(j=0;j<nattribs;j++){
+ char attribname[64];
+ Long length;
+ infile->readAttributeInfo(j,attribname,datatype,length);
+ printf("\tAttribute[%u] name=%s\n",j,attribname);
+ switch(datatype){
+ case IObase::Float32:{
+ //float buf[5];
+ puts("Float");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::Float64:{
+ double buf[5];
+ puts("Double");
+ printf("length=%u\n",length);
+ infile->readAttribute(j,buf);
+ for(int k=0;k<length;k++)
+ printf("\tElement[%u]=%lf\n",k,buf[k]);
+ } break;
+ case IObase::Int32:{
+ //int buf[5];
+ puts("Integer");
+ printf("length=%u\n",length);
+ } break;
+ case IObase::String:{
+ char buf[128];
+ puts("String");
+ infile->readAttribute(j,buf);
+ printf("len=%u val=[%s]\n",length,buf);
+ break;
+ }
+ default:
+ printf("unknown type %d\n",(int)datatype);
+ break;
+ }
+ }
+ }
+ //delete reader;
+ delete infile;
+ puts("done");
+ return 0;
+}
diff --git a/src/vatoi.cc b/src/vatoi.cc
new file mode 100644
index 0000000..9044cc4
--- /dev/null
+++ b/src/vatoi.cc
@@ -0,0 +1,22 @@
+#include "vatoi.hh"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int vatoi(char *p){
+ char param[128];
+ strcpy(param,p);
+ char *offset;
+ int n;
+ if((offset=strchr(param,'k')) || (offset=strchr(param,'K')) ){
+ *offset='\0';
+ n=1024;
+ }
+ else if((offset=strchr(param,'m')) || (offset=strchr(param,'M')) ){
+ *offset='\0';
+ n=1024*1024;
+ }
+ else n=1;
+ n*=atoi(param);
+ return n;
+}
diff --git a/src/vatoi.hh b/src/vatoi.hh
new file mode 100644
index 0000000..be25080
--- /dev/null
+++ b/src/vatoi.hh
@@ -0,0 +1,6 @@
+#ifndef __VATOI_H_
+#define __VATOI_H_
+
+int vatoi(char *p);
+
+#endif /* __VATOI_H_ */
diff --git a/src/writef77.f b/src/writef77.f
new file mode 100644
index 0000000..36a1310
--- /dev/null
+++ b/src/writef77.f
@@ -0,0 +1,17 @@
+
+ subroutine openf77()
+ OPEN(UNIT=10,FILE='f77speed.unf',FORM='UNFORMATTED')
+ RETURN
+ END
+
+ subroutine writef77(array)
+ REAL*8 array(64,64,64)
+ WRITE(10) array
+ RETURN
+ END
+
+ subroutine closef77()
+ CLOSE(10)
+ RETURN
+ END
+
diff --git a/src/xmlview.cc b/src/xmlview.cc
new file mode 100644
index 0000000..bad9443
--- /dev/null
+++ b/src/xmlview.cc
@@ -0,0 +1,272 @@
+/*-------------------< >---------------------------
+
+Currently missing markup for EXTENTS and DIMSCALES
+If an attribute is a text string, then it will print the attribute
+with a tag of <DATA>. Otherwise, it will just provide information
+about the attribute (the range, length, type, name... etc).
+
+Does not provide refs for data right now, but I don't think they
+are necessary (the query will need to be based on index anyways).
+
+DTD for HDF XML Markup
+----------------------
+<!ELEMENT HDF4 (FILENAME?,SDS*,ANNOTATION*,ATTRIBUTE*,ERROR?)>
+<!ELEMENT ERROR (#PCDATA)>
+<!ELEMENT FILENAME (#PCDATA)>
+<!ELEMENT SDS (DIMS,TYPE,UNITS?,NAME?,RANGE?,EXTENTS?,ANNOTATION*,ATTRIBUTE*)>
+<!ELEMENT NAME (#PCDATA)>
+<!ELEMENT DIMS (#PCDATA)>
+<!ATTRIBUTE RANK CDATA "3">
+<!ELEMENT TYPE (#PCDATA)>
+<!ELEMENT ANNOTATION (#PCDATA)>
+<!ELEMENT EXTENTS (#PCDATA)>
+<!ELEMENT RANGE (#PCDATA)>
+<!ELEMENT ATTRIBUTE (LENGTH,TYPE,NAME,RANGE?,EXTENTS?)>
+
+ ----------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef WITH_HDF4
+#include <HDFIO.hh>
+#endif
+#ifdef WITH_HDF5
+#include <H5IO.hh>
+#endif
+#include <IEEEIO.hh>
+
+char filedrivername[128];
+
+#define FindMinMax(dt) { \
+ dt *data = (dt*)buffer; \
+ min = max = (double)(data[0]); \
+ for(int i=1;i<nelem;i++){ \
+ double v = (double)(data[i]); \
+ if(v<min) min=v; \
+ if(v>max) max=v; \
+ } \
+ }
+
+// Print an XML tag for the name of the data element
+// tabover<NAME>name</NAME>
+void PrintNameXML(char *tab,// leading whitespace (for formating)
+ char *name);
+// Print an XML tag for the dimensions of an array
+// tabover <DIMS RANK=rank>dim1,dim2..dimN</DIMS>
+void PrintDimsXML(char *tab,// leading whitespace (for formating)
+ int rank,
+ int *dims);
+// Print an XML tag for the length of an array
+// tabover <LENGTH>length</LENGTH>
+void PrintLengthXML(char *tab,// leading whitespace (for formating)
+ int length);
+// Print an XML tag for the data type of an array
+// Must be one of Float32,Float64,Int16,Int32,Int64,Byte,Char
+// Byte indicates data whereas Char indicates text (a string)
+// even though both ar 8 bits
+// tabover <TYPE>datatype</TYPE>
+void PrintTypeXML(char *tab, // OK, you get the picture...
+ IObase::DataType datatype);
+
+// Compute the min and max for a data array.
+void GetRangeXML(IObase::DataType datatype,
+ int nelem,
+ char *buffer,
+ double &min,
+ double &max);
+// Print an XML tag for the Range of the data (the min/max)
+// Uses GetRangeXML.
+// tabover <RANGE>min,max</RANGE>
+// Problem is that this forces a load of the dataset into memory
+// which can be slow and memory intensive. Need to change this
+// so that it can load a subset of the data into RAM (load in
+// 8k blocks rather than the entire thing).
+void PrintRangeXML(char *tab,
+ IObase::DataType datatype,
+ int nelem,
+ char *buffer);
+
+int main(int argc,char *argv[]){
+ sprintf(filedrivername,"ERROR");
+ if(argc<2){
+ printf("<ERROR>missing filename</ERROR>\n");
+ exit(0);
+ }
+ IObase *file = 0;
+
+ IEEEIO *ifile = new IEEEIO(argv[1],IObase::Read);
+ if(!ifile->isValid()){ delete ifile; ifile=0;}
+ else {
+ sprintf(filedrivername,"IEEEIO");
+ file = ifile; // success
+ }
+
+#ifdef WITH_HDF4
+ HDFIO *hfile=0;
+ if(!file){
+ hfile = new HDFIO(argv[1],IObase::Read);
+ if(!hfile->isValid()) {delete hfile; hfile=0;}
+ else {
+ sprintf(filedrivername,"HDF4");
+ file = hfile; // success
+ }
+ }
+#else
+ IObase *hfile=0;
+#endif
+
+#ifdef WITH_HDF5
+ H5IO *h5file=0;
+ if(!file){
+ h5file = new H5IO(argv[1],IObase::Read);
+ if(!h5file->isValid()) {delete h5file; h5file=0;}
+ else {
+ sprintf(filedrivername,"HDF5");
+ file = h5file; // success
+ }
+ }
+#endif
+
+ if(!file){
+ printf("<ERROR>could not open file %s</ERROR>\n",argv[1]);
+ exit(0);
+ }
+ printf("<%s>\n",filedrivername);
+ // now say anything you want about the HDF file
+ for(int n=0,ndatasets=file->nDatasets();n<ndatasets;n++){ // for each dataset
+ int rank,dims[5];
+ char name[128];
+ IObase::DataType datatype;
+ puts("\t<SDS>");// begin an sds
+ if(hfile){
+#ifdef WITH_HDF4
+ hfile->readInfo(name,datatype,rank,dims);
+#endif
+ }
+ else{
+ name[0]='\0';
+ file->readInfo(datatype,rank,dims);
+ }
+ if(strlen(name)>0)
+ PrintNameXML("\t\t",name);
+ PrintTypeXML("\t\t",datatype);
+ PrintDimsXML("\t\t",rank,dims);
+ if(datatype!=IObase::Char){
+ char *buffer = new char[IObase::nBytes(datatype,rank,dims)];
+ file->read(buffer); // read the data
+ PrintRangeXML("\t\t",datatype,IObase::nElements(rank,dims),buffer);
+ delete buffer;
+ }
+ // for now, skip the annotations
+ for(int an=0,nannotations=file->nAnnotations();an<nannotations;an++){
+ int length;
+ file->readAnnotationInfo(an,length);
+ printf("\t\t <ANNOTATION>%u</ANNOTATION>\n",length);
+ }
+ // cycle through each of the attributes
+ for(int a=0,nattribs=file->nAttributes();a<nattribs;a++){
+ int length;
+ printf("\t\t<ATTRIBUTE>\n");
+ file->readAttributeInfo(a,name,datatype,length);
+ PrintNameXML("\t\t ",name);
+ PrintTypeXML("\t\t ",datatype);
+ PrintLengthXML("\t\t ",length);
+ if(datatype==IObase::Char){ // its a string, so print it
+ char *s = new char[length+1];
+ file->readAttribute(a,s);
+ printf("\t\t <DATA>%s</DATA>\n",s);
+ delete s;
+ }
+ else {
+ char *buffer = new char[IObase::nBytes(datatype,1,&length)];
+ file->readAttribute(a,buffer); // read the data
+ PrintRangeXML("\t\t",datatype,length,buffer);
+ delete buffer;
+ }
+ printf("\t\t</ATTRIBUTE>\n");
+ }
+ puts("\t</SDS>");
+ }
+ printf("</%s>\n",filedrivername);
+ delete file;
+ return 0;
+}
+
+
+void PrintNameXML(char *tab,char *name){
+ printf("%s<NAME>%s</NAME>\n",tab,name);
+}
+
+void PrintDimsXML(char *tab,int rank,int *dims){
+ printf("%s<DIMS RANK=\"%u\">",tab,rank);
+ printf("%u",dims[0]); for(int i=1;i<rank;i++) printf(",%u",dims[i]);
+ puts("</DIMS>");
+}
+
+void PrintLengthXML(char *tab,int length){
+ printf("%s<LENGTH>%u</LENGTH>\n",tab,length);
+}
+
+void PrintTypeXML(char *tab,IObase::DataType datatype){
+ printf("%s<TYPE>",tab);
+ switch(datatype){
+ case IObase::Float32:
+ printf("Float32");
+ break;
+ case IObase::Float64:
+ printf("Float64");
+ break;
+ case IObase::Int16:
+ printf("Int16");
+ break;
+ case IObase::Int32:
+ printf("Int32");
+ break;
+ case IObase::Int64:
+ printf("Int64");
+ break;
+ case IObase::Byte:
+ printf("Byte");
+ break;
+ case IObase::Char:
+ printf("Char");
+ break;
+ default:
+ printf("Unknown(%d)",(int)datatype);
+ }
+ puts("</TYPE>");
+}
+
+
+void GetRangeXML(IObase::DataType datatype,int nelem,char *buffer,
+ double &min,double &max){
+ switch(datatype){
+ case IObase::Float32:
+ FindMinMax(float);
+ break;
+ case IObase::Float64:
+ FindMinMax(double);
+ break;
+ case IObase::Int16:
+ FindMinMax(short);
+ break;
+ case IObase::Int32:
+ FindMinMax(int);
+ break;
+ case IObase::Int64:
+ FindMinMax(long); // well. long long for 32bit compiles
+ break;
+ case IObase::Byte:
+ case IObase::Char:
+ FindMinMax(char);
+ break;
+ default:
+ //printf("Unknown(%d)",(int)datatype);
+ return; // don't print
+ }
+}
+void PrintRangeXML(char *tab,IObase::DataType datatype,int nelem,char *buffer){
+ // now compute the range in a datatype-dependent manner
+ double min,max;
+ GetRangeXML(datatype,nelem,buffer,min,max);
+ printf("%s<RANGE>%lf,%lf</RANGE>\n",tab,min,max);
+}