source: trunk/packages/vizservers/nanovis/dxReader.cpp @ 3874

Last change on this file since 3874 was 3874, checked in by ldelgass, 11 years ago

fix trace output

  • Property svn:eol-style set to native
File size: 17.1 KB
RevLine 
[2798]1 /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
[835]2/*
3 * ----------------------------------------------------------------------
4 * Nanovis: Visualization of Nanoelectronics Data
5 *
6 *  dxReader.cpp
[927]7 *      This module contains openDX readers for 2D and 3D volumes.
[835]8 *
9 * ======================================================================
10 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
11 *           Michael McLennan <mmclennan@purdue.edu>
12 *           Purdue Rendering and Perceptualization Lab (PURPL)
13 *
[3502]14 *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
[835]15 *
16 *  See the file "license.terms" for information on usage and
17 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * ======================================================================
19 */
20#include <stdio.h>
21#include <math.h>
[2880]22#include <sys/types.h>
23#include <unistd.h>
24#include <float.h>
25
[835]26#include <fstream>
27#include <iostream>
28#include <sstream>
29#include <string>
30
[2849]31#include <RpOutcome.h>
[2831]32#include <RpField1D.h>
33#include <RpFieldRect3D.h>
34#include <RpFieldPrism3D.h>
35
[3502]36// common file/data reader functions
37#include "ReaderCommon.h"
[2831]38
[2881]39#include "config.h"
[835]40#include "nanovis.h"
[3611]41#include "dxReader.h"
[2831]42#include "Unirect.h"
[2849]43#include "Volume.h"
[835]44
[3611]45using namespace nv;
46
[2849]47/**
48 * \brief Load a 3D volume from a dx-format file
[2880]49 *
50 * In DX format:
51 *  rank 0 means scalars,
52 *  rank 1 means vectors,
53 *  rank 2 means matrices,
54 *  rank 3 means tensors
55 *
56 *  For rank 1, shape is a single number equal to the number of dimensions.
57 *  e.g. rank 1 shape 3 means a 3-component vector field
[835]58 */
[1493]59Volume *
[3611]60nv::load_dx_volume_stream(Rappture::Outcome& result, const char *tag,
61                          std::iostream& fin)
[851]62{
[3502]63    TRACE("Enter tag:%s", tag);
[2849]64
[835]65    Rappture::MeshTri2D xymesh;
66    int dummy, nx, ny, nz, nxy, npts;
[2880]67    // origin
68    double x0, y0, z0;
69    // deltas (cell dimensions)
70    double dx, dy, dz;
71    // length of volume edges
72    double lx, ly, lz;
73    // temps for delta values
74    double ddx, ddy, ddz;
[835]75    char line[128], type[128], *start;
76
77    int isrect = 1;
[2849]78
79    dx = dy = dz = 0.0;
80    x0 = y0 = z0 = 0.0; // May not have an origin line.
[1474]81    nx = ny = nz = npts = nxy = 0;
[2880]82    while (!fin.eof()) {
[2849]83        fin.getline(line, sizeof(line) - 1);
[2861]84        if (fin.fail()) {
85            result.error("error in data stream");
86            return NULL;
87        }
[2849]88        for (start = line; *start == ' ' || *start == '\t'; start++)
[835]89            ;  // skip leading blanks
90
91        if (*start != '#') {  // skip comment lines
[2849]92            if (sscanf(start, "object %d class gridpositions counts %d %d %d",
[2839]93                       &dummy, &nx, &ny, &nz) == 4) {
[835]94                // found grid size
95                isrect = 1;
[2849]96            } else if (sscanf(start, "object %d class array type float rank 1 shape 3 items %d data follows",
97                              &dummy, &nxy) == 2) {
[835]98                isrect = 0;
[2849]99
[835]100                double xx, yy, zz;
[2849]101                for (int i = 0; i < nxy; i++) {
[835]102                    fin.getline(line,sizeof(line)-1);
103                    if (sscanf(line, "%lg %lg %lg", &xx, &yy, &zz) == 3) {
[2880]104                        xymesh.addNode(Rappture::Node2D(xx, yy));
[835]105                    }
106                }
107
108                char fpts[128];
109                sprintf(fpts, "/tmp/tmppts%d", getpid());
110                char fcells[128];
111                sprintf(fcells, "/tmp/tmpcells%d", getpid());
112
113                std::ofstream ftmp(fpts);
114                // save corners of bounding box first, to work around meshing
115                // problems in voronoi utility
[2942]116                int numBoundaryPoints = 4;
117
118                // Bump out the bounds by an epsilon to avoid problem when
119                // corner points are already nodes
120                double XEPS = (xymesh.rangeMax(Rappture::xaxis) -
121                               xymesh.rangeMin(Rappture::xaxis)) / 10.0f;
122
123                double YEPS = (xymesh.rangeMax(Rappture::yaxis) -
124                               xymesh.rangeMin(Rappture::yaxis)) / 10.0f;
125
126                ftmp << xymesh.rangeMin(Rappture::xaxis) - XEPS << " "
127                     << xymesh.rangeMin(Rappture::yaxis) - YEPS << std::endl;
128                ftmp << xymesh.rangeMax(Rappture::xaxis) + XEPS << " "
129                     << xymesh.rangeMin(Rappture::yaxis) - YEPS << std::endl;
130                ftmp << xymesh.rangeMax(Rappture::xaxis) + XEPS << " "
131                     << xymesh.rangeMax(Rappture::yaxis) + YEPS << std::endl;
132                ftmp << xymesh.rangeMin(Rappture::xaxis) - XEPS << " "
133                     << xymesh.rangeMax(Rappture::yaxis) + YEPS << std::endl;
134
[2849]135                for (int i = 0; i < nxy; i++) {
[835]136                    ftmp << xymesh.atNode(i).x() << " " << xymesh.atNode(i).y() << std::endl;
137                }
138                ftmp.close();
139
140                char cmdstr[512];
141                sprintf(cmdstr, "voronoi -t < %s > %s", fpts, fcells);
142                if (system(cmdstr) == 0) {
143                    int cx, cy, cz;
144                    std::ifstream ftri(fcells);
145                    while (!ftri.eof()) {
146                        ftri.getline(line,sizeof(line)-1);
147                        if (sscanf(line, "%d %d %d", &cx, &cy, &cz) == 3) {
[2942]148                            if (cx >= numBoundaryPoints &&
149                                cy >= numBoundaryPoints &&
150                                cz >= numBoundaryPoints) {
151                                // skip boundary points we added
152                                xymesh.addCell(cx - numBoundaryPoints,
153                                               cy - numBoundaryPoints,
154                                               cz - numBoundaryPoints);
[835]155                            }
156                        }
157                    }
158                    ftri.close();
159                } else {
[1325]160                    result.error("triangularization failed");
[2839]161                    return NULL;
[835]162                }
[2849]163                unlink(fpts);
164                unlink(fcells);
[911]165            } else if (sscanf(start, "object %d class regulararray count %d", &dummy, &nz) == 2) {
[835]166                // found z-grid
[911]167            } else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
[835]168                // found origin
[911]169            } else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
[2880]170                // found one of the delta lines
[2840]171                int count = 0;
172                if (ddx != 0.0) {
173                    dx = ddx;
174                    count++;
175                }
176                if (ddy != 0.0) {
177                    dy = ddy;
178                    count++;
179                }
180                if (ddz != 0.0) {
181                    dz = ddz;
182                    count++;
183                }
184                if (count > 1) {
185                    result.addError("don't know how to handle multiple non-zero"
186                                    " delta values");
187                    return NULL;
188                }
[2849]189            } else if (sscanf(start, "object %d class array type %s rank 0 items %d data follows",
190                              &dummy, type, &npts) == 3) {
[835]191                if (isrect && (npts != nx*ny*nz)) {
[2849]192                    result.addError("inconsistent data: expected %d points"
[2839]193                                    " but found %d points", nx*ny*nz, npts);
[1493]194                    return NULL;
[911]195                } else if (!isrect && (npts != nxy*nz)) {
[2849]196                    result.addError("inconsistent data: expected %d points"
[2839]197                                    " but found %d points", nxy*nz, npts);
[1493]198                    return NULL;
[835]199                }
200                break;
[2849]201            } else if (sscanf(start, "object %d class array type %s rank 0 times %d data follows",
202                              &dummy, type, &npts) == 3) {
[835]203                if (npts != nx*ny*nz) {
[2849]204                    result.addError("inconsistent data: expected %d points"
[2839]205                                    " but found %d points", nx*ny*nz, npts);
[1493]206                    return NULL;
[835]207                }
208                break;
209            }
210        }
[2880]211    }
[835]212
[3874]213    TRACE("found nx=%d ny=%d nxy=%d nz=%d\ndx=%g dy=%g dz=%g\nx0=%g y0=%g z0=%g",
[2953]214          nx, ny, nxy, nz, dx, dy, dz, x0, y0, z0);
[2861]215
[2942]216    lx = (nx - 1) * dx;
217    ly = (ny - 1) * dy;
218    lz = (nz - 1) * dz;
219
[835]220    // read data points
[2880]221    if (fin.eof()) {
222        result.error("data not found in stream");
[2839]223        return NULL;
[1382]224    }
[3597]225    Volume *volume = NULL;
[2942]226    float *data = NULL;
227    double vmin = DBL_MAX;
228    double nzero_min = DBL_MAX;
229    double vmax = -DBL_MAX;
[1382]230    if (isrect) {
[3362]231#ifdef DOWNSAMPLE_DATA
[2880]232        Rappture::Mesh1D xgrid(x0, x0 + lx, nx);
233        Rappture::Mesh1D ygrid(y0, y0 + ly, ny);
234        Rappture::Mesh1D zgrid(z0, z0 + lz, nz);
235        Rappture::FieldRect3D field(xgrid, ygrid, zgrid);
[3362]236#else // !DOWNSAMPLE_DATA
237        data = new float[nx *  ny *  nz * 4];
238        memset(data, 0, nx*ny*nz*4);
239#endif // DOWNSAMPLE_DATA
[2839]240        double dval[6];
241        int nread = 0;
242        int ix = 0;
243        int iy = 0;
244        int iz = 0;
[2849]245
[2839]246        while (!fin.eof() && nread < npts) {
247            fin.getline(line,sizeof(line)-1);
[2861]248            if (fin.fail()) {
249                result.addError("error reading data points");
250                return NULL;
251            }
[2849]252            int n = sscanf(line, "%lg %lg %lg %lg %lg %lg",
253                           &dval[0], &dval[1], &dval[2], &dval[3], &dval[4], &dval[5]);
254            for (int p = 0; p < n; p++) {
[2880]255#ifdef notdef
256                if (isnan(dval[p])) {
[3452]257                    TRACE("Found NAN in input at %d,%d,%d", ix, iy, iz);
[2880]258                }
259#endif
[3362]260#ifdef DOWNSAMPLE_DATA
261                int nindex = iz*nx*ny + iy*nx + ix;
262                field.define(nindex, dval[p]);
263#else // !DOWNSAMPLE_DATA
[2839]264                int nindex = (iz*nx*ny + iy*nx + ix) * 4;
265                data[nindex] = dval[p];
[2849]266
[2839]267                if (dval[p] < vmin) {
268                    vmin = dval[p];
269                } else if (dval[p] > vmax) {
270                    vmax = dval[p];
271                }
[2849]272                if (dval[p] != 0.0 && dval[p] < nzero_min) {
[2839]273                    nzero_min = dval[p];
274                }
[3362]275#endif // DOWNSAMPLE_DATA
[2839]276                nread++;
277                if (++iz >= nz) {
278                    iz = 0;
279                    if (++iy >= ny) {
280                        iy = 0;
281                        ++ix;
282                    }
283                }
284            }
285        }
[2849]286
[2839]287        // make sure that we read all of the expected points
[3574]288        if (nread != npts) {
[2849]289            result.addError("inconsistent data: expected %d points"
[3574]290                            " but found %d points", npts, nread);
[2839]291            return NULL;
292        }
[2849]293
[3362]294#ifndef DOWNSAMPLE_DATA
[2849]295
[3574]296        // scale all values [0-1], -1 => out of bounds
297        normalizeScalar(data, npts, 4, vmin, vmax);
[2880]298        computeSimpleGradient(data, nx, ny, nz,
299                              dx, dy, dz);
[3362]300#else // DOWNSAMPLE_DATA
[2839]301        // figure out a good mesh spacing
[3576]302        int nsample = 64;
[2880]303        double dmin = pow((lx*ly*lz)/((nsample-1)*(nsample-1)*(nsample-1)), 0.333);
[2849]304
[3362]305        nx = (int)ceil(lx/dmin) + 1;
306        ny = (int)ceil(ly/dmin) + 1;
307        nz = (int)ceil(lz/dmin) + 1;
[2880]308
[2877]309#ifndef HAVE_NPOT_TEXTURES
[2839]310        // must be an even power of 2 for older cards
311        nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
312        ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
313        nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
[835]314#endif
[2849]315
[2880]316        dx = lx /(double)(nx - 1);
317        dy = ly /(double)(ny - 1);
318        dz = lz /(double)(nz - 1);
319
[2942]320        vmin = field.valueMin();
321        vmax = field.valueMax();
322        nzero_min = DBL_MAX;
[2880]323        double dv = vmax - vmin;
[2839]324        if (dv == 0.0) {
[2849]325            dv = 1.0;
[2839]326        }
[2942]327
[2880]328        int ngen = 0;
[3362]329#ifdef FILTER_GRADIENTS
[2880]330        // Sobel filter expects a single float at
331        // each node
332        const int step = 1;
333        float *cdata = new float[nx*ny*nz * step];
334#else // !FILTER_GRADIENTS
335        // Leave 3 floats of space for gradients
336        // to be filled in by computeSimpleGradient()
337        const int step = 4;
[2942]338        data = new float[nx*ny*nz * step];
[2880]339#endif // FILTER_GRADIENTS
[2849]340
341        for (int iz = 0; iz < nz; iz++) {
[2880]342            double zval = z0 + iz*dz;
[2849]343            for (int iy = 0; iy < ny; iy++) {
[2880]344                double yval = y0 + iy*dy;
[2849]345                for (int ix = 0; ix < nx; ix++) {
[2880]346                    double xval = x0 + ix*dx;
[2849]347                    double v = field.value(xval, yval, zval);
[2880]348#ifdef notdef
349                    if (isnan(v)) {
350                        TRACE("NAN at %d,%d,%d: (%g, %g, %g)", ix, iy, iz, xval, yval, zval);
[2839]351                    }
[835]352#endif
[2849]353                    if (v != 0.0 && v < nzero_min) {
[2839]354                        nzero_min = v;
355                    }
[3362]356#ifdef FILTER_GRADIENTS
[3574]357                    // NOT normalized, may have NaNs (FIXME: how does gradient filter handle NaN?)
[2839]358                    cdata[ngen] = v;
[2880]359#else // !FILTER_GRADIENTS
360                    // scale all values [0-1], -1 => out of bounds
361                    v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
362                    data[ngen] = v;
363#endif // FILTER_GRADIENTS
[2839]364                    ngen += step;
365                }
366            }
367        }
[3362]368#ifdef FILTER_GRADIENTS
[2880]369        // computeGradient returns a new array with gradients
370        // filled in, so data is now 4 floats per node
[2942]371        data = computeGradient(cdata, nx, ny, nz,
372                               dx, dy, dz,
373                               vmin, vmax);
[2874]374        delete [] cdata;
[2880]375#else // !FILTER_GRADIENTS
376        computeSimpleGradient(data, nx, ny, nz,
377                              dx, dy, dz);
378#endif // FILTER_GRADIENTS
[2849]379
[3362]380#endif // DOWNSAMPLE_DATA
[1382]381    } else {
[2880]382        Rappture::Mesh1D zgrid(z0, z0 + (nz-1)*dz, nz);
[2839]383        Rappture::FieldPrism3D field(xymesh, zgrid);
[2849]384
[2839]385        double dval;
386        int nread = 0;
387        int ixy = 0;
388        int iz = 0;
389        while (!fin.eof() && nread < npts) {
390            fin >> dval;
391            if (fin.fail()) {
392                result.addError("after %d of %d points: can't read number",
393                                nread, npts);
394                return NULL;
395            } else {
396                int nid = nxy*iz + ixy;
397                field.define(nid, dval);
[2849]398
[2839]399                nread++;
400                if (++iz >= nz) {
401                    iz = 0;
402                    ixy++;
403                }
404            }
405        }
[2849]406
[2839]407        // make sure that we read all of the expected points
[3574]408        if (nread != npts) {
[2839]409            result.addError("inconsistent data: expected %d points"
[3574]410                            " but found %d points", npts, nread);
[2839]411            return NULL;
412        }
[2849]413
[2839]414        x0 = field.rangeMin(Rappture::xaxis);
[2880]415        lx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis);
[2839]416        y0 = field.rangeMin(Rappture::yaxis);
[2880]417        ly = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis);
[2839]418        z0 = field.rangeMin(Rappture::zaxis);
[2880]419        lz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis);
[2953]420
421        // figure out a good mesh spacing
[3576]422        int nsample = 64;
[2880]423        double dmin = pow((lx*ly*lz)/((nsample-1)*(nsample-1)*(nsample-1)), 0.333);
[2849]424
[3362]425        nx = (int)ceil(lx/dmin) + 1;
426        ny = (int)ceil(ly/dmin) + 1;
427        nz = (int)ceil(lz/dmin) + 1;
[2877]428#ifndef HAVE_NPOT_TEXTURES
[2839]429        // must be an even power of 2 for older cards
430        nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
431        ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
432        nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
[1000]433#endif
[2880]434
435        dx = lx /(double)(nx - 1);
436        dy = ly /(double)(ny - 1);
437        dz = lz /(double)(nz - 1);
438
[2942]439        vmin = field.valueMin();
440        vmax = field.valueMax();
441        nzero_min = DBL_MAX;
[2880]442        double dv = vmax - vmin;
[2849]443        if (dv == 0.0) {
444            dv = 1.0;
445        }
446
[2953]447        data = new float[4*nx*ny*nz];
[2839]448        // generate the uniformly sampled data that we need for a volume
449        int ngen = 0;
[2849]450        for (int iz = 0; iz < nz; iz++) {
[2880]451            double zval = z0 + iz*dz;
[2849]452            for (int iy = 0; iy < ny; iy++) {
[2880]453                double yval = y0 + iy*dy;
[2849]454                for (int ix = 0; ix < nx; ix++) {
[2880]455                    double xval = x0 + ix*dx;
[2849]456                    double v = field.value(xval, yval, zval);
457
458                    if (v != 0.0 && v < nzero_min) {
[2839]459                        nzero_min = v;
460                    }
461                    // scale all values [0-1], -1 => out of bounds
462                    v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
463                    data[ngen] = v;
[2849]464
[2839]465                    ngen += 4;
466                }
467            }
468        }
[2849]469
[2880]470        computeSimpleGradient(data, nx, ny, nz,
471                              dx, dy, dz);
[2942]472    }
[2849]473
[3452]474    TRACE("nx = %i ny = %i nz = %i", nx, ny, nz);
475    TRACE("x0 = %lg y0 = %lg z0 = %lg", x0, y0, z0);
476    TRACE("lx = %lg ly = %lg lz = %lg", lx, ly, lz);
477    TRACE("dx = %lg dy = %lg dz = %lg", dx, dy, dz);
478    TRACE("dataMin = %lg dataMax = %lg nzero_min = %lg",
[2942]479          vmin, vmax, nzero_min);
480
[3597]481    volume = NanoVis::loadVolume(tag, nx, ny, nz, 4, data,
[2942]482                                 vmin, vmax, nzero_min);
[3597]483    volume->xAxis.setRange(x0, x0 + lx);
484    volume->yAxis.setRange(y0, y0 + ly);
485    volume->zAxis.setRange(z0, z0 + lz);
486    volume->updatePending = true;
[2942]487
488    delete [] data;
[1000]489
[3597]490    return volume;
[1000]491}
Note: See TracBrowser for help on using the repository browser.