Once the laminate load-deformation relations are solved, the deformation is known.
Then, the strains in the laminate coordinate system at any position $z$ through the thickness of the laminate can be computed by:
\begin{equation} \begin{bmatrix} \varepsilon_x \\ \varepsilon_y \\ \gamma_{xy} \end{bmatrix}= \begin{bmatrix} \varepsilon_x^0 \\ \varepsilon_y^0 \\ \gamma_{xy}^0 \end{bmatrix}+ z\begin{bmatrix} \kappa_x \\ \kappa_y \\ \kappa_{xy} \end{bmatrix} \end{equation}Example:
from laminatelib import laminateStiffnessMatrix, solveLaminateLoadCase, laminateThickness
m1={'E1':140000, 'E2':10000, 'v12':0.3, 'G12':5000}
layup1 =[ {'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ]
ABD1 = laminateStiffnessMatrix(layup1)
result = solveLaminateLoadCase(ABD1,Nx=500,Mx=100)
d=result[1]
print(d[0:3]) # mid-plane strains
print(d[3:6]) # curvatures
The strains at the bottom of the laminate ( $z=-1.5$ ) and the top of the laminate ( $z=1.5$ ) are:
strn_xyz_botLam = d[0:3] -1.5*d[3:6]
strn_xyz_topLam = d[0:3] +1.5*d[3:6]
print(strn_xyz_botLam)
print(strn_xyz_topLam)
The most relevant positions for asessing strains and stresses are the ones at bottom and top of the individual layers:
bot = -laminateThickness(layup1)/2 # The bottom coordinate of the laminate
counter=1
for layer in layup1:
top = bot + layer['thi']
strnXYZbot=d[0:3]+bot*d[3:6]
strnXYZtop=d[0:3]+top*d[3:6]
print('Layer',str(counter),'bot','z=',bot,strnXYZbot)
print('Layer',str(counter),'top','z=',top,strnXYZtop)
counter=counter+1
bot=top # for the next layer, top becomes the bot
The stresses at bottom and top of all layers can be obtained by a few more lines including the transformed stiffness matrix and Hooke's law: \begin{equation} \mathbf{Q{'}}_k = \mathbf{T}_{\sigma}^{-1}\mathbf{Q}_k \mathbf{T}_{\epsilon} \end{equation}
\begin{equation} \boldsymbol{\sigma}{'} = \mathbf{Q{'}}_k\boldsymbol{\epsilon}{'} \end{equation}from laminatelib import Q2D, Q2Dtransform
import numpy as np
bot = -laminateThickness(layup1)/2 # The bottom coordinate of the laminate
counter=1
for layer in layup1:
top = bot + layer['thi']
strnXYZbot=d[0:3]+bot*d[3:6]
strnXYZtop=d[0:3]+top*d[3:6]
Q=Q2D(layer['mat']) # the stiffness matrix of current layer
Qt=Q2Dtransform(Q,layer['ori']) # the transformed stiffness matrix of current layer
strsXYZbot = np.dot( Qt, strnXYZbot) # stresses by Hooke's law
strsXYZtop = np.dot( Qt, strnXYZtop) # stresses by Hooke's law
print('Layer',str(counter),'bot','z=',bot,strsXYZbot)
print('Layer',str(counter),'top','z=',top,strsXYZtop)
counter=counter+1
bot=top # for the next layer, top becomes the bot
In order to find the stresses in the material coordinate system we must add a transformation:
\begin{equation} \boldsymbol{\sigma} = \mathbf{T}_{\sigma}\boldsymbol{\sigma}{'} \end{equation}from laminatelib import T2Ds, T2De
bot = -laminateThickness(layup1)/2 # The bottom coordinate of the laminate
counter=1
for layer in layup1:
top = bot + layer['thi']
strnXYZbot=d[0:3]+bot*d[3:6]
strnXYZtop=d[0:3]+top*d[3:6]
Q=Q2D(layer['mat']) # the stiffness matrix of current layer
Qt=Q2Dtransform(Q,layer['ori']) # the transformed stiffness matrix of current layer
strsXYZbot = np.dot( Qt, strnXYZbot) # stresses by Hooke's law
strsXYZtop = np.dot( Qt, strnXYZtop) # stresses by Hooke's law
T=T2Ds(layer['ori']) # transformation matrix for stresses
strs123bot = np.dot( T, strsXYZbot) # strains in material coordinate system
strs123top = np.dot( T, strsXYZtop) # strains in materila coordinate system
print('Layer',str(counter),'bot','z=',bot,strs123bot)
print('Layer',str(counter),'top','z=',top,strs123top)
counter=counter+1
bot=top # for the next layer, top becomes the bot
When the stresses in the material coordinate system are found, the exposure factors can be computed using the previously defined plane stress failure criteria functions
from laminatelib import fE2DMS, fE2DME, fE2DTW
The derived results for one layer includes stresses and strains in two coordinate systems, as well as stress exposure factors and other relevant data such as the z-coordinates. All of these results should generally be computed at two locations; at the bottom and at the top of the layer. A suggestion for a useful datastructure is illustrated:
Layer k
|
------------------------------------------------------------------
| | | |
stress strain fail h
----------- ----------- ------------------- -----
| | | | | | | | |
xyz 123 xyz 123 MS ME TW bot top
----- ----- ----- ----- ----- ----- -----
| | | | | | | | | | | | | |
bot top bot top bot top bot top bot top bot top bot top
The data structure can easily be created using dictionaries and then be organized into a list containing the results from all layers:
def layerResults(layup,deformations):
# An empty list that shall be populated with results from all layers:
results=[]
# The bottom coordinate of the laminate:
bot = -laminateThickness(layup)/2
for layer in layup:
# the top of current layer is just the bottom + the thickness:
top=bot+layer['thi']
# creating a dictionary with the two coordinates:
h={'bot':bot, 'top':top}
# computing the strains in laminate coordinate system:
strnXYZbot=deformations[0:3]+bot*deformations[3:6]
strnXYZtop=deformations[0:3]+top*deformations[3:6]
# put the strains into a dictionary:
strnXYZ={'bot':strnXYZbot, 'top':strnXYZtop}
# the transformation matrix for strains:
Te=T2De(layer['ori'])
# transforming the strains into the material coordinate system:
strn123bot=np.dot(Te, strnXYZbot)
strn123top=np.dot(Te, strnXYZtop)
# the strains at top and bottom as a dictionary:
strn123={'bot':strn123bot, 'top':strn123top}
# all strains as a new dictionary:
strn={'xyz':strnXYZ, '123':strn123}
# stiffness matrix of the material:
Q=Q2D(layer['mat'])
# Hooke's law: finding the stresses in material system:
strs123bot=np.dot(Q,strn123bot)
strs123top=np.dot(Q,strn123top)
# the material stresses as a dictionary having bottom and topp results:
strs123={'bot':strs123bot, 'top':strs123top}
# transformation matrix for stress, negativ rotation applies now,
# since this is from material system to laminat system (reversed..)
Ts=T2Ds(-layer['ori'])
# transforming stresses into laminate system:
strsXYZbot=np.dot(Ts,strs123bot)
strsXYZtop=np.dot(Ts,strs123top)
# organizing the stresses for the two location in a dictionary
strsXYZ={'bot':strsXYZbot, 'top':strsXYZtop}
# all stresses as a new nested dictionary:
strs={'xyz':strsXYZ, '123':strs123}
# Failure criteria...follows the same logic as above
MSbot=fE2DMS(strs123bot,layer['mat'])
MStop=fE2DMS(strs123top,layer['mat'])
MS={'bot':MSbot, 'top':MStop}
MEbot=fE2DME(strs123bot,layer['mat'])
MEtop=fE2DME(strs123top,layer['mat'])
ME={'bot':MEbot, 'top':MEtop}
TWbot=fE2DTW(strs123bot,layer['mat'])
TWtop=fE2DTW(strs123top,layer['mat'])
TW={'bot':TWbot, 'top':TWtop}
fail={'MS':MS, 'ME':ME, 'TW':TW}
# and finally put everything into a top level dictionary,
# and add that to the list
results.append( {'h':h , 'strain':strn, 'stress':strs, 'fail':fail } )
bot=top
return results
m1={'E1':140000, 'E2':10000, 'v12':0.3, 'G12':5000, 'XT':1200, 'XC':800, 'YT':50, 'YC':120, 'S12':75, 'f12':-0.5}
layup1 =[ {'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': -45 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': +45 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ]
ABD1=laminateStiffnessMatrix(layup1)
load,defs = solveLaminateLoadCase(ABD=ABD1, Nx=500)
res = layerResults(layup1,defs)
z-coordinate at the bottom of the first layer:
print( res[0]['h']['bot'] )
Stress in the global coordinate system at the bottom of the first layer:
print( res[0]['stress']['xyz']['bot'] )
Stress in the material coordinate system at the top of the second layer:
print( res[1]['stress']['123']['top'] )
Exposure factors for all layers and all positions based on the Tsai-Wu failure criterion:
for r in res:
print (r['fail']['TW']['bot'])
print (r['fail']['TW']['top'])
The function plotLayerStresses(results)
found in Plot Gallery makes graphs of layer results through the thickness of a laminate where results are obtained by the function layerResults(layup,deformations)
.
from plotlib import plotLayerStresses
%matplotlib inline
Examples:
m1={'E1':140000, 'E2':10000, 'v12':0.3, 'G12':5000, 'XT':1200, 'XC':800, 'YT':50, 'YC':120, 'S12':75, 'f12':-0.5}
layup1 =[ {'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ]
ABD1=laminateStiffnessMatrix(layup1)
load,defs = solveLaminateLoadCase(ABD=ABD1, Nx=500, Nxy=200)
res = layerResults(layup1,defs)
plotLayerStresses(res)
m1={'E1':140000, 'E2':10000, 'v12':0.3, 'G12':5000, 'XT':1200, 'XC':800, 'YT':50, 'YC':120, 'S12':75, 'f12':-0.5}
layup1 =[ {'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': -45 , 'thi':1} ,
{'mat':m1 , 'ori': +45 , 'thi':1} ,
{'mat':m1 , 'ori': +45 , 'thi':1} ,
{'mat':m1 , 'ori': -45 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ]
ABD1=laminateStiffnessMatrix(layup1)
load,defs = solveLaminateLoadCase(ABD=ABD1, Nx=500)
res = layerResults(layup1,defs)
plotLayerStresses(res)
m1={'E1':140000, 'E2':10000, 'v12':0.3, 'G12':5000, 'XT':1200, 'XC':800, 'YT':50, 'YC':120, 'S12':75, 'f12':-0.5}
layup1 =[ {'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ]
ABD1=laminateStiffnessMatrix(layup1)
load,defs = solveLaminateLoadCase(ABD=ABD1, Ny=500, Mx=200)
res = layerResults(layup1,defs)
plotLayerStresses(res)
The function plotLayerFailure(results)
found in Plot Gallery makes graphs of layer results through the thickness of a laminate where results are obtained by the function layerResults(layup,deformations)
.
from plotlib import plotLayerFailure
%matplotlib inline
Examples:
m1={'E1':140000, 'E2':10000, 'v12':0.3, 'G12':5000, 'XT':1200, 'XC':800, 'YT':50, 'YC':120, 'S12':75, 'f12':-0.5}
layup1 =[ {'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ,
{'mat':m1 , 'ori': 90 , 'thi':1} ,
{'mat':m1 , 'ori': 0 , 'thi':1} ]
ABD1=laminateStiffnessMatrix(layup1)
load,defs = solveLaminateLoadCase(ABD=ABD1, Ny=500, Mx=200)
res = layerResults(layup1,defs)
plotLayerFailure(res)
Disclaimer:This site is about polymer composites, designed for educational purposes. Consumption and use of any sort & kind is solely at your own risk.
Fair use: I spent some time making all the pages, and even the figures and illustrations are my own creations. Obviously, you may steal whatever you find useful here, but please show decency and give some acknowledgment if or when copying. Thanks! Contact me: nils.p.vedvik@ntnu.no www.ntnu.edu/employees/nils.p.vedvik
Copyright 2021, All right reserved, I guess.