def test_calc_moisture_forces_invalid_input_errors(self): """Sends invalid inputs to the function, expects the proper error""" (valid_lam, valid_mat_list) = assemble_valid_laminate() valid_Z = clt.assemble_Z(valid_lam) self.assertRaises( clt.LaminateLayupError, clt.calc_moisture_forces, valid_mat_list, valid_lam, None # Tests for invalid Z_vector ) self.assertRaises( clt.LaminateLayupError, clt.calc_moisture_forces, valid_mat_list, None, # Tests for invalid lam valid_Z) self.assertRaises( clt.LaminateLayupError, clt.calc_moisture_forces, None, # Tests for invalid mat_list valid_mat_list, valid_Z)
def test_assemble_ABD_invalid_input_errors(self): """Sends invalid inputs to the function, expects the proper error""" valid_mat_list = [ { 'X': 1 }, ] (valid_lam, _) = assemble_valid_laminate() valid_Z = clt.assemble_Z(valid_lam) self.assertRaises( clt.LaminateLayupError, clt.assemble_ABD, valid_mat_list, valid_lam, None # Tests for invalid Z_vector ) self.assertRaises( clt.LaminateLayupError, clt.assemble_ABD, valid_mat_list, None, # Tests for invalid lam valid_Z) self.assertRaises( clt.LaminateLayupError, clt.assemble_ABD, None, # Tests for invalid mat_list valid_mat_list, valid_Z)
def test_known_layup_returns_expected_Z_vector(self): """Sends a lam with known correct Z_vector and compares to returned""" (lam, _) = assemble_valid_laminate() Z_vector = clt.assemble_Z(lam) Z_vector = [round(z, 6) for z in Z_vector] expected_Z_vector = [ -5e-04, -4e-04, -3e-04, -2e-04, -1e-04, 0, 1e-04, 2e-04, 3e-04, 4e-04, 5e-04 ] self.assertEqual(Z_vector, expected_Z_vector)
def test_assemble_ABD_known_input_returns_correct_result(self): """Sends known input to the function and expects a known output, allowing for 0.1% error. Values come from Nasa Mechanics of Laminated Composite Plates Page 38 - Example 2""" mat1 = { "E1": 20010000.0, "E2": 1301000.0, "n12": 0.3, "G12": 1001000.0, } mat_list = (mat1, ) # Initializes dictionary of the laminate layup configurations # thk is thickness; ang is angle; mat_id is material id lam = {"thk": [], "ang": [], "mat_id": []} # Ply 1 lam['thk'].append(0.005) lam['ang'].append(45) lam['mat_id'].append(0) # Ply 2 lam['thk'].append(0.005) lam['ang'].append(0) lam['mat_id'].append(0) Z = clt.assemble_Z(lam) expected_A = numpy.array([[133420, 24735, 23523], [24735, 39325, 23523], [23523, 23523, 30819]]) expected_B = numpy.array([[169.6, -52.02, -58.80], [-52.02, -65.59, -58.80], [-58.80, -58.80, -52.02]]) expected_D = numpy.array([[1.1118, 0.2061, 0.1960], [0.2061, 0.3277, 0.1960], [0.1960, 0.1960, 0.2568]]) expected_ABD = numpy.zeros((6, 6)) expected_ABD[:3, :3] = expected_A expected_ABD[:3, 3:6] = expected_ABD[3:6, :3] = expected_B expected_ABD[3:6, 3:6] = expected_D returned_ABD = clt.assemble_ABD(mat_list, lam, Z) for rABD, eABD in zip(numpy.nditer(returned_ABD), numpy.nditer(expected_ABD)): if rABD == 0 or eABD == 0: continue else: error = rABD / eABD self.assertTrue(0.999 < error < 1.001)
def test_calc_moistures_forces_known_input_returns_expected_result(self): """Sends known input to the function and expects a known output, allowing for 0.1% error. Values come from Nasa Mechanics of Laminated Composite Plates Page 53 - Example 5""" mat1 = { "E1": 20010000.0, "E2": 1301000.0, "n12": 0.3, "G12": 1001000.0, "b1": 0.01, "b2": 0.35, } mat_list = (mat1, ) # Initializes dictionary of the laminate layup configurations # thk is thickness; ang is angle; mat_id is material id lam = {"thk": [], "ang": [], "mat_id": []} # Ply 1 lam['thk'].append(0.005) lam['ang'].append(0) lam['mat_id'].append(0) # Ply 2 lam['thk'].append(0.005) lam['ang'].append(45) lam['mat_id'].append(0) # Ply 3 lam['thk'].append(0.005) lam['ang'].append(45) lam['mat_id'].append(0) # Ply 4 lam['thk'].append(0.005) lam['ang'].append(0) lam['mat_id'].append(0) Z = clt.assemble_Z(lam) returned_Nm = clt.calc_moisture_forces(mat_list, lam, Z, dM=0.007) expected_Nm = numpy.array([51.7, 60.4, -4.3]) for rNm, eNm in zip(numpy.nditer(returned_Nm), numpy.nditer(expected_Nm)): if rNm == 0 or eNm == 0: continue else: error = rNm / eNm self.assertTrue(0.999 < error < 1.001)
def test_calc_thermal_forces_known_input_returns_expected_result(self): """Sends known input to the function and expects a known output, allowing for 0.1% error. Values come from Nasa Mechanics of Laminated Composite Plates Page 51 - Example 4""" mat1 = { "E1": 20010000.0, "E2": 1301000.0, "n12": 0.3, "G12": 1001000.0, "a1": -0.04e-6, "a2": 18e-6, } mat_list = (mat1, ) # Initializes dictionary of the laminate layup configurations # thk is thickness; ang is angle; mat_id is material id lam = {"thk": [], "ang": [], "mat_id": []} # Ply 1 lam['thk'].append(0.005) lam['ang'].append(0) lam['mat_id'].append(0) # Ply 2 lam['thk'].append(0.005) lam['ang'].append(45) lam['mat_id'].append(0) # Ply 3 lam['thk'].append(0.005) lam['ang'].append(45) lam['mat_id'].append(0) # Ply 4 lam['thk'].append(0.005) lam['ang'].append(0) lam['mat_id'].append(0) Z = clt.assemble_Z(lam) returned_Nt = clt.calc_thermal_forces(mat_list, lam, Z, dT=-155.6) expected_Nt = numpy.array([-33.57, -60.42, 12.83]) for rNt, eNt in zip(numpy.nditer(returned_Nt), numpy.nditer(expected_Nt)): if rNt == 0 or eNt == 0: continue else: error = rNt / eNt self.assertTrue(0.999 < error < 1.001)
def Profile(self, coord_sys, axis, var, step): """ Plots stress/strain in LCS or MCS against Z vector. """ # Sets plot dimension fig = plt.figure() #plt.figure(figsize=(10, 8)) Z = clt.assemble_Z(self.lam) X = { "inf": np.zeros((self.num_layers)), "sup": np.zeros((self.num_layers)) } Y = { "inf": np.zeros((self.num_layers)), "sup": np.zeros((self.num_layers)) } P = np.zeros((self.num_layers * 2, 2)) # Sets the proper names if coord_sys == "MCS": if axis == 0: axis_name = "1" elif axis == 1: axis_name = "2" else: axis_name = "6" else: if axis == 0: axis_name = "x" elif axis == 1: axis_name = "y" else: axis_name = "xy" # Formats the plot plt.title('Profile ' + coord_sys + '-' + axis_name + ' ' + var) plt.xlabel(var + ' (' + coord_sys + '-' + axis_name + ')') plt.ticklabel_format(style='sci', axis='x', scilimits=(0, 0)) plt.ylabel('Z coordinate') plt.grid(True) # Iterates the layers, add data to plot for layer in range(self.num_layers): X["inf"][layer] = self.res[step][coord_sys][var]["inf"][axis][ layer] Y["inf"][layer] = Z[layer] X["sup"][layer] = self.res[step][coord_sys][var]["sup"][axis][ layer] Y["sup"][layer] = Z[layer + 1] P[layer * 2] = [X["inf"][layer], Y["inf"][layer]] P[layer * 2 + 1] = [X["sup"][layer], Y["sup"][layer]] plt.fill_betweenx([P[layer * 2, 1], P[layer * 2 + 1, 1]], [P[layer * 2, 0], P[layer * 2 + 1, 0]], hatch="//", facecolor="none", edgecolor="r", lw=1.0) # Adds main lines plt.plot(P[:, 0], P[:, 1], color="r", lw=2.5) plt.plot([0] * (self.num_layers + 1), Z, color="b", lw=2.5) # Displays the plot if self.display: plt.show() if self.save: fig.savefig("plots/profile.png") plt.close(fig) """
def test_valid_layup_to_assemble_Z_returns_valid_numpy_array(self): """Z_vector returned by the function must always be a np.ndarray""" (lam, _) = assemble_valid_laminate() Z_vector = clt.assemble_Z(lam) self.assertTrue(isinstance(Z_vector, numpy.ndarray))