def test_det_6(): # {{{1 """Using a random generated matrix and https://www.mathsisfun.com/algebra/matrix-calculator.html """ assert round(mat.det(_rndm), 2) == -0.45
def test_det_dia(): # {{{1 m = [[1, 0, 0], [0, 2, 0], [0, 0, 3]] assert mat.det(m) == 6
def test_det_3(): # {{{1 """From https://www.mathsisfun.com/algebra/matrix-determinant.html""" m = [[6, 1, 1], [4, -2, 5], [2, 8, 7]] assert mat.det(m) == -306
def laminate(name, layers): """Create a laminate. Arguments/properties of a laminate: name: A non-empty string containing the name of the laminate layers: A non-empty sequence of lamina (will be converted into a tuple). Additional properties: thickness: Thickness of the laminate in mm. fiber_weight: Total area weight of fibers in g/m². ρ: Specific gravity of the laminate in g/cm³. vf: Average fiber volume fraction. resin_weight: Total area weight of resin in g/m². ABD: Stiffness matrix. abd: Compliance matrix. Ex: Young's modulus in the x-direction. Ey: Young's modulus in the y-direction. Ez: Young's modulus in the z-direction. Gxy: In-plane shear modulus. νxy: Poisson constant. νyx: Poisson constant. αx: CTE in x-direction. αy: CTE in y-direction. wf: Fiber weight fraction. C: 3D Stiffness matrix for the laminate in global coordinates. """ if not layers: raise ValueError("no layers in the laminate") if not isinstance(name, str): raise ValueError("the name of a laminate must be a string") if len(name) == 0: raise ValueError("the length of the name of a laminate must be >0") layers = tuple(layers) thickness = sum(la.thickness for la in layers) fiber_weight = sum(la.fiber_weight for la in layers) ρ = sum(la.ρ * la.thickness for la in layers) / thickness vf = sum(la.vf * la.thickness for la in layers) / thickness resin_weight = sum(la.resin_weight for la in layers) wf = fiber_weight / (fiber_weight + resin_weight) # Set z-values for lamina. zs = -thickness / 2 lz2, lz3 = [], [] C = lpm.zeros(6) for la in layers: ze = zs + la.thickness lz2.append((ze * ze - zs * zs) / 2) lz3.append((ze * ze * ze - zs * zs * zs) / 3) zs = ze C = lpm.add(C, lpm.mul(la.C, la.thickness / thickness)) C = lpm.clean(C) S = lpm.inv(C) Ntx, Nty, Ntxy = 0.0, 0.0, 0.0 ABD = lpm.zeros(6) H = lpm.zeros(2) c3 = 0 for la, z2, z3 in zip(layers, lz2, lz3): # first row ABD[0][0] += la.Q̅11 * la.thickness # Hyer:1998, p. 290 ABD[0][1] += la.Q̅12 * la.thickness ABD[0][2] += la.Q̅16 * la.thickness ABD[0][3] += la.Q̅11 * z2 ABD[0][4] += la.Q̅12 * z2 ABD[0][5] += la.Q̅16 * z2 # second row ABD[1][0] += la.Q̅12 * la.thickness ABD[1][1] += la.Q̅22 * la.thickness ABD[1][2] += la.Q̅26 * la.thickness ABD[1][3] += la.Q̅12 * z2 ABD[1][4] += la.Q̅22 * z2 ABD[1][5] += la.Q̅26 * z2 # third row ABD[2][0] += la.Q̅16 * la.thickness ABD[2][1] += la.Q̅26 * la.thickness ABD[2][2] += la.Q̅66 * la.thickness ABD[2][3] += la.Q̅16 * z2 ABD[2][4] += la.Q̅26 * z2 ABD[2][5] += la.Q̅66 * z2 # fourth row ABD[3][0] += la.Q̅11 * z2 ABD[3][1] += la.Q̅12 * z2 ABD[3][2] += la.Q̅16 * z2 ABD[3][3] += la.Q̅11 * z3 ABD[3][4] += la.Q̅12 * z3 ABD[3][5] += la.Q̅16 * z3 # fifth row ABD[4][0] += la.Q̅12 * z2 ABD[4][1] += la.Q̅22 * z2 ABD[4][2] += la.Q̅26 * z2 ABD[4][3] += la.Q̅12 * z3 ABD[4][4] += la.Q̅22 * z3 ABD[4][5] += la.Q̅26 * z3 # sixth row ABD[5][0] += la.Q̅16 * z2 ABD[5][1] += la.Q̅26 * z2 ABD[5][2] += la.Q̅66 * z2 ABD[5][3] += la.Q̅16 * z3 ABD[5][4] += la.Q̅26 * z3 ABD[5][5] += la.Q̅66 * z3 # Calculate unit thermal stress resultants. # Hyer:1998, p. 445 Ntx += (la.Q̅11 * la.αx + la.Q̅12 * la.αy + la.Q̅16 * la.αxy) * la.thickness Nty += (la.Q̅12 * la.αx + la.Q̅22 * la.αy + la.Q̅26 * la.αxy) * la.thickness Ntxy += (la.Q̅16 * la.αx + la.Q̅26 * la.αy + la.Q̅66 * la.αxy) * la.thickness # Calculate H matrix (derived from Barbero:2018, p. 181) sb = 5 / 4 * (la.thickness - 4 * z3 / thickness ** 2) H[0][0] += la.Q̅s44 * sb H[0][1] += la.Q̅s45 * sb H[1][0] += la.Q̅s45 * sb H[1][1] += la.Q̅s55 * sb # Calculate E3 c3 += la.thickness / la.E3 # Finish the matrices, discarding very small numbers in ABD and H. ABD = lpm.clean(ABD) H = lpm.clean(H) abd = lpm.inv(ABD) h = lpm.inv(H) # Calculate the engineering properties. # Nettles:1994, p. 34 e.v. dABD = lpm.det(ABD) dt1 = lpm.det(lpm.delete(ABD, 0, 0)) Ex = dABD / (dt1 * thickness) dt2 = lpm.det(lpm.delete(ABD, 1, 1)) Ey = dABD / (dt2 * thickness) dt3 = lpm.det(lpm.delete(ABD, 2, 2)) Gxy = dABD / (dt3 * thickness) dt4 = lpm.det(lpm.delete(ABD, 0, 1)) dt5 = lpm.det(lpm.delete(ABD, 1, 0)) νxy = dt4 / dt1 νyx = dt5 / dt2 # See Barbero:2018, p. 197 Gyz = H[0][0] / thickness Gxz = H[1][1] / thickness # All layers experience the same force in Z-direction. Ez = thickness / c3 # Calculate the coefficients of thermal expansion. # *Technically* only valid for a symmetric laminate! # Hyer:1998, p. 451, (11.86) αx = abd[0][0] * Ntx + abd[0][1] * Nty + abd[0][2] * Ntxy αy = abd[1][0] * Ntx + abd[1][1] * Nty + abd[1][2] * Ntxy # Calculate tensor engineering properties tEx, tEy, tEz = 1 / S[0][0], 1 / S[1][1], 1 / S[2][2] tGxy, tGxz, tGyz = 1 / S[5][5], 1 / S[4][4], 1 / S[3][3] tνxy, tνxz, tνyz = -S[1][0] / S[0][0], -S[2][0] / S[0][0], -S[2][1] / S[1][1] return SimpleNamespace( name=name, layers=layers, thickness=thickness, fiber_weight=fiber_weight, ρ=ρ, vf=vf, resin_weight=resin_weight, ABD=ABD, abd=abd, H=H, h=h, Ex=Ex, Ey=Ey, Ez=Ez, Gxy=Gxy, Gyz=Gyz, Gxz=Gxz, νxy=νxy, νyx=νyx, αx=αx, αy=αy, wf=wf, C=C, S=S, tEx=tEx, tEy=tEy, tEz=tEz, tGxy=tGxy, tGyz=tGyz, tGxz=tGxz, tνxy=tνxy, tνxz=tνxz, tνyz=tνyz, )