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

Last change on this file since 3335 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

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