Resumen: Se presentan algunos ejemplos de definición dominios y la construcción de sus mallados.
Tomaremos como dominio
Las siguientes instrucciones definen la frontera del dominio, utilizando ecuaciones paramétricas. Obsérvese que hemos asignado la etiqueta 14
a dicha curva con la instrucción label = 14
. Se recomienda siempre la asignación de etiquetas a las fronteras (más adelante se verá su uso).
// Definicion de la frontera del dominio
border C(t = 0, 2*pi){x = 2*cos(t); y = 2*sin(t); label = 14;};
Obsérvese que, para dibujar la curva x
e y
que representan, en FreeFEM, las dos coordenadas espaciales.
Para dibujar dicha curva usamos el comando plot
ver aquí las explicaciones de su uso. Escribiendo C(30)
indicamos que la curva
// Representacion de la frontera del dominio
plot(C(30), wait = 1);
Se observa que, según la parametrización que se ha hecho, la frontera se recorre en el sentido directo (contrario a las agujas del reloj). Obsérvese la diferencia si se define el borde haciendo variar t
desde 2*pi
hasta 0
.
// Definicion de la frontera del dominio
border C1(t = 2*pi, 0){x = 2*cos(t); y = 2*sin(t); label = 15;};
plot(C1(30), wait = 1);
Para construir el mallado, declaramos primero una variable de tipo mesh
, y después construimos una triangulación del dominio encerrado por la curva
// Construccion de la triangulacion
mesh Th;
Th = buildmesh(C(30));
plot(Th, wait = 1);
Se observa que no es posible construir una triangulación del dominio definido por el borde C1
que aparece más arriba, puesto que el dominio que queda a la izquierda cuando se recorre la frontera C1
es el exterior del círculo y no está acotado. En una situación como esta, para arreglar el problema, basta indicar un número negativo de segmentos sobre la frontera para construir el mallado:
// Construccion de la triangulacion usando el borde C1
mesh T1h;
T1h = buildmesh(C1(-30));
plot(T1h, wait = 1);
Tomaremos como dominio
Las siguientes instrucciones definen las dos partes de la frontera del dominio, utilizando de nuevo ecuaciones paramétricas. Obsérvese que hemos asignado las etiquetas label = 1
y label = 10
a dichas curvas:
// Definicion de la frontera del dominio
real pi2 = pi/2;
border Gamma1(t = 0, pi2){x = 1+ cos(t); y = sin(t); label = 1;};
border Gamma2(t = pi2, 2*pi){x = 1 + cos(t); y = sin(t); label = 10;};
plot(Gamma1(10) + Gamma2(30), wait = 1, ps = "Circulo2.eps");
Para construir el mallado, se procede como en el ejemplo anterior, teniendo en cuenta ahora que la frontera es compuesta. Por ejemplo, elegiremos para
// Construccion de la triangulacion
mesh Ch = buildmesh(Gamma1(10) + Gamma2(30));
plot(Ch, wait = 1, ps = "MalladoCirculo2.eps");
El comando square
permite construir un mallado de un dominio rectangular. En su uso más básico, permite generar un mallado del cuadrado
mesh Qh = square(n, m);
donde el significado de los parámetros obligatorios n
y m
es el siguiente:
n
es el número de segmentos en m
es el número de segmentos en Por ejemplo, un mallado
xxxxxxxxxx
// Mallado del cuadrado [0,1]x[0,1]
mesh Sh = square(4,5);
plot(Sh, wait = 1);
Se observa que, por defecto, se asignan las etiquetas 1
, 2
, 3
y 4
a los 4 lados del cuadrado, en el orden que se indica en la figura.
Para construir un mallado square
en su forma más general:
xxxxxxxxxx
mesh Rh = square(n, m, [x0+(x1-x0)*x, y0+(y1-y0)*y]);
Por ejemplo, un mallado
xxxxxxxxxx
// Mallado de rectangulo [x0,x1]x[y0,y1]
real x0 = 1.2, x1 = 2.;
real y0 = 0.5, y1 = 1.5;
int n = 5, m = 20;
mesh Rh = square(n, m, [x0+(x1-x0)*x, y0+(y1-y0)*y]);
plot(Rh, wait = 1);
La forma mas completa del comando square
es:
xxxxxxxxxx
mesh Th = square(n, m, [x0+(x1-x0)*x,y0+(y1-y0)*y], flags = iC, label = La, region = id);
Donde los parámetros (opcionales) son :
flags= iC
indica el tipo de mallado que se va a realizar, siendo flags = 0
la opción por defecto. Los otros cuatro posibles valores de flags
son 1, 2, 3, 4
, cuyo resultado se puede observar en las figuras siguientes
flags = 0 | ![]() |
---|---|
flags = 1 | ![]() |
flags = 2 | ![]() |
flags = 3 | ![]() |
flags = 4 | ![]() |
label = La
, donde La
es un vector fila de cuatro elementos que define las etiquetas para las 4 fronteras.
region = id
, permite asignar un número de identificación a la región interior al cuadrado.
Ejercicio 1
Sea
Construir un mallado de
Ejercicio 2
Construir un mallado del dominio
Utilizar distinto número de segmentos para discretizar
La adaptación del mallado es una herramienta muy útil cuando la solución de un problema tiene importantes variaciones en una zona determinada del dominio. El comando adaptmesh
permite adaptar el mallado a esta circunstancia, de modo que el mallado inicial se hace "más fino" en la parte en la que se producen grandes variaciones de la función.
El uso básico del comando adaptmesh
es
mesh ThNew = adaptmesh(Th, f);
donde el significado de los argumentos es el que sigue:
Th
es el mallado inicial a adaptar,f
es una función de tipo func
o una función de tipo fespace
del espacio de elementos finitos.ThNew
es el nuevo mallado adaptado. El papel desempeñado por f
es el de fijar una "métrica" en base a la cual:
(a) en la zona donde f
experimenta grandes variaciones (es decir, su gradiente es "grande") se refina el mallado, y
(b) por el contrario, allá donde f
es aproximadamente constante, se usan triángulos de gran tamaño (si es necesario, incluso se suprimen triángulos anteriormente construidos).
Ejemplo 1: Consideramos la siguiente función en un mallado
En el código que sigue se realiza la adaptación del mallado dos veces:
x// Ejemplo 1 (adaptacion del mallado)
mesh Th = square(5,5);
plot(Th, wait = true, cmm = "Ejemplo 1: Mallado original");
// Funcion para adaptar
real sigma = 0.001, qx = 0.65, qy = 0.35, sigma2 = - 0.5 / sigma;
func fg = 3 * exp(sigma2*((x-qx)^2+(y-qy)^2));
fespace Vh(Th, P1);
Vh g = fg;
plot(Th, g, wait = true, cmm = "Funcion para adaptar el mallado");
// Adaptacion del mallado 1
Th = adaptmesh(Th, fg);
g = fg;
plot(Th, g, wait = true, cmm = "adaptmesh: 1 iteracion");
// Adaptacion del mallado 2
Th = adaptmesh(Th, fg);
g = fg;
plot(Th, g, wait = true, cmm = "adaptmesh: 2 iteraciones");
El uso algo más completo del comando adaptmesh
es el que sigue
mesh ThNew = adaptmesh(Th, f, err = Error );
donde el parámetro err
toma un valor real Error
que indica el nivel del error de interpolación 0.01
).
Ejemplo 2: Consideramos la siguiente función en un mallado
En el código que sigue se realiza la adaptación del mallado tres veces, haciendo disminuir el parámetro del error en cada iteración de la adaptación.
xxxxxxxxxx
// Ejemplo 2 (adaptacion del mallado)
real eps = 0.0001;
real Error = 0.01;
// atan2(y, x) = arctag(y/x)
func f = 10.*x^3 + y^3 + atan2(eps, sin(7.0*y)-2.0*x);
// Mallado
mesh Th = square(5, 5, [-1+2*x, -1+2*y]);
// Espacio de elementos finitos
fespace Vh(Th,P1);
Vh fh = f;
plot(Th, fh, nbiso=50, cmm = "Mallado original y funcion", fill = true, wait = true);
// Adaptacion del mallado
int niter = 3;
for (int i = 0; i < niter; i++){
Th = adaptmesh(Th, fh, err= Error);
Error /= 2;
fh = f;
plot(Th, fh, nbiso=50, fill = true, cmm = "Iteracion "+ (i+1)+"/"+niter, wait=true);
}
Para construir mallados en tres dimensiones hay que escribir al comienzo del programa la orden
load "msh3"
El comando cube
permite construir un mallado de un cubo. Su uso más básico permite generar un mallado del cubo
xxxxxxxxxx
mesh3 Th1 = cube(n, m, k);
donde el significado de los parámetros obligatorios n
, m
y k
es
n
es el número de segmentos en m
es el número de segmentos en k
es el número de segmentos en Por ejemplo, un mallado
xxxxxxxxxx
// Mallado del cubo [0,1]x[0,1]x[0,1]
load "msh3"
mesh3 Th1 = cube(3, 4, 5);
plot(Th1, wait = true);
Por defecto las etiquetas asignadas son:
Para construir un mallado cube
en su forma más general.
xxxxxxxxxx
mesh3 Th2 = cube(n, m, k, [x0+(x1-x0)*x, y0+(y1-y0)*y, z0+(z1-z0)*z]);
Por ejemplo, un mallado
xxxxxxxxxx
// Mallado de [x0,x1]x[y0,y1]x[z0,z1]
load "msh3"
real x0 = -1., x1 = 1.;
real y0 = 1., y1 = 2.;
real z0 = 2., z1 = 3.;
mesh3 Th2 = cube(5,4,6, [x0+(x1-x0)*x, y0+(y1-y0)*y, z0+(z1-z0)*z]);
plot(Th2, wait = true);
Una forma mas completa del comando cube
es:
xxxxxxxxxx
mesh3 Th3 = cube(n, m, k, [x0+(x1-x0)*x, y0+(y1-y0)*y, z0+(z1-z0)*z], flags = iC, label = La, region = id);
donde el significado de los parámetros (opcionales) es similar al que se describe en el comando square
. Por ejemplo, un mallado del cubo
xxxxxxxxxx
// Mallado del cubo [0,1]^3
load "msh3"
int[int] L6 = [14, 1, 5, 20, 9, 0];
mesh3 Th3 = cube(3, 4, 5, label = L6, flags = 3);
plot(Th3, wait = true);
El comando buildlayer
permite construir un mallado 3D extendiendo por capas un mallado bidimensional en la dirección del eje OZ. Por ejemplo, un mallado de un cilindro con base elíptica se consigue con los comandos
x
load "msh3"
// Mallado 2D (elipse)
int L1 = 14;
border elipse(t=0, 2*pi){x = cos(t); y = 2*sin(t); label = L1;};
mesh Thelipse = buildmesh(elipse(60));
plot(Thelipse, wait = true);
// Mallado 3D (cilindro)
int nz = 4;
real zmin = 0., zmax = 1.;
int[int] rup = [0, 9], rdown = [0, 20];
mesh3 Thcylinder = buildlayers(Thelipse, nz, zbound = [zmin, zmax],
labelup = rup, labeldown = rdown);
plot(Thcylinder, wait = true);
Los parámetros que se han usado en buildlayers
son:
Thelipse
indica nombre del mallado bidimensional que se va a extender por capas.nz
es un entero que indica el número de capas, en este caso, igual a 4
. zbound = [zmin, zmax]
, siendo zmin(x,y)
y zmax(x,y)
dos funciones que definen, respectivamente, la superficie inferior (sobre la que reposa la cara inferior del dominio resultante) y la superficie superior (resp. la cara superior). En este caso, las funciones son constantes, iguales a 0
y 1
, lo cual corresponde a superficies planas paralelas al plano labeldown
, labelmid
, labelup
son vectores formados por pares de números enteros: [NumOld, NumNew]
, donde NumOld
hace referencia a la etiqueta del mallado 2D que se quiere cambiar por NumNew
en el mallado 3D. Por defecto, los elementos de la cara inferior y superior del mallado 3D heredan la referencia de la región del mallado 2D, mientras que los elementos de la superficie lateral del cilindro heredan la referencia del borde del mallado 2D del que proceden. En estas asignaciones, los números de las etiquetas no se pueden proporcionar directamente a partir de constantes, sino que deben ser previamente asignados a variables adecuadas. En el caso del ejemplo, rup
y rdown
. Construir usando buildlayers
, un mallado del dominio 90
a la superficie de arriba y abajo y la etiqueta 9
a las superficies laterales (usando el parámetro labelmid
).
Resumen: Se presentan algunos métodos de visualización de los resultados obtenidos con FreeFEM.
Esta función permite representar mallados y resultados obtenidos con FreeFEM. Su uso general es
xxxxxxxxxx
plot(Parametros obligatorios, parametros opcionales)
Algunos ejemplos de parámetros obligatorios son:
Triangulacion
(un objeto de tipo mesh
o mesh3
): el mallado a representar funcion
(una función de un espacio de elementos finitos): la función a representar. Puede ser escalar o vectorial. Por ejemplo, la solución de un problema variacional.frontera
: una discretización de un contorno construido con border
.poligonal
: un par de vectores reales [xu, yu]
conteniendo respectivamente las abscisas y las ordenadas de los vértices de la poligonal (por ejemplo, para dibujar una curva).Es posible incluir más de uno de los parámetros obligatorios, por ejemplo, un mallado junto con la solución de un problema.
Algunos de los parámetros opcionales son:
wait = true / false
wait = 1 / 0
Si es true
o 1
, se espera antes de continuar, hasta que se pulse return
.ps = "fichero.ps" / "fichero.eps"
Nombre del fichero para salvar la figura representada con plot
(formato Postscript).fill = true / false
Si es true
, se rellenan con colores los espacios entre las líneas de nivel (solo para funciones fespace
escalares).cmm = "comentario"
Texto a incluir en la gráfica.value = true / false
Si es true
, se muestra la barra de colores (asociación color : valor). nbiso = numero
Número de líneas de nivel a representar en la escala. boundary = true/false
) Se es true
, se dibuja la frontera del dominio (valor por defecto).dim = 2/3
Establece la dimensión de la gráfica 2 o 3.WindowIndex = numero
Especifica el número de ventana para cuando hay varias ventanas gráficas.
Algunos atajos del teclado en la representación con plot
son:
wait = true
.
Anna Doubova - Rosa Echevarría - Dpto. EDAN - Universidad de Sevilla