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