1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkXMLPStructuredDataWriter.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkXMLPStructuredDataWriter.h"
16 #include "vtkXMLStructuredDataWriter.h"
17 #include "vtkExecutive.h"
18 #include "vtkErrorCode.h"
19 #include "vtkDataSet.h"
20 #include "vtkInformation.h"
21 #include "vtkInformationVector.h"
22 #include "vtkStreamingDemandDrivenPipeline.h"
23 #include "vtkCommunicator.h"
24 #include "vtkMultiProcessController.h"
25 
26 //----------------------------------------------------------------------------
vtkXMLPStructuredDataWriter()27 vtkXMLPStructuredDataWriter::vtkXMLPStructuredDataWriter()
28 {
29 }
30 
31 //----------------------------------------------------------------------------
~vtkXMLPStructuredDataWriter()32 vtkXMLPStructuredDataWriter::~vtkXMLPStructuredDataWriter()
33 {
34 }
35 
36 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)37 void vtkXMLPStructuredDataWriter::PrintSelf(ostream& os, vtkIndent indent)
38 {
39   this->Superclass::PrintSelf(os,indent);
40 }
41 
42 //----------------------------------------------------------------------------
WriteInternal()43 int vtkXMLPStructuredDataWriter::WriteInternal()
44 {
45   int retVal = this->Superclass::WriteInternal();
46   this->Extents.clear();
47   return retVal;
48 }
49 
50 //----------------------------------------------------------------------------
WritePrimaryElementAttributes(ostream & os,vtkIndent indent)51 void vtkXMLPStructuredDataWriter::WritePrimaryElementAttributes(ostream &os, vtkIndent indent)
52 {
53   int* wExt = this->GetInputInformation(0, 0)->Get(
54     vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
55   this->WriteVectorAttribute("WholeExtent", 6, wExt);
56   this->Superclass::WritePrimaryElementAttributes(os, indent);
57 }
58 
59 //----------------------------------------------------------------------------
WritePPieceAttributes(int index)60 void vtkXMLPStructuredDataWriter::WritePPieceAttributes(int index)
61 {
62   if (this->Extents.find(index) != this->Extents.end())
63     {
64     this->WriteVectorAttribute("Extent", 6, &this->Extents[index][0]);
65     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
66       {
67       return;
68       }
69     }
70   this->Superclass::WritePPieceAttributes(index);
71 }
72 
73 //----------------------------------------------------------------------------
CreatePieceWriter(int index)74 vtkXMLWriter* vtkXMLPStructuredDataWriter::CreatePieceWriter(int index)
75 {
76   vtkXMLStructuredDataWriter* pWriter = this->CreateStructuredPieceWriter();
77   pWriter->SetNumberOfPieces(this->NumberOfPieces);
78   pWriter->SetWritePiece(index);
79   pWriter->SetGhostLevel(this->GhostLevel);
80 
81   return pWriter;
82 }
83 
84 //----------------------------------------------------------------------------
WritePieces()85 int vtkXMLPStructuredDataWriter::WritePieces()
86 {
87   int result = this->Superclass::WritePieces();
88 
89   // The code below gathers extens from all processes to write in the
90   // meta-file. Note that the extent of each piece was already stored by
91   // each writer in WritePiece(). This is gathering it all to root node.
92   if (result)
93     {
94     if (this->Controller)
95       {
96       // Even though the logic is pretty straightforward, we need to
97       // do a fair amount of work to use GatherV. Each rank simply
98       // serializes its extents to 7 int blocks - piece number and 6
99       // extent values. Then we gather this all to root.
100       int rank = this->Controller->GetLocalProcessId();
101       int nRanks = this->Controller->GetNumberOfProcesses();
102 
103       int nPiecesTotal = 0;
104       vtkIdType nPieces = this->Extents.size();
105 
106       vtkIdType* offsets = 0;
107       vtkIdType* nPiecesAll = 0;
108       vtkIdType* recvLengths = 0;
109       if (rank == 0)
110         {
111         nPiecesAll = new vtkIdType[nRanks];
112         recvLengths = new vtkIdType[nRanks];
113         offsets = new vtkIdType[nRanks];
114         }
115       this->Controller->Gather(&nPieces, nPiecesAll, 1, 0);
116       if (rank == 0)
117         {
118         for (int i=0; i<nRanks; i++)
119           {
120           offsets[i] = nPiecesTotal*7;
121           nPiecesTotal += nPiecesAll[i];
122           recvLengths[i] = nPiecesAll[i]*7;
123           }
124         }
125       int* sendBuffer = 0;
126       int sendSize = nPieces*7;
127       if (nPieces > 0)
128         {
129         sendBuffer = new int[sendSize];
130         ExtentsType::iterator iter = this->Extents.begin();
131         for (int count = 0; iter != this->Extents.end(); iter++, count++)
132           {
133           sendBuffer[count*7] = iter->first;
134           memcpy(&sendBuffer[count*7+1], &iter->second[0], 6*sizeof(int));
135           }
136         }
137       int* recvBuffer = 0;
138       if (rank == 0)
139         {
140         recvBuffer = new int[nPiecesTotal*7];
141         }
142       this->Controller->GatherV(sendBuffer, recvBuffer, sendSize,
143         recvLengths, offsets, 0);
144 
145       if (rank == 0)
146         {
147         // Add all received values to Extents.
148         // These are later written in WritePPieceAttributes()
149         for (int i=1; i<nRanks; i++)
150           {
151           for (int j=0; j<nPiecesAll[i]; j++)
152             {
153             int* buffer = recvBuffer + offsets[i] + j*7;
154             this->Extents[*buffer] =
155               std::vector<int>(buffer+1, buffer+7);
156             }
157           }
158         }
159 
160       delete[] nPiecesAll;
161       delete[] recvBuffer;
162       delete[] offsets;
163       delete[] recvLengths;
164       delete[] sendBuffer;
165       }
166     }
167   return result;
168 }
169 
170 //----------------------------------------------------------------------------
WritePiece(int index)171 int vtkXMLPStructuredDataWriter::WritePiece(int index)
172 {
173   int result = this->Superclass::WritePiece(index);
174   if (result)
175     {
176     // Store the extent of this piece in Extents. This is later used
177     // in WritePPieceAttributes to write the summary file.
178     vtkDataSet* input = this->GetInputAsDataSet();
179     int* ext = input->GetInformation()->Get(vtkDataObject::DATA_EXTENT());
180     this->Extents[index] = std::vector<int>(ext, ext+6);
181     }
182   return result;
183 }
184 
185 //----------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)186 int vtkXMLPStructuredDataWriter::ProcessRequest(vtkInformation* request,
187                                                 vtkInformationVector** inputVector,
188                                                 vtkInformationVector* outputVector)
189 {
190   // generate the data
191   if(request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()))
192     {
193     return this->RequestUpdateExtent(request, inputVector, outputVector);
194     }
195 
196   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
197 }
198 
199 //----------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))200 int vtkXMLPStructuredDataWriter::RequestUpdateExtent(
201   vtkInformation *vtkNotUsed(request),
202   vtkInformationVector **inputVector,
203   vtkInformationVector *vtkNotUsed(outputVector))
204 {
205   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
206 
207   // The code below asks for an extent based on the number of pieces and
208   // the first piece. This is mainly for the sake of other filters/writers
209   // that may internally use this writer. Those writers usually delegate
210   // RequestUpdateExtent() to the internal writer and expect it to do the
211   // right thing. Before this change, vtkXMLPStructuredDataWriter did not
212   // bother setting the update extent because it is taken care of by the
213   // vtkXMLStructuredDataWriter during WritePiece() (see vtkXMLPDataWriter).
214   // This is fine when vtkXMLPStructuredDataWriter's input is connected
215   // to the actual pipeline but causes problems when it is not, which happens
216   // in the situation described above. Here I picked the StartPiece as
217   // the default. This will not effect the behavior when writing multiple
218   // pieces because that does its own RequestUpdateExtent with the right
219   // piece information.
220 
221   vtkStreamingDemandDrivenPipeline::SetUpdateExtent(inInfo,
222     this->StartPiece, this->GetNumberOfPieces(), this->GhostLevel);
223 
224   return 1;
225 }
226