示例#1
0
def test_sineWave_disp_rotation_invariance(comm, pnp, nx, ny, basenpoints):
    """
    for a sinusoidal displacement, test if the energy depends on if the wave is
    oriented in x or y direction

    Parameters
    ----------
    comm
    pnp
    fftengine_class
    nx
    ny
    basenpoints

    Returns
    -------

    """
    nx += basenpoints
    ny += basenpoints
    sx = 3.  # 30.0
    sy = 3.

    # equivalent Young's modulus
    E_s = 1.0

    computedenergies = []
    computedenergies_kspace = []
    for k in [(min(nx, ny) // 2, 0), (0, min(nx, ny) // 2)]:
        qx = k[0] * np.pi * 2 / sx
        qy = k[1] * np.pi * 2 / sy

        Y, X = np.meshgrid(
            np.linspace(0, sy, ny + 1)[:-1],
            np.linspace(0, sx, nx + 1)[:-1])
        # At the Nyquist frequency for even number of points, the energy
        # computation can only be exact for this point
        disp = np.cos(qx * X + qy * Y) + np.sin(qx * X + qy * Y)

        substrate = PeriodicFFTElasticHalfSpace((nx, ny),
                                                E_s, (sx, sy),
                                                fft='mpi',
                                                communicator=comm)

        computedenergies_kspace += [
            substrate.evaluate(disp[substrate.subdomain_slices],
                               pot=True,
                               forces=False)[0]
        ]
        computedenergies += [
            substrate.evaluate(disp[substrate.subdomain_slices],
                               pot=True,
                               forces=True)[0]
        ]

    # np.testing.assert_allclose(computedpressures[0],computedpressures[1].T)
    np.testing.assert_allclose(*computedenergies, rtol=1e-10)
    np.testing.assert_allclose(*computedenergies_kspace, rtol=1e-10)
 def test_same_energy(self):
     """
     Asserts that the energies computed in the real space and in the fourier
     space are the same
     """
     for res in [(16, 16), (16, 15), (15, 16), (15, 9)]:
         disp = np.random.normal(size=res)
         hs = PeriodicFFTElasticHalfSpace(res, self.young,
                                          self.physical_sizes)
         np.testing.assert_allclose(
             hs.evaluate(disp, pot=True, forces=True)[0],
             hs.evaluate(disp, pot=True, forces=False)[0])
    def test_gradient(self):
        res = size = (2, 2)
        disp = random(res)
        disp -= disp.mean()
        hs = PeriodicFFTElasticHalfSpace(res, self.young, size)
        hs.compute(disp, forces=True)
        f = hs.energy
        g = -hs.force
        approx_g = Tools.evaluate_gradient(
            lambda x: hs.evaluate(x, forces=True)[0], disp, 1e-5)

        tol = 1e-8
        error = Tools.mean_err(g, approx_g)
        msg = []
        msg.append("f = {}".format(f))
        msg.append("g = {}".format(g))
        msg.append('approx = {}'.format(approx_g))
        msg.append("error = {}".format(error))
        msg.append("tol = {}".format(tol))
        self.assertTrue(error < tol, ", ".join(msg))
示例#4
0
def test_sineWave_disp(comm, pnp, nx, ny, basenpoints):
    """
    for given sinusoidal displacements, compares the pressures and the energies
    to the analytical solutions

    Special cases at the edges of the fourier domain are done

    Parameters
    ----------
    comm
    pnp
    fftengine_class
    nx
    ny
    basenpoints

    Returns
    -------

    """
    nx += basenpoints
    ny += basenpoints
    sx = 2.45  # 30.0
    sy = 1.0

    # equivalent Young's modulus
    E_s = 1.0

    for k in [(1, 0), (0, 1), (1, 2), (nx // 2, 0), (1, ny // 2), (0, 2),
              (nx // 2, ny // 2), (0, ny // 2)]:
        # print("testing wavevector ({}* np.pi * 2 / sx,
        # {}* np.pi * 2 / sy) ".format(*k))
        qx = k[0] * np.pi * 2 / sx
        qy = k[1] * np.pi * 2 / sy
        q = np.sqrt(qx**2 + qy**2)

        Y, X = np.meshgrid(
            np.linspace(0, sy, ny + 1)[:-1],
            np.linspace(0, sx, nx + 1)[:-1])
        disp = np.cos(qx * X + qy * Y) + np.sin(qx * X + qy * Y)

        refpressure = -disp * E_s / 2 * q

        substrate = PeriodicFFTElasticHalfSpace((nx, ny),
                                                E_s, (sx, sy),
                                                fft='mpi',
                                                communicator=comm)
        fftengine = FFT((nx, ny), fft='mpi', communicator=comm)
        fftengine.create_plan(1)

        kpressure = substrate.evaluate_k_force(
            disp[substrate.subdomain_slices]) / substrate.area_per_pt / (nx *
                                                                         ny)
        expected_k_disp = np.zeros((nx // 2 + 1, ny), dtype=complex)
        expected_k_disp[k[0], k[1]] += .5 - .5j

        # add the symetrics
        if k[0] == 0:
            expected_k_disp[0, -k[1]] += .5 + .5j
        if k[0] == nx // 2 and nx % 2 == 0:
            expected_k_disp[k[0], -k[1]] += .5 + .5j

        fft_disp = np.zeros(substrate.nb_fourier_grid_pts,
                            order='f',
                            dtype=complex)
        fftengine.fft(disp[substrate.subdomain_slices], fft_disp)
        np.testing.assert_allclose(fft_disp / (nx * ny),
                                   expected_k_disp[substrate.fourier_slices],
                                   rtol=1e-7,
                                   atol=1e-10)

        expected_k_pressure = -E_s / 2 * q * expected_k_disp
        np.testing.assert_allclose(
            kpressure,
            expected_k_pressure[substrate.fourier_slices],
            rtol=1e-7,
            atol=1e-10)

        computedpressure = substrate.evaluate_force(
            disp[substrate.subdomain_slices]) / substrate.area_per_pt
        np.testing.assert_allclose(computedpressure,
                                   refpressure[substrate.subdomain_slices],
                                   atol=1e-10,
                                   rtol=1e-7)

        computedenergy_kspace = \
            substrate.evaluate(disp[substrate.subdomain_slices], pot=True,
                               forces=False)[0]
        computedenergy = \
            substrate.evaluate(disp[substrate.subdomain_slices], pot=True,
                               forces=True)[0]
        refenergy = E_s / 8 * 2 * q * sx * sy

        # print(substrate.nb_domain_grid_pts[-1] % 2)
        # print(substrate.nb_fourier_grid_pts)
        # print(substrate.fourier_locations[-1] +
        # substrate.nb_fourier_grid_pts[-1] - 1)
        # print(substrate.nb_domain_grid_pts[-1] // 2 )
        # print(computedenergy)
        # print(computedenergy_kspace)
        # print(refenergy)
        np.testing.assert_allclose(
            computedenergy,
            refenergy,
            rtol=1e-10,
            err_msg="wavevektor {} for nb_domain_grid_pts {}, "
            "subdomain nb_grid_pts {}, nb_fourier_grid_pts {}".format(
                k, substrate.nb_domain_grid_pts,
                substrate.nb_subdomain_grid_pts,
                substrate.nb_fourier_grid_pts))
        np.testing.assert_allclose(
            computedenergy_kspace,
            refenergy,
            rtol=1e-10,
            err_msg="wavevektor {} for nb_domain_grid_pts {}, "
            "subdomain nb_grid_pts {}, nb_fourier_grid_pts {}".format(
                k, substrate.nb_domain_grid_pts,
                substrate.nb_subdomain_grid_pts,
                substrate.nb_fourier_grid_pts))
示例#5
0
def test_multipleSineWaves_evaluate(comm, pnp, nx, ny, basenpoints):
    """
    displacements: superposition of sinwaves, compares forces and energes with
    analytical solution

    Parameters
    ----------
    comm
    pnp
    fftengine_class
    nx
    ny
    basenpoints

    Returns
    -------

    """
    nx += basenpoints
    ny += basenpoints
    sx = 2  # 30.0
    sy = 1.0
    # equivalent Young's modulus
    E_s = 1.0

    Y, X = np.meshgrid(
        np.linspace(0, sy, ny + 1)[:-1],
        np.linspace(0, sx, nx + 1)[:-1])

    disp = np.zeros((nx, ny))
    refForce = np.zeros((nx, ny))

    refEnergy = 0
    for qx, qy in zip((1, 0, 5, nx // 2 - 1), (4, 4, 0, ny // 2 - 2)):
        qx = qx * np.pi * 2 / sx
        qy = qy * np.pi * 2 / sy

        q = np.sqrt(qx**2 + qy**2)
        h = 1  # q**(-0.8)
        disp += h * (np.cos(qx * X + qy * Y) + np.sin(qx * X + qy * Y))
        refForce += h * (np.cos(qx * X + qy * Y) +
                         np.sin(qx * X + qy * Y)) * E_s / 2 * q
        refEnergy += E_s / 8 * q * 2 * h**2
        # * 2 because the amplitude of cos(x) + sin(x) is sqrt(2)

    # max possible Wavelengths at the edge

    for qx, qy in zip((nx // 2, nx // 2, 0), (ny // 2, 0, ny // 2)):
        qx = qx * np.pi * 2 / sx
        qy = qy * np.pi * 2 / sy

        q = np.sqrt(qx**2 + qy**2)
        h = 1  # q**(-0.8)
        disp += h * (np.cos(qx * X + qy * Y) + np.sin(qx * X + qy * Y))
        refForce += h * (np.cos(qx * X + qy * Y) +
                         np.sin(qx * X + qy * Y)) * E_s / 2 * q

        refEnergy += E_s / 8 * q * h**2 * 2
        # * 2 because the amplitude of cos(x) + sin(x) is sqrt(2)

    refEnergy *= sx * sy
    refForce *= -sx * sy / (nx * ny)

    substrate = PeriodicFFTElasticHalfSpace((nx, ny),
                                            E_s, (sx, sy),
                                            fft='mpi',
                                            communicator=comm)
    computed_E_k_space = substrate.evaluate(disp[substrate.subdomain_slices],
                                            pot=True,
                                            forces=False)[0]
    # If force is not queried this computes the energy using kspace
    computed_E_realspace, computed_force = substrate.evaluate(
        disp[substrate.subdomain_slices], pot=True, forces=True)

    # print("{}: Local: E_kspace: {}, E_realspace: {}"
    # .format(substrate.fftengine.comm.Get_rank(),computed_E_k_space,computed_E_realspace))
    # print(computed_E_k_space)
    # print(refEnergy)

    # if substrate.fftengine.comm.Get_rank() == 0 :
    #    print(computed_E_k_space)
    #    print(computed_E_realspace)

    # print("{}: Global: E_kspace: {}, E_realspace: {}"
    # .format(substrate.fftengine.comm.Get_rank(),
    # computed_E_k_space, computed_E_realspace))

    # Make an MPI-Reduce of the Energies !
    # print(substrate.evaluate_elastic_energy(refForce, disp))
    # print(0.5*np.vdot(refForce,disp))
    # print(substrate.evaluate_elastic_energy(substrate.evaluate_force(disp),disp))
    # print(computed_E_k_space)
    # print(computed_E_realspace)
    # print(refEnergy)

    np.testing.assert_almost_equal(computed_E_k_space, refEnergy)
    np.testing.assert_almost_equal(computed_E_realspace, refEnergy)
    np.testing.assert_allclose(computed_force,
                               refForce[substrate.subdomain_slices],
                               atol=1e-7,
                               rtol=1e-10)