This function converts a strain to a deformation gradient that will
    produce that strain.  Supports three methods:

    Args:
        strain (3x3 array-like): strain matrix
        shape: (string): method for determining deformation, supports
            "upper" produces an upper triangular defo
            "lower" produces a lower triangular defo
            "symmetric" produces a symmetric defo

def convert_strain_to_deformation(strain, shape="upper"):
    """
    This function converts a strain to a deformation gradient that will
    produce that strain.  Supports three methods:

    Args:
        strain (3x3 array-like): strain matrix
        shape: (string): method for determining deformation, supports
            "upper" produces an upper triangular defo
            "lower" produces a lower triangular defo
            "symmetric" produces a symmetric defo
    """
    strain = SquareTensor(strain)
    ftdotf = 2*strain + np.eye(3)
    if shape == "upper":
        result = scipy.linalg.cholesky(ftdotf)
    elif shape == "symmetric":
        result = scipy.linalg.sqrtm(ftdotf)
    else:
        raise ValueError("shape must be \"upper\" or \"symmetric\"")
    return Deformation(result)