avtDatabase.C 92.9 KB
Newer Older
hrchilds's avatar
hrchilds committed
1
2
/*****************************************************************************
*
brugger's avatar
   
brugger committed
3
* Copyright (c) 2000 - 2008, Lawrence Livermore National Security, LLC
hrchilds's avatar
hrchilds committed
4
* Produced at the Lawrence Livermore National Laboratory
brugger's avatar
   
brugger committed
5
* LLNL-CODE-400142
hrchilds's avatar
hrchilds committed
6
7
* All rights reserved.
*
brugger's avatar
   
brugger committed
8
* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The
hrchilds's avatar
hrchilds committed
9
10
11
12
13
14
15
16
17
18
* full copyright notice is contained in the file COPYRIGHT located at the root
* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
*
* Redistribution  and  use  in  source  and  binary  forms,  with  or  without
* modification, are permitted provided that the following conditions are met:
*
*  - Redistributions of  source code must  retain the above  copyright notice,
*    this list of conditions and the disclaimer below.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
brugger's avatar
   
brugger committed
19
20
21
*    documentation and/or other materials provided with the distribution.
*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may
*    be used to endorse or promote products derived from this software without
hrchilds's avatar
hrchilds committed
22
23
24
25
26
*    specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
brugger's avatar
   
brugger committed
27
28
29
* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,
* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY
* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL
hrchilds's avatar
hrchilds committed
30
31
32
33
34
35
36
37
38
* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*****************************************************************************/

hrchilds's avatar
hrchilds committed
39
40
41
42
43
44
// ************************************************************************* //
//                              avtDatabase.C                                //
// ************************************************************************* //

#include <avtDatabase.h>

hrchilds's avatar
hrchilds committed
45
#include <visitstream.h>
hrchilds's avatar
hrchilds committed
46
#include <visit-config.h>
hrchilds's avatar
hrchilds committed
47
48
#include <stdio.h>

hrchilds's avatar
hrchilds committed
49
#include <Expression.h>
hrchilds's avatar
hrchilds committed
50
#include <ExprNode.h>
hrchilds's avatar
hrchilds committed
51
#include <ParsingExprList.h>
hrchilds's avatar
hrchilds committed
52
53
54
55
#include <PickAttributes.h>
#include <PickVarInfo.h>
#include <Utility.h>

56
#include <avtDatabaseFactory.h>
hrchilds's avatar
hrchilds committed
57
58
59
60
61
62
63
64
#include <avtDatabaseMetaData.h>
#include <avtDataObjectSource.h>
#include <avtDataset.h>
#include <avtExtents.h>
#include <avtIOInformation.h>
#include <avtIntervalTree.h>
#include <avtSIL.h>

65
#include <DebugStream.h>
hrchilds's avatar
hrchilds committed
66
#include <ImproperUseException.h>
hrchilds's avatar
hrchilds committed
67
68
69
#include <InvalidFilesException.h>
#include <InvalidDimensionsException.h>
#include <InvalidVariableException.h>
hrchilds's avatar
hrchilds committed
70
71
#include <TimingsManager.h>

72
73
74
75
76
77
78
79
80
#include <algorithm>
#include <map>
#include <string>
#include <vector>

using std::map;
using std::string;
using std::vector;

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
void
ConvertSlashes(char *str)
{
    int len = strlen(str);
    for (int i = 0; i < len; i++)
    {
#ifndef WIN32
        if (str[i] == '\\')
            str[i] = '/';
#else
        if (str[i] == '/')
            str[i] = '\\';
#endif
    }
}


hrchilds's avatar
hrchilds committed
98
99
100
101
// size of MD/SIL caches
int       avtDatabase::mdCacheSize         = 20;
int       avtDatabase::silCacheSize        = 20;

hrchilds's avatar
hrchilds committed
102
103
104
bool      avtDatabase::onlyServeUpMetaData = false;


105
106
// ****************************************************************************
// The following methods are convenience methods to help database plugins
107
108
// do dynamic domain decomposion for rectilinear grids. There are four 
// methods...
109
//
110
111
112
113
// 1 DetermineRectilinearDecomposition: Used to compute a domain decomposition
// 2 ComputeDomainLogicalCoords: Used to compute the logical indices of a domain 
// 3 ComputeDomainBounds: Used to compute spatial bounds of a domain
// 4 RectilinearDecompCost: Used *internally* to help compute domain decomp.
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//
//   DetermineRectilinearDecomposition determines the number of domains in
//   each dimension to decompose the mesh into. For example, for a mesh that
//   is 100 zones in X and 50 zones in Y and a total number of domains (e.g.
//   processor count) of 6, it would return (3,2,0) meaning 3 domains in X
//   by 2 domains in Y by zero domains in Z like so...
//   
//      +---------+---------+---------+
//   1  |    3    |    4    |    5    |    
//      +---------+---------+---------+
//   0  |    0    |    1    |    2    |    
//      +---------+---------+---------+
//           0         1         2
//
//   The numbers inside each box above are the MPI ranks associated with the
//   domains or, in other words, the domain numbers.
//
//   ComputeDomainLogicalCoords is used to map an MPI rank into a set of 
//   logical domain indices. It would be called, for example, on processor of
//   rank 5 to return the indices (2,1,0) meaning that domain '5' has logical
//   indices 2,1,0.
//
//   ComputeDomainBounds is used to compute the logical bounds of a domain
//   'slot' along a given axis. For example, for the case above, slot 0's
//   domain in the Y axis would go from 0 to 49 while slot 1 would go from
//   50 to 99.
//
141
//   These routines could be improved to support simple ghosting.
142
143
144
//
// ****************************************************************************

hrchilds's avatar
hrchilds committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// ****************************************************************************
//  Function: RectilinearDecompCost 
//
//  Purpose:
//      Compute the "cost" of a decomposition in terms of the amount of
//      communication algorithms might require. Note, this is part of the
//      domain decomposition algorithm taken from Matt O'Brien's domain
//      decomposition library
//      
//  Programmer: Mark C. Miller (plagerized from Matt O'Brien)
//  Creation:   September 20, 2004 
//
//  Modification:
//
//    Mark C. Miller, Mon Aug 14 13:59:33 PDT 2006
//    Moved here from ViSUS plugin so it can be used by other plugins
//
// ****************************************************************************
double
avtDatabase::RectilinearDecompCost(int i, int j, int k, int nx, int ny, int nz)
{
    double costtot;

    i--;
    j--;
    k--;

    costtot = 0;

    /* estimate cost based on size of communicating surfaces */

    costtot+=i*((ny*nz));
    costtot+=j*((nx*nz));
    costtot+=k*((ny*nx));
    costtot+=2*i*j*((nz));
    costtot+=2*i*k*((ny));
    costtot+=2*j*k*((nx));
    costtot+=4*i*j*k;

    return(costtot);
}

// ****************************************************************************
//  Function: DetermineRectilinearDecomposition 
//
//  Purpose:
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//      Decides how to decompose a rectilinear mesh into numbers of processors
//      along each independent axis. This code was taken from Matt O'Brien's
//      domain decomposition library. 
//
//      ndims : is the number of logical dimensions in the mesh
//      n     : is the number of desired domains
//      nx    : size of global, logical mesh in x
//      ny    : size of global, logical mesh in y
//      nz    : size of global, logical mesh in z
//      imin  : (named consistent with orig. code) domain count along x axis
//      jmin  : (named consistent with orig. code) domain count along y axis
//      kmin  : (named consistent with orig. code) domain count along z axis
//
//      After calling, it should be the case that imin * jmin * kmin = n;
//      Therefore, one can decompose the mesh into an array of 'domains' that
//      is imin x jmin x kmin.
//
//      If n is a prime number, I think the result is imin = n, jmin = kmin = 1
hrchilds's avatar
hrchilds committed
209
210
211
212
213
214
215
216
217
//      
//  Programmer: Mark C. Miller (plagerized from Matt O'Brien)
//  Creation:   September 20, 2004 
//
//  Modification:
//
//    Mark C. Miller, Mon Aug 14 13:59:33 PDT 2006
//    Moved here from ViSUS plugin so it can be used by other plugins
//
hrchilds's avatar
hrchilds committed
218
219
220
//    Mark C. Miller, Tue Dec  5 18:14:58 PST 2006
//    Fixed UMR
//
hrchilds's avatar
hrchilds committed
221
222
223
224
225
226
227
228
229
// ****************************************************************************
double
avtDatabase::ComputeRectilinearDecomposition(int ndims, int n, int nx, int ny, int nz,
   int *imin, int *jmin, int *kmin)
{
    int i,j;
    double cost, costmin = 1e80;

    if (ndims == 2)
hrchilds's avatar
hrchilds committed
230
        nz = 1;
hrchilds's avatar
hrchilds committed
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

    /* find all two or three product factors of the number of domains
       and evaluate the communication cost */

   for (i = 1; i <= n; i++)
   {
      if (n%i == 0)
      {
         if (ndims == 3)
         {
            for (j = 1; j <= i; j++)
            {
               if ((i%j) == 0)
               {
                  cost = RectilinearDecompCost(j, i/j, n/i, nx, ny, nz);
                  
                  if (cost < costmin)
                  {
                     *imin = j;
                     *jmin = i/j;
                     *kmin = n/i;
                     costmin = cost;
                  }
               }
            }
         }
         else
         {
            cost = RectilinearDecompCost(i, n/i, 1, nx, ny, nz);
            
            if (cost < costmin)
            {
               *imin = i;
               *jmin = n/i;
               *kmin = 1;
               costmin = cost;
            }
         } 
      }
   }

   return costmin;
}

