Source code for slippy.contact.sub_models.epp_wear
import warnings
import numpy as np
import slippy
from slippy.core import _SubModelABC
__all__ = ['WearElasticPerfectlyPlastic']
[docs]class WearElasticPerfectlyPlastic(_SubModelABC):
r"""
Remove overlap between surfaces left after contact with a maximum load
Parameters
----------
name: str
The name of the sub model and wear source, used for outputs and error logging
proportion_surface_1: float
The proportion of the overlap to come be worn from the main surface in the simulation.
proportion_surface_2: float, optional (None)
The proportion of the overlap to be removed from surface 2, this defaults to the remaining overlap, after
subtracting the proportion from the first surface
no_time: bool, optional (False)
Must be set to True if the step which this sub-model is added to is solved with no time dependence, otherwise
the full wear will be applied for each time step leading to unphysical results
Notes
-----
This sub model assumes that the grid spacings for the surfaces are the same, if this is not correct wear will be
assigned incorrectly
For this model to work there must be some overlap between the surfaces at the end of the model step, otherwise no
wear will be applied.
Provides:
* 'total_plastic_deformation': The total material removed for this time step
* 'wear_plastic_surface_1': The wear applied to each point of surface 1, applied at the points 'surface_1_points',
only provided if proportion_surface_1 is greater than 0
* 'wear_plastic_surface_2': The wear applied to each point of surface 2, applied at the points 'surface_2_points',
only provided if proportion_surface_1 is less than 1
For simulations with movement between the surfaces wear_plastic_surface_1 and 2 can be confusing as they are aligned
with the points specified is surface_1_points, not the base coordinates of surface 1 or 2. For examining the output
from this wear model over time it may be more simple to request the following output:
'surface_1.wear_volumes['this_model_name']'
This will always contain the cumulative wear from this model in the base coordinates of the surface.
"""
n_calls = 0
[docs] def __init__(self, name: str, proportion_surface_1: float, proportion_surface_2: float = None,
no_time: bool = False):
requires = {'interference', 'total_displacement_z', 'just_touching_gap'}
provides = {'total_plastic_deformation'}
super().__init__(name, requires, provides)
if proportion_surface_1 > 1 or proportion_surface_1 < 0:
raise ValueError("Proportion of wear applied to surface 1 should be between 0 and 1")
if proportion_surface_2 is not None:
if proportion_surface_2 > 1 or proportion_surface_2 < 0:
raise ValueError("Proportion of wear applied to surface 2 should be between 0 and 1")
if (proportion_surface_1+proportion_surface_2) > 1.00000001:
warnings.warn("Proportion surface 1 + proportion surface 2 is greater than 1, more wear will be applied"
" than the overlap between the surfaces, this will result in unphysical results")
self.p_surf_1 = proportion_surface_1
self.p_surf_2 = proportion_surface_2
if proportion_surface_1 > 0:
self.requires.add('surface_1_points')
self.provides.add('wear_plastic_surface_1')
if proportion_surface_2 > 0:
self.requires.add('surface_2_points')
self.provides.add('wear_plastic_surface_2')
self.plastic_def_this_step = None
self.no_time = no_time
def solve(self, current_state: dict) -> dict:
if 'converged' in current_state and not current_state['converged']:
print(f"SUB MODEL: {self.name}, Solution did not converge, no wear")
return current_state
if self.no_time:
just_touching_gap = current_state['just_touching_gap']
if self.plastic_def_this_step is None or ('new_step' in current_state and current_state['new_step']):
self.plastic_def_this_step = np.zeros_like(just_touching_gap)
# need to sort out the discrepancy between the current just touching gap and the one used for the model
gap = (just_touching_gap - current_state['interference'] + current_state['total_displacement_z'] +
self.plastic_def_this_step)
else:
# just use the current just touching gap and interference
gap = slippy.asnumpy(current_state['gap'])
# just_touching_gap = current_state['just_touching_gap']
# gap = (just_touching_gap - current_state['interference'] + current_state['total_displacement_z'])
max_load = min(self.model.surface_1.material.max_load,
self.model.surface_2.material.max_load)
idx = np.logical_and(current_state['loads_z'] >= max_load,
np.logical_and(gap < 0, current_state['contact_nodes']))
total_wear = -gap[idx]
if self.no_time:
self.plastic_def_this_step[idx] += total_wear
if total_wear.size:
tpd = np.sum(total_wear) * self.model.surface_1.grid_spacing ** 2 * (self.p_surf_1+self.p_surf_2)
else:
tpd = np.array(0.0)
results = {'total_plastic_deformation': tpd}
if self.p_surf_1 > 0:
y_pts = current_state['surface_1_points'][0][idx]
x_pts = current_state['surface_1_points'][1][idx]
surface_1_wear = total_wear * self.p_surf_1
results['wear_plastic_surface_1'] = surface_1_wear
self.model.surface_1.wear(self.name, x_pts, y_pts, surface_1_wear)
if self.p_surf_2 > 0:
y_pts = current_state['surface_2_points'][0][idx]
x_pts = current_state['surface_2_points'][1][idx]
surface_2_wear = total_wear * self.p_surf_2
results['wear_plastic_surface_2'] = surface_2_wear
self.model.surface_2.wear(self.name, x_pts, y_pts, surface_2_wear)
print(f"SUB MODEL: {self.name}, total deformation: {tpd}")
return results