import math
import numpy as np

class ParameterSet(dict):
    def __init__(self, *args, **kwargs):
        super(ParameterSet, self).__init__(*args, **kwargs)
        self.__dict__ = self

parameterSet = ParameterSet()

""""
    Experiment: Taken from 
                [Bartels]:
                APPROXIMATION OF LARGE BENDING ISOMETRIES WITH
                DISCRETE KIRCHHOFF TRIANGLE
                * Ex. 4.1 (Vertical Load on a square-shaped plate)
"""

#############################################
#  Paths
#############################################
parameterSet.resultPath = '/home/klaus/Desktop/Dune_bendIso/dune-microstructure/outputs_L-clamped-Plate'
parameterSet.baseName= 'L-clamped-Plate'

#############################################
#  Grid parameters
#############################################
nX=8
nY=8

parameterSet.structuredGrid = 'simplex'
parameterSet.lower = '0 0'
parameterSet.upper = '4 4'
parameterSet.elements = str(nX)+' '+  str(nY)

parameterSet.macroGridLevel = 1
#############################################
#  Options
#############################################
parameterSet.measure_analyticalError = False
parameterSet.measure_isometryError = False
parameterSet.vtkWrite_analyticalSurfaceNormal = False
parameterSet.vtkwrite_analyticalSolution = False


parameterSet.conforming_DiscreteJacobian = 0
#############################################
#  Solver parameters
#############################################
# Tolerance of the multigrid solver
parameterSet.tolerance = 1e-12
# Maximum number of multigrid iterations
parameterSet.maxProximalNewtonSteps = 6
# Initial regularization
parameterSet.initialRegularization = 1
# Measure convergence
parameterSet.instrumented = 0

############################
#   Problem specifications
############################
# Dimension of the domain (only used for numerical-test python files)
parameterSet.dim = 2

# # Dimension of the target space
# parameterSet.targetDim = 3
# parameterSet.targetSpace = 'BendingIsometry'
#############################################
#  VTK/Output
#############################################
# Write discrete solution as .vtk-File
parameterSet.writeVTK = 1
parameterSet.vtkwrite_analyticalSolution = 0
parameterSet.vtkWrite_analyticalSurfaceNormal = 0

# The grid can be refined several times for a higher resolution in the VTK-file.
parameterSet.subsamplingRefinement = 2

# Write Dof-Vector to .txt-file
parameterSet.writeDOFvector = 0

#############################################
#  Dirichlet boundary indicator
#############################################
def dirichlet_indicator(x) :
    if( (x[0] <= 0.001) or (x[1]<=0.001)):
        return True
    else:
        return False



# #Test clamp on other side:
# def dirichlet_indicator(x) :
#     if( (x[0] >=3.999) or (x[1]<=0.001)):
#         return True
#     else:
#         return False


#boundary-values/derivative function
def boundaryValues(x):
    return [x[0], x[1], 0]


# def boundaryValuesDerivative(x):
#     return ((1,0,0),
#             (0,1,0),
#             (0,0,1))

#############################################
#  MICROSTRUCTURE
############################################
parameterSet.printMicroOutput = False
parameterSet.VTKwriteMacroPhaseIndicator = False
parameterSet.MacroPhaseSubsamplingRefinement = 3


# essentially have no microstructure at all... 

class GlobalMicrostructure:
    """ Class that represents the global microstructure.
    
        The global microstructure can be defined individually 
        for different (finitely many) macroscopic phases. 
        Each macroscopic phase corresponds to a 'LocalMicrostructure_'
        sub-class that defines the necessary data for the local 
        micro-problem. 

        Currently, there are three possibilities for the LocalMicrostructure:
            (1) Read the effective quantities (Qhom,Beff) from this parset.
            (Constant local microstructure)
            (2) Solve the micro-problem once to obtain the effective quantities. 
            (Constant local microstructure)
            (3) Solve for micro-problem for each macroscopic quadrature point.
            (Macroscopocally varying local microstructure)) 
    """
    def __init__(self,macroPoint=[0,0]):
        self.macroPhases = 1

        # define first local microstructure options.
        self.macroPhase1_constantMicrostructure = True
        self.macroPhase1_readEffectiveQuantities = True;

    def macroPhaseIndicator(self,y): #y :macroscopic point
            """ Indicatorfunction that determines the domains 
                i.e. macro-phases of different local microstructures.
            """
            return 1;
                
    # Represents the local microstructure in Phase 1
    class LocalMicrostructure_1:  
        def __init__(self,macroPoint=[0,0]):
            self.gamma = 1.0    #in the future this might change depending on macroPoint.
            self.phases = 2     #in the future this might change depending on macroPoint.

            self.effectivePrestrain= np.array([[ 0.0,  0.0],
                                               [ 0.0, 0.0]]);

            self.effectiveQuadraticForm = np.array([[1.0, 0.0, 0.0],
                                                    [0.0, 1.0, 0.0],
                                                    [0.0, 0.0, 1.0]]);


#############################################
#  Initial iterate function
#############################################
def f(x):
    return [x[0], x[1], 0]


def df(x):
    return ((1,0),
            (0,1),
            (0,0))


fdf = (f, df)
#############################################
#  Force
############################################
parameterSet.assemble_force_term = True

def force(x):
    return [0, 0, 0.025]