def upwindSchemeMatrix(nx,cfl): upwindMat=cdmath.SparseMatrixPetsc(nx,nx,2) for i in range(nx): upwindMat.setValue(i,i,1+cfl) upwindMat.setValue(i,(i-1)%nx,-cfl) return upwindMat
def centeredSchemeMatrix(nx,cfl): centeredMat=cdmath.SparseMatrixPetsc(nx,nx,2) for i in range(nx): centeredMat.setValue(i,i,1+cfl) centeredMat.setValue(i,(i-1)%nx,-cfl) return centeredMat
def computeStaggeredDivergenceMatrix(a, b, nx, nbVoisinsMax, dt, scaling): nbCells = nx dx = (b - a) / nx dim = 1 nbComp = dim + 1 normal = cdmath.Vector(dim) implMat = cdmath.SparseMatrixPetsc(nbCells * nbComp, nbCells * nbComp, (nbVoisinsMax + 1) * nbComp) S1, S2 = staggeredMatrices(dt / dx, scaling) for k in range(nbCells): #On parcourt les cellules if (k == 0): implMat.addValue(k * nbComp, (k + 1) * nbComp, S1) implMat.addValue(k * nbComp, k * nbComp, S1 * (-1.)) elif (k == nbCells - 1): implMat.addValue(k * nbComp, k * nbComp, S2) implMat.addValue(k * nbComp, (k - 1) * nbComp, S2 * (-1.)) else: implMat.addValue(k * nbComp, (k + 1) * nbComp, S1) implMat.addValue(k * nbComp, k * nbComp, S1 * (-1.)) implMat.addValue(k * nbComp, k * nbComp, S2) implMat.addValue(k * nbComp, (k - 1) * nbComp, S2 * (-1.)) return implMat
def computeUpwindDivergenceMatrix(a,b,nx,nbVoisinsMax,dt,scaling): nbCells = nx dx=(b-a)/nx dim=1 nbComp=dim+1 normal=cdmath.Vector(dim) implMat=cdmath.SparseMatrixPetsc(nbCells*nbComp,nbCells*nbComp,(nbVoisinsMax+1)*nbComp) A,absA= jacobianMatrices(dt/dx,scaling) for j in range(nbCells):#On parcourt les cellules if ( j==0) : implMat.addValue(j*nbComp,(j+1)*nbComp,(A-absA)/2) implMat.addValue(j*nbComp, j*nbComp,(A-absA)/2*(-1.)) elif ( j==nbCells-1) : implMat.addValue(j*nbComp, j*nbComp,(A+absA)/2) implMat.addValue(j*nbComp,(j-1)*nbComp,(A+absA)/2*(-1.)) else : implMat.addValue(j*nbComp,(j+1)*nbComp,(A-absA)/2) implMat.addValue(j*nbComp, j*nbComp,(A-absA)/2*(-1.)) implMat.addValue(j*nbComp, j*nbComp,(A+absA)/2) implMat.addValue(j*nbComp,(j-1)*nbComp,(A+absA)/2*(-1.)) return implMat
def computeDivergenceMatrix(my_mesh, nbVoisinsMax, dt, test_bc, velocity): nbCells = my_mesh.getNumberOfCells() dim = my_mesh.getMeshDimension() nbComp = 1 normal = cdmath.Vector(dim) implMat = cdmath.SparseMatrixPetsc(nbCells * nbComp, nbCells * nbComp, (nbVoisinsMax + 1) * 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 = upwinding_coeff(normal, dt * Fk.getMeasure() / Cj.getMeasure(), velocity) 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() != "Neumann" ): #Periodic boundary condition unless Wall/Neumann specified explicitly 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.)) 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 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 implicitSchemeMatrix(nx, cfl): implMat = cdmath.SparseMatrixPetsc(nx, nx, 3) for i in range(nx): implMat.setValue(i, (i + 1) % nx, -cfl) implMat.setValue(i, i, 1. + 2 * cfl) implMat.setValue(i, (i - 1) % nx, -cfl) return implMat
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 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 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
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) # 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)
def solve(my_mesh, filename, resolution, meshType, testColor): start = time.time() test_desc["Mesh_type"] = meshType test_desc["Test_color"] = testColor nbCells = my_mesh.getNumberOfCells() if (my_mesh.getSpaceDimension() != 2 or my_mesh.getMeshDimension() != 2): raise ValueError( "Wrong space or mesh dimension : space and mesh dimensions should be 2" ) test_desc["Space_dimension"] = my_mesh.getSpaceDimension() test_desc["Mesh_dimension"] = my_mesh.getMeshDimension() test_desc["Mesh_number_of_elements"] = my_mesh.getNumberOfCells() test_desc["Mesh_cell_type"] = my_mesh.getElementTypesNames() print("Mesh groups done") print("Number of cells = ", nbCells) #Discrétisation du second membre et extraction du nb max de voisins d'une cellule #================================================================================ my_RHSfield = cdmath.Field("RHS_field", cdmath.CELLS, my_mesh, 1) maxNbNeighbours = 0 #This is to determine the number of non zero coefficients in the sparse finite element rigidity matrix #parcours des cellules pour discrétisation du second membre et extraction du nb max de voisins d'une cellule for i in range(nbCells): Ci = my_mesh.getCell(i) x = Ci.x() y = Ci.y() my_RHSfield[i] = 2 * pi * pi * sin(pi * x) * sin( pi * y) #mettre la fonction definie au second membre de l edp # compute maximum number of neighbours maxNbNeighbours = max(1 + Ci.getNumberOfFaces(), maxNbNeighbours) test_desc["Mesh_max_number_of_neighbours"] = maxNbNeighbours print("Right hand side discretisation done") print("Max nb of neighbours=", maxNbNeighbours) # Construction de la matrice et du vecteur second membre du système linéaire #=========================================================================== Rigidite = cdmath.SparseMatrixPetsc( nbCells, nbCells, maxNbNeighbours ) # warning : third argument is maximum number of non zero coefficients per line of the matrix RHS = cdmath.Vector(nbCells) #Parcours des cellules du domaine for i in range(nbCells): RHS[i] = my_RHSfield[ i] #la valeur moyenne du second membre f dans la cellule i Ci = my_mesh.getCell(i) for j in range(Ci.getNumberOfFaces()): # parcours des faces voisinnes Fj = my_mesh.getFace(Ci.getFaceId(j)) if not Fj.isBorder(): k = Fj.getCellId(0) if k == i: k = Fj.getCellId(1) Ck = my_mesh.getCell(k) distance = Ci.getBarryCenter().distance(Ck.getBarryCenter()) coeff = Fj.getMeasure() / Ci.getMeasure() / distance Rigidite.setValue(i, k, -coeff) # terme extradiagonal else: coeff = Fj.getMeasure() / Ci.getMeasure() / Ci.getBarryCenter( ).distance(Fj.getBarryCenter()) #For the particular case where the mesh boundary does not coincide with the domain boundary x = Fj.getBarryCenter().x() y = Fj.getBarryCenter().y() RHS[i] += coeff * sin(pi * x) * sin( pi * y ) #mettre ici la condition limite du problème de Dirichlet Rigidite.addValue(i, i, coeff) # terme diagonal print("Linear system matrix building done") # Résolution du système linéaire #================================= LS = cdmath.LinearSolver(Rigidite, RHS, 500, 1.E-6, "CG", "LU") 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.CELLS, my_mesh, 1) for i in range(nbCells): my_ResultField[i] = SolSyst[i] #sauvegarde sur le disque dur du résultat dans un fichier paraview my_ResultField.writeVTK("FiniteVolumes2DPoisson_SQUARE_" + meshType + str(nbCells)) print( "Numerical solution of 2D Poisson equation 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 the right hand side divided by 2*pi*pi max_abs_sol_exacte = max(my_RHSfield.max(), -my_RHSfield.min()) / (2 * pi * pi) max_sol_num = my_ResultField.max() min_sol_num = my_ResultField.min() erreur_abs = 0 for i in range(nbCells): if erreur_abs < abs(my_RHSfield[i] / (2 * pi * pi) - my_ResultField[i]): erreur_abs = abs(my_RHSfield[i] / (2 * 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( "FiniteVolumes2DPoisson_SQUARE_" + meshType + str(nbCells) + '_0.vtu', "ResultField", 'CELLS', "FiniteVolumes2DPoisson_SQUARE_" + meshType + str(nbCells)) 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_Poisson' + str(my_mesh.getMeshDimension()) + 'D_VF_' + str(nbCells) + "Cells.json", 'w') as outfile: json.dump(test_desc, outfile) return erreur_abs / max_abs_sol_exacte, nbCells, diag_data, min_sol_num, max_sol_num, end - start
phi=atan2(y,x) exactSolField[i] = sin(3*phi)*cos(3*theta+ phi) # for the exact solution we use the funtion given in the article of Olshanskii, Reusken 2009, page 19 my_RHSfield[i] = 9*sin(3*phi)*cos(3*theta+ phi)/(r*r) + (10*sin(3*phi)*cos(3*theta+ phi) + 6*cos(3*phi)*sin(3*theta+ phi))/((R+r*cos(theta))*(R+r*cos(theta))) - 3*sin(theta)*sin(3*phi)*sin(3*theta+ phi)/(r*(R+r*cos(theta))) #for the right hand side we use the function given in the article of Olshanskii, Reusken 2009, page 19 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)#true only for planar cells, otherwise use function Ni.getNumberOfEdges() 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) 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)
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
def solve(my_mesh, filename, resolution, meshType, testColor): start = time.time() test_desc["Mesh_type"] = meshType test_desc["Test_color"] = testColor nbCells = my_mesh.getNumberOfCells() if (my_mesh.getSpaceDimension() != 2 or my_mesh.getMeshDimension() != 2): raise ValueError( "Wrong space or mesh dimension : space and mesh dimensions should be 2" ) test_desc["Space_dimension"] = my_mesh.getSpaceDimension() test_desc["Mesh_dimension"] = my_mesh.getMeshDimension() test_desc["Mesh_number_of_elements"] = my_mesh.getNumberOfCells() test_desc["Mesh_cell_type"] = my_mesh.getElementTypesNames() print("Mesh groups done") print("Number of cells = ", nbCells) #Discrétisation du second membre et extraction du nb max de voisins d'une cellule #================================================================================ my_ExactSol = cdmath.Field("Exact_field", cdmath.CELLS, my_mesh, 1) maxNbNeighbours = 0 #This is to determine the number of non zero coefficients in the sparse finite element rigidity matrix eps = 1e-6 #For coarse meshes #parcours des cellules pour discrétisation du second membre et extraction du nb max de voisins d'une cellule for i in range(nbCells): Ci = my_mesh.getCell(i) x = Ci.x() y = Ci.y() #Robust calculation of atan(2x/(x**2+y**2-1) if x**2 + y**2 - 1 > eps: print("!!! Warning Mesh ", meshType, " !!! Cell is not in the unit disk.", ", eps=", eps, ", x**2+y**2 - 1=", x**2 + y**2 - 1) #raise ValueError("Exact solution computation !!! 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 # compute maximum number of neighbours maxNbNeighbours = max(1 + Ci.getNumberOfFaces(), maxNbNeighbours) test_desc["Mesh_max_number_of_neighbours"] = maxNbNeighbours print("Right hand side discretisation done") print("Max nb of neighbours=", maxNbNeighbours) # Construction de la matrice et du vecteur second membre du système linéaire #=========================================================================== Rigidite = cdmath.SparseMatrixPetsc( nbCells, nbCells, maxNbNeighbours ) # warning : third argument is maximum number of non zero coefficients per line of the matrix RHS = cdmath.Vector(nbCells) #Parcours des cellules du domaine for i in range(nbCells): Ci = my_mesh.getCell(i) for j in range(Ci.getNumberOfFaces()): # parcours des faces voisinnes Fj = my_mesh.getFace(Ci.getFaceId(j)) if not Fj.isBorder(): k = Fj.getCellId(0) if k == i: k = Fj.getCellId(1) Ck = my_mesh.getCell(k) distance = Ci.getBarryCenter().distance(Ck.getBarryCenter()) coeff = Fj.getMeasure() / Ci.getMeasure() / distance Rigidite.setValue(i, k, -coeff) # terme extradiagonal else: coeff = Fj.getMeasure() / Ci.getMeasure() / Ci.getBarryCenter( ).distance(Fj.getBarryCenter()) #For the particular case where the mesh boundary does not coincide with the domain boundary x = Fj.getBarryCenter().x() y = Fj.getBarryCenter().y() if x**2 + y**2 - 1 > eps: print("!!! Warning Mesh ", meshType, " !!! Face 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: RHS[i] += coeff * atan(2 * x / (x**2 + y**2 - 1)) elif x > 0: #x**2+y**2-1>=0 RHS[i] += coeff * (-pi / 2) elif x < 0: #x**2+y**2-1>=0 RHS[i] += coeff * pi / 2 else: #x=0 RHS[i] += 0 Rigidite.addValue(i, i, coeff) # terme diagonal print("Linear system matrix building done") # Résolution du système linéaire #================================= LS = cdmath.LinearSolver(Rigidite, RHS, 500, 1.E-6, "CG", "LU") 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.CELLS, my_mesh, 1) for i in range(nbCells): my_ResultField[i] = SolSyst[i] #sauvegarde sur le disque dur du résultat dans un fichier paraview my_ResultField.writeVTK("FiniteVolumes2DPoissonStiffBC_DISK_" + meshType + str(nbCells)) my_ExactSol.writeVTK("ExactSol2DPoissonStiffBC_DISK_" + meshType + str(nbCells)) print( "Numerical solution of 2D Poisson equation on a disk using finite volumes 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( "FiniteVolumes2DPoissonStiffBC_DISK_" + meshType + str(nbCells) + '_0.vtu', "ResultField", 'CELLS', "FiniteVolumes2DPoissonStiffBC_DISK_" + meshType + str(nbCells)) PV_routines.Save_PV_data_to_picture_file( "ExactSol2DPoissonStiffBC_DISK_" + meshType + str(nbCells) + '_0.vtu', "Exact_field", 'CELLS', "ExactSol2DPoissonStiffBC_DISK_" + meshType + str(nbCells)) 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_VF_' + "DISK_" + str(nbCells) + "Cells.json", 'w') as outfile: json.dump(test_desc, outfile) return l2_error / l2_norm_sol_exacte, nbCells, diag_data, my_ResultField.min( ), my_ResultField.max(), 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.getElementTypes() 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 #====================================================================== 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]=2*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 #======================================================================================= 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]*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("FiniteElements2DPoisson_SQUARE_"+meshType+str(nbNodes)) print("Numerical solution of 2D Poisson equation 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 the right hand side divided by 2*pi*pi max_abs_sol_exacte=max(my_RHSfield.max(),-my_RHSfield.min())/(2*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]/(2*pi*pi) - my_ResultField[i]) : erreur_abs = abs(my_RHSfield[i]/(2*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("FiniteElements2DPoisson_SQUARE_"+meshType+str(nbNodes)+'_0.vtu',"ResultField",'NODES',"FiniteElements2DPoisson_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_Poisson'+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
def EulerSystemVF(ntmax, tmax, cfl, my_mesh, output_freq, filename, resolution, isImplicit): dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() meshName = my_mesh.getName() dt = 0. time = 0. it = 0 isStationary = False nbVoisinsMax = my_mesh.getMaxNbNeighbours(cdmath.CELLS) # Initial conditions # print("Construction of the initial condition …") if (dim == 1 or filename.find("square") > -1 or filename.find("Square") > -1 or filename.find("cube") > -1 or filename.find("Cube") > -1): pressure_field, velocity_field = initial_conditions_shock( my_mesh, False) elif (filename.find("disk") > -1 or filename.find("Disk") > -1): pressure_field, velocity_field = initial_conditions_shock( my_mesh, True) else: print "Mesh name : ", filename raise ValueError( "Mesh name should contain substring square, cube or disk") #iteration vectors Un = cdmath.Vector(nbCells * (dim + 1)) dUn = cdmath.Vector(nbCells * (dim + 1)) for k in range(nbCells): Un[k * (dim + 1) + 0] = pressure_field[k] Un[k * (dim + 1) + 1] = rho0 * velocity_field[k, 0] if (dim >= 2): Un[k + 2 * nbCells] = rho0 * velocity_field[k, 1] # value on the bottom face if (dim == 3): Un[k + 3 * nbCells] = rho0 * initial_velocity[k, 2] #sauvegarde de la donnée initiale pressure_field.setTime(time, it) pressure_field.writeVTK("EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_pressure") velocity_field.setTime(time, it) velocity_field.writeVTK("EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_velocity") dx_min = my_mesh.minRatioVolSurf() divMat = cdmath.SparseMatrixPetsc(nbCells * (1 + dim), nbCells * (1 + dim), (nbVoisinsMax + 1) * (1 + dim)) if (isImplicit): iterGMRESMax = 50 LS = cdmath.LinearSolver(divMat, Un, iterGMRESMax, precision, "GMRES", "ILU") print( "Starting computation of the linear wave system with an explicit UPWIND scheme …" ) # Starting time loop while (it < ntmax and time <= tmax and not isStationary): divMat.zeroEntries() #sets the matrix coefficients to zero vp_max = computeDivergenceMatrix(my_mesh, divMat, Un) #To update at each time step dt = cfl * dx_min / vp_max #To update at each time step if (isImplicit): #Adding the identity matrix on the diagonal divMat.diagonalShift(1) #only after filling all coefficients dUn = Un.deepCopy() LS.setSndMember(Un) Un = LS.solve() if (not LS.getStatus()): print "Linear system did not converge ", LS.getNumberOfIter( ), " GMRES iterations" raise ValueError("Pas de convergence du système linéaire") dUn -= Un else: dUn = divMat * Un Un -= dUn time = time + dt it = it + 1 #Sauvegardes if (it % output_freq == 0 or it >= ntmax or isStationary or time >= tmax): print("-- Iter: " + str(it) + ", Time: " + str(time) + ", dt: " + str(dt)) for k in range(nbCells): pressure_field[k] = Un[k * (dim + 1) + 0] velocity_field[k, 0] = Un[k * (dim + 1) + 1] / rho0 if (dim > 1): velocity_field[k, 1] = Un[k * (dim + 1) + 2] / rho0 if (dim > 2): velocity_field[k, 2] = Un[k * (dim + 1) + 3] / rho0 pressure_field.setTime(time, it) pressure_field.writeVTK( "EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_pressure", False) velocity_field.setTime(time, it) velocity_field.writeVTK( "EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_velocity", False) print("-- Iter: " + str(it) + ", Time: " + str(time) + ", dt: " + str(dt)) print if (it >= ntmax): print "Nombre de pas de temps maximum ntmax= ", ntmax, " atteint" elif (isStationary): print "Régime stationnaire atteint au pas de temps ", it, ", t= ", time pressure_field.setTime(time, 0) pressure_field.writeVTK("EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_pressure_Stat") velocity_field.setTime(time, 0) velocity_field.writeVTK("EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_velocity_Stat") #Postprocessing : Extraction of the diagonal data diag_data_press = VTK_routines.Extract_field_data_over_line_to_numpyArray( pressure_field, [0, 1, 0], [1, 0, 0], resolution) diag_data_vel = VTK_routines.Extract_field_data_over_line_to_numpyArray( velocity_field, [0, 1, 0], [1, 0, 0], resolution) #Postprocessing : save 2D picture PV_routines.Save_PV_data_to_picture_file( "EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_pressure_Stat" + '_0.vtu', "Pressure", 'CELLS', "EulerSystem" + str(dim) + "DUpwind" + meshName + "_pressure_Stat") PV_routines.Save_PV_data_to_picture_file( "EulerSystem" + str(dim) + "DUpwind" + "_isImplicit" + str(isImplicit) + meshName + "_velocity_Stat" + '_0.vtu', "Velocity", 'CELLS', "EulerSystem" + str(dim) + "DUpwind" + meshName + "_velocity_Stat") else: print "Temps maximum Tmax= ", tmax, " atteint"