miller86's avatar
miller86 committed
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
// ****************************************************************************
//  Function: ComputeRectilinearSpatialDecomposition
//
//  Purpose: Just like ComputeRectilinearDecomposition except it is intended
//  to compute a decomposition of a spatial bounding box instead of a logical
//  one.
//
//      ndims : is the number of logical dimensions in the mesh
//      n     : is the number of desired domains
//      wx    : size of global, mesh in x
//      wy    : size of global, mesh in y
//      wz    : size of global, mesh in z
//      imin  : (named consistent with orig. code) domain count along x axis
//      jmin  : (named consistent with orig. code) domain count along y axis
//      kmin  : (named consistent with orig. code) domain count along z axis
//
//  Programmer: Mark C. Miller
//  Creation:   September 27, 2007 
// 
// ****************************************************************************
double
avtDatabase::ComputeRectilinearSpatialDecomposition(int ndims, int n, double wx,
    double wy, double wz, int *imin, int *jmin, int *kmin)
{
    double xscale = 1000.0 / wx;
    double yscale = 1000.0 / wy;
    double zscale = ndims == 3 ? (1000.0 / wz ) : xscale;
    double scale = xscale;
    if (yscale > xscale)
        scale = yscale;
    if (zscale > scale)
        scale = zscale;

    int nx = (int) (scale * wx);
    int ny = (int) (scale * wy);
    int nz = (int) (scale * wz);
    return ComputeRectilinearDecomposition(ndims, n, nx, ny, nz, imin, jmin, kmin);
}

hrchilds's avatar
hrchilds committed
314
315
316
317
318
// ****************************************************************************
//  Function: ComputeDomainLogicalCoords
//
//  Purpose: Given the number of domains along each axis in a decomposition
//  and the rank of a processor, this routine will determine the domain logical
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
//  coordinates of the processor's domain.
//
//  dataDim            : number of logical dimensions in the mesh
//  domCount[]         : array of counts of domains in each of x, y, z axes
//  rank               : zero-origin rank of calling processors
//  domLogicalCoords[] : returned logical indices of the domain associated
//                       with this rank.
//
//  For example, in a 6 processor case decomposed in a 3 x 2 array of domains
//  like so...
//
//      +---------+---------+---------+
//   1  |    3    |    4    |    5    |    
//      +---------+---------+---------+
//   0  |    0    |    1    |    2    |    
//      +---------+---------+---------+
//           0         1         2
//
//   Calling this method on processor of rank 5 would return
//   domLogicalCoords = {2,1,0}
hrchilds's avatar
hrchilds committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
//      
//  Programmer: Mark C. Miller
//  Creation:   September 20, 2004 
//
//  Modification:
//
//    Mark C. Miller, Mon Aug 14 13:59:33 PDT 2006
//    Moved here from ViSUS plugin so it can be used by other plugins
//
// ****************************************************************************
void
avtDatabase::ComputeDomainLogicalCoords(int dataDim, int domCount[3], int rank,
    int domLogicalCoords[3])
{
    int r = rank;

    // handle Z (K logical) axis
    if (dataDim == 3)
    {
        domLogicalCoords[2] = r / (domCount[1]*domCount[0]);
        r = r % (domCount[1]*domCount[0]);
    }

    // handle Y (J logical) axis
    domLogicalCoords[1] = r / domCount[0];
    r = r % domCount[0];

    // handle X (I logical) axis
    domLogicalCoords[0] = r;
}

// ****************************************************************************
//  Function: ComputeDomainBounds 
//
//  Purpose: Given the global zone count along an axis, the domain count for
//  the same axis and a domain's logical index along the same axis, compute
//  the starting global zone index along this axis and the count of zones
//  along this axis for the associated domain.
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
//
//  For example, in the case a 2D mesh that is globally 100 zones in X by
//  100 zones in Y, if we want to obtain the bounds in X of domains (1,0)
//  (rank 1) or (1,1) (rank 4)...
//
//      +---------+---------+---------+
//   1  |    3    |    4    |    5    |    
//      +---------+---------+---------+
//   0  |    0    |    1    |    2    |    
//      +---------+---------+---------+
//           0         1         2
//
//   We would call this method with globalZoneCount = 100, domCount = 3
//   because there are 3 domains along the X axis, domLogicalCoord = 1
//   because we are dealing with the domain whose index is 1 along the
//   X axis.
hrchilds's avatar
hrchilds committed
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
//      
//  Programmer: Mark C. Miller
//  Creation:   September 20, 2004 
//
//  Modification:
//
//    Mark C. Miller, Mon Aug 14 13:59:33 PDT 2006
//    Moved here from ViSUS plugin so it can be used by other plugins
//
// ****************************************************************************
void
avtDatabase::ComputeDomainBounds(int globalZoneCount, int domCount, int domLogicalCoord,
    int *globalZoneStart, int *zoneCount)
{
    int domZoneCount       = globalZoneCount / domCount;
    int domsWithExtraZones = globalZoneCount % domCount;
    int domZoneCountPlus1  = domZoneCount;
    if (domsWithExtraZones > 0)
        domZoneCountPlus1 = domZoneCount + 1;

    int i;
    int stepSize = domZoneCount;
    *globalZoneStart = 0;
    for (i = 0; i < domLogicalCoord; i++)
    {
        *globalZoneStart += stepSize;
        if (i >= domCount - domsWithExtraZones)
            stepSize = domZoneCountPlus1;
    }
    if (i >= domCount - domsWithExtraZones)
        stepSize = domZoneCountPlus1;
    *zoneCount = stepSize;
}

miller86's avatar
miller86 committed
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
// ****************************************************************************
//  Function: ComputeDomainSpatialBounds 
//
//  Purpose: Just like ComputeDomainBounds but for sptial case. 
//
//  Programmer: Mark C. Miller
//  Creation:   September 20, 2004 
// ****************************************************************************
void
avtDatabase::ComputeDomainSpatialBounds(double globalWidth, int domCount, int domLogicalCoord,
    double *globalStart, double *width)
{
    double domWidth = globalWidth / domCount;
    *globalStart = domLogicalCoord * domWidth;
    *width = domWidth;
}


hrchilds's avatar
hrchilds committed
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
// ****************************************************************************
//  Method: avtDatabase constructor
//
//  Arguments:
//      f       The list of files.
//      nf      The number of files in f.
//
//  Programmer: Hank Childs
//  Creation:   August 9, 2000
//
//  Modifications:
//
//    Hank Childs, Mon Aug 14 11:49:24 PDT 2000
//    Made a database be more tied to its files by putting them in constructor.
//
//    Hank Childs, Wed Sep 13 20:56:28 PDT 2000
//    Moved initialization of files to base class.
//
//    Hank Childs, Thu Mar  1 13:42:43 PST 2001
//    Split class so functionality went in derived type, avtGenericDatabase.
//
//    Hank Childs, Fri Aug 31 17:01:18 PDT 2001
//    Initialized gotIOInfo.
//
hrchilds's avatar
hrchilds committed
469
470
471
//    Jeremy Meredith/Hank Childs, Tue Mar 23 12:26:55 PST 2004
//    Initialize file format type.
//
472
473
//    Mark C. Miller, Tue Jun 10 22:36:25 PDT 2008
//    Added support for ignoring bad extents from dbs.
hrchilds's avatar
hrchilds committed
474
475
476
477
// ****************************************************************************

avtDatabase::avtDatabase()
{
hrchilds's avatar
hrchilds committed
478
479
480
    gotIOInfo         = false;
    invariantMetaData = NULL;
    invariantSIL      = NULL;
hrchilds's avatar
hrchilds committed
481
    fileFormat        = "<unknown>";
482
    ignoreExtents     = false;
hrchilds's avatar
hrchilds committed
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
}


