# ---
# jupyter:
# jupytext:
# formats: py:percent
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.14.4
# kernelspec:
# display_name: Python 3
# language: python
# name: python3
# ---
Example of rough simulation with adhesion on the contact challenge 512x512 topography
The adhesion is longer ranged in this example than in the original contact challenge problem definitition because we use a much coarser grid here.
from SurfaceTopography import read_published_container
import Adhesion # required to register the "make_system" function
from Adhesion.Interactions import Exponential
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import LinearSegmentedColormap
fatal: not a git repository (or any of the parent directories): .git
fatal: not a git repository (or any of the parent directories): .git
fatal: not a git repository (or any of the parent directories): .git
c, = read_published_container("https://doi.org/10.57703/ce-rs7jq")
t = c._topographies[1].to_unit("m")
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[4], line 1
----> 1 t = c._topographies[1].to_unit("m")
File ~/work/Adhesion/venv/lib/python3.8/site-packages/SurfaceTopography/Container/SurfaceContainer.py:53, in SurfaceContainer.__getattr__(self, name)
51 return func
52 else:
---> 53 raise AttributeError("Unkown attribute '{}' and no analysis or pipeline function of this name registered"
54 "(class {}). Available functions: {}".format(name, self.__class__.__name__,
55 ', '.join(self._functions.keys())))
AttributeError: Unkown attribute '_topographies' and no analysis or pipeline function of this name registered(class LazySurfaceContainer). Available functions: to_zip, bandwidth, suggest_length_unit, autocorrelation, power_spectrum, variable_bandwidth, scale_dependent_statistical_property, ciso_moment, c1d_moment, integrate_psd_from_profile, variance_half_derivative_from_autocorrelation, variance_half_derivative_via_autocorrelation_from_profile
t.is_periodic
t.rms_gradient()
t.rms_height_from_area()
1/t.rms_curvature_from_area()
Es = 25e6 # N / m2
challenge_wint = 0.05 # mJ / m2
challenge_rho = 2.071e-9 # interaction_range in the contact challenge
# External load 250 kPa
challenge_external_pressure = 250e3 # Pa
Defining meaningful numerical tolerances
In adhesive simulations, the optimisation variable is the displacement. The algorithm seeks the minimum of the total energy $\Pi_\mathrm{tot}$, where the residual $\partial \Pi_\mathrm{tot}/\partial u_{ij} = 0$
A typical repulsive contact pressure is $E^\prime h^\prime_{rms}$, leading to the typical repulsive pixel force $E^\prime h^\prime_{rms} \Delta x^2$. We use a small fraction of this typical force as the numerical tolerance for the residual:
pixel_force_tol = 1e-5 * Es * t.rms_gradient() * t.area_per_pt
Another valid choice of “typical pressure” would be to use the maximum interaction force.
In dual minimizers (used in the nonadhesive contact system), the residual is the gap inside the contact area. Let’s use a typical change of heights for the tolerance
penetration_tol = 1e-3 * t.rms_gradient() * t.pixel_size[0]
Nonadhesive contact system
nonadhesive_system = t.make_contact_system(interaction="hardwall", young=Es)
sol = nonadhesive_system.minimize_proxy(external_force=np.prod(t.physical_sizes)
* challenge_external_pressure, pentol=penetration_tol)
nonadhesive_offset = sol.offset
fig,ax=plt.subplots()
cmap = LinearSegmentedColormap.from_list('contactcmap', ((1,1,1,0.), "black"), N=256)
ax.matshow(nonadhesive_system.contact_zone.T, cmap = cmap)
ax.grid(False)
contact system with hardwall repulsion
from Adhesion.Interactions import Exponential
from Adhesion.System import BoundedSmoothContactSystem
interaction=Exponential(gamma0=challenge_wint ,rho=challenge_rho*30)
w = -interaction.evaluate(0)[0]
dx = t.pixel_size[0]
Properties of the adhesive rough contact
Energy for full conformal contact
print("Persson and Tosatti adhesion criterion: ")
print(
"elastic deformation energy for full contact / work of adhesion: "
"{}".format(nonadhesive_system.substrate.evaluate(t.detrend(detrend_mode="center").heights())[0]
/ w / np.prod(t.physical_sizes))) # ^
# sets the mean to zero, so |
# that the energy of the q = 0 --
# mode is not taken into
# account
Pastewka and Robbins criterion
P&R equation 10, with $\kappa_{rep} = 2$, $d_{rep}=4 h^{\prime}{rms} / h^{\prime\prime}{rms}$ (Only valid in the DMT regime, i.e. until the onset of stickiness) If this value is smaller then 1 the surfaces are sticky and normal CG’s might not work anymore
A requirement for the Pastewka Robbins theory to be valid is that the interaction is short ranged enough. See below.
rho = interaction.rho
print("P&R stickiness criterion: "
"{}".format(t.rms_gradient() * Es * rho / 2 / w *
(t.rms_gradient() ** 2 / t.rms_curvature_from_area() / rho)
** (2 / 3)))
R = 1 / t.rms_curvature_from_area()
elastocapillary_length = w / Es
print("Generalized Tabor parameter following Martin Müser")
print("{}".format(
R ** (1 / 3) * elastocapillary_length ** (2 / 3) / rho))
Is the Pastewka Robbins assumption of short-ranged adhesion valid ?
print("rms_height / interaction_length: "
"{}".format(t.rms_height_from_area() / interaction.rho))
Monti Sanner and Pastewka 2021
g0 = 16 /3 * t.rms_gradient()**2 / t.rms_curvature_from_area()
g0
print("rho / g0: "
"{}".format(g0 / interaction.rho))
This value should be smaller than 0.1 for the assumptions behind the Pastewka and Robbins theory to be valid. We hence cannot apply the theory to the system considered here.
Estimate whether the discretisation is alright
Process zone in a crack
process_zone_size = Es * w / np.pi / abs(interaction.max_tensile) ** 2
print("nb pixels in process zone: {}".format(process_zone_size / dx))
# print("highcut wavelength / process_zone size: "
# "{}".format(short_cutoff / process_zone_size))
Empirical criterion on contact of spheres (see adhesive_simulation_sphere.ipynb)
$$ dx \leq 2 \rho^2 \frac{4}{3\pi} \frac{1}{\ell_a} $$
The value below should be greater than 1:
interaction.rho ** 2 * 8 / 3 / np.pi * Es / w / dx
Wang, Zhou and Müser 2021 Equation (9) and Fig.8:
$\mu_{rho}$
np.sqrt(- interaction.evaluate(0, True, True, True)[-1] # min curvature for the exponential interaction
/ Es * dx
)
should be smaller than 0.5
Adhesive simulation
system = t.make_contact_system(interaction=interaction, young=Es, system_class=BoundedSmoothContactSystem)
sol=system.minimize_proxy(
offset=nonadhesive_offset,
# tol=pixel_force_tol,
lbounds="auto",
options=dict(
ftol=0,
gtol=pixel_force_tol,
maxcor=3,
maxiter=1000,
)
)
assert sol.success
fig,ax=plt.subplots(figsize=(10, 10))
color = "red"
cmap = LinearSegmentedColormap.from_list('contactcmap', ((1,1,1,0.), color), N=256)
ax.matshow(system.contact_zone.T, cmap = cmap)
cmap = LinearSegmentedColormap.from_list('contactcmap', ((1,1,1,0.), "black"), N=256)
ax.matshow(nonadhesive_system.contact_zone.T, cmap = cmap)
ax.grid(False)
ax.set_xlim(0, 128)
ax.set_ylim(0, 128)
fig
Gaps
fig,ax=plt.subplots()
plt.colorbar(ax.matshow(system.gap[:128,:128].T / interaction.rho), label=r"$g/\rho$")
ax.set_xlim(0, 128)
ax.set_ylim(0, 128)
ax.grid(False)
How adhesion affected the mean pressure (in MPa)
system.compute_normal_force() / np.prod(t.physical_sizes) / 1000
nonadhesive_system.compute_normal_force() / np.prod(t.physical_sizes) / 1000
Further examples
../test/test_bugnicourt_primal_rough_weakly_adhesive.py