Defining Flow Stress from Interpolated Data - The Classic Way

In this notebook it is shown, how to define a flow stress function from interpolated data using the interpolation functions from scipy. The concept can be transferred to any other material data as well.

First, we need to import some packages.

import pyroll.basic as pr # PyRolL itself

import pandas as pd # pandas for data import
import numpy as np # numpy for numeric calculations
import scipy.interpolate as interpolate # scipy.interpolate for interpolations

We import the data to interpolate from a CSV file using pandas. The result is a dataframe containing all data from the file. Note, that the column names are derived from the first row of the file.

flow_stress_data = pd.read_csv("Interpolating_Flow_Stress_Data.csv")
flow_stress_data
phi kf
0 0.000000 100.000000
1 0.020202 106.203666
2 0.040404 107.637609
3 0.060606 108.625511
4 0.080808 109.403000
... ... ...
95 1.919192 124.320109
96 1.939394 124.396628
97 1.959596 124.472591
98 1.979798 124.548008
99 2.000000 124.622888

100 rows × 2 columns

We can interpolate the data using scipy to get an interpolation function, which we can evaluate as any other function.

flow_stress_function = interpolate.interp1d(flow_stress_data.phi, flow_stress_data.kf)

To make available to PyRolL, we have to implement hooks. The flow_stress hook is the main hook for calculation flow stress, it returns the flow stress depending on the current state of the profile. Another hook regarding flow stress is flow_stress_function. It returns a function of the classic flow stress parameters strain, strain rate and temperature to enable plugins to calculate their own variations of flow stress.

@pr.DeformationUnit.Profile.flow_stress
def flow_stress_interpolated(self: pr.DeformationUnit.Profile):
    return flow_stress_function(self.strain)

@pr.DeformationUnit.Profile.flow_stress_function
def flow_stress_function_interpolated(self: pr.DeformationUnit.Profile):
    def f(strain, strain_rate, temperature):
        return flow_stress_function(strain)
    
    return f

Lets try it in simulation, first as usual the input workpiece. Note, that we do not define a material key or constant flow stress here.

in_profile = pr.Profile.square(
    side=45e-3,
    corner_radius=3e-3,
    temperature=1100 + 273.15,
    strain=0,
    density=7.5e3,
    specific_heat_capacity=690,
)
in_profile
SquareProfile
classifiers
'square'
'diamond'
corner_radius0.003
cross_section
Polygon
area0.0020172289364149133
height0.061154328932550704
perimeter0.17484198694172845
width0.061154328932550704
density7500.0
diagonalnp.float64(0.06363961030678927)
side0.045
specific_heat_capacity690
strain0
t0
temperature1373.15

And the groove, the working roll and the roll pass…