// ****************************************************************************
//  Method: avtDatabase destructor
//
//  Programmer: Hank Childs
//  Creation:   August 9, 2000
//
//  Modifications:
//
//    Hank Childs, Mon Aug 14 09:28:41 PDT 2000
//    Added deletion of variable and source as arrays.
//
//    Hank Childs, Wed Sep 13 20:56:28 PDT 2000
//    Moved deletion of files down to base class.
//
//    Hank Childs, Thu Mar  1 13:42:43 PST 2001
//    Split class so functionality went in derived type, avtGenericDatabase.
//
hrchilds's avatar
hrchilds committed
503
504
505
506
507
508
//    Mark C. Miller, 30Sep03
//    Added support to time-varying SIL/MD
//
//    Hank Childs, Tue Mar 22 10:41:23 PST 2005
//    Fix memory leak.
//
509
510
511
//    Mark C. Miller, Thu Feb 12 11:33:59 PST 2009
//    Removed std:: qualification on some STL classes due to use of using
//    statements at top 
hrchilds's avatar
hrchilds committed
512
513
514
515
// ****************************************************************************

avtDatabase::~avtDatabase()
{
516
    vector<avtDataObjectSource *>::iterator it;
hrchilds's avatar
hrchilds committed
517
518
519
520
521
    for (it = sourcelist.begin() ; it != sourcelist.end() ; it++)
    {
        delete *it;
    }

hrchilds's avatar
hrchilds committed
522
523
524
525
526
527
528
    if (invariantMetaData != NULL)
    {
        delete invariantMetaData;
        invariantMetaData = NULL;
    }

    if (invariantSIL != NULL)
hrchilds's avatar
hrchilds committed
529
    {
hrchilds's avatar
hrchilds committed
530
531
        delete invariantSIL;
        invariantSIL = NULL;
hrchilds's avatar
hrchilds committed
532
    }
hrchilds's avatar
hrchilds committed
533
534
535
536
537
538
539
540
541
542
543

    std::list<CachedMDEntry>::iterator it2;
    for (it2 = metadata.begin() ; it2 != metadata.end() ; it2++)
    {
        delete (*it2).md;
    }
    std::list<CachedSILEntry>::iterator it3;
    for (it3 = sil.begin() ; it3 != sil.end() ; it3++)
    {
        delete (*it3).sil;
    }
hrchilds's avatar
hrchilds committed
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
}


// ****************************************************************************
//  Method: avtDatabase::GetOutput
//
//  Purpose:
//      Gets an avtDataset object that corresponds to the currently opened
//      files and specified variable.
//
//  Arguments:
//      var     The variable that the dataset should correspond to.
//      ts      The timestep that the dataset should correspond to.
//
//  Returns:    An avtDataset corresponding to the files and variable.
//
//  Programmer: Hank Childs
//  Creation:   August 9, 2000
//
//  Modifications:
//
//    Hank Childs, Mon Aug 14 09:42:50 PDT 2000
//    Re-wrote to handle multiple variables.
//
//    Hank Childs, Thu Mar  1 09:01:30 PST 2001
//    Added timestep argument.  Rewrote to not need data members.
//
//    Hank Childs, Fri Aug 17 16:03:44 PDT 2001
//    Removed dependencies on avtDataset.
//
hrchilds's avatar
hrchilds committed
574
575
//    Mark C. Miller, Tue Sep 28 19:32:50 PDT 2004
//    Added dummy argument for c all to PopulateDataObjectInformation
hrchilds's avatar
hrchilds committed
576
577
578
579
580
581
582
583
// ****************************************************************************

avtDataObject_p
avtDatabase::GetOutput(const char *var, int ts)
{
    //
    // Figure out how many domains there are for the current variable.
    //
hrchilds's avatar
hrchilds committed
584
    int nDomains = GetMetaData(ts)->GetNDomains(var);
hrchilds's avatar
hrchilds committed
585
586
587
588
589
590
591
592
593
594
595
596

    if (nDomains <= 0)
    {
        EXCEPTION1(InvalidVariableException, var);
    }

    //
    // Create the source object.
    //
    avtDataObjectSource *src = CreateSource(var, ts);
    avtDataObject_p dob = src->GetOutput();

hrchilds's avatar
hrchilds committed
597
598
    vector<bool> dummy;
    PopulateDataObjectInformation(dob, var, ts, dummy);
hrchilds's avatar
hrchilds committed
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661

    sourcelist.push_back(src);

    return dob;
}


// ****************************************************************************
//  Method: avtDatabase::PopulateDataObjectInformation
//
//  Purpose:
//      Populates the information from a data object from the database 
//      metadata.
//
//  Arguments:
//      dob       The data object to populate.
//      var       The variable the data object corresponds to.
//
//  Programmer:   Hank Childs
//  Creation:     October 26, 2000
//
//  Modifications:
//
//    Hank Childs, Fri Dec 22 14:10:22 PST 2000
//    Accounted for interface change with dataset information.
//
//    Hank Childs, Mon Mar 19 16:22:25 PST 2001
//    Accounted for centering, vector vars.
//
//    Hank Childs, Sun Mar 25 11:55:28 PST 2001
//    Accounted for new data object information interface.
//
//    Hank Childs, Fri Aug 17 16:07:26 PDT 2001
//    Renamed to get away from avtDataset roots.
//
//    Eric Brugger, Mon Nov  5 13:28:45 PST 2001
//    Modified to always compile the timing code.
//
//    Hank Childs, Wed Dec 19 20:18:19 PST 2001
//    Added species support.
//
//    Hank Childs, Fri Dec 21 07:23:47 PST 2001
//    Write out variable names.
//
//    Hank Childs, Sun Jun 16 19:52:06 PDT 2002
//    Pass on the cell and block origins.
//
//    Hank Childs, Sun Aug 18 11:09:55 PDT 2002
//    Pass on disjoint elements information.
//
//    Hank Childs, Fri Sep 27 16:45:38 PDT 2002
//    Pass on units.
//
//    Hank Childs, Mon Sep 30 09:06:44 PDT 2002
//    Pass on containsGhostZones.
//
//    Hank Childs, Tue Oct  1 14:59:20 PDT 2002
//    If we are doing a material plot, then the output's zones will be
//    invalidated.
//
//    Kathleen Bonnell, Wed Mar 26 13:03:54 PST 2003 
//    Pass on containsOriginalCells.
//
hrchilds's avatar
hrchilds committed
662
663
664
665
//    Jeremy Meredith, Thu Jun 12 08:48:20 PDT 2003
//    Added logic to decrement the topo. dimension if we have requested
//    material boundaries.
//
hrchilds's avatar
hrchilds committed
666
667
668
//    Hank Childs, Fri Aug  1 21:54:08 PDT 2003
//    Add support for curves.
//
hrchilds's avatar
hrchilds committed
669
670
671
672
//    Hank Childs, Wed Aug 13 11:17:58 PDT 2003
//    No longer assume that requesting a material means that we are doing
//    material interface reconstruction.
//
hrchilds's avatar
hrchilds committed
673
674
675
//    Hank Childs, Tue Sep 23 23:03:07 PDT 2003
//    Add support for tensors.
//
hrchilds's avatar
hrchilds committed
676
677
678
679
680
681
//    Mark C. Miller, 30Sep03
//    Added timeStep argument
//
//    Hank Childs, Mon Feb 23 07:49:51 PST 2004
//    Update for new data attribute interface.  Now add variables for each of
//    the secondary variables in data specification.
hrchilds's avatar
hrchilds committed
682
//
hrchilds's avatar
hrchilds committed
683
684
685
//    Kathleen Bonnell, Thu Mar 11 11:17:58 PST 2004
//    DataExtents now always has only 2 componnts. 
//
hrchilds's avatar
hrchilds committed
686
687
688
//    Kathleen Bonnell, Fri May 28 18:26:09 PDT 2004 
//    Pass on containsOriginalNodes.
//
hrchilds's avatar
hrchilds committed
689
690
691
//    Kathleen Bonnell, Thu Jul 22 12:10:19 PDT 2004 
//    Set avtDataAttributes::treatAsASCII from ScalarMetaData::treatAsASCII.
//
hrchilds's avatar
hrchilds committed
692
693
694
695
//    Brad Whitlock, Tue Jul 20 13:35:38 PST 2004
//    Added units for scalar, vector, tensor, symmetric tensor, and curve
//    vars. I also added labels for meshes.
//
hrchilds's avatar
hrchilds committed
696
697
698
//    Hank Childs, Fri Aug 20 15:42:34 PDT 2004
//    Correct cut-and-paste bug for checking units for symmetric tensors.
//
hrchilds's avatar
hrchilds committed
699
700
701
//    Mark C. Miller, Tue Sep 28 19:32:50 PDT 2004
//    Added argument for data selections that have been applied as well
//    as code to populate data attributes
hrchilds's avatar
hrchilds committed
702
703
704
705
706
//
//    Mark C. Miller, Tue Oct 19 14:08:56 PDT 2004
//    Changed 'spec' arg to ref_ptr. Added code to attempt to get spatial/data
//    extents trees and set true extents from those if available
//
hrchilds's avatar
hrchilds committed
707
708
709
710
//    Mark C. Miller, Wed Oct 20 10:35:53 PDT 2004
//    Moved code to get extents from auxiliary data to a subroutine. Also,
//    placed it inside the checks for various variable types.
//
hrchilds's avatar
hrchilds committed
711
712
713
714
//    Kathleen Bonnell, Fri Nov 12 08:13:02 PST 2004 
//    Throw an exception in the case that BoundarySurfaces are requested but
//    the topological dimension is zero. 
//
hrchilds's avatar
hrchilds committed
715
716
717
//    Kathleen Bonnell, Thu Dec  9 08:43:47 PST 2004 
//    Set ContainsGlobalNode/ZoneIds in DataAtts from db MetaData. 
//
hrchilds's avatar
hrchilds committed
718
719
720
//    Hank Childs, Sat Jan  1 11:33:13 PST 2005
//    Initialize the mesh name.
//
hrchilds's avatar
hrchilds committed
721
722
723
//    Kathleen Bonnell, Thu Jan 27 09:14:35 PST 2005 
//    Share the number of states with DataAttributes.
//
hrchilds's avatar
hrchilds committed
724
725
726
//    Brad Whitlock, Mon Apr 4 09:07:04 PDT 2005
//    Added support for Label type variables.
//
hrchilds's avatar
hrchilds committed
727
728
729
//    Hank Childs, Tue Jul 19 15:54:14 PDT 2005
//    Add support for array variables.
//
hrchilds's avatar
hrchilds committed
730
731
732
//    Hank Childs, Fri Aug  5 16:32:56 PDT 2005
//    Set the variable type, as well as the array subnames.
//
hrchilds's avatar
hrchilds committed
733
734
735
//    Jeremy Meredith, Thu Aug 25 11:06:06 PDT 2005
//    Added group origin.
//
hrchilds's avatar
hrchilds committed
736
737
738
//    Hank Childs, Fri Oct  7 08:21:03 PDT 2005
//    Added fullDBName.
//
hrchilds's avatar
hrchilds committed
739
740
741
//    Kathleen Bonnell, Fri Feb  3 10:32:12 PST 2006 
//    Added meshCoordType.
//
hrchilds's avatar
hrchilds committed
742
743
744
//    Kathleen Bonnell, Thu Aug  3 08:42:33 PDT 2006 
//    Add Variable and DataExtents from CurveMetaData. 
//
hrchilds's avatar
hrchilds committed
745
746
747
//    Jeremy Meredith, Mon Aug 28 16:45:10 EDT 2006
//    Added unit cell vectors.  Added nodesAreCritical.
//
hrchilds's avatar
hrchilds committed
748
749
750
//    Jeremy Meredith, Thu Feb 15 12:53:11 EST 2007
//    Added support for rectilinear grids with an inherent transform.
//
hrchilds's avatar
hrchilds committed
751
752
//    Mark C. Miller, Tue Mar 27 08:39:55 PDT 2007
//    Added support for node origin
753
754
755
756
//
//    Kathleen Bonnell,  Fri Jun 22 13:41:14 PDT 2007
//    Added meshType.
//
757
758
759
//    Hank Childs, Wed Jul 25 14:16:36 PDT 2007
//    Renamed method: NeedBoundarySurfaces -> GetBoundarySurfaceRepresentation.
//
hrchilds's avatar
hrchilds committed
760
761
762
//    Hank Childs, Sun Oct 28 09:51:53 PST 2007
//    Added support for ghost data on the exterior of the boundary.
//
hrchilds's avatar
hrchilds committed
763
764
765
//    Hank Childs, Fri Feb 15 16:19:02 PST 2008
//    Fix possible buffer overwrite.
//
766
767
768
769
//    Hank Childs, Tue Jan 20 10:36:40 PST 2009
//    Initialize data member for whether or not the file format does its own
//    domain decomposition.
//
770
771
772
773
774
775
//    Mark C. Miller, Wed Feb 11 17:08:51 PST 2009
//    Removed 'centering' member from curve metadata
//
//    Mark C. Miller, Thu Feb 12 11:33:59 PST 2009
//    Removed std:: qualification on some STL classes due to use of using
//    statements at top 
hrchilds's avatar
hrchilds committed
776
777
778
779
// ****************************************************************************

