~gcg/constrain/trunk

« back to all changes in this revision

Viewing changes to align_stress_strain.py

  • Committer: GCG at MSI
  • Date: 2021-02-16 18:56:47 UTC
  • Revision ID: gcg@msi-20210216185647-jundceapke4mtvbz
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
Created on Thu Sep  3 23:17:27 2020
 
4
 
 
5
@author: Georg
 
6
 
 
7
plot stress vs. strain with Bridgeman correction
 
8
 
 
9
"""
 
10
 
 
11
import numpy as np
 
12
import matplotlib.pyplot as plt
 
13
from matplotlib.widgets import Button
 
14
import os
 
15
from scipy import interpolate
 
16
from scipy.optimize import curve_fit
 
17
import bottleneck as bn
 
18
import triaxiality
 
19
import configparser
 
20
 
 
21
cfg = configparser.ConfigParser()
 
22
cfg.read("constrain.ini")
 
23
notched_specimen = cfg.getboolean("DEFAULT", "notched_specimen")
 
24
factor = cfg.getint("DEFAULT", "nsmooth") # moving average filter -- window width for strain data
 
25
D0 = cfg.getfloat("DEFAULT", "D0") # initial diameter in cylindric gauge section
 
26
case = cfg.get("DEFAULT", "case")
 
27
dt_strain = cfg.getfloat("DEFAULT", "dt_images") # strain acquisition time period
 
28
offset_strain = cfg.getint("DEFAULT", "offset_images")  # number of images which were skipped after trigger point
 
29
nueps = cfg.getfloat("DEFAULT", "nueps") # plastic Poisson ratio
 
30
 
 
31
def find_limits(t1, t2):
 
32
    """ return common time range between to time axes
 
33
    """
 
34
    
 
35
    low = max(t1[0], t2[0])
 
36
    high = min(t1[-1], t2[-1])
 
37
    
 
38
    return low, high
 
39
 
 
40
def power_law_plasticity(strain):
 
41
    """ return power law plastic strain according to LS-Dyna material model Nr. 18"
 
42
    """
 
43
    E = 110.32
 
44
    pr = 0.33
 
45
    K = 0.6043
 
46
    n = 0.107014
 
47
    eps_ela = (E/K)**(1/(n-1))
 
48
    print("elastic strain at yield is: ", eps_ela)
 
49
    sigma = K * (eps_ela + strain)**n
 
50
    return eps_ela + strain, sigma * 1000
 
51
 
 
52
def load_force_LSDyna():
 
53
    """ read force from LS-Dyna axis-symmetric analysis
 
54
    """
 
55
    force_filename = "force.csv"
 
56
    data = np.genfromtxt(force_filename, delimiter=",", skip_header=2)
 
57
    time_force = data[:,0]
 
58
    force  = data[:,1] * 2 * np.pi * 1000
 
59
    dt_force = time_force[1] - time_force[0]    
 
60
    return time_force, force, dt_force
 
61
 
 
62
def load_force_Zwick():
 
63
    """ read force from Zwick UTM
 
64
    """
 
65
    force_filename = "force.TRA"
 
66
    data = np.genfromtxt(force_filename, delimiter=";", skip_header=16)
 
67
    time_force = data[:,0]
 
68
    force  = data[:,1]
 
69
    dt_force = time_force[1] - time_force[0]    
 
70
    return time_force, force, dt_force
 
71
 
 
72
def load_force_SHTB():
 
73
    """ read force from SHTB data analysis
 
