"""
Composite Matlamina Module (:mod:`compmech.composite.matlamina`)
================================================================

.. currentmodule:: compmech.composite.matlamina

"""
import numpy as np

from compmech.constants import DOUBLE
from compmech.logger import *


class MatLamina(object):
    r"""
    Orthotropic material lamina

    ==========  ==========================================================
    attributes  description
    ==========  ==========================================================
    e1          Young Modulus in direction 1
    e2          Young Modulus in direction 2
    g12         in-plane shear modulus
    g13         transverse shear modulus for plane 1-Z
    g23         transverse shear modulus for plane 2-Z
    nu12        Poisson's ratio 12
    nu13        Poisson's ratio 13
    nu23        Poisson's ratio 23
    nu21        Poisson's ratio 21: use formula nu12/e1 = nu21/e2
    nu31        Poisson's ratio 31: use formula nu31/e3 = nu13/e1
    nu32        Poisson's ratio 32: use formula nu23/e2 = nu32/e3
    rho         especific mass (mass / volume)
    a1          thermal expansion coeffiecient in direction 1
    a2          thermal expansion coeffiecient in direction 2
    a3          thermal expansion coeffiecient in direction 3
    tref        reference temperature
    st1,st2     allowable tensile stresses for directions 1 and 2
    sc1,sc2     allowable compressive stresses for directions 1 and 2
    ss12        allowable in-plane stress for shear
    strn        allowable strain for direction 1
    q11         lamina constitutive constant 11
    q12         lamina constitutive constant 12
    q13         lamina constitutive constant 13
    q21         lamina constitutive constant 21
    q22         lamina constitutive constant 22
    q23         lamina constitutive constant 23
    q31         lamina constitutive constant 31
    q32         lamina constitutive constant 32
    q33         lamina constitutive constant 33
    q44         lamina constitutive constant 44
    q55         lamina constitutive constant 55
    q66         lamina constitutive constant 66
    u           matrix with lamina invariants
    c           matrix with lamina stiffness coefficients
    ==========  ==========================================================

    Notes
    -----
    For isotropic materials when the user defines `\nu` and `E`, `G` will be
    recaculated based on equation: `G = E/(2 \times (1+\nu))`; in a lower
    priority if the user defines `\nu` and `G`, `E` will be recaculated based
    on equation: `E = 2 \times (1+\nu) \times G`.

    """
    def __init__(self):
        super(MatLamina, self).__init__()
        self.e1 = None
        self.e2 = None
        self.e3 = 0
        self.g12 = None
        self.g13 = None
        self.g23 = None
        self.nu12 = None
        self.nu13 = 0
        self.nu21 = None
        self.nu23 = 0
        self.nu31 = 0
        self.nu32 = 0
        self.rho = None
        self.a1 = None
        self.a2 = None
        self.a3 = None
        self.st1 = None
        self.st2 = None
        self.sc1 = None
        self.sc2 = None
        self.ss12 = None
        self.strn = None
        self.q11 = None
        self.q12 = None
        self.q13 = None
        self.q21 = None
        self.q22 = None
        self.q23 = None
        self.q31 = None
        self.q32 = None
        self.q33 = None
        self.q44 = None
        self.q55 = None
        self.q66 = None
        self.u = None


    def rebuild(self):
        #
        # from references:
        #   Reddy, J. N., Mechanics of laminated composite plates and shells.
        #   Theory and analysis. Second Edition. CRC Press, 2004.
        e1 = self.e1
        e2 = self.e2
        e3 = self.e3
        nu12 = self.nu12
        nu21 = self.nu21
        nu13 = self.nu13
        nu31 = self.nu31
        nu23 = self.nu23
        nu32 = self.nu32
        delta = (1-nu12*nu21-nu23*nu32-nu31*nu13-2*nu21*nu32*nu13)/(e1*e2)
        c11 = (1    - nu23*nu23)/(delta*e2)
        c12 = (nu21 + nu31*nu23)/(delta*e2)
        c13 = (nu31 + nu21*nu32)/(delta*e2)
        c22 = (1    - nu13*nu31)/(delta*e1)
        c23 = (nu32 + nu12*nu31)/(delta*e1)
        c33 = e3*(1    - nu12*nu21)/(delta*e1*e2)
        c44 = self.g23
        c55 = self.g13
        c66 = self.g12
        self.c = np.array(
            [[c11, c12, c13,   0,   0,   0],
             [c12, c22, c23,   0,   0,   0],
             [c13, c23, c33,   0,   0,   0],
             [  0,   0,   0, c44,   0,   0],
             [  0,   0,   0,   0, c55,   0],
             [  0,   0,   0,   0,   0, c66]], dtype = DOUBLE)

        #
        # from references:
        #   hansen_hvejsen_2007 page 43
        #
        #   Guerdal Z., R. T. Haftka and P. Hajela (1999), Design and
        #   Optimization of Laminated Composite Materials, Wiley-Interscience.
        den = (1 - self.nu12 * self.nu21
                 - self.nu13 * self.nu31
                 - self.nu23 * self.nu32
                 - self.nu12 * self.nu23 * self.nu31
                 - self.nu13 * self.nu21 * self.nu32)
        den = np.array(den, dtype=DOUBLE)
        self.q11 = self.e1*(1         - self.nu23 * self.nu32) / den
        self.q12 = self.e1*(self.nu21 + self.nu23 * self.nu31) / den
        self.q13 = self.e1*(self.nu31 + self.nu21 * self.nu32) / den
        self.q21 = self.e2*(self.nu12 + self.nu13 * self.nu32) / den
        self.q22 = self.e2*(1         - self.nu13 * self.nu31) / den
        self.q23 = self.e2*(self.nu32 + self.nu12 * self.nu31) / den
        self.q31 = self.e3*(self.nu13 + self.nu12 * self.nu32) / den
        self.q32 = self.e3*(self.nu23 + self.nu13 * self.nu21) / den
        self.q33 = self.e3*(1         - self.nu12 * self.nu21) / den
        self.q44 = self.g12
        self.q55 = self.g23
        self.q66 = self.g13
        #
        # from reference:
        #   Jones R. M. (1999), Mechanics of Composite Materials, second edn,
        #   Taylor & Francis, Inc., 325 Chestnut Street, Philadelphia,
        #   PA 19106. ISBN 1-56032-712-X
        # slightly changed to include the transverse shear terms u6 ans
        # u7, taken from ABAQUS Example Problems Manual, vol1,
        # example 1.2.2 Laminated composite shell: buckling of a
        # cylindrical panel with a circular hole
        #
        u1 = (3*self.q11 + 3*self.q22 + 2*self.q12 + 4*self.q44) / 8.
        u2 = (self.q11 - self.q22) / 2.
        u3 = (self.q11 + self.q22 - 2*self.q12 - 4*self.q44) / 8.
        u4 = (self.q11 + self.q22 + 6*self.q12 - 4*self.q44) / 8.
        u5 = (u1-u4) / 2.
        u6 = (self.q55 + self.q66) / 2.
        u7 = (self.q55 - self.q66) / 2.
        self.u = np.array(
            [[u1,  u2,    0,  u3,   0],                # q11
             [u1, -u2,    0,  u3,   0],                # q22
             [u4,   0,    0, -u3,   0],                # q12
             [u6,  u7,    0,   0,   0],                # q55
             [u6, -u7,    0,   0,   0],                # q66
             [ 0,   0,  -u7,   0,   0],                # q56
             [u5,   0,    0, -u3,   0],                # q44
             [ 0,   0, u2/2,   0,  u3],                # q14
             [ 0,   0, u2/2,   0, -u3]], dtype=DOUBLE)  # q24


    def read_inputs(self, inputs={}):
        if len(inputs) > 0:
            self = user_setattr(self, inputs)
        if not self.nu21:
            nu21 = np.array(self.nu12*self.e2/self.e1, dtype=DOUBLE)
            self.nu21 = nu21
        if not self.nu12:
            nu12 = np.array(self.nu21*self.e1/self.e2, dtype=DOUBLE)
            self.nu12 = nu12


