vtkXMLStructuredDataWriter.cxx 19 KB
Newer Older
1
2
3
4
5
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXMLStructuredDataWriter.cxx

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7
8
9
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

10
11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
13
14
15
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkXMLStructuredDataWriter.h"
16

Utkarsh Ayachit's avatar
ENH:    
Utkarsh Ayachit committed
17
#include "vtkArrayIteratorIncludes.h"
18
#include "vtkCellData.h"
19
20
#include "vtkDataArray.h"
#include "vtkDataCompressor.h"
21
#include "vtkDataSet.h"
22
#include "vtkErrorCode.h"
23
24
25
#include "vtkInformation.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationVector.h"
26
#include "vtkPointData.h"
27
#include "vtkStreamingDemandDrivenPipeline.h"
28
29
30
#define vtkXMLOffsetsManager_DoNotInclude
#include "vtkXMLOffsetsManager.h"
#undef  vtkXMLOffsetsManager_DoNotInclude
31
32
33
34

//----------------------------------------------------------------------------
vtkXMLStructuredDataWriter::vtkXMLStructuredDataWriter()
{
35
  this->WritePiece = -1;
36
  this->NumberOfPieces = 1;
37
38
  this->GhostLevel = 0;

39
40
41
  this->WriteExtent[0] = 0; this->WriteExtent[1] = -1;
  this->WriteExtent[2] = 0; this->WriteExtent[3] = -1;
  this->WriteExtent[4] = 0; this->WriteExtent[5] = -1;
42
43
44

  this->CurrentPiece = 0;
  this->ProgressFractions = 0;
45
46
47
  this->FieldDataOM->Allocate(0);
  this->PointDataOM = new OffsetsManagerArray;
  this->CellDataOM  = new OffsetsManagerArray;
48
49
50
51
52
}

//----------------------------------------------------------------------------
vtkXMLStructuredDataWriter::~vtkXMLStructuredDataWriter()
{
53
  delete[] this->ProgressFractions;
54
55
  delete this->PointDataOM;
  delete this->CellDataOM;
56
57
58
59
60
61
62
63
64
65
66
}

//----------------------------------------------------------------------------
void vtkXMLStructuredDataWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "WriteExtent: "
     << this->WriteExtent[0] << " " << this->WriteExtent[1] << "  "
     << this->WriteExtent[2] << " " << this->WriteExtent[3] << "  "
     << this->WriteExtent[4] << " " << this->WriteExtent[5] << "\n";
  os << indent << "NumberOfPieces" << this->NumberOfPieces << "\n";
67
  os << indent << "WritePiece: " << this->WritePiece << "\n";
68
69
70
}

//----------------------------------------------------------------------------
71
void vtkXMLStructuredDataWriter::SetInputUpdateExtent(int piece)
72
{
73
  vtkInformation* inInfo =
74
    this->GetExecutive()->GetInputInformation(0, 0);
75
76
77
78
79
80
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
    piece);
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
    this->NumberOfPieces);
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
    this->GhostLevel);
81
  if ((this->WriteExtent[0] == 0) && (this->WriteExtent[1] == -1) &&
82
83
84
85
86
87
88
89
90
91
92
93
94
     (this->WriteExtent[2] == 0) && (this->WriteExtent[3] == -1) &&
     (this->WriteExtent[4] == 0) && (this->WriteExtent[5] == -1))
    {
    inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
      inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()),
      6);
    }
  else
    {
    inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
      this->WriteExtent, 6);
    }
  inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
95
96
97
98
99
100
101
102
103
}

//----------------------------------------------------------------------------
int vtkXMLStructuredDataWriter::ProcessRequest(
  vtkInformation* request,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{

104
  if (request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_INFORMATION()))
105
106
107
108
109
110
111
112
    {
    if (this->WritePiece >= 0)
      {
      this->CurrentPiece = this->WritePiece;
      }
    return 1;
    }

113
  if (request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()))
114
    {
115
    this->SetInputUpdateExtent(this->CurrentPiece);
116
117

    return 1;
118
    }
119

120
  // generate the data
121
  else if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
122
    {
123
124
    this->SetErrorCode(vtkErrorCode::NoError);

125
    if (!this->Stream && !this->FileName && !this->WriteToOutputString)
126
127
      {
      this->SetErrorCode(vtkErrorCode::NoFileNameError);
128
129
      vtkErrorMacro("The FileName or Stream must be set first or "
        "the output must be written to a string.");
130
131
132
      return 0;
      }

133
134
135
136
137
138
139
140
    // We are just starting to write.  Do not call
    // UpdateProgressDiscrete because we want a 0 progress callback the
    // first time.
    this->UpdateProgress(0);

    // Initialize progress range to entire 0..1 range.
    float wholeProgressRange[2] = {0,1};
    this->SetProgressRange(wholeProgressRange, 0, 1);
141

142
    int result = 1;
143
    if ((this->CurrentPiece == 0 || this->WritePiece >= 0) && this->CurrentTimeIndex == 0 )
144
      {
145
      if (!this->OpenStream())
146
147
148
        {
        return 0;
        }
149
      if (this->GetInputAsDataSet() != NULL &&
150
151
          (this->GetInputAsDataSet()->GetPointGhostArray() != NULL ||
           this->GetInputAsDataSet()->GetCellGhostArray() != NULL))
152
        {
153
154
        // use the current version for the file
        this->UsePreviousVersion = false;
155
        }
156
157
158
159
160
161
162
163
164
165
      // Write the file.
      if (!this->StartFile())
        {
        return 0;
        }

      if (!this->WriteHeader())
        {
        return 0;
        }
166

167
      this->CurrentTimeIndex = 0;
168
      if (this->DataMode == vtkXMLWriter::Appended && this->FieldDataOM->GetNumberOfElements())
169
170
171
        {
        // Write the field data arrays.
        this->WriteFieldDataAppendedData(this->GetInput()->GetFieldData(),
172
          this->CurrentTimeIndex, this->FieldDataOM);
173
174
175
176
177
178
        if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
          {
          this->DeletePositionArrays();
          return 0;
          }
        }
179
      }
180

181
    if (!(this->UserContinueExecuting == 0)) //if user ask to stop do not try to write a piece
182
183
184
      {
      result = this->WriteAPiece();
      }
185

186
    if (this->WritePiece < 0)
187
      {
188
189
190
191
192
193
      // Tell the pipeline to start looping.
      if (this->CurrentPiece == 0)
        {
        request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1);
        }
      this->CurrentPiece++;
194
      }
195

196
    if (this->CurrentPiece == this->NumberOfPieces || this->WritePiece >= 0)
197
198
199
      {
      request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING());
      this->CurrentPiece = 0;
Mathieu Malaterre's avatar
Mathieu Malaterre committed
200
       // We are done writing all the pieces, lets loop over time now:
201
      this->CurrentTimeIndex++;
202

203
      if (this->UserContinueExecuting != 1)
204
        {
205
206
207
208
        if (!this->WriteFooter())
          {
          return 0;
          }
209

210
211
212
213
        if (!this->EndFile())
          {
          return 0;
          }
214

215
        this->CloseStream();
216
        this->CurrentTimeIndex = 0; // Reset
217
        }
218
219
220
221
222
223
224
      }

    // We have finished writing.
    this->UpdateProgressDiscrete(1);
    return result;
    }
  return this->Superclass::ProcessRequest(request, inputVector, outputVector);
225
226
}

227

228
//----------------------------------------------------------------------------
229
230
void vtkXMLStructuredDataWriter::AllocatePositionArrays()
{
231
232
  this->ExtentPositions = new vtkTypeInt64[this->NumberOfPieces];

233
234
  // Prepare storage for the point and cell data array appended data
  // offsets for each piece.
235
236
  this->PointDataOM->Allocate(this->NumberOfPieces);
  this->CellDataOM->Allocate(this->NumberOfPieces);
237
238
239
240
241
}

//----------------------------------------------------------------------------
void vtkXMLStructuredDataWriter::DeletePositionArrays()
{
242
243
  delete[] this->ExtentPositions;
  this->ExtentPositions = NULL;
244
245
246
247
248
249
250
251
}

//----------------------------------------------------------------------------
int vtkXMLStructuredDataWriter::WriteHeader()
{
  vtkIndent indent = vtkIndent().GetNextIndent();

  ostream& os = *(this->Stream);
252

253
  if (!this->WritePrimaryElement(os, indent))
254
255
256
257
    {
    return 0;
    }

258
259
  this->WriteFieldData(indent.GetNextIndent());

260
  if (this->DataMode == vtkXMLWriter::Appended)
261
    {
262
263
264
265
266
267
268
    int begin = this->WritePiece;
    int end = this->WritePiece + 1;
    if (this->WritePiece < 0)
      {
      begin = 0;
      end = this->NumberOfPieces;
      }
269
    vtkIndent nextIndent = indent.GetNextIndent();
270

271
272
273
    this->AllocatePositionArrays();

    // Loop over each piece and write its structure.
274
    for (int i=begin; i < end; ++i)
275
276
277
278
      {
      // Update the piece's extent.

      os << nextIndent << "<Piece";
279
280
281
      // We allocate 66 characters because that is as big as 6 integers
      // with spaces can get.
      this->ExtentPositions[i] = this->ReserveAttributeSpace("Extent", 66);
282
      os << ">\n";
283

284
285
286
287
288
      if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
        {
        this->DeletePositionArrays();
        return 0;
        }
289

290
      this->WriteAppendedPiece(i, nextIndent.GetNextIndent());
291

292
293
294
295
296
297
298
299
300
301
302
      if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
        {
        this->DeletePositionArrays();
        return 0;
        }
      // Close the piece's element.
      os << nextIndent << "</Piece>\n";
      }

    // Close the primary element.
    os << indent << "</" << this->GetDataSetName() << ">\n";
303

304
305
    os.flush();
    if (os.fail())
306
      {
307
308
      this->DeletePositionArrays();
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
309
310
      return 0;
      }
311
312

    this->StartAppendedData();
313
314
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
315
      this->DeletePositionArrays();
316
317
      return 0;
      }
318
    }
319

320
321
  // Split progress of the data write by the fraction contributed by
  // each piece.
322
  float progressRange[2] = { 0.f, 0.f };
323
  this->GetProgressRange(progressRange);
324
325
326
327
328
329
330
331
332
333
  this->ProgressFractions = new float[this->NumberOfPieces+1];
  this->CalculatePieceFractions(this->ProgressFractions);

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLStructuredDataWriter::WriteAPiece()
{
  vtkIndent indent = vtkIndent().GetNextIndent();
334
  int result = 1;
335

336
  if (this->DataMode == vtkXMLWriter::Appended)
337
    {
338
339
    vtkDataSet* input = this->GetInputAsDataSet();

340
    // Make sure input is valid.
341
    if (input->CheckAttributes() == 0)
342
      {
343
      this->WriteAppendedPieceData(this->CurrentPiece);
344

345
346
      if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
        {
347
        this->DeletePositionArrays();
348
349
        return 0;
        }
350
351
352
      }
    else
      {
353
354
      vtkErrorMacro("Input is invalid for piece "
                    << this->CurrentPiece
355
                    << ".  Aborting.");
356
357
      result = 0;
      }
358
    }
359
  else
360
    {
361
    this->WriteInlineMode(indent);
362
    }
363

364
  return result;
365
366
367
}

//----------------------------------------------------------------------------
368
int vtkXMLStructuredDataWriter::WriteFooter()
369
{
370
371
  vtkIndent indent = vtkIndent().GetNextIndent();

372
  ostream& os = *(this->Stream);
373

374
  if (this->DataMode == vtkXMLWriter::Appended)
375
    {
376
377
    this->DeletePositionArrays();
    this->EndAppendedData();
378
    }
379
380
381
382
  else
    {
    // Close the primary element.
    os << indent << "</" << this->GetDataSetName() << ">\n";
383

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    os.flush();
    if (os.fail())
      {
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    }

  delete[] this->ProgressFractions;
  this->ProgressFractions = 0;

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLStructuredDataWriter::WriteInlineMode(vtkIndent indent)
{
  vtkDataSet* input = this->GetInputAsDataSet();
  ostream& os = *(this->Stream);

403
  int* extent = input->GetInformation()->Get(vtkDataObject::DATA_EXTENT());
404

405
406
  // Split progress of the data write by the fraction contributed by
  // each piece.
407
  float progressRange[2] = { 0.f, 0.f };
408
  this->GetProgressRange(progressRange);
409

410
  // Write each piece's XML and data.
411
  int result = 1;
412
413
414

  // Set the progress range for this piece.
  this->SetProgressRange(progressRange, this->CurrentPiece, this->ProgressFractions);
415

416
  // Make sure input is valid.
417
  if (input->CheckAttributes() == 0)
418
419
420
421
    {
    os << indent << "<Piece";
    this->WriteVectorAttribute("Extent", 6, extent);
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
422
      {
423
424
      return 0;
      }
425

426
    os << ">\n";
427

428
429
    this->WriteInlinePiece(indent.GetNextIndent());
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
430
      {
431
      return 0;
432
      }
433
    os << indent << "</Piece>\n";
434
    }
435
  else
436
    {
437
    vtkErrorMacro("Input is invalid for piece " << this->CurrentPiece << ".  Aborting.");
438
439
    result = 0;
    }
440

441
  return result;
442
443
444
}

//----------------------------------------------------------------------------
Utkarsh Ayachit's avatar
ENH:    
Utkarsh Ayachit committed
445
template <class iterT>
446
inline void vtkXMLStructuredDataWriterCopyTuples(
Utkarsh Ayachit's avatar
ENH:    
Utkarsh Ayachit committed
447
448
449
450
451
452
453
  iterT* destIter, vtkIdType destTuple,
  iterT* srcIter, vtkIdType sourceTuple,
  vtkIdType numTuples)
{
  // for all contiguous-fixed component size arrays (except Bit).
  int tupleSize = (srcIter->GetDataTypeSize() *
                   srcIter->GetNumberOfComponents());
454

Utkarsh Ayachit's avatar
ENH:    
Utkarsh Ayachit committed
455
456
457
458
459
  memcpy(destIter->GetTuple(destTuple), srcIter->GetTuple(sourceTuple),
    numTuples*tupleSize);
}

//----------------------------------------------------------------------------
460
inline void vtkXMLStructuredDataWriterCopyTuples(
Utkarsh Ayachit's avatar
ENH:    
Utkarsh Ayachit committed
461
462
463
464
465
466
467
  vtkArrayIteratorTemplate<vtkStdString>* destIter, vtkIdType destTuple,
  vtkArrayIteratorTemplate<vtkStdString>* srcIter, vtkIdType sourceTuple,
  vtkIdType numTuples)
{
  vtkIdType numValues = numTuples * srcIter->GetNumberOfComponents();
  vtkIdType destIndex = destTuple * destIter->GetNumberOfComponents();
  vtkIdType srcIndex = sourceTuple * srcIter->GetNumberOfComponents();
468

469
  for (vtkIdType cc = 0; cc < numValues; cc++)
Utkarsh Ayachit's avatar
ENH:    
Utkarsh Ayachit committed
470
471
472
473
474
475
    {
    destIter->GetValue(destIndex++) = srcIter->GetValue(srcIndex++);
    }
}

//----------------------------------------------------------------------------
476
477
void vtkXMLStructuredDataWriter::WritePrimaryElementAttributes(ostream &os,
                                                               vtkIndent indent)
478
{
479
  this->Superclass::WritePrimaryElementAttributes(os, indent);
480

481
  int* ext = this->WriteExtent;
482
  if ((this->WriteExtent[0] == 0) && (this->WriteExtent[1] == -1) &&
483
484
     (this->WriteExtent[2] == 0) && (this->WriteExtent[3] == -1) &&
     (this->WriteExtent[4] == 0) && (this->WriteExtent[5] == -1))
485
    {
486
487
    ext = this->GetInputInformation(0, 0)->Get(
      vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
488
    }
489
490

  if (this->WritePiece >= 0)
491
    {
492
493
    vtkDataSet* input = this->GetInputAsDataSet();
    ext = input->GetInformation()->Get(vtkDataObject::DATA_EXTENT());
494
    }
495

496
  this->WriteVectorAttribute("WholeExtent", 6, ext);
497
498
499
500
501
502
503
}

//----------------------------------------------------------------------------
void vtkXMLStructuredDataWriter::WriteAppendedPiece(int index,
                                                    vtkIndent indent)
{
  // Write the point data and cell data arrays.
504
  vtkDataSet* input = this->GetInputAsDataSet();
505
  this->WritePointDataAppended(input->GetPointData(), indent,
506
    &this->PointDataOM->GetPiece(index));
Mathieu Malaterre's avatar
Mathieu Malaterre committed
507
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
508
509
510
    {
    return;
    }
511
  this->WriteCellDataAppended(input->GetCellData(), indent,
512
    &this->CellDataOM->GetPiece(index));
Mathieu Malaterre's avatar
Mathieu Malaterre committed
513
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
514
515
516
    {
    return;
    }
517
518
519
520
}

//----------------------------------------------------------------------------
void vtkXMLStructuredDataWriter::WriteAppendedPieceData(int index)
521
{
522
  // Write the point data and cell data arrays.
523
  vtkDataSet* input = this->GetInputAsDataSet();
524

525
526
527
528
529
530
531
532
533
534
535
536
537
  int* ext = input->GetInformation()->Get(vtkDataObject::DATA_EXTENT());

  ostream& os = *(this->Stream);

  std::streampos returnPosition = os.tellp();
  os.seekp(std::streampos(this->ExtentPositions[index]));
  this->WriteVectorAttribute("Extent", 6, ext);
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    return;
    }
  os.seekp(returnPosition);

538
  // Split progress between point data and cell data arrays.
539
  float progressRange[2] = { 0.f, 0.f };
540
541
542
543
544
545
  this->GetProgressRange(progressRange);
  int pdArrays = input->GetPointData()->GetNumberOfArrays();
  int cdArrays = input->GetCellData()->GetNumberOfArrays();
  int total = (pdArrays+cdArrays)? (pdArrays+cdArrays):1;
  float fractions[3] =
    {
546
547
548
    0,
    static_cast<float>(pdArrays) / total,
    1
549
    };
550

551
552
  // Set the range of progress for the point data arrays.
  this->SetProgressRange(progressRange, 0, fractions);
553
554
  this->WritePointDataAppendedData(input->GetPointData(), this->CurrentTimeIndex,
                                   &this->PointDataOM->GetPiece(index));
555
556
557
558
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    return;
    }
559

560
561
  // Set the range of progress for the cell data arrays.
  this->SetProgressRange(progressRange, 1, fractions);
562
563
  this->WriteCellDataAppendedData(input->GetCellData(), this->CurrentTimeIndex,
                                  &this->CellDataOM->GetPiece(index));
564
565
566
}

//----------------------------------------------------------------------------
567
void vtkXMLStructuredDataWriter::WriteInlinePiece(vtkIndent indent)
568
569
{
  // Write the point data and cell data arrays.
570
  vtkDataSet* input = this->GetInputAsDataSet();
571

572
  // Split progress between point data and cell data arrays.
573
  float progressRange[2] = { 0.f, 0.f };
574
575
576
577
578
579
580
581
582
583
  this->GetProgressRange(progressRange);
  int pdArrays = input->GetPointData()->GetNumberOfArrays();
  int cdArrays = input->GetCellData()->GetNumberOfArrays();
  int total = (pdArrays+cdArrays)? (pdArrays+cdArrays):1;
  float fractions[3] =
    {
      0,
      float(pdArrays)/total,
      1
    };
584

585
586
  // Set the range of progress for the point data arrays.
  this->SetProgressRange(progressRange, 0, fractions);
587
  this->WritePointDataInline(input->GetPointData(), indent);
588
589
590
591
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    return;
    }
592

593
594
  // Set the range of progress for the cell data arrays.
  this->SetProgressRange(progressRange, 1, fractions);
595
596
597
598
  this->WriteCellDataInline(input->GetCellData(), indent);
}

//----------------------------------------------------------------------------
599
600
601
vtkIdType vtkXMLStructuredDataWriter::GetStartTuple(int* extent,
                                                    vtkIdType* increments,
                                                    int i, int j, int k)
602
603
604
605
606
607
{
  return (((i - extent[0]) * increments[0]) +
          ((j - extent[2]) * increments[1]) +
          ((k - extent[4]) * increments[2]));
}

608
609
610
611
612
//----------------------------------------------------------------------------
void vtkXMLStructuredDataWriter::CalculatePieceFractions(float* fractions)
{
  // Calculate the fraction of total data contributed by each piece.
  fractions[0] = 0;
613
  for (int i = 0; i < this->NumberOfPieces;++i)
614
    {
615
    int extent[6];
616
    this->GetInputExtent(extent);
617

618
619
620
621
622
    // Add this piece's size to the cumulative fractions array.
    fractions[i+1] = fractions[i] + ((extent[1]-extent[0]+1)*
                                     (extent[3]-extent[2]+1)*
                                     (extent[5]-extent[4]+1));
    }
623
  if (fractions[this->NumberOfPieces] == 0)
624
625
626
    {
    fractions[this->NumberOfPieces] = 1;
    }
627
  for (int i = 0; i < this->NumberOfPieces; ++i)
628
629
630
631
    {
    fractions[i+1] = fractions[i+1] / fractions[this->NumberOfPieces];
    }
}