@@ -323,3 +323,110 @@ def test_facet_expression(compile_args):
323
323
324
324
# Check that facet normal is pointing out of the cell
325
325
assert np .dot (midpoint - coords [i ], output ) > 0
326
+
327
+
328
+ def test_facet_geometry_expressions (compile_args ):
329
+ """Test various geometrical quantities for facet expressions."""
330
+ cell = basix .CellType .triangle
331
+ mesh = ufl .Mesh (basix .ufl .element ("Lagrange" , cell , 1 , shape = (2 ,)))
332
+ dtype = np .float64
333
+ points = np .array ([[0.5 ]], dtype = dtype )
334
+ c_type = "double"
335
+ c_xtype = "double"
336
+ ffi = cffi .FFI ()
337
+
338
+ # Prepare reference geometry and working arrays
339
+ coords = np .array ([[1 , 0 , 0 ], [3 , 0 , 0 ], [0 , 2 , 0 ]], dtype = dtype )
340
+ u_coeffs = np .array ([], dtype = dtype )
341
+ consts = np .array ([], dtype = dtype )
342
+ entity_index = np .empty (1 , dtype = np .intc )
343
+ quad_perm = np .array ([0 ], dtype = np .dtype ("uint8" ))
344
+ ffi_data = {
345
+ "const" : ffi .cast (f"{ c_type } *" , consts .ctypes .data ),
346
+ "coeff" : ffi .cast (f"{ c_type } *" , u_coeffs .ctypes .data ),
347
+ "coords" : ffi .cast (f"{ c_xtype } *" , coords .ctypes .data ),
348
+ "entity_index" : ffi .cast ("int *" , entity_index .ctypes .data ),
349
+ "quad_perm" : ffi .cast ("uint8_t *" , quad_perm .ctypes .data ),
350
+ }
351
+
352
+ def check_expression (expression_class , output_shape , entity_values , reference_values ):
353
+ obj = ffcx .codegeneration .jit .compile_expressions (
354
+ [(expression_class (mesh ), points )], cffi_extra_compile_args = compile_args
355
+ )[0 ][0 ]
356
+ output = np .zeros (output_shape , dtype = dtype )
357
+ for i , ref_val in enumerate (reference_values ):
358
+ output [:] = 0
359
+ entity_index [0 ] = i
360
+ obj .tabulate_tensor_float64 (
361
+ ffi .cast (f"{ c_type } *" , output .ctypes .data ),
362
+ ffi_data ["coeff" ],
363
+ ffi_data ["const" ],
364
+ ffi_data ["coords" ],
365
+ ffi_data ["entity_index" ],
366
+ ffi_data ["quad_perm" ],
367
+ )
368
+ np .testing .assert_allclose (output , ref_val )
369
+
370
+ check_expression (
371
+ ufl .geometry .CellFacetJacobian , (2 , 1 ), entity_index , basix .cell .facet_jacobians (cell )
372
+ )
373
+ check_expression (
374
+ ufl .geometry .ReferenceFacetVolume ,
375
+ (1 ,),
376
+ entity_index ,
377
+ basix .cell .facet_reference_volumes (cell ),
378
+ )
379
+ check_expression (
380
+ ufl .geometry .ReferenceCellEdgeVectors ,
381
+ (3 , 2 ),
382
+ entity_index ,
383
+ np .array (
384
+ [
385
+ [
386
+ basix .geometry (cell )[j ] - basix .geometry (cell )[i ]
387
+ for i , j in basix .topology (cell )[1 ]
388
+ ]
389
+ ]
390
+ ),
391
+ )
392
+
393
+
394
+ def test_facet_geometry_expressions_3D (compile_args ):
395
+ cell = basix .CellType .tetrahedron
396
+ c_el = basix .ufl .element ("Lagrange" , cell , 1 , shape = (3 ,))
397
+ mesh = ufl .Mesh (c_el )
398
+ dtype = np .float64
399
+ points = np .array ([[0.33 , 0.33 ]], dtype = dtype )
400
+ c_type = "double"
401
+ c_xtype = "double"
402
+ ffi = cffi .FFI ()
403
+
404
+ # Prepare reference geometry and working arrays
405
+ coords = np .array ([[1 , 0 , 0 ], [3 , 0 , 0 ], [0 , 2 , 0 ], [0 , 0 , 1 ]], dtype = dtype )
406
+ u_coeffs = np .array ([], dtype = dtype )
407
+ consts = np .array ([], dtype = dtype )
408
+ entity_index = np .empty (1 , dtype = np .intc )
409
+ quad_perm = np .array ([0 ], dtype = np .dtype ("uint8" ))
410
+
411
+ # Check ReferenceFacetEdgeVectors
412
+ output = np .zeros ((3 , 3 ))
413
+ triangle_edges = basix .topology (basix .CellType .triangle )[1 ]
414
+ ref_fev = []
415
+ topology = basix .topology (cell )
416
+ geometry = basix .geometry (cell )
417
+ for facet in topology [- 2 ]:
418
+ ref_fev += [geometry [facet [j ]] - geometry [facet [i ]] for i , j in triangle_edges ]
419
+
420
+ ref_fev_code = ffcx .codegeneration .jit .compile_expressions (
421
+ [(ufl .geometry .ReferenceFacetEdgeVectors (mesh ), points )],
422
+ cffi_extra_compile_args = compile_args ,
423
+ )[0 ][0 ]
424
+ ref_fev_code .tabulate_tensor_float64 (
425
+ ffi .cast (f"{ c_type } *" , output .ctypes .data ),
426
+ ffi .cast (f"{ c_type } *" , u_coeffs .ctypes .data ),
427
+ ffi .cast (f"{ c_type } *" , consts .ctypes .data ),
428
+ ffi .cast (f"{ c_xtype } *" , coords .ctypes .data ),
429
+ ffi .cast ("int *" , entity_index .ctypes .data ),
430
+ ffi .cast ("uint8_t *" , quad_perm .ctypes .data ),
431
+ )
432
+ np .testing .assert_allclose (output , np .asarray (ref_fev )[:3 , :])
0 commit comments