def read_laminaprop(laminaprop=None):
    """Returns a ``MatLamina`` object based on an input ``laminaprop`` tuple

    Parameters
    ----------
    laminaprop : list or tuple
        Tuple containing the folliwing entries:

            (e1, e2, nu12, g12, g13, g23, e3, nu13, nu23)

        for othotropic materials the user can only supply:

            (e1, e2, nu12, g12, g13, g23)

        for isotropic materials the user can only supply:

            (e1, e2, nu12)

        ======  ==============================
        symbol  value
        ======  ==============================
        e1      Young Module in direction 1
        e2      Young Module in direction 2
        nu12    12 Poisson's ratio
        g12     12 Shear Modulus
        g13     13 Shear Modulus
        g23     13 Shear Modulus
        e3      Young Module in direction 3
        nu13    13 Poisson's ratio
        nu23    23 Poisson's ratio
        ======  ==============================

    Returns
    -------
    matlam : MatLamina
        A :class:`.MatLamina` object.

    """
    matlam = MatLamina()

    #laminaProp = (e1, e2, nu12, g12, g13, g23, e3, nu13, nu23)
    if laminaprop == None:
        error('laminaprop must be a tuple in the following format:\n\t'
              +'(e1, e2, nu12, g12, g13, g23, e3, nu13, nu23)')
    if len(laminaprop) == 3: #ISOTROPIC
        e = laminaprop[0]
        nu = laminaprop[2]
        g = e/(2*(1+nu))
        laminaprop = (e, e, nu, g, g, g, e, nu, nu)
    nu12 = laminaprop[2]

    if len(laminaprop) < 9:
        e2 = laminaprop[1]
        laminaprop = tuple(list(laminaprop)[:6] + [e2, nu12, nu12])
    matlam.e1 = laminaprop[0]
    matlam.e2 = laminaprop[1]
    matlam.e3 = laminaprop[6]
    matlam.nu12 = laminaprop[2]
    matlam.nu13 = laminaprop[7]
    matlam.nu23 = laminaprop[8]
    matlam.nu21 = matlam.nu12 * matlam.e2 / matlam.e1
    matlam.nu31 = matlam.nu13 * matlam.e3 / matlam.e1
    matlam.nu32 = matlam.nu23 * matlam.e3 / matlam.e2
    matlam.g12 = laminaprop[3]
    matlam.g13 = laminaprop[4]
    matlam.g23 = laminaprop[5]

    matlam.rebuild()

    return matlam

