@@ -67,21 +67,64 @@ where
6767 data : NestedVec < Data > ,
6868}
6969
70+ fn unit_data_table_for_weights < T > ( points : & NestedVec < T > ) -> NestedVec < ( ) > {
71+ let mut data = NestedVec :: new ( ) ;
72+ for i in 0 ..points. len ( ) {
73+ data. push ( & vec ! [ ( ) ; points. get( i) . unwrap( ) . len( ) ] ) ;
74+ }
75+ data
76+ }
77+
7078impl < T , GeometryDim > GeneralQuadratureTable < T , GeometryDim >
7179where
7280 T : Scalar ,
7381 GeometryDim : DimName ,
7482 DefaultAllocator : Allocator < T , GeometryDim > ,
7583{
7684 pub fn from_points_and_weights ( points : NestedVec < OPoint < T , GeometryDim > > , weights : NestedVec < T > ) -> Self {
77- let mut data = NestedVec :: new ( ) ;
78- for i in 0 ..points. len ( ) {
79- data. push ( & vec ! [ ( ) ; points. get( i) . unwrap( ) . len( ) ] ) ;
80- }
85+ let data = unit_data_table_for_weights ( & weights) ;
8186 Self :: from_points_weights_and_data ( points, weights, data)
8287 }
8388}
8489
90+ /// Checks that the provided quadrature rules are consistent, in the sense that
91+ /// the number of elements for each table is identical, and that each rule has
92+ /// consistent numbers of points, weights and data entries.
93+ fn check_rules_consistency < T , D , Data > ( points : & NestedVec < OPoint < T , D > > , weights : & NestedVec < T > , data : & NestedVec < Data > )
94+ where
95+ T : Scalar ,
96+ D : DimName ,
97+ DefaultAllocator : Allocator < T , D > ,
98+ {
99+ assert_eq ! (
100+ points. len( ) ,
101+ weights. len( ) ,
102+ "Quadrature point and weight tables must have the same number of rules."
103+ ) ;
104+ assert_eq ! (
105+ points. len( ) ,
106+ data. len( ) ,
107+ "Quadrature point and data tables must have the same number of rules."
108+ ) ;
109+
110+ // Ensure that each element has a consistent quadrature rule
111+ let iter = izip ! ( points. iter( ) , weights. iter( ) , data. iter( ) ) ;
112+ for ( element_index, ( element_points, element_weights, element_data) ) in iter. enumerate ( ) {
113+ assert_eq ! (
114+ element_points. len( ) ,
115+ element_weights. len( ) ,
116+ "Element {} has mismatched number of points and weights." ,
117+ element_index
118+ ) ;
119+ assert_eq ! (
120+ element_points. len( ) ,
121+ element_data. len( ) ,
122+ "Element {} has mismatched number of points and data." ,
123+ element_index
124+ ) ;
125+ }
126+ }
127+
85128impl < T , GeometryDim , Data > GeneralQuadratureTable < T , GeometryDim , Data >
86129where
87130 T : Scalar ,
@@ -93,26 +136,7 @@ where
93136 weights : NestedVec < T > ,
94137 data : NestedVec < Data > ,
95138 ) -> Self {
96- assert_eq ! ( points. len( ) , weights. len( ) ) ;
97- assert_eq ! ( points. len( ) , data. len( ) ) ;
98-
99- // Ensure that each element has a consistent quadrature rule
100- let iter = izip ! ( points. iter( ) , weights. iter( ) , data. iter( ) ) ;
101- for ( element_index, ( element_points, element_weights, element_data) ) in iter. enumerate ( ) {
102- assert_eq ! (
103- element_points. len( ) ,
104- element_weights. len( ) ,
105- "Element {} has mismatched number of points and weights." ,
106- element_index
107- ) ;
108- assert_eq ! (
109- element_points. len( ) ,
110- element_data. len( ) ,
111- "Element {} has mismatched number of points and data." ,
112- element_index
113- ) ;
114- }
115-
139+ check_rules_consistency ( & points, & weights, & data) ;
116140 Self { points, weights, data }
117141 }
118142
@@ -272,3 +296,144 @@ where
272296 weights. clone_from_slice ( & self . weights ) ;
273297 }
274298}
299+
300+ /// A general quadrature table that avoids duplication of identical rules.
301+ ///
302+ /// In a nutshell, [`CompactQuadratureTable`] sits in between [`UniformQuadratureTable`]
303+ /// and [`GeneralQuadratureTable`]. Like [`GeneralQuadratureTable`], it can store an arbitrary
304+ /// rule per element, but it uses a layer of indirection so that `M` quadrature rules
305+ /// are associated with `N` elements.
306+ ///
307+ /// This can be useful in settings where many elements share the same quadrature data, such
308+ /// as a finite element space with elements of different degrees, or the common case
309+ /// where the elements are the same but different quadrature data is needed in different
310+ /// regions of the mesh.
311+ #[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
312+ pub struct CompactQuadratureTable < T , D , Data = ( ) >
313+ where
314+ T : Scalar ,
315+ D : DimName ,
316+ DefaultAllocator : Allocator < T , D > ,
317+ {
318+ #[ serde( bound( serialize = "OPoint<T, D>: Serialize" ) ) ]
319+ #[ serde( bound( deserialize = "OPoint<T, D>: Deserialize<'de>" ) ) ]
320+ points : NestedVec < OPoint < T , D > > ,
321+ weights : NestedVec < T > ,
322+ data : NestedVec < Data > ,
323+ element_to_rule_map : Vec < usize > ,
324+ }
325+
326+ impl < T , D > CompactQuadratureTable < T , D >
327+ where
328+ T : Scalar ,
329+ D : DimName ,
330+ DefaultAllocator : Allocator < T , D > ,
331+ {
332+ pub fn from_points_weights_and_map (
333+ points : NestedVec < OPoint < T , D > > ,
334+ weights : NestedVec < T > ,
335+ element_to_rule_map : Vec < usize > ,
336+ ) -> Self {
337+ let data = unit_data_table_for_weights ( & weights) ;
338+ Self :: from_quadrature_rules_and_map ( points, weights, data, element_to_rule_map)
339+ }
340+ }
341+
342+ impl < T , D , Data > CompactQuadratureTable < T , D , Data >
343+ where
344+ T : Scalar ,
345+ D : DimName ,
346+ DefaultAllocator : Allocator < T , D > ,
347+ {
348+ /// Construct a new table from the given quadrature rules and a map from elements
349+ /// to quadrature rules.
350+ ///
351+ /// # Panics
352+ ///
353+ /// Panics if `points`, `weights` and `data` are not consistent with each other.
354+ ///
355+ /// Panics if the mapping from elements to quadrature rules contains indices that are
356+ /// out of bounds with respect to the number of quadrature rules.
357+ pub fn from_quadrature_rules_and_map (
358+ points : NestedVec < OPoint < T , D > > ,
359+ weights : NestedVec < T > ,
360+ data : NestedVec < Data > ,
361+ element_to_rule_map : Vec < usize > ,
362+ ) -> Self {
363+ check_rules_consistency ( & points, & weights, & data) ;
364+ let num_rules = points. len ( ) ;
365+ let rule_indices_in_bounds = element_to_rule_map
366+ . iter ( )
367+ . all ( |rule_index| rule_index < & num_rules) ;
368+ assert ! (
369+ rule_indices_in_bounds,
370+ "Each rule index must correspond to a provided quadrature rule."
371+ ) ;
372+ Self {
373+ element_to_rule_map,
374+ points,
375+ weights,
376+ data,
377+ }
378+ }
379+
380+ fn rule_index_for_element ( & self , element_index : usize ) -> usize {
381+ self . element_to_rule_map [ element_index]
382+ }
383+ }
384+
385+ impl < T , D , Data > QuadratureTable < T , D > for CompactQuadratureTable < T , D , Data >
386+ where
387+ T : Scalar ,
388+ D : SmallDim ,
389+ Data : Default + Clone ,
390+ DefaultAllocator : Allocator < T , D > ,
391+ {
392+ type Data = Data ;
393+
394+ fn element_quadrature_size ( & self , element_index : usize ) -> usize {
395+ let rule_index = self . rule_index_for_element ( element_index) ;
396+ self . points
397+ . get ( rule_index)
398+ . expect ( "Internal error: Rule index out of bounds" )
399+ . len ( )
400+ }
401+
402+ fn populate_element_data ( & self , element_index : usize , data : & mut [ Self :: Data ] ) {
403+ let rule_index = self . rule_index_for_element ( element_index) ;
404+ let data_array = self
405+ . data
406+ . get ( rule_index)
407+ . expect ( "Internal error: Rule index out of bounds" ) ;
408+ assert_eq ! (
409+ data. len( ) ,
410+ data_array. len( ) ,
411+ "Length mismatch in data array: Stored quadrature data array has different length than output array."
412+ ) ;
413+ data. clone_from_slice ( data_array) ;
414+ }
415+
416+ fn populate_element_quadrature ( & self , element_index : usize , points : & mut [ OPoint < T , D > ] , weights : & mut [ T ] ) {
417+ let rule_index = self . rule_index_for_element ( element_index) ;
418+ let points_array = self
419+ . points
420+ . get ( rule_index)
421+ . expect ( "Internal error: Rule index out of bounds" ) ;
422+ let weights_array = self
423+ . weights
424+ . get ( rule_index)
425+ . expect ( "Internal error: Rule index out of bounds" ) ;
426+ assert_eq ! (
427+ points. len( ) ,
428+ points_array. len( ) ,
429+ "Length mismatch in points array: Stored points array has different length than output array."
430+ ) ;
431+ assert_eq ! (
432+ weights. len( ) ,
433+ weights_array. len( ) ,
434+ "Length mismatch in points array: Stored points array has different length than output array."
435+ ) ;
436+ points. clone_from_slice ( points_array) ;
437+ weights. clone_from_slice ( weights_array) ;
438+ }
439+ }
0 commit comments