8282 }
8383}
8484
85+ /// Checks that the provided quadrature rules are consistent, in the sense that
86+ /// the number of elements for each table is identical, and that each rule has
87+ /// consistent numbers of points, weights and data entries.
88+ fn check_rules_consistency < T , D , Data > (
89+ points : & NestedVec < OPoint < T , D > > ,
90+ weights : & NestedVec < T > ,
91+ data : & NestedVec < Data >
92+ )
93+ where
94+ T : Scalar ,
95+ D : DimName ,
96+ DefaultAllocator : Allocator < T , D >
97+ {
98+ assert_eq ! ( points. len( ) , weights. len( ) ,
99+ "Quadrature point and weight tables must have the same number of rules." ) ;
100+ assert_eq ! ( points. len( ) , data. len( ) ,
101+ "Quadrature point and data tables must have the same number of rules." ) ;
102+
103+ // Ensure that each element has a consistent quadrature rule
104+ let iter = izip ! ( points. iter( ) , weights. iter( ) , data. iter( ) ) ;
105+ for ( element_index, ( element_points, element_weights, element_data) ) in iter. enumerate ( ) {
106+ assert_eq ! (
107+ element_points. len( ) ,
108+ element_weights. len( ) ,
109+ "Element {} has mismatched number of points and weights." ,
110+ element_index
111+ ) ;
112+ assert_eq ! (
113+ element_points. len( ) ,
114+ element_data. len( ) ,
115+ "Element {} has mismatched number of points and data." ,
116+ element_index
117+ ) ;
118+ }
119+ }
120+
85121impl < T , GeometryDim , Data > GeneralQuadratureTable < T , GeometryDim , Data >
86122where
87123 T : Scalar ,
@@ -93,26 +129,7 @@ where
93129 weights : NestedVec < T > ,
94130 data : NestedVec < Data > ,
95131 ) -> 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-
132+ check_rules_consistency ( & points, & weights, & data) ;
116133 Self { points, weights, data }
117134 }
118135
@@ -272,3 +289,105 @@ where
272289 weights. clone_from_slice ( & self . weights ) ;
273290 }
274291}
292+
293+ /// A general quadrature table that avoids duplication of identical rules.
294+ ///
295+ /// In a nutshell, [`CompactQuadratureTable`] sits in between [`UniformQuadratureTable`]
296+ /// and [`GeneralQuadratureTable`]. Like [`GeneralQuadratureTable`], it can store an arbitrary
297+ /// rule per element, but it uses a layer of indirection so that `M` quadrature rules
298+ /// are associated with `N` elements.
299+ ///
300+ /// This can be useful in settings where many elements share the same quadrature data, such
301+ /// as a finite element space with elements of different degrees, or the common case
302+ /// where the elements are the same but different quadrature data is needed in different
303+ /// regions of the mesh.
304+ #[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
305+ pub struct CompactQuadratureTable < T , D , Data =( ) >
306+ where
307+ T : Scalar ,
308+ D : DimName ,
309+ DefaultAllocator : Allocator < T , D > ,
310+ {
311+ #[ serde( bound( serialize = "OPoint<T, D>: Serialize" ) ) ]
312+ #[ serde( bound( deserialize = "OPoint<T, D>: Deserialize<'de>" ) ) ]
313+ points : NestedVec < OPoint < T , D > > ,
314+ weights : NestedVec < T > ,
315+ data : NestedVec < Data > ,
316+ element_to_rule_map : Vec < usize > ,
317+ }
318+
319+ impl < T , D , Data > CompactQuadratureTable < T , D , Data >
320+ where
321+ T : Scalar ,
322+ D : DimName ,
323+ DefaultAllocator : Allocator < T , D > ,
324+ {
325+ /// Construct a new table from the given quadrature rules and a map from elements
326+ /// to quadrature rules.
327+ ///
328+ /// # Panics
329+ ///
330+ /// Panics if `points`, `weights` and `data` are not consistent with each other.
331+ ///
332+ /// Panics if the mapping from elements to quadrature rules contains indices that are
333+ /// out of bounds with respect to the number of quadrature rules.
334+ pub fn from_quadrature_rules_and_map (
335+ points : NestedVec < OPoint < T , D > > ,
336+ weights : NestedVec < T > ,
337+ data : NestedVec < Data > ,
338+ element_to_rule_map : Vec < usize >
339+ ) -> Self {
340+ check_rules_consistency ( & points, & weights, & data) ;
341+ let num_rules = points. len ( ) ;
342+ let rule_indices_in_bounds = element_to_rule_map
343+ . iter ( )
344+ . all ( |rule_index| rule_index < & num_rules) ;
345+ assert ! ( rule_indices_in_bounds,
346+ "Each rule index must correspond to a provided quadrature rule." ) ;
347+ Self {
348+ element_to_rule_map,
349+ points,
350+ weights,
351+ data
352+ }
353+ }
354+
355+ fn rule_index_for_element ( & self , element_index : usize ) -> usize {
356+ self . element_to_rule_map [ element_index]
357+ }
358+ }
359+
360+ impl < T , D , Data > QuadratureTable < T , D > for CompactQuadratureTable < T , D , Data >
361+ where
362+ T : Scalar ,
363+ D : SmallDim ,
364+ Data : Default + Clone ,
365+ DefaultAllocator : Allocator < T , D > ,
366+ {
367+ type Data = Data ;
368+
369+ fn element_quadrature_size ( & self , element_index : usize ) -> usize {
370+ let rule_index = self . rule_index_for_element ( element_index) ;
371+ self . points . get ( rule_index) . expect ( "Internal error: Rule index out of bounds" ) . len ( )
372+ }
373+
374+ fn populate_element_data ( & self , element_index : usize , data : & mut [ Self :: Data ] ) {
375+ let rule_index = self . rule_index_for_element ( element_index) ;
376+ let data_array = self . data . get ( rule_index) . expect ( "Internal error: Rule index out of bounds" ) ;
377+ assert_eq ! ( data. len( ) , data_array. len( ) ,
378+ "Length mismatch in data array: Stored quadrature data array has different length than output array." ) ;
379+ data. clone_from_slice ( data_array) ;
380+ }
381+
382+ fn populate_element_quadrature ( & self , element_index : usize , points : & mut [ OPoint < T , D > ] , weights : & mut [ T ] ) {
383+ let rule_index = self . rule_index_for_element ( element_index) ;
384+ let points_array = self . points . get ( rule_index) . expect ( "Internal error: Rule index out of bounds" ) ;
385+ let weights_array = self . weights . get ( rule_index) . expect ( "Internal error: Rule index out of bounds" ) ;
386+ assert_eq ! ( points. len( ) , points_array. len( ) ,
387+ "Length mismatch in points array: Stored points array has different length than output array." ) ;
388+ assert_eq ! ( weights. len( ) , weights_array. len( ) ,
389+ "Length mismatch in points array: Stored points array has different length than output array." ) ;
390+ points. clone_from_slice ( points_array) ;
391+ weights. clone_from_slice ( weights_array) ;
392+ }
393+ }
0 commit comments