Source code for composipy.laminate_class

import numbers

import numpy as np
import scipy as sp


import sys
sys.path.append('D:/repositories/composipy')

from composipy.ply_class import Ply

[docs]class Laminate: ''' This class creates laminate object. It needs ply objects and the angle information. Some formulation characteristics are: Laminate formulations ares used (see References) Main reference is the chapter 4 of reference 2. Parameters ---------- layup : list The layup instance is composed of a list containing a tuple to each ply. The tuple must contain the ply angle (float in degrees) with relation to the 1 direciton and a ply object (of Ply class). [(angle_of_ply_1, ply_1), (angle_of_ply_2, ply_2), ... (angle_of_ply_n, ply_n)] Returns ------- None Example ------- >>> from composipy import Ply, Laminate >>> ply_1 = Ply(129500, 9370, 0.38, 5240, 0.2) >>> layup_1 = [(90, ply_1), (0, ply_1), (90, ply_1)] >>> laminate = Laminate(layup_1) >>> laminate_1.D # retunrs a array containing bending stiffness matrix [D] of the laminate >>> laminate_1.A # retunrs a array containing stiffness matrix [A] of the laminate >>> laminate_1.B # retunrs a array containing coupled stiffness matrix [B] of the laminate >>> laminate_1.print_ABD() # method that prints ABD matrices of the laminate >>> laminate_1.ABD_p # returns an array containing the ABD prime matricies of the laminate References ---------- 1 - JONES, M. Robert. Mechanics of Composite Materials. Taylor & Francis: 2nd ed 1999. 2 - Analysis and Design of composite structures. Class notes. ITA 2020. ''' def __init__(self, layup): # Checking layup if not isinstance(layup, list): raise ValueError( 'layup must be a list of tuples.\n\ Each tuple must contain a angle value and a Ply object' ) for ply in layup: if not isinstance(ply[0], numbers.Real): raise ValueError(f'the angle must be a real number. Check {ply}') if not isinstance(ply[1], Ply): raise ValueError(f'the ply mus be a Ply object. Check {ply}') self.layup = layup self._z_position = None self._Q_layup = None self._T_layup = None self._A = None self._B = None self._D = None self._ABD_p = None #Properties @property def z_position(self): total_thickness = 0 for t in self.layup: total_thickness += t[1].thickness current_z = -total_thickness/2 ply_position = [current_z] for t in self.layup: current_z += t[1].thickness ply_position.append(current_z) return ply_position @property def Q_layup(self): if self._Q_layup is None: self._Q_layup = [] for theta in self.layup: c = np.cos(theta[0]*np.pi/180) s = np.sin(theta[0]*np.pi/180) T_real = np.array([ [c**2, s**2, 2*c*s], [s**2, c**2, -2*c*s], [-c*s, c*s, c**2-s**2] ]) T_engineering = np.array([ [c**2, s**2, c*s], [s**2, c**2, -c*s], [-2*c*s, 2*c*s, c**2-s**2] ]) self._Q_layup.append( (np.linalg.inv(T_real)) @ theta[1].Q_0 @ T_engineering ) return self._Q_layup @property def T_layup(self): if self._T_layup is None: self._T_layup = [] for theta in self.layup: c = np.cos(theta[0]*np.pi/180) s = np.sin(theta[0]*np.pi/180) T_real = np.array([ [c**2, s**2, 2*c*s], [s**2, c**2, -2*c*s], [-c*s, c*s, c**2-s**2] ]) T_engineering = np.array([ [c**2, s**2, c*s], [s**2, c**2, -c*s], [-2*c*s, 2*c*s, c**2-s**2] ]) self._T_layup.append([T_real,T_engineering]) return self._T_layup @property def A(self): '''[A] Matrix as numpy.ndarray ''' if self._A is None: self._A = np.zeros(9).reshape(3,3) for i in enumerate(self.Q_layup): zk1 = self.z_position[i[0]+1] zk0 = self.z_position[i[0]] self._A += (zk1-zk0) * i[1] return self._A @property def B(self): '''[B] Matrix as numpy.ndarray ''' if self._B is None: self._B = np.zeros(9).reshape(3,3) for i in enumerate(self.Q_layup): zk1 = self.z_position[i[0]+1] zk0 = self.z_position[i[0]] self._B += (1/2) * (zk1**2-zk0**2) * i[1] return self._B @property def D(self): '''[D] Matrix as numpy.ndarray ''' if self._D is None: self._D = np.zeros(9).reshape(3,3) for i in enumerate(self.Q_layup): zk1 = self.z_position[i[0]+1] zk0 = self.z_position[i[0]] self._D += (1/3) * (zk1**3-zk0**3) * i[1] return self._D @property def ABD_p(self): ''' [A',B',D'], which is inverse of ABD Matrix, as numpy.ndarray ''' if self._ABD_p is None: A_p = np.linalg.inv(self.A) \ + (-np.linalg.inv(self.A) * self.B) \ * (np.linalg.inv(self.D-self.B * np.linalg.inv(self.A) * self.B)) \ * (self.B * np.linalg.inv(self.A)) B_p = (-np.linalg.inv(self.A) * self.B) \ * np.linalg.inv(self.D \ - self.B \ * np.linalg.inv(self.A) \ * self.B ) D_p = np.linalg.inv( self.D - self.B * np.linalg.inv(self.A) * self.B ) ABD_p = sp.matrix( np.vstack( (np.hstack((A_p,B_p)), np.hstack((B_p,D_p)))) ) ABD_p[np.isnan(ABD_p)] = 0 self._ABD_p = ABD_p return self._ABD_p @staticmethod def _pprint(*args): nStrings = 20 representation = '' for arg in args: nSpaces = nStrings - len(str(arg)) if nSpaces < 0: nSpaces = 1 representation += str(arg) + nSpaces * " " return representation #Representation (str not implemented) def __repr__(self): representation = '' for angle, ply in self.layup: if angle == abs(90): angle_repr = '|||||' elif angle == 0: angle_repr = '=====' elif angle == 45 or angle == -45: angle_repr = '/////' else: angle_repr = '***' representation += self._pprint(ply.name, angle, angle_repr) + '\n' return representation #Comparisons def __eq__(self, other): if isinstance(other, Laminate): return (self.layup == other.layup) return NotImplemented #Methods
[docs] def show_ABD(self): ''' This method prints ABD Matrix''' result = "[A]:\n" + str(self.A) + "\n" result += "[B]:\n" + str(self.B) + "\n" result += "[D]:\n" + str(self.D) print(result) return None