@@ -80,3 +80,44 @@ def test_structured_grid2d_vtk_assigns_quad_cell_types():
8080 triangulated = vtk_grid .triangulate ()
8181
8282 assert triangulated .n_cells == grid .n_elements * 2
83+
84+
85+ def test_evaluate_gradient_2d_world_units ():
86+ """
87+ Gradient must be returned in world units, independent of the cell size.
88+
89+ Regression test for #289: get_element_gradient_for_location returned the
90+ shape-function derivatives with respect to local (0-1) cell coordinates,
91+ so gradients were inflated by step_vector on each axis.
92+ """
93+ grid = StructuredGrid2D (
94+ origin = np .zeros (2 ), nsteps = np .array ([10 , 10 ]), step_vector = np .array ([2.5 , 0.5 ])
95+ )
96+ # f(x, y) = x and f(x, y) = y have unit gradients regardless of cell size
97+ gradient_x = np .mean (grid .evaluate_gradient (grid .barycentre , grid .nodes [:, 0 ]), axis = 0 )
98+ gradient_y = np .mean (grid .evaluate_gradient (grid .barycentre , grid .nodes [:, 1 ]), axis = 0 )
99+ assert np .allclose (gradient_x , np .array ([1.0 , 0.0 ]))
100+ assert np .allclose (gradient_y , np .array ([0.0 , 1.0 ]))
101+
102+
103+ def test_fdi_2d_gradient_resolution_independent ():
104+ """
105+ The interpolated gradient magnitude must not depend on nelements (#289).
106+ """
107+ from LoopStructural .geometry import BoundingBox
108+ from LoopStructural .interpolators import InterpolatorFactory
109+
110+ sqrt2 = np .sqrt (2.0 )
111+ bbox = BoundingBox (dimensions = 2 , origin = np .array ([0.0 , 0.0 ]), maximum = np .array ([100.0 , 100.0 ]))
112+ points = np .random .default_rng (0 ).uniform (10 , 90 , size = (60 , 2 ))
113+ for nelements in (1e3 , 4e3 ):
114+ interpolator = InterpolatorFactory .create_interpolator (
115+ interpolatortype = "FDI" , boundingbox = bbox , nelements = nelements
116+ )
117+ interpolator .set_value_constraints (
118+ np .column_stack ([points , (points [:, 0 ] + points [:, 1 ]) / sqrt2 ])
119+ )
120+ interpolator .setup_interpolator ()
121+ interpolator .solve_system (solver = "cg" )
122+ gradient_norm = np .linalg .norm (interpolator .evaluate_gradient (np .array ([[50.0 , 50.0 ]]))[0 ])
123+ assert np .isclose (gradient_norm , 1.0 , atol = 0.05 )
0 commit comments