@@ -556,82 +556,120 @@ def __init__(self, ref_el, degree, order=0, **kwargs):
556556 super ().__init__ (ref_el , degree , degree , U .expansion_set , coeffs )
557557
558558
559- class MacroExpansionSet (expansions .ExpansionSet ):
560-
559+ def pullback (mapping , Jinv , phi ):
560+ try :
561+ formdegree = {
562+ "affine" : (0 ,),
563+ "covariant piola" : (1 ,),
564+ "contravariant piola" : (2 ,),
565+ "double covariant piola" : (1 , 1 ),
566+ "double contravariant piola" : (2 , 2 ),
567+ "covariant contravariant piola" : (1 , 2 ),
568+ "contravariant covariant piola" : (2 , 1 ), }[mapping ]
569+ except KeyError :
570+ raise ValueError (f"Unrecognized mapping { mapping } " )
571+
572+ F1 = Jinv .T
573+ F2 = numpy .linalg .inv (Jinv ) * numpy .linalg .det (Jinv )
574+
575+ perm = [* range (1 , phi .ndim - 1 ), 0 , - 1 ]
576+ phi = phi .transpose (perm )
577+
578+ for i , k in enumerate (formdegree ):
579+ if k == 0 :
580+ continue
581+ F = F1 if k == 1 else F2
582+ phi = numpy .tensordot (F , phi , (1 , i ))
583+
584+ perm = [- 2 , * range (phi .ndim - 2 ), - 1 ]
585+ phi = phi .transpose (perm )
586+ return phi
587+
588+
589+ class MacroPolynomialSet (polynomial_set .PolynomialSet ):
590+ """Constructs a PolynomialSet by tiling a CiarletElement on a
591+ SimplicialComplex.
592+
593+ :arg ref_el: The SimplicialComplex.
594+ :arg element: The CiarletElement.
595+ """
561596 def __init__ (self , ref_el , element ):
562- self .element = element
563- self .ref_el = ref_el
564- self .variant = None
565- sd = ref_el .get_spatial_dimension ()
566597 top = ref_el .get_topology ()
567- base_ref_el = element .ref_el
568- base_verts = base_ref_el .get_vertices ()
569-
570- self .affine_mappings = [reference_element .make_affine_mapping (
571- ref_el .get_vertices_of_subcomplex (top [sd ][cell ]),
572- base_verts ) for cell in top [sd ]]
573- self .scale = 1
574- self .continuity = element .entity_dofs ()
575- self .recurrence_order = element .degree
576- self ._dmats_cache = {}
577- self ._cell_node_map_cache = {}
578-
579- def _tabulate_on_cell (self , n , pts , order = 0 , cell = 0 , direction = None ):
580- A , b = self .affine_mappings [cell ]
581- ref_pts = numpy .add (numpy .dot (pts , A .T ), b )
582- Jinv = A if direction is None else numpy .dot (A , direction )[:, None ]
583- phis = self .element .tabulate (order , ref_pts )
584- for alpha in phis :
585- phis [alpha ] = self .pullback (Jinv , phis [alpha ])
586- return phis
587-
588- def pullback (self , Jinv , phi ):
589- mapping = self .element .mapping ()[0 ]
590- if mapping == "covariant piola" :
591- phi = numpy .tensordot (Jinv .T , phi , (1 , 1 )).transpose ((1 , 0 , 2 ))
592- elif mapping == "contravariant piola" :
593- J = numpy .linalg .inv (Jinv )
594- Jdet = abs (numpy .linalg .det (J ))
595- phi = numpy .tensordot (J / Jdet , phi , (1 , 1 )).transpose ((1 , 0 , 2 ))
596- elif mapping != "identity" :
597- raise ValueError (f"Unrecognized mapping { mapping } " )
598-
599- return phi
598+ sd = ref_el .get_spatial_dimension ()
599+
600+ mapping , = set (element .mapping ())
601+ base_ref_el = element .get_reference_element ()
602+ base_entity_ids = element .entity_dofs ()
603+ n = element .degree ()
604+
605+ base_expansion_set = element .get_nodal_basis ().get_expansion_set ()
606+ expansion_set = base_expansion_set .reconstruct (ref_el = ref_el )
607+
608+ base_entity_ids = expansions .polynomial_entity_ids (base_ref_el , n , base_entity_ids )
609+ entity_ids = expansions .polynomial_entity_ids (ref_el , n , base_entity_ids )
610+
611+ shp = element .value_shape ()
612+ num_bfs = expansions .polynomial_dimension (ref_el , n , entity_ids )
613+ num_members = expansion_set .get_num_members (n )
614+ coeffs = numpy .zeros ((num_bfs , * shp , num_members ))
615+ base_coeffs = element .get_coeffs ()
616+
617+ rmap = expansions .polynomial_cell_node_map (ref_el , n , base_entity_ids )
618+ cmap = expansion_set .get_cell_node_map (n )
619+ for cell in sorted (top ):
620+ cell_verts = ref_el .get_vertices_of_subcomplex (top [sd ][cell ])
621+ A , b = reference_element .make_affine_mapping (cell_verts , base_ref_el .vertices )
622+
623+ indices = numpy .ix_ (rmap [cell ], * map (range , shp ), cmap [cell ])
624+ coeffs [indices ] = pullback (mapping , A , base_coeffs )
625+
626+ super ().__init__ (ref_el , element .degree (), element .degree (), expansion_set , coeffs )
600627
601628
602629if __name__ == "__main__" :
603- from FIAT import RaviartThomas
630+ from FIAT import Lagrange , Nedelec , RaviartThomas , Regge
604631 from FIAT .reference_element import symmetric_simplex
605632
633+ degree = 1
606634 dim = 3
607635 K = symmetric_simplex (dim )
608- A = IsoSplit (K )
636+ A = AlfeldSplit (K )
609637
610- degree = 1
638+ fe = Lagrange (K , degree )
639+ fe = Nedelec (K , degree )
611640 fe = RaviartThomas (K , degree )
612- # fe = Nedelec(K, degree)
613-
614- U = MacroExpansionSet (A , fe )
641+ fe = Regge (K , 0 )
615642
616643 mapping = fe .mapping ()[0 ]
617644 fdim = fe .formdegree
645+ if isinstance (fdim , tuple ):
646+ fdim , = set (fdim )
618647 comps = []
619648 pts = []
620649 for entity in A .topology [fdim ]:
621650 pts_cur = A .make_points (fdim , entity , degree + fdim )
622651 pts .extend (pts_cur )
623- if mapping == "covariant piola" :
652+ if mapping == "affine" :
653+ comp = numpy .ones (())
654+ elif mapping .endswith ("covariant piola" ):
624655 comp = A .compute_edge_tangent (entity )
625- elif mapping == "contravariant piola" :
656+ elif mapping . endswith ( "contravariant piola" ) :
626657 comp = A .compute_scaled_normal (entity )
658+ if mapping .startswith ("double" ):
659+ comp = numpy .outer (comp , comp )
627660 comps .extend ([comp ] * len (pts_cur ))
628661
629- phis = U ._tabulate (degree , pts )
662+ P = MacroPolynomialSet (A , fe )
663+ phis = P .tabulate (pts )
664+
630665 for alpha in phis :
631666 shape = phis [alpha ].shape
667+ shp = shape [1 :- 1 ]
632668 result = numpy .zeros ((shape [0 ], shape [- 1 ]))
669+
670+ ax = (tuple (range (- len (shp ), 0 )), )* 2
633671 for i , comp in enumerate (comps ):
634- result [..., i ] = numpy .dot (phis [alpha ][..., i ], comp )
672+ result [..., i ] = numpy .tensordot (phis [alpha ][..., i ], comp , ax )
635673 result [abs (result ) < 1E-14 ] = 0
636674 phis [alpha ] = result
637675
0 commit comments