def append_material_properties(plies, plybook):
	#Opens .xlsx material properties data and appends material property list based on materials contained in plybook. Returns plybook
	workbook = openpyxl.load_workbook(filename = 'MECH530_Material_Database_ElaineCraigie.xlsx', use_iterators = True, data_only = True)

	property_sheet = workbook.worksheets[1] #True provided that Properties remains the second sheet in the file
	property_range = property_sheet.iter_rows('A10:M17') #contains all of my materials and their properties

	#MATERIAL DATABASE---------------------------------------------------------------------------------------------------------------------------
	mat_properties = [] #This list will contain all information provided in the Plybook and sort out doubled plies, etc.
	mat_properties = [[cell.value for cell in row] for row in property_range]

	#Build these properties into my plybook list so that each row has all of the appropriate material properties associated with it
	ply_r = 0

	while ply_r <= plies - 1:
		mat_r = 0 #counts my rows in the mat_properties list (5 materials so far - change limit on WHILE loop if this evolves)
		while mat_r <= 6:
			# print 'ply_r_2 = ' + str(ply_r_2)
			# print 'mat_r = ' + str(mat_r)
			if plybook[ply_r][1] == mat_properties[mat_r][0]:
				mat_c = 4 #counts my columns in the mat_properties list (these are the correct indices for the plybook list, but are +3 for the mat_properties list)
				while mat_c <= 12: #Add material properties to each ply in Plybook
					plybook[ply_r][mat_c] = mat_properties[mat_r][mat_c - 1]
					mat_c += 1
				#The following line builds the S_on, Q_on, S_off, Q_off, Uq, Us matrices and vector into plybook for EACH ply respectively	
				plybook = MECH530_matrices.get_on_off_matrices(plies, plybook, ply_r)	
			mat_r += 1		
		ply_r += 1

	return plybook
#Created by Elaine Craigie, Fall 2014
import MECH530_getplybook #Contains all functions related to reading and sorting raw plybook data to final plybook.
import MECH530_print #Contains all print statements
import MECH530_matrices #Contains all calculations related to Q, S, A and U matrix/vector properties
import MECH530_input #Contains all scripts related to input commands
import MECH530_failure #Contains all scripts related to failure analysis

#Existing modules/classes
import numpy #Allows me to create arrays that can be nicely formatted when printed

#Regular commands - outputs for every single assignment
plies, h_laminate, h_core, plybook = MECH530_getplybook.getplybook() #Get sorted plybook, total number of plies, thickness of core and laminate 
plybook = MECH530_getplybook.append_material_properties(plies, plybook) #Get newly appended plybook with material properties assigned to each ply
materials_used, num_materials = MECH530_getplybook.count_laminate_materials(plies, plybook) #Get dictionary of materials used and size of dictionary
A, A_comp, D, D_comp = MECH530_matrices.compute_A_D(plybook, plies, h_laminate, h_core)
MECH530_print.print_init(plies, h_laminate, h_core, plybook, materials_used, num_materials, A, A_comp, D, D_comp) #Prints all regular outputs require

# __________________________________ASSIGNMENT 6 - Nov 15______________________________________________
case = 1
stress_applied, stress_type, moment_applied, moment_type = MECH530_input.input_loads(case) #Contains applied stress and type (in [N] and [N/m])

if moment_type != "NO" or stress_type != "NO":
	#Get the stress and R values in table and array formats
	stress_state, R_fail, stress_df1, failure_df1 = MECH530_print.print_loadapplied(case, plybook, plies, stress_applied, stress_type, moment_applied, moment_type, A, A_comp, D, D_comp, h_laminate) #Will determine other components of stress and strain
	#Identify the minimum R's along with their corresponding failure modes
	max_stress_crit1, quad_poly_crit1, hashin_crit1 = MECH530_print.print_failure_modes(failure_df1, stress_applied, moment_applied)
print "------------------------------------------------------------------------------"

case = 2
stress_applied, stress_type, moment_applied, moment_type = MECH530_input.input_loads(case) #Contains applied stress and type (in [N] and [N/m])
def print_loadapplied(case, plybook, plies, stress_applied, stress_type, moment_applied, moment_type, A, A_comp, D, D_comp, h_laminate):

	#Find the stress, strain and failure criterion R values	
	i = 0

	engineering_formatter = lambda x: "%9.4f" % x if x != 0 else "%9.1f" % x
	numpy.set_printoptions(formatter = {'float_kind':engineering_formatter})

	if (stress_type == 'OFF' or stress_type == 'NO') and (moment_type == 'OFF' or moment_type == 'NO'):		
		K = 10**(-9) * D_comp.dot(moment_applied) #Now this will be in [m] since D_comp is in 

		strain_off_av = 10**(-9) * A_comp.dot(stress_applied) #Convert [a], [m/GN] --> [m/N]. This is now unitless

		if case == 1:
			print "OFF-AXIS APPLIED RESULTANTS: CASE 1"
		elif case == 2:	
			print "OFF-AXIS APPLIED RESULTANTS: CASE 2"	
		elif case == 3:
			print "OFF-AXIS APPLIED RESULTANTS: CASE 3" 	
		else:	
			print "OFF-AXIS APPLIED RESULTANTS"		
		print "\nCurvature K ="
		print K.T, "[1/m]"	 
		print "\n(INPUT) Off-axis Applied stress resultant N = "
		print stress_applied.T, "[N/m]"
		print "\n(INPUT) Off-axis Applied moment resultant M = "
		print moment_applied.T, "[N]"		

		h = h_laminate / 2.0
		position = {'1':'TOP', '0':'BOTTOM'}
		while i < plies:
			temp_env = numpy.zeros(2) #Contains my ply number, and angle

			if plybook[i][1] == 'CORE':
				h -= plybook[i][3] #Subtract the thickness of the core 
			else:	
				position_counter = 1 #Start at the top

				while position_counter > -1:
					strain_off = strain_off_av + (h * K / 1000.0) #Convert thickness to m 
					stress_on, strain_on = MECH530_matrices.convert_to_on_axis(plybook, i, strain_off)

					strength = MECH530_failure.failure_props(plybook, i)
					max_R = MECH530_failure.max_stress(stress_on, strength, i)
					quad_R = MECH530_failure.quad_poly(stress_on, strength, i)
					hash_R = MECH530_failure.hashin_crit(stress_on, strength, i)

					temp_env[0] = plies-i
					temp_env[1] = plybook[i][2] #The angle		

					temp_R = numpy.hstack((temp_env, max_R, quad_R, hash_R))	
					temp_stress = numpy.hstack((temp_env, strain_off.flatten(), strain_on.flatten(), stress_on.flatten()))

					if position_counter == 0: #We've just done the bottom of a ply
						h == h
						R_fail = numpy.vstack((R_fail, temp_R))
						stress_state = numpy.vstack((stress_state, temp_stress)) #Creates an array full of stresses and strains
					else: #We've just done the top of a ply and we want to do the bottom next
						h -= plybook[i][3] #Subtract the thickness of a ply
						if i == 0: #We need to create the R_fail and result matrices
							R_fail = temp_R
							stress_state = temp_stress
						else:
							R_fail = numpy.vstack((R_fail, temp_R))
							stress_state = numpy.vstack((stress_state, temp_stress))

					position_counter -= 1		

			i += 1			
	else:
		pass	

	#Stress DataFrame
	stress_df = pd.DataFrame(data = stress_state, 
					columns = ['Ply','Angle','e_1','e_2','e_3',
									'e_x','e_y','e_z',
									'Sigma_x (GPa)','Sigma_y (GPa)','Sigma_z (GPa)'
							]
					)
	pos = [k for i in range(len(stress_df)/2) for k in ['TOP','BOT'] ]

	stress_df['Pos'] = pos
	stress_df.set_index('Pos', inplace = True)

	#Failure R values DataFrame
	failure_df = pd.DataFrame(data = R_fail, 
					columns = ['Ply','Angle','max_FT','max_FC','max_MT',
									'max_MC','max_S','(+)','(-)',
									'hash_FT','hash_FC','hash_MT','hash_MC'
							]
					)

	failure_df['Pos'] = pos
	#failure_df.set_index('Pos', inplace = True)	

	return stress_state, R_fail, stress_df, failure_df