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 [Rumof,Simon,Smoch]: TWO-SCALE FINITE ELEMENT APPROXIMATION OF A HOMOGENIZED PLATE MODEL * Diagonal trusses example """ ############################################# # Paths ############################################# parameterSet.resultPath = '/home/klaus/Desktop/Dune_bendIso/dune-microstructure/outputs_diagonal-trusses' parameterSet.baseName= 'diagonal-trusses' ############################################# # Grid parameters ############################################# nX=8 nY=8 parameterSet.structuredGrid = 'simplex' parameterSet.lower = '0 0' parameterSet.upper = '1 1' parameterSet.elements = str(nX)+' '+ str(nY) parameterSet.macroGridLevel = 2 ############################################# # 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 = 200 # Initial regularization parameterSet.initialRegularization = 200 # Measure convergence parameterSet.instrumented = 0 ############################ # Problem specifications ############################ # Dimension of the domain (only used for numerical-test python files) parameterSet.dim = 2 ############################################# # 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 = 0 # Write Dof-Vector to .txt-file parameterSet.writeDOFvector = 0 ############################################# # Dirichlet boundary indicator ############################################# def dirichlet_indicator(x) : if( (x[0] <= 0.01) or (x[0] >= 0.99)): return True else: return False ############################################# # MICROSTRUCTURE ############################################ parameterSet.VTKwriteMacroPhaseIndicator = True parameterSet.MacroPhaseSubsamplingRefinement = 3 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 = False self.macroPhase1_readEffectiveQuantities = False; 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]): #default value for initialization self.macroPoint = macroPoint # self.macroPoint = macroPoint 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. #--- Define different material phases: #- PHASE 1 self.phase1_type="isotropic" #hard material materialRatio = (1.0/50.0) # self.materialParameters_phase1 = [5.0/3.0, 5.0/2.0] self.materialParameters_phase1 = [200, 1.0] #- PHASE 2 self.phase2_type="isotropic" # self.materialParameters_phase2 = [materialRatio*5.0/3.0, materialRatio*5.0/2.0] self.materialParameters_phase2 = [100, 1.0] self.cacheMacroPhase=True # self.macroPhases = [] #store macro phase numbers. # self.macroPhaseCount = 0 self.a = (1.0-macroPoint[0])*(2.0-np.sqrt(3.0))/2.0 self.b = macroPoint[0] * (2.0-np.sqrt(3.0))/2.0 # self.a = (0.5)*(2.0-np.sqrt(3)) # self.b = 0.5 * (2.0-np.sqrt(3)) # self.a = 0 # self.b = (2.0-np.sqrt(3))/2 # print('self.a', self.a) # print('self.b', self.b) # --- Indicator function for material phases # def indicatorFunction(self,x): # if self.macroPoint[0] <= 2.0: # # if (abs(x[0]) < (theta/2) and x[2] >= 0 ): # if (abs(x[0]) < (1.0/4.0) and x[2] <= 0 ): # return 1 #Phase1 # else : # return 2 #Phase2 # else: # if (abs(x[0]) < (1.0/4.0) and x[2] >= 0 ): # return 1 #Phase1 # else : # return 2 #Phase2 def one_norm(self,v,w): return np.abs(v) + np.abs(w) #--- Indicator function for material phases def indicatorFunction(self,y): #shift domain x = [y[0]+0.5,y[1]+0.5] # indicator = (( (self.one_norm(x[0],x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0],x[1])) )\ # | (( (self.one_norm(x[0]-1,x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0]-1,x[1])))\ # | (x[0] < self.a/2.0) | (x[0] > 1-self.a/2.0) | (x[1] < self.a/2.0) | (x[1] > 1-self.a/2.0) indicator = (( (self.one_norm(x[0],x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0],x[1])) )\ | (( (self.one_norm(x[0]-1,x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0]-1,x[1])))\ | (x[0] < self.a/2.0) | (x[0] > 1-self.a/2.0) | (x[1] < self.a/2.0) | (x[1] > 1-self.a/2.0) # indicator = (x[0] < self.b/2.0 ) # indicator = (np.abs(x[0]) + np.abs(x[1]) < 1 + self.b/2.0) # indicator = (self.one_norm(x[0],x[1]) < 1 + self.b/2.0) if(indicator): return 1 #Phase1 else : return 2 #Phase2 #--- Define prestrain function for each phase def prestrain_phase1(self,x): return [[0, 0, 0], [0,0,0], [0,0,0]] def prestrain_phase2(self,x): return [[0, 0, 0], [0,0,0], [0,0,0]] # class Microstructure: # def __init__(self,macroPoint=[0,0]): #default value for initialization # self.macroPoint = macroPoint # # self.macroPoint = macroPoint # 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. # #--- Define different material phases: # #- PHASE 1 # self.phase1_type="isotropic" # self.materialParameters_phase1 = [200, 1.0] # #- PHASE 2 # self.phase2_type="isotropic" # self.materialParameters_phase2 = [100, 1.0] # self.cacheMacroPhase=True # self.macroPhases = [] #store macro phase numbers. # self.macroPhaseCount = 0 # self.a = (1.0-macroPoint[0])*(2.0-np.sqrt(3.0))/2.0 # self.b = macroPoint[0] * (2.0-np.sqrt(3.0))/2.0 # # self.a = (0.5)*(2.0-np.sqrt(3)) # # self.b = 0.5 * (2.0-np.sqrt(3)) # # self.a = 0 # # self.b = (2.0-np.sqrt(3))/2 # # print('self.a', self.a) # # print('self.b', self.b) # # --- Indicator function for material phases # # def indicatorFunction(self,x): # # if self.macroPoint[0] <= 2.0: # # # if (abs(x[0]) < (theta/2) and x[2] >= 0 ): # # if (abs(x[0]) < (1.0/4.0) and x[2] <= 0 ): # # return 1 #Phase1 # # else : # # return 2 #Phase2 # # else: # # if (abs(x[0]) < (1.0/4.0) and x[2] >= 0 ): # # return 1 #Phase1 # # else : # # return 2 #Phase2 # def one_norm(self,v,w): # return np.abs(v) + np.abs(w) # #--- Indicator function for material phases # def indicatorFunction(self,y): # #shift domain # x = [y[0]+0.5,y[1]+0.5] # # indicator = (( (self.one_norm(x[0],x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0],x[1])) )\ # # | (( (self.one_norm(x[0]-1,x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0]-1,x[1])))\ # # | (x[0] < self.a/2.0) | (x[0] > 1-self.a/2.0) | (x[1] < self.a/2.0) | (x[1] > 1-self.a/2.0) # indicator = (( (self.one_norm(x[0],x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0],x[1])) )\ # | (( (self.one_norm(x[0]-1,x[1])) < 1 + self.b/2.0) & (1 - self.b/2.0 < self.one_norm(x[0]-1,x[1])))\ # | (x[0] < self.a/2.0) | (x[0] > 1-self.a/2.0) | (x[1] < self.a/2.0) | (x[1] > 1-self.a/2.0) # # indicator = (x[0] < self.b/2.0 ) # # indicator = (np.abs(x[0]) + np.abs(x[1]) < 1 + self.b/2.0) # # indicator = (self.one_norm(x[0],x[1]) < 1 + self.b/2.0) # if(indicator): # return 1 #Phase1 # else : # return 2 #Phase2 # def macroPhaseMap(self,y): # if y[0] <= 2.0: # return 1 #Phase 1 # else: # return 2 #Phase 2 # #--- Define prestrain function for each phase (also works with non-constant values) # def prestrain_phase1(self,x): # return [[0, 0, 0], [0,0,0], [0,0,0]] # # rho = 0 # # # rho = 1.0 # # return [[rho*1.0, 0, 0], [0,rho*1.0,0], [0,0,rho*1.0]] # def prestrain_phase2(self,x): # return [[0, 0, 0], [0,0,0], [0,0,0]] # #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): # # a = 0.0 # # a = 0.4 # a= 1.4 # if(x[0] <= -1.99): # return [x[0] + a, x[1], 0] # if(x[0] >= 1.99): # return [x[0] - a, x[1], 0] # def boundaryValues(x): # return [x[0], x[1], 0] # def boundaryValuesDerivative(x): # return ((1,0,0), # (0,1,0), # (0,0,1)) ############################################# # Microstructure ############################################ # parameterSet.prestrainFlag = True # # parameterSet.macroscopically_varying_microstructure = False # # parameterSet.read_effectiveQuantities_from_Parset = True # Otherwise the Micro/Cell-Problem is solved once to obtain the quantities. # parameterSet.macroscopically_varying_microstructure = True # parameterSet.read_effectiveQuantities_from_Parset = False # Otherwise the Micro/Cell-Problem is solved once to obtain the quantities. # parameterSet.printMicroOutput = False # effectivePrestrain= np.array([[0.75, 0.0], # [0.0, 1.0]]); # effectiveQuadraticForm = np.array([[3.0, 0.0, 0.0], # [0.0, 1.0, 0.0], # [0.0, 0.0, 0.8]]); # effectivePrestrain= np.array([[1.0, 0.0], # [0.0, 1.0]]); # 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)) # #Rotation: # def R(beta): # return [[math.cos(beta),0], # [0,1], # [-math.sin(beta),0]] # def f(x): # a = 0.5 # if(x[0] <= 0.01): # return [x[0], x[1], 0] # elif(x[0] >= 3.99): # return [x[0] - a, x[1], 0] # else: # return [x[0], x[1], 0] # beta = math.pi/4.0 # def df(x): # a = 0.5 # if(x[0] <= 0.01): # return R(-1*beta) # elif(x[0] >= 3.99): # return R(beta) # else: # return ((1,0), # (0,1), # (0,0)) #RUMPF EXAMPLE def f(x): a = (3.0/16.0) if(x[0] <= 0.01): return [x[0]+a, x[1], 0] elif(x[0] >= 0.99): return [x[0] - a, x[1], 0] else: return [x[0], x[1], 0] def df(x): return ((1,0), (0,1), (0,0)) # def f(x): # # a = 0.4 # a = 1.4 # if(x[0] <= -1.99): # return [x[0] + a, x[1], 0] # elif(x[0] >= 1.99): # return [x[0] - a, x[1], 0] # else: # 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, 1e-2] ############################################# # Analytical reference Solution ############################################# # def f(x): # return [x[0], x[1], 0] # # # def df(x): # return ((1,0), # (0,1), # (0,0)) # # # fdf = (f, df) ##################### MICROSCALE PROBLEM #################### # Microstructure used: Parametrized Laminate. # --- Choose scale ratio gamma: # parameterSet.gamma = 1.0 # # --- Number of material phases # parameterSet.Phases = 4 # #--- Indicator function for material phases # def indicatorFunction(x): # theta=0.25 # factor=1 # if (abs(x[0]) < (theta/2) and x[2] < 0 ): # return 1 #Phase1 # elif (abs(x[0]) > (theta/2) and x[2] > 0 ): # return 2 #Phase2 # elif (abs(x[0]) < (theta/2) and x[2] > 0 ): # return 3 #Phase3 # else : # return 4 #Phase4 # ########### Options for material phases: ################################# # # 1. "isotropic" 2. "orthotropic" 3. "transversely_isotropic" 4. "general_anisotropic" # ######################################################################### # ## Notation - Parameter input : # # isotropic (Lame parameters) : [mu , lambda] # # orthotropic : [E1,E2,E3,G12,G23,G31,nu12,nu13,nu23] # see https://en.wikipedia.org/wiki/Poisson%27s_ratio with x=1,y=2,z=3 # # transversely_isotropic : [E1,E2,G12,nu12,nu23] # # general_anisotropic : full compliance matrix C # ###################################################################### # #--- Define different material phases: # #- PHASE 1 # parameterSet.phase1_type="isotropic" # materialParameters_phase1 = [2.0, 0] # #- PHASE 2 # parameterSet.phase2_type="isotropic" # materialParameters_phase2 = [1.0, 0] # #- PHASE 3 # parameterSet.phase3_type="isotropic" # materialParameters_phase3 = [2.0, 0] # #- PHASE 4 # parameterSet.phase4_type="isotropic" # materialParameters_phase4 = [1.0, 0] # #--- Define prestrain function for each phase (also works with non-constant values) # def prestrain_phase1(x): # return [[2, 0, 0], [0,2,0], [0,0,2]] # def prestrain_phase2(x): # return [[1, 0, 0], [0,1,0], [0,0,1]] # def prestrain_phase3(x): # return [[0, 0, 0], [0,0,0], [0,0,0]] # def prestrain_phase4(x): # return [[0, 0, 0], [0,0,0], [0,0,0]] parameterSet.printMicroOutput = 0 # Flag that allows to supress the output of the micro-problem. ############################################# # Grid parameters ############################################# parameterSet.microGridLevel = 2 ############################################# # Assembly options ############################################# parameterSet.set_IntegralZero = 1 #(default = false, This overwrites the option 'set_oneBasisFunction_Zero') parameterSet.set_oneBasisFunction_Zero = 1 #(default = false) # parameterSet.arbitraryLocalIndex = 7 #(default = 0) # parameterSet.arbitraryElementNumber = 3 #(default = 0) parameterSet.cacheElementMatrices = 1 # Use caching of element matrices ############################################# # Solver Options, Type: #1: CHOLMOD (default) | #2: UMFPACK | #3: GMRES | #4 CG | #5 QR: # (maybe switch to an iterative solver (e.g. GMRES) if direct solver (CHOLMOD/UMFPACK) runs out of memory for too fine grids) ############################################# parameterSet.Solvertype = 1 parameterSet.Solver_verbosity = 0 # (default = 2) degree of information for solver output ############################################# # Write/Output options #(default=false) ############################################# # --- (Optional output) write Material / prestrain / Corrector functions to .vtk-Files: parameterSet.write_materialFunctions = 0 # VTK indicator function for material/prestrain definition #parameterSet.write_prestrainFunctions = 1 # VTK norm of B (currently not implemented) parameterSet.MaterialSubsamplingRefinement= 2 # --- Write Correctos to VTK-File: parameterSet.writeCorrectorsVTK = 0 # --- write effective quantities (Qhom.Beff) to .txt-files parameterSet.write_EffectiveQuantitiesToTxt = False ############################################# # Debug options ############################################# parameterSet.print_debug = 0 #(default=false) parameterSet.print_conditionNumber = 0 parameterSet.print_corrector_matrices = 0 parameterSet.write_checkOrthogonality = 0 #Check orthogonality (75) from the paper.