1
- # Copyright (C) 2009-2022 Chris N. Richardson, Garth N. Wells and Michal Habera
1
+ # Copyright (C) 2009-2023 Chris N. Richardson, Garth N. Wells and Michal Habera
2
2
#
3
3
# This file is part of DOLFINx (https://www.fenicsproject.org)
4
4
#
5
5
# SPDX-License-Identifier: LGPL-3.0-or-later
6
- """Collection of functions and function spaces"""
6
+ """Finite element function spaces and functions """
7
7
8
8
from __future__ import annotations
9
9
14
14
15
15
from functools import singledispatch
16
16
17
- import numpy as np
18
- import numpy .typing as npt
19
-
20
17
import basix
21
18
import basix .ufl_wrapper
19
+ import numpy as np
20
+ import numpy .typing as npt
22
21
import ufl
23
22
import ufl .algorithms
24
23
import ufl .algorithms .analysis
25
- from dolfinx import cpp as _cpp
26
- from dolfinx import jit , la
27
24
from dolfinx .fem import dofmap
25
+ from petsc4py import PETSc
28
26
from ufl .domain import extract_unique_domain
29
27
30
- from petsc4py import PETSc
28
+ from dolfinx import cpp as _cpp
29
+ from dolfinx import jit , la
31
30
32
31
33
32
class Constant (ufl .Constant ):
@@ -41,7 +40,6 @@ def __init__(self, domain, c: typing.Union[np.ndarray, typing.Sequence, float]):
41
40
"""
42
41
c = np .asarray (c )
43
42
super ().__init__ (domain , c .shape )
44
-
45
43
try :
46
44
if c .dtype == np .complex64 :
47
45
self ._cpp_object = _cpp .fem .Constant_complex64 (c )
@@ -373,13 +371,11 @@ def _(expr: Expression, cells: typing.Optional[np.ndarray] = None):
373
371
except TypeError :
374
372
# u is callable
375
373
assert callable (u )
376
- x = _cpp .fem .interpolation_coords (
377
- self ._V .element , self ._V .mesh , cells )
378
- self ._cpp_object .interpolate (
379
- np .asarray (u (x ), dtype = self .dtype ), cells )
374
+ x = _cpp .fem .interpolation_coords (self ._V .element , self ._V .mesh ._cpp_object , cells )
375
+ self ._cpp_object .interpolate (np .asarray (u (x ), dtype = self .dtype ), cells )
380
376
381
377
def copy (self ) -> Function :
382
- """Return a copy of the Function. The FunctionSpace is shared and the
378
+ """Create a copy of the Function. The FunctionSpace is shared and the
383
379
degree-of-freedom vector is copied.
384
380
385
381
"""
@@ -445,8 +441,7 @@ def split(self) -> tuple[Function, ...]:
445
441
446
442
def collapse (self ) -> Function :
447
443
u_collapsed = self ._cpp_object .collapse ()
448
- V_collapsed = FunctionSpace (None , self .ufl_element (),
449
- u_collapsed .function_space )
444
+ V_collapsed = FunctionSpace (self .function_space ._mesh , self .ufl_element (), u_collapsed .function_space )
450
445
return Function (V_collapsed , u_collapsed .x )
451
446
452
447
@@ -459,23 +454,13 @@ class ElementMetaData(typing.NamedTuple):
459
454
class FunctionSpace (ufl .FunctionSpace ):
460
455
"""A space on which Functions (fields) can be defined."""
461
456
462
- def __init__ (self , mesh : typing . Union [ None , Mesh ] ,
457
+ def __init__ (self , mesh : Mesh ,
463
458
element : typing .Union [ufl .FiniteElementBase , ElementMetaData , typing .Tuple [str , int ]],
464
459
cppV : typing .Optional [_cpp .fem .FunctionSpace ] = None ,
465
460
form_compiler_options : dict [str , typing .Any ] = {}, jit_options : dict [str , typing .Any ] = {}):
466
461
"""Create a finite element function space."""
467
462
468
- # Create function space from a UFL element and existing cpp
469
- # FunctionSpace
470
- if cppV is not None :
471
- assert mesh is None
472
- ufl_domain = cppV .mesh .ufl_domain ()
473
- super ().__init__ (ufl_domain , element )
474
- self ._cpp_object = cppV
475
- return
476
-
477
- if mesh is not None :
478
- assert cppV is None
463
+ if cppV is None :
479
464
# Initialise the ufl.FunctionSpace
480
465
if isinstance (element , ufl .FiniteElementBase ):
481
466
super ().__init__ (mesh .ufl_domain (), element )
@@ -491,17 +476,26 @@ def __init__(self, mesh: typing.Union[None, Mesh],
491
476
jit_options = jit_options )
492
477
493
478
ffi = module .ffi
494
- cpp_element = _cpp .fem .FiniteElement (
495
- ffi .cast ("uintptr_t" , ffi .addressof (self ._ufcx_element )))
479
+ cpp_element = _cpp .fem .FiniteElement (ffi .cast ("uintptr_t" , ffi .addressof (self ._ufcx_element )))
496
480
cpp_dofmap = _cpp .fem .create_dofmap (mesh .comm , ffi .cast (
497
481
"uintptr_t" , ffi .addressof (self ._ufcx_dofmap )), mesh .topology , cpp_element )
498
482
499
- # Initialize the cpp.FunctionSpace
500
- self ._cpp_object = _cpp .fem .FunctionSpace (
501
- mesh , cpp_element , cpp_dofmap )
483
+ # Initialize the cpp.FunctionSpace and store mesh
484
+ self ._cpp_object = _cpp .fem .FunctionSpace (mesh ._cpp_object , cpp_element , cpp_dofmap )
485
+ self ._mesh = mesh
486
+ else :
487
+ # Create function space from a UFL element and an existing
488
+ # C++ FunctionSpace
489
+ if mesh ._cpp_object is not cppV .mesh :
490
+ raise RecursionError ("Meshes do not match in FunctionSpace initialisation." )
491
+ ufl_domain = mesh .ufl_domain ()
492
+ super ().__init__ (ufl_domain , element )
493
+ self ._cpp_object = cppV
494
+ self ._mesh = mesh
495
+ return
502
496
503
497
def clone (self ) -> FunctionSpace :
504
- """Return a new FunctionSpace :math:`W` which shares data with this
498
+ """Create a new FunctionSpace :math:`W` which shares data with this
505
499
FunctionSpace :math:`V`, but with a different unique integer ID.
506
500
507
501
This function is helpful for defining mixed problems and using
@@ -513,10 +507,12 @@ def clone(self) -> FunctionSpace:
513
507
diagonal blocks. This is relevant for the handling of boundary
514
508
conditions.
515
509
510
+ Returns:
511
+ A new function space that shares data
512
+
516
513
"""
517
- Vcpp = _cpp .fem .FunctionSpace (
518
- self ._cpp_object .mesh , self ._cpp_object .element , self ._cpp_object .dofmap )
519
- return FunctionSpace (None , self .ufl_element (), Vcpp )
514
+ Vcpp = _cpp .fem .FunctionSpace (self ._cpp_object .mesh , self ._cpp_object .element , self ._cpp_object .dofmap )
515
+ return FunctionSpace (self ._mesh , self .ufl_element (), Vcpp )
520
516
521
517
@property
522
518
def num_sub_spaces (self ) -> int :
@@ -536,7 +532,7 @@ def sub(self, i: int) -> FunctionSpace:
536
532
assert self .ufl_element ().num_sub_elements () > i
537
533
sub_element = self .ufl_element ().sub_elements ()[i ]
538
534
cppV_sub = self ._cpp_object .sub ([i ])
539
- return FunctionSpace (None , sub_element , cppV_sub )
535
+ return FunctionSpace (self . _mesh , sub_element , cppV_sub )
540
536
541
537
def component (self ):
542
538
"""Return the component relative to the parent space."""
@@ -562,15 +558,13 @@ def __ne__(self, other):
562
558
"""Comparison for inequality."""
563
559
return super ().__ne__ (other ) or self ._cpp_object != other ._cpp_object
564
560
565
- def ufl_cell (self ):
566
- return self ._cpp_object .mesh .ufl_cell ()
567
-
568
561
def ufl_function_space (self ) -> ufl .FunctionSpace :
569
562
"""UFL function space"""
570
563
return self
571
564
572
565
@property
573
566
def element (self ):
567
+ """Function space finite element."""
574
568
return self ._cpp_object .element
575
569
576
570
@property
@@ -579,9 +573,9 @@ def dofmap(self) -> dofmap.DofMap:
579
573
return dofmap .DofMap (self ._cpp_object .dofmap )
580
574
581
575
@property
582
- def mesh (self ) -> _cpp . mesh . Mesh :
583
- """Return the mesh on which the function space is defined."""
584
- return self ._cpp_object . mesh
576
+ def mesh (self ) -> Mesh :
577
+ """Mesh on which the function space is defined."""
578
+ return self ._mesh
585
579
586
580
def collapse (self ) -> tuple [FunctionSpace , np .ndarray ]:
587
581
"""Collapse a subspace and return a new function space and a map from
@@ -592,31 +586,37 @@ def collapse(self) -> tuple[FunctionSpace, np.ndarray]:
592
586
593
587
"""
594
588
cpp_space , dofs = self ._cpp_object .collapse ()
595
- V = FunctionSpace (None , self .ufl_element (), cpp_space )
589
+ V = FunctionSpace (self . _mesh , self .ufl_element (), cpp_space )
596
590
return V , dofs
597
591
598
- def tabulate_dof_coordinates (self ) -> np .ndarray :
592
+ def tabulate_dof_coordinates (self ) -> npt .NDArray [np .float64 ]:
593
+ """Tabulate the coordinates of the degrees-of-freedom in the function space.
594
+
595
+ Returns:
596
+ Coordinates of the degrees-of-freedom.
597
+
598
+ Notes:
599
+ This method should be used only for elements with point
600
+ evaluation degrees-of-freedom.
601
+
602
+ """
599
603
return self ._cpp_object .tabulate_dof_coordinates ()
600
604
601
605
602
- def VectorFunctionSpace (mesh : Mesh , element : typing .Union [ElementMetaData , typing .Tuple [str , int ]], dim = None ,
603
- restriction = None ) -> FunctionSpace :
606
+ def VectorFunctionSpace (mesh : Mesh , element : typing .Union [ElementMetaData , typing .Tuple [str , int ]],
607
+ dim = None ) -> FunctionSpace :
604
608
"""Create vector finite element (composition of scalar elements) function space."""
605
-
606
609
e = ElementMetaData (* element )
607
- ufl_element = basix .ufl_wrapper .create_vector_element (
608
- e .family , mesh .ufl_cell ().cellname (), e .degree , dim = dim ,
609
- gdim = mesh .geometry .dim )
610
-
610
+ ufl_element = basix .ufl_wrapper .create_vector_element (e .family , mesh .ufl_cell ().cellname (), e .degree ,
611
+ dim = dim , gdim = mesh .geometry .dim )
611
612
return FunctionSpace (mesh , ufl_element )
612
613
613
614
614
615
def TensorFunctionSpace (mesh : Mesh , element : typing .Union [ElementMetaData , typing .Tuple [str , int ]], shape = None ,
615
- symmetry : typing .Optional [bool ] = None , restriction = None ) -> FunctionSpace :
616
+ symmetry : typing .Optional [bool ] = None ) -> FunctionSpace :
616
617
"""Create tensor finite element (composition of scalar elements) function space."""
617
-
618
618
e = ElementMetaData (* element )
619
- ufl_element = basix .ufl_wrapper .create_tensor_element (
620
- e . family , mesh . ufl_cell (). cellname (), e .degree , shape = shape , symmetry = symmetry ,
621
- gdim = mesh .geometry .dim )
619
+ ufl_element = basix .ufl_wrapper .create_tensor_element (e . family , mesh . ufl_cell (). cellname (),
620
+ e .degree , shape = shape , symmetry = symmetry ,
621
+ gdim = mesh .geometry .dim )
622
622
return FunctionSpace (mesh , ufl_element )
0 commit comments