void
avtDatabase::PopulateDataObjectInformation(avtDataObject_p &dob,
hrchilds's avatar
hrchilds committed
780
781
782
                                          const char *var,
                                          int ts,
                                          const vector<bool> &selectionsApplied,
hrchilds's avatar
hrchilds committed
783
                                          avtDataRequest_p spec)
hrchilds's avatar
hrchilds committed
784
{
hrchilds's avatar
hrchilds committed
785
    int   i;
hrchilds's avatar
hrchilds committed
786

hrchilds's avatar
hrchilds committed
787
788
789
    int timerHandle = visitTimer->StartTimer();

    avtDataAttributes &atts     = dob->GetInfo().GetAttributes();
hrchilds's avatar
hrchilds committed
790
    atts.SetFullDBName(fullDBName);
hrchilds's avatar
hrchilds committed
791
792
    avtDataValidity   &validity = dob->GetInfo().GetValidity();

793
794
795
796
    avtDatabaseMetaData *md = GetMetaData(ts);
    atts.SetDynamicDomainDecomposition(md->GetFormatCanDoDomainDecomposition());
    string mesh = md->MeshForVar(var);
    const avtMeshMetaData *mmd = md->GetMesh(mesh);
hrchilds's avatar
hrchilds committed
797
    bool haveSetTrueSpatialExtents = false;
798
    atts.SetNumStates(md->GetNumStates());
hrchilds's avatar
hrchilds committed
799
800
801
    if (mmd != NULL)
    {
        atts.SetCellOrigin(mmd->cellOrigin);
hrchilds's avatar
hrchilds committed
802
        atts.SetNodeOrigin(mmd->nodeOrigin);
hrchilds's avatar
hrchilds committed
803
        atts.SetBlockOrigin(mmd->blockOrigin);
hrchilds's avatar
hrchilds committed
804
        atts.SetGroupOrigin(mmd->groupOrigin);
hrchilds's avatar
hrchilds committed
805
806
        atts.SetTopologicalDimension(mmd->topologicalDimension);
        atts.SetSpatialDimension(mmd->spatialDimension);
hrchilds's avatar
hrchilds committed
807
        atts.SetMeshname(mesh);
hrchilds's avatar
hrchilds committed
808
809
810
        atts.SetXUnits(mmd->xUnits);
        atts.SetYUnits(mmd->yUnits);
        atts.SetZUnits(mmd->zUnits);
hrchilds's avatar
hrchilds committed
811
812
813
        atts.SetXLabel(mmd->xLabel);
        atts.SetYLabel(mmd->yLabel);
        atts.SetZLabel(mmd->zLabel);
hrchilds's avatar
hrchilds committed
814
        atts.SetContainsGhostZones(mmd->containsGhostZones);
hrchilds's avatar
hrchilds committed
815
816
        atts.SetContainsExteriorBoundaryGhosts(
                             mmd->containsExteriorBoundaryGhosts);
hrchilds's avatar
hrchilds committed
817
        atts.SetContainsOriginalCells(mmd->containsOriginalCells);
hrchilds's avatar
hrchilds committed
818
        atts.SetContainsOriginalNodes(mmd->containsOriginalNodes);
hrchilds's avatar
hrchilds committed
819
820
        atts.SetContainsGlobalZoneIds(mmd->containsGlobalZoneIds);
        atts.SetContainsGlobalNodeIds(mmd->containsGlobalNodeIds);
hrchilds's avatar
hrchilds committed
821
822
        vector<bool> tmp = selectionsApplied;
        atts.SetSelectionsApplied(tmp);
hrchilds's avatar
hrchilds committed
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
        validity.SetDisjointElements(mmd->disjointElements);

        //
        // Note that we are using the spatial extents as both the spatial 
        // extents and as the global spatial extents (the spatial extents 
        // across all timesteps).
        //
        if (mmd->hasSpatialExtents)
        {
            double extents[6];
            for (int i = 0 ; i < mmd->spatialDimension ; i++)
            {
                extents[2*i]   = mmd->minSpatialExtents[i];
                extents[2*i+1] = mmd->maxSpatialExtents[i];
            }
            atts.GetTrueSpatialExtents()->Set(extents);
hrchilds's avatar
hrchilds committed
839
840
            haveSetTrueSpatialExtents = true;
        }
841
        atts.SetMeshType(mmd->meshType);
hrchilds's avatar
hrchilds committed
842
        atts.SetMeshCoordType(mmd->meshCoordType);
hrchilds's avatar
hrchilds committed
843
844
        atts.SetNodesAreCritical(mmd->nodesAreCritical);
        atts.SetUnitCellVectors(mmd->unitCellVectors);
hrchilds's avatar
hrchilds committed
845
846
847
848
849
        if (mmd->rectilinearGridHasTransform)
        {
            atts.SetRectilinearGridHasTransform(true);
            atts.SetRectilinearGridTransform(mmd->rectilinearGridTransform);
        }
hrchilds's avatar
hrchilds committed
850
851
852
853
854
855
856
    }

    //
    // If we haven't set spatial extents, try using a data tree
    //
    if (haveSetTrueSpatialExtents == false)
    {
hrchilds's avatar
hrchilds committed
857
858
859
        double extents[6];
        if (GetExtentsFromAuxiliaryData(spec, mesh.c_str(),
                AUXILIARY_DATA_SPATIAL_EXTENTS, extents))
hrchilds's avatar
hrchilds committed
860
        {
hrchilds's avatar
hrchilds committed
861
            atts.GetTrueSpatialExtents()->Set(extents);
hrchilds's avatar
hrchilds committed
862
863
        }
    }
hrchilds's avatar
hrchilds committed
864
        
hrchilds's avatar
hrchilds committed
865
866
867
868
869
870
    //
    // We want to add information to the data attributes for each of the 
    // variables.  Make a big list of the primary and secondary variables.
    //
    vector<const char *> var_list;
    var_list.push_back(var);
hrchilds's avatar
hrchilds committed
871
    if (*spec != NULL)
hrchilds's avatar
hrchilds committed
872
    {
873
        const vector<CharStrRef> &secondaryVariables 
hrchilds's avatar
hrchilds committed
874
875
                                               = spec->GetSecondaryVariables();
        for (i = 0 ; i < secondaryVariables.size() ; i++)
hrchilds's avatar
hrchilds committed
876
        {
hrchilds's avatar
hrchilds committed
877
            var_list.push_back(*(secondaryVariables[i]));
hrchilds's avatar
hrchilds committed
878
879
880
        }
    }

hrchilds's avatar
hrchilds committed
881
882
883
884
885
    //
    // Now iterate through our variable list and add information about each
    // variable as we go.
    //
    for (i = 0 ; i < var_list.size() ; i++)
hrchilds's avatar
hrchilds committed
886
    {
hrchilds's avatar
hrchilds committed
887
888
        const avtScalarMetaData *smd = GetMetaData(ts)->GetScalar(var_list[i]);
        if (smd != NULL)
hrchilds's avatar
hrchilds committed
889
        {
hrchilds's avatar
hrchilds committed
890
891
892
893
            if (smd->hasUnits)
                atts.AddVariable(var_list[i], smd->units);
            else
                atts.AddVariable(var_list[i]);
hrchilds's avatar
hrchilds committed
894
895
            atts.SetVariableDimension(1, var_list[i]);
            atts.SetCentering(smd->centering, var_list[i]);
hrchilds's avatar
hrchilds committed
896
            atts.SetTreatAsASCII(smd->treatAsASCII, var_list[i]); 
hrchilds's avatar
hrchilds committed
897
898
            atts.SetVariableType(AVT_SCALAR_VAR, var_list[i]);

hrchilds's avatar
hrchilds committed
899
900
901
902
903
904
            //
            // Note that we are using the spatial extents as both the spatial 
            // extents and as the global spatial extents (the spatial extents 
            // across all timesteps).
            //
            if (smd->hasDataExtents)
hrchilds's avatar
hrchilds committed
905
            {
hrchilds's avatar
hrchilds committed
906
                double extents[6]; // 6 is probably too much, but better to be safe
hrchilds's avatar
hrchilds committed
907
908
909
910
                extents[0] = smd->minDataExtents;
                extents[1] = smd->maxDataExtents;
    
                atts.GetTrueDataExtents(var_list[i])->Set(extents);
hrchilds's avatar
hrchilds committed
911
912
913
            }
            else
            {
hrchilds's avatar
hrchilds committed
914
                double extents[6]; // 6 is probably too much, but better to be safe
hrchilds's avatar
hrchilds committed
915
916
917
918
919
                if (GetExtentsFromAuxiliaryData(spec, var_list[i],
                        AUXILIARY_DATA_DATA_EXTENTS, extents))
                {
                    atts.GetTrueDataExtents(var_list[i])->Set(extents);
                }
hrchilds's avatar
hrchilds committed
920
921
            }
        }
hrchilds's avatar
hrchilds committed
922
923
924
925
    
        const avtVectorMetaData *vmd = GetMetaData(ts)->GetVector(var_list[i]);
        if (vmd != NULL)
        {
hrchilds's avatar
hrchilds committed
926
927
928
929
            if (vmd->hasUnits)
                atts.AddVariable(var_list[i], vmd->units);
            else
                atts.AddVariable(var_list[i]);
hrchilds's avatar
hrchilds committed
930
931
            atts.SetVariableDimension(vmd->varDim, var_list[i]);
            atts.SetCentering(vmd->centering, var_list[i]);
hrchilds's avatar
hrchilds committed
932
            atts.SetVariableType(AVT_VECTOR_VAR, var_list[i]);
hrchilds's avatar
hrchilds committed
933
934
935
936
937
938
939
940
    
            //
            // Note that we are using the spatial extents as both the spatial 
            // extents and as the global spatial extents (the spatial extents 
            // across all timesteps).
            //
            if (vmd->hasDataExtents)
            {
hrchilds's avatar
hrchilds committed
941
                double extents[6]; // 6 is probably too much, but better to be safe
hrchilds's avatar
hrchilds committed
942
943
                extents[0] = vmd->minDataExtents;
                extents[1] = vmd->maxDataExtents;
hrchilds's avatar
hrchilds committed
944
                atts.GetTrueDataExtents(var_list[i])->Set(extents);
hrchilds's avatar
hrchilds committed
945
            }
hrchilds's avatar
hrchilds committed
946
            else
hrchilds's avatar
hrchilds committed
947
            {
hrchilds's avatar
hrchilds committed
948
                double extents[6]; // 6 is probably too much, but better to be safe
hrchilds's avatar
hrchilds committed
949
950
951
952
953
                if (GetExtentsFromAuxiliaryData(spec, var_list[i],
                        AUXILIARY_DATA_DATA_EXTENTS, extents))
                {
                    atts.GetTrueDataExtents(var_list[i])->Set(extents);
                }
hrchilds's avatar
hrchilds committed
954
955
            }
        }
hrchilds's avatar
hrchilds committed
956

hrchilds's avatar
hrchilds committed
957
958
959
        const avtTensorMetaData *tmd = GetMetaData(ts)->GetTensor(var_list[i]);
        if (tmd != NULL)
        {
hrchilds's avatar
hrchilds committed
960
961
962
963
            if (tmd->hasUnits)
                atts.AddVariable(var_list[i], tmd->units);
            else
                atts.AddVariable(var_list[i]);
hrchilds's avatar
hrchilds committed
964
965
            atts.SetVariableDimension(9, var_list[i]);
            atts.SetCentering(tmd->centering, var_list[i]);
hrchilds's avatar
hrchilds committed
966
            atts.SetVariableType(AVT_TENSOR_VAR, var_list[i]);
hrchilds's avatar
hrchilds committed
967
968
969
970
971
972
        }
    
        const avtSymmetricTensorMetaData *stmd = 
                                   GetMetaData(ts)->GetSymmTensor(var_list[i]);
        if (stmd != NULL)
        {
hrchilds's avatar
hrchilds committed
973
974
            if (stmd->hasUnits)
                atts.AddVariable(var_list[i], stmd->units);
hrchilds's avatar
hrchilds committed
975
976
            else
                atts.AddVariable(var_list[i]);
hrchilds's avatar
hrchilds committed
977
            atts.SetVariableType(AVT_SYMMETRIC_TENSOR_VAR, var_list[i]);
hrchilds's avatar
hrchilds committed
978
979
980
            atts.SetVariableDimension(9, var_list[i]);
            atts.SetCentering(stmd->centering, var_list[i]);
        }
hrchilds's avatar
hrchilds committed
981

hrchilds's avatar
hrchilds committed
982
983
984
985
986
987
988
        const avtArrayMetaData *amd = GetMetaData(ts)->GetArray(var_list[i]);
        if (amd != NULL)
        {
            if (amd->hasUnits)
                atts.AddVariable(var_list[i], amd->units);
            else
                atts.AddVariable(var_list[i]);
hrchilds's avatar
hrchilds committed
989
            atts.SetVariableType(AVT_ARRAY_VAR, var_list[i]);
hrchilds's avatar
hrchilds committed
990
991
            atts.SetVariableDimension(amd->nVars, var_list[i]);
            atts.SetCentering(amd->centering, var_list[i]);
hrchilds's avatar
hrchilds committed
992
            atts.SetVariableSubnames(amd->compNames, var_list[i]);
hrchilds's avatar
hrchilds committed
993
994
        }

hrchilds's avatar
hrchilds committed
995
996
997
998
999
1000
1001
        const avtSpeciesMetaData *spmd = 
                                      GetMetaData(ts)->GetSpecies(var_list[i]);
        if (spmd != NULL)
        {
            atts.AddVariable(var_list[i]);
            atts.SetVariableDimension(1, var_list[i]);
            atts.SetCentering(AVT_ZONECENT, var_list[i]);
hrchilds's avatar
hrchilds committed
1002
            atts.SetVariableType(AVT_MATSPECIES, var_list[i]);
hrchilds's avatar
hrchilds committed
1003
1004
1005
1006
1007
1008
            double extents[2];
            extents[0] = 0.;
            extents[1] = 1.;
            atts.GetEffectiveDataExtents(var_list[i])->Set(extents);
            atts.GetTrueDataExtents(var_list[i])->Set(extents);
        }
hrchilds's avatar
hrchilds committed
1009

hrchilds's avatar
hrchilds committed
1010
1011
1012
        const avtCurveMetaData *cmd = GetMetaData(ts)->GetCurve(var_list[i]);
        if (cmd != NULL)
        {
hrchilds's avatar
hrchilds committed
1013
1014
1015
            atts.AddVariable(var_list[i]);
            atts.SetVariableDimension(1, var_list[i]);
            atts.SetVariableType(AVT_CURVE, var_list[i]);
hrchilds's avatar
hrchilds committed
1016
            atts.SetTopologicalDimension(1);
hrchilds's avatar
hrchilds committed
1017
            atts.SetSpatialDimension(1);
hrchilds's avatar
hrchilds committed
1018
1019
1020
1021
            atts.SetXUnits(cmd->xUnits);
            atts.SetXLabel(cmd->xLabel);
            atts.SetYUnits(cmd->yUnits);
            atts.SetYLabel(cmd->yLabel);
hrchilds's avatar
hrchilds committed
1022
1023
            if (cmd->hasDataExtents)
            {
hrchilds's avatar
hrchilds committed
1024
                double extents[6]; // 6 is probably too much, but better to be safe
hrchilds's avatar
hrchilds committed
1025
1026
1027
1028
1029
1030
                extents[0] = cmd->minDataExtents;
                extents[1] = cmd->maxDataExtents;
                atts.GetTrueDataExtents(var_list[i])->Set(extents);
            }
            else
            {
hrchilds's avatar
hrchilds committed
1031
                double extents[6]; // 6 is probably too much, but better to be safe
hrchilds's avatar
hrchilds committed
1032
1033
1034
1035
1036
1037
                if (GetExtentsFromAuxiliaryData(spec, var_list[i],
                        AUXILIARY_DATA_DATA_EXTENTS, extents))
                {
                    atts.GetTrueDataExtents(var_list[i])->Set(extents);
                }
            }
hrchilds's avatar
hrchilds committed
1038
        }
hrchilds's avatar
hrchilds committed
1039
1040
1041
1042
1043
1044
1045
1046

        const avtLabelMetaData *lmd = GetMetaData(ts)->GetLabel(var_list[i]);
        if (lmd != NULL)
        {
            atts.AddVariable(var_list[i]);
            atts.SetVariableDimension(1, var_list[i]);
            atts.SetCentering(lmd->centering, var_list[i]);
            atts.SetTreatAsASCII(true, var_list[i]); 
hrchilds's avatar
hrchilds committed
1047
            atts.SetVariableType(AVT_LABEL_VAR, var_list[i]);
hrchilds's avatar
hrchilds committed
1048
        }
hrchilds's avatar
hrchilds committed
1049
    }
hrchilds's avatar
hrchilds committed
1050
    atts.SetActiveVariable(var);
hrchilds's avatar
hrchilds committed
1051

hrchilds's avatar
hrchilds committed
1052
1053
1054
1055
1056
1057
1058
    //
    // SPECIAL CASE:
    //
    // We need to decrement the topological dimension if we asked for
    // an unfilled boundary.  The way this is handles (by directly
    // checking a data specification) needs to change.
    //
1059
    if (*spec && spec->GetBoundarySurfaceRepresentation())
hrchilds's avatar
hrchilds committed
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
    {
        if (atts.GetTopologicalDimension() > 0)
        {
            atts.SetTopologicalDimension(atts.GetTopologicalDimension() - 1);
        }
        else 
        {
            EXCEPTION2(InvalidDimensionsException, "Boundary", ">0"); 
        }
    }
hrchilds's avatar
hrchilds committed
1070

hrchilds's avatar
hrchilds committed
1071
1072
1073
1074
1075
1076
1077
1078
    char str[1024];
    sprintf(str, "Populating Information for %s", var);
    visitTimer->StopTimer(timerHandle, str);
    visitTimer->DumpTimings();
}


