Saltar al contenido

¿Cómo generar una malla con elementos cuadriláteros?

Solución:

Basado en el tutorial aquí

Las mallas QuadElement se comportan exactamente igual que las mallas TriangleElement, con la excepción de que, para elementos quad lineales, se necesitan cuatro incidentes por elemento y, para elementos cuadráticos, se necesitan ocho incidentes por elemento.

aquí hay otra posible respuesta:

Needs["NDSolve`FEM`"]

rectangleA = {{0, 4}, {8, 8}};
rectangleB = {{5, 0}, {8, 4}};

pitch = 0.25;

rectAx = 1/pitch (rectangleA[[2, 1]] - rectangleA[[1, 1]]) + 1;
rectAy = 1/pitch (rectangleA[[2, 2]] - rectangleA[[1, 2]]) + 1;
rectBx = 1/pitch (rectangleB[[2, 1]] - rectangleB[[1, 1]]) + 1;
rectBy = 1/pitch (rectangleB[[2, 2]] - rectangleB[[1, 2]]) + 1;

coordinatesA = 
  Flatten[Table[{x, y}, {x, rectangleA[[1, 1]], rectangleA[[2, 1]], pitch},
   {y, rectangleA[[1, 2]], rectangleA[[2, 2]], pitch}], 1];
coordinatesB = 
  Flatten[Table[{x, y}, {x, rectangleB[[1, 1]], rectangleB[[2, 1]], pitch},
   {y, rectangleB[[1, 2]], rectangleB[[2, 2]], pitch}], 1];

coordinates = Join[coordinatesA, coordinatesB];

incidents = Join[
   Flatten[
    Table[{j*rectAy + i, j*rectAy + i + 1, (j - 1)*rectAy + i + 1, (j - 1)*rectAy + i},
     {i, 1, rectAy - 1}, 
     {j, 1, rectAx - 1}], 1],
   Flatten[
    Table[{j*rectBy + i, j*rectBy + i + 1, (j - 1)*rectBy + i + 1, (j - 1)*rectBy + i},
     {i, 1 + Length[coordinatesA], Length[coordinatesA] + rectBy - 1},
     {j, 1, rectBx - 1}], 1]
   ];

mesh1 = ToElementMesh["Coordinates" -> coordinates, 
   "MeshElements" -> {QuadElement[incidents]}, 
   "NodeReordering" -> True];
mesh2 = MeshOrderAlteration[mesh1, 2];
mesh2["MeshOrder"]

ingrese la descripción de la imagen aquí

Show[
 DiscretizeGraphics[
  GraphicsComplex[{{0, 4}, {5, 4}, {5, 0}, {8, 0}, {8, 8}, {0, 8}}, 
   Polygon[{1, 2, 3, 4, 5, 6}]]],
 mesh2["Wireframe"],
 ListPlot[coordinates]
 ]

Problema de muestra:

sol = NDSolveValue[{D[u[x, y], x, x] + D[u[x, y], y, y] == 0,
   DirichletCondition[u[x, y] == 100, y == 4 && x <= 5 || y <= 4 && x == 5],
   DirichletCondition[u[x, y] == 0, y == 8 || x == 8]},
  u, {x, y} ∈ mesh2]

sol["ElementMesh"]
ContourPlot[sol[x, y], {x, y} ∈ mesh2, Mesh -> None, 
 ColorFunction -> "Rainbow", PlotRange -> All, 
 PlotLegends -> Automatic]

ingrese la descripción de la imagen aquí

Aquí hay un enfoque diferente. La idea es generar primero una malla triangular de segundo orden. A continuación, se agrega una coordenada central en cada triángulo. Luego dividimos cada triángulo en tres quads de primer orden haciendo uso de la coordenada central recién agregada y los incidentes de triángulo inicial de segundo orden.

ingrese la descripción de la imagen aquí

Entonces agregamos un nodo en el centro del elemento y creamos los elementos cuádruples {c, 6,1,4}, {c, 4,2,5} y {c, 5,3,6}.

Comience con una malla triangular inicial:

Needs["NDSolve`FEM`"]
m = ToElementMesh[
   DiscretizeGraphics[
    GraphicsComplex[{{0, 4}, {5, 4}, {5, 0}, {8, 0}, {8, 8}, {0, 8}}, 
     Polygon[{1, 2, 3, 4, 5, 6}]]]];

Dos funciones auxiliares que funcionan para elementos de malla triangular de segundo orden. Si uno desea extender esto a 3D, deberá agregar una función tetToHex.

getMidEleCoords = Compile[{{eleCoords, _Real, 2}},
   Mean[eleCoords], RuntimeAttributes -> {Listable}];

