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