介绍
在本系列的第 1 部分中,推导出了如何使用以下积分方程计算任何应变历史的应力响应:
正如在第 1 部分中展示的那样,这个方程可以在像 julia 这样的高级数学语言中使用像 quadgk 这样的函数来解决。这种方法的问题在于非常慢。为了说明有多慢,设N是计算σ(Δt)所需的浮点运算(FLOP)数,然后计算应力σ(M⋅Δt)需要MN浮点运算。更重要的是,需要 O(N⋅M2) 浮点运算来计算由 M 个点组成的整个应力-应变曲线。因此,如果应力-应变曲线有 1,000 个数据点,那么计算整个曲线所需的时间大约是第一个数据点的 100 万倍。这很糟糕!我们需要一个更好的方法。在本文中,我将展示如何将此计算速度提高 100 倍到 1000 倍。
单项Prony系列
在计算应力响应之前,我们需要定义如何量化应力松弛响应。在这里,我将使用以下 1 项 Prony 级数方程:
在此方程中,g=0 对应于线弹性响应,g=1 对应于完全应力松弛。
分部积分
从概念上讲,使用以下众所周知的方程按分部积分进行积分是一个好主意:
这得到了以下应力方程:
这个方程很酷的地方在于,我们可以看到应力由瞬时部分(σi)和粘弹性部分(σv)组成。但是,这个等式并没有帮助我们解决运行时问题。为此,我们需要一种不同的方法。
将积分分成两部分
现在是时候应用一些数学“魔法”了。首先重写σ(t+Δt)的等式(4)。请注意,我将积分分为两部分:
如果你考虑了一段时间,你应该能够说服自己,第一个积分可以简化很多:
为了计算最终积分,我们需要假设应变在时间间隔 [t,t+Δt] 内随时间线性变化:
有了这个假设,就可以计算方程(7)中的积分。经过 2 页代数推导,能够得到以下应力的最终方程:
计算应力
下面的 Julia 代码计算了给定应变历史的应力,图 2 显示了运行代码的结果。此实现的运行速度明显快于原始公式 (1)。
预测的应力
using QuadGK, Plots
function strain(t)
t1 = maxStrain / strainRate
if t <= t1
return strainRate * t
else
return maxStrain - (t - t1) * strainRate
end
end
function calcStress_direct(time, strain)
N = length(time)
stress = zeros(N)
stressV = zeros(N)
for i in 2:N
dt = time[i] - time[i-1]
de = strain[i] - strain[i-1]
stressE = E0 * strain[i]
stressV1 = stressV[i-1] * exp(-dt/tau0)
stressV2 = E0*g * (strain[i-1] - de/dt * time[i]) * (1 - exp(-dt/tau0))
stressV3 = E0*g * de/dt * (time[i]+dt-tau0 + (tau0-time[i])*exp(-dt/tau0))
stressV[i] = stressV1 + stressV2 + stressV3
stress[i] = stressE - stressV[i]
end
return stress
end
E0 = 10.0
tau0 = 4.0
g = 1.0
maxStrain = 0.1
strainRate = 0.01
N = 100
time = range(0, 2*maxStrain/strainRate, length=N)
ee = zeros(N)
for i in 1:N
ee[i] = strain(time[i])
end
ss3 = calcStress_direct(time, ee)
plot!(ee, ss3, label="direct", linewidth=2)
plot!(size=(1000,800), framestyle=:box)
plot!(tickfontsize=14, guidefontsize=16, xlabel="Strain", ylabel="Stress")