74
    """
 
75
    data = np.genfromtxt("time_force_nonshifted.txt", skip_header=0)
 
76
    time_force = data[:,0]
 
77
    force  = data[:,3] * 1000 # convert kN to N
 
78
    dt_force = time_force[1] - time_force[0]
 
79
    
 
80
    #plt.plot(time_force, force)
 
81
    #plt.show()
 
82
    return time_force, force, dt_force
 
83
 
 
84
def load_conStrain():
 
85
    """ load strain and triaxiality data from conStrain analysis """
 
86
    
 
87
    strain_data = np.genfromtxt("strain.txt")
 
88
    indices_strain = strain_data[:,0]
 
89
    dias = strain_data[:,2]
 
90
    notch_radii = strain_data[:,3]
 
91
    
 
92
    
 
93
    eps_eq = (1./nueps) * np.log(dias[0] / dias)
 
94
    eps_eq = bn.move_mean(eps_eq,window=factor,min_count=1)
 
95
    dias = bn.move_mean(dias,window=factor,min_count=1)
 
96
    
 
97
    if notched_specimen == False:
 
98
        notch_radii = np.where(eps_eq < 0.25, 100*dias, notch_radii)
 
99
    
 
100
    notch_radii = bn.move_mean(notch_radii,window=factor,min_count=1)
 
101
    b = triaxiality.bridgman_function(dias, notch_radii)
 
102
    triaxs = triaxiality.triax_function(dias, notch_radii)
 
103
    
 
104
    
 
105
    return indices_strain, eps_eq, dias, b, triaxs
 
106
 
 
107
def shift_conStrain(indices_strain, nFrames, dt_strain):
 
108
    """ shift conStrain data by a number of frames to make it coincident in time with the force trigger time """
 
109
    time_strain = (indices_strain + nFrames) * dt_strain
 
110
    
 
111
    if case == "SHTB":
 
112
        time_strain += 120.0/5090 # account for strain gauge being 120 mm positioned after center of specimen
 
113
    return time_strain
 
114
 
 
115
def interpolate_to_common_time(time_strain):
 
116
    # construct new time axis
 
117
    dt = min(dt_force, dt_strain)
 
118
    low, high = find_limits(time_force, time_strain)
 
119
    print("common time limits: %g -- %g" % (low, high))
 
120
    n = int((high-low)/dt)
 
121
    time = np.linspace(low, high, num=n, endpoint=True)
 
122
    print("new time axis:", time[0], time[-1])
 
123
    
 
124
    # interpolate strain-based quantities onto new time axis
 
125
    f = interpolate.interp1d(time_strain, eps_eq0)
 
126
    eps_eq_i = f(time)
 
127
    f = interpolate.interp1d(time_strain, b0)
 
128
    b_i = f(time)
 
129
    f = interpolate.interp1d(time_strain, triaxs0)
 
130
    triax_i = f(time)
 
131
    f = interpolate.interp1d(time_strain, dias0)
 
132
    diameter_i = f(time)
 
133
    
 
134
    # interpolate force quantities onto new time axis
 
135
    f = interpolate.interp1d(time_force, force0)
 
136
    force_i = f(time)
 
137
    
 
138
    return eps_eq_i, diameter_i, force_i, b_i, triax_i, time
 
139
 
 
140
 
 
141
 
 
142
def compute_stress_measures(force, diameter, b):
 
143
    # nominal (engineering) stress
 
144
    area0 = 0.25 * np.pi * D0**2
 
145
    stress_nominal = force/area0
 
146
    
 
147
    # stress measures based on current area
 
148
    cd_mm = D0 * diameter / diameter[0]# current diameter in mm
 
149
    area = 0.25 * np.pi * cd_mm**2
 
150
    stress_cauchy = force / area
 
151
    stress_eq = stress_cauchy * b
 
152
    
 
153
    return stress_nominal, stress_cauchy, stress_eq
 
154
    
 
155
 
 
156
# load force file
 
157
if case == "Zwick":
 
158
    time_force, force0, dt_force = load_force_Zwick()
 
159
elif case == "SHTB":
 
160
    time_force, force0, dt_force = load_force_SHTB()
 
161
elif case == "LS-Dyna":
 
162
    time_force, force0, dt_force = load_force_LSDyna()
 
163
else:
 
164
    print("unknown force case, exiting")
 
165
    
 
166
    
 
167
print("force time axis covers %g to %g" % (time_force[0], time_force[-1]))
 
168
indices_strain, eps_eq0, dias0, b0, triaxs0 = load_conStrain()
 
169
time_strain =  shift_conStrain(indices_strain, offset_strain, dt_strain)
 
170
print("strain time axis covers %g to %g" % (time_strain[0], time_strain[-1]))  
 
171
eps_eq, diameter, force, b, triax, time = interpolate_to_common_time(time_strain)
 
172
 
 
173
stress_nominal, stress_cauchy, stress_eq = compute_stress_measures(force, diameter, b)
 
174
 
 
175
# first plot window: nominal stress and strain over time
 
176
fig, ax = plt.subplots(3, figsize=(8,7))
 
177
ax[0].plot(time, stress_nominal, color="blue", label="stress")
 
178
ax[0].legend()
 
179
ax[0].set_ylabel("nominal stress [MPa]", color="blue")
 
180
ax[0].set_xlabel("time [ms]")
 
181
ax[0].set_ylim((0,None))
 
182
ax2 = ax[0].twinx()
 
183
ax2.set_ylabel("true strain [-]", color="red") 
 
184
ax2.plot(time, eps_eq, "r-", label="strain")
 
185
ax2.set_ylim((0,None))
 
186
ax[0].grid()
 
187
ax[0].legend()
 
188
 
 
189
 
 
190
# third plot: triaxiality over time
 
191
ax[1].plot(time, triax, label="triaxiality", color="blue")
 
192
ax[1].legend()
 
193
ax[1].set_ylabel("triaxiality [-]", color="blue")
 
194
ax[1].set_xlabel("time")
 
195
ax[1].set_ylim((0, 1.2))
 
196
ax32 = ax[1].twinx()
 
197
ax32.set_ylabel("bridgman factor [-]", color="red")
 
198
ax32.plot(time, b, "r-", label=b)
 
199
ax32.set_ylim((0,1.1))
 
200
ax[1].grid()
 
201
 
 
202
# 3rd plot: stress / strain
 
203
l_stress_nominal, = ax[2].plot(eps_eq, stress_nominal, lw=2, label="nominal stress")
 
204
l_stress_cauchy, = ax[2].plot(eps_eq, stress_cauchy, lw=2, label="Cauchy stress")
 
205
l_stress_eq, = ax[2].plot(eps_eq, stress_eq, "g--", lw=2, label="true eq. stress, Bridgman corrected")
 
206
 
 
207
if case == "LS-Dyna":
 
208
    x, y = power_law_plasticity(eps_eq)
 
209
    ax[2].plot(x, y, "b--", lw=2, label="material model stress")
 
210
 
 
211
ax[2].grid()
 
212
ax[2].set_xlabel("equivalent strain [-]")
 
213
ax[2].set_ylabel("stress [MPa]")
 
214
ax[2].legend()
 
215
ax[2].set_xlim(0, None)
 
216
ax[2].set_ylim(0, None)
 
217
 
 
218
 
 
219
 
 
220
 
 
221
 
 
222
class Index(object):
 
223
    ind = 0
 
224
    def __init__(self):
 
225
        self.update_stresses()
 
226
    
 
227
    def update_stresses(self):
 
228
        offset = offset_strain + self.ind
 
229
        time_strain =  shift_conStrain(indices_strain, offset, dt_strain)
 
230
        self.eps_eq, self.diameter, self.force, self.b, self.triax, time = interpolate_to_common_time(time_strain)
 
231
        self.stress_nominal, self.stress_cauchy, self.stress_eq = compute_stress_measures(self.force, self.diameter, self.b)
 
232
        
 
233
        l_stress_nominal.set_xdata(self.eps_eq)
 
234
        l_stress_nominal.set_ydata(self.stress_nominal)
 
235
        l_stress_cauchy.set_xdata(self.eps_eq)
 
236
        l_stress_cauchy.set_ydata(self.stress_cauchy)
 
237
        l_stress_eq.set_xdata(self.eps_eq)
 
238
        l_stress_eq.set_ydata(self.stress_eq)
 
239
        ax[2].set_title("frame offset: %d, @failure: triax=%3.2f, stress=%4d, strain=%3.2f" % (offset, self.triax[-1], self.stress_eq[-1], self.eps_eq[-1]))
 
240
        plt.draw()
 
241
 
 
242
    def next(self, event):
 
243
        self.ind += 1
 
244
        self.update_stresses()
 
245
 
 
246
    def prev(self, event):
 
247
        self.ind -= 1
 
248
        self.update_stresses()
 
249
 
 
250
callback = Index()
 
251
axprev = plt.axes([0.2, 0.01, 0.2, 0.04])
 
252
axnext = plt.axes([0.6, 0.01, 0.2, 0.04])
 
253
bnext = Button(axnext, '+ 1 frame')
 
254
bnext.on_clicked(callback.next)
 
255
bprev = Button(axprev, '- 1 frame')
 
256
bprev.on_clicked(callback.prev)
 
257
 
 
258
plt.subplots_adjust(bottom=0.15, top=1)
 
259
fig.tight_layout()
 
260
plt.show()
 
261
 
 
262
data = np.column_stack((callback.eps_eq, callback.stress_nominal, callback.stress_cauchy, callback.stress_eq, callback.triax, callback.b))
 
263
np.savetxt("stress_strain.dat", data, header="strain, nominal_stress, Cauchy_stress, Cauchy_Bridgman_stress, triaxiality, bridgman_factor")
 
264
 
 
265
import sys
 
266
sys.exit()
 
267
 
 
268
#-----------------------
 
269
#fit Hockett-Sherby plasticity model to Cauchy-Bridgman stress
 
270
sig0 = 1500
 
271
sig1 = 500
 
272
m = 0.80
 
273
n = 2.0
 
274
 
 
275
bounds = [(500, 25000),
 
276
          (500, 2500),
 
277
          (0.1, 2),
 
278
          (0.1, 2.0)]
 
279
bounds = np.asarray(bounds)
 
280
bounds = bounds.T
 
281
 
 
282
p0 = (sig0, sig1, m, n)
 
283
indices = np.asarray(np.where(eps_eq > 0.015)).ravel()
 
284
print("indices:", indices)
 
285
 
 
286
if len(indices > 1):
 
287
    idx = indices[0]
 
288
else:
 
289
    idx = 0
 
290
print("start index: ", idx)
 
291
print("eps_eq:", eps_eq)
 
292
 
 
293
eps_pl = eps_eq[idx:]
 
294
 
 
295
popt, pcov = curve_fit(hocket_sherby, eps_pl, stress_eq[idx:], p0=p0, bounds=bounds)
 
296
fit = hocket_sherby(eps_pl, *popt)
 
297
format = "%10s %6s %6s %6s %6s"
 
298
format_num = "%10s %06.2f %06.2f %06.2f %06.2f"
 
299
print(format % ("parameters", "sig0", "sig1", "m", "n"))
 
300
print(format_num % ("start", *p0))
 
301
print(format_num % ("final", *popt))
 
302
 
 
303
plt.plot(eps_pl, stress_eq[idx:])
 
304
plt.plot(eps_pl, fit)
 
305
plt.show()
 
306
 
 
307
 
 
308
# # fit Swift-Voce plasticity model to Cauchy-Bridgman stress
 
309
# A = 1501
 
310
# eps0 = 0.001
 
311
# n = 0.40
 
312
# k0 = 668
 
313
# Q = 1093
 
314
# b = 1.54
 
315
# alpha = 0.5
 
316
 
 
317
# bounds = [(1000, 2000),
 
318
#           (0.001, 0.2),
 
319
#           (0.1,0.5),
 
320
#           (200,1000),
 
321
#           (200,2000),
 
322
#           (0.1, 100),
 
323
#           (0,1)]
 
324
# bounds = np.asarray(bounds)
 
325
# bounds = bounds.T
 
326
 
 
327
# p0 = (A, eps0, n, k0, Q, b, alpha)
 
328
# idx = np.where(eps_eq > 0.0025)[0][0]
 
329
# eps_pl = eps_eq[idx:]
 
330
# print("start index: ", idx)
 
331
# popt, pcov = curve_fit(swift_voce, eps_pl, stress_eq[idx:], p0=p0, bounds=bounds)
 
332
# fit = swift_voce(eps_pl, *popt)
 
333
# format = "%10s %6s %6s %6s %6s %6s %6s %6s"
 
334
# format_num = "%10s %06.2f %06.2f %06.2f %06.2f %06.2f %06.2f %06.2f"
 
335
# print(format % ("parameters", "A", "eps0", "n", "k0", "Q", "b", "alpha"))
 
336
# print(format_num % ("start", *p0))
 
337
#print(format_num % ("final", *popt))
 
338
 
 
339
# --------------