def test_force_disp_reversibility(self): # since only the zero-frequency is rejected, any force/disp field with # zero mean should be fully reversible tol = 1e-10 for res in ((self.res[0], ), self.res, (self.res[0] + 1, self.res[1]), (self.res[0], self.res[1] + 1)): hs = PeriodicFFTElasticHalfSpace(res, self.young, self.physical_sizes) disp = random(res) disp -= disp.mean() error = Tools.mean_err(disp, hs.evaluate_disp(hs.evaluate_force(disp))) self.assertTrue( error < tol, "for nb_grid_pts = {}, error = {} > tol = {}".format( res, error, tol)) force = random(res) force -= force.mean() error = Tools.mean_err(force, hs.evaluate_force(hs.evaluate_disp(force))) self.assertTrue( error < tol, "for nb_grid_pts = {}, error = {} > tol = {}".format( res, error, tol))
def test_energy(self): tol = 1e-10 L = 2 + rand() # domain length a = 3 + rand() # amplitude of force E = 4 + rand() # Young's Mod for res in [4, 8, 16]: area_per_pt = L / res x = np.arange(res) * area_per_pt force = a * np.cos(2 * np.pi / L * x) # theoretical FFT of force Fforce = np.zeros_like(x) Fforce[1] = Fforce[-1] = res / 2. * a # theoretical FFT of disp Fdisp = np.zeros_like(x) Fdisp[1] = Fdisp[-1] = res / 2. * a / E * L / (np.pi) # verify consistency hs = PeriodicFFTElasticHalfSpace(res, E, L) fforce = rfftn(force.T).T fdisp = hs.greens_function * fforce self.assertTrue( Tools.mean_err(fforce, Fforce, rfft=True) < tol, "fforce = \n{},\nFforce = \n{}".format(fforce.real, Fforce)) self.assertTrue( Tools.mean_err(fdisp, Fdisp, rfft=True) < tol, "fdisp = \n{},\nFdisp = \n{}".format(fdisp.real, Fdisp)) # Fourier energy E = .5 * np.dot(Fforce / area_per_pt, Fdisp) / res disp = hs.evaluate_disp(force) e = hs.evaluate_elastic_energy(force, disp) kdisp = hs.evaluate_k_disp(force) self.assertTrue( abs(disp - irfftn(kdisp.T).T).sum() < tol, ("disp = {}\n" "ikdisp = {}").format(disp, irfftn(kdisp.T).T)) ee = hs.evaluate_elastic_energy_k_space(fforce, kdisp) self.assertTrue( abs(e - ee) < tol, "violate Parseval: e = {}, ee = {}, ee/e = {}".format( e, ee, ee / e)) self.assertTrue( abs(E - e) < tol, "theoretical E = {}, computed e = {}, diff(tol) = {}({})". format(E, e, E - e, tol))
def test_unit_neutrality(self): tol = 1e-7 # runs the same problem in two unit sets and checks whether results are # changed # Conversion factors length_c = 1. + np.random.rand() force_c = 2. + np.random.rand() pressure_c = force_c / length_c**2 # energy_c = force_c * length_c # length_rc = (1., 1. / length_c) force_rc = (1., 1. / force_c) # pressure_rc = (1., 1. / pressure_c) # energy_rc = (1., 1. / energy_c) nb_grid_pts = (32, 32) young = (self.young, pressure_c * self.young) size = (self.physical_sizes, tuple((length_c * s for s in self.physical_sizes))) comp_nb_grid_pts = tuple((2 * res for res in nb_grid_pts)) disp = np.random.random(comp_nb_grid_pts) disp -= disp.mean() disp = (disp, disp * length_c) forces = list() for i in range(2): sub = FreeFFTElasticHalfSpace(nb_grid_pts, young[i], size[i]) force = sub.evaluate_force(disp[i]) forces.append(force * force_rc[i]) error = Tools.mean_err(forces[0], forces[1]) self.assertTrue(error < tol, "error = {} ≥ tol = {}".format(error, tol))
def test_unit_neutrality1D(self): tol = 1e-7 # runs the same problem in two unit sets and checks whether results are # changed # Conversion factors length_c = 1. + np.random.rand() force_c = 2. + np.random.rand() pressure_c = force_c / length_c**2 # energy_c = force_c * length_c force_per_length_c = force_c / length_c # length_rc = (1., 1. / length_c) # force_rc = (1., 1. / force_c) # pressure_rc = (1., 1. / pressure_c) # energy_rc = (1., 1. / energy_c) force_per_length_rc = (1., 1. / force_per_length_c) nb_grid_pts = (32, ) young = (self.young, pressure_c * self.young) size = (self.physical_sizes[0], length_c * self.physical_sizes[0]) disp = np.random.random(nb_grid_pts) disp -= disp.mean() disp = (disp, disp * length_c) subs = tuple((PeriodicFFTElasticHalfSpace(nb_grid_pts, y, s) for y, s in zip(young, size))) forces = tuple( (s.evaluate_force(d) * f_p_l for s, d, f_p_l in zip(subs, disp, force_per_length_rc))) error = Tools.mean_err(forces[0], forces[1]) self.assertTrue(error < tol, "error = {} ≥ tol = {}".format(error, tol))
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))