def initial_conditions_wave_system(my_mesh): dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() if (dim != 1): raise ValueError( "initial_conditions_wave_system: Mesh dimension should be 1") pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, dim) U = cdmath.Field("Conservative vector", cdmath.CELLS, my_mesh, dim + 1) for i in range(nbCells): x = my_mesh.getCell(i).x() pressure_field[i] = p0 if (x > 0.5): velocity_field[i, 0] = 1 else: velocity_field[i, 0] = -1 U[i, 0] = p0 U[i, 1] = rho0 * velocity_field[i, 0] return U, pressure_field, velocity_field
def initial_conditions_wave_system(my_mesh): test_desc["Initial_data"]="Constant pressure, divergence free velocity" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for i in range(nbCells): x = my_mesh.getCell(i).x() y = my_mesh.getCell(i).y() pressure_field[i] = p0 if(dim==1): velocity_field[i,0] = 1 velocity_field[i,1] = 0 velocity_field[i,2] = 0 elif(dim==2): velocity_field[i,0] = sin(pi*x)*cos(pi*y) velocity_field[i,1] = -sin(pi*y)*cos(pi*x) velocity_field[i,2] = 0 elif(dim==3): z = my_mesh.getCell(i).z() velocity_field[i,0] = sin(pi*x)*cos(pi*y)*cos(pi*z) velocity_field[i,1] = sin(pi*y)*cos(pi*x)*cos(pi*z) velocity_field[i,2] = -2*sin(pi*z)*cos(pi*x)*cos(pi*y) return pressure_field, velocity_field
def initial_conditions_square_vortex(my_mesh): print "Initial data : Square vortex (Constant pressure, divergence free velocity)" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for i in range(nbCells): x = my_mesh.getCell(i).x() y = my_mesh.getCell(i).y() z = my_mesh.getCell(i).z() pressure_field[i] = p0 if(dim==1): velocity_field[i,0] = 1 velocity_field[i,1] = 0 velocity_field[i,2] = 0 elif(dim==2): velocity_field[i,0] = sin(pi*x)*cos(pi*y) velocity_field[i,1] = -sin(pi*y)*cos(pi*x) velocity_field[i,2] = 0 elif(dim==3): velocity_field[i,0] = sin(pi*x)*cos(pi*y)*cos(pi*z) velocity_field[i,1] = sin(pi*y)*cos(pi*x)*cos(pi*z) velocity_field[i,2] = -2*sin(pi*z)*cos(pi*x)*cos(pi*y) return pressure_field, velocity_field
def initial_conditions_RiemannProblem(my_mesh): print "Initial data : Riemann problem" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() xcentre = 0 pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for i in range(nbCells): x = my_mesh.getCell(i).x() velocity_field[i, 0] = 0 velocity_field[i, 1] = 0 velocity_field[i, 2] = 0 if x < xcentre: pressure_field[i] = p0 pass else: pressure_field[i] = p0 / 2 pass pass return pressure_field, velocity_field
def source_term_and_stat_solution_wave_system(my_mesh): test_desc["Source_term"] = "True" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() source_vector = cdmath.Vector(nbCells * (dim + 1)) stat_pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) stat_momentum_field = cdmath.Field("Momentum", cdmath.CELLS, my_mesh, 3) for k in range(nbCells): x = my_mesh.getCell(k).x() y = my_mesh.getCell(k).y() z = my_mesh.getCell(k).z() if (dim == 1): source_vector[k * (dim + 1) + 0] = -2 * c0 * c0 * sign(x - 1. / 2) source_vector[k * (dim + 1) + 1] = 0 stat_pressure_field[k] = abs(x - 1. / 2) * (x - 1. / 2) stat_momentum_field[k, 0] = -2 * abs(x - 1. / 2) stat_momentum_field[k, 1] = 0 stat_momentum_field[k, 2] = 0 elif (dim == 2): source_vector[k * (dim + 1) + 0] = -2 * c0 * c0 * ( sign(x - 1. / 2) * (y - 1. / 2) * abs(y - 1. / 2) + (x - 1. / 2) * abs(x - 1. / 2) * sign(y - 1. / 2)) source_vector[k * (dim + 1) + 1] = 0 source_vector[k * (dim + 1) + 2] = 0 stat_pressure_field[k] = (x - 1. / 2) * abs(x - 1. / 2) * ( y - 1. / 2) * abs(y - 1. / 2) stat_momentum_field[ k, 0] = -2 * abs(x - 1. / 2) * (y - 1. / 2) * abs(y - 1. / 2) stat_momentum_field[ k, 1] = -2 * (x - 1. / 2) * abs(x - 1. / 2) * abs(y - 1. / 2) stat_momentum_field[k, 2] = 0 elif (dim == 3): source_vector[k * (dim + 1) + 0] = -2 * c0 * c0 * ( sign(x - 1. / 2) * (y - 1. / 2) * abs(y - 1. / 2) * (z - 1. / 2) * abs(z - 1. / 2) + (x - 1. / 2) * abs(x - 1. / 2) * sign(y - 1. / 2) * (z - 1. / 2) * abs(z - 1. / 2) + (x - 1. / 2) * abs(x - 1. / 2) * (y - 1. / 2) * abs(y - 1. / 2) * sign(z - 1. / 2)) source_vector[k * (dim + 1) + 1] = 0 source_vector[k * (dim + 1) + 2] = 0 source_vector[k * (dim + 1) + 3] = 0 stat_pressure_field[k] = (x - 1. / 2) * abs(x - 1. / 2) * ( y - 1. / 2) * abs(y - 1. / 2) * (z - 1. / 2) * abs(z - 1. / 2) stat_momentum_field[k, 0] = -2 * abs(x - 1. / 2) * ( y - 1. / 2) * abs(y - 1. / 2) * (z - 1. / 2) * abs(z - 1. / 2) stat_momentum_field[k, 1] = -2 * (x - 1. / 2) * abs( x - 1. / 2) * abs(y - 1. / 2) * (z - 1. / 2) * abs(z - 1. / 2) stat_momentum_field[k, 2] = -2 * (x - 1. / 2) * abs(x - 1. / 2) * ( y - 1. / 2) * abs(y - 1. / 2) * abs(z - 1. / 2) return source_vector, stat_pressure_field, stat_momentum_field
def source_term_and_stat_solution_wave_system(my_mesh): test_desc["Source_term"] = "True" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() source_vector = cdmath.Vector(nbCells * (dim + 1)) stat_pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) stat_velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for k in range(nbCells): x = my_mesh.getCell(k).x() y = my_mesh.getCell(k).y() z = my_mesh.getCell(k).z() if (dim == 1): source_vector[k * (dim + 1) + 0] = c0 * c0 * 4 * pi * pi * sin(2 * pi * x) source_vector[k * (dim + 1) + 1] = 0 stat_pressure_field[k] = sin(2 * pi * x) stat_velocity_field[k, 0] = -2 * pi * cos(2 * pi * x) / rho0 stat_velocity_field[k, 1] = 0 stat_velocity_field[k, 2] = 0 elif (dim == 2): source_vector[k * (dim + 1) + 0] = 2 * c0 * c0 * 4 * pi * pi * sin( 2 * pi * x) * sin(2 * pi * y) source_vector[k * (dim + 1) + 1] = 0 source_vector[k * (dim + 1) + 2] = 0 stat_pressure_field[k] = sin(2 * pi * x) * sin(2 * pi * y) stat_velocity_field[k, 0] = -2 * pi * cos(2 * pi * x) * sin( 2 * pi * y) / rho0 stat_velocity_field[k, 1] = -2 * pi * sin(2 * pi * x) * cos( 2 * pi * y) / rho0 stat_velocity_field[k, 2] = 0 elif (dim == 3): source_vector[k * (dim + 1) + 0] = 3 * c0 * c0 * 4 * pi * pi * sin( 2 * pi * x) * sin(2 * pi * y) * sin(2 * pi * z) source_vector[k * (dim + 1) + 1] = 0 source_vector[k * (dim + 1) + 2] = 0 source_vector[k * (dim + 1) + 3] = 0 stat_pressure_field[k] = sin(2 * pi * x) * sin(2 * pi * y) * sin( 2 * pi * z) stat_velocity_field[k, 0] = -2 * pi * cos(2 * pi * x) * sin( 2 * pi * y) * sin(2 * pi * z) / rho0 stat_velocity_field[k, 1] = -2 * pi * sin(2 * pi * x) * cos( 2 * pi * y) * sin(2 * pi * z) / rho0 stat_velocity_field[k, 2] = -2 * pi * sin(2 * pi * x) * sin( 2 * pi * y) * cos(2 * pi * z) / rho0 return source_vector, stat_pressure_field, stat_velocity_field
def initial_conditions_wave_system_staggered(my_mesh): test_desc["Initial_data"] = "Constant pressure, divergence free velocity" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() if (not my_mesh.isStructured()): raise ValueError("WaveSystemStaggered: the mesh should be structured") NxNyNz = my_mesh.getCellGridStructure() DxDyDz = my_mesh.getDXYZ() dx = DxDyDz[0] if (dim >= 2): dy = DxDyDz[1] if (dim == 3): dz = DxDyDz[2] pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for i in range(nbCells): Ci = my_mesh.getCell(i) x = Ci.x() pressure_field[i] = p0 #We take only the normal component of the velocity on a cartesian grid #We save the x component from the back face, the y component from the left face and the z component from the bottom face #Warning : boundary values should be the same for left and right as well as top and down (front and back in 3D) boundaries if (dim == 2): y = Ci.y() velocity_field[i, 0] = sin(pi * (x - 0.5 * dx)) * cos( pi * y) # value on the left face velocity_field[i, 1] = -sin(pi * (y - 0.5 * dy)) * cos( pi * x) # value on the bottom face velocity_field[i, 2] = 0 elif (dim == 3): y = Ci.y() z = Ci.z() velocity_field[i, 0] = sin(pi * (x - 0.5 * dx)) * cos(pi * y) * cos( pi * z) # value on the back face velocity_field[i, 1] = sin(pi * (y - 0.5 * dy)) * cos(pi * x) * cos( pi * z) # value on the left face velocity_field[i, 2] = -2 * sin(pi * (z - 0.5 * dz)) * cos( pi * x) * cos(pi * y) # value on the bottom face else: raise ValueError( "initial_conditions_wave_system_staggered: the 1D mesh not yet implemented" ) return pressure_field, velocity_field
def initial_conditions_shock(my_mesh, isCircle): print "Initial data : Spherical wave" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() rayon = 0.15 if (not isCircle): xcentre = 0.5 ycentre = 0.5 zcentre = 0.5 else: xcentre = 0. ycentre = 0. zcentre = 0. pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for i in range(nbCells): velocity_field[i, 0] = 0 velocity_field[i, 1] = 0 velocity_field[i, 2] = 0 x = my_mesh.getCell(i).x() valX = (x - xcentre) * (x - xcentre) if (dim == 1): val = sqrt(valX) if (dim == 2): y = my_mesh.getCell(i).y() valY = (y - ycentre) * (y - ycentre) val = sqrt(valX + valY) if (dim == 3): y = my_mesh.getCell(i).y() z = my_mesh.getCell(i).z() valY = (y - ycentre) * (y - ycentre) valZ = (z - zcentre) * (z - zcentre) val = sqrt(valX + valY + valZ) if val < rayon: pressure_field[i] = p0 pass else: pressure_field[i] = p0 / 2 pass pass return pressure_field, velocity_field
def source_term_and_stat_solution_transport_equation(my_mesh,velocity): test_desc["Source_term"]="True" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() source_vector = cdmath.Vector(nbCells) stat_field = cdmath.Field("Stationary field", cdmath.CELLS, my_mesh, 1) for k in range(nbCells): x = my_mesh.getCell(k).x() y = my_mesh.getCell(k).y() z = my_mesh.getCell(k).z() if(dim==1): source_vector[k] = 2*pi*velocity[0]*cos(2*pi*x) stat_field[k] = sin(2*pi*x) elif(dim==2): source_vector[k*(dim+1)+0] = 2*pi*(velocity[0]*cos(2*pi*x)*sin(2*pi*y)+velocity[1]*sin(2*pi*x)*cos(2*pi*y)) stat_field[k] = sin(2*pi*x)*sin(2*pi*y) elif(dim==3): source_vector[k*(dim+1)+0] = 2*pi*(velocity[0]*cos(2*pi*x)*sin(2*pi*y)*sin(2*pi*z)+velocity[1]*sin(2*pi*x)*cos(2*pi*y)*sin(2*pi*z)+velocity[2]*sin(2*pi*x)*sin(2*pi*y)*cos(2*pi*z)) stat_field[k] = sin(2*pi*x)*sin(2*pi*y)*sin(2*pi*z) return source_vector, stat_field
def initial_conditions_wave_system(my_mesh): print "Spherical wave initial data" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() rayon = 0.15 xcentre = 0.5 ycentre = 0.5 zcentre = 0.5 pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) U = cdmath.Field("Conservative vector", cdmath.CELLS, my_mesh, dim + 1) for i in range(nbCells): x = my_mesh.getCell(i).x() y = my_mesh.getCell(i).y() velocity_field[i, 0] = 0 velocity_field[i, 1] = 0 velocity_field[i, 2] = 0 valX = (x - xcentre) * (x - xcentre) valY = (y - ycentre) * (y - ycentre) if (dim == 2): val = sqrt(valX + valY) if (dim == 3): z = my_mesh.getCell(i).z() valZ = (z - zcentre) * (z - zcentre) val = sqrt(valX + valY + valZ) if val < rayon: pressure_field[i] = p0 pass else: pressure_field[i] = p0 / 2 pass pass U[i, 0] = pressure_field[i] U[i, 1] = rho0 * velocity_field[i, 0] U[i, 2] = rho0 * velocity_field[i, 1] return U, pressure_field, velocity_field
def main(): a = -5.0 b = 5.0 nx = 1000 ntmax = 1000 dx = (b - a) / nx pi = 3.1415927 # Transport velocity cfl = 0.5 u = 3. dt = cfl * dx / u my_mesh = cdmath.Mesh(a, b, nx) conc = cdmath.Field("Concentration", cdmath.CELLS, my_mesh, 1) # Initial conditions sigma = math.sqrt(0.2) for i in xrange(my_mesh.getNumberOfCells()): x = my_mesh.getCell(i).x() conc[i] = 0.5 / (sigma * math.sqrt(2 * pi)) * math.exp(-0.5 * math.pow( (x / sigma), 2)) pass time = 0. tmax = 3.0 it = 0 print("MED post-treatment of the solution at T=" + str(time) + "…") output_filename = "EqTr1D" conc.setTime(time, it) conc.writeMED(output_filename) conc.writeVTK(output_filename) conc.writeCSV(output_filename) output_freq = 10 # Time loop while (it < ntmax and time <= tmax): print("-- Iter: " + str(it) + ", Time: " + str(time) + ", dt: " + str(dt)) conc[0] = conc[0] - u * dt / dx * ( conc[0] - conc[my_mesh.getNumberOfCells() - 1]) for j in xrange(1, my_mesh.getNumberOfCells()): conc[j] = conc[j] - u * dt / dx * (conc[j] - conc[j - 1]) pass time += dt it += 1 if (it % output_freq == 0): conc.setTime(time, it) conc.writeMED(output_filename, False) conc.writeVTK(output_filename, False) conc.writeCSV(output_filename) pass pass print("CDMATH calculation done.") return
def initial_conditions_disk_vortex(my_mesh): print "Disk vortex initial data" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() if(dim!=2): raise ValueError("Wave system on disk : mesh dimension should be 2") pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for i in range(nbCells): x = my_mesh.getCell(i).x() y = my_mesh.getCell(i).y() pressure_field[i] = p0 velocity_field[i,0] = -y velocity_field[i,1] = x velocity_field[i,2] = 0 return pressure_field, velocity_field
def initial_conditions(my_mesh): rayon = 0.15 xcentre = 0.25 ycentre = 0.25 y_field = cdmath.Field("Y field", cdmath.CELLS, my_mesh, 1) nbCells = my_mesh.getNumberOfCells() for j in range(nbCells): x = my_mesh.getCell(j).x() y = my_mesh.getCell(j).y() valX = (x - xcentre) * (x - xcentre) valY = (y - ycentre) * (y - ycentre) val = math.sqrt(valX + valY) if val < rayon: y_field[j] = 1.0 pass else: y_field[j] = 0.0 pass pass return y_field
def initial_conditions_transport_equation(my_mesh): print "Initial_data", "Shock" dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() initial_field = cdmath.Field("unknown", cdmath.CELLS, my_mesh, 1) rayon = 0.15 xcentre = 0.5 ycentre = 0.5 zcentre = 0.5 for i in range(nbCells): x = my_mesh.getCell(i).x() valX = (x - xcentre) * (x - xcentre) if (dim == 1): val = sqrt(valX) if (dim == 2): y = my_mesh.getCell(i).y() valY = (y - ycentre) * (y - ycentre) val = sqrt(valX + valY) if (dim == 3): y = my_mesh.getCell(i).y() z = my_mesh.getCell(i).z() valY = (y - ycentre) * (y - ycentre) valZ = (z - zcentre) * (z - zcentre) val = sqrt(valX + valY + valZ) if val < rayon: initial_field[i] = 1 pass else: initial_field[i] = 0 pass pass return initial_field
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 #my_mesh.setGroupAtPlan(0,2,eps,"DirichletBorder") #Bord AVANT si calcul 3D #my_mesh.setGroupAtPlan(1,2,eps,"DirichletBorder") #Bord ARRIERE si calcul 3D nbNodes = my_mesh.getNumberOfNodes() nbCells = my_mesh.getNumberOfCells() print("Fin chargement du maillage") print("nb of nodes = ", nbNodes) print("nb of cells = ", nbCells) # Discrétisation du second membre et détermination des noeuds intérieurs #======================================================================= my_RHS_field = 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() #z=Ni.z() si calcul 3D my_RHS_field[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)
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 sigma_flux(VitesseX, VitesseY, cfl, y_field, indexFacesPerio): # Fluxes calculation # SumFlux = cdmath.Field("Fluxes", cdmath.CELLS, y_field.getMesh(), 1) my_mesh = y_field.getMesh() nbCells = my_mesh.getNumberOfCells() normU = math.sqrt(VitesseX * VitesseX + VitesseY * VitesseY) for j in range(nbCells): Cj = my_mesh.getCell(j) nbFace = Cj.getNumberOfFaces() SumF = 0.0 minlengthFk = 1.E30 for k in range(nbFace): indexFace = Cj.getFacesId()[k] Fk = my_mesh.getFace(indexFace) NormalX = Cj.getNormalVector(k, 0) NormalY = Cj.getNormalVector(k, 1) LengthFk = Fk.getMeasure() UN = VitesseX * NormalX + VitesseY * NormalY minlengthFk = min(minlengthFk, LengthFk / abs(UN)) minlengthFk = min(minlengthFk, LengthFk / abs(VitesseX)) minlengthFk = min(minlengthFk, LengthFk / abs(VitesseY)) conc = 0.0 cellCourante = j cellAutre = -1 if (not Fk.isBorder()): indexC1 = Fk.getCellsId()[0] indexC2 = Fk.getCellsId()[1] # hypothese: La cellule d'index indexC1 est la cellule courante index j # if (indexC1 == j): # hypothese verifie # cellCourante = indexC1 cellAutre = indexC2 pass elif (indexC2 == j): # hypothese non verifie # cellCourante = indexC2 cellAutre = indexC1 pass # definir la cellule gauche et droite par le prduit vitesse * normale sortante # si u*n>0 : rien a faire sinon inverser la gauche et la droite if (UN > 1.E-15): conc = y_field[cellCourante] pass else: conc = y_field[cellAutre] pass pass else: # conditions aux limites neumann homogene # if (Fk.getGroupName() == "LeftEdge" or Fk.getGroupName() == "RightEdge"): if (UN > 1.E-15): conc = y_field[cellCourante] pass else: conc = 0.0 pass pass # conditions aux limites periodiques # if (Fk.getGroupName() == "BottomEdge" or Fk.getGroupName() == "TopEdge"): indexFP = indexFacesPerio[indexFace] # une autre manière de recuperer l'index de la face periodique # # int indexFP=my_mesh.getIndexFacePeriodic(indexFace); Fp = my_mesh.getFace(indexFP) indexCp = Fp.getCellsId()[0] if (UN > 1.E-15): conc = y_field[cellCourante] pass else: conc = y_field[indexCp] pass pass pass SumF = SumF + UN * LengthFk * conc pass dt = cfl * minlengthFk / normU SumFlux[j] = dt * SumF / Cj.getMeasure() pass return dt, SumFlux
def WaveSystem1DVF(ntmax, tmax, cfl, my_mesh, output_freq, resolution): dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() dt = 0. time = 0. it = 0 isStationary = False SumFluxes = cdmath.Field("Fluxes", cdmath.CELLS, my_mesh, dim + 1) # Initial conditions # print("Construction of the initial condition …") U, pressure_field, velocity_field = initial_conditions_wave_system(my_mesh) dx_min = my_mesh.minRatioVolSurf() dt = cfl * dx_min / c0 print( "Starting computation of the linear wave system with an UPWIND explicit scheme …" ) # Starting time loop while (it < ntmax and time <= tmax and not isStationary): computeFluxes(U, SumFluxes) SumFluxes *= dt maxVector = SumFluxes.normMax() isStationary = maxVector[0] / p0 < precision and maxVector[ 1] / rho0 < precision U -= SumFluxes 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)) print "Variation temporelle relative : pressure ", maxVector[ 0] / p0, ", velocity x", maxVector[1] / rho0 print for k in range(nbCells): pressure_field[k] = U[k, 0] velocity_field[k, 0] = U[k, 1] / rho0 pressure_field.setTime(time, it) pressure_field.writeCSV("WaveSystem1DUpwind_pressure") velocity_field.setTime(time, it) velocity_field.writeCSV("WaveSystem1DUpwind_velocity") print("-- Iter: " + str(it) + ", Time: " + str(time) + ", dt: " + str(dt)) print "|| Un+1 - Un || : pressure ", maxVector[ 0] / p0, ", velocity x", maxVector[1] / rho0 print if (it >= ntmax): print "Nombre de pas de temps maximum ntmax= ", ntmax, " atteint" raise ValueError( "Maximum number of time steps reached : Stationary state not found !!!!!!!" ) elif (isStationary): print "Régime stationnaire atteint au pas de temps ", it, ", t= ", time for k in range(nbCells): pressure_field[k] = U[k, 0] velocity_field[k, 0] = U[k, 1] / rho0 pressure_field.setTime(time, 0) pressure_field.writeCSV("WaveSystem1DUpwind_pressure_Stat") velocity_field.setTime(time, 0) velocity_field.writeCSV("WaveSystem1DUpwind_velocity_Stat") else: print "Temps maximum Tmax= ", tmax, " atteint" raise ValueError( "Maximum time reached : Stationary state not found !!!!!!!")
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 WaveSystemVF(ntmax, tmax, cfl, my_mesh, output_freq, meshName, resolution, scaling, test_bc): dim = my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() dt = 0. time = 0. it = 0 isStationary = False nbVoisinsMax = my_mesh.getMaxNbNeighbours(cdmath.CELLS) iterGMRESMax = 50 #iteration vectors Un = cdmath.Vector(nbCells * (dim + 1)) dUn = cdmath.Vector(nbCells * (dim + 1)) # Initial conditions # print("Construction of the initial condition …") if (meshName.find("square") == -1 and meshName.find("Square") == -1 and meshName.find("cube") == -1 and meshName.find("Cube") == -1): print "Mesh name : ", meshName raise ValueError( "Mesh name should contain substring square or cube to use wave system with smooth source term" ) pressure_field = cdmath.Field("Pressure", cdmath.CELLS, my_mesh, 1) velocity_field = cdmath.Field("Velocity", cdmath.CELLS, my_mesh, 3) for k in range(nbCells): # fields initialisation pressure_field[k] = 0 velocity_field[k, 0] = 0 velocity_field[k, 1] = 0 velocity_field[k, 2] = 0 S, stat_pressure, stat_velocity = source_term_and_stat_solution_wave_system( my_mesh) for k in range(nbCells): Un[k * (dim + 1) + 0] = pressure_field[k] Un[k * (dim + 1) + 1] = rho0 * velocity_field[k, 0] Un[k * (dim + 1) + 2] = rho0 * velocity_field[k, 1] if (dim == 3): Un[k * (dim + 1) + 3] = rho0 * velocity_field[k, 2] if (scaling == 1): Vn = Un.deepCopy() for k in range(nbCells): Vn[k * (dim + 1) + 0] = Vn[k * (dim + 1) + 0] / (c0 * c0) S[k * (dim + 1) + 0] = S[k * (dim + 1) + 0] / (c0 * c0) elif (scaling == 2): Vn = Un.deepCopy() for k in range(nbCells): Vn[k * (dim + 1) + 0] = Vn[k * (dim + 1) + 0] / c0 S[k * (dim + 1) + 0] = S[k * (dim + 1) + 0] / c0 #sauvegarde de la donnée initiale pressure_field.setTime(time, it) pressure_field.writeVTK("WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure") velocity_field.setTime(time, it) velocity_field.writeVTK("WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity") #Postprocessing : save 2D picture PV_routines.Save_PV_data_to_picture_file( "WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure" + '_0.vtu', "Pressure", 'CELLS', "WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure_initial") PV_routines.Save_PV_data_to_picture_file( "WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity" + '_0.vtu', "Velocity", 'CELLS', "WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity_initial") total_pressure_initial = pressure_field.integral( ) #For conservation test later total_velocity_initial = velocity_field.integral( ) #For conservation test later dx_min = my_mesh.minRatioVolSurf() dt = cfl * dx_min / c0 divMat = computeDivergenceMatrix(my_mesh, nbVoisinsMax, dt, scaling, test_bc) #Adding the momentum friction term for j in range(nbCells): for i in range(dim): divMat.addValue(j * (dim + 1) + 1 + i, j * (dim + 1) + 1 + i, dt) #Add the identity matrix on the diagonal if (scaling == 0 or scaling == 2): divMat.diagonalShift(1) #only after filling all coefficients else: for j in range(nbCells): divMat.addValue(j * (dim + 1), j * (dim + 1), 1 / (c0 * c0)) #/(c0*c0) for i in range(dim): divMat.addValue(j * (dim + 1) + 1 + i, j * (dim + 1) + 1 + i, 1) if (scaling == 0): LS = cdmath.LinearSolver(divMat, Un + S * dt, iterGMRESMax, precision, "GMRES", "ILU") else: LS = cdmath.LinearSolver(divMat, Vn + S * dt, iterGMRESMax, precision, "GMRES", "ILU") LS.setComputeConditionNumber() 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["Numerical_parameter_space_step"] = dx_min test_desc["Numerical_parameter_time_step"] = dt test_desc["Linear_solver_with_scaling"] = scaling test_desc['Linear_system_max_actual_iterations_number'] = 0 test_desc["Linear_system_max_actual_error"] = 0 test_desc["Linear_system_max_actual_condition number"] = 0 print( "Starting computation of the linear wave system with a centered scheme …" ) # Starting time loop while (it < ntmax and time <= tmax and not isStationary): dUn = Un.deepCopy() if (scaling == 0): LS.setSndMember(Un + S * dt) else: LS.setSndMember(Vn + S * dt) if (scaling < 2): Un = LS.solve() if (scaling == 1): Vn = Un.deepCopy() for k in range(nbCells): Vn[k * (dim + 1) + 0] = Vn[k * (dim + 1) + 0] / (c0 * c0) else: #( scaling==2) Vn = LS.solve() Un = Vn.deepCopy() for k in range(nbCells): Un[k * (dim + 1) + 0] = c0 * Vn[k * (dim + 1) + 0] if (not LS.getStatus()): print "Linear system did not converge ", iterGMRES, " GMRES iterations" raise ValueError("Pas de convergence du système linéaire") dUn -= Un test_desc["Linear_system_max_actual_iterations_number"] = max( LS.getNumberOfIter(), test_desc["Linear_system_max_actual_iterations_number"]) test_desc["Linear_system_max_actual_error"] = max( LS.getResidu(), test_desc["Linear_system_max_actual_error"]) test_desc["Linear_system_max_actual_condition number"] = max( LS.getConditionNumber(), test_desc["Linear_system_max_actual_condition number"]) maxVector = dUn.maxVector(dim + 1) isStationary = maxVector[0] < precision and maxVector[ 1] / rho0 < precision and maxVector[2] / rho0 < precision if (dim == 3): isStationary = isStationary and maxVector[3] / rho0 < precision time = time + dt it = it + 1 #Sauvegardes if (it == 1 or it % output_freq == 0 or it >= ntmax or isStationary or time >= tmax): print "-- Iter: " + str(it) + ", Time: " + str( time) + ", dt: " + str(dt) print "Variation temporelle relative : pressure ", maxVector[ 0], ", velocity x", maxVector[ 1] / rho0, ", velocity y", maxVector[2] / rho0 print "Linear system converged in ", LS.getNumberOfIter( ), " GMRES iterations" delta_press = 0 delta_v = cdmath.Vector(dim) 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 if (abs(stat_pressure[k] - pressure_field[k]) > delta_press): delta_press = abs(stat_pressure[k] - pressure_field[k]) if (abs(stat_velocity[k, 0] - velocity_field[k, 0]) > delta_v[0]): delta_v[0] = abs(stat_velocity[k, 0] - velocity_field[k, 0]) if (abs(stat_velocity[k, 1] - velocity_field[k, 1]) > delta_v[1]): delta_v[1] = abs(stat_velocity[k, 1] - velocity_field[k, 1]) if (dim == 3): if (abs(stat_velocity[k, 2] - velocity_field[k, 2]) > delta_v[2]): delta_v[2] = abs(stat_velocity[k, 2] - velocity_field[k, 2]) pressure_field.setTime(time, it) pressure_field.writeVTK( "WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure", False) velocity_field.setTime(time, it) velocity_field.writeVTK( "WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity", False) print "Ecart au stationnaire exact : error_p= ", delta_press, " error_||u||= ", delta_v.maxVector( )[0] print print "-- Iter: " + str(it) + ", Time: " + str(time) + ", dt: " + str(dt) print "Variation temporelle relative : pressure ", maxVector[ 0], ", velocity x", maxVector[1] / rho0, ", velocity y", maxVector[ 2] / rho0 print if (it >= ntmax): print "Nombre de pas de temps maximum ntmax= ", ntmax, " atteint" raise ValueError( "Maximum number of time steps reached : Stationary state not found !!!!!!!" ) elif (isStationary): print "Régime stationnaire atteint au pas de temps ", it, ", t= ", time print "------------------------------------------------------------------------------------" pressure_field.setTime(time, 0) pressure_field.writeVTK("WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure_Stat") velocity_field.setTime(time, 0) velocity_field.writeVTK("WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity_Stat") #Postprocessing : Extraction of the diagonal data if (dim == 2): 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) elif (dim == 3): diag_data_press = VTK_routines.Extract_field_data_over_line_to_numpyArray( pressure_field, [0, 0, 0], [1, 1, 1], resolution) diag_data_vel = VTK_routines.Extract_field_data_over_line_to_numpyArray( velocity_field, [0, 0, 0], [1, 1, 1], resolution) #Postprocessing : save 2D picture PV_routines.Save_PV_data_to_picture_file( "WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure_Stat" + '_0.vtu', "Pressure", 'CELLS', "WaveSystem" + str(dim) + "DCentered" + meshName + "_pressure_Stat") PV_routines.Save_PV_data_to_picture_file( "WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity_Stat" + '_0.vtu', "Velocity", 'CELLS', "WaveSystem" + str(dim) + "DCentered" + meshName + "_velocity_Stat") return delta_press, delta_v.maxVector( )[0], nbCells, time, it, velocity_field.getNormEuclidean().max( ), diag_data_press, diag_data_vel, test_desc[ "Linear_system_max_actual_condition number"] else: print "Temps maximum Tmax= ", tmax, " atteint" raise ValueError( "Maximum time reached : Stationary state not found !!!!!!!")
def WaveSystemVF(ntmax, tmax, cfl, my_mesh, output_freq, filename,resolution): dim=my_mesh.getMeshDimension() nbCells = my_mesh.getNumberOfCells() meshName=my_mesh.getName() dt = 0. time = 0. it=0; isStationary=False; SumFluxes = cdmath.Field("Fluxes", cdmath.CELLS, my_mesh, dim+1) # Initial conditions # print("Construction of the initial condition …") if(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_square_shock(my_mesh) elif(filename.find("disk")>-1 or filename.find("Disk")>-1): pressure_field, velocity_field = initial_conditions_disk_vortex(my_mesh) else: print "Mesh name : ", filename raise ValueError("Mesh name should contain substring square, cube or disk") U = cdmath.Field("Conservative vector", cdmath.CELLS, my_mesh, dim+1) for i in range(nbCells): U[i,0] = pressure_field[i] U[i,1] = rho0*velocity_field[i,0] U[i,2] = rho0*velocity_field[i,1] #sauvegarde de la donnée initiale pressure_field.setTime(time,it); pressure_field.writeVTK("WaveSystem"+str(dim)+"DUpwind"+meshName+"_pressure"); velocity_field.setTime(time,it); velocity_field.writeVTK("WaveSystem"+str(dim)+"DUpwind"+meshName+"_velocity"); dx_min=my_mesh.minRatioVolSurf() dt = cfl * dx_min / c0 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): computeFluxes(U,SumFluxes); SumFluxes*=dt; maxVector=SumFluxes.normMax() isStationary= maxVector[0]/p0<precision and maxVector[1]/rho0<precision and maxVector[2]/rho0<precision; U-=SumFluxes; 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)) print "Variation temporelle relative : pressure ", maxVector[0]/p0 ,", velocity x", maxVector[1]/rho0 ,", velocity y", maxVector[2]/rho0 for k in range(nbCells): pressure_field[k]=U[k,0] velocity_field[k,0]=U[k,1]/rho0 if(dim>1): velocity_field[k,1]=U[k,2]/rho0 if(dim>2): velocity_field[k,2]=U[k,3]/rho0 pressure_field.setTime(time,it); pressure_field.writeVTK("WaveSystem"+str(dim)+"DUpwind"+meshName+"_pressure",False); velocity_field.setTime(time,it); velocity_field.writeVTK("WaveSystem"+str(dim)+"DUpwind"+meshName+"_velocity",False); print("-- Iter: " + str(it) + ", Time: " + str(time) + ", dt: " + str(dt)) print "Variation temporelle relative : pressure ", maxVector[0]/p0 ,", velocity x", maxVector[1]/rho0 ,", velocity y", maxVector[2]/rho0 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("WaveSystem"+str(dim)+"DUpwind"+meshName+"_pressure_Stat"); velocity_field.setTime(time,0); velocity_field.writeVTK("WaveSystem"+str(dim)+"DUpwind"+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("WaveSystem"+str(dim)+"DUpwind"+meshName+"_pressure_Stat"+'_0.vtu',"Pressure",'CELLS',"WaveSystem"+str(dim)+"DUpwind"+meshName+"_pressure_Stat") PV_routines.Save_PV_data_to_picture_file("WaveSystem"+str(dim)+"DUpwind"+meshName+"_velocity_Stat"+'_0.vtu',"Velocity",'CELLS',"WaveSystem"+str(dim)+"DUpwind"+meshName+"_velocity_Stat") else: print "Temps maximum Tmax= ", tmax, " atteint"
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 my_mesh.setGroupAtPlan(0,2,eps,"DirichletBorder")#Bord AVANT my_mesh.setGroupAtPlan(1,2,eps,"DirichletBorder")#Bord ARRIERE nbCells = my_mesh.getNumberOfCells() print("Mesh loading 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) my_ExactSol = cdmath.Field("EXACT_SOL", 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() z = Ci.z() r=sqrt(x*x+y*y+z*z) phi=atan2(y,x) theta=atan2(y,z*sin(phi)) my_RHSfield[i]=6*r*sin(theta)**2*cos(phi)+3*(r-1)*cos(phi)#mettre la fonction definie au second membre de l'edp
def sigma_flux(VitesseX, VitesseY, cfl, y_field, indexFacesPerio): # Calculation of fluxes # SumFlux = cdmath.Field("Fluxes", cdmath.CELLS, y_field.getMesh(), 1) my_mesh = y_field.getMesh() nbCells = my_mesh.getNumberOfCells() normU = math.sqrt(VitesseX * VitesseX + VitesseY * VitesseY) for j in range(nbCells): Cj = my_mesh.getCell(j) nbFace = Cj.getNumberOfFaces() SumF = 0.0 minlengthFk = 1.E30 for k in range(nbFace): indexFace = Cj.getFacesId()[k] Fk = my_mesh.getFace(indexFace) NormalX = Cj.getNormalVector(k, 0) NormalY = Cj.getNormalVector(k, 1) LengthFk = Fk.getMeasure() UN = VitesseX * NormalX + VitesseY * NormalY minlengthFk = min(minlengthFk, LengthFk / abs(UN)) minlengthFk = min(minlengthFk, LengthFk / abs(VitesseX)) minlengthFk = min(minlengthFk, LengthFk / abs(VitesseY)) conc = 0.0 cellCourante = j cellAutre = -1 if (not Fk.isBorder()): indexC1 = Fk.getCellsId()[0] indexC2 = Fk.getCellsId()[1] # hypothesis: the cell of index indexC1 is the current cell of index j # if (indexC1 == j): # hypothese is verified # cellCourante = indexC1 cellAutre = indexC2 pass elif (indexC2 == j): # hypothesis is not verified # cellCourante = indexC2 cellAutre = indexC1 pass # define left and right cell with the product of velocity * outward normal vector # if u*n>0: nothing to do, else invert left and right if (UN > 1.E-15): conc = y_field[cellCourante] pass else: conc = y_field[cellAutre] pass pass else: # homogeneous Neumann boundary conditions # if (Fk.getGroupName() == "GAUCHE" or Fk.getGroupName() == "DROITE"): if (UN > 1.E-15): conc = y_field[cellCourante] pass else: conc = 0.0 pass pass # periodical boundary conditions # if (Fk.getGroupName() == "BAS" or Fk.getGroupName() == "HAUT"): indexFP = indexFacesPerio[indexFace] # another way to get the index of the periodical face # # int indexFP=my_mesh.getIndexFacePeriodic(indexFace); Fp = my_mesh.getFace(indexFP) indexCp = Fp.getCellsId()[0] if (UN > 1.E-15): conc = y_field[cellCourante] pass else: conc = y_field[indexCp] pass pass pass SumF = SumF + UN * LengthFk * conc pass dt = cfl * minlengthFk / normU SumFlux[j] = dt * SumF / Cj.getMeasure() pass return dt, SumFlux
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
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() 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) 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 = [] #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() r = sqrt(x * x + y * y) theta = atan2(y, x)
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() 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:
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 my_mesh.setGroupAtPlan(0, 2, eps, "DirichletBorder") #Bord AVANT my_mesh.setGroupAtPlan(1, 2, eps, "DirichletBorder") #Bord ARRIERE nbCells = my_mesh.getNumberOfCells() print("Mesh loading 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() z = Ci.z() my_RHSfield[i] = 3 * pi * pi * sin(pi * x) * sin(pi * y) * sin( pi * z) #mettre la fonction definie au second membre de l edp # compute maximum number of neighbours maxNbNeighbours = max(1 + Ci.getNumberOfFaces(), maxNbNeighbours) print("Right hand side discretisation done") print("Maximum number of neighbours=", maxNbNeighbours)
raise ValueError("Wrong space dimension : expected a space of dimension 3") nbNodes = my_mesh.getNumberOfNodes() nbCells = my_mesh.getNumberOfCells() print("Mesh building/loading done") print("nb of nodes=", nbNodes) print("nb of cells=", nbCells) # Torus radii (calculation will fail if the mesh is not correct) R=1 #Grand rayon r=0.6 #Petit rayon #Discrétisation du second membre, de la solution exacte et détermination des noeuds intérieurs #====================================================================== my_RHSfield = cdmath.Field("RHS field", cdmath.NODES, my_mesh, 1) exactSolField = cdmath.Field("Exact solution 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() theta=atan2(z,sqrt(x*x+y*y)-R) 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
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 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