66from numpy .testing import assert_array_equal , assert_array_almost_equal ,\
77 assert_array_less
88from matplotlib .testing .decorators import image_comparison
9+ import matplotlib .cm as cm
910
1011
1112def test_delaunay ():
@@ -322,8 +323,8 @@ def gradient_quad(x, y):
322323 cubic_min_E = mtri .CubicTriInterpolator (triang , z )
323324 cubic_geom = mtri .CubicTriInterpolator (triang , z , kind = 'geom' )
324325 zs = quad (xs , ys )
326+ diff_lin = np .abs (linear_interp (xs , ys ) - zs )
325327 for interp in (cubic_min_E , cubic_geom ):
326- diff_lin = np .abs (linear_interp (xs , ys ) - zs )
327328 diff_cubic = np .abs (interp (xs , ys ) - zs )
328329 assert (np .max (diff_lin ) >= 10. * np .max (diff_cubic ))
329330 assert (np .dot (diff_lin , diff_lin ) >=
@@ -461,7 +462,7 @@ def poisson_sparse_matrix(n, m):
461462 assert_array_almost_equal (np .dot (mat_dense , x ), b )
462463
463464 # 2) Same matrix with inserting 2 rows - cols with null diag terms
464- # (but still linked with the rest of the matrice by extra-diag terms)
465+ # (but still linked with the rest of the matrix by extra-diag terms)
465466 (i_zero , j_zero ) = (12 , 49 )
466467 vals , rows , cols , _ = poisson_sparse_matrix (n , m )
467468 rows = rows + 1 * (rows >= i_zero ) + 1 * (rows >= j_zero )
@@ -530,11 +531,10 @@ def test_triinterp_colinear():
530531 # These are not valid triangulations, but we try to deal with the
531532 # simplest violations (i. e. those handled by default TriFinder).
532533 #
533- # Note that CubicTriInterpolator with kind='min_E' or 'geom' still pass a
534- # linear patch test.
535- # For the CubicTriInterpolator, we also test interpolation inside a
536- # flat triangle, by forcing *tri_index* in a call to
537- # :meth:`_interpolate_multikeys`
534+ # Note that the LinearTriInterpolator and the CubicTriInterpolator with
535+ # kind='min_E' or 'geom' still pass a linear patch test.
536+ # We also test interpolation inside a flat triangle, by forcing
537+ # *tri_index* in a call to :meth:`_interpolate_multikeys`.
538538
539539 delta = 0. # If +ve, triangulation is OK, if -ve triangulation invalid,
540540 # if zero have colinear points but should pass tests anyway.
@@ -584,6 +584,197 @@ def test_triinterp_colinear():
584584 assert_array_almost_equal (zs_target , zs )
585585
586586
587+ def test_triinterp_transformations ():
588+ # 1) Testing that the interpolation scheme is invariant by rotation of the
589+ # whole figure.
590+ # Note: This test is non-trivial for a CubicTriInterpolator with
591+ # kind='min_E'. It does fail for a non-isotropic stiffness matrix E of
592+ # :class:`_ReducedHCT_Element` (tested with E=np.diag([1., 1., 1.])), and
593+ # provides a good test for :meth:`get_Kff_and_Ff`of the same class.
594+ #
595+ # 2) Also testing that the interpolation scheme is invariant by expansion
596+ # of the whole figure along one axis.
597+ n_angles = 20
598+ n_radii = 10
599+ min_radius = 0.15
600+
601+ def z (x , y ):
602+ r1 = np .sqrt ((0.5 - x )** 2 + (0.5 - y )** 2 )
603+ theta1 = np .arctan2 (0.5 - x , 0.5 - y )
604+ r2 = np .sqrt ((- x - 0.2 )** 2 + (- y - 0.2 )** 2 )
605+ theta2 = np .arctan2 (- x - 0.2 , - y - 0.2 )
606+ z = - (2 * (np .exp ((r1 / 10 )** 2 )- 1 )* 30. * np .cos (7. * theta1 ) +
607+ (np .exp ((r2 / 10 )** 2 )- 1 )* 30. * np .cos (11. * theta2 ) +
608+ 0.7 * (x ** 2 + y ** 2 ))
609+ return (np .max (z )- z )/ (np .max (z )- np .min (z ))
610+
611+ # First create the x and y coordinates of the points.
612+ radii = np .linspace (min_radius , 0.95 , n_radii )
613+ angles = np .linspace (0 + n_angles , 2 * np .pi + n_angles ,
614+ n_angles , endpoint = False )
615+ angles = np .repeat (angles [..., np .newaxis ], n_radii , axis = 1 )
616+ angles [:, 1 ::2 ] += np .pi / n_angles
617+ x0 = (radii * np .cos (angles )).flatten ()
618+ y0 = (radii * np .sin (angles )).flatten ()
619+ triang0 = mtri .Triangulation (x0 , y0 ) # Delaunay triangulation
620+ z0 = z (x0 , y0 )
621+
622+ # Then create the test points
623+ xs0 = np .linspace (- 1. , 1. , 23 )
624+ ys0 = np .linspace (- 1. , 1. , 23 )
625+ xs0 , ys0 = np .meshgrid (xs0 , ys0 )
626+ xs0 = xs0 .ravel ()
627+ ys0 = ys0 .ravel ()
628+
629+ interp_z0 = {}
630+ for i_angle in range (2 ):
631+ # Rotating everything
632+ theta = 2 * np .pi / n_angles * i_angle
633+ x = np .cos (theta )* x0 + np .sin (theta )* y0
634+ y = - np .sin (theta )* x0 + np .cos (theta )* y0
635+ xs = np .cos (theta )* xs0 + np .sin (theta )* ys0
636+ ys = - np .sin (theta )* xs0 + np .cos (theta )* ys0
637+ triang = mtri .Triangulation (x , y , triang0 .triangles )
638+ linear_interp = mtri .LinearTriInterpolator (triang , z0 )
639+ cubic_min_E = mtri .CubicTriInterpolator (triang , z0 )
640+ cubic_geom = mtri .CubicTriInterpolator (triang , z0 , kind = 'geom' )
641+ dic_interp = {'lin' : linear_interp ,
642+ 'min_E' : cubic_min_E ,
643+ 'geom' : cubic_geom }
644+ # Testing that the interpolation is invariant by rotation...
645+ for interp_key in ['lin' , 'min_E' , 'geom' ]:
646+ interp = dic_interp [interp_key ]
647+ if i_angle == 0 :
648+ interp_z0 [interp_key ] = interp (xs0 , ys0 ) # storage
649+ else :
650+ interpz = interp (xs , ys )
651+ assert_array_almost_equal (interpz , interp_z0 [interp_key ])
652+
653+ scale_factor = 987654.3210
654+ for scaled_axis in ('x' , 'y' ):
655+ # Scaling everything (expansion along scaled_axis)
656+ if scaled_axis == 'x' :
657+ x = scale_factor * x0
658+ y = y0
659+ xs = scale_factor * xs0
660+ ys = ys0
661+ else :
662+ x = x0
663+ y = scale_factor * y0
664+ xs = xs0
665+ ys = scale_factor * ys0
666+ triang = mtri .Triangulation (x , y , triang0 .triangles )
667+ linear_interp = mtri .LinearTriInterpolator (triang , z0 )
668+ cubic_min_E = mtri .CubicTriInterpolator (triang , z0 )
669+ cubic_geom = mtri .CubicTriInterpolator (triang , z0 , kind = 'geom' )
670+ dic_interp = {'lin' : linear_interp ,
671+ 'min_E' : cubic_min_E ,
672+ 'geom' : cubic_geom }
673+ # Testing that the interpolation is invariant by expansion along
674+ # 1 axis...
675+ for interp_key in ['lin' , 'min_E' , 'geom' ]:
676+ interpz = dic_interp [interp_key ](xs , ys )
677+ assert_array_almost_equal (interpz , interp_z0 [interp_key ])
678+
679+
680+ @image_comparison (baseline_images = ['tri_smooth_contouring' ],
681+ extensions = ['png' ], remove_text = True )
682+ def test_tri_smooth_contouring ():
683+ # Image comparison based on example tricontour_smooth_user.
684+ n_angles = 20
685+ n_radii = 10
686+ min_radius = 0.15
687+
688+ def z (x , y ):
689+ r1 = np .sqrt ((0.5 - x )** 2 + (0.5 - y )** 2 )
690+ theta1 = np .arctan2 (0.5 - x , 0.5 - y )
691+ r2 = np .sqrt ((- x - 0.2 )** 2 + (- y - 0.2 )** 2 )
692+ theta2 = np .arctan2 (- x - 0.2 , - y - 0.2 )
693+ z = - (2 * (np .exp ((r1 / 10 )** 2 )- 1 )* 30. * np .cos (7. * theta1 ) +
694+ (np .exp ((r2 / 10 )** 2 )- 1 )* 30. * np .cos (11. * theta2 ) +
695+ 0.7 * (x ** 2 + y ** 2 ))
696+ return (np .max (z )- z )/ (np .max (z )- np .min (z ))
697+
698+ # First create the x and y coordinates of the points.
699+ radii = np .linspace (min_radius , 0.95 , n_radii )
700+ angles = np .linspace (0 + n_angles , 2 * np .pi + n_angles ,
701+ n_angles , endpoint = False )
702+ angles = np .repeat (angles [..., np .newaxis ], n_radii , axis = 1 )
703+ angles [:, 1 ::2 ] += np .pi / n_angles
704+ x0 = (radii * np .cos (angles )).flatten ()
705+ y0 = (radii * np .sin (angles )).flatten ()
706+ triang0 = mtri .Triangulation (x0 , y0 ) # Delaunay triangulation
707+ z0 = z (x0 , y0 )
708+ xmid = x0 [triang0 .triangles ].mean (axis = 1 )
709+ ymid = y0 [triang0 .triangles ].mean (axis = 1 )
710+ mask = np .where (xmid * xmid + ymid * ymid < min_radius * min_radius , 1 , 0 )
711+ triang0 .set_mask (mask )
712+
713+ # Then the plot
714+ plt .title ("Refined tricontouring, subdiv=4" )
715+ refiner = mtri .UniformTriRefiner (triang0 )
716+ tri_refi , z_test_refi = refiner .refine_field (z0 , subdiv = 4 )
717+ levels = np .arange (0. , 1. , 0.025 )
718+ plt .triplot (triang0 , lw = 0.5 , color = '0.5' )
719+ plt .tricontour (tri_refi , z_test_refi , levels = levels , colors = "black" )
720+
721+
722+ @image_comparison (baseline_images = ['tri_smooth_gradient' ],
723+ extensions = ['png' ], remove_text = True )
724+ def test_tri_smooth_gradient ():
725+ # Image comparison based on example trigradient_demo.
726+
727+ def dipole_potential (x , y ):
728+ """ An electric dipole potential V """
729+ r_sq = x ** 2 + y ** 2
730+ theta = np .arctan2 (y , x )
731+ z = np .cos (theta )/ r_sq
732+ return (np .max (z )- z ) / (np .max (z )- np .min (z ))
733+
734+ # Creating a Triangulation
735+ n_angles = 30
736+ n_radii = 10
737+ min_radius = 0.2
738+ radii = np .linspace (min_radius , 0.95 , n_radii )
739+ angles = np .linspace (0 , 2 * np .pi , n_angles , endpoint = False )
740+ angles = np .repeat (angles [..., np .newaxis ], n_radii , axis = 1 )
741+ angles [:, 1 ::2 ] += np .pi / n_angles
742+ x = (radii * np .cos (angles )).flatten ()
743+ y = (radii * np .sin (angles )).flatten ()
744+ V = dipole_potential (x , y )
745+ triang = mtri .Triangulation (x , y )
746+ xmid = x [triang .triangles ].mean (axis = 1 )
747+ ymid = y [triang .triangles ].mean (axis = 1 )
748+ mask = np .where (xmid * xmid + ymid * ymid < min_radius * min_radius , 1 , 0 )
749+ triang .set_mask (mask )
750+
751+ # Refine data - interpolates the electrical potential V
752+ refiner = mtri .UniformTriRefiner (triang )
753+ tri_refi , z_test_refi = refiner .refine_field (V , subdiv = 3 )
754+
755+ # Computes the electrical field (Ex, Ey) as gradient of -V
756+ tci = mtri .CubicTriInterpolator (triang , - V )
757+ (Ex , Ey ) = tci .gradient (triang .x , triang .y )
758+ E_norm = np .sqrt (Ex ** 2 + Ey ** 2 )
759+
760+ # Plot the triangulation, the potential iso-contours and the vector field
761+ plt .figure ()
762+ plt .gca ().set_aspect ('equal' )
763+ plt .triplot (triang , color = '0.8' )
764+
765+ levels = np .arange (0. , 1. , 0.01 )
766+ cmap = cm .get_cmap (name = 'hot' , lut = None )
767+ plt .tricontour (tri_refi , z_test_refi , levels = levels , cmap = cmap ,
768+ linewidths = [2.0 , 1.0 , 1.0 , 1.0 ])
769+ # Plots direction of the electrical vector field
770+ plt .quiver (triang .x , triang .y , Ex / E_norm , Ey / E_norm ,
771+ units = 'xy' , scale = 10. , zorder = 3 , color = 'blue' ,
772+ width = 0.007 , headwidth = 3. , headlength = 4. )
773+
774+ plt .title ('Gradient plot: an electrical dipole' )
775+ plt .show ()
776+
777+
587778def test_tritools ():
588779 # Tests TriAnalyzer.scale_factors on masked triangulation
589780 # Tests circle_ratios on equilateral and right-angled triangle.
0 commit comments