FiberVISH 0.2
Fish - The Fiber Bundle API for the Vish Visualization Shell
Range.hpp
1#ifndef FIBEROPERATIONS_RANGE_HPP
2#define FIBEROPERATIONS_RANGE_HPP 20241206
3
4#include <field/MemBase.hpp>
5#include <grid/Representation.hpp>
6#include <memcore/typemap.hpp>
7#include <memcore/Profiler.hpp>
8
9#include <field/DirectProductArray.hpp>
10
11#ifdef USE_OPENMP
12#include <omp.h>
13#endif
14#include <algorithm>
15
16#include "RangeBase.hpp"
17
18namespace Fiber
19{
20
21
22template <typename Type>
23void computeRangeIt(Type&MinValue, Type&MaxValue, const Iterator<Type>&Data)
24{
25#ifdef USE_OPENMP
26
27// parallel version
28const int max_threads_possible = omp_get_max_threads();
29
30// stl container (write access) is not thread safe, so every thread gets its own element
31std::vector<Type> minList(max_threads_possible);
32std::vector<Type> maxList(max_threads_possible);
33
34std::vector<int> valueFound(max_threads_possible);
35
36 for(int i=0; i<max_threads_possible; i++)
37 {
38 valueFound[i] = 0;
39 }
40
41index_t count = Data.count();
42
43#pragma omp parallel
44 {
45 Type localMin = Data[0];
46 Type localMax = Data[0];
47
48//#pragma omp for shared( Data, minList, maxList, minFound, maxFound)
49#pragma omp for
50 for(index_t i = 1; i<count ; i++)
51 {
52 const Type&value = Data[i];
53 if (value < localMin) localMin = value;
54 if (value > localMax) localMax = value;
55 }
56
57 const int my_thread_id = omp_get_thread_num();
58
59 minList[my_thread_id] = localMin;
60 maxList[my_thread_id] = localMax;
61
62 valueFound[my_thread_id] = 1;
63 }
64 // parallel execution ends
65
66 // ... variables declared locally within a structured block or a routine
67 // that is invoked from within a parallel region are private by default.
68
69 for( int i=0; i<max_threads_possible; i++)
70 {
71 if( valueFound[i] == 1 )
72 {
73 if( minList[i] < MinValue ) MinValue = minList[i];
74 if( maxList[i] > MaxValue ) MaxValue = maxList[i];
75 }
76 }
77#else
78 // straightforward version
79 for(index_t i=1; i<count ; i++)
80 {
81 const Type&value = Data[i];
82 if (value < MinValue) MinValue = value;
83 if (value > MaxValue) MaxValue = value;
84 }
85#endif
86}
87
88
89template <typename T>
90void computeRange(T&MinValue, T&MaxValue, const T*Data, size_t size)
91{
92 if (!size) return;
93
94 MinValue = MaxValue = Data[0];
95
96#pragma omp parallel
97 {
98 T local_min = Data[0],
99 local_max = Data[0];
100
101#pragma omp for nowait
102 for (size_t i = 1; i < size; ++i)
103 { // Start from the second element
104 if (Data[i] < local_min) local_min = Data[i];
105 if (Data[i] > local_max) local_max = Data[i];
106 }
107
108#pragma omp critical(RangeComputation)
109 {
110 if (local_min < MinValue) MinValue = local_min;
111 if (local_max > MaxValue) MaxValue = local_max;
112 }
113 }
114 RangeVerbose(20) << "Compute Scalar Range resulting in " << MinValue << " - " << MaxValue;
115}
116
117template <typename T, typename index_t>
118void computeIndexedRange(T&MinValue, T&MaxValue, const T*Data, size_t size, const std::vector<index_t>&index_array)
119{
120 if (!size) return;
121 if (!index_array.size()) return;
122
123 MinValue = MaxValue = Data[ index_array[0] ];
124
125#pragma omp parallel
126 {
127 T local_min = Data[ index_array[0] ],
128 local_max = Data[ index_array[0] ];
129
130#pragma omp for nowait
131 for (size_t I = 1; I < index_array.size(); ++I) // Start from the second element
132 {
133 auto i = index_array[I];
134
135 if (Data[i] < local_min) local_min = Data[i];
136 if (Data[i] > local_max) local_max = Data[i];
137 }
138
139#pragma omp critical(RangeComputation)
140 {
141 if (local_min < MinValue) MinValue = local_min;
142 if (local_max > MaxValue) MaxValue = local_max;
143 }
144 }
145}
146
147
148
149template <typename T, Eagle::dimension_t N>
150void computeRange( Eagle::FixedArray<T, N>&MinValue, Eagle::FixedArray<T, N>&MaxValue,
151 const Eagle::FixedArray<T,N>*Data, size_t size)
152{
153 if (!size) return;
154
155 MinValue = MaxValue = Data[0];
156
157#pragma omp parallel num_threads(1)
158 {
160 local_min = Data[0],
161 local_max = Data[0];
162
163#pragma omp for nowait
164 for (size_t i = 1; i < size; ++i) // Start from the second element!
165 {
166 for(Eagle::dimension_t j = 0; j<N; j++)
167 {
168 if (Data[i][j] < local_min[j]) local_min[j] = Data[i][j];
169 if (Data[i][j] > local_max[j]) local_max[j] = Data[i][j];
170 }
171// Data[i].expandMinMax( local_min, local_max );
172 }
173
174#pragma omp critical(RangeComputation)
175 {
176 for(Eagle::dimension_t i = 0; i<N; i++)
177 {
178 if (local_min[i] < MinValue[i]) MinValue[i] = local_min[i];
179 if (local_max[i] > MaxValue[i]) MaxValue[i] = local_max[i];
180 }
181 }
182 }
183
184 RangeVerbose(20) << "Compute Range FixedArray<" << N << ">: resulting in " << MinValue << " - " << MaxValue;
185}
186
187template <typename T, Eagle::dimension_t N, typename index_t>
188void computeIndexedRange( Eagle::FixedArray<T, N>&MinValue, Eagle::FixedArray<T, N>&MaxValue,
189 const Eagle::FixedArray<T,N>*Data, size_t size,
190 const std::vector<index_t>&index_array)
191{
192 if (!size) return;
193 if (!index_array.size()) return;
194
195 MinValue = MaxValue = Data[ index_array[0] ];
196
197#pragma omp parallel
198 {
200 local_min = Data[ index_array[0] ],
201 local_max = Data[ index_array[0] ];
202
203#pragma omp for nowait
204 for (size_t I = 1; I < index_array.size(); ++I) // Start from the second element!
205 {
206 auto i = index_array[I];
207 for(Eagle::dimension_t j = 0; j<N; j++)
208 {
209 if (Data[i][j] < local_min[j]) local_min[j] = Data[i][j];
210 if (Data[i][j] > local_max[j]) local_max[j] = Data[i][j];
211 }
212// Data[i].expandMinMax( local_min, local_max );
213 }
214
215#pragma omp critical(RangeComputation)
216 {
217 for(Eagle::dimension_t i = 0; i<N; i++)
218 {
219 if (local_min[i] < MinValue[i]) MinValue[i] = local_min[i];
220 if (local_max[i] > MaxValue[i]) MaxValue[i] = local_max[i];
221 }
222 }
223 }
224}
225
226
227
228template <typename T, Eagle::dimension_t N>
229void computeRangeIt( Eagle::FixedArray<T, N>&MinValue, Eagle::FixedArray<T, N>&MaxValue,
230 const Iterator<Eagle::FixedArray<T,N>>&Data)
231{
232 // TODO: implement computing the range over a fixed array using the Iterator<>
233 Assert( false );
234}
235
236
237template <typename Type>
238inline void computeRange(Type&MinValue, Type&MaxValue, const std::vector<Type>&Data)
239{
240 computeRange(MinValue, MaxValue, Data.data(), Data.size() );
241}
242
243template <typename Type, typename index_t>
244inline void computeIndexedRange(Type&MinValue, Type&MaxValue, const std::vector<Type>&Data, const std::vector<index_t>&index_array)
245{
246 computeIndexedRange(MinValue, MaxValue, Data.data(), Data.size(), index_array );
247}
248
249
250extern template
251void computeRange<double>(double&MinValue, double&MaxValue, const std::vector<double>&Data);
252
253
254
256template <class Type, class OtherType>
257void expand_by_other_minmax( Type&Minimum, Type&Maximum, const OtherType&OtherMinimum, const OtherType&OtherMaximum)
258{
259 if (Minimum > OtherMinimum) Minimum = OtherMinimum;
260 if (Maximum < OtherMaximum) Maximum = OtherMaximum;
261}
262
263template <class Type, class OtherType>
264inline bool contains_value( const Type&Minimum, const Type&Maximum, const OtherType&Value)
265{
266 if (Value<Minimum) return false;
267 if (Value>Maximum) return false;
268 return true;
269}
270
271
276template <typename T>
278{
279 using type = double;
280
281static type convert(const T&t)
282 {
283 return type(t);
284 }
285};
286
287
288
289#if (__cplusplus > 201703L)
290
291template <typename T>
292concept DerivedFromFixedArray = requires
293{
294 typename std::enable_if_t<std::is_base_of_v<Eagle::FixedArray<typename T::value_type, T::size()>, T>>;
295};
296
297#define HAVE_DerivedFromFixedArray_concept
298
299template <DerivedFromFixedArray Type, DerivedFromFixedArray OtherType>
300requires (Type::size() == OtherType::size())
301void expand_by_other_minmax( Type&Minimum, Type&Maximum,
302 const OtherType&OtherMinimum, const OtherType&OtherMaximum)
303{
304constexpr auto N = Minimum.size();
305 for(Eagle::dimension_t i = 0; i<N; i++)
306 {
307 if (Minimum[i] > OtherMinimum[i]) Minimum[i] = OtherMinimum[i];
308 if (Maximum [i]< OtherMaximum[i]) Maximum[i] = OtherMaximum[i];
309 }
310}
311
312template <DerivedFromFixedArray Type>
313inline void computeRange(Type&MinValue, Type&MaxValue, const std::vector<Type>&Data)
314{
315 computeRange(MinValue.getFixedArray(), MaxValue.getFixedArray(), Data.data(), Data.size() );
316}
317
318
319template <DerivedFromFixedArray Type, typename index_t>
320inline void computeIndexedRange(Type&MinValue, Type&MaxValue, const std::vector<Type>&Data, const std::vector<index_t>&index_array)
321{
322 computeIndexedRange(MinValue.getFixedArray(), MaxValue.getFixedArray(), Data.data(), Data.size(), index_array );
323}
324
325
326template <DerivedFromFixedArray Type, DerivedFromFixedArray OtherType>
327requires (Type::size() == OtherType::size())
328inline bool contains_value( const Type&Minimum, const Type&Maximum, const OtherType&Value)
329{
330constexpr auto N = Minimum.size();
331
332 for(Eagle::dimension_t i = 0; i<N; i++)
333 {
334 if (Value[i] < Minimum[i]) return false;
335 if (Value[i] > Maximum[i]) return false;
336 }
337
338 return true;
339}
340
348template <DerivedFromFixedArray T>
349struct Range_as_FloatVersion<T>
350{
351 using type = FixedArray<double, T::size() >;
352
353static type convert(const T&t)
354 {
355 type retval;
356 for(size_t i=0; i<T::size(); i++)
357 retval[i] = t[i];
358
359 return retval;
360 }
361};
362
363#endif
364
365template <class Type>
366inline auto ComputeRangeFromDirectProduct(const RefPtr<MemBase>&ArrayBase)
367{
368 return nullptr;
369}
370
371template <>
372inline auto ComputeRangeFromDirectProduct<Eagle::point3>(const RefPtr<MemBase>&ArrayBase);
373
377template <class Type>
379{
380public:
382 using float_range_type = typename Range_as_FloatVersion<Type>::type;
383
384 Type&Minimum() { return (*this)[0]; }
385 Type&Maximum() { return (*this)[1]; }
386
387 const Type&Minimum() const { return (*this)[0]; }
388 const Type&Maximum() const { return (*this)[1]; }
389
390
393 {}
394
396 DataRange(const Type&min,const Type&max)
397 : std::array<Type, 2>{ min, max }
398 {}
399
400 DataRange(const Ageable&Age)
401 : DataRangeBase(Age)
402 {}
403
405 DataRange(const Ageable&Age, const Type&min,const Type&max)
407 , std::array<Type, 2>{ min, max }
408 {}
409
410 ~DataRange() override
411 {}
412
414 const Type&Min() const
415 {
416 return Minimum();
417 }
418
420 const Type&Max() const
421 {
422 return Maximum();
423 }
424
427 {
429 float_version::convert( Min() ),
430 float_version::convert( Max() ) );
431 }
432
433 std::string str() const override
434 {
435 return "["
436 + std::to_string( Minimum() )
437 + ", "
438 + std::to_string( Maximum() )
439 + "]";
440 }
441
443 template <class OtherType>
445 : std::array<Type, 2>{ DR.Min(), DR.Max() }
446 {}
447
449 template <class OtherType>
451 {
452 expand_by_other_minmax( Minimum(), Maximum(), DR.Min(), DR.Max() );
453 update( DR ); // update always or only if there was some change?
454 }
455
458 {
459 if (RefPtr<DataRange<Type> > DR = DRB)
460 {
461 expand(*DR);
462 }
463 }
464
468 template <class CompareType>
469 bool contains(const CompareType&Value) const
470 {
471 return contains_value( Minimum(), Maximum(), Value);
472 }
473
480 {
481 if (CAB.AttributeModificationAge.isOlderThan(CAB))
482 return nullptr;
483
484 RefPtr<Chunk<Type> > myChunk = CAB.getAttribute( RangeAttributeName );
485 if (!myChunk)
486 return nullptr;
487
488 RefPtr<DataRange> DR = new DataRange( CAB, myChunk[0], myChunk[1] );
489
490 RangeVerbose(31) << " get_attribute<" << MemCore::Typename(typeid(Type)) << "> "
491 << CAB.getFirstProvenancePath() << " --> "
492 << myChunk[0] << " - " << myChunk[1]
493 << " Creator Age: " << CAB.getAge()
494 << " DataRange Age: " << DR->getAge()
495 ;
496 return DR;
497// return new DataRange(CAB, myChunk[0], myChunk[1] );
498 }
499
500static RefPtr<DataRange> set_from_attribute(CreativeArrayBase&CAB)
501 {
503 if (DR)
504 {
505 RangeVerbose(31) << "set_from_attribute("
506 << CAB.getFirstProvenancePath() << " --> " << DR->str()
507 << " range age " << DR->getAge()
508 << " CAB age " << CAB.getAge()
509 << " CAB attribute age " << CAB.getAttributeAge();
510
511 CAB.addInterface(DR);
512 DR->update(CAB);
513 }
514 else
515 {
516 RangeVerbose(14) << "set_from_attribute() did not find a Range attribute on " << CAB.getFirstProvenancePath();
517 }
518 return DR;
519 }
520
527 {
528 if (F.AttributeModificationAge.isOlderThan(F))
529 return nullptr;
530
531 RefPtr<Chunk<Type> > myChunk = F.getAttribute( RangeAttributeName );
532 if (!myChunk)
533 return nullptr;
534
535 return new DataRange(F, myChunk[0], myChunk[1] );
536 }
537
538static RefPtr<DataRange> set_from_attribute(Field&F)
539 {
541 if (DR)
542 {
543 F.addInterface(DR);
544 DR->update(F);
545 }
546 return DR;
547 }
548
549
550static RefPtr<DataRange> get_cached_range_if_older_than_data(const CreativeArrayBase&CAB)
551 {
552 if (RefPtr<DataRange> DR = interface_cast<DataRange>(CAB) )
553 {
554 if (CAB.isNewerThan(*DR))
555 return nullptr;
556
557 return DR;
558 }
559 return nullptr;
560 }
561
567 {
569 return nullptr;
570
571 if (RefPtr<DataRange> DR = get_cached_range_if_older_than_data(CAB) )
572 {
573 RangeVerbose(21) << "get_range_if_older_than_data(): Have Range Interface on " << CAB.getFirstProvenancePath() << " --> " << DR->str();
574 return DR;
575 }
576
577 if (RefPtr<DataRange> DR = set_from_attribute(CAB) )
578 {
579 RangeVerbose(21) << "get_range_if_older_than_data(): GOT Range attribute on " << CAB.getFirstProvenancePath() << " --> " << DR->str();
580
581 Assert( !DR->isOlderThan( CAB ) );
582 return DR;
583 }
584
585 RangeVerbose(13) << "get_range_if_older_than_data(): No Range Interface on " << CAB.getFirstProvenancePath()
586// << " attribute: " << get_attribute(CAB)
587// << " range attribute: " << CAB.getAttribute( RangeAttributeName )
588 ;
589
590 return nullptr;
591 }
592
593static RefPtr<DataRangeBase> get_range_if_older_than_creator_data(CreativeArrayBase&CAB)
594 {
596 }
597
603 {
605 {
606 if ( !DR->isOlderThan( F ) )
607 return DR;
608 }
609 return nullptr;
610 }
611
619 {
621 return DR;
622
623 return get_attribute(F);
624 }
625
631 {
633 {
634 if ( !DR->isOlderThan( F ) )
635 return DR;
636 }
637 if (RefPtr<DataRange> DR = set_from_attribute(F))
638 {
639 RangeVerbose(10) << "Getting range from field attribute.";
640 return DR;
641 }
642 return nullptr;
643 }
644
649 {
650 using namespace MemCore;
652 if (!ArrayBase) return nullptr;
653
654 MEMCORE_PROFILE_THIS("actual compute_range", 6);
655
656 // Compute range based on std::vector
658 {
659 using base_type = typename TypedChunk<Type>::base_type;
660 const std::vector<base_type>&base_vec = DataAsChunk->base_vector();
661 if (base_vec.size()<1)
662 return nullptr;
663
664 RefPtr<DataRange> DR = new DataRange();
665 base_type &Min = DR->Minimum(), &Max = DR->Maximum();
666
667 computeRange(Min, Max, base_vec );
668
669 RangeVerbose(5) << " Computing the range based on std::vector<"
670 << MemCore::Typename( typeid(base_type ))
671 << ">["<< base_vec.size()/1E6<<"Mio] : " << Min << " - " << Max
672 << " took " << RangeTimer.secs()
673 << "s @ "
675 return DR;
676 }
677
678
680 return DR;
681
682 //
683 // Compute range based on Iterator<>
684 //
686 if (!DataArray)
687 {
688 RangeVerbose(5) << " NO TypedArray data...";
689 return nullptr;
690 }
691
692 RangeVerbose(11) << " GET creative iterator...";
693
694 CreativeIterator<Type>*values = DataArray->creativeIterator();
695 if (!values or !*values )
696 return nullptr;
697
698 const Iterator<Type>&Data = *values;
699 if (!Data) return nullptr;
700
701 index_t count = Data.count();
702 if (count<1)
703 return nullptr;
704
705 RefPtr<DataRange> DR = new DataRange();
706
707 Type &MinValue = DR->Minimum(),
708 &MaxValue = DR->Maximum();
709 MinValue = MaxValue = Data[ 0 ];
710
711 auto ArrayIterator = Data.getArrayIterator();
712
713 computeRangeIt(MinValue, MaxValue, ArrayIterator );
714
715 RangeVerbose(5) << " Computing the range based on Iterator<"
716 << MemCore::Typename( typeid( Type ))
717 << "> : " << MinValue << " - " << MaxValue
718 << " took " << RangeTimer.secs()*1000.0
719 ;
720 return DR;
721 }
722
723
724 template <typename index_t>
725static RefPtr<DataRange> compute_indexed_range(const RefPtr<MemBase>&ArrayBase, const std::vector<index_t>&index_array)
726 {
727 using namespace MemCore;
728 if (!ArrayBase) return nullptr;
729
730 // Compute range based on std::vector
732 {
733 using base_type = typename TypedChunk<Type>::base_type;
734 const std::vector<base_type>&base_vec = DataAsChunk->base_vector();
735 if (base_vec.size()<1)
736 return nullptr;
737
738 RefPtr<DataRange> DR = new DataRange();
739 base_type &Min = DR->Minimum(), &Max = DR->Maximum();
740
741 computeIndexedRange(Min, Max, base_vec, index_array );
742
743 return DR;
744 }
745 return nullptr;
746 }
747
748
749 RefPtr<DataRangeBase> getIndexedRange(const RefPtr<MemBase>&ArrayBase, const std::vector<uint32_t>&index_array) const override
750 {
751 return compute_indexed_range(ArrayBase, index_array);
752 }
753
754 RefPtr<DataRangeBase> getIndexedRange(const RefPtr<MemBase>&ArrayBase, const std::vector<size_t>&index_array) const override
755 {
756 return compute_indexed_range(ArrayBase, index_array);
757 }
758
759
761 {
762 if (RefPtr<FiberTypeBase> CreatorType = CAB.getFiberType())
763 {
765 if (CreatorType->getType() != typeid(Type))
766 {
767#if 0
768 Verbose(0) << " Creator type "
769 << CreatorType->description()
770 << " does not match field type "
771 << MemCore::Typename( typeid(Type ))
772 << " , cannot compute range";
773#endif
774 return false;
775 }
776 return true;
777 }
778 else
779 {
780 RangeVerbose(0) << "Range CANNOT determine data type of creator fragment without loading it, no fiber type available - bailing out!";
781
782 // note: we could still try get() here, but we're probably already wrong at this point.
783 return false;
784 }
785 }
786
787
792 {
793 if (RefPtr<DataRange> DR = compute_range(ArrayBase, CAB.getFirstProvenancePath() ))
794 {
795 CAB.addInterface( DR );
796 DR->update( CAB );
797
798 RefPtr<Chunk<Type> > myChunk = new Chunk<Type> (2);
799 myChunk[0]= DR->Minimum();
800 myChunk[1]= DR->Maximum();
801 CAB.setAttribute( RangeAttributeName, myChunk);
802 CAB.updateAttributeAge( *DR );
803
804 RangeVerbose(11) << " Setting attribute " << RangeAttributeName
805 << " to {" << DR->Minimum() << "," << DR->Maximum() << "}"
806 << " on " << CAB.getFirstProvenancePath()
807 ;
808 RangeVerbose(12) << " Ages for " << CAB.getFirstProvenancePath()
809 << " CAB: " << CAB.getAge()
810 << " CAB Attributes: " << CAB.getAttributeAge()
811 << " Range: " << DR->getAge()
812 ;
813
814 return DR;
815 }
816
817 return nullptr;
818 }
819
826 {
828 return nullptr;
829
831 if (!ArrayBase) ArrayBase = CAB.get();
832 if (!ArrayBase)
833 {
835 {
836 RangeVerbose(15) << " Range is not computed because data are not available in RAM for "
837 << CAB.getFirstProvenancePath();
838 return nullptr;
839 }
840
841 if (AsynchRequest)
842 {
843 RangeVerbose(15) << " returning for now as asynch loading request."
844 << CAB.getFirstProvenancePath();
845
846 CAB.request(); // possibly register callback functor here
847 return nullptr;
848 }
849 else
850 {
851 RangeVerbose(1) << " WARNING: Need to LOAD data for range computation on " << CAB.getFirstProvenancePath();
852 ArrayBase = CAB.create();
853 if (!ArrayBase)
854 {
855 RangeVerbose(1) << " PROBLEM: Could not LOAD data for range computation on " << CAB.getFirstProvenancePath();
856 return nullptr;
857 }
858 }
859 }
860
861 RangeVerbose(9) << " Need to COMPUTE range @"
862 << CAB.getFirstProvenancePath();
863
865 return DR;
866
867 RangeVerbose(10) << " NO data range, removing " << RangeAttributeName
868 << " from " << CAB.getFirstProvenancePath();
869 CAB.removeAttribute( RangeAttributeName );
870
871 return nullptr;
872 }
873
881 {
883 return nullptr;
884
886 if (DR)
887 {
888 RangeVerbose(40) << " Got Range attribute " << DR->getAge();
889 return DR;
890 }
891
892 RangeVerbose(16) << "DataRange> retrieve(): "
893 << CAB.getFirstProvenancePath() << " NO valid data range available"
894 << " CAB age " << CAB.getAge()
895 << " CAB attribute age " << CAB.getAttributeAge();
896
898 }
899
901 {
902 MEMCORE_PROFILE_THIS("FieldRange: retrieve() - get CREC", 7);
903 if (RefPtr<CreativeArrayBase> CAB = F.getCreator(f))
904 {
905 MEMCORE_PROFILE_THIS("FieldRange: retrieve()", 7);
906 return retrieve( *CAB, AsynchRequest, AvoidDataLoading, CAB->get() );
907 }
908
909 return nullptr;
910 }
911
912static bool expand_range(RefPtr<DataRange<Type> >&GlobalRange,
913 const RefPtr<DataRange<Type> >&LocalRange)
914 {
915 MEMCORE_PROFILE_THIS("FieldRange: expand()", 7);
916
917 if (!LocalRange)
918 return false;
919
920 if (!GlobalRange)
921 GlobalRange = new DataRange<Type>( *LocalRange );
922 else
923 GlobalRange->expand( *LocalRange );
924
925 return true;
926
927 }
928
929static bool compute_and_expand_range(RefPtr<DataRange<Type> >&GlobalRange,
931 bool theAsynchRequest, bool theAvoidDataLoading )
932 {
933 if (!cab)
934 return false;
935
937 FragmentRange;
938
939 {
940 MEMCORE_PROFILE_THIS("FieldRange: call retrieve()", 7);
941 FragmentRange = DataRange<Type>::retrieve(*cab, theAsynchRequest, theAvoidDataLoading);
942 }
943
944 MEMCORE_PROFILE_THIS("FieldRange: call expand_range()", 7);
945 return expand_range(GlobalRange, FragmentRange);
946 }
947
948static void computeRangeOnAvailableFragments(Field&F, bool RequestToLoadMore = false)
949 {
950 DataRangeBase::computeRangeOnAvailableFragments(F,
952 &get_range_if_older_than_creator_data,
953 RequestToLoadMore);
954 }
955
956static RefPtr<DataRange<Type> > retrieve(Field&F, bool theAsynchRequest, bool theAvoidDataLoading = false)
957 {
958// Get Datarangebase first, and if type does not match, bail out here right away, or try the getType() function!
959
960 RefPtr<FiberTypeBase> FType = F.getElementFiberType();
961 if (!FType)
962 {
963 Verbose(1) << "Field::retrieve() without type information!";
964 return nullptr;
965 }
966
967 const type_info&FieldType = F.getElementType();
968 if ( FieldType != typeid(Type))
969 return nullptr;
970
971 MEMCORE_PROFILE_THIS("FieldRange: retrieve", 6);
972
973 bool need_to_compute_field_range = DataRangeBase::need_to_recompute(F);
974
975/*
976 const Ageable&FieldAttributeAge = F.getAttributeAge();
977 bool need_to_compute_field_range = false;
978 {
979 MEMCORE_PROFILE_THIS("FieldRange: need to compute?", 6);
980 F.iterate( [&FieldAttributeAge, &need_to_compute_field_range, &FieldType](const RefPtr<FragmentID>&f, const RefPtr<CreativeArrayBase>&CAB)
981 {
982 if (!CAB) return true;
983// if (FieldAttributeAge.isOlderThan( *CAB ))
984 if (CAB->isNewerThan(FieldAttributeAge))
985 {
986 RangeVerbose(10) << "Need to recompute field range "
987 << MemCore::Typename(FieldType)
988 << " because creator fragment ["
989 << FragmentID::Name(f) << "] "
990 << CAB->getFirstProvenancePath()
991 << " is newer: "
992 << " Creator: " << CAB->getAge()
993 << " Field: " << FieldAttributeAge
994 ;
995 need_to_compute_field_range = true;
996 return false;
997 }
998
999 if (RefPtr<DataRange<Type>> DR = interface_cast<DataRange<Type>>(CAB) )
1000 {
1001// if (FieldAttributeAge.isOlderThan( *DR ))
1002 if (DR->isNewerThan(FieldAttributeAge))
1003 {
1004 need_to_compute_field_range = true;
1005 RangeVerbose(10) << "Need to recompute field range because fragment is newer: "
1006 << CAB->getFirstProvenancePath()
1007 << " Creator: " << CAB->getAge()
1008 << " Range: " << DR->getAge()
1009 << " Field: " << FieldAttributeAge
1010 ;
1011 return false;
1012 }
1013 }
1014 return true;
1015 }
1016 );
1017 }
1018*/
1019
1020
1022 if (theRange and not need_to_compute_field_range)
1023 {
1024 RangeVerbose(10) << " FieldRange for ["
1025 << MemCore::Typename(F.getElementType())
1026 << "] got OLD (but still valid) range "
1027 << theRange->str()
1028 << " with age " << theRange->getAge()
1029// << " on field with age " << FieldAttributeAge;
1030 ;
1031
1032 return theRange;
1033 }
1034 else
1035 {
1036 MEMCORE_PROFILE_THIS("FieldRange: check", 6);
1037
1038 RangeVerbose(9) << " FieldRange COMPUTE for ["
1039 << MemCore::Typename(F.getElementType())
1040// << " FieldAttributes Age: " << FieldAttributeAge
1041 << " Field Age: " << F.getAge()
1042 << " Newest Field Creator: " << F.getMostRecentCreatorAge()
1043 << " Newest Field Fragment Attribute: " << F.getMostRecentAttributeAge()
1044 ;
1045 if (theRange)
1046 {
1047 RangeVerbose(9) << " Old Range: " << *theRange
1048 << " of age " << theRange->getAge();
1049 }
1050
1051 MEMCORE_PROFILE_THIS("FieldRange: compute", 6);
1052
1053 {
1054 MEMCORE_PROFILE_THIS("FieldRange: compute available", 7);
1055 computeRangeOnAvailableFragments(F);
1056 }
1057
1058 unsigned IncompleteRangeFragments = 0;
1059 unsigned Nfrags;
1060
1061 {MEMCORE_PROFILE_THIS("FieldRange: expand", 7);
1062
1063 theRange = nullptr; // reset range if old one existed.
1064
1065 Nfrags =
1066 F.iterate( [&theRange, theAsynchRequest,theAvoidDataLoading, &IncompleteRangeFragments]
1068 {
1069 if (!cab) return true;
1070
1072 return false; // if the type of the first creator does not match, then others will not match either.
1073
1074 {
1075 MEMCORE_PROFILE_THIS("FieldRange: call compute_and_expand()", 7);
1076 if (!compute_and_expand_range(theRange, f, cab,
1077 theAsynchRequest, theAvoidDataLoading))
1078 {
1079 IncompleteRangeFragments++;
1080 }
1081 }
1082
1083 if (theRange)
1084 RangeVerbose(13) << " Expanded FieldRange to " << theRange->str() << " from " << cab->getFirstProvenancePath();
1085 else
1086 RangeVerbose(13) << " no field range so far.";
1087
1088 return true;
1089 }
1090 );
1091 }
1092
1093 RangeVerbose(10) << " iterated FieldRange "<<Nfrags<<" fragments for ["
1094 << MemCore::Typename(F.getElementType()) << "] "
1095 << " with "
1096 << IncompleteRangeFragments
1097 << " incomplete fragments (no data there)";
1098 ;
1099
1100 if (theRange)
1101 {
1102 MEMCORE_PROFILE_THIS("FieldRange: Set Range attribute", 7);
1103
1104 F.addInterface( theRange );
1105
1106 RefPtr<Chunk<Type> > myChunk = new Chunk<Type> (2);
1107 myChunk[0]= theRange->Min();
1108 myChunk[1]= theRange->Max();
1109 F.setAttribute( RangeAttributeName, myChunk);
1110
1111 setRangeCompleteness(F, Nfrags, IncompleteRangeFragments );
1112
1113// theRange->update( FieldAttributeAge );
1114 F.updateAttributeAge( *theRange );
1115
1116 RangeVerbose(11) << " Field: Set computed Range to " << theRange->str()
1117 << " with age " << theRange->getAge()
1118 << " to Field of attribute age " << F.getAttributeAge()
1119 ;
1120 return theRange;
1121 }
1122 else
1123 {
1124 RangeVerbose(12) << " No Range was computed for this field";
1125 }
1126 return nullptr;
1127 }
1128 }
1129
1130
1135static RefPtr<DataRange<Type>> setFieldRange(Field&F, const Type&Min, const Type&Max, bool Unchangeable = false)
1136 {
1137 RefPtr<DataRange<Type>> theRange = new DataRange(Min, Max);
1138 F.addInterface( theRange );
1139 if (Unchangeable)
1140 theRange->setInfinitelyNew();
1141 else
1142 theRange->update( F );
1143
1144 RefPtr<Chunk<Type> > myChunk = new Chunk<Type> (2);
1145 myChunk[0]= theRange->Min();
1146 myChunk[1]= theRange->Max();
1147 F.setAttribute( RangeAttributeName, myChunk);
1148
1149 setRangeCompleteness(F, 0, 0);
1150
1151 if (!Unchangeable)
1152 F.updateAttributeAge( *theRange );
1153
1154 RangeVerbose(11) << " Field: Set specified Range to " << theRange->str()
1155 << " with age " << theRange->getAge();
1156
1157 return theRange;
1158 }
1159
1165 {
1167 CAB.addInterface( DR );
1168 DR->update( CAB );
1169
1170 RefPtr<Chunk<Type> > myChunk = new Chunk<Type> (2);
1171 myChunk[0]= DR->Minimum();
1172 myChunk[1]= DR->Maximum();
1173 CAB.setAttribute( RangeAttributeName, myChunk);
1174 CAB.updateAttributeAge( *DR );
1175
1176 return DR;
1177 }
1178
1179};
1180
1181#if (__cplusplus > 201703L)
1182
1183template <>
1184inline auto ComputeRangeFromDirectProduct<Eagle::point3>(const RefPtr<MemBase>&ArrayBase)
1185{
1187 retval = nullptr;
1188
1189 if (RefPtr<DirectProductMemArray<Eagle::point3> > DM = ArrayBase)
1190 {
1191 auto Start = DM->first(),
1192 End = DM->last();
1193
1194 retval = new DataRange<Eagle::point3>(Start, End);
1195 }
1196
1197 return retval;
1198}
1199
1200#endif
1201
1202
1209template <class Type>
1210inline RefPtr<DataRange<Type>> setFieldRange(Field&F, const Type&Min, const Type&Max)
1211{
1212 return DataRange<Type>::setFieldRange(F, Min, Max);
1213}
1214
1221template <class Type>
1222inline RefPtr<DataRange<Type>> setCreatorRange(CreativeArrayBase&CAB, const Type&Min, const Type&Max)
1223{
1224 return DataRange<Type>::setCreatorRange(CAB, Min, Max);
1225}
1226
1227
1228
1229#if 1
1233template <class Type>
1234struct
1235[[deprecated("Use DataRange<Type> instead of ComputeRange<Type> ")]]
1237{
1238 RefPtr<DataRange<Type> > theRange;
1239// const size_t NumberOfFieldFragments = 0;
1240// size_t IncompleteRangeFragments = 0;
1241
1242#if 0
1243 // same as DataRange::retrieve()
1245#endif
1246
1247
1251 [[deprecated("Use range = DataRange<Type>::retrieve() instead")]]
1253// : NumberOfFieldFragments ( F.NumberOfFragments() )
1254 {
1256 }
1257
1261 [[deprecated("Use range = DataRange<Type>::retrieve() instead")]]
1263 // : NumberOfFieldFragments ( F.NumberOfFragments() )
1264 {
1266 }
1267};
1268#endif
1269
1270
1271template <class Type>
1272inline bool Contains(CreativeArrayBase&CAB, const Type&Value, bool ComputeEventually)
1273{
1274 if (ComputeEventually)
1275 {
1276 if (RefPtr<DataRange<Type> > DR = DataRange<Type>::retrieve(CAB) )
1277 {
1278 return DR->contains( Value );
1279 }
1280 }
1281 else
1282 {
1283 if (RefPtr<DataRange<Type> > DR = DataRange<Type>::get(CAB) )
1284 {
1285 return DR->contains( Value );
1286 }
1287 }
1288 throw DataRangeBase::NoDataRange();
1289}
1290
1291
1292
1294
1295template <typename... Type>
1298{
1300
1301 ( (result = DataRange<Type>::retrieve(CAB, AsynchRequest, theAvoidDataLoading, PossibleData), result?true:false)
1302 or ...);
1303
1304 return result;
1305}
1306
1314template <typename... Type>
1317{
1319
1320// ( (result = ComputeRange<Type>(F, fragmentID, AsynchRequest, theAvoidDataLoading).theRange, result?true:false)
1321
1323 or ...);
1324
1325 return result;
1326}
1327
1328
1330{
1331 virtual RefPtr<DataRangeBase>
1332 getFragmentRange(CreativeArrayBase&CAB, bool AsynchRequest=false, bool theAvoidDataLoading = false, const RefPtr<MemBase>&PossibleData = nullptr) = 0;
1333
1335
1336static Registry_t&getRegistry();
1337
1338};
1339
1340
1357template <typename... Type>
1360{
1362
1363 ( (result = DataRange<Type>::retrieve(F, AsynchRequest, theAvoidDataLoading), result?true:false)
1364 or ...);
1365
1366 return result;
1367}
1368
1369
1370
1371
1372
1373
1378template <typename First, typename... MoreTypes>
1379[[deprecated("this function is for educational purposes only")]]
1382{
1384 result = DataRange<First>(F, AsynchRequest, theAvoidDataLoading).theRange )
1385 return result;
1386
1387 if constexpr (sizeof...(MoreTypes) > 0)
1389 else
1390 return nullptr;
1391}
1392
1393
1394} // namespace Fiber
1395
1396namespace std
1397{
1398fiberop_API string to_string(const Fiber::DataRange<double>& a);
1399fiberop_API string to_string(const Fiber::DataRangeBase& a);
1400}
1401
1402#endif // FIBEROPERATIONS_RANGE_HPP
typename enable_if< _Cond, _Tp >::type enable_if_t
_Tp min() const
_Tp max() const
valarray< size_t > size() const
constexpr iterator_traits< _InputIterator >::difference_type count(_InputIterator __first, _InputIterator __last, const _Tp &__value)
basic_string< char > string
constexpr size_type size() const noexcept
Base class for multidimensional arrays that employ deferred storage, i.e.
Definition CreativeArrayBase.hpp:75
An iterator with an optional DataCreator, which is just a class to intercept creation of data along a...
Definition CreativeIterator.hpp:34
A Field is a collection of CreativeArrayBase reference pointers which are accessed via FragmentID obj...
Definition Field.hpp:245
bool isOlderThan(const Ageable &a) const noexcept
constexpr const Ageable & getAge() const
age_t update(age_t age) noexcept
void setAttribute(const std::string &name, const MemCore::RefPtr< MemCore::ChunkBase > &AttribData)
const Ageable & getAttributeAge() const
MemCore::RefPtr< MemCore::ChunkBase > getAttribute(const std::string &name) const
virtual bool request(const result &R=nullptr)
virtual RefPtr< Domain > get() const=0
RefPtr< Domain > create(bool CreateAsOld=false)
void addInterface(const RefPtr< InterfaceBase > &I) const
MEMCORE_API std::string Typename(const std::type_info &t)
Given a fragmented field of curvilinear coordinates, (3D array of coordinates), build a uniform Grid ...
Definition FAQ.dox:2
RefPtr< DataRangeBase > getTypedFragmentRange(CreativeArrayBase &CAB, bool AsynchRequest, bool theAvoidDataLoading, const RefPtr< MemBase > &PossibleData=nullptr)
{
Definition Range.hpp:1297
void expand_by_other_minmax(Type &Minimum, Type &Maximum, const OtherType &OtherMinimum, const OtherType &OtherMaximum)
Expand a range by a given type, which must be convertible.
Definition Range.hpp:257
RefPtr< DataRangeBase > getFragmentRange(CreativeArrayBase &CAB, bool AsynchRequest, bool theAvoidDataLoading, const RefPtr< MemBase > &PossibleData)
TODO: Go via a type registry.
Definition Range.cpp:18
RefPtr< DataRangeBase > recursive_getTypedRange(Field &F, bool AsynchRequest, bool theAvoidDataLoading)
An alternative version of getTypedRange() which does not rely on a fold expression and achieves the s...
Definition Range.hpp:1381
RefPtr< DataRangeBase > getTypedFieldRange(Field &F, bool AsynchRequest, bool theAvoidDataLoading)
Get the range of a field by iterating over a list of types.
Definition Range.hpp:1359
std::string to_string(const span< char > &s)
STL namespace.
string to_string(const Eagle::FixedArray< ElementType, N > &A, const char *OpenBrace="{", const char *CloseBrace="}", const char *Separator=",")
A class to compute the range of fields or field fragments.
Definition Range.hpp:1237
ComputeRange(Field &F, bool theAsynchRequest, bool theAvoidDataLoading=false)
Compute the range of an entire field.
Definition Range.hpp:1262
ComputeRange(Field &F, const RefPtr< FragmentID > &f, bool theAsynchRequest, bool theAvoidDataLoading)
Compute the range of a single fragment within a field.
Definition Range.hpp:1252
Base class for ranges that can be attached to Creators.
Definition RangeBase.hpp:33
DataRangeBase()
Constructor, age will be youngest.
Definition RangeBase.cpp:8
Class for ranges of types, such as minimum/maximum.
Definition Range.hpp:379
static RefPtr< DataRange > retrieve(CreativeArrayBase &CAB, bool AsynchRequest=false, bool AvoidDataLoading=false, const RefPtr< MemBase > &PossibleData=nullptr)
Provide a data range on a given CreativeArrayBase from the attribute, if such exists and is older tha...
Definition Range.hpp:880
RefPtr< DataRangeBase > getFloatRange() const override
Always double precison!
Definition Range.hpp:426
static RefPtr< DataRange > get_cached_range(const Field &F)
Get any range information that is available from the Field, used e.g.
Definition Range.hpp:618
void expand(const DataRange< OtherType > &DR)
Expand the range by a given type, which must be convertible.
Definition Range.hpp:450
RefPtr< DataRange< Type > > setCreatorRange(CreativeArrayBase &CAB, const Type &Min, const Type &Max)
Set the range information on a data Creator with type information as provided implicitly by the type ...
Definition Range.hpp:1222
static RefPtr< DataRange > compute_range(const RefPtr< MemBase > &ArrayBase, const string &ProvenancePath)
Perform an actual computation of the range.
Definition Range.hpp:648
void expandRange(const RefPtr< DataRangeBase > &DRB) override
Expand range by same type.
Definition Range.hpp:457
DataRange()
Default constructor, no initializiation.
Definition Range.hpp:392
static RefPtr< DataRangeBase > compute_range_and_set_attribute(CreativeArrayBase &CAB, const RefPtr< MemBase > &ArrayBase)
unconditionally compute: Overwrites a given attribute or interface.
Definition Range.hpp:791
DataRange(const DataRange< OtherType > &DR)
Initialize the range by a given type, which must be convertible.
Definition Range.hpp:444
static RefPtr< DataRange > get_range_if_older_than_field(Field &F)
Get a cached range from the Field if the data are older or than the range.
Definition Range.hpp:630
bool contains(const CompareType &Value) const
Check if certain value is contained here.
Definition Range.hpp:469
static bool creator_has_compatible_type(CreativeArrayBase &CAB)
Definition Range.hpp:760
static RefPtr< DataRange< Type > > setFieldRange(Field &F, const Type &Min, const Type &Max, bool Unchangeable=false)
Set, and overwrite, and explicit range attribute on a Field.
Definition Range.hpp:1135
RefPtr< DataRange< Type > > setFieldRange(Field &F, const Type &Min, const Type &Max)
Set the range information on a field with type information as provided implicitly by the type of the ...
Definition Range.hpp:1210
const Type & Max() const
The maximum.
Definition Range.hpp:420
DataRange(const Ageable &Age, const Type &min, const Type &max)
Initialize constructor age (may be important!!) with min and max.
Definition Range.hpp:405
DataRange(const Type &min, const Type &max)
Initialize constructor with min and max.
Definition Range.hpp:396
static RefPtr< DataRange > get_cached_range_if_older_than_field(const Field &F)
Get a cached range from the Field if the data are older or than the range.
Definition Range.hpp:602
static RefPtr< DataRange< Type > > setCreatorRange(CreativeArrayBase &CAB, const Type &Min, const Type &Max)
Set, and overwrite, and explicit range attribute on a Creator.
Definition Range.hpp:1164
static RefPtr< DataRange > get_attribute(const Field &F)
Get the range attribute for a Field if the attributes are valid, i.e.
Definition Range.hpp:526
static RefPtr< DataRange > get_attribute(const CreativeArrayBase &CAB)
Get the range attribute for a Fragment's Creator if the attributes are valid, i.e.
Definition Range.hpp:479
static RefPtr< DataRange > possibly_compute_and_set_attribute(CreativeArrayBase &CAB, bool AsynchRequest, bool AvoidDataLoading, const RefPtr< MemBase > &PossibleData)
Ignore an existing Range attribute and try to compute the Range newly if the data are available (and ...
Definition Range.hpp:825
static RefPtr< DataRange > get_range_if_older_than_data(CreativeArrayBase &CAB)
Get a cached range from the creative array if the data are older or than the range.
Definition Range.hpp:566
const Type & Min() const
The minimum.
Definition Range.hpp:414
Definition Range.hpp:1330
Type trait class to help DataRange<T> .
Definition Range.hpp:278