1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkRandomPool.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 #include "vtkRandomPool.h"
15 #include "vtkDataArray.h"
16 #include "vtkMersenneTwister.h"
17 #include "vtkMinimalStandardRandomSequence.h"
18 #include "vtkMultiThreader.h"
19 #include "vtkObjectFactory.h"
20 #include "vtkMath.h"
21 #include "vtkNew.h"
22 #include "vtkSMPTools.h"
23
24 #include <cassert>
25
26 vtkStandardNewMacro(vtkRandomPool);
27 vtkCxxSetObjectMacro(vtkRandomPool,Sequence,vtkRandomSequence);
28
29 //----------------------------------------------------------------------------
30 // Static methods to populate a data array.
31 namespace {
32
33 // This method scales all components between (min,max)
34 template <typename T>
35 struct PopulateDA
36 {
37 const double *Pool;
38 T *Array;
39 T Min;
40 T Max;
41
PopulateDA__anona08694e70111::PopulateDA42 PopulateDA(const double *pool, T *array, double min, double max) :
43 Pool(pool), Array(array)
44 {
45 this->Min = static_cast<T>(min);
46 this->Max = static_cast<T>(max);
47 }
48
Initialize__anona08694e70111::PopulateDA49 void Initialize()
50 {
51 }
52
operator ()__anona08694e70111::PopulateDA53 void operator() (vtkIdType dataId, vtkIdType endDataId)
54 {
55 const double *p = this->Pool + dataId;
56 T *array = this->Array + dataId;
57 double range = static_cast<double>(this->Max - this->Min);
58
59 for ( ; dataId < endDataId; ++dataId, ++array, ++p )
60 {
61 *array = this->Min + static_cast<T>( *p * range );
62 }
63 }
64
Reduce__anona08694e70111::PopulateDA65 void Reduce()
66 {
67 }
68
Execute__anona08694e70111::PopulateDA69 static void Execute(const double *pool, T *array, double min, double max,
70 vtkIdType totalSize)
71 {
72 PopulateDA popDA(pool,array,min,max);
73 vtkSMPTools::For(0, totalSize, popDA);
74 }
75 };
76
77 // This method scales a selected component between (min,max)
78 template <typename T>
79 struct PopulateDAComponent
80 {
81 const double *Pool;
82 T *Array;
83 int NumComp;
84 int CompNum;
85 T Min;
86 T Max;
87
PopulateDAComponent__anona08694e70111::PopulateDAComponent88 PopulateDAComponent(const double *pool, T *array, double min, double max,
89 int numComp, int compNum) :
90 Pool(pool), Array(array), NumComp(numComp), CompNum(compNum)
91 {
92 this->Min = static_cast<T>(min);
93 this->Max = static_cast<T>(max);
94 }
95
Initialize__anona08694e70111::PopulateDAComponent96 void Initialize()
97 {
98 }
99
operator ()__anona08694e70111::PopulateDAComponent100 void operator() (vtkIdType tupleId, vtkIdType endTupleId)
101 {
102 int numComp = this->NumComp;
103 const double *p = this->Pool + tupleId*numComp + this->CompNum;
104 T *array = this->Array + tupleId*numComp + this->CompNum;
105 double range = static_cast<double>(this->Max - this->Min);
106
107 for ( ; tupleId < endTupleId; ++tupleId, array+=numComp, p+=numComp )
108 {
109 *array = this->Min + static_cast<T>( *p * range );
110 }
111 }
112
Reduce__anona08694e70111::PopulateDAComponent113 void Reduce()
114 {
115 }
116
Execute__anona08694e70111::PopulateDAComponent117 static void Execute(const double *pool, T *array, double min, double max,
118 vtkIdType size, int numComp, int compNum)
119 {
120 PopulateDAComponent popDAC(pool,array,min,max,numComp,compNum);
121 vtkSMPTools::For(0, size, popDAC);
122 }
123 };
124
125 } //anonymous namespace
126
127 // ----------------------------------------------------------------------------
vtkRandomPool()128 vtkRandomPool::vtkRandomPool()
129 {
130 this->Sequence = vtkMinimalStandardRandomSequence::New();
131 this->Size = 0;
132 this->NumberOfComponents = 1;
133 this->ChunkSize = 10000;
134
135 this->TotalSize = 0;
136 this->Pool = nullptr;
137
138 // Ensure that the modified time > generate time
139 this->GenerateTime.Modified();
140 this->Modified();
141 }
142
143 // ----------------------------------------------------------------------------
~vtkRandomPool()144 vtkRandomPool::~vtkRandomPool()
145 {
146 this->SetSequence(nullptr);
147 delete [] this->Pool;
148 }
149
150 //----------------------------------------------------------------------------
151 void vtkRandomPool::
PopulateDataArray(vtkDataArray * da,double minRange,double maxRange)152 PopulateDataArray(vtkDataArray *da, double minRange, double maxRange)
153 {
154 if ( da == nullptr )
155 {
156 vtkWarningMacro(<<"Bad request");
157 return;
158 }
159
160 vtkIdType size = da->GetNumberOfTuples();
161 int numComp = da->GetNumberOfComponents();
162
163 this->SetSize(size);
164 this->SetNumberOfComponents(numComp);
165 const double *pool = this->GeneratePool();
166 if ( pool == nullptr )
167 {
168 return;
169 }
170
171 // Now perform the scaling of all components
172 void *ptr = da->GetVoidPointer(0);
173 switch (da->GetDataType())
174 {
175 vtkTemplateMacro(PopulateDA<VTK_TT>::
176 Execute(pool, (VTK_TT *)ptr, minRange, maxRange,
177 this->GetTotalSize()));
178 }
179
180 // Make sure that the data array is marked modified
181 da->Modified();
182 }
183
184 //----------------------------------------------------------------------------
185 void vtkRandomPool::
PopulateDataArray(vtkDataArray * da,int compNum,double minRange,double maxRange)186 PopulateDataArray(vtkDataArray *da, int compNum,
187 double minRange, double maxRange)
188 {
189 if ( da == nullptr )
190 {
191 vtkWarningMacro(<<"Bad request");
192 return;
193 }
194
195 vtkIdType size = da->GetNumberOfTuples();
196 int numComp = da->GetNumberOfComponents();
197 compNum = (compNum < 0 ? 0 : (compNum >= numComp ? numComp-1 : compNum));
198
199 this->SetSize(size);
200 this->SetNumberOfComponents(numComp);
201 const double *pool = this->GeneratePool();
202 if ( pool == nullptr )
203 {
204 return;
205 }
206
207 // Now perform the scaling for one of the components
208 void *ptr = da->GetVoidPointer(0);
209 switch (da->GetDataType())
210 {
211 vtkTemplateMacro(PopulateDAComponent<VTK_TT>::
212 Execute(pool, (VTK_TT *)ptr, minRange, maxRange,
213 size, numComp, compNum));
214 }
215
216 // Make sure that the data array is marked modified
217 da->Modified();
218 }
219
220 //----------------------------------------------------------------------------
221 // Support multithreading of sequence generation
222 struct vtkRandomPoolInfo
223 {
224 vtkIdType NumThreads;
225 vtkRandomSequence **Sequencer;
226 double *Pool;
227 vtkIdType SeqSize;
228 vtkIdType SeqChunk;
229 vtkRandomSequence *Sequence;
230
vtkRandomPoolInfovtkRandomPoolInfo231 vtkRandomPoolInfo(double *pool, vtkIdType seqSize, vtkIdType seqChunk,
232 vtkIdType numThreads, vtkRandomSequence *ranSeq) :
233 NumThreads(numThreads), Pool(pool), SeqSize(seqSize), SeqChunk(seqChunk),
234 Sequence(ranSeq)
235 {
236 this->Sequencer = new vtkRandomSequence* [numThreads];
237 for (vtkIdType i=0; i < numThreads; ++i)
238 {
239 this->Sequencer[i] = ranSeq->NewInstance();
240 assert(this->Sequencer[i] != nullptr);
241 this->Sequencer[i]->Initialize(static_cast<vtkTypeUInt32>(i));
242 }
243 }
244
~vtkRandomPoolInfovtkRandomPoolInfo245 ~vtkRandomPoolInfo()
246 {
247 for (vtkIdType i=0; i < this->NumThreads; ++i)
248 {
249 this->Sequencer[i]->Delete();
250 }
251 delete [] this->Sequencer;
252 }
253
254 };
255
256 //----------------------------------------------------------------------------
257 // This is the multithreaded piece of random sequence generation.
vtkRandomPool_ThreadedMethod(void * arg)258 static VTK_THREAD_RETURN_TYPE vtkRandomPool_ThreadedMethod( void *arg )
259 {
260 // Grab input
261 vtkRandomPoolInfo *info;
262 int threadId;
263
264 threadId = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
265 info = (vtkRandomPoolInfo *)
266 (((vtkMultiThreader::ThreadInfo *)(arg))->UserData);
267
268 // Generate subsequence and place into global sequence in correct spot
269 vtkRandomSequence *sequencer = info->Sequencer[threadId];
270 double *pool = info->Pool;
271 vtkIdType i, start = threadId * info->SeqChunk;
272 vtkIdType end = start + info->SeqChunk;
273 end = ( end < info->SeqSize ? end : info->SeqSize );
274 for ( i=start; i < end; ++i, sequencer->Next())
275 {
276 pool[i] = sequencer->GetValue();
277 }
278
279 return VTK_THREAD_RETURN_VALUE;
280 }
281
282
283 // ----------------------------------------------------------------------------
284 // May use threaded sequence generation if the length of the sequence is
285 // greater than a pre-defined work size.
286 const double * vtkRandomPool::
GeneratePool()287 GeneratePool()
288 {
289 // Return if generation has already occurred
290 if ( this->GenerateTime > this->MTime )
291 {
292 return this->Pool;
293 }
294
295 // Check for valid input and correct if necessary
296 this->TotalSize = this->Size * this->NumberOfComponents;
297 if ( this->TotalSize <= 0 || this->Sequence == nullptr )
298 {
299 vtkWarningMacro(<<"Bad pool size");
300 this->Size = this->TotalSize = 1000;
301 this->NumberOfComponents = 1;
302 }
303 this->ChunkSize = ( this->ChunkSize < 1000 ? 1000 : this->ChunkSize );
304 this->Pool = new double [this->TotalSize];
305
306 // Control the number of threads spawned.
307 vtkIdType seqSize = this->TotalSize;
308 vtkIdType seqChunk = this->ChunkSize;
309 vtkIdType numThreads = (seqSize / seqChunk) + 1;
310 vtkRandomSequence *sequencer = this->Sequence;
311
312 // Fast path don't spin up threads
313 if ( numThreads == 1 )
314 {
315 sequencer->Initialize(31415);
316 double *p = this->Pool;
317 for ( vtkIdType i=0; i < seqSize; ++i, sequencer->Next() )
318 {
319 *p++ = sequencer->GetValue();
320 }
321 }
322
323 // Otherwise spawn threads to fill in chunks of the sequence.
324 else
325 {
326 vtkNew<vtkMultiThreader> threader;
327 threader->SetNumberOfThreads(numThreads);
328 vtkIdType actualThreads = threader->GetNumberOfThreads();
329 if ( actualThreads < numThreads) //readjust work load
330 {
331 numThreads = actualThreads;
332 }
333
334 // Now distribute work
335 vtkRandomPoolInfo info(this->Pool, seqSize, seqChunk, numThreads, this->Sequence);
336 threader->SetSingleMethod( vtkRandomPool_ThreadedMethod, (void *)&info);
337 threader->SingleMethodExecute();
338 }//spawning threads
339
340 // Update generation time
341 this->GenerateTime.Modified();
342 return this->Pool;
343 }
344
345 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)346 void vtkRandomPool::PrintSelf(ostream& os, vtkIndent indent)
347 {
348 this->Superclass::PrintSelf(os, indent);
349
350 os << indent << "Sequence: " << this->Sequence << "\n";
351 os << indent << "Size: " << this->Size << "\n";
352 os << indent << "Number Of Components: " << this->NumberOfComponents << "\n";
353 os << indent << "Chunk Size: " << this->ChunkSize << "\n";
354
355 }
356