|
6 | 6 | from numpy.testing import assert_array_equal, assert_array_almost_equal,\
|
7 | 7 | assert_array_less
|
8 | 8 | from matplotlib.testing.decorators import image_comparison
|
| 9 | +import matplotlib.cm as cm |
9 | 10 |
|
10 | 11 |
|
11 | 12 | def test_delaunay():
|
@@ -322,8 +323,8 @@ def gradient_quad(x, y):
|
322 | 323 | cubic_min_E = mtri.CubicTriInterpolator(triang, z)
|
323 | 324 | cubic_geom = mtri.CubicTriInterpolator(triang, z, kind='geom')
|
324 | 325 | zs = quad(xs, ys)
|
| 326 | + diff_lin = np.abs(linear_interp(xs, ys) - zs) |
325 | 327 | for interp in (cubic_min_E, cubic_geom):
|
326 |
| - diff_lin = np.abs(linear_interp(xs, ys) - zs) |
327 | 328 | diff_cubic = np.abs(interp(xs, ys) - zs)
|
328 | 329 | assert(np.max(diff_lin) >= 10.*np.max(diff_cubic))
|
329 | 330 | assert(np.dot(diff_lin, diff_lin) >=
|
@@ -461,7 +462,7 @@ def poisson_sparse_matrix(n, m):
|
461 | 462 | assert_array_almost_equal(np.dot(mat_dense, x), b) |
462 | 463 |
|
463 | 464 | # 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) |
465 | 466 | (i_zero, j_zero) = (12, 49)
|
466 | 467 | vals, rows, cols, _ = poisson_sparse_matrix(n, m)
|
467 | 468 | rows = rows + 1*(rows >= i_zero) + 1*(rows >= j_zero)
|
@@ -530,11 +531,10 @@ def test_triinterp_colinear():
|
530 | 531 | # These are not valid triangulations, but we try to deal with the
|
531 | 532 | # simplest violations (i. e. those handled by default TriFinder).
|
532 | 533 | #
|
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`. |
538 | 538 |
|
539 | 539 | delta = 0. # If +ve, triangulation is OK, if -ve triangulation invalid,
|
540 | 540 | # if zero have colinear points but should pass tests anyway.
|
@@ -584,6 +584,197 @@ def test_triinterp_colinear():
|
584 | 584 | assert_array_almost_equal(zs_target, zs)
|
585 | 585 |
|
586 | 586 |
|
| 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 | + |
587 | 778 | def test_tritools():
|
588 | 779 | # Tests TriAnalyzer.scale_factors on masked triangulation
|
589 | 780 | # Tests circle_ratios on equilateral and right-angled triangle.
|
|
0 commit comments