// ****************************************************************************
hrchilds's avatar
hrchilds committed
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
//  Method: avtDatabase::MetaDataIsInvariant
//
//  Purpose: Return whether or not database meta data is invariant.
//
//  We use a bool* to implement this so that we can know whether or not the
//  bool has been set and once it is set, never call down to the plugins to
//  re-acquire this knowledge
//
//  Programmer: Mark C. Miller, 30Sep03
// ****************************************************************************
bool
avtDatabase::MetaDataIsInvariant(void)
{
   if (invariantMetaData == NULL)
   {
      invariantMetaData = new bool;
      *invariantMetaData = HasInvariantMetaData();
   }

   return *invariantMetaData;
}

// ****************************************************************************
//  Method: avtDatabase::SILIsInvariant
//
//  Purpose: Return whether or not SIL is invariant.
//
//  We use a bool* to implement this so that we can know whether or not the
//  bool has been set and once it is set, never call down to the plugins to
//  re-acquire this knowledge
//
//  Programmer: Mark C. Miller, 30Sep03
// ****************************************************************************
bool
avtDatabase::SILIsInvariant(void)
{
   if (invariantSIL == NULL)
   {
      invariantSIL = new bool;
      *invariantSIL = HasInvariantSIL();
   }

   return *invariantSIL;
}