triToQuad = Compile[{{triInci, _Integer, 1}, {midInci, _Integer, 0}}, {
    {midInci, triInci[[6]], triInci[[1]], triInci[[4]]},
    {midInci, triInci[[4]], triInci[[2]], triInci[[5]]},
    {midInci, triInci[[5]], triInci[[3]], triInci[[6]]}
    }
   , RuntimeAttributes -> {Listable}
   ];

getConverterCode[TriangleElement] := triToQuad;
getNumOfResEle[TriangleElement] := 3
getConvertedEleType[TriangleElement] := QuadElement

Primero, calculamos las nuevas coordenadas dentro de los elementos triángulo / tet:

coords = m["Coordinates"];
numOfCoords = Length[coords];
meshEle = m["MeshElements"];
inci = ElementIncidents[meshEle];
markers = ElementMarkers[meshEle];
eleCoords = GetElementCoordinates[coords, #] & /@ inci;
midEleCoords = getMidEleCoords[eleCoords];
numOfMidCoords = Length /@ midEleCoords;
temp = Join[{numOfCoords}, numOfMidCoords];
temp = FoldList[Plus, temp] + 1;
midEleInci = MapThread[Range, {Most[temp], Rest[temp - 1]}];
newCoords = Join[coords, Join @@ midEleCoords];
(*Max[midEleInci]===Length[newCoords]*)

Luego generamos los nuevos elementos:

newEle = Table[
   Block[{thisMeshEle, thisType, thisInci, thisMarker, converter, 
     newEle, newEleMarkers},
    thisMeshEle = meshEle[[i]];
    thisType = Head[thisMeshEle];
    thisInci = ElementIncidents[thisMeshEle];
    thisMarker = ElementMarkers[thisMeshEle];
    converter = getConverterCode[thisType];
    newEle = Join @@ converter[thisInci, midEleInci[[i]]];
    newEleMarkers = 
     Join @@ Transpose[
       ConstantArray[thisMarker, getNumOfResEle[thisType]]];
    getConvertedEleType[thisType][newEle, newEleMarkers]
    ]
   , {i, Length[meshEle]}];

Genere una malla cuádruple:

mq1 = ToElementMesh["Coordinates" -> newCoords, 
  "MeshElements" -> newEle]
(* ElementMesh[{{0., 8.}, {0., 8.}}, {QuadElement["<" 1338 ">"]}] *)

Mira la malla:

mq1["Wireframe"]

ingrese la descripción de la imagen aquí

Esta es ahora una malla de primer orden:

mq1["MeshOrder"]
1

Uno puede usar MeshOrderAlteration[mq1, 2] para luego generar posteriormente una malla de segundo orden.

Histogram[Join @@ mq1["Quality"]]

ingrese la descripción de la imagen aquí

La calidad se ve bien, pero valdría la pena probar algún tipo de suavizado (por ejemplo, suavizado laplaciano).

(Actualizar: Hay una pregunta de seguimiento que analiza la idea del suavizado laplaciano. Spoiler: no parece que valga la pena)

Resuelva un problema de modelo sobre la malla:

sol = NDSolveValue[{-Laplacian[u[x, y], {x, y}] == 1, 
    DirichletCondition[u[x, y] == 0, True]}, u, {x, y} [Element] mq1];
Plot3D[sol[x, y], {x, y} [Element] sol["ElementMesh"]]

ingrese la descripción de la imagen aquí

Dado que esto generará tres elementos cuádruples por cada triángulo, la medida de la celda de la malla es menor de lo que debe ser, se podría ajustar haciendo uso de “MaxCellMeasure” en la malla del triángulo inicial.

Espero que esto ayude.

En general, eso no es posible en V11.0. La única primitiva a partir de la cual se puede generar una malla cuádruple es

ToElementMesh[Rectangle[]]

o

ToElementMesh[FullRegion[2], {{0, 1}, {0, 1}}]

Entonces, para obtener una malla cuádruple para una forma más complicada, necesitaría programar un poco y usar

ToElementMesh["Coordinates"->..., "MeshElements"->{QuadElement[....]}]

Como otro enfoque, podría fusionar 2 triángulos en un cuádruple y así obtener una malla en su mayoría cuádruple. Si haces eso. Me interesaría ver el resultado.

Aquí hay otra información: si tiene una malla de primer orden, puede hacer esa segunda orden.

m = ToElementMesh["Coordinates" -> coordinates, 
   "MeshElements" -> {QuadElement[incidents]}];
m["MeshOrder"]
1

m2 = MeshOrderAlteration[m, 2];
m2["MeshOrder"]
2

Dado que su caso no implica límites curvos, no es necesario mover los nodos del lado medio (nodos de segundo orden) a la posición adecuada.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *