1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPLSDynaReader.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 /*----------------------------------------------------------------------------
16  Copyright (c) Sandia Corporation
17  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19 
20 // NOTE TO DEVELOPERS: ========================================================
21 //
22 // This is a parallel version of the LSDynaReader.
23 // Its primary tasks are to determine which parts should be read on each process
24 // and to send the relevant information from the master node to all slave nodes
25 
26 #include "vtkPLSDynaReader.h"
27 #include "LSDynaFamily.h"
28 #include "LSDynaMetaData.h"
29 #include "vtkLSDynaPartCollection.h"
30 
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkIntArray.h"
34 #include "vtkMultiBlockDataSet.h"
35 #include "vtkMultiProcessController.h"
36 #include "vtkObjectFactory.h"
37 #include "vtkStreamingDemandDrivenPipeline.h"
38 #include "vtkUnstructuredGrid.h"
39 
40 vtkStandardNewMacro(vtkPLSDynaReader);
41 
42 struct vtkPLSDynaReader::vtkPLSDynaReaderInternal
43 {
44   unsigned int MinDataset;
45   unsigned int MaxDataset;
46   unsigned int UpdatePiece;
47   unsigned int UpdateNumPieces;
48 
49   vtkIdType NumProcesses;
50   vtkIdType ProcessRank;
51 
vtkPLSDynaReaderInternalvtkPLSDynaReader::vtkPLSDynaReaderInternal52   vtkPLSDynaReaderInternal()
53     : MinDataset(0)
54     , MaxDataset(0)
55     , UpdatePiece(0)
56     , UpdateNumPieces(0)
57   {
58   }
59 };
60 
61 //------------------------------------------------------------------------------
vtkPLSDynaReader()62 vtkPLSDynaReader::vtkPLSDynaReader()
63 {
64   this->Controller = nullptr;
65 
66   // need to construct the internal datastructure before call SetController
67   this->Internal = new vtkPLSDynaReader::vtkPLSDynaReaderInternal();
68   this->SetController(vtkMultiProcessController::GetGlobalController());
69 }
70 
71 //------------------------------------------------------------------------------
~vtkPLSDynaReader()72 vtkPLSDynaReader::~vtkPLSDynaReader()
73 {
74   this->SetController(nullptr);
75 
76   delete this->Internal;
77 }
78 
PrintSelf(ostream & os,vtkIndent indent)79 void vtkPLSDynaReader::PrintSelf(ostream& os, vtkIndent indent)
80 {
81   os << indent << "Controller: " << this->Controller << endl;
82   this->Superclass::PrintSelf(os, indent);
83 }
84 
85 //------------------------------------------------------------------------------
SetController(vtkMultiProcessController * c)86 void vtkPLSDynaReader::SetController(vtkMultiProcessController* c)
87 {
88   if ((c == nullptr) || (c->GetNumberOfProcesses() == 0))
89   {
90     this->Internal->NumProcesses = 1;
91     this->Internal->ProcessRank = 0;
92   }
93 
94   if (this->Controller == c)
95   {
96     return;
97   }
98 
99   this->Modified();
100 
101   if (this->Controller)
102   {
103     this->Controller->UnRegister(this);
104     this->Controller = nullptr;
105   }
106 
107   if (c == nullptr)
108   {
109     return;
110   }
111 
112   this->Controller = c;
113 
114   c->Register(this);
115   this->Internal->NumProcesses = c->GetNumberOfProcesses();
116   this->Internal->ProcessRank = c->GetLocalProcessId();
117 }
118 
119 //------------------------------------------------------------------------------
CanReadFile(const char * fname)120 int vtkPLSDynaReader::CanReadFile(const char* fname)
121 {
122   return this->Superclass::CanReadFile(fname);
123 }
124 
125 //------------------------------------------------------------------------------
RequestInformation(vtkInformation * request,vtkInformationVector ** iinfo,vtkInformationVector * outputVector)126 int vtkPLSDynaReader::RequestInformation(
127   vtkInformation* request, vtkInformationVector** iinfo, vtkInformationVector* outputVector)
128 {
129   vtkInformation* outInfo = outputVector->GetInformationObject(0);
130 
131   // call the parents request information on all the nodes.
132   // This is not optimal, but sooo much information is stored in the
133   // metadata that is read during request information that sending it over the wire
134   // might not be faster than each node contending for the info. Plus it would
135   // be a massive chunk of code
136   this->Superclass::RequestInformation(request, iinfo, outputVector);
137 
138   outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
139   return 1;
140 }
141 
142 //------------------------------------------------------------------------------
RequestData(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)143 int vtkPLSDynaReader::RequestData(
144   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
145 {
146   // get the information needed to determine which subsection of the full
147   // data set we need to load
148   vtkInformation* outInfo = outputVector->GetInformationObject(0);
149   this->Internal->UpdatePiece =
150     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
151   this->Internal->UpdateNumPieces =
152     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
153 
154   return this->Superclass::RequestData(request, inputVector, outputVector);
155 }
156 
157 //------------------------------------------------------------------------------
ReadTopology()158 int vtkPLSDynaReader::ReadTopology()
159 {
160   bool readTopology = false;
161   if (!this->Parts)
162   {
163     readTopology = true;
164     this->Parts = vtkLSDynaPartCollection::New();
165     vtkIdType* minCellIds = new vtkIdType[LSDynaMetaData::NUM_CELL_TYPES];
166     vtkIdType* maxCellIds = new vtkIdType[LSDynaMetaData::NUM_CELL_TYPES];
167     this->GetPartRanges(minCellIds, maxCellIds);
168 
169     this->Parts->InitCollection(this->P, minCellIds, maxCellIds);
170     delete[] minCellIds;
171     delete[] maxCellIds;
172   }
173   if (!readTopology)
174   {
175     return 0;
176   }
177 
178   if (this->ReadPartSizes())
179   {
180     vtkErrorMacro("Could not read cell sizes.");
181     return 1;
182   }
183 
184   if (this->ReadConnectivityAndMaterial())
185   {
186     vtkErrorMacro("Could not read connectivity.");
187     return 1;
188   }
189 
190   // finalize the topology on each process, each process will remove
191   // any part that it doesn't have a cell for.
192   this->Parts->FinalizeTopology();
193 
194   if (this->ReadNodes())
195   {
196     vtkErrorMacro("Could not read static node values.");
197     return 1;
198   }
199 
200   // we need to read the user ids after we have read the topology
201   // so we know how many cells are in each part
202   if (this->ReadUserIds())
203   {
204     vtkErrorMacro("Could not read user node/element IDs.");
205     return 1;
206   }
207 
208   return 0;
209 }
210 
211 //------------------------------------------------------------------------------
212 // determine which parts will be read by this processor
GetPartRanges(vtkIdType * mins,vtkIdType * maxs)213 void vtkPLSDynaReader::GetPartRanges(vtkIdType* mins, vtkIdType* maxs)
214 {
215   // 1 == load the whole data
216   // determine which domains in this mesh this processor is responsible for
217   if (this->Internal->UpdateNumPieces > 1)
218   {
219     double numCells;
220     for (int i = 0; i < LSDynaMetaData::NUM_CELL_TYPES; ++i)
221     {
222       numCells = static_cast<double>(this->P->NumberOfCells[i]);
223       if (numCells > 1000)
224       {
225         double percent = (1.0 / this->Internal->UpdateNumPieces) * numCells;
226         mins[i] = static_cast<vtkIdType>(percent * this->Internal->UpdatePiece);
227         maxs[i] = static_cast<vtkIdType>(percent * (this->Internal->UpdatePiece + 1));
228       }
229       else
230       {
231         // else not enough cells to worth dividing the reading
232         mins[i] = 0;
233         maxs[i] = static_cast<vtkIdType>((this->Internal->ProcessRank == 0) ? numCells : 0);
234       }
235     }
236   }
237   else
238   {
239     for (int i = 0; i < LSDynaMetaData::NUM_CELL_TYPES; ++i)
240     {
241       mins[i] = 0;
242       maxs[i] = this->P->NumberOfCells[i];
243     }
244   }
245 }
246