tadd tests for contact model based on Young's modulus - sphere - GPU-based 3D d… | |
git clone git://src.adamsgaard.dk/sphere | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit f67134dcadd498588f5689329190fa3940efff8d | |
parent 29ce3482c183769fdafcfbadf4a957831bee4e04 | |
Author: Anders Damsgaard Christensen <[email protected]> | |
Date: Tue, 16 Aug 2016 12:12:44 -0700 | |
add tests for contact model based on Young's modulus | |
Diffstat: | |
M tests/CMakeLists.txt | 6 ++++++ | |
A tests/contactmodel_wall_young.py | 115 +++++++++++++++++++++++++++++… | |
A tests/contactmodel_young.py | 232 ++++++++++++++++++++++++++++++ | |
3 files changed, 353 insertions(+), 0 deletions(-) | |
--- | |
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt | |
t@@ -9,6 +9,12 @@ add_test(wall_contact_model_tests ${PYTHON_EXECUTABLE} | |
add_test(contact_model_tests ${PYTHON_EXECUTABLE} | |
${CMAKE_CURRENT_BINARY_DIR}/contactmodel.py) | |
+add_test(wall_contact_model_young_tests ${PYTHON_EXECUTABLE} | |
+ ${CMAKE_CURRENT_BINARY_DIR}/contactmodel_wall_young.py) | |
+ | |
+add_test(contact_model_young_tests ${PYTHON_EXECUTABLE} | |
+ ${CMAKE_CURRENT_BINARY_DIR}/contactmodel_young.py) | |
+ | |
add_test(io_tests_fluid ${PYTHON_EXECUTABLE} | |
${CMAKE_CURRENT_BINARY_DIR}/io_tests_fluid.py) | |
diff --git a/tests/contactmodel_wall_young.py b/tests/contactmodel_wall_young.py | |
t@@ -0,0 +1,115 @@ | |
+#!/usr/bin/env python | |
+''' | |
+Validate the implemented contact models by observing the behavior of one or two | |
+particles. | |
+''' | |
+ | |
+import sphere | |
+import numpy | |
+import pytestutils | |
+ | |
+### Wall-particle interaction ################################################… | |
+ | |
+## Linear elastic collisions | |
+ | |
+# Normal impact: Check for conservation of momentum (sum(v_i*m_i)) | |
+orig = sphere.sim(np=1, nw=0, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+orig.radius[:] = 1.0 | |
+orig.x[0,:] = [5.0, 5.0, 1.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = -0.1 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.gamma_wn[0] = 0.0 # Disable wall viscosity | |
+orig.gamma_wt[0] = 0.0 # Disable wall viscosity | |
+orig.initTemporal(total = 1.0, file_dt = 0.01) | |
+#orig.time_dt = orig.time_dt*0.1 | |
+moment_before = orig.totalKineticEnergy() | |
+orig.run(verbose=False) | |
+#orig.writeVTKall() | |
+orig.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.vel[0,2], 0.1,\ | |
+ "Elastic normal wall collision (1/2):") | |
+moment_after = orig.totalKineticEnergy() | |
+#print(moment_before) | |
+#print(moment_after) | |
+#print("time step: " + str(orig.time_dt[0])) | |
+#print(str((moment_after[0]-moment_before[0])/moment_before[0]*100.0) + " %") | |
+pytestutils.compareFloats(moment_before, moment_after,\ | |
+ "Elastic normal wall collision (2/2):") | |
+ | |
+# Oblique impact: Check for conservation of momentum (sum(v_i*m_i)) | |
+orig = sphere.sim(np=1, sid='contactmodeltest') | |
+orig.radius[:] = 1.0 | |
+orig.x[0,:] = [5.0, 5.0, 1.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = -0.1 | |
+orig.vel[0,0] = 0.1 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.gamma_wn[0] = 0.0 # Disable wall viscosity | |
+orig.gamma_wt[0] = 0.0 # Disable wall viscosity | |
+orig.initTemporal(total = 0.3, file_dt = 0.01) | |
+moment_before = orig.totalKineticEnergy() | |
+orig.run(verbose=False) | |
+#orig.writeVTKall() | |
+orig.readlast(verbose=False) | |
+moment_after = orig.totalKineticEnergy() | |
+pytestutils.compareFloats(moment_before, moment_after,\ | |
+ " 45 deg. wall collision:\t") | |
+ | |
+## Visco-elastic collisions | |
+ | |
+# Normal impact with normal viscous damping. Test that the lost kinetic energy | |
+# is saved as dissipated viscous energy | |
+orig = sphere.sim(np=1, sid='contactmodeltest') | |
+orig.radius[:] = 1.0 | |
+orig.x[0,:] = [5.0, 5.0, 1.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = -0.1 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.gamma_wn[0] = 1.0e6 | |
+orig.gamma_wt[0] = 0.0 | |
+orig.initTemporal(total = 1.0, file_dt = 0.01) | |
+Ekin_before = orig.energy('kin') | |
+orig.run(verbose=False) | |
+#orig.writeVTKall() | |
+orig.readlast(verbose=False) | |
+Ekin_after = orig.energy('kin') | |
+Ev_after = orig.energy('visc_n') | |
+#print("Ekin_before = " + str(Ekin_before) + " J") | |
+#print("Ekin_after = " + str(Ekin_after) + " J") | |
+pytestutils.test(Ekin_before > Ekin_after, | |
+ "Viscoelastic normal wall collision (1/2):") | |
+pytestutils.compareFloats(Ekin_before, Ekin_after+Ev_after,\ | |
+ "Viscoelastic normal wall collision (2/2):", tolerance=0.05) | |
+ | |
+# Oblique impact: Check for conservation of momentum (sum(v_i*m_i)) | |
+orig = sphere.sim(np=1, sid='contactmodeltest') | |
+orig.radius[:] = 1.0 | |
+orig.x[0,:] = [5.0, 5.0, 1.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = -0.1 | |
+orig.vel[0,0] = 0.1 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.gamma_wn[0] = 1.0e6 | |
+orig.gamma_wt[0] = 1.0e6 | |
+orig.initTemporal(total = 1.0, file_dt = 0.01) | |
+E_kin_before = orig.energy('kin') | |
+orig.run(verbose=False) | |
+#orig.writeVTKall() | |
+orig.readlast(verbose=False) | |
+#Ekin_after = orig.energy('kin') | |
+#Erot_after = orig.energy('rot') | |
+#Es_after = orig.energy('shear') | |
+#pytestutils.compareFloats(Ekin_before,\ | |
+ #Ekin_after+Erot_after+Es_after,\ | |
+ #" 45 deg. wall collision:", tolerance=0.03) | |
+pytestutils.test(Ekin_before > Ekin_after, | |
+ " 45 deg. wall collision (1/2):") | |
+pytestutils.test((orig.angvel[0,0] == 0.0 and orig.angvel[0,1] > 0.0 \ | |
+ and orig.angvel[0,2] == 0.0), | |
+ " 45 deg. wall collision (2/2):") | |
+ | |
+ | |
+ | |
+sphere.cleanup(orig) | |
diff --git a/tests/contactmodel_young.py b/tests/contactmodel_young.py | |
t@@ -0,0 +1,232 @@ | |
+#!/usr/bin/env python | |
+''' | |
+Validate the implemented contact models by observing the behavior of two | |
+particles. | |
+''' | |
+ | |
+import sphere | |
+import numpy | |
+import pytestutils | |
+ | |
+### Particle-particle interaction ############################################… | |
+ | |
+## Linear elastic collisions | |
+ | |
+# Normal impact: Check for conservation of momentum (sum(v_i*m_i)) | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+#orig.radius[:] = [1.0, 2.0] | |
+orig.radius[:] = [1.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 4.05] | |
+orig.setYoungsModulus(70.0e9) | |
+v_orig = 1 | |
+orig.vel[0,2] = v_orig | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+ | |
+orig.run(dry=True) | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.vel[0,2], after.vel[1,2],\ | |
+ "Elastic normal collision (1/4):") | |
+#print(orig.totalKineticEnergy()) | |
+#print(after.totalKineticEnergy()) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), after.totalKineticEnergy(… | |
+ "Elastic normal collision (2/4):") | |
+ | |
+# Normal impact with different sizes: Check for conservation of momentum | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+orig.radius[:] = [2.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 5.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1.0 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), after.totalKineticEnergy(… | |
+ "Elastic normal collision (3/4):") | |
+ | |
+# Normal impact with different sizes: Check for conservation of momentum | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+orig.radius[:] = [1.0, 2.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 5.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1.0 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), after.totalKineticEnergy(… | |
+ "Elastic normal collision (4/4):") | |
+ | |
+ | |
+## Linear viscous-elastic collisions | |
+ | |
+# Normal impact: Check for conservation of momentum (sum(v_i*m_i)) | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+orig.radius[:] = [1.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 4.05] | |
+orig.setYoungsModulus(70.0e9) | |
+v_orig = 1 | |
+orig.vel[0,2] = v_orig | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+orig.gamma_n[0] = 1.0e6 | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+#print(orig.totalKineticEnergy()) | |
+#print(after.totalKineticEnergy()) | |
+#print(after.totalViscousEnergy()) | |
+pytestutils.test(orig.vel[0,2] > after.vel[1,2],\ | |
+ "Viscoelastic normal collision (1/4):") | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), | |
+ after.totalKineticEnergy() | |
+ + after.totalViscousEnergy(), | |
+ "Viscoelastic normal collision (2/4):", tolerance=0.05) | |
+ | |
+# Normal impact with different sizes: Check for conservation of momentum | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+orig.radius[:] = [2.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 5.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1.0 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+orig.gamma_n[0] = 1.0e6 | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), | |
+ after.totalKineticEnergy() | |
+ + after.totalViscousEnergy(), | |
+ "Viscoelastic normal collision (3/4):", tolerance=0.05) | |
+ | |
+# Normal impact with different sizes: Check for conservation of momentum | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+orig.radius[:] = [1.0, 2.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 5.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1.0 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+orig.gamma_n[0] = 1.0e6 | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), | |
+ after.totalKineticEnergy() | |
+ + after.totalViscousEnergy(), | |
+ "Viscoelastic normal collision (4/4):", tolerance=0.05) | |
+ | |
+ | |
+ | |
+## Oblique elastic collisions | |
+ | |
+# Normal impact, low angle, no slip | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+#orig.radius[:] = [1.0, 2.0] | |
+orig.radius[:] = [1.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 4.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1 | |
+orig.vel[0,0] = 1 | |
+orig.mu_s[0] = 1e9 # no slip | |
+orig.mu_d[0] = 1e9 # no slip | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.test((after.angvel[:,1] < 0.0).all(), | |
+ "Oblique normal collision (1/8):") | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), | |
+ after.totalKineticEnergy() | |
+ + after.totalRotationalEnergy(), | |
+ "Oblique normal collision (2/8):", tolerance=0.05) | |
+ | |
+# Normal impact, low angle, slip | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+#orig.radius[:] = [1.0, 2.0] | |
+orig.radius[:] = [1.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 4.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1 | |
+orig.vel[0,0] = 1 | |
+orig.mu_s[0] = 0.3 | |
+orig.mu_d[0] = 0.3 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), | |
+ after.totalKineticEnergy() | |
+ + after.totalRotationalEnergy() | |
+ + after.totalFrictionalEnergy(), | |
+ "Oblique normal collision (3/8):", tolerance=0.05) | |
+pytestutils.test((after.angvel[:,1] < 0.0).all(), | |
+ "Oblique normal collision (4/8):") | |
+pytestutils.test(after.totalFrictionalEnergy() > 0.0, | |
+ "Oblique normal collision (5/8):") | |
+ | |
+# Normal impact, low angle, slip, viscous damping tangentially | |
+orig = sphere.sim(np=2, sid='contactmodeltest') | |
+after = sphere.sim(np=2, sid='contactmodeltest') | |
+sphere.cleanup(orig) | |
+#orig.radius[:] = [1.0, 2.0] | |
+orig.radius[:] = [1.0, 1.0] | |
+orig.x[0,:] = [5.0, 5.0, 2.0] | |
+orig.x[1,:] = [5.0, 5.0, 4.05] | |
+orig.setYoungsModulus(70.0e9) | |
+orig.vel[0,2] = 1 | |
+orig.vel[0,0] = 1 | |
+orig.mu_s[0] = 0.3 | |
+orig.mu_d[0] = 0.3 | |
+orig.gamma_t[0] = 1.0e3 | |
+orig.defineWorldBoundaries(L=[10,10,10]) | |
+orig.initTemporal(total = 0.1, file_dt = 0.01) | |
+ | |
+orig.run(verbose=False) | |
+after.readlast(verbose=False) | |
+print(after.totalViscousEnergy()) | |
+pytestutils.compareFloats(orig.totalKineticEnergy(), | |
+ after.totalKineticEnergy() | |
+ + after.totalRotationalEnergy() | |
+ + after.totalFrictionalEnergy() | |
+ + after.totalViscousEnergy(), | |
+ "Oblique normal collision (6/8):", tolerance=0.05) | |
+pytestutils.test((after.angvel[:,1] < 0.0).all(), | |
+ "Oblique normal collision (7/8):") | |
+pytestutils.test(after.totalFrictionalEnergy() > 0.0, | |
+ "Oblique normal collision (8/8):") | |
+pytestutils.test(after.totalFrictionalEnergy() > 0.0, | |
+ "Oblique normal collision (8/8):") | |
+ | |
+orig.cleanup() |