def jacobianMatrices(normale, coeff, rho_l, q_l, rho_r, q_r): RoeMat = cdmath.Matrix(3, 3) AbsRoeMa = cdmath.Matrix(3, 3) tangent = cdmath.Vector(2) tangent[0] = normale[1] tangent[1] = -normale[0] u_l = q_l / rho_l u_r = q_r / rho_r if rho_l < 0 or rho_r < 0: print "rho_l=", rho_l, " rho_r= ", rho_r raise ValueError("Negative density") u = (u_l * sqrt(rho_l) + u_r * sqrt(rho_r)) / (sqrt(rho_l) + sqrt(rho_r)) un = u * normale RoeMat[0, 0] = 0 RoeMat[0, 1] = normale[0] RoeMat[0, 2] = normale[1] RoeMat[1, 0] = c0 * c0 * normale[0] - un * u[0] RoeMat[2, 0] = c0 * c0 * normale[1] - un * u[1] RoeMat[1, 1] = un + normale[0] * u[0] RoeMat[1, 2] = normale[1] * u[0] RoeMat[2, 2] = un + normale[1] * u[1] RoeMat[2, 1] = normale[0] * u[1] AbsRoeMa[0, 0] = (abs(un - c0) * (un + c0) + abs(un + c0) * (c0 - un)) / (2 * c0) AbsRoeMa[0, 1] = (abs(un + c0) - abs(un - c0)) / (2 * c0) * normale[0] AbsRoeMa[0, 2] = (abs(un + c0) - abs(un - c0)) / (2 * c0) * normale[1] AbsRoeMa[1, 0] = (abs(un - c0) * (un + c0) * (u[0] - c0 * normale[0]) - abs(un + c0) * (un - c0) * (u[0] + c0 * normale[0])) / (2 * c0) - abs(un) * ( u * tangent) * tangent[0] AbsRoeMa[2, 0] = (abs(un - c0) * (un + c0) * (u[1] - c0 * normale[1]) - abs(un + c0) * (un - c0) * (u[1] + c0 * normale[1])) / (2 * c0) - abs(un) * ( u * tangent) * tangent[1] #subMatrix=(abs(un+c0)*((u-c0*normale)^normale)-abs(un-c0)*((u-c0*normale)^normale))/(2*c0)+abs(un)*(tangent^tangent); AbsRoeMa[1, 1] = (abs(un + c0) * ((u[0] - c0 * normale[0]) * normale[0]) - abs(un - c0) * ((u[0] - c0 * normale[0]) * normale[0])) / ( 2 * c0) + abs(un) * (tangent[0] * tangent[0]) #subMatrix[0,0]; AbsRoeMa[1, 2] = (abs(un + c0) * ((u[0] - c0 * normale[0]) * normale[1]) - abs(un - c0) * ((u[0] - c0 * normale[0]) * normale[1])) / ( 2 * c0) + abs(un) * (tangent[0] * tangent[1]) #subMatrix[0,1]; AbsRoeMa[2, 1] = (abs(un + c0) * ((u[1] - c0 * normale[1]) * normale[0]) - abs(un - c0) * ((u[1] - c0 * normale[1]) * normale[0])) / ( 2 * c0) + abs(un) * (tangent[1] * tangent[0]) AbsRoeMa[2, 2] = (abs(un + c0) * ((u[1] - c0 * normale[1]) * normale[1]) - abs(un - c0) * ((u[1] - c0 * normale[1]) * normale[1])) / ( 2 * c0) + abs(un) * (tangent[1] * tangent[1]) return (RoeMat - AbsRoeMa) * coeff / 2, un
def jacobianMatrices(): A = cdmath.Matrix(2, 2) absA = cdmath.Matrix(2, 2) absA[0, 0] = c0 absA[1, 1] = c0 A[1, 0] = 1 A[0, 1] = c0 * c0 return A, absA
def jacobianMatrices(): test_desc["Numerical_method_name"]="Upwind" A=cdmath.Matrix(2,2) absA=cdmath.Matrix(2,2) absA[0,0]=c0 absA[1,1]=c0 A[1,0]=1 A[0,1]=c0*c0 return A, absA
def jacobianMatrices(normal, coeff, signun): dim = normal.size() A = cdmath.Matrix(dim + 1, dim + 1) absA = cdmath.Matrix(dim + 1, dim + 1) for i in range(dim): A[i + 1, 0] = normal[i] * coeff absA[i + 1, 0] = -signun * A[i + 1, 0] A[0, i + 1] = c0 * c0 * normal[i] * coeff absA[0, i + 1] = signun * A[0, i + 1] return (A - absA) / 2
def jacobianMatrices(normal,coeff): dim=normal.size() A=cdmath.Matrix(dim+1,dim+1) absA=cdmath.Matrix(dim+1,dim+1) absA[0,0]=c0*coeff for i in range(dim): A[i+1,0]= normal[i]*coeff A[0,i+1]=c0*c0*normal[i]*coeff for j in range(dim): absA[i+1,j+1]=c0*normal[i]*normal[j]*coeff return (A - absA)/2
def jacobianMatrices(normal): dim=normal.size() A=cdmath.Matrix(dim+1,dim+1) absA=cdmath.Matrix(dim+1,dim+1) absA[0,0]=c0 for i in range(dim): A[i+1,0]=normal[i] A[0,i+1]=c0*c0*normal[i] for j in range(dim): absA[i+1,j+1]=c0*normal[i]*normal[j] return A, absA
def staggeredMatrices(coeff, scaling): dim = 1 S1 = cdmath.Matrix(dim + 1, dim + 1) S2 = cdmath.Matrix(dim + 1, dim + 1) for i in range(dim): if (scaling == 0): S1[0, i + 1] = c0 * c0 * coeff S2[i + 1, 0] = coeff else: S1[0, i + 1] = c0 * coeff S2[i + 1, 0] = c0 * coeff return S1, S2
def jacobianMatrices(normal, coeff): test_desc["Numerical_method_name"] = "Upwind" dim = normal.size() A = cdmath.Matrix(dim + 1, dim + 1) absA = cdmath.Matrix(dim + 1, dim + 1) absA[0, 0] = c0 * coeff for i in range(dim): A[i + 1, 0] = normal[i] * coeff A[0, i + 1] = c0 * c0 * normal[i] * coeff for j in range(dim): absA[i + 1, j + 1] = c0 * normal[i] * normal[j] * coeff return (A - absA) / 2
def computeDivergenceMatrix(my_mesh,nbVoisinsMax,dt,test_bc): nbCells = my_mesh.getNumberOfCells() dim=my_mesh.getMeshDimension() nbComp=dim+1 normal=cdmath.Vector(dim) implMat=cdmath.SparseMatrixPetsc(nbCells*nbComp,nbCells*nbComp,(nbVoisinsMax+1)*nbComp) idMoinsJacCL=cdmath.Matrix(nbComp) for j in range(nbCells):#On parcourt les cellules Cj = my_mesh.getCell(j) nbFaces = Cj.getNumberOfFaces(); for k in range(nbFaces) : indexFace = Cj.getFacesId()[k]; Fk = my_mesh.getFace(indexFace); for i in range(dim) : normal[i] = Cj.getNormalVector(k, i);#normale sortante Am=jacobianMatrices( normal,dt*Fk.getMeasure()/Cj.getMeasure()); cellAutre =-1 if ( not Fk.isBorder()) : # hypothese: La cellule d'index indexC1 est la cellule courante index j */ if (Fk.getCellsId()[0] == j) : # hypothese verifiée cellAutre = Fk.getCellsId()[1]; elif(Fk.getCellsId()[1] == j) : # hypothese non verifiée cellAutre = Fk.getCellsId()[0]; else : raise ValueError("computeFluxes: problem with mesh, unknown cel number") implMat.addValue(j*nbComp,cellAutre*nbComp,Am) implMat.addValue(j*nbComp, j*nbComp,Am*(-1.)) else : if( test_bc=="Periodic" and Fk.getGroupName() != "Wall" and Fk.getGroupName() != "Paroi" and Fk.getGroupName() != "Neumann"):#Periodic boundary condition unless Wall/Neumann specified explicitly test_desc["Boundary_conditions"]="Periodic" indexFP = my_mesh.getIndexFacePeriodic(indexFace) Fp = my_mesh.getFace(indexFP) cellAutre = Fp.getCellsId()[0] implMat.addValue(j*nbComp,cellAutre*nbComp,Am) implMat.addValue(j*nbComp, j*nbComp,Am*(-1.)) elif( test_bc=="Wall" or Fk.getGroupName() == "Wall" or Fk.getGroupName() == "Paroi"):#Wall boundary condition test_desc["Boundary_conditions"]="Wall" v=cdmath.Vector(dim+1) for i in range(dim) : v[i+1]=normal[i] idMoinsJacCL=v.tensProduct(v)*2 implMat.addValue(j*nbComp,j*nbComp,Am*(-1.)*idMoinsJacCL) elif(test_bc!="Neumann" and Fk.getGroupName() != "Neumann"):#Nothing to do for Neumann boundary condition print Fk.getGroupName() raise ValueError("computeFluxes: Unknown boundary condition name"); return implMat
def jacobianMatrices(normal, coeff, signun): dim = normal.size() A = cdmath.Matrix(dim + 1, dim + 1) for i in range(dim): A[i + 1, 0] = normal[i] * coeff A[0, i + 1] = c0 * c0 * normal[i] * coeff return A / 2
def jacobianMatrices(coeff,scaling): dim=1 A=cdmath.Matrix(dim+1,dim+1) absA=cdmath.Matrix(dim+1,dim+1) absA[0,0]=c0*coeff for i in range(dim): for j in range(dim): absA[i+1,j+1]=c0*coeff if( scaling==0): A[0,i+1]=c0*c0*coeff A[i+1,0]= coeff elif( scaling==1): A[0,i+1]= coeff A[i+1,0]= coeff else: A[0,i+1]= c0*coeff A[i+1,0]= c0*coeff return A,absA
def computeDivergenceMatrix(my_mesh, nbVoisinsMax, dt, scaling, test_bc): nbCells = my_mesh.getNumberOfCells() dim = my_mesh.getMeshDimension() nbComp = dim + 1 normal = cdmath.Vector(dim) implMat = cdmath.SparseMatrixPetsc(nbCells * nbComp, nbCells * nbComp, (nbVoisinsMax + 1) * nbComp) idMoinsJacCL = cdmath.Matrix(nbComp) for j in range(nbCells): #On parcourt les cellules Cj = my_mesh.getCell(j) nbFaces = Cj.getNumberOfFaces() for k in range(nbFaces): indexFace = Cj.getFacesId()[k] Fk = my_mesh.getFace(indexFace) for i in range(dim): normal[i] = Cj.getNormalVector(k, i) #normale sortante Am = jacobianMatrices(normal, dt * Fk.getMeasure() / Cj.getMeasure(), scaling) cellAutre = -1 if (not Fk.isBorder()): # hypothese: La cellule d'index indexC1 est la cellule courante index j */ if (Fk.getCellsId()[0] == j): # hypothese verifiée cellAutre = Fk.getCellsId()[1] elif (Fk.getCellsId()[1] == j): # hypothese non verifiée cellAutre = Fk.getCellsId()[0] else: raise ValueError( "computeFluxes: problem with mesh, unknown cell number" ) implMat.addValue(j * nbComp, cellAutre * nbComp, Am) implMat.addValue(j * nbComp, j * nbComp, Am * (-1.)) else: indexFP = my_mesh.getIndexFacePeriodic( indexFace, my_mesh.getName() == "squareWithBrickWall", my_mesh.getName() == "squareWithHexagons") Fp = my_mesh.getFace(indexFP) cellAutre = Fp.getCellsId()[0] implMat.addValue(j * nbComp, cellAutre * nbComp, Am) implMat.addValue(j * nbComp, j * nbComp, Am * (-1.)) return implMat
def jacobianMatrices(normal, coeff, signun, scaling): test_desc["Numerical_method_name"] = "Pseudo staggered" dim = normal.size() A = cdmath.Matrix(dim + 1, dim + 1) absA = cdmath.Matrix(dim + 1, dim + 1) for i in range(dim): if (scaling == 0): A[0, i + 1] = c0 * c0 * normal[i] * coeff A[i + 1, 0] = normal[i] * coeff elif (scaling == 1): A[0, i + 1] = normal[i] * coeff A[i + 1, 0] = normal[i] * coeff else: A[0, i + 1] = c0 * normal[i] * coeff A[i + 1, 0] = c0 * normal[i] * coeff absA[0, i + 1] = signun * A[0, i + 1] absA[i + 1, 0] = -signun * A[i + 1, 0] return (A - absA) / 2
def jacobianMatrices(normal, coeff, scaling): test_desc["Numerical_method_name"] = "Centered scheme" dim = normal.size() A = cdmath.Matrix(dim + 1, dim + 1) for i in range(dim): if (scaling == 0): A[0, i + 1] = c0 * c0 * normal[i] * coeff A[i + 1, 0] = normal[i] * coeff elif (scaling == 1): A[0, i + 1] = normal[i] * coeff A[i + 1, 0] = normal[i] * coeff else: A[0, i + 1] = c0 * normal[i] * coeff A[i + 1, 0] = c0 * normal[i] * coeff return A / 2
def computeDivergenceMatrix(my_mesh, implMat, Un): nbCells = my_mesh.getNumberOfCells() dim = my_mesh.getMeshDimension() nbComp = dim + 1 normal = cdmath.Vector(dim) maxAbsEigVa = 0 q_l = cdmath.Vector(2) q_r = cdmath.Vector(2) idMoinsJacCL = cdmath.Matrix(nbComp) for j in range(nbCells): #On parcourt les cellules Cj = my_mesh.getCell(j) nbFaces = Cj.getNumberOfFaces() for k in range(nbFaces): indexFace = Cj.getFacesId()[k] Fk = my_mesh.getFace(indexFace) for i in range(dim): normal[i] = Cj.getNormalVector(k, i) #normale sortante cellAutre = -1 if (not Fk.isBorder()): # hypothese: La cellule d'index indexC1 est la cellule courante index j */ if (Fk.getCellsId()[0] == j): # hypothese verifiée cellAutre = Fk.getCellsId()[1] elif (Fk.getCellsId()[1] == j): # hypothese non verifiée cellAutre = Fk.getCellsId()[0] else: raise ValueError( "computeFluxes: problem with mesh, unknown cell number" ) q_l[0] = Un[j * nbComp + 1] q_l[1] = Un[j * nbComp + 2] q_r[0] = Un[cellAutre * nbComp + 1] q_r[1] = Un[cellAutre * nbComp + 2] Am, un = jacobianMatrices(normal, Fk.getMeasure() / Cj.getMeasure(), Un[j * nbComp], q_l, Un[cellAutre * nbComp], q_r) implMat.addValue(j * nbComp, cellAutre * nbComp, Am) implMat.addValue(j * nbComp, j * nbComp, Am * (-1.)) else: if ( Fk.getGroupName() != "Periodic" and Fk.getGroupName() != "Neumann" ): #Wall boundary condition unless Periodic/Neumann specified explicitly q_l[0] = Un[j * nbComp + 1] q_l[1] = Un[j * nbComp + 2] q_r = q_l - normal * 2 * (q_l * normal) Am, un = jacobianMatrices( normal, Fk.getMeasure() / Cj.getMeasure(), Un[j * nbComp], q_l, Un[j * nbComp], q_r) v = cdmath.Vector(dim + 1) for i in range(dim): v[i + 1] = normal[i] idMoinsJacCL = v.tensProduct(v) * 2 implMat.addValue(j * nbComp, j * nbComp, Am * (-1.) * idMoinsJacCL) elif (Fk.getGroupName() == "Periodic" ): #Periodic boundary condition q_l[0] = Un[j * nbComp + 1] q_l[1] = Un[j * nbComp + 2] q_r[0] = Un[cellAutre * nbComp + 1] q_r[1] = Un[cellAutre * nbComp + 2] Am, un = jacobianMatrices( normal, Fk.getMeasure() / Cj.getMeasure(), Un[j * nbComp], Un[j * nbComp + 1], Un[j * nbComp + 2], Un[cellAutre * nbComp], Un[cellAutre * nbComp + 1], Un[cellAutre * nbComp + 2]) indexFP = my_mesh.getIndexFacePeriodic(indexFace) Fp = my_mesh.getFace(indexFP) cellAutre = Fp.getCellsId()[0] implMat.addValue(j * nbComp, cellAutre * nbComp, Am) implMat.addValue(j * nbComp, j * nbComp, Am * (-1.)) elif (Fk.getGroupName() != "Neumann" ): #Nothing to do for Neumann boundary condition print Fk.getGroupName() raise ValueError( "computeFluxes: Unknown boundary condition name") maxAbsEigVa = max(maxAbsEigVa, abs(un + c0), abs(un - c0)) return maxAbsEigVa
def solve(filename, resolution, meshName, testColor): start = time.time() test_desc["Mesh_name"] = meshName test_desc["Test_color"] = testColor #Chargement du maillage triangulaire du disque unité D(0,1) #======================================================================================= my_mesh = cdmath.Mesh(filename + ".med") if (my_mesh.getSpaceDimension() != 2 or my_mesh.getMeshDimension() != 2): raise ValueError( "Wrong space or mesh dimension : space and mesh dimensions should be 2" ) if (not my_mesh.isTriangular()): raise ValueError("Wrong cell types : mesh is not made of triangles") nbNodes = my_mesh.getNumberOfNodes() nbCells = my_mesh.getNumberOfCells() test_desc["Space_dimension"] = my_mesh.getSpaceDimension() test_desc["Mesh_dimension"] = my_mesh.getMeshDimension() test_desc["Mesh_number_of_elements"] = my_mesh.getNumberOfNodes() test_desc["Mesh_cell_type"] = my_mesh.getElementTypesNames() print("Mesh loading done") print("Number of nodes=", nbNodes) print("Number of cells=", nbCells) #Détermination des noeuds intérieurs #====================================================================== my_ExactSol = cdmath.Field("Exact_field", cdmath.NODES, my_mesh, 1) nbInteriorNodes = 0 nbBoundaryNodes = 0 maxNbNeighbours = 0 #This is to determine the number of non zero coefficients in the sparse finite element rigidity matrix interiorNodes = [] boundaryNodes = [] eps = 1e-6 #parcours des noeuds pour discrétisation du second membre et extraction 1) des noeuds intérieur 2) des noeuds frontière 3) du nb max voisins d'un noeud for i in range(nbNodes): Ni = my_mesh.getNode(i) x = Ni.x() y = Ni.y() #Robust calculation of atan(2x/(x**2+y**2-1) #my_ExactSol[i]=atan2(2*x*sign(x**2+y**2-1),abs(x**2+y**2-1))#mettre la solution exacte de l'edp if x**2 + y**2 - 1 > eps: print("!!! Warning Mesh ", meshName, " !!! Node is not in the unit disk.", ", eps=", eps, ", x**2+y**2-1=", x**2 + y**2 - 1) #raise ValueError("!!! Domain should be the unit disk.") if x**2 + y**2 - 1 < -eps: my_ExactSol[i] = atan(2 * x / (x**2 + y**2 - 1)) elif x > 0: #x**2+y**2-1>=0 my_ExactSol[i] = -pi / 2 elif x < 0: #x**2+y**2-1>=0 my_ExactSol[i] = pi / 2 else: #x=0 my_ExactSol[i] = 0 if my_mesh.isBorderNode(i): # Détection des noeuds frontière boundaryNodes.append(i) nbBoundaryNodes = nbBoundaryNodes + 1 else: # Détection des noeuds intérieurs interiorNodes.append(i) nbInteriorNodes = nbInteriorNodes + 1 maxNbNeighbours = max( 1 + Ni.getNumberOfCells(), maxNbNeighbours ) #true only in 2D, need a function Ni.getNumberOfNeighbourNodes() test_desc["Mesh_max_number_of_neighbours"] = maxNbNeighbours print("Right hand side discretisation done") print("Number of interior nodes=", nbInteriorNodes) print("Number of boundary nodes=", nbBoundaryNodes) print("Max number of neighbours=", maxNbNeighbours) # Construction de la matrice de rigidité et du vecteur second membre du système linéaire #======================================================================================= Rigidite = cdmath.SparseMatrixPetsc( nbInteriorNodes, nbInteriorNodes, maxNbNeighbours ) # warning : third argument is maximum number of non zero coefficients per line of the matrix RHS = cdmath.Vector(nbInteriorNodes) M = cdmath.Matrix(3, 3) # Vecteurs gradient de la fonction de forme associée à chaque noeud d'un triangle (hypothèse 2D) GradShapeFunc0 = cdmath.Vector(2) GradShapeFunc1 = cdmath.Vector(2) GradShapeFunc2 = cdmath.Vector(2) #On parcourt les triangles du domaine for i in range(nbCells): Ci = my_mesh.getCell(i) #Contribution à la matrice de rigidité nodeId0 = Ci.getNodeId(0) nodeId1 = Ci.getNodeId(1) nodeId2 = Ci.getNodeId(2) N0 = my_mesh.getNode(nodeId0) N1 = my_mesh.getNode(nodeId1) N2 = my_mesh.getNode(nodeId2) M[0, 0] = N0.x() M[0, 1] = N0.y() M[0, 2] = 1 M[1, 0] = N1.x() M[1, 1] = N1.y() M[1, 2] = 1 M[2, 0] = N2.x() M[2, 1] = N2.y() M[2, 2] = 1 #Values of each shape function at each node values0 = [1, 0, 0] values1 = [0, 1, 0] values2 = [0, 0, 1] GradShapeFunc0 = gradientNodal(M, values0) / 2 GradShapeFunc1 = gradientNodal(M, values1) / 2 GradShapeFunc2 = gradientNodal(M, values2) / 2 #Création d'un tableau (numéro du noeud, gradient de la fonction de forme) GradShapeFuncs = {nodeId0: GradShapeFunc0} GradShapeFuncs[nodeId1] = GradShapeFunc1 GradShapeFuncs[nodeId2] = GradShapeFunc2 # Remplissage de la matrice de rigidité et du second membre for j in [nodeId0, nodeId1, nodeId2]: if boundaryNodes.count( j ) == 0: #seuls les noeuds intérieurs contribuent au système linéaire (matrice de rigidité et second membre) j_int = interiorNodes.index( j) #indice du noeud j en tant que noeud intérieur #Pas de contribution au second membre car pas de terme source boundaryContributionAdded = False #Needed in case j is a border cell #Contribution de la cellule triangulaire i à la ligne j_int du système linéaire for k in [nodeId0, nodeId1, nodeId2]: if boundaryNodes.count( k ) == 0: #seuls les noeuds intérieurs contribuent à la matrice du système linéaire k_int = interiorNodes.index( k) #indice du noeud k en tant que noeud intérieur Rigidite.addValue( j_int, k_int, GradShapeFuncs[j] * GradShapeFuncs[k] / Ci.getMeasure()) elif boundaryContributionAdded == False: #si condition limite non nulle au bord (ou maillage non recouvrant), ajouter la contribution du bord au second membre de la cellule j if boundaryNodes.count(nodeId0) != 0: u0 = my_ExactSol[nodeId0] else: u0 = 0 if boundaryNodes.count(nodeId1) != 0: u1 = my_ExactSol[nodeId1] else: u1 = 0 if boundaryNodes.count(nodeId2) != 0: u2 = my_ExactSol[nodeId2] else: u2 = 0 boundaryContributionAdded = True #Contribution from the boundary to matrix line j is done in one step GradGh = gradientNodal(M, [u0, u1, u2]) / 2 RHS[j_int] += -(GradGh * GradShapeFuncs[j]) / Ci.getMeasure() print("Linear system matrix building done") # Résolution du système linéaire #================================= LS = cdmath.LinearSolver( Rigidite, RHS, 100, 1.E-6, "CG", "LU") #Remplacer CG par CHOLESKY pour solveur direct LS.setComputeConditionNumber() SolSyst = LS.solve() print("Preconditioner used : ", LS.getNameOfPc()) print("Number of iterations used : ", LS.getNumberOfIter()) print("Linear system solved") test_desc["Linear_solver_algorithm"] = LS.getNameOfMethod() test_desc["Linear_solver_preconditioner"] = LS.getNameOfPc() test_desc["Linear_solver_precision"] = LS.getTolerance() test_desc["Linear_solver_maximum_iterations"] = LS.getNumberMaxOfIter() test_desc[ "Linear_system_max_actual_iterations_number"] = LS.getNumberOfIter() test_desc["Linear_system_max_actual_error"] = LS.getResidu() test_desc[ "Linear_system_max_actual_condition number"] = LS.getConditionNumber() # Création du champ résultat #=========================== my_ResultField = cdmath.Field("ResultField", cdmath.NODES, my_mesh, 1) for j in range(nbInteriorNodes): my_ResultField[interiorNodes[j]] = SolSyst[j] #remplissage des valeurs pour les noeuds intérieurs for j in range(nbBoundaryNodes): my_ResultField[boundaryNodes[j]] = my_ExactSol[boundaryNodes[j]] #remplissage des valeurs pour les noeuds frontière (condition limite) #sauvegarde sur le disque dur du résultat dans un fichier paraview my_ResultField.writeVTK("FiniteElements2DPoissonStiffBC_DISK_" + meshName + str(nbNodes)) print( "Numerical solution of 2D Poisson equation on a disk using finite elements done" ) end = time.time() #Calcul de l'erreur commise par rapport à la solution exacte #=========================================================== l2_norm_sol_exacte = my_ExactSol.normL2()[0] l2_error = (my_ExactSol - my_ResultField).normL2()[0] print( "L2 relative error = norm( exact solution - numerical solution )/norm( exact solution ) = ", l2_error / l2_norm_sol_exacte) print("Maximum numerical solution = ", my_ResultField.max(), " Minimum numerical solution = ", my_ResultField.min()) print("Maximum exact solution = ", my_ExactSol.max(), " Minimum exact solution = ", my_ExactSol.min()) #Postprocessing : #================ # Extraction of the diagonal data diag_data = VTK_routines.Extract_field_data_over_line_to_numpyArray( my_ResultField, [0, -1, 0], [0, 1, 0], resolution) # save 2D picture PV_routines.Save_PV_data_to_picture_file( "FiniteElements2DPoissonStiffBC_DISK_" + meshName + str(nbNodes) + '_0.vtu', "ResultField", 'NODES', "FiniteElements2DPoissonStiffBC_DISK_" + meshName + str(nbNodes)) test_desc["Computational_time_taken_by_run"] = end - start test_desc["Absolute_error"] = l2_error test_desc["Relative_error"] = l2_error / l2_norm_sol_exacte with open( 'test_PoissonStiffBC' + str(my_mesh.getMeshDimension()) + 'D_EF_' + "DISK_" + meshName + str(nbCells) + "Cells.json", 'w') as outfile: json.dump(test_desc, outfile) return l2_error / l2_norm_sol_exacte, nbNodes, diag_data, my_ResultField.min( ), my_ResultField.max(), end - start
def computeDivergenceMatrix(my_mesh, nbVoisinsMax, dt, scaling): nbCells = my_mesh.getNumberOfCells() dim = my_mesh.getMeshDimension() nbComp = dim + 1 if (not my_mesh.isStructured()): raise ValueError("WaveSystemStaggered: the mesh should be structured") NxNyNz = my_mesh.getCellGridStructure() DxDyDz = my_mesh.getDXYZ() implMat = cdmath.SparseMatrixPetsc(nbCells * nbComp, nbCells * nbComp, (nbVoisinsMax + 1) * nbComp) idMoinsJacCL = cdmath.Matrix(nbComp) if (dim == 1): nx = NxNyNz[0] dx = DxDyDz[0] if (scaling == 0): for k in range(nbCells): implMat.addValue(k, 1 * nbCells + k, -c0 * c0 * dt / dx) implMat.addValue(k, 1 * nbCells + (k + 1) % nx, c0 * c0 * dt / dx) implMat.addValue(1 * nbCells + k, k, dt / dx) implMat.addValue(1 * nbCells + (k + 1) % nx, k, -dt / dx) else: # scaling >0 for k in range(nbCells): implMat.addValue(k, 1 * nbCells + k, -c0 * dt / dx) implMat.addValue(k, 1 * nbCells + (k + 1) % nx, c0 * dt / dx) implMat.addValue(1 * nbCells + k, k, c0 * dt / dx) implMat.addValue(1 * nbCells + (k + 1) % nx, k, -c0 * dt / dx) elif (dim == 2): # k = j*nx+i nx = NxNyNz[0] ny = NxNyNz[1] dx = DxDyDz[0] dy = DxDyDz[1] if (scaling == 0): for k in range(nbCells): i = k % nx j = k // nx implMat.addValue(k, 1 * nbCells + j * nx + i, -c0 * c0 * dt / dx) implMat.addValue(k, 1 * nbCells + j * nx + (i + 1) % nx, c0 * c0 * dt / dx) implMat.addValue(k, 2 * nbCells + j * nx + i, -c0 * c0 * dt / dy) implMat.addValue(k, 2 * nbCells + ((j + 1) % ny) * nx + i, c0 * c0 * dt / dy) implMat.addValue(1 * nbCells + j * nx + i, k, dt / dx) implMat.addValue(1 * nbCells + j * nx + (i + 1) % nx, k, -dt / dx) implMat.addValue(2 * nbCells + j * nx + i, k, dt / dy) implMat.addValue(2 * nbCells + ((j + 1) % ny) * nx + i, k, -dt / dy) else: # scaling >0 for k in range(nbCells): i = k % nx j = k // nx implMat.addValue(k, 1 * nbCells + j * nx + i, -c0 * dt / dx) implMat.addValue(k, 1 * nbCells + j * nx + (i + 1) % nx, c0 * dt / dx) implMat.addValue(k, 2 * nbCells + j * nx + i, -c0 * dt / dy) implMat.addValue(k, 2 * nbCells + ((j + 1) % ny) * nx + i, c0 * dt / dy) implMat.addValue(1 * nbCells + j * nx + i, k, c0 * dt / dx) implMat.addValue(1 * nbCells + j * nx + (i + 1) % nx, k, -c0 * dt / dx) implMat.addValue(2 * nbCells + j * nx + i, k, c0 * dt / dy) implMat.addValue(2 * nbCells + ((j + 1) % ny) * nx + i, k, -c0 * dt / dy) elif (dim == 3): # k = l*nx*ny+j*nx+i nx = NxNyNz[0] ny = NxNyNz[1] nz = NxNyNz[2] dx = DxDyDz[0] dy = DxDyDz[1] dz = DxDyDz[2] if (scaling == 0): for k in range(nbCells): i = k % nx j = (k // nx) % ny l = k // (nx * ny) implMat.addValue(k, 1 * nbCells + l * nx * ny + j * nx + i, -c0 * c0 * dt / dx) implMat.addValue( k, 1 * nbCells + l * nx * ny + j * nx + (i + 1) % nx, c0 * c0 * dt / dx) implMat.addValue(k, 2 * nbCells + l * nx * ny + j * nx + i, -c0 * c0 * dt / dy) implMat.addValue( k, 2 * nbCells + l * nx * ny + ((j + 1) % ny) * nx + i, c0 * c0 * dt / dy) implMat.addValue(k, 3 * nbCells + l * nx * ny + j * nx + i, -c0 * c0 * dt / dz) implMat.addValue( k, 3 * nbCells + ((l + 1) % nz) * nx * ny + j * nx + i, c0 * c0 * dt / dz) implMat.addValue(1 * nbCells + l * nx * ny + j * nx + i, k, dt / dx) implMat.addValue( 1 * nbCells + l * nx * ny + j * nx + (i + 1) % nx, k, -dt / dx) implMat.addValue(2 * nbCells + l * nx * ny + j * nx + i, k, dt / dy) implMat.addValue( 2 * nbCells + l * nx * ny + ((j + 1) % ny) * nx + i, k, -dt / dy) implMat.addValue(3 * nbCells + l * nx * ny + j * nx + i, k, dt / dz) implMat.addValue( 3 * nbCells + ((l + 1) % nz) * nx * ny + j * nx + i, k, -dt / dz) else: # scaling >0 for k in range(nbCells): i = k % nx j = (k // nx) % ny l = k // (nx * ny) implMat.addValue(k, 1 * nbCells + l * nx * ny + j * nx + i, -c0 * dt / dx) implMat.addValue( k, 1 * nbCells + l * nx * ny + j * nx + (i + 1) % nx, c0 * dt / dx) implMat.addValue(k, 2 * nbCells + l * nx * ny + j * nx + i, -c0 * dt / dy) implMat.addValue( k, 2 * nbCells + l * nx * ny + ((j + 1) % ny) * nx + i, c0 * dt / dy) implMat.addValue(k, 3 * nbCells + l * nx * ny + j * nx + i, -c0 * dt / dz) implMat.addValue( k, 3 * nbCells + ((l + 1) % nz) * nx * ny + j * nx + i, c0 * dt / dz) implMat.addValue(1 * nbCells + l * nx * ny + j * nx + i, k, c0 * dt / dx) implMat.addValue( 1 * nbCells + l * nx * ny + j * nx + (i + 1) % nx, k, -c0 * dt / dx) implMat.addValue(2 * nbCells + l * nx * ny + j * nx + i, k, c0 * dt / dy) implMat.addValue( 2 * nbCells + l * nx * ny + ((j + 1) % ny) * nx + i, k, -c0 * dt / dy) implMat.addValue(3 * nbCells + l * nx * ny + j * nx + i, k, c0 * dt / dz) implMat.addValue( 3 * nbCells + ((l + 1) % nz) * nx * ny + j * nx + i, k, -c0 * dt / dz) #Add the identity matrix on the diagonal #divMat.diagonalShift(1)#only after filling all coefficients for j in range(nbCells * nbComp): implMat.addValue(j, j, 1) #/(c0*c0) return implMat
nbInteriorNodes = len(interiorNodes) nbBoundaryNodes = len(boundaryNodes) print("nb of interior nodes=", nbInteriorNodes) print("nb of Boundary nodes=", nbBoundaryNodes) print("Max nb of neighbours=", maxNbNeighbours) # Construction de la matrice de rigidité et du vecteur second membre du système linéaire #======================================================================================= Rigidite = cdmath.SparseMatrixPetsc(nbInteriorNodes, nbInteriorNodes, maxNbNeighbours) RHS = cdmath.Vector(nbInteriorNodes) # Vecteurs gradient de la fonction de forme associée à chaque noeud d'un tétrèdre (hypothèse 3D) M = cdmath.Matrix(4, 4) GradShapeFunc0 = cdmath.Vector(3) GradShapeFunc1 = cdmath.Vector(3) GradShapeFunc2 = cdmath.Vector(3) GradShapeFunc3 = cdmath.Vector(3) #On parcourt les tétraèdres du domaine pour remplir la matrice for i in range(nbCells): Ci = my_mesh.getCell(i) #Extraction des noeuds de la cellule nodeId0 = Ci.getNodeId(0) nodeId1 = Ci.getNodeId(1) nodeId2 = Ci.getNodeId(2) nodeId3 = Ci.getNodeId(3)
def solve(filename,resolution,meshType, testColor): start = time.time() test_desc["Mesh_type"]=meshType test_desc["Test_color"]=testColor #Chargement du maillage triangulaire de la sphère #======================================================================================= my_mesh = cdmath.Mesh(filename+".med") if(not my_mesh.isTriangular()) : raise ValueError("Wrong cell types : mesh is not made of triangles") if(my_mesh.getMeshDimension()!=2) : raise ValueError("Wrong mesh dimension : expected a surface of dimension 2") if(my_mesh.getSpaceDimension()!=3) : raise ValueError("Wrong space dimension : expected a space of dimension 3") nbNodes = my_mesh.getNumberOfNodes() nbCells = my_mesh.getNumberOfCells() test_desc["Space_dimension"]=my_mesh.getSpaceDimension() test_desc["Mesh_dimension"]=my_mesh.getMeshDimension() test_desc["Mesh_number_of_elements"]=my_mesh.getNumberOfNodes() test_desc["Mesh_cell_type"]=my_mesh.getElementTypes() print("Mesh building/loading done") print("nb of nodes=", nbNodes) print("nb of cells=", nbCells) #Discrétisation du second membre et détermination des noeuds intérieurs #====================================================================== my_RHSfield = cdmath.Field("RHS_field", cdmath.NODES, my_mesh, 1) maxNbNeighbours = 0#This is to determine the number of non zero coefficients in the sparse finite element rigidity matrix #parcours des noeuds pour discrétisation du second membre et extraction du nb max voisins d'un noeud for i in range(nbNodes): Ni=my_mesh.getNode(i) x = Ni.x() y = Ni.y() z = Ni.z() my_RHSfield[i]=12*y*(3*x*x-y*y)/pow(x*x+y*y+z*z,3/2)#vecteur propre du laplacien sur la sphère if my_mesh.isBorderNode(i): # Détection des noeuds frontière raise ValueError("Mesh should not contain borders") else: maxNbNeighbours = max(1+Ni.getNumberOfCells(),maxNbNeighbours) test_desc["Mesh_max_number_of_neighbours"]=maxNbNeighbours print("Right hand side discretisation done") print("Max nb of neighbours=", maxNbNeighbours) print("Integral of the RHS", my_RHSfield.integral(0)) # Construction de la matrice de rigidité et du vecteur second membre du système linéaire #======================================================================================= Rigidite=cdmath.SparseMatrixPetsc(nbNodes,nbNodes,maxNbNeighbours)# warning : third argument is number of non zero coefficients per line RHS=cdmath.Vector(nbNodes) # Vecteurs gradient de la fonction de forme associée à chaque noeud d'un triangle GradShapeFunc0=cdmath.Vector(3) GradShapeFunc1=cdmath.Vector(3) GradShapeFunc2=cdmath.Vector(3) normalFace0=cdmath.Vector(3) normalFace1=cdmath.Vector(3) #On parcourt les triangles du domaine for i in range(nbCells): Ci=my_mesh.getCell(i) #Contribution à la matrice de rigidité nodeId0=Ci.getNodeId(0) nodeId1=Ci.getNodeId(1) nodeId2=Ci.getNodeId(2) N0=my_mesh.getNode(nodeId0) N1=my_mesh.getNode(nodeId1) N2=my_mesh.getNode(nodeId2) #Build normal to cell Ci normalFace0[0]=Ci.getNormalVector(0,0) normalFace0[1]=Ci.getNormalVector(0,1) normalFace0[2]=Ci.getNormalVector(0,2) normalFace1[0]=Ci.getNormalVector(1,0) normalFace1[1]=Ci.getNormalVector(1,1) normalFace1[2]=Ci.getNormalVector(1,2) normalCell = normalFace0.crossProduct(normalFace1) test = normalFace0.tensProduct(normalFace1) normalCell = normalCell/normalCell.norm() cellMat=cdmath.Matrix(4) cellMat[0,0]=N0.x() cellMat[0,1]=N0.y() cellMat[0,2]=N0.z() cellMat[1,0]=N1.x() cellMat[1,1]=N1.y() cellMat[1,2]=N1.z() cellMat[2,0]=N2.x() cellMat[2,1]=N2.y() cellMat[2,2]=N2.z() cellMat[3,0]=normalCell[0] cellMat[3,1]=normalCell[1] cellMat[3,2]=normalCell[2] cellMat[0,3]=1 cellMat[1,3]=1 cellMat[2,3]=1 cellMat[3,3]=0 #Formule des gradients voir EF P1 -> calcul déterminants GradShapeFunc0[0]= cellMat.partMatrix(0,0).determinant()/2 GradShapeFunc0[1]=-cellMat.partMatrix(0,1).determinant()/2 GradShapeFunc0[2]= cellMat.partMatrix(0,2).determinant()/2 GradShapeFunc1[0]=-cellMat.partMatrix(1,0).determinant()/2 GradShapeFunc1[1]= cellMat.partMatrix(1,1).determinant()/2 GradShapeFunc1[2]=-cellMat.partMatrix(1,2).determinant()/2 GradShapeFunc2[0]= cellMat.partMatrix(2,0).determinant()/2 GradShapeFunc2[1]=-cellMat.partMatrix(2,1).determinant()/2 GradShapeFunc2[2]= cellMat.partMatrix(2,2).determinant()/2 #Création d'un tableau (numéro du noeud, gradient de la fonction de forme GradShapeFuncs={nodeId0 : GradShapeFunc0} GradShapeFuncs[nodeId1]=GradShapeFunc1 GradShapeFuncs[nodeId2]=GradShapeFunc2 # Remplissage de la matrice de rigidité et du second membre for j in [nodeId0,nodeId1,nodeId2] : #Ajout de la contribution de la cellule triangulaire i au second membre du noeud j RHS[j]=Ci.getMeasure()/3*my_RHSfield[j]+RHS[j] # intégrale dans le triangle du produit f x fonction de base #Contribution de la cellule triangulaire i à la ligne j du système linéaire for k in [nodeId0,nodeId1,nodeId2] : Rigidite.addValue(j,k,GradShapeFuncs[j]*GradShapeFuncs[k]/Ci.getMeasure()) print("Linear system matrix building done") # Résolution du système linéaire #================================= LS=cdmath.LinearSolver(Rigidite,RHS,100,1.E-2,"CG","ILU")#Remplacer CG par CHOLESKY pour solveur direct LS.isSingular()#En raison de l'absence de bord LS.setComputeConditionNumber() SolSyst=LS.solve() print "Preconditioner used : ", LS.getNameOfPc() print "Number of iterations used : ", LS.getNumberOfIter() print "Final residual : ", LS.getResidu() print("Linear system solved") test_desc["Linear_solver_algorithm"]=LS.getNameOfMethod() test_desc["Linear_solver_preconditioner"]=LS.getNameOfPc() test_desc["Linear_solver_precision"]=LS.getTolerance() test_desc["Linear_solver_maximum_iterations"]=LS.getNumberMaxOfIter() test_desc["Linear_system_max_actual_iterations_number"]=LS.getNumberOfIter() test_desc["Linear_system_max_actual_error"]=LS.getResidu() test_desc["Linear_system_max_actual_condition number"]=LS.getConditionNumber() # Création du champ résultat #=========================== my_ResultField = cdmath.Field("ResultField", cdmath.NODES, my_mesh, 1) for j in range(nbNodes): my_ResultField[j]=SolSyst[j];#remplissage des valeurs pour les noeuds intérieurs #sauvegarde sur le disque dur du résultat dans un fichier paraview my_ResultField.writeVTK("FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)) end = time.time() print("Integral of the numerical solution", my_ResultField.integral(0)) print("Numerical solution of poisson equation on a sphere using finite elements done") #Calcul de l'erreur commise par rapport à la solution exacte #=========================================================== #The following formulas use the fact that the exact solution is equal the right hand side divided by 12 max_abs_sol_exacte=0 erreur_abs=0 max_sol_num=0 min_sol_num=0 for i in range(nbNodes) : if max_abs_sol_exacte < abs(my_RHSfield[i]) : max_abs_sol_exacte = abs(my_RHSfield[i]) if erreur_abs < abs(my_RHSfield[i]/12 - my_ResultField[i]) : erreur_abs = abs(my_RHSfield[i]/12 - my_ResultField[i]) if max_sol_num < my_ResultField[i] : max_sol_num = my_ResultField[i] if min_sol_num > my_ResultField[i] : min_sol_num = my_ResultField[i] max_abs_sol_exacte = max_abs_sol_exacte/12 print("Absolute error = max(| exact solution - numerical solution |) = ",erreur_abs ) print("Relative error = max(| exact solution - numerical solution |)/max(| exact solution |) = ",erreur_abs/max_abs_sol_exacte) print ("Maximum numerical solution = ", max_sol_num, " Minimum numerical solution = ", min_sol_num) test_desc["Computational_time_taken_by_run"]=end-start test_desc["Absolute_error"]=erreur_abs test_desc["Relative_error"]=erreur_abs/max_abs_sol_exacte #Postprocessing : #================ # save 3D picture PV_routines.Save_PV_data_to_picture_file("FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)+'_0.vtu',"ResultField",'NODES',"FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)) # save 3D clip VTK_routines.Clip_VTK_data_to_VTK("FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)+'_0.vtu',"Clip_VTK_data_to_VTK_"+ "FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)+'_0.vtu',[0.25,0.25,0.25], [-0.5,-0.5,-0.5],resolution ) PV_routines.Save_PV_data_to_picture_file("Clip_VTK_data_to_VTK_"+"FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)+'_0.vtu',"ResultField",'NODES',"Clip_VTK_data_to_VTK_"+"FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)) # save plot around circumference finiteElementsOnSphere_0vtu = pvs.XMLUnstructuredGridReader(FileName=["FiniteElementsOnSpherePoisson_"+meshType+str(nbNodes)+'_0.vtu']) slice1 = pvs.Slice(Input=finiteElementsOnSphere_0vtu) slice1.SliceType.Normal = [0.5, 0.5, 0.5] renderView1 = pvs.GetActiveViewOrCreate('RenderView') finiteElementsOnSphere_0vtuDisplay = pvs.Show(finiteElementsOnSphere_0vtu, renderView1) pvs.ColorBy(finiteElementsOnSphere_0vtuDisplay, ('POINTS', 'ResultField')) slice1Display = pvs.Show(slice1, renderView1) pvs.SaveScreenshot("./FiniteElementsOnSpherePoisson"+"_Slice_"+meshType+str(nbNodes)+'.png', magnification=1, quality=100, view=renderView1) plotOnSortedLines1 = pvs.PlotOnSortedLines(Input=slice1) pvs.SaveData('./FiniteElementsOnSpherePoisson_PlotOnSortedLines'+meshType+str(nbNodes)+'.csv', proxy=plotOnSortedLines1) lineChartView2 = pvs.CreateView('XYChartView') plotOnSortedLines1Display = pvs.Show(plotOnSortedLines1, lineChartView2) plotOnSortedLines1Display.UseIndexForXAxis = 0 plotOnSortedLines1Display.XArrayName = 'arc_length' plotOnSortedLines1Display.SeriesVisibility = ['ResultField (1)'] pvs.SaveScreenshot("./FiniteElementsOnSpherePoisson"+"_PlotOnSortedLine_"+meshType+str(nbNodes)+'.png', magnification=1, quality=100, view=lineChartView2) pvs.Delete(lineChartView2) with open('test_Poisson'+str(my_mesh.getMeshDimension())+'D_EF_'+meshType+str(nbCells)+ "Cells.json", 'w') as outfile: json.dump(test_desc, outfile) return erreur_abs/max_abs_sol_exacte, nbNodes, min_sol_num, max_sol_num, end - start
def solve(filename, resolution, meshType, testColor): start = time.time() test_desc["Mesh_type"] = meshType test_desc["Test_color"] = testColor #Chargement du maillage triangulaire du domaine carré [0,1]x[0,1], définition des bords #======================================================================================= my_mesh = cdmath.Mesh(filename + ".med") if (my_mesh.getSpaceDimension() != 2 or my_mesh.getMeshDimension() != 2): raise ValueError( "Wrong space or mesh dimension : space and mesh dimensions should be 2" ) if (not my_mesh.isTriangular()): raise ValueError("Wrong cell types : mesh is not made of triangles") eps = 1e-6 my_mesh.setGroupAtPlan(0., 0, eps, "DirichletBorder") #Bord GAUCHE my_mesh.setGroupAtPlan(1., 0, eps, "DirichletBorder") #Bord DROIT my_mesh.setGroupAtPlan(0., 1, eps, "DirichletBorder") #Bord BAS my_mesh.setGroupAtPlan(1., 1, eps, "DirichletBorder") #Bord HAUT nbNodes = my_mesh.getNumberOfNodes() nbCells = my_mesh.getNumberOfCells() test_desc["Space_dimension"] = my_mesh.getSpaceDimension() test_desc["Mesh_dimension"] = my_mesh.getMeshDimension() test_desc["Mesh_number_of_elements"] = my_mesh.getNumberOfNodes() test_desc["Mesh_cell_type"] = my_mesh.getElementTypesNames() print("Mesh loading done") print("Number of nodes=", nbNodes) print("Number of cells=", nbCells) #Discrétisation du second membre et détermination des noeuds intérieurs #====================================================================== dim = my_mesh.getSpaceDimension() K = 10 ^ 4 my_RHSfield = cdmath.Field("RHS_field", cdmath.NODES, my_mesh, 1) nbInteriorNodes = 0 nbBoundaryNodes = 0 maxNbNeighbours = 0 #This is to determine the number of non zero coefficients in the sparse finite element rigidity matrix interiorNodes = [] boundaryNodes = [] #parcours des noeuds pour discrétisation du second membre et extraction 1) des noeuds intérieur 2) des noeuds frontière 3) du nb max voisins d'un noeud for i in range(nbNodes): Ni = my_mesh.getNode(i) x = Ni.x() y = Ni.y() my_RHSfield[i] = (1 + K) * pi * pi * sin(pi * x) * sin( pi * y) #mettre la fonction definie au second membre de l'edp if my_mesh.isBorderNode(i): # Détection des noeuds frontière boundaryNodes.append(i) nbBoundaryNodes = nbBoundaryNodes + 1 else: # Détection des noeuds intérieurs interiorNodes.append(i) nbInteriorNodes = nbInteriorNodes + 1 maxNbNeighbours = max( 1 + Ni.getNumberOfCells(), maxNbNeighbours ) #true only in 2D, need a function Ni.getNumberOfNeighbourNodes() test_desc["Mesh_max_number_of_neighbours"] = maxNbNeighbours print("Right hand side discretisation done") print("Number of interior nodes=", nbInteriorNodes) print("Number of boundary nodes=", nbBoundaryNodes) print("Max number of neighbours=", maxNbNeighbours) # Construction de la matrice de rigidité et du vecteur second membre du système linéaire #======================================================================================= DiffusionMatrix = cdmath.Matrix(dim, dim) DiffusionMatrix[0, 0] = 1 DiffusionMatrix[0, 1] = 0 DiffusionMatrix[1, 0] = 0 DiffusionMatrix[1, 1] = K Rigidite = cdmath.SparseMatrixPetsc( nbInteriorNodes, nbInteriorNodes, maxNbNeighbours ) # warning : third argument is maximum number of non zero coefficients per line of the matrix RHS = cdmath.Vector(nbInteriorNodes) # Vecteurs gradient de la fonction de forme associée à chaque noeud d'un triangle (hypothèse 2D) GradShapeFunc0 = cdmath.Vector(2) GradShapeFunc1 = cdmath.Vector(2) GradShapeFunc2 = cdmath.Vector(2) #On parcourt les triangles du domaine for i in range(nbCells): Ci = my_mesh.getCell(i) #Contribution à la matrice de rigidité nodeId0 = Ci.getNodeId(0) nodeId1 = Ci.getNodeId(1) nodeId2 = Ci.getNodeId(2) N0 = my_mesh.getNode(nodeId0) N1 = my_mesh.getNode(nodeId1) N2 = my_mesh.getNode(nodeId2) #Formule des gradients voir EF P1 -> calcul déterminants GradShapeFunc0[0] = (N1.y() - N2.y()) / 2 GradShapeFunc0[1] = -(N1.x() - N2.x()) / 2 GradShapeFunc1[0] = -(N0.y() - N2.y()) / 2 GradShapeFunc1[1] = (N0.x() - N2.x()) / 2 GradShapeFunc2[0] = (N0.y() - N1.y()) / 2 GradShapeFunc2[1] = -(N0.x() - N1.x()) / 2 #Création d'un tableau (numéro du noeud, gradient de la fonction de forme GradShapeFuncs = {nodeId0: GradShapeFunc0} GradShapeFuncs[nodeId1] = GradShapeFunc1 GradShapeFuncs[nodeId2] = GradShapeFunc2 # Remplissage de la matrice de rigidité et du second membre for j in [nodeId0, nodeId1, nodeId2]: if boundaryNodes.count( j ) == 0: #seuls les noeuds intérieurs contribuent au système linéaire (matrice de rigidité et second membre) j_int = interiorNodes.index( j) #indice du noeud j en tant que noeud intérieur #Ajout de la contribution de la cellule triangulaire i au second membre du noeud j RHS[j_int] = Ci.getMeasure() / 3 * my_RHSfield[j] + RHS[ j_int] # intégrale dans le triangle du produit f x fonction de base #Contribution de la cellule triangulaire i à la ligne j_int du système linéaire for k in [nodeId0, nodeId1, nodeId2]: if boundaryNodes.count( k ) == 0: #seuls les noeuds intérieurs contribuent à la matrice du système linéaire k_int = interiorNodes.index( k) #indice du noeud k en tant que noeud intérieur Rigidite.addValue( j_int, k_int, GradShapeFuncs[j] * (DiffusionMatrix * GradShapeFuncs[k]) / Ci.getMeasure()) #else: si condition limite non nulle au bord, ajouter la contribution du bord au second membre de la cellule j print("Linear system matrix building done") # Résolution du système linéaire #================================= LS = cdmath.LinearSolver( Rigidite, RHS, 100, 1.E-6, "CG", "ILU") #Remplacer CG par CHOLESKY pour solveur direct LS.setComputeConditionNumber() SolSyst = LS.solve() print("Preconditioner used : ", LS.getNameOfPc()) print("Number of iterations used : ", LS.getNumberOfIter()) print("Linear system solved") test_desc["Linear_solver_algorithm"] = LS.getNameOfMethod() test_desc["Linear_solver_preconditioner"] = LS.getNameOfPc() test_desc["Linear_solver_precision"] = LS.getTolerance() test_desc["Linear_solver_maximum_iterations"] = LS.getNumberMaxOfIter() test_desc[ "Linear_system_max_actual_iterations_number"] = LS.getNumberOfIter() test_desc["Linear_system_max_actual_error"] = LS.getResidu() test_desc[ "Linear_system_max_actual_condition number"] = LS.getConditionNumber() # Création du champ résultat #=========================== my_ResultField = cdmath.Field("ResultField", cdmath.NODES, my_mesh, 1) for j in range(nbInteriorNodes): my_ResultField[interiorNodes[j]] = SolSyst[j] #remplissage des valeurs pour les noeuds intérieurs for j in range(nbBoundaryNodes): my_ResultField[boundaryNodes[j]] = 0 #remplissage des valeurs pour les noeuds frontière (condition limite) #sauvegarde sur le disque dur du résultat dans un fichier paraview my_ResultField.writeVTK("FiniteElements2DAnisotropicDiffusion_SQUARE_" + meshType + str(nbNodes)) print( "Numerical solution of 2D anisotropic diffusion on a square using finite elements done" ) end = time.time() #Calcul de l'erreur commise par rapport à la solution exacte #=========================================================== #The following formulas use the fact that the exact solution is equal to the right hand side divided by (1+K)*pi*pi max_abs_sol_exacte = max(my_RHSfield.max(), -my_RHSfield.min()) / ( (1 + K) * pi * pi) max_sol_num = my_ResultField.max() min_sol_num = my_ResultField.min() erreur_abs = 0 for i in range(nbNodes): if erreur_abs < abs(my_RHSfield[i] / ((1 + K) * pi * pi) - my_ResultField[i]): erreur_abs = abs(my_RHSfield[i] / ((1 + K) * pi * pi) - my_ResultField[i]) print( "Relative error = max(| exact solution - numerical solution |)/max(| exact solution |) = ", erreur_abs / max_abs_sol_exacte) print("Maximum numerical solution = ", max_sol_num, " Minimum numerical solution = ", min_sol_num) #Postprocessing : #================ # Extraction of the diagonal data diag_data = VTK_routines.Extract_field_data_over_line_to_numpyArray( my_ResultField, [0, 1, 0], [1, 0, 0], resolution) # save 2D picture PV_routines.Save_PV_data_to_picture_file( "FiniteElements2DAnisotropicDiffusion_SQUARE_" + meshType + str(nbNodes) + '_0.vtu', "ResultField", 'NODES', "FiniteElements2DAnisotropicDiffusion_SQUARE_" + meshType + str(nbNodes)) test_desc["Computational_time_taken_by_run"] = end - start test_desc["Absolute_error"] = erreur_abs test_desc["Relative_error"] = erreur_abs / max_abs_sol_exacte with open( 'test_Diffusion' + str(my_mesh.getMeshDimension()) + 'D_EF_' + "SQUARE_" + meshType + str(nbCells) + "Cells.json", 'w') as outfile: json.dump(test_desc, outfile) return erreur_abs / max_abs_sol_exacte, nbNodes, diag_data, min_sol_num, max_sol_num, end - start
else: # Détection des noeuds intérieurs interiorNodes.append(i) nbInteriorNodes=nbInteriorNodes+1 maxNbNeighbours= max(1+Ni.getNumberOfCells(),maxNbNeighbours) #true only in 2D, otherwise use function Ni.getNumberOfEdges() print("Right hand side discretisation done") print("Number of interior nodes=", nbInteriorNodes) print("Number of boundary nodes=", nbBoundaryNodes) print("Maximum number of neighbours=", maxNbNeighbours) # Construction de la matrice de rigidité et du vecteur second membre du système linéaire #======================================================================================= Rigidite=cdmath.SparseMatrixPetsc(nbInteriorNodes,nbInteriorNodes,maxNbNeighbours)# warning : third argument is max number of non zero coefficients per line of the matrix RHS=cdmath.Vector(nbInteriorNodes) M=cdmath.Matrix(3,3) # Vecteurs gradient de la fonction de forme associée à chaque noeud d'un triangle (hypothèse 2D) GradShapeFunc0=cdmath.Vector(2) GradShapeFunc1=cdmath.Vector(2) GradShapeFunc2=cdmath.Vector(2) #On parcourt les triangles du domaine for i in range(nbCells): Ci=my_mesh.getCell(i) #Contribution à la matrice de rigidité nodeId0=Ci.getNodeId(0) nodeId1=Ci.getNodeId(1) nodeId2=Ci.getNodeId(2)
N1 = my_mesh.getNode(nodeId1) N2 = my_mesh.getNode(nodeId2) #Build normal to cell Ci normalFace0[0] = Ci.getNormalVector(0, 0) normalFace0[1] = Ci.getNormalVector(0, 1) normalFace0[2] = Ci.getNormalVector(0, 2) normalFace1[0] = Ci.getNormalVector(1, 0) normalFace1[1] = Ci.getNormalVector(1, 1) normalFace1[2] = Ci.getNormalVector(1, 2) normalCell = normalFace0.crossProduct(normalFace1) test = normalFace0.tensProduct(normalFace1) normalCell = normalCell / normalCell.norm() cellMat = cdmath.Matrix(4) cellMat[0, 0] = N0.x() cellMat[0, 1] = N0.y() cellMat[0, 2] = N0.z() cellMat[1, 0] = N1.x() cellMat[1, 1] = N1.y() cellMat[1, 2] = N1.z() cellMat[2, 0] = N2.x() cellMat[2, 1] = N2.y() cellMat[2, 2] = N2.z() cellMat[3, 0] = normalCell[0] cellMat[3, 1] = normalCell[1] cellMat[3, 2] = normalCell[2] cellMat[0, 3] = 1 cellMat[1, 3] = 1 cellMat[2, 3] = 1