groove1 = pr.DiamondGroove(
    usable_width=76.55e-3,
    tip_depth=22.1e-3,
    r1=12e-3,
    r2=8e-3,
)
groove1
DiamondGroove
alpha1np.float64(0.5236363668157296)
alpha2np.float64(0.5236363668157296)
classifiers
'generic_elongation'
'diamond'
contour_line
LineString
height0.020862195195594648
length0.12428942750252188
width0.11360126410252692
depthnp.float64(0.020862195195594648)
flank_anglenp.float64(0.5236363668157296)
ground_widthnp.float64(0.004287509401684611)
r10.012
r20.008
tip_angleNone
tip_depth0.0221
usable_width0.07655
roll1 = pr.Roll(
    groove=groove1,
    nominal_radius=328e-3,
)
roll1
Roll
groove
DiamondGroove
alpha1np.float64(0.5236363668157296)
alpha2np.float64(0.5236363668157296)
classifiers
'generic_elongation'
'diamond'
contour_line
LineString
height0.020862195195594648
length0.12428942750252188
width0.11360126410252692
depthnp.float64(0.020862195195594648)
flank_anglenp.float64(0.5236363668157296)
ground_widthnp.float64(0.004287509401684611)
r10.012
r20.008
tip_angleNone
tip_depth0.0221
usable_width0.07655
nominal_radius0.328
pass1 = pr.RollPass(
    roll=roll1,
    gap=3e-3,
    velocity=1,
)
pass1
TwoRollPass
classifiers
'symmetric'
'generic_elongation'
'diamond'
contour_lines
MultiLineString
height0.0447243903911893
length0.24857885500504376
width0.11360126410252692
convergence_history
disk_elements
engine
TwoRollPass.Engine
gap0.003
global_iterator1
in_profileNone
label''
out_profileNone
roll
TwoRollPass.Roll
contour_pointsarray([[-5.68006321e-02, 0.00000000e+00], [-4.14906321e-02, 0.00000000e+00], [-4.11906125e-02, 3.75107461e-06], [-4.08905930e-02, 1.50113425e-05], [-4.05905735e-02, 3.38020023e-05], [-4.02905539e-02, 6.01586074e-05], [-3.99905344e-02, 9.41314051e-05], [-3.96905149e-02, 1.35785821e-04], [-3.93904953e-02, 1.85203103e-04], [-3.90904758e-02, 2.42481133e-04], [-3.87904563e-02, 3.07735434e-04], [-3.84904367e-02, 3.81100396e-04], [-3.81904172e-02, 4.62730744e-04], [-3.78903977e-02, 5.52803299e-04], [-3.75903781e-02, 6.51519075e-04], [-3.72903586e-02, 7.59105780e-04], [-3.69903391e-02, 8.75820795e-04], [-3.66903195e-02, 1.00195473e-03], [-3.63903000e-02, 1.13783572e-03], [-3.60902805e-02, 1.28383451e-03], [-3.57902609e-02, 1.44037079e-03], [-3.54902414e-02, 1.60792071e-03], [-4.00026044e-03, 1.97902481e-02], [-3.80024741e-03, 1.99019480e-02], [-3.60023439e-03, 2.00063055e-02], [-3.40022137e-03, 2.01036381e-02], [-3.20020835e-03, 2.01942254e-02], [-3.00019533e-03, 2.02783147e-02], [-2.80018231e-03, 2.03561247e-02], [-2.60016928e-03, 2.04278491e-02], [-2.40015626e-03, 2.04936597e-02], [-2.20014324e-03, 2.05537080e-02], [-2.00013022e-03, 2.06081283e-02], [-1.80011720e-03, 2.06570382e-02], [-1.60010417e-03, 2.07005411e-02], [-1.40009115e-03, 2.07387265e-02], [-1.20007813e-03, 2.07716713e-02], [-1.00006511e-03, 2.07994409e-02], [-8.00052087e-04, 2.08220895e-02], [-6.00039066e-04, 2.08396605e-02], [-4.00026044e-04, 2.08521876e-02], [-2.00013022e-04, 2.08596945e-02], [ 0.00000000e+00, 2.08621952e-02], [ 2.00013022e-04, 2.08596945e-02], [ 4.00026044e-04, 2.08521876e-02], [ 6.00039066e-04, 2.08396605e-02], [ 8.00052087e-04, 2.08220895e-02], [ 1.00006511e-03, 2.07994409e-02], [ 1.20007813e-03, 2.07716713e-02], [ 1.40009115e-03, 2.07387265e-02], [ 1.60010417e-03, 2.07005411e-02], [ 1.80011720e-03, 2.06570382e-02], [ 2.00013022e-03, 2.06081283e-02], [ 2.20014324e-03, 2.05537080e-02], [ 2.40015626e-03, 2.04936597e-02], [ 2.60016928e-03, 2.04278491e-02], [ 2.80018231e-03, 2.03561247e-02], [ 3.00019533e-03, 2.02783147e-02], [ 3.20020835e-03, 2.01942254e-02], [ 3.40022137e-03, 2.01036381e-02], [ 3.60023439e-03, 2.00063055e-02], [ 3.80024741e-03, 1.99019480e-02], [ 4.00026044e-03, 1.97902481e-02], [ 3.54902414e-02, 1.60792071e-03], [ 3.57902609e-02, 1.44037079e-03], [ 3.60902805e-02, 1.28383451e-03], [ 3.63903000e-02, 1.13783572e-03], [ 3.66903195e-02, 1.00195473e-03], [ 3.69903391e-02, 8.75820795e-04], [ 3.72903586e-02, 7.59105780e-04], [ 3.75903781e-02, 6.51519075e-04], [ 3.78903977e-02, 5.52803299e-04], [ 3.81904172e-02, 4.62730744e-04], [ 3.84904367e-02, 3.81100396e-04], [ 3.87904563e-02, 3.07735434e-04], [ 3.90904758e-02, 2.42481133e-04], [ 3.93904953e-02, 1.85203103e-04], [ 3.96905149e-02, 1.35785821e-04], [ 3.99905344e-02, 9.41314051e-05], [ 4.02905539e-02, 6.01586074e-05], [ 4.05905735e-02, 3.38020023e-05], [ 4.08905930e-02, 1.50113425e-05], [ 4.11906125e-02, 3.75107461e-06], [ 4.14906321e-02, 0.00000000e+00], [ 5.68006321e-02, 0.00000000e+00]])
groove
DiamondGroove
alpha1np.float64(0.5236363668157296)
alpha2np.float64(0.5236363668157296)
classifiers
'generic_elongation'
'diamond'
contour_line
LineString
height0.020862195195594648
length0.12428942750252188
width0.11360126410252692
depthnp.float64(0.020862195195594648)
flank_anglenp.float64(0.5236363668157296)
ground_widthnp.float64(0.004287509401684611)
r10.012
r20.008
tip_angleNone
tip_depth0.0221
usable_width0.07655
nominal_radius0.328
velocity1

Lets run the solution procedure of the roll pass. We see no errors claiming that a flow stress value is missing.

pass1.solve(in_profile)
WARNING:root:No coulomb_friction_coefficient hook found. Continuing with 0.
WARNING:root:No coulomb_friction_coefficient hook found. Continuing with 0.
WARNING:root:No coulomb_friction_coefficient hook found. Continuing with 0.
WARNING:root:No coulomb_friction_coefficient hook found. Continuing with 0.
WARNING:root:No coulomb_friction_coefficient hook found. Continuing with 0.
WARNING:root:No coulomb_friction_coefficient hook found. Continuing with 0.
Profile
classifiers
'symmetric'
'generic_elongation'
'diamond'
cross_section
Polygon
area0.0017909735754438032
height0.0447243903911893
perimeter0.16262870637092414
width0.06560167360406854
cross_section_error-0.06535133698736628
cross_section_filling_ratio0.9346486630126337
density7500.0
filling_errornp.float64(-0.14302189935900012)
filling_rationp.float64(0.8569781006409999)
length0.0
specific_heat_capacity690
strainnp.float64(0.20420123818243657)
tnp.float64(0.07056039637464354)
technologically_orientated_cross_section
Polygon
area0.0017909735754438032
height0.0447243903911893
perimeter0.16262870637092414
width0.06560167360406854
temperaturenp.float64(1369.1203295635323)
velocity1

Lets check, if our new hooks are really used. We check that the flow stress value stored in the out profile of the pass is numerically equal to a manually calculated value using the respective strain. If everything went fine, we shall se no output of this statement, otherwise an error message.

assert np.isclose(pass1.out_profile.flow_stress, flow_stress_function(pass1.out_profile.strain))