// ****************************************************************************
//  Method: avtDatabase::GetMostRecentTimestepQueried
//
//  Purpose:
//      Provide convenience method for caller's that don't have a reasonable
//      'current' time to pass to GetMetaData and GetSIL which now both
//      require the caller to specify the time. This function simply returns
//      the time of the most recent request for either SIL or MetaData. The
//      idea is that a reasonable time to use when one is not available is
//      the time of the most recent query for metadata or SIL. 
//      
// ****************************************************************************
int
avtDatabase::GetMostRecentTimestep(void) const
{
   if (sil.size() == 0)
   {
      if (metadata.size() == 0)
         return 0;
      else
         return metadata.front().ts;
   }
   else
   {
      if (metadata.size() == 0)
         return sil.front().ts;
      else
      {
         if (sil.front().ts > metadata.front().ts)
            return sil.front().ts;
         else
            return metadata.front().ts;
      }
   }
}

// ****************************************************************************
//  Method: avtDatabase::GetNewMetaData
hrchilds's avatar
hrchilds committed
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
//
//  Purpose:
//      Provide mechanism for clients to get information about the file
//      and the variables in the file.
//
//  Arguments:
//     timeState : The time state that we're interested in.
//
//  Programmer: Jeremy Meredith
//  Creation:   August 22, 2000
//
//  Modifications:
//    Hank Childs, Fri May 11 14:10:59 PDT 2001
//    Also populate the IO info when you get the meta-data.
//
//    Brad Whitlock, Wed May 14 09:11:03 PDT 2003
//    Added timeState argument.
//
hrchilds's avatar
hrchilds committed
1180
1181
1182
//    Hank Childs, Thu Aug 14 08:45:39 PDT 2003
//    Set the database's name with the meta-data.
//
hrchilds's avatar
hrchilds committed
1183
1184
1185
//    Mark C. Miller, 22Sep03, changed name to Get'New'MetaData. Put result
//    in MRU cache
//
hrchilds's avatar
hrchilds committed
1186
1187
1188
//    Hank Childs, Tue Nov 25 07:38:18 PST 2003
//    Add mesh quality expressions.
//
hrchilds's avatar
hrchilds committed
1189
1190
1191
//    Hank Childs, Thu Jan 22 10:05:41 PST 2004
//    Do not populate the I/O information if we are only getting meta-data.
//
hrchilds's avatar
hrchilds committed
1192
1193
1194
//    Jeremy Meredith/Hank Childs, Tue Mar 23 12:26:55 PST 2004
//    Set the file format with the meta-data.
//
hrchilds's avatar
hrchilds committed
1195
1196
1197
//    Mark C. Miller, Tue May 17 18:48:38 PDT 2005
//    Added bool to force reading of all cycles and times 
//
1198
1199
1200
1201
//    Kathleen Bonnell, Tue Oct  9 14:40:10 PDT 2007
//    Only create MeshQuality and TimeDerivative expressions if the option
//    hasn't been turned off. 
//
1202
1203
1204
//    Cyrus Harrison, Wed Nov 28 09:50:46 PST 2007
//    Added vector magnitude expressions 
//
1205
1206
//    Mark C. Miller, Thu Feb 12 11:35:34 PST 2009
//    Added call to convert 1D vars to curves
hrchilds's avatar
hrchilds committed
1207
// ****************************************************************************
hrchilds's avatar
hrchilds committed
1208

hrchilds's avatar
hrchilds committed
1209
void
hrchilds's avatar
hrchilds committed
1210
avtDatabase::GetNewMetaData(int timeState, bool forceReadAllCyclesTimes)
hrchilds's avatar
hrchilds committed
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
{
    // sanity check: since SIL info is currently embedded in MetaData,
    // we cannot have MD invariant but SIL NOT invariant
    if (MetaDataIsInvariant() && !SILIsInvariant())
    {
        EXCEPTION1(ImproperUseException, "invalid MD/SIL invariants condition");
    }

    // acquire new metadata for the given timestep
    avtDatabaseMetaData *md = new avtDatabaseMetaData;
    const char *filename = GetFilename(timeState);
    string fname;
    if (filename == NULL)
        fname = "";
    else
        fname = filename;
hrchilds's avatar
hrchilds committed
1227
    SetDatabaseMetaData(md, timeState, forceReadAllCyclesTimes);
hrchilds's avatar
hrchilds committed
1228
    md->SetDatabaseName(fname);
hrchilds's avatar
hrchilds committed
1229
    md->SetFileFormat(fileFormat);
hrchilds's avatar
hrchilds committed
1230
1231
    md->SetMustRepopulateOnStateChange(!MetaDataIsInvariant() ||
                                       !SILIsInvariant());
hrchilds's avatar
hrchilds committed
1232

1233
1234
1235
1236
1237
    if (avtDatabaseFactory::GetCreateMeshQualityExpressions())
        AddMeshQualityExpressions(md);

    if (avtDatabaseFactory::GetCreateTimeDerivativeExpressions())
        AddTimeDerivativeExpressions(md);
hrchilds's avatar
hrchilds committed
1238

1239
1240
1241
    if (avtDatabaseFactory::GetCreateVectorMagnitudeExpressions())
        AddVectorMagnitudeExpressions(md);

1242
1243
    Convert1DVarMDsToCurveMDs(md);

hrchilds's avatar
hrchilds committed
1244
1245
    if (! OnlyServeUpMetaData())
    {
hrchilds's avatar
hrchilds committed
1246
        PopulateIOInformation(timeState, ioInfo);
hrchilds's avatar
hrchilds committed
1247
1248
        gotIOInfo = true;
    }
hrchilds's avatar
hrchilds committed
1249
1250
1251
1252
1253
1254

    // put the metadata at the front of the MRU cache
    CachedMDEntry tmp = {md, timeState};
    metadata.push_front(tmp);
}

hrchilds's avatar
hrchilds committed
1255
1256

// ****************************************************************************
1257
1258
1259
1260
1261
1262
//  Method: avtDatabase::Convert1DVarMDsToCurveMDs
//
//  Purpose: Convert 1D var MDs (vars defined on 1D meshes) to Curve MDs 
//
//  Programmer: Mark C. Miller
//  Creation: February 9, 2009
1263
1264
1265
1266
1267
//
//  Modifications:
//    Mark C. Miller, Wed Feb 18 14:54:59 PST 2009
//    Fixed naming of curve md objects so their names don't wind up colliding
//    with thier original scalar var objects.
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
// ****************************************************************************

void
avtDatabase::Convert1DVarMDsToCurveMDs(avtDatabaseMetaData *md)
{
    int i;

    //
    // Look for any 1D meshes. If we don't have any, then we can't
    // have any 1D vars and we can terminate early.
    //
    map<string, int> meshNameToNumMap;
    for (i = 0; i < md->GetNumMeshes(); i++)
    {
        const avtMeshMetaData *mmd = md->GetMesh(i);
        if (mmd->spatialDimension == 1 && mmd->numBlocks == 1)
            meshNameToNumMap[mmd->name] = i;
    }
    if (meshNameToNumMap.size() == 0)
        return;

    //
    // Find all scalar vars defined on the meshes found above. These
    // need to be converted to Curve MD objects.
    //
    map<string, int>::iterator it;
    vector<int> scalarsToHide;
    for (i = 0; i < md->GetNumScalars(); i++)
    {
        const avtScalarMetaData *smd = md->GetScalar(i);
        it = meshNameToNumMap.find(smd->meshName);
        if (it != meshNameToNumMap.end())
        {
            const avtMeshMetaData *mmd = md->GetMesh(it->second);
            scalarsToHide.push_back(i);
            avtCurveMetaData *cmd = new avtCurveMetaData();
1304
            cmd->name = "Scalar_Curves/" + smd->name;
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
            cmd->originalName = smd->originalName;
            cmd->validVariable = smd->validVariable;
            cmd->yUnits = smd->units;
            cmd->xUnits = mmd->xUnits;
            cmd->xLabel = mmd->xLabel;
            cmd->hasDataExtents = smd->hasDataExtents;
            cmd->minDataExtents = smd->minDataExtents;
            cmd->maxDataExtents = smd->maxDataExtents;
            cmd->hideFromGUI = smd->hideFromGUI;
            cmd->from1DScalarName = smd->name;
            md->Add(cmd);
            debug3 << "Re-interpreted 1D avtScalarMetaData \"" << smd->originalName
                   << "\" as avtCurveMetaData \"" << cmd->name << "\"" << endl;
        }
    }

1321
1322
1323
1324
    //
    // Hide from the GUI, those scalars that got converted as well
    // as any 1D meshes.
    //
1325
1326
1327
1328
1329
1330
    for (i = 0; i < (int) scalarsToHide.size(); i++)
        md->GetScalars(scalarsToHide[i]).hideFromGUI = true;
    for (it = meshNameToNumMap.begin(); it != meshNameToNumMap.end(); it++)
        md->GetMeshes(it->second).hideFromGUI = true;
}

hrchilds's avatar
hrchilds committed
1331
1332
1333
1334
1335
1336
1337
1338
1339
//  Method: avtDatabase::AddMeshQualityExpressions
//
//  Purpose:
//      Adds the mesh quality expressions for unstructured and structured
//      meshes.
//
//  Programmer: Hank Childs
//  Creation:   November 25, 2003
//
hrchilds's avatar
hrchilds committed
1340
1341
1342
1343
1344
1345
1346
//  Modifications:
//
//    Hank Childs, Mon Dec 15 14:36:03 PST 2003
//    If there are multiple meshes, put each mesh in its own subdirectory 
//    ('4214).  Also, if the meshes are in subdirectories, set them up so that
//    the expressions code will recognize them ('4195).
//
hrchilds's avatar
hrchilds committed
1347
1348
1349
//    Hank Childs, Thu Jul 29 09:30:43 PDT 2004
//    Do not add MQE for nodes or edges.
//
hrchilds's avatar
hrchilds committed
1350
1351
1352
//    Hank Childs, Thu Jan 20 15:47:25 PST 2005
//    Added side volume.
//
hrchilds's avatar
hrchilds committed
1353
1354
1355
//    Hank Childs, Thu May 26 15:45:48 PDT 2005
//    Mark mesh quality expressions as auto-expressions.
//
hrchilds's avatar
hrchilds committed
1356
1357
1358
//    Hank Childs, Thu Sep 22 15:49:34 PDT 2005
//    Change side_volume to min_side_volume.  Add edge length as well.
//
hrchilds's avatar
hrchilds committed
1359
1360
1361
1362
//    Brad Whitlock, Thu Mar 23 09:38:44 PDT 2006
//    Added code to limit the number of meshes that receive mesh quality
//    expressions to 10.
//
1363
1364
//    Mark C. Miller, Tue Apr 15 15:12:26 PDT 2008
//    Eliminated database objects for which hideFromGUI is true
1365
1366
1367
1368
//
//    Hank Childs, Thu Jul 24 13:40:46 PDT 2008
//    Give priority to names with MESH in it.
//
brugger's avatar
   
brugger committed
1369
1370
1371
//    Eric Brugger, Thu Aug  7 08:52:06 PDT 2008
//    Updated for verdict version 110.
//
hrchilds's avatar
hrchilds committed
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
// ****************************************************************************

void
avtDatabase::AddMeshQualityExpressions(avtDatabaseMetaData *md)
{
    struct MQExprTopoPair
    {
        MQExprTopoPair(const char *s, int t) { mq_expr = s; topo = t; };
        MQExprTopoPair() { ; };
        string mq_expr;
        int    topo;
    };

    int nmeshes = md->GetNumMeshes();
1386
1387
1388
1389
    int nmeshes_done = 0;
    int numpasses = 2;
    int total_iterations = numpasses*nmeshes;
    for (int iter = 0 ; iter < total_iterations && nmeshes_done < 10 ; iter++)
hrchilds's avatar
hrchilds committed
1390
    {
1391
1392
1393
        int i    = iter % nmeshes;
        int pass = (iter < nmeshes ? 1 : 2);

hrchilds's avatar
hrchilds committed
1394
1395
        const avtMeshMetaData *mmd = md->GetMesh(i);
        avtMeshType mt = mmd->meshType;
1396

hrchilds's avatar
hrchilds committed
1397
1398
1399
1400
1401
1402
        if (mt != AVT_CURVILINEAR_MESH && mt != AVT_UNSTRUCTURED_MESH &&
            mt != AVT_SURFACE_MESH)
        {
            continue;
        }

hrchilds's avatar
hrchilds committed
1403
1404
1405
1406
        int topoDim = mmd->topologicalDimension;
        if (topoDim == 0 || topoDim == 1)
            continue;

1407
1408
        if (mmd->hideFromGUI)
            continue;
1409

1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
        int pass_for_this_mesh = 2;
        string name = mmd->name;
        if (strstr(name.c_str(), "MESH") != NULL || (strstr(name.c_str(), "mesh") != NULL))
        {
            pass_for_this_mesh = 1;
        }

        if (pass != pass_for_this_mesh)
            continue;

        nmeshes_done++;
hrchilds's avatar
hrchilds committed
1421
        const int nPairs = 24;
hrchilds's avatar
hrchilds committed
1422
1423
1424
1425
1426
1427
1428
1429
        MQExprTopoPair exprs[nPairs];
        exprs[0]  = MQExprTopoPair("area", 2);
        exprs[1]  = MQExprTopoPair("aspect_gamma", 3);
        exprs[2]  = MQExprTopoPair("aspect", -1);
        exprs[3]  = MQExprTopoPair("condition", -1);
        exprs[4]  = MQExprTopoPair("diagonal", 3);
        exprs[5]  = MQExprTopoPair("dimension", 3);
        exprs[6]  = MQExprTopoPair("jacobian", -1);
brugger's avatar
   
brugger committed
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
        exprs[7]  = MQExprTopoPair("max_edge_length", -1);
        exprs[8]  = MQExprTopoPair("max_side_volume", 3);
        exprs[9]  = MQExprTopoPair("maximum_angle", 2);
        exprs[10] = MQExprTopoPair("min_edge_length", -1);
        exprs[11] = MQExprTopoPair("min_side_volume", 3);
        exprs[12] = MQExprTopoPair("minimum_angle", 2);
        exprs[13] = MQExprTopoPair("oddy", -1);
        exprs[14] = MQExprTopoPair("relative_size", -1);
        exprs[15] = MQExprTopoPair("scaled_jacobian", -1);
        exprs[16] = MQExprTopoPair("shape", -1);
        exprs[17] = MQExprTopoPair("shape_and_size", -1);
        exprs[18] = MQExprTopoPair("shear", -1);
        exprs[19] = MQExprTopoPair("skew", -1);
        exprs[20] = MQExprTopoPair("stretch", -1);
        exprs[21] = MQExprTopoPair("taper", -1);
        exprs[22] = MQExprTopoPair("volume", 3);
        exprs[23] = MQExprTopoPair("warpage", 2);
hrchilds's avatar
hrchilds committed
1447

1448
        for (int j = 0 ; j < nPairs ; j++)
hrchilds's avatar
hrchilds committed
1449
        {
1450
            if ((topoDim != exprs[j].topo) && (exprs[j].topo != -1))
hrchilds's avatar
hrchilds committed
1451
1452
1453
1454
1455
                continue;

            Expression new_expr;
            char buff[1024];
            if (nmeshes == 1)
1456
                sprintf(buff, "mesh_quality/%s", exprs[j].mq_expr.c_str());
hrchilds's avatar
hrchilds committed
1457
            else
hrchilds's avatar
hrchilds committed
1458
                sprintf(buff, "mesh_quality/%s/%s", name.c_str(),
1459
                                                    exprs[j].mq_expr.c_str());
hrchilds's avatar
hrchilds committed
1460
            new_expr.SetName(buff);
hrchilds's avatar
hrchilds committed
1461
1462
            bool hasSlash = (strstr(name.c_str(), "/") != NULL);
            if (hasSlash)
1463
                sprintf(buff,"%s(<%s>)",exprs[j].mq_expr.c_str(),name.c_str());
hrchilds's avatar
hrchilds committed
1464
            else
1465
                sprintf(buff,"%s(%s)",exprs[j].mq_expr.c_str(),name.c_str());
hrchilds's avatar
hrchilds committed
1466
1467
            new_expr.SetDefinition(buff);
            new_expr.SetType(Expression::ScalarMeshVar);
hrchilds's avatar
hrchilds committed
1468
            new_expr.SetAutoExpression(true);
hrchilds's avatar
hrchilds committed
1469
1470
1471
1472
1473
1474
            md->AddExpression(&new_expr);
        }
    }
}


hrchilds's avatar
hrchilds committed
1475
1476
1477
1478
1479
1480
1481
1482
1483
// ****************************************************************************
//  Method: avtDatabase::AddTimeDerivativeExpressions
//
//  Purpose:
//      Adds the time derivative expressions for time-varying databases.
//
//  Programmer: Hank Childs
//  Creation:   January 11, 2006
//
hrchilds's avatar
hrchilds committed
1484
1485
1486
1487
1488
//  Modifications:
//
//    Hank Childs, Fri Jun  9 13:57:29 PDT 2006
//    Add default to switch statement.
//
1489
1490
1491
//    Mark C. Miller, Tue Jul 17 11:06:37 PDT 2007
//    Made expressions divided by time difference (instead of assuming unity).
//
1492
1493
//    Mark C. Miller, Tue Apr 15 15:12:26 PDT 2008
//    Eliminated database objects for which hideFromGUI is true
1494
1495
1496
1497
//
//    Mark C. Miller, Thu Feb 12 11:33:59 PST 2009
//    Removed std:: qualification on some STL classes due to use of using
//    statements at top 
hrchilds's avatar
hrchilds committed
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
// ****************************************************************************

void
avtDatabase::AddTimeDerivativeExpressions(avtDatabaseMetaData *md)
{
    int   i, j;

    if (md->GetNumStates() <= 1)
        return;

    int numMeshes = md->GetNumMeshes();
1509
    string base1 = "time_derivative";
1510

hrchilds's avatar
hrchilds committed
1511
1512
1513
1514
    for (i = 0 ; i < numMeshes ; i++)
    {
         const avtMeshMetaData *mmd = md->GetMesh(i);

1515
         string base2;
hrchilds's avatar
hrchilds committed
1516
1517
1518
         if (numMeshes == 1)
             base2 = base1;
         else
1519
             base2 = base1 + string("/") + string(mmd->name);
hrchilds's avatar
hrchilds committed
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543

         avtMeshType mt = mmd->meshType;
         
         bool doConn = false;
         bool doPos  = false;
         switch (mt)
         {
           case AVT_RECTILINEAR_MESH:
             doConn = true;
             break;
           case AVT_CURVILINEAR_MESH:
             doConn = true;
             doPos  = true;
             break;
           case AVT_UNSTRUCTURED_MESH:
             doConn = true;
             doPos  = true;
             break;
           case AVT_POINT_MESH:
             doConn = true;
             break;
           case AVT_AMR_MESH:
             doPos  = true;
             break;
hrchilds's avatar
hrchilds committed
1544
1545
           default:
             break;
hrchilds's avatar
hrchilds committed
1546
1547
1548
1549
1550
1551
         }

         if (!doConn && !doPos)
             continue;

         bool needPrefix = (doPos && doConn);
1552
         string conn_base = base2;
hrchilds's avatar
hrchilds committed
1553
         if (needPrefix)
1554
1555
             conn_base = base2 + string("/") + string("conn_based");
         string pos_base = base2;
hrchilds's avatar
hrchilds committed
1556
         if (needPrefix)
1557
             pos_base = base2 + string("/") + string("pos_based");
hrchilds's avatar
hrchilds committed
1558

1559
1560
1561
1562
1563
     //
     // Define expressions for time and last time to use in denominator of expressions
     //
     if (doConn)
     {
1564
             Expression new_expr;
1565
             string expr_name = conn_base + string("/") + mmd->name + "_time";
1566
1567
1568
1569
1570
1571
1572
1573
             new_expr.SetName(expr_name);
             char buff[1024];
             SNPRINTF(buff, 1024, "time(%s)", mmd->name.c_str());
             new_expr.SetDefinition(buff);
             new_expr.SetType(Expression::ScalarMeshVar);
             new_expr.SetAutoExpression(true);
             md->AddExpression(&new_expr);

1574
1575
             expr_name = conn_base + string("/") + mmd->name + "_lasttime";
             string time_expr_name = conn_base + string("/") + mmd->name + "_time";
1576
1577
             new_expr.SetName(expr_name);
             SNPRINTF(buff, 1024, "conn_cmfe(<[-1]id:%s>, %s)",
1578
             time_expr_name.c_str(), mmd->name.c_str());
1579
1580
1581
1582
             new_expr.SetDefinition(buff);
             new_expr.SetType(Expression::ScalarMeshVar);
             new_expr.SetAutoExpression(true);
             md->AddExpression(&new_expr);
1583
     }