Range.hpp

00001 #ifndef __FIBEROPERATIONS_RANGE_HPP
00002 #define __FIBEROPERATIONS_RANGE_HPP
00003 
00004 #include <field/MemBase.hpp>
00005 #include <grid/Representation.hpp>
00006 #include "fiberopDllApi.h"
00007 
00008 #ifdef  USE_OPENMP
00009 #include <omp.h>
00010 #endif
00011 
00012 #include <algorithm>
00013 
00014 namespace Fiber
00015 {
00016 
00020 struct  fiberop_API DataRangeBase : public Interface<DataRangeBase>, public MemCore::Ageable
00021 {
00022         struct fiberop_API NoDataRange : std::exception
00023         {
00024                 ~NoDataRange() throw (); 
00025 
00026                 override const char*what() const throw();
00027         }; 
00028 
00030         DataRangeBase(); 
00031 
00033         DataRangeBase(const MemCore::Ageable&Age);
00034 
00036         virtual ~DataRangeBase() = 0; 
00037 
00039         virtual void expandRange(const RefPtr<DataRangeBase>&DRB) = 0;
00040 };
00041 
00045 template <class Type>
00046 struct  fiberop_API  DataRange : DataRangeBase
00047 {
00048         Type    Minimum, Maximum;
00049 
00050 public: 
00052         DataRange()
00053         {} 
00054 
00056         const Type&Min() const
00057         {
00058                 return Minimum;
00059         } 
00060 
00062         const Type&Max() const
00063         {
00064                 return Maximum;
00065         } 
00066 
00068         template <class OtherType>
00069         DataRange(const DataRange<OtherType>&DR)
00070         : Minimum(DR.Min() )
00071         , Maximum(DR.Max() )
00072         {}
00073 
00075         template <class OtherType>
00076         void    expand(const DataRange<OtherType>&DR)
00077         {
00078                 if (Minimum > DR.Min() ) Minimum = DR.Min(); 
00079                 if (Maximum < DR.Max() ) Maximum = DR.Max(); 
00080                 update( DR );
00081         }
00082 
00084         override void expandRange(const RefPtr<DataRangeBase>&DRB)
00085         {
00086                 if (RefPtr<DataRange<Type> > DR = DRB)
00087                 {
00088                         expand(*DR);
00089                 }
00090         } 
00091 
00095         template <class CompareType>
00096         bool    contains(const CompareType&Value) const
00097         {
00098                 if (Value<Minimum) return false;
00099                 if (Value>Maximum) return false;
00100                 return true;
00101         } 
00102 
00107 static  RefPtr<DataRange> get(CreativeArrayBase&CAB)
00108         {
00109                 if (RefPtr<DataRange> DR = interface_cast<DataRange>(CAB) )
00110                 {
00111                         if ( !DR->isOlderThan( CAB ) )
00112                                 return DR;
00113                 }
00114 
00115                 return NullPtr();
00116         }
00117 
00122 static  RefPtr<DataRange> get(Field&F)
00123         {
00124                 if (RefPtr<DataRange> DR = interface_cast<DataRange>(F) )
00125                 {
00126                         if ( !DR->isOlderThan( F ) )
00127                                 return DR;
00128                 }
00129 
00130                 return NullPtr();
00131         } 
00132 
00136 static  RefPtr<DataRange> compute(CreativeArrayBase&CAB)
00137         {
00138         RefPtr<MemBase> ArrayBase = CAB.create();
00139         RefPtr<TypedArray<Type> > DataArray = ArrayBase;
00140                 if (!DataArray)
00141                         return NullPtr();
00142 
00143         CreativeIterator<Type>*values = DataArray->creativeIterator();
00144                 if (!values)
00145                         return NullPtr();
00146 
00147                 if (!*values)
00148                 {
00149                         return NullPtr();
00150                 }
00151         const Iterator<Type>&Data = *values;
00152 
00153         index_t count = Data.count();
00154                 if (count<1)
00155                         return NullPtr(); 
00156 
00157 //              printf("MINMAX ELEMENTS: %ld\n", count);
00158 
00159         RefPtr<DataRange> DR = new DataRange();
00160 
00161         Type    &MinValue = DR->Minimum,
00162                 &MaxValue = DR->Maximum;
00163                 MinValue = MaxValue = Data[ 0 ]; 
00164 
00165 #ifdef  USE_OPENMP
00166         // parallel version 
00167 
00168         const int max_threads_possible =  omp_get_max_threads(); 
00169 
00170         // stl container (write access) is not thread safe, so every thread gets its own element
00171         std::vector<Type> minList(max_threads_possible); 
00172         std::vector<Type> maxList(max_threads_possible); 
00173 
00174         std::vector<int> valueFound(max_threads_possible);
00175 
00176                 for(int i=0; i<max_threads_possible; i++)
00177                 {
00178                         valueFound[i] = 0;      
00179                 }
00180 
00181 
00182                 #pragma omp parallel
00183                 {
00184                 Type localMin = Data[0];
00185                 Type localMax = Data[0]; 
00186 
00187                         //#pragma omp for shared( Data, minList, maxList, minFound, maxFound)
00188                         #pragma omp for
00189                         for(index_t i = 1; i<count ; i++)
00190                         {
00191                                 // printf("Executing index i=%i in thread %i of %i\n", i, omp_get_thread_num(), omp_get_num_threads()); 
00192                         
00193                         const Type&value = Data[i]; 
00194                                 if (value < localMin) localMin = value; 
00195                                 if (value > localMax) localMax = value;
00196                         } 
00197 
00198                         const int my_thread_id = omp_get_thread_num(); 
00199 
00200                                 minList[my_thread_id] = localMin; 
00201                                 maxList[my_thread_id] = localMax; 
00202 
00203                                 valueFound[my_thread_id] = 1;
00204                 } 
00205                 // parallel execution ends 
00206 
00207                 // ... variables declared locally within a structured block or a routine 
00208                 // that is invoked from within a parallel region are private by default. 
00209 
00210                         for( int i=0; i<max_threads_possible; i++)
00211                         {
00212                                 if( valueFound[i] == 1 )
00213                                 {       
00214                                         if( minList[i] < MinValue ) MinValue = minList[i]; 
00215                                         if( maxList[i] > MaxValue ) MaxValue = maxList[i];
00216                                 } 
00217                         }          
00218 #else
00219                 // straight forward version
00220                 for(index_t i=1; i<count ; i++)
00221                 {
00222                 const Type&value = Data[i];
00223                         if (value < MinValue) MinValue = value;
00224                         if (value > MaxValue) MaxValue = value;
00225                 } 
00226 #endif 
00227 //              std::cout << " Min = " << MinValue << std::endl; 
00228 //              std::cout << " Max = " << MaxValue << std::endl;
00229 
00230                 CAB.addInterface( DR ); 
00231                 DR->update( CAB ); 
00232 
00233                 return DR;
00234         }
00235 
00236 static  RefPtr<DataRange> retrieve(CreativeArrayBase&CAB)
00237         {
00238         RefPtr<DataRange> DR = get(CAB);
00239                 if (DR) return DR;
00240 
00241                 return compute(CAB);
00242         }
00243 };
00244 
00245 
00246 template <class Type>
00247 struct  FieldRange : Field::Iterator
00248 {
00249         RefPtr<DataRange<Type> > theRange;
00250 
00251         override bool apply(const RefPtr<FragmentID>&f, const RefPtr<CreativeArrayBase>&F)
00252         {
00253                 if (!F)
00254                         return true; 
00255 
00256                 if (RefPtr<DataRange<Type> > FragmentRange = DataRange<Type>::retrieve( *F) )
00257                 {
00258                         if (!theRange)
00259                                 theRange = new DataRange<Type>( *FragmentRange ); 
00260                         else
00261                                 theRange->expand( *FragmentRange ); 
00262                 }
00263 
00264                 return true;
00265         }
00266 
00267         FieldRange(Field&F, const MemCore::WeakPtr<FragmentSelector>&FS = NullPtr() )
00268         {
00269                 if (!FS)
00270                 {
00271                         theRange = DataRange<Type>::get(F);
00272 #if     0
00273                         if (!theRange)
00274                                 puts("FieldRange: No datarange yet"); 
00275                         else
00276                         {
00277                                 printf("FieldRange: Returning old datarange from %ld, Field is %ld (field %p)\n", theRange->time_value(), F.time_value(), &F );
00278                         }
00279 #endif
00280                 }
00281                 if (!theRange)
00282                 {
00283                         F.iterate( *this, FS );
00284 
00285                         if (theRange && !FS)
00286                         {
00287                                 F.addInterface( theRange );
00288                                 theRange->update( F );
00289 //                              puts("Added range to field");
00290                         }
00291                 }
00292         }
00293 };
00294 
00295 extern fiberop_API template struct DataRange<float>;
00296 extern fiberop_API template struct DataRange<double>;
00297 
00298 extern fiberop_API template struct FieldRange<float>;
00299 extern fiberop_API template struct FieldRange<double>;
00300 
00301 template <class Type>
00302 inline fiberop_API
00303 bool    Contains(CreativeArrayBase&CAB, const Type&Value, bool ComputeEventually)
00304 {
00305         if (ComputeEventually)
00306         {
00307                 if (RefPtr<DataRange<Type> > DR = DataRange<Type>::retrieve(CAB) )
00308                 {
00309                         return DR->contains( Value );
00310                 }
00311         }
00312         else
00313         {
00314                 if (RefPtr<DataRange<Type> > DR = DataRange<Type>::get(CAB) )
00315                 {
00316                         return DR->contains( Value );
00317                 }
00318         }
00319         throw DataRangeBase::NoDataRange();
00320 }
00321 
00328 extern fiberop_API RefPtr<DataRangeBase> getRange(Field&);
00329 
00330 
00331 } // namespace Fiber
00332 
00333 
00334 #endif // __FIBEROPERATIONS_RANGE_HPP
00335 
00336