import json
import sys
import numpy
from importlib.metadata import version

from material.orthotropic import Orthotropic
from ply.ply import Ply
from laminate.laminate import Laminate
from panel.panel import Panel
from loads.loads import Loads
from lamfail.lamfail import Lamfail
numpy.set_printoptions(threshold=sys.maxsize)
__version__ = version("3pc-lamfail")

class LamfailIO(object):

    def __init__(self, materialFile=None, plyFile=None, laminateFile=None,
    panelFile=None, loadsFile=None, outputFile=None, analysisType=None,
    failureTheory=None):
        """Initializes LamfailIO instance

        Parameters
        ----------

        materialFile : str

            Full path filename of material json file.

        plyfile : str

            Full path filename of ply json file.

        laminateFile : str

            Full path filename of laminate json file.

        panelFile : str

            Full path filename of panel json file.

        loadsFile : str

            Full path filename of loads json file.

        outputFile : str

            Full path filename of output file.

        analysisType : str

            Analysis type - MECHANICAL, THERMO-MECHANICAL, 
            HYGRO-MECHANICAL, HYGRO-THERMO-MECHANICAL

        failureTheory : str

            Failure analysis - NO FAILURE ANALYSIS,
            MAX STRESS, MAX STRAIN, TSAI-HILL, TSAI-WU
       
        """

        self.materialFile = materialFile
        self.plyFile = plyFile
        self.laminateFile = laminateFile
        self.panelFile = panelFile
        self.loadsFile = loadsFile
        self.outputFile = outputFile
        self.analysisType = analysisType
        self.failureTheory = failureTheory

        self._invalidate()

    def _invalidate(self):
        self._materials = {}
        self._plies = {}
        self._laminates = {}
        self._panels = {}
        self._loads = {}
        self._results = []
        self._pairs = []
        self._unpairs = []

    @property
    def materials(self):
        """Returns dictionary of materials read from input file. The key 
        in the dictionary is the material id.

        Returns
        -------

        materialDict : dict

            {Material.matID : Material}
        
        """

        if not self._materials:
            with open(self.materialFile, 'r') as fh:
                jsonData = json.load(fh)
            for materialDict in jsonData["materials"]:
                matID = materialDict["matID"]
                E1 = materialDict["E1"]
                E2 = materialDict["E2"]
                G12 = materialDict["G12"]
                G13 = materialDict["G13"]
                G23 = materialDict["G23"]
                v12 = materialDict["v12"]
                alpha1 = materialDict["alpha1"]
                alpha2 = materialDict["alpha2"]
                beta1 = materialDict["beta1"]
                beta2 = materialDict["beta2"]
                eps11_tension_allowable = materialDict["eps11_tension_allowable"]
                eps11_compression_allowable = materialDict["eps11_compression_allowable"]
                eps22_tension_allowable = materialDict["eps22_tension_allowable"]
                eps22_compression_allowable = materialDict["eps22_compression_allowable"]
                gamma12_allowable = materialDict["gamma12_allowable"]
                sig11_tension_allowable = materialDict["sig11_tension_allowable"]
                sig11_compression_allowable = materialDict["sig11_compression_allowable"]
                sig22_tension_allowable = materialDict["sig22_tension_allowable"]
                sig22_compression_allowable = materialDict["sig22_compression_allowable"]
                tau12_allowable = materialDict["tau12_allowable"]
                self._materials[matID] = Orthotropic(matID=matID, E1=E1, E2=E2, 
                G12=G12, G13=G13, G23=G23, v12=v12, alpha1=alpha1,
                alpha2=alpha2, beta1=beta1, beta2=beta2,
                eps11_tension_allowable=eps11_tension_allowable,
                eps11_compression_allowable=eps11_compression_allowable,
                eps22_tension_allowable=eps22_tension_allowable,
                eps22_compression_allowable=eps22_compression_allowable,
                gamma12_allowable=gamma12_allowable,
                sig11_tension_allowable=sig11_tension_allowable,
                sig11_compression_allowable=sig11_compression_allowable,
                sig22_tension_allowable=sig22_tension_allowable,
                sig22_compression_allowable=sig22_compression_allowable,
                tau12_allowable=tau12_allowable)
        return self._materials

    @property
    def plies(self):
        """Returns dictionary of plies read from input file. The key 
        in the dictionary is the ply id.

        Returns
        -------

        plyDict : dict

            {Ply.plyID : Ply, ...}
        
        """

        if not self._plies:
            with open(self.plyFile, 'r') as fh:
                jsonData = json.load(fh)
            for plyDict in jsonData["plies"]:
                plyID = plyDict["plyID"]
                angle = plyDict["angle"]
                material = self.materials[plyDict["material"]]
                thickness = plyDict["thickness"]
                self._plies[plyID] = Ply(plyID=plyID, angle=angle, 
                material=material, thickness=thickness)
        return self._plies
    
    @property
    def laminates(self):
        """Returns dictionary of laminates read from input file. The key 
        in the dictionary is the laminate id.

        Returns
        -------

        laminateDict : dict

            {Laminate.lamID : Laminate, ...}
        
        """
        if not self._laminates:
            with open(self.laminateFile, 'r') as fh:
                jsonData = json.load(fh)
            for laminateDict in jsonData["laminates"]:
                lamID = laminateDict["lamID"]
                stacking_sequence = [self.plies[str(plyID)] for plyID in 
                laminateDict["stacking_sequence"]]
                offset = laminateDict["offset"]
                self._laminates[lamID] = Laminate(lamID=lamID, 
                stacking_sequence=stacking_sequence, offset=offset)
        return self._laminates

    @property
    def panels(self):
        """Returns dictionary of panels read from input file. The key 
        in the dictionary is the panel id.

        Returns
        -------

        panelDict : dict

            {Panel.panelID : Panel, ...}
        
        """
        if not self._panels:
            with open(self.panelFile, 'r') as fh:
                jsonData = json.load(fh)
            for panelDict in jsonData["panels"]:
                panelID = panelDict["panelID"]
                length = panelDict["length"]
                width = panelDict["width"]
                laminate = self.laminates[panelDict["laminate"]]
                boundary_condition = panelDict["boundary_condition"]
                self._panels[panelID] = Panel(panelID=panelID, length=length, width=width,
                laminate=laminate, boundary_condition=boundary_condition)
                self._panels[panelID].number_of_terms = 2

        return self._panels

    @property
    def loads(self):
        """Returns dictionary of loads read from input file. The key
        in the dictionary is the loadscase or loads id
        
        Returns
        -------
        
        loadsDict : dict

            {Loads.loadsID_Panel.panelID : Loads, ...}
            
        """

        if not self._loads:
            with open(self.loadsFile, 'r') as fh:
                jsonData = json.load(fh)
                for loadsDict in jsonData["loads"]:
                    loadsID = loadsDict["loadsID"]
                    panelID = loadsDict["panelID"]
                    Nxx = loadsDict["Nxx"]
                    Nyy = loadsDict["Nyy"]
                    Nxy = loadsDict["Nxy"]
                    Mxx = loadsDict["Mxx"]
                    Myy = loadsDict["Myy"]
                    Mxy = loadsDict["Mxy"]
                    Qyz = loadsDict["Qyz"]
                    Qxz = loadsDict["Qxz"]
                    deltaT = loadsDict["deltaT"]
                    deltaC = loadsDict["deltaC"]
                    self._loads[loadsID+"_"+panelID] = Loads(loadsID=loadsID, panelID=panelID,
                    Nxx=Nxx, Nyy=Nyy, Nxy=Nxy, Mxx=Mxx, Myy=Myy, Mxy=Mxy,
                    Qyz=Qyz, Qxz=Qxz, deltaT=deltaT, deltaC=deltaC)
        
        return self._loads

    @property
    def pairs(self):
        """Returns a list of analysis pairs of (Panel, Loads).
        
        Returns
        -------
        
        pairs : list
            [(Panel, Loads), ...]
            
        """

        if not self._pairs:
            for k, lds in self.loads.items():
                pnl = self.panels[lds.panelID]
                self._pairs.append((pnl, lds))
        
        return self._pairs

    @property
    def results(self):
        """Returns a list of Lamfail for each pair of (panel, loads)
        
        Returns
        -------

        lamfailList : list
            [Lamfail, ...]

        """
        if not self._results:
            for pnl, lds in self.pairs:
                lmf = Lamfail(panel=pnl, loads=lds)
                self._results.append(lmf)
        return self._results

    def _writeResults(self):
        """Writes output in outputfile"""

        outputData = "3pc-lamfail "+__version__+"\n\n"
        for lmf in self.results:
            postedMat = []
            postedMatTH = []
            postedMatA = []
            outputData +=  "LOADS ID  PANEL ID  \n"
            outputData += "{:<10s}".format(lmf.loads.loadsID)
            outputData += "{:<10s}\n\n".format(lmf.panel.panelID)

            outputData += "{:^87s}\n".format("MATERIAL PROPERTIES")
            outputData += "ID            E1            E2            G12           G23           G13           v12           \n"
            for ply in lmf.panel.laminate.stacking_sequence:
                if ply.material.matID in postedMat:
                    continue
                postedMat.append(ply.material.matID)
                if len(ply.material.matID) <= 13:
                    outputData += "{:<14s}".format(ply.material.matID)
                else:
                    outputData += "{:<14s}".format(ply.material.matID[0:12])
                outputData += "{:<14.6e}".format(ply.material.E1)
                outputData += "{:<14.6e}".format(ply.material.E2)
                outputData += "{:<14.6e}".format(ply.material.G12)
                outputData += "{:<14.6e}".format(ply.material.G23)
                outputData += "{:<14.6e}".format(ply.material.G13)
                outputData += "{:<14.6e}\n".format(ply.material.v12)
            outputData += "\n"

            if self.analysisType == "HYGRO-THERMO-MECHANICAL":
                outputData += "{:^61s}\n".format("HYGROTHERMAL MATERIAL PROPERTIES")
                outputData += "ID            alpha1        alpha2        beta1         beta2         \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatTH:
                        continue
                    postedMatTH.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<14.6e}".format(ply.material.alpha1)
                    outputData += "{:<14.6e}".format(ply.material.alpha2)
                    outputData += "{:<14.6e}".format(ply.material.beta1)
                    outputData += "{:<14.6e}\n".format(ply.material.beta2)
                outputData += "\n"
            elif self.analysisType == "THERMO-MECHANICAL":
                outputData += "{:^34s}\n".format("THERMAL MATERIAL PROPERTIES")
                outputData += "ID            alpha1        alpha2        \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatTH:
                        continue
                    postedMatTH.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<14.6e}".format(ply.material.alpha1)
                    outputData += "{:<14.6e}\n".format(ply.material.alpha2)
                outputData += "\n"
            elif self.analysisType == "HYGRO-MECHANICAL":
                outputData += "{:^33s}\n".format("HYGRAL MATERIAL PROPERTIES")
                outputData += "ID            beta1         beta2         \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatTH:
                        continue
                    postedMatTH.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<14.6e}".format(ply.material.beta1)
                    outputData += "{:<14.6e}\n".format(ply.material.beta2)
                outputData += "\n"

            if self.failureTheory == "MAX STRESS":
                outputData += "{:^75s}\n".format("MATERIAL ALLOWABLES")
                outputData += "ID            SIG11T        SIG11C        SIG22T        SIG22C        TAU12         \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatA:
                        continue
                    postedMatA.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<+14.6e}".format(ply.material.sig11_tension_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig11_compression_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig22_tension_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig22_compression_allowable)
                    outputData += "{:<+14.6e}\n".format(ply.material.tau12_allowable)
                outputData += "\n"
            elif self.failureTheory == "MAX STRAIN":
                outputData += "{:^77s}\n".format("MATERIAL ALLOWABLES")
                outputData += "ID            EPS11T        EPS11C        EPS22T        EPS22C        GAMMA12       \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatA:
                        continue
                    postedMatA.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<+14.4e}".format(ply.material.eps11_tension_allowable)
                    outputData += "{:<+14.4e}".format(ply.material.eps11_compression_allowable)
                    outputData += "{:<+14.4e}".format(ply.material.eps22_tension_allowable)
                    outputData += "{:<+14.4e}".format(ply.material.eps22_compression_allowable)
                    outputData += "{:<+14.4e}\n".format(ply.material.gamma12_allowable)
                outputData += "\n"
            elif self.failureTheory == "TSAI-HILL":
                outputData += "{:^47s}\n".format("MATERIAL ALLOWABLES")
                outputData += "ID            SIG11T        SIG22T        TAU12         \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatA:
                        continue
                    postedMatA.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<+14.6e}".format(ply.material.sig11_tension_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig22_tension_allowable)
                    outputData += "{:<+14.6e}\n".format(ply.material.tau12_allowable)
                outputData += "\n"
            elif self.failureTheory == "TSAI-WU":
                outputData += "{:^75s}\n".format("MATERIAL ALLOWABLES")
                outputData += "ID            SIG11T        SIG11C        SIG22T        SIG22C        TAU12         \n"
                for ply in lmf.panel.laminate.stacking_sequence:
                    if ply.material.matID in postedMatA:
                        continue
                    postedMatA.append(ply.material.matID)
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}".format(ply.material.matID[0:12])
                    outputData += "{:<+14.6e}".format(ply.material.sig11_tension_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig11_compression_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig22_tension_allowable)
                    outputData += "{:<+14.6e}".format(ply.material.sig22_compression_allowable)
                    outputData += "{:<+14.6e}\n".format(ply.material.tau12_allowable)
                outputData += "\n"
            else:
                pass

            outputData += "{:^28s}\n".format("LAMINATE GEOMETRY")
            outputData += "STACKING SEQUENCE (PLY ANG): ["
            for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                if i < len(lmf.panel.laminate.stacking_sequence):
                    outputData += "{:<+14.1f}, ".format(ply.angle)
                else:
                    outputData += "{:<+14.1f}]\n".format(ply.angle)
            
            outputData += "STACKING SEQUENCE (PLY MAT): ["
            for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                if i < len(lmf.panel.laminate.stacking_sequence):
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}, ".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}, ".format(ply.material.matID[0:12])
                else:
                    if len(ply.material.matID) <= 13:
                        outputData += "{:<14s}]\n".format(ply.material.matID)
                    else:
                        outputData += "{:<14s}]\n".format(ply.material.matID[0:12])

            outputData += "TOTAL THICKNESS: {:<14.6e}\n".format(lmf.panel.laminate.thickness)
            outputData += "OFFSET: {:<14.6e}\n".format(lmf.panel.laminate.offset)
            outputData += "\n"

            outputData += "{:^42s}\n".format("LAMINATE PROPERTIES")
            outputData += "{:^42s}\n".format("A MATRIX")
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.A[0,0], 
            lmf.panel.laminate.A[0,1], lmf.panel.laminate.A[0,2])
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.A[1,0], 
            lmf.panel.laminate.A[1,1], lmf.panel.laminate.A[1,2])
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.A[2,0], 
            lmf.panel.laminate.A[2,1], lmf.panel.laminate.A[2,2])

            outputData += "{:^42s}\n".format("A MATRIX - TRANSVERSE SHEAR")
            outputData += "{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.A44, 
            lmf.panel.laminate.A45)
            outputData += "{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.A45, 
            lmf.panel.laminate.A55)

            outputData += "{:^42s}\n".format("B MATRIX")
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.B[0,0], lmf.panel.laminate.B[0,1], 
            lmf.panel.laminate.B[0,2])
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.B[1,0], lmf.panel.laminate.B[1,1], 
            lmf.panel.laminate.B[1,2])
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.B[2,0], lmf.panel.laminate.B[2,1], 
            lmf.panel.laminate.B[2,2])

            if lmf.panel.laminate.offsetKey.upper() != "MIDDLE":
                outputData += "{:^42s}\n".format("B MATRIX - NO OFFSET")
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.Bmid[0,0], lmf.panel.laminate.Bmid[0,1], 
                lmf.panel.laminate.Bmid[0,2])
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.Bmid[1,0], lmf.panel.laminate.Bmid[1,1], 
                lmf.panel.laminate.Bmid[1,2])
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.Bmid[2,0], lmf.panel.laminate.Bmid[2,1], 
                lmf.panel.laminate.Bmid[2,2])

            outputData += "{:^42s}\n".format("D MATRIX")
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.D[0,0], lmf.panel.laminate.D[0,1], 
            lmf.panel.laminate.D[0,2])
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.D[1,0], lmf.panel.laminate.D[1,1], 
            lmf.panel.laminate.D[1,2])
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.D[2,0], lmf.panel.laminate.D[2,1], 
            lmf.panel.laminate.D[2,2])

            if lmf.panel.laminate.offsetKey.upper() != "MIDDLE":
                outputData += "{:^42s}\n".format("D MATRIX - NO OFFSET")
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.Dmid[0,0], lmf.panel.laminate.Dmid[0,1], 
                lmf.panel.laminate.Dmid[0,2])
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n".format(lmf.panel.laminate.Dmid[1,0], lmf.panel.laminate.Dmid[1,1], 
                lmf.panel.laminate.Dmid[1,2])
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.Dmid[2,0], lmf.panel.laminate.Dmid[2,1], 
                lmf.panel.laminate.Dmid[2,2])

            outputData += "{:^130s}\n".format("EFFECTIVE LAMINATE INPLANE AND FLEXURAL ENGINEERING CONSTANTS")
            outputData += "Ex            Ey            Gxy           vxy           vyx           "
            outputData += "Efx           Efy           Gfxy          vfxy          vfyx          \n"
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.Ex,
            lmf.panel.laminate.Ey, lmf.panel.laminate.Gxy, lmf.panel.laminate.vxy, lmf.panel.laminate.vyx,
            lmf.panel.laminate.Efx, lmf.panel.laminate.Efy, lmf.panel.laminate.Gfxy, lmf.panel.laminate.vfxy,
            lmf.panel.laminate.vfyx)

            if self.analysisType == "HYGRO-THERMO-MECHANICAL":
                outputData += "{:^76s}\n".format("EFFECTIVE LAMINATE HYGROTHERMAL ENGINEERING CONSTANTS")
                outputData += "alphax        alphay        alphaxy       betax         betay         betaxy        \n"
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.alphax, 
                lmf.panel.laminate.alphay, lmf.panel.laminate.alphaxy, lmf.panel.laminate.betax, lmf.panel.laminate.betay, lmf.panel.laminate.betaxy)
            elif self.analysisType == "THERMO-MECHANICAL":
                outputData += "{:<s}\n".format("EFFECTIVE LAMINATE THERMAL ENGINEERING CONSTANTS")
                outputData += "alphax        alphay        alphaxy       \n"
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.alphax, 
                lmf.panel.laminate.alphay, lmf.panel.laminate.alphaxy)
            elif self.analysisType == "HYGRO-MECHANICAL":
                outputData += "{:<s}\n".format("EFFECTIVE LAMINATE HYGRAL ENGINEERING CONSTANTS")
                outputData += "betax         betay         betaxy        \n"
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.panel.laminate.betax, lmf.panel.laminate.betay, lmf.panel.laminate.betaxy)

            outputData += "{:^101s}\n".format("MECHANICAL LOADS AND MOMENTS")
            outputData += "NX            NY            NXY           MX            MY            MXY           QXZ           QYZ           \n"
            outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.loads.Nxx, lmf.loads.Nyy,
            lmf.loads.Nxy, lmf.loads.Mxx, lmf.loads.Myy, lmf.loads.Mxy, lmf.loads.Qxz, lmf.loads.Qyz)

            if self.analysisType == "HYGRO-THERMO-MECHANICAL" or self.analysisType == "THERMO-MECHANICAL":
                outputData += "{:^88s}\n".format("THERMAL LOADS AND MOMENTS")
                outputData += "DELTAT        NXT           NYT           NXYT          MXT           MYT           MXYT          \n"
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.loads.deltaT, lmf.NT[0], lmf.NT[1],
                lmf.NT[2], lmf.MT[0], lmf.MT[1], lmf.MT[2])

            if self.analysisType == "HYGRO-THERMO-MECHANICAL" or self.analysisType == "HYGRO-MECHANICAL":
                outputData += "{:^88s}\n".format("HYGRAL LOADS AND MOMENTS")
                outputData += "DELTAC        NXH           NYH           NXYH          MXH           MYH           MXYH          \n"
                outputData += "{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}{:<+14.6e}\n\n".format(lmf.loads.deltaC, lmf.NC[0], lmf.NC[1],
                lmf.NC[2], lmf.MC[0], lmf.MC[1], lmf.MC[2])

            outputData += "{:^106s}\n".format("LAMINATE REFERENCE PLANE STRAINS AND CURVATURES")
            outputData += "EPSX0         EPSY0         GAMMAXY0      KAPPAX0       KAPPAY0       KAPPAXY0      GAMMAYZ0      GAMMAXZ0      \n"
            outputData += "(x 1E-6)      (x 1E-6)      (x 1E-6)      (x 1E-6)      (x 1E-6)      (x 1E-6)      (x 1E-6)      (x 1E-6)      \n"
            outputData += "{:<+14.6e}".format(lmf.ek0[0]*1E6)
            outputData += "{:<+14.6e}".format(lmf.ek0[1]*1E6)
            outputData += "{:<+14.6e}".format(lmf.ek0[2]*1E6)
            outputData += "{:<+14.6e}".format(lmf.ek0[3]*1E6)
            outputData += "{:<+14.6e}".format(lmf.ek0[4]*1E6)
            outputData += "{:<+14.6e}".format(lmf.ek0[5]*1E6)
            outputData += "{:<+14.6e}".format(lmf.gT0[0]*1E6)
            outputData += "{:<+14.6e}\n\n".format(lmf.gT0[1]*1E6)

            outputData += "{:^102s}".format("PLY BY PLY INPLANE STRAINS (TOTAL)")
            if self.failureTheory == "MAX STRAIN":
                outputData += "{:^40s}\n".format("FAILURE ANALYSIS - MAX STRAIN")
            else:
                outputData += "\n"
            outputData += "ANGLE         Z             EPS1          EPS2          GAMMA12       "
            outputData += "EPSX          EPSY          GAMMAXY       "
            if self.failureTheory == "MAX STRAIN":
                outputData += "MS1           MS2           MS12          \n"
            else:
                outputData += "\n"
            outputData += "                            (x 1E-6)      (x 1E-6)      (x 1E-6)      "
            outputData += "(x 1E-6)      (x 1E-6)      (x 1E-6)      \n"
            for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                outputData += "{:<+14.1f}".format(ply.angle)
                outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i-1])

                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["bottom"][0]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["bottom"][1]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["bottom"][2]*1E6)

                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["bottom"][0]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["bottom"][1]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["bottom"][2]*1E6)

                if self.failureTheory == "MAX STRAIN":
                    val = lmf.strain1MS[str(i)]["bottom"][0]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.strain1MS[str(i)]["bottom"][1]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.strain1MS[str(i)]["bottom"][2]
                    if isinstance(val, str):
                        outputData += "{:<14s}\n".format(val)
                    else:
                        outputData += "{:<+14.6e}\n".format(val)
                else:
                    outputData += "\n"

                outputData += "              "

                outputData += "{:<+14.6e}".format((lmf.panel.laminate.z[i-1]+lmf.panel.laminate.z[i])/2.0)

                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["mid"][0]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["mid"][1]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["mid"][2]*1E6)

                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["mid"][0]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["mid"][1]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["mid"][2]*1E6)

                if self.failureTheory == "MAX STRAIN":
                    val = lmf.strain1MS[str(i)]["mid"][0]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.strain1MS[str(i)]["mid"][1]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.strain1MS[str(i)]["mid"][2]
                    if isinstance(val, str):
                        outputData += "{:<14s}\n".format(val)
                    else:
                        outputData += "{:<+14.6e}\n".format(val)
                else:
                    outputData += "\n"

                outputData += "              "

                outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i])

                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["top"][0]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["top"][1]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["top"][2]*1E6)

                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["top"][0]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["top"][1]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["top"][2]*1E6)

                if self.failureTheory == "MAX STRAIN":
                    val = lmf.strain1MS[str(i)]["top"][0]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.strain1MS[str(i)]["top"][1]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.strain1MS[str(i)]["top"][2]
                    if isinstance(val, str):
                        outputData += "{:<14s}\n".format(val)
                    else:
                        outputData += "{:<+14.6e}\n".format(val)
                else:
                    outputData += "\n"

            outputData += "\n"
            
            if self.analysisType == "HYGRO-THERMO-MECHANICAL" or self.analysisType == "HYGRO-MECHANICAL" or self.analysisType == "THERMO-MECHANICAL":
                outputData += "{:^102s}".format("PLY BY PLY INPLANE STRAINS (MECHANICAL OR RESIDUAL)")
                if self.failureTheory == "MAX STRAIN":
                    outputData += "{:^40s}\n".format("FAILURE ANALYSIS - MAX STRAIN")
                else:
                    outputData += "\n"
                outputData += "ANGLE         Z             EPS1          EPS2          GAMMA12       "
                outputData += "EPSX          EPSY          GAMMAXY       "
                if self.failureTheory == "MAX STRAIN":
                    outputData += "MS1           MS2           MS12          \n"
                else:
                    outputData += "\n"
                outputData += "                            (x 1E-6)      (x 1E-6)      (x 1E-6)      "
                outputData += "(x 1E-6)      (x 1E-6)      (x 1E-6)      \n"
                for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                    outputData += "{:<+14.1f}".format(ply.angle)
                    outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i-1])
    
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["bottom"][0]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["bottom"][1]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["bottom"][2]*1E6)
    
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["bottom"][0]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["bottom"][1]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["bottom"][2]*1E6)
    
                    if self.failureTheory == "MAX STRAIN":
                        val = lmf.strainM1MS[str(i)]["bottom"][0]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.strainM1MS[str(i)]["bottom"][1]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.strainM1MS[str(i)]["bottom"][2]
                        if isinstance(val, str):
                            outputData += "{:<14s}\n".format(val)
                        else:
                            outputData += "{:<+14.6e}\n".format(val)
                    else:
                        outputData += "\n"
    
                    outputData += "              "
    
                    outputData += "{:<+14.6e}".format((lmf.panel.laminate.z[i-1]+lmf.panel.laminate.z[i])/2.0)
    
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["mid"][0]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["mid"][1]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["mid"][2]*1E6)
    
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["mid"][0]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["mid"][1]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["mid"][2]*1E6)
    
                    if self.failureTheory == "MAX STRAIN":
                        val = lmf.strainM1MS[str(i)]["mid"][0]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.strainM1MS[str(i)]["mid"][1]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.strainM1MS[str(i)]["mid"][2]
                        if isinstance(val, str):
                            outputData += "{:<14s}\n".format(val)
                        else:
                            outputData += "{:<+14.6e}\n".format(val)
                    else:
                        outputData += "\n"
    
                    outputData += "              "
    
                    outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i])
    
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["top"][0]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["top"][1]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM1[str(i)]["top"][2]*1E6)
    
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["top"][0]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["top"][1]*1E6)
                    outputData += "{:<+14.6e}".format(lmf.strainM[str(i)]["top"][2]*1E6)
    
                    if self.failureTheory == "MAX STRAIN":
                        val = lmf.strainM1MS[str(i)]["top"][0]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.strainM1MS[str(i)]["top"][1]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.strainM1MS[str(i)]["top"][2]
                        if isinstance(val, str):
                            outputData += "{:<14s}\n".format(val)
                        else:
                            outputData += "{:<+14.6e}\n".format(val)
                    else:
                        outputData += "\n"
    
                outputData += "\n"
                
            outputData += "{:^73s}\n".format("PLY BY PLY TRANSVERSE SHEAR STRAINS")
            outputData += "ANGLE         Z             GAMMA23       GAMMA13       "
            outputData += "GAMMAYZ       GAMMAXZ       \n"
            outputData += "                            (x 1E-6)      (x 1E-6)      "
            outputData += "(x 1E-6)      (x 1E-6)      \n"
            for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                outputData += "{:<+14.1f}".format(ply.angle)
                outputData += "{:<+14.6e}".format(lmf.panel.laminate.zmid[i-1])

                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["bottom"][3]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["bottom"][4]*1E6)

                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["bottom"][3]*1E6)
                outputData += "{:<+14.6e}\n".format(lmf.strain[str(i)]["bottom"][4]*1E6)

                outputData += "              "

                outputData += "{:<+14.6e}".format((lmf.panel.laminate.zmid[i-1]+lmf.panel.laminate.zmid[i])/2.0)

                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["mid"][3]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["mid"][4]*1E6)

                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["mid"][3]*1E6)
                outputData += "{:<+14.6e}\n".format(lmf.strain[str(i)]["mid"][4]*1E6)

                outputData += "              "

                outputData += "{:<+14.6e}".format(lmf.panel.laminate.zmid[i])

                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["top"][3]*1E6)
                outputData += "{:<+14.6e}".format(lmf.strain1[str(i)]["top"][4]*1E6)

                outputData += "{:<+14.6e}".format(lmf.strain[str(i)]["top"][3]*1E6)
                outputData += "{:<+14.6e}\n".format(lmf.strain[str(i)]["top"][4]*1E6)
            outputData += "\n"
                
            outputData += "{:^99s}".format("PLY BY PLY INPLANE STRESSES (TOTAL)")
            if self.failureTheory == "MAX STRESS":
                outputData += "{:^40s}\n".format("FAILURE ANALYSIS - MAX STRESS")
            elif self.failureTheory == "TSAI-WU":
                outputData += "{:^30s}\n".format("FAILURE ANALYSIS - TSAI-WU")
            elif self.failureTheory == "TSAI-HILL":
                outputData += "{:^30s}\n".format("FAILURE ANALYSIS - TSAI-HILL")
            else:
                outputData += "\n"
            outputData += "ANGLE         Z             SIG1          SIG2          TAU12         "
            outputData += "SIGX          SIGY          TAUXY         "
            if self.failureTheory == "MAX STRESS":
                outputData += "MS1           MS2           MS12          \n"
            elif self.failureTheory == "TSAI-WU":
                outputData += "FI            MS            \n"
            elif self.failureTheory == "TSAI-HILL":
                outputData += "FI            MS            \n"
            else:
                outputData += "\n"
            for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                outputData += "{:<+14.1f}".format(ply.angle)
                outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i-1])

                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["bottom"][0])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["bottom"][1])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["bottom"][2])

                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["bottom"][0])
                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["bottom"][1])
                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["bottom"][2])

                if self.failureTheory == "MAX STRESS":
                    val = lmf.stress1MS[str(i)]["bottom"][0]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.stress1MS[str(i)]["bottom"][1]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.stress1MS[str(i)]["bottom"][2]
                    if isinstance(val, str):
                        outputData += "{:<14s}\n".format(val)
                    else:
                        outputData += "{:<+14.6e}\n".format(val)
                elif self.failureTheory == "TSAI-WU":
                    val = lmf.tsaiWu1MS[str(i)]["bottom"]
                    for data in val:
                        if isinstance(data, str):
                            outputData += "{:<14s}".format(data)
                        else:
                            outputData += "{:<+14.6e}".format(data)
                    outputData += "\n"
                elif self.failureTheory == "TSAI-HILL":
                    val = lmf.tsaiHill1MS[str(i)]["bottom"]
                    for data in val:
                        if isinstance(data, str):
                            outputData += "{:<14s}".format(data)
                        else:
                            outputData += "{:<+14.6e}".format(data)
                    outputData += "\n"
                else:
                    outputData += "\n"

                outputData += "              "

                outputData += "{:<+14.6e}".format((lmf.panel.laminate.z[i-1]+lmf.panel.laminate.z[i])/2.0)

                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["mid"][0])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["mid"][1])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["mid"][2])

                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["mid"][0])
                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["mid"][1])
                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["mid"][2])

                if self.failureTheory == "MAX STRESS":
                    val = lmf.stress1MS[str(i)]["mid"][0]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.stress1MS[str(i)]["mid"][1]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.stress1MS[str(i)]["mid"][2]
                    if isinstance(val, str):
                        outputData += "{:<14s}\n".format(val)
                    else:
                        outputData += "{:<+14.6e}\n".format(val)
                elif self.failureTheory == "TSAI-WU":
                    val = lmf.tsaiWu1MS[str(i)]["mid"]
                    for data in val:
                        if isinstance(data, str):
                            outputData += "{:<14s}".format(data)
                        else:
                            outputData += "{:<+14.6e}".format(data)
                    outputData += "\n"
                elif self.failureTheory == "TSAI-HILL":
                    val = lmf.tsaiHill1MS[str(i)]["mid"]
                    for data in val:
                        if isinstance(data, str):
                            outputData += "{:<14s}".format(data)
                        else:
                            outputData += "{:<+14.6e}".format(data)
                    outputData += "\n"
                else:
                    outputData += "\n"

                outputData += "              "

                outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i])

                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["top"][0])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["top"][1])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["top"][2])

                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["top"][0])
                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["top"][1])
                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["top"][2])

                if self.failureTheory == "MAX STRESS":
                    val = lmf.stress1MS[str(i)]["top"][0]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.stress1MS[str(i)]["top"][1]
                    if isinstance(val, str):
                        outputData += "{:<14s}".format(val)
                    else:
                        outputData += "{:<+14.6e}".format(val)
                    val = lmf.stress1MS[str(i)]["top"][2]
                    if isinstance(val, str):
                        outputData += "{:<14s}\n".format(val)
                    else:
                        outputData += "{:<+14.6e}\n".format(val)
                elif self.failureTheory == "TSAI-WU":
                    val = lmf.tsaiWu1MS[str(i)]["top"]
                    for data in val:
                        if isinstance(data, str):
                            outputData += "{:<14s}".format(data)
                        else:
                            outputData += "{:<+14.6e}".format(data)
                    outputData += "\n"
                elif self.failureTheory == "TSAI-HILL":
                    val = lmf.tsaiHill1MS[str(i)]["top"]
                    for data in val:
                        if isinstance(data, str):
                            outputData += "{:<14s}".format(data)
                        else:
                            outputData += "{:<+14.6e}".format(data)
                    outputData += "\n"
                else:
                    outputData += "\n"

            outputData += "\n"

            if self.analysisType == "HYGRO-THERMO-MECHANICAL" or self.analysisType == "THERMO-MECHANICAL" or self.analysisType == "HYGRO-MECHANICAL":
                outputData += "{:^99s}".format("PLY BY PLY INPLANE STRESSES (MECHANICAL OR RESIDUAL)")
                if self.failureTheory == "MAX STRESS":
                    outputData += "{:^42s}\n".format("FAILURE ANALYSIS - MAX STRESS")
                elif self.failureTheory == "TSAI-WU":
                    outputData += "{:^30s}\n".format("FAILURE ANALYSIS - TSAI-WU")
                elif self.failureTheory == "TSAI-HILL":
                    outputData += "{:^30s}\n".format("FAILURE ANALYSIS - TSAI-HILL")
                else:
                    outputData += "\n"
                outputData += "ANGLE         Z             SIG1          SIG2          TAU12         "
                outputData += "SIGX          SIGY          TAUXY         "
                if self.failureTheory == "MAX STRESS":
                    outputData += "MS1           MS2           MS12          \n"
                elif self.failureTheory == "TSAI-WU":
                    outputData += "FI            MS            \n"
                elif self.failureTheory == "TSAI-HILL":
                    outputData += "FI            MS            \n"
                else:
                    outputData += "\n"
                for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                    outputData += "{:<+14.1f}".format(ply.angle)
                    outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i-1])

                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["bottom"][0])
                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["bottom"][1])
                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["bottom"][2])

                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["bottom"][0])
                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["bottom"][1])
                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["bottom"][2])

                    if self.failureTheory == "MAX STRESS":
                        val = lmf.stressM1MS[str(i)]["bottom"][0]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.stressM1MS[str(i)]["bottom"][1]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.stressM1MS[str(i)]["bottom"][2]
                        if isinstance(val, str):
                            outputData += "{:<14s}\n".format(val)
                        else:
                            outputData += "{:<+14.6e}\n".format(val)
                    elif self.failureTheory == "TSAI-WU":
                        val = lmf.tsaiWuM1MS[str(i)]["bottom"]
                        for data in val:
                            if isinstance(data, str):
                                outputData += "{:<14s}".format(data)
                            else:
                                outputData += "{:<+14.6e}".format(data)
                        outputData += "\n"
                    elif self.failureTheory == "TSAI-HILL":
                        val = lmf.tsaiHillM1MS[str(i)]["bottom"]
                        for data in val:
                            if isinstance(data, str):
                                outputData += "{:<14s}".format(data)
                            else:
                                outputData += "{:<+14.6e}".format(data)
                        outputData += "\n"
                    else:
                        outputData += "\n"

                    outputData += "              "

                    outputData += "{:<+14.6e}".format((lmf.panel.laminate.z[i-1]+lmf.panel.laminate.z[i])/2.0)

                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["mid"][0])
                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["mid"][1])
                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["mid"][2])

                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["mid"][0])
                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["mid"][1])
                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["mid"][2])

                    if self.failureTheory == "MAX STRESS":
                        val = lmf.stressM1MS[str(i)]["mid"][0]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.stressM1MS[str(i)]["mid"][1]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.stressM1MS[str(i)]["mid"][2]
                        if isinstance(val, str):
                            outputData += "{:<14s}\n".format(val)
                        else:
                            outputData += "{:<+14.6e}\n".format(val)
                    elif self.failureTheory == "TSAI-WU":
                        val = lmf.tsaiWuM1MS[str(i)]["mid"]
                        for data in val:
                            if isinstance(data, str):
                                outputData += "{:<14s}".format(data)
                            else:
                                outputData += "{:<+14.6e}".format(data)
                        outputData += "\n"
                    elif self.failureTheory == "TSAI-HILL":
                        val = lmf.tsaiHillM1MS[str(i)]["mid"]
                        for data in val:
                            if isinstance(data, str):
                                outputData += "{:<14s}".format(data)
                            else:
                                outputData += "{:<+14.6e}".format(data)
                        outputData += "\n"
                    else:
                        outputData += "\n"

                    outputData += "              "

                    outputData += "{:<+14.6e}".format(lmf.panel.laminate.z[i])

                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["top"][0])
                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["top"][1])
                    outputData += "{:<+14.6e}".format(lmf.stressM1[str(i)]["top"][2])

                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["top"][0])
                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["top"][1])
                    outputData += "{:<+14.6e}".format(lmf.stressM[str(i)]["top"][2])

                    if self.failureTheory == "MAX STRESS":
                        val = lmf.stressM1MS[str(i)]["top"][0]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.stressM1MS[str(i)]["top"][1]
                        if isinstance(val, str):
                            outputData += "{:<14s}".format(val)
                        else:
                            outputData += "{:<+14.6e}".format(val)
                        val = lmf.stressM1MS[str(i)]["top"][2]
                        if isinstance(val, str):
                            outputData += "{:<14s}\n".format(val)
                        else:
                            outputData += "{:<+14.6e}\n".format(val)
                    elif self.failureTheory == "TSAI-WU":
                        val = lmf.tsaiWuM1MS[str(i)]["top"]
                        for data in val:
                            if isinstance(data, str):
                                outputData += "{:<14s}".format(data)
                            else:
                                outputData += "{:<+14.6e}".format(data)
                        outputData += "\n"
                    elif self.failureTheory == "TSAI-HILL":
                        val = lmf.tsaiHillM1MS[str(i)]["top"]
                        for data in val:
                            if isinstance(data, str):
                                outputData += "{:<14s}".format(data)
                            else:
                                outputData += "{:<+14.6e}".format(data)
                        outputData += "\n"
                    else:
                        outputData += "\n"

                outputData += "\n"

            outputData += "{:^71s}\n".format("PLY BY PLY TRANSVERSE SHEAR STRESSES")
            outputData += "ANGLE         Z             TAU23         TAU13         "
            outputData += "TAUYZ         TAUXZ         \n"
            for i, ply in enumerate(lmf.panel.laminate.stacking_sequence, start=1):
                outputData += "{:<+14.1f}".format(ply.angle)
                outputData += "{:<+14.6e}".format(lmf.panel.laminate.zmid[i-1])

                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["bottom"][3])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["bottom"][4])

                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["bottom"][3])
                outputData += "{:<+14.6e}\n".format(lmf.stress[str(i)]["bottom"][4])

                outputData += "              "

                outputData += "{:<+14.6e}".format((lmf.panel.laminate.zmid[i-1]+lmf.panel.laminate.zmid[i])/2.0)

                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["mid"][3])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["mid"][4])

                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["mid"][3])
                outputData += "{:<+14.6e}\n".format(lmf.stress[str(i)]["mid"][4])

                outputData += "              "

                outputData += "{:<+14.6e}".format(lmf.panel.laminate.zmid[i])

                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["top"][3])
                outputData += "{:<+14.6e}".format(lmf.stress1[str(i)]["top"][4])

                outputData += "{:<+14.6e}".format(lmf.stress[str(i)]["top"][3])
                outputData += "{:<+14.6e}\n".format(lmf.stress[str(i)]["top"][4])
            outputData += "\n"

        with open(self.outputFile, 'w') as fh:
            fh